diff --git a/.changeset/brown-icons-appear.md b/.changeset/brown-icons-appear.md new file mode 100644 index 000000000..98aeb3ef0 --- /dev/null +++ b/.changeset/brown-icons-appear.md @@ -0,0 +1,5 @@ +--- +'vite-plugin-kit-routes': patch +--- + +fix ensurePrefix on ROOT diff --git a/.changeset/heavy-moose-wash.md b/.changeset/heavy-moose-wash.md new file mode 100644 index 000000000..bf1f5d9e4 --- /dev/null +++ b/.changeset/heavy-moose-wash.md @@ -0,0 +1,5 @@ +--- +'vite-plugin-kit-routes': patch +--- + +add generic types to the plugin diff --git a/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts b/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts index 8d6667248..d607ede09 100644 --- a/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts +++ b/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts @@ -6,7 +6,7 @@ export const PAGES = { _ROOT: () => { - return `/` + return ensurePrefix(`/`) }, contract: () => { return `/contract` @@ -59,9 +59,11 @@ export const ACTIONS = { }, site_contract_siteId_contractId: ( action: 'sendSomething', - params: { siteId: string | number; contractId: string | number }, + params: { siteId: string | number; contractId: string | number; extra?: 'A' | 'B' }, ) => { - return `/site_contract/${params.siteId}-${params.contractId}?/${action}` + return `/site_contract/${params.siteId}-${params.contractId}?/${action}${appendSp({ + extra: params.extra, + })}` }, } @@ -77,3 +79,48 @@ const appendSp = (sp?: Record) => { } return '' } + +const ensurePrefix = (str: string) => { + if (str.startsWith('/')) { + return str + } + return `/${str}` +} + +/** + * Add this type as a generic of the vite plugin `kitRoutes`. + * + * Full example: + * ```ts + * import type { ROUTES } from '$lib/ROUTES' + * import { kitRoutes } from 'vite-plugin-kit-routes' + * + * kitRoutes({ + * extend: { + * PAGES: { + * // here, "paths" it will be typed! + * } + * } + * }) + * ``` + */ +export type ROUTES = { + PAGES: { + _ROOT: never + contract: never + contract_id: 'id' + gp_logged_one: never + gp_public_two: never + lang_lang: 'lang' + match_id_int: 'id' + site: 'limit' + site_id: 'id' | 'limit' + site_contract_siteId_contractId: 'siteId' | 'contractId' + } + SERVERS: { contract: never; site: never } + ACTIONS: { + contract_id: 'id' + site: never + site_contract_siteId_contractId: 'siteId' | 'contractId' | 'extra' + } +} diff --git a/packages/vite-plugin-kit-routes/src/lib/index.ts b/packages/vite-plugin-kit-routes/src/lib/index.ts index cf53a3501..5f850d1e4 100644 --- a/packages/vite-plugin-kit-routes/src/lib/index.ts +++ b/packages/vite-plugin-kit-routes/src/lib/index.ts @@ -9,7 +9,17 @@ import { read, write } from './fs.js' const { visit } = recast.types -export type Options = { +export type Options< + T extends { + PAGES: Record + SERVERS: Record + ACTIONS: Record + } = { + PAGES: Record + SERVERS: Record + ACTIONS: Record + }, +> = { /** * run command after file updated * @@ -47,15 +57,15 @@ export type Options = { extra_search_params?: 'with' | 'without' extend?: { - PAGES?: Record - SERVERS?: Record - ACTIONS?: Record + PAGES?: Partial<{ [K in keyof T['PAGES']]: CustomPath> }> + SERVERS?: Partial<{ [K in keyof T['SERVERS']]: CustomPath> }> + ACTIONS?: Partial<{ [K in keyof T['ACTIONS']]: CustomPath> }> } } -export type CustomPath = { +export type CustomPath = { explicit_search_params?: Record - params?: Record + params?: Partial> extra_search_params?: 'default' | 'with' | 'without' } @@ -136,8 +146,7 @@ export const fileToMetadata = ( options: Options | undefined, useWithAppendSp: boolean | undefined, ) => { - const href = original.replace(/\([^)]*\)/g, '').replace(/\/+/g, '/') - let toRet = href + let toRet = original.replace(/\([^)]*\)/g, '').replace(/\/+/g, '/') const keyToUse = formatKey(original, options) @@ -147,6 +156,7 @@ export const fileToMetadata = ( extra_search_params: 'default', } if (viteCustomPathConfig && viteCustomPathConfig[keyToUse]) { + // @ts-expect-error customConf = viteCustomPathConfig[keyToUse] } @@ -157,10 +167,10 @@ export const fileToMetadata = ( Object.entries(customConf.params).forEach(sp => { for (let i = 0; i < paramsFromPath.length; i++) { if (paramsFromPath[i].name === sp[0]) { - if (sp[1].type) { + if (sp[1] && sp[1].type) { paramsFromPath[i].type = sp[1].type } - if (sp[1].default !== undefined) { + if (sp[1] && sp[1].default !== undefined) { paramsFromPath[i].default = sp[1].default // It's becoming optional because it has a default paramsFromPath[i].optional = true @@ -249,7 +259,9 @@ export const fileToMetadata = ( `"${keyToUse}": (${params.join(', ')}) => ` + ` { ` + `${paramsDefaults.join('')}` + - `return \`${toRet}${actionsFormat}${fullSP}\`` + + `return ${keyToUse === '_ROOT' ? `ensurePrefix(` : ``}` + + `\`${toRet}${actionsFormat}${fullSP}\`` + + `${keyToUse === '_ROOT' ? `)` : ``}` + ` }` return { keyToUse, prop, paramsFromPath } @@ -366,18 +378,20 @@ const run = (options?: Options) => { log.error(`Can't extend "${green(`${o.type}.`)}${red(key)}" as this path doesn't exist!`) allOk = false } else { - Object.entries(cPath.params ?? {}).forEach(p => { - const [pKey] = p - const paramsFromPathFound = found.paramsFromPath.find(c => c.name === pKey) - if (!paramsFromPathFound) { - log.error( - `Can't extend "${green(`${o.type}.${key}.params.`)}${red( - pKey, - )}" as this param doesn't exist!`, - ) - allOk = false - } - }) + if (cPath) { + Object.entries(cPath.params ?? {}).forEach(p => { + const [pKey] = p + const paramsFromPathFound = found.paramsFromPath.find(c => c.name === pKey) + if (!paramsFromPathFound) { + log.error( + `Can't extend "${green(`${o.type}.${key}.params.`)}${red( + pKey, + )}" as this param doesn't exist!`, + ) + allOk = false + } + }) + } } }) }) @@ -390,6 +404,7 @@ const run = (options?: Options) => { * >> DO NOT EDIT THIS FILE MANUALLY << */ `, + // consts objTypes .map(c => { return `export const ${c.type} = { @@ -410,7 +425,53 @@ const appendSp = (sp?: Record) => { } return '' } + +const ensurePrefix = (str: string) => { + if (str.startsWith('/')) { + return str + } + return \`/\${str}\` +} `, + // types + ` +/** + * Add this type as a generic of the vite plugin \`kitRoutes\`. + * + * Full example: + * \`\`\`ts + * import type { ROUTES } from '$lib/ROUTES' + * import { kitRoutes } from 'vite-plugin-kit-routes' + * + * kitRoutes({ + * extend: { + * PAGES: { + * // here, "paths" it will be typed! + * } + * } + * }) + * \`\`\` + */ +export type ROUTES = { +${objTypes + .map(c => { + return ` ${c.type}: { ${c.files + .map(d => { + return `'${d.keyToUse}': ${ + d.paramsFromPath.length === 0 + ? 'never' + : d.paramsFromPath + .map(e => { + return `'${e.name}'` + }) + .join(' | ') + }` + }) + .join(', ')} }` + }) + .join('\n')} +} + `, ]) // TODO: optimize this later. We want to write the new file only if different after prettier?! (having a tmp file somewhere?) @@ -441,7 +502,37 @@ const appendSp = (sp?: Record) => { return false } -export function kitRoutes(options?: Options): Plugin[] { +/** + * First you can start with something simple: + * ```ts + * import { kitRoutes } from 'vite-plugin-kit-routes' + * + * kitRoutes({ + * // Conf + * }) + * ``` + * --- + * Then, you can add the `ROUTES` type... It will be crazy good! + * ```ts + * import type { ROUTES } from '$lib/ROUTES' + * import { kitRoutes } from 'vite-plugin-kit-routes' + * + * kitRoutes({ + * // Conf + * }) + * ``` + */ +export function kitRoutes< + T extends { + PAGES: Record + SERVERS: Record + ACTIONS: Record + } = { + PAGES: Record + SERVERS: Record + ACTIONS: Record + }, +>(options?: Options): Plugin[] { return [ // Run the thing at startup { diff --git a/packages/vite-plugin-kit-routes/vite.config.ts b/packages/vite-plugin-kit-routes/vite.config.ts index d8bb905cb..c54d30f45 100644 --- a/packages/vite-plugin-kit-routes/vite.config.ts +++ b/packages/vite-plugin-kit-routes/vite.config.ts @@ -1,12 +1,16 @@ import { sveltekit } from '@sveltejs/kit/vite' +import type { ROUTES } from '$lib/ROUTES.js' import { defineConfig } from 'vite' import { kitRoutes } from './src/lib/index.js' +type TT = 'A' | 'B' +const u: Partial> = {} + export default defineConfig({ plugins: [ sveltekit(), // demo - kitRoutes({ + kitRoutes({ // for testing // generated_file_path: 'src/lib/ROUTES2.ts', post_update_run: 'npm exec prettier ./src/lib/ROUTES.ts -- -w', @@ -25,9 +29,19 @@ export default defineConfig({ params: { id: { type: 'string', default: '' } }, }, }, - // SERVERS: { - // yop: {}, - // }, + SERVERS: { + // site: { + // params: { } + // } + // yop: {}, + }, + ACTIONS: { + site_contract_siteId_contractId: { + explicit_search_params: { + extra: { type: "'A' | 'B'", default: 'A' }, + }, + }, + }, }, }), ],