Skip to content

Commit

Permalink
fix: 🎨 better types/imports
Browse files Browse the repository at this point in the history
remove `stringifiedSchemasByName` and `stringifiedDefsSchemas`: now use `oaSchemasByName` and `oaDefsSchemas` or `useOaServerSchema()`
  • Loading branch information
Morgbn committed Jun 19, 2024
1 parent d08a179 commit 29c5606
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 150 deletions.
10 changes: 4 additions & 6 deletions playground/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,13 @@
import { ref } from 'vue'
import { JsonSchema } from 'j2u'
import { keywords } from '~/ajv-keywords'
import { useFetch, useOaSchema, useOaDefsSchema, useNuxtApp } from '#imports'
import { useFetch, useOaSchema, useOaDefsSchema, oaTodoSchema, useNuxtApp } from '#imports'
const schema = useNuxtApp().$getTodoOaSchema
const schema2 = useOaSchema('Todo')
const schema = useOaSchema('Todo')
// OR: const schema = oaTodoSchema
// OR: const schema = useNuxtApp().$oaTodoSchema
const defsSchema = useOaDefsSchema('defs')
// const s = schema.properties.cost.range
// const s2 = schema2.properties
const msg = ref<string | null>(null)
const msgColor = ref('green')
const { data: todos, pending } = await useFetch('/api/todos', { lazy: true })
Expand Down
127 changes: 91 additions & 36 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { existsSync, lstatSync, readdirSync, readFileSync } from 'node:fs'
import { useLogger, defineNuxtModule, createResolver, addServerHandler, addImports, addPlugin, addPluginTemplate, addTemplate, addTypeTemplate, updateTemplates } from '@nuxt/kit'
import { useLogger, defineNuxtModule, createResolver, addServerHandler, addImports, addPlugin, addTemplate, addTypeTemplate, updateTemplates } from '@nuxt/kit'
import type { Nuxt } from '@nuxt/schema'
import chalk from 'chalk'
import { defu } from 'defu'
Expand All @@ -11,7 +11,6 @@ const logger = useLogger('nuxt-oa')
const getSchemas = (options: ModuleOptions, nuxt: Nuxt) => {
// Get schemas & defs
const schemasByName: Record<string, Schema> = {}
const schemasFolderPathByName: Record<string, string> = {}
const defsById: Record<string, DefsSchema> = {}
for (const layer of nuxt.options._layers) {
const { oa } = layer.config
Expand Down Expand Up @@ -41,12 +40,11 @@ const getSchemas = (options: ModuleOptions, nuxt: Nuxt) => {
}
} else if (!schemasByName[name]) { // schema file, earlier = higher priority
schemasByName[name] = schema
schemasFolderPathByName[name] = schemasFolderPath
}
}
}
const defsSchemas = Object.values(defsById)
return { schemasByName, defsSchemas, schemasFolderPathByName, defsById }
return { schemasByName, defsSchemas, defsById }
}

export default defineNuxtModule<ModuleOptions>({
Expand All @@ -65,17 +63,11 @@ export default defineNuxtModule<ModuleOptions>({
dbUrl: ''
},
async setup(options, nuxt) {
const { schemasByName, defsSchemas, schemasFolderPathByName, defsById } = getSchemas(options, nuxt)

nuxt.options.oa = defu(options, {
stringifiedSchemasByName: JSON.stringify(schemasByName),
stringifiedDefsSchemas: JSON.stringify(defsSchemas)
})
const { schemasByName, defsSchemas, defsById } = getSchemas(options, nuxt)

// Set up runtime configuration
nuxt.options.runtimeConfig.oa = defu(nuxt.options.runtimeConfig.oa, {
...nuxt.options.oa
})
nuxt.options.oa = { ...options }
nuxt.options.runtimeConfig.oa = defu(nuxt.options.runtimeConfig.oa, nuxt.options.oa)

// Transpile runtime
const { resolve } = createResolver(import.meta.url)
Expand Down Expand Up @@ -121,31 +113,97 @@ export default defineNuxtModule<ModuleOptions>({
}
}

// Provide get[ModelName]OaSchema for each schema
// Provide oa[ModelName]Schema for each schema
const clientSchemaByName: Record<string, Schema> = {}
for (const modelName in schemasByName) {
addPluginTemplate({
filename: `get${modelName}OaSchema.ts`,
const schema = schemasByName[modelName]
schema.type = 'object'
delete schema.encryptedProperties
delete schema.trackedProperties
delete schema.timestamps
delete schema.userstamps
// remove writeOnly props
if (!schema.writeOnly) {
const stack: { parent: Schema, key: string, el: Schema }[] = []
const addToStack = (parent: Schema) => Object.entries(parent).forEach(([key, el]) =>
(el && typeof el === 'object') ? stack.push({ key, parent, el }) : 0)
addToStack(schema)
while (stack.length) {
const { parent, key, el } = stack.pop()!
if (el.writeOnly) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete parent[key]
} else {
addToStack(el)
}
}
}
const t = addTemplate({
filename: `oa/schemas/${modelName}.ts`,
write: true,
src: resolve('runtime/plugins/oaSchema.ejs'),
options: { schemasFolderPath: schemasFolderPathByName[modelName], modelName }
getContents: () => `export default ${JSON.stringify(schema, null, 2)} as const`
})
addImports([{ name: 'default', as: `oa${modelName}Schema`, from: t.dst }])
addPlugin(addTemplate({
filename: `oa/plugins/${modelName}.ts`,
write: true,
getContents: () => [
`import { defineNuxtPlugin } from '#imports'`,
`import oa${modelName}Schema from '${t.dst}'`,
`export default defineNuxtPlugin((nuxtApp) => ({ provide: { oa${modelName}Schema } }))\n`,
'declare module "#app" {',
` interface NuxtApp { oa${modelName}Schema: typeof oa${modelName}Schema }`,
'}',
'declare module "vue" {',
` interface ComponentCustomProperties { oa${modelName}Schema: typeof oa${modelName}Schema }`,
'}'
].join('\n')
}).dst)
clientSchemaByName[modelName] = schema
}
// Provide getOaDefsSchema
addPlugin(addTemplate({
filename: 'getOaDefsSchema.ts',
// Provide useOaSchema
const templateSchema = addTemplate({
filename: 'oa/useOaSchema.ts',
write: true,
getContents: () => [
'import { useNuxtApp } from "#app"',
'import type { OaClientSchemas } from "nuxt-oa"',
'\nexport const useOaSchema = <K extends keyof OaClientSchemas>(modelName: K) => {',
' const key = `$oa${modelName}Schema`',
' return useNuxtApp()[key] as OaClientSchemas[K]',
'}'
].join('\n')
})
addImports([{ name: 'useOaSchema', as: 'useOaSchema', from: templateSchema.dst }])
// Provide useOaDefsSchema
const templateDefs = addTemplate({
filename: 'oa/useOaDefsSchema.ts',
write: true,
getContents: () => [
`const byId = ${JSON.stringify(defsById)} as const`,
`export type OaDefSchemaKey = keyof typeof byId`,
`export const useOaDefsSchema = (id: OaDefSchemaKey) => byId[id]`
].join('\n')
})
addImports([{ name: 'useOaDefsSchema', as: 'useOaDefsSchema', from: templateDefs.dst }])
// Provide schemas for nitro
const templateNitro = addTemplate({
filename: 'oa/nitro.ts',
write: true,
getContents: () => `import { defineNuxtPlugin } from '#imports'\nconst byId = ${JSON.stringify(defsById)}\nexport type OaDefSchemaKey = keyof typeof byId\nexport default defineNuxtPlugin(() => ({ provide: { getOaDefsSchema: (id: OaDefSchemaKey) => byId[id] } }))`
}).dst)
getContents: () => [
`export const oaSchemasByName = ${JSON.stringify(schemasByName)}`,
`export const oaDefsSchemas = ${JSON.stringify(defsSchemas)}`,
`export type OaModelName = keyof typeof oaSchemasByName`,
`export const useOaServerSchema = () => ({ schemasByName: oaSchemasByName, defsSchemas: oaDefsSchemas })`
].join('\n')
})
nuxt.options.nitro.imports.presets.push({
from: templateNitro.dst,
imports: ['oaSchemasByName', 'oaDefsSchemas', 'useOaServerSchema', 'OaModelName']
})

// Add j2u (auto form generator)
addPlugin(resolve('runtime/plugins/j2u'))
addImports([
'useOaSchema', 'useOaDefsSchema'
].map(key => ({
name: key,
as: key,
from: resolve('runtime/composables')
})))

// Add types
let n = -1
Expand All @@ -154,9 +212,9 @@ export default defineNuxtModule<ModuleOptions>({
getContents: () => {
if (++n) { // on schema update
const { schemasByName, defsSchemas } = getSchemas(options, nuxt)
return genTypes(schemasByName, defsSchemas)
return genTypes(schemasByName, defsSchemas, clientSchemaByName)
}
return genTypes(schemasByName, defsSchemas) // first-time
return genTypes(schemasByName, defsSchemas, clientSchemaByName) // first-time
}
})
// On update
Expand All @@ -173,9 +231,6 @@ declare module 'nuxt/schema' {
oa: ModuleOptions
}
interface RuntimeConfig {
oa: ModuleOptions & {
readonly stringifiedSchemasByName: string
readonly stringifiedDefsSchemas: string
}
oa: ModuleOptions
}
}
11 changes: 0 additions & 11 deletions src/runtime/composables.ts

This file was deleted.

45 changes: 0 additions & 45 deletions src/runtime/plugins/oaSchema.ejs

This file was deleted.

12 changes: 6 additions & 6 deletions src/runtime/server/helpers/controllers.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createError, readBody } from 'h3'
import type { H3Event } from 'h3'
import type { ObjectId } from 'mongodb'
import type { OaModels } from '../../types'
import type Model from './model'
import { oaHandler } from './router'
import type { OaModelName } from '~/.nuxt/oa/nitro.js'

const instance200 = (name: string) => ({
description: `Updated ${name.toLowerCase()}.`,
Expand Down Expand Up @@ -31,7 +31,7 @@ export function useUserId(event: H3Event): string | ObjectId {
return event.context.user.id
}

export const useGetAll = <T extends keyof OaModels & string>(model: Model<T>, apiDoc = {}) => {
export const useGetAll = <T extends OaModelName>(model: Model<T>, apiDoc = {}) => {
const { name } = model
const lowerName = name.toLowerCase()

Expand Down Expand Up @@ -60,7 +60,7 @@ export const useGetAll = <T extends keyof OaModels & string>(model: Model<T>, ap
})
}

export const useCreate = <T extends keyof OaModels & string>(model: Model<T>, apiDoc = {}) => {
export const useCreate = <T extends OaModelName>(model: Model<T>, apiDoc = {}) => {
const { name } = model
const lowerName = name.toLowerCase()

Expand All @@ -87,7 +87,7 @@ export const useCreate = <T extends keyof OaModels & string>(model: Model<T>, ap
})
}

export const useUpdate = <T extends keyof OaModels & string>(model: Model<T>, apiDoc = {}) => {
export const useUpdate = <T extends OaModelName>(model: Model<T>, apiDoc = {}) => {
const { name } = model
const lowerName = name.toLowerCase()

Expand Down Expand Up @@ -115,7 +115,7 @@ export const useUpdate = <T extends keyof OaModels & string>(model: Model<T>, ap
})
}

export const useArchive = <T extends keyof OaModels & string>(model: Model<T>, apiDoc = {}) => {
export const useArchive = <T extends OaModelName>(model: Model<T>, apiDoc = {}) => {
const { name } = model
const lowerName = name.toLowerCase()

Expand Down Expand Up @@ -146,7 +146,7 @@ export const useArchive = <T extends keyof OaModels & string>(model: Model<T>, a
})
}

export const useDelete = <T extends keyof OaModels & string>(model: Model<T>, apiDoc = {}) => {
export const useDelete = <T extends OaModelName>(model: Model<T>, apiDoc = {}) => {
const { name } = model
const lowerName = name.toLowerCase()

Expand Down
Loading

0 comments on commit 29c5606

Please sign in to comment.