diff --git a/.changeset/rude-pillows-train.md b/.changeset/rude-pillows-train.md new file mode 100644 index 000000000..33c350254 --- /dev/null +++ b/.changeset/rude-pillows-train.md @@ -0,0 +1,5 @@ +--- +'vite-plugin-kit-routes': patch +--- + +rename object_keys_format to format diff --git a/.changeset/unlucky-bulldogs-occur.md b/.changeset/unlucky-bulldogs-occur.md new file mode 100644 index 000000000..6bd9e5ca0 --- /dev/null +++ b/.changeset/unlucky-bulldogs-occur.md @@ -0,0 +1,5 @@ +--- +'vite-plugin-kit-routes': patch +--- + +remove exdend in the config to reduce the file nesting diff --git a/.gitignore b/.gitignore index c56ad10ee..9e97ed5f0 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,6 @@ coverage/ .idea/ .svelte-kit/ .env +.DS_Store -stats.html \ No newline at end of file +stats.html diff --git a/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts b/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts index ed2c09a3c..12509f22d 100644 --- a/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts +++ b/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts @@ -136,10 +136,8 @@ const appendSp = (sp?: Record) => { * import { kitRoutes } from 'vite-plugin-kit-routes' * * kitRoutes({ - * extend: { - * PAGES: { - * // here, "paths" it will be typed! - * } + * PAGES: { + * // here, "paths" it will be typed! * } * }) * ``` diff --git a/packages/vite-plugin-kit-routes/src/lib/fs.ts b/packages/vite-plugin-kit-routes/src/lib/fs.ts index 56ead09bf..97c466dd8 100644 --- a/packages/vite-plugin-kit-routes/src/lib/fs.ts +++ b/packages/vite-plugin-kit-routes/src/lib/fs.ts @@ -2,7 +2,10 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' import { dirname, join } from 'node:path' export function read(pathFile: string) { - return readFileSync(pathFile, { encoding: 'utf8' }) + try { + return readFileSync(pathFile, { encoding: 'utf8' }) + } catch (error) {} + return null } export function write(pathFile: string, data: string[]) { diff --git a/packages/vite-plugin-kit-routes/src/lib/plugin.ts b/packages/vite-plugin-kit-routes/src/lib/plugin.ts index bcb34a404..764c3864e 100644 --- a/packages/vite-plugin-kit-routes/src/lib/plugin.ts +++ b/packages/vite-plugin-kit-routes/src/lib/plugin.ts @@ -10,21 +10,16 @@ import { read, write } from './fs.js' const { visit } = recast.types -export type Options< - T extends { - PAGES: Record - SERVERS: Record - ACTIONS: Record - Params: Record - } = { - PAGES: Record - SERVERS: Record - ACTIONS: Record - Params: Record - }, -> = { +type ExtendTypes = { + PAGES: Record + SERVERS: Record + ACTIONS: Record + Params: Record +} + +export type Options = { /** - * run command after file updated + * run any command after an update of some routes. * * @example * ```ts @@ -47,7 +42,7 @@ export type Options< * PAGES.site_id_two_hello * ``` */ - object_keys_format?: '/' | '_' + format?: '/' | '_' /** * default is: `string | number` @@ -59,16 +54,39 @@ export type Options< * * when `with`, each paths get an extra arg for open search param * + * ⚠️ **We don't recommend to use it, but it can be useful in some cases.** + * * Can be tuned at individual path level */ extra_search_params?: 'with' | 'without' - extend?: { - PAGES?: Partial<{ [K in keyof T['PAGES']]: CustomPath> }> - SERVERS?: Partial<{ [K in keyof T['SERVERS']]: CustomPath> }> - ACTIONS?: Partial<{ [K in keyof T['ACTIONS']]: CustomPath> }> - LINKS?: 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> }> + /** + * ```ts + * { + * // ... Example ... + * LINKS: { + * // reference to a hardcoded link + * twitter: 'https://twitter.com/jycouet', + * // ✅ Twitter + * + * // reference to link with params! (Like svelteKit routes add [ ] to specify params) + * mailto: 'mailto:[email]', + * // ✅ Mail + * + * // reference to link with params & search params! + * twitter_post: { + * href: 'https://twitter.com/[name]/status/[id]', + * explicit_search_params: { limit: { type: 'number' } } + * } + * // ✅ Twitter Post + * } + * } + * ``` + */ + LINKS?: Record)> /** * To override the type of a param globally. @@ -87,8 +105,34 @@ export type Options< } export type CustomPath = { + /** + * Add to this route an explicit search params (with some options) + * @example + * explicit_search_params { + * limit: { // name of the search param + * required?: true | false, // default: false + * type: 'number', // default: 'string | number' + * default: '12', // default: undefined + * } + * } + */ explicit_search_params?: Record + /** + * Specify for this route the type & a default. + * @example + * params { + * id: { // name of the param (if you set the plugin `kitRoutes`, it will be typed!) + * type: 'number', // default: 'string | number' + * default: '12', // default: undefined + * } + * } + */ params?: Partial> + /** + * If `with`, you can add extra search params to this route (without any typecheck!) + * + * ⚠️ **We don't recommend to use it, but it can be useful in some cases.** + */ extra_search_params?: 'default' | 'with' | 'without' } @@ -126,7 +170,7 @@ export function rmvGroups(key: string) { export function formatKey(key: string, options?: Options) { let toRet = rmvGroups(key) - if (options?.object_keys_format === undefined || options?.object_keys_format === '/') { + if (options?.format === undefined || options?.format === '/') { return toRet } @@ -167,8 +211,10 @@ const getFileKeys = ( const useWithAppendSp = withAppendSp && options?.extra_search_params === 'with' if (type === 'LINKS') { - const toRet = Object.entries(options?.extend?.LINKS ?? {}).map(c => { - return fileToMetadata(c[0], c[1].href, type, options, useWithAppendSp) + const toRet = Object.entries(options?.LINKS ?? {}).map(c => { + const hrefToUse = typeof c[1] === 'string' ? c[1] : c[1].href + + return fileToMetadata(c[0], hrefToUse, type, options, useWithAppendSp) }) return toRet.filter(c => c !== null) as { keyToUse: string @@ -210,7 +256,7 @@ export const fileToMetadata = ( let toRet = rmvGroups(originalValue) // custom conf - const viteCustomPathConfig = options?.extend?.[type] + const viteCustomPathConfig = options?.[type] let customConf: CustomPath = { extra_search_params: 'default', } @@ -466,7 +512,7 @@ const getActionsOfServerPages = (pathFile: string) => { return { actions, withLoad } } -const run = (options?: Options) => { +export const run = (options?: Options) => { const objTypes = [ { type: 'PAGES', files: getFileKeys('PAGES', options, true) }, { type: 'SERVERS', files: getFileKeys('SERVERS', options, true) }, @@ -479,7 +525,7 @@ const run = (options?: Options) => { objTypes .filter(c => c.type !== 'LINKS') .forEach(o => { - Object.entries(options?.extend?.[o.type] ?? {}).forEach(e => { + Object.entries(options?.[o.type] ?? {}).forEach(e => { const [key, cPath] = e const found = o.files.find(c => c.keyToUse === key) if (!found) { @@ -544,10 +590,8 @@ const appendSp = (sp?: Record) => { * import { kitRoutes } from 'vite-plugin-kit-routes' * * kitRoutes({ -* extend: { -* PAGES: { -* // here, "paths" it will be typed! -* } +* PAGES: { +* // here, "paths" it will be typed! * } * }) * \`\`\` @@ -700,19 +744,7 @@ ${objTypes * }) * ``` */ -export function kitRoutes< - T extends { - PAGES: Record - SERVERS: Record - ACTIONS: Record - Params: Record - } = { - PAGES: Record - SERVERS: Record - ACTIONS: Record - Params: Record - }, ->(options?: Options): Plugin[] { +export function kitRoutes(options?: Options): Plugin[] { return [ // Run the thing at startup { diff --git a/packages/vite-plugin-kit-routes/src/lib/plugins.spec.ts b/packages/vite-plugin-kit-routes/src/lib/plugins.spec.ts index 04b970a10..46d57dec8 100644 --- a/packages/vite-plugin-kit-routes/src/lib/plugins.spec.ts +++ b/packages/vite-plugin-kit-routes/src/lib/plugins.spec.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest' -import { extractParamsFromPath, fileToMetadata, formatKey } from './plugin.js' +import { read } from './fs.js' +import { extractParamsFromPath, fileToMetadata, formatKey, run, type Options } from './plugin.js' describe('vite-plugin-kit-routes', () => { it('get id', async () => { @@ -66,29 +67,29 @@ describe('vite-plugin-kit-routes', () => { }) it('formatKey /l', async () => { - expect( - formatKey('/[param]site/[yop](group)/[id]', { object_keys_format: '/' }), - ).toMatchInlineSnapshot('"/[param]site/[yop]/[id]"') + expect(formatKey('/[param]site/[yop](group)/[id]', { format: '/' })).toMatchInlineSnapshot( + '"/[param]site/[yop]/[id]"', + ) }) it('formatKey _', async () => { - expect( - formatKey('/[param]site/[yop](group)/[id]', { object_keys_format: '_' }), - ).toMatchInlineSnapshot('"param_site_yop_id"') + expect(formatKey('/[param]site/[yop](group)/[id]', { format: '_' })).toMatchInlineSnapshot( + '"param_site_yop_id"', + ) }) it('formatKey / starting with group', async () => { - expect(formatKey('/(group)/test', { object_keys_format: '/' })).toMatchInlineSnapshot('"/test"') + expect(formatKey('/(group)/test', { format: '/' })).toMatchInlineSnapshot('"/test"') }) it('formatKey _ starting with group', async () => { - expect(formatKey('/(group)/test', { object_keys_format: '_' })).toMatchInlineSnapshot('"test"') + expect(formatKey('/(group)/test', { format: '_' })).toMatchInlineSnapshot('"test"') }) it('formatKey group original', async () => { - expect( - formatKey('/[param]site/[yop](group)/[id]', { object_keys_format: '_' }), - ).toMatchInlineSnapshot('"param_site_yop_id"') + expect(formatKey('/[param]site/[yop](group)/[id]', { format: '_' })).toMatchInlineSnapshot( + '"param_site_yop_id"', + ) }) it('formatKey ROOT', async () => { @@ -144,14 +145,12 @@ describe('vite-plugin-kit-routes', () => { key, 'PAGES', { - extend: { - PAGES: { - subscriptions_snapshot_id: { - explicit_search_params: { limit: { type: 'number' } }, - params: { - snapshot: { type: 'string', default: 'snapshot' }, - id: { type: 'string', default: 'id' }, - }, + PAGES: { + subscriptions_snapshot_id: { + explicit_search_params: { limit: { type: 'number' } }, + params: { + snapshot: { type: 'string', default: 'snapshot' }, + id: { type: 'string', default: 'id' }, }, }, }, @@ -169,3 +168,322 @@ describe('vite-plugin-kit-routes', () => { } }) }) + +describe('run()', () => { + const commonConfig: Options = { + LINKS: { + // reference to a hardcoded link + twitter: 'https://twitter.com/jycouet', + + // reference to link with params! + mailto: 'mailto:[email]', + + // reference to link with params & search params! + twitter_post: { + href: 'https://twitter.com/[name]/status/[id]', + explicit_search_params: { limit: { type: 'number' } }, + }, + }, + override_params: { + lang: { type: "'fr' | 'en' | 'hu' | 'at' | string" }, + }, + } + + it('style _', () => { + const generated_file_path = 'src/test/ROUTES_test1.ts' + run({ + generated_file_path, + format: '_', + PAGES: { + subGroup2: { + explicit_search_params: { + first: { + required: true, + }, + }, + }, + lang_contract: { + extra_search_params: 'with', + }, + lang_site: { + // extra_search_params: 'with', + explicit_search_params: { limit: { type: 'number' } }, + params: { + // yop: { type: 'number' }, + }, + extra_search_params: 'with', + }, + lang_site_id: { + explicit_search_params: { limit: { type: 'number' }, demo: { type: 'string' } }, + params: { + id: { type: 'string', default: '7' }, + lang: { type: "'fr' | 'hu' | undefined", default: 'fr' }, + }, + }, + lang_site_contract_siteId_contractId: { + explicit_search_params: { limit: { type: 'number' } }, + }, + }, + SERVERS: { + // site: { + // params: { } + // } + // yop: {}, + }, + ACTIONS: { + lang_site_contract_siteId_contractId: { + explicit_search_params: { + extra: { type: "'A' | 'B'", default: 'A' }, + }, + }, + }, + ...commonConfig, + }) + + expect(read(generated_file_path)).toMatchInlineSnapshot(` + "/** + * This file was generated by 'vite-plugin-kit-routes' + * + * >> DO NOT EDIT THIS FILE MANUALLY << + */ + + export const PAGES = { + \\"_ROOT\\": \`/\`, + \\"subGroup\\": \`/subGroup\`, + \\"subGroup2\\": (params: {first: string | number}) => { + return \`/subGroup2\${appendSp({ first: params.first })}\` + }, + \\"lang_contract\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}, sp?: Record) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/contract\${appendSp(sp)}\` + }, + \\"lang_contract_id\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, id: string | number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/contract/\${params.id}\` + }, + \\"lang_gp_one\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/gp/one\` + }, + \\"lang_gp_two\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/gp/two\` + }, + \\"lang_main\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/main\` + }, + \\"lang_match_id_int\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, id: string | number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/match/\${params.id}\` + }, + \\"lang_site\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, limit?: number}= {}, sp?: Record) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site\${appendSp({...sp, limit: params.limit })}\` + }, + \\"lang_site_id\\": (params: {lang?: 'fr' | 'hu' | undefined, id?: string, limit?: number, demo?: string}= {}) => { + params.lang = params.lang ?? 'fr'; + params.id = params.id ?? '7'; + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site/\${params.id}\${appendSp({ limit: params.limit, demo: params.demo })}\` + }, + \\"lang_site_contract_siteId_contractId\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, siteId: string | number, contractId: string | number, limit?: number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site_contract/\${params.siteId}-\${params.contractId}\${appendSp({ limit: params.limit })}\` + } + } + + export const SERVERS = { + \\"lang_contract\\": (method: 'GET' | 'POST', params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/contract\` + }, + \\"lang_site\\": (method: 'GET', params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site\` + }, + \\"api_graphql\\": (method: 'GET' | 'POST') => { + return \`/api/graphql\` + } + } + + export const ACTIONS = { + \\"lang_contract_id\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, id: string | number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/contract/\${params.id}\` + }, + \\"lang_site\\": (action: 'action1' | 'action2', params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site?/\${action}\` + }, + \\"lang_site_contract_siteId_contractId\\": (action: 'sendSomething', params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, siteId: string | number, contractId: string | number, extra?: 'A' | 'B'}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site_contract/\${params.siteId}-\${params.contractId}?/\${action}\${appendSp({ extra: params.extra })}\` + } + } + + export const LINKS = { + \\"twitter\\": \`https:/twitter.com/jycouet\`, + \\"mailto\\": (params: {email: string | number}) => { + return \`mailto:\${params.email}\` + }, + \\"twitter_post\\": (params: {name: string | number, id: string | number, limit?: number}) => { + return \`https:/twitter.com/\${params.name}/status/\${params.id}\${appendSp({ limit: params.limit })}\` + } + } + + const appendSp = (sp?: Record) => { + if (sp === undefined) return '' + const mapping = Object.entries(sp) + .filter(c => c[1] !== undefined) + .map(c => [c[0], String(c[1])]) + + const formated = new URLSearchParams(mapping).toString() + if (formated) { + return \`?\${formated}\` + } + return '' + } + + + /** + * Add this type as a generic of the vite plugin \`kitRoutes\`. + * + * Full example: + * \`\`\`ts + * import type { KIT_ROUTES } from '$lib/ROUTES' + * import { kitRoutes } from 'vite-plugin-kit-routes' + * + * kitRoutes({ + * PAGES: { + * // here, \\"paths\\" it will be typed! + * } + * }) + * \`\`\` + */ + export type KIT_ROUTES = { + PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup2': 'first', 'lang_contract': 'lang', 'lang_contract_id': 'lang' | 'id', 'lang_gp_one': 'lang', 'lang_gp_two': 'lang', 'lang_main': 'lang', 'lang_match_id_int': 'lang' | 'id', 'lang_site': 'lang' | 'limit', 'lang_site_id': 'lang' | 'id' | 'limit' | 'demo', 'lang_site_contract_siteId_contractId': 'lang' | 'siteId' | 'contractId' | 'limit' } + SERVERS: { 'lang_contract': 'lang', 'lang_site': 'lang', 'api_graphql': never } + ACTIONS: { 'lang_contract_id': 'lang' | 'id', 'lang_site': 'lang', 'lang_site_contract_siteId_contractId': 'lang' | 'siteId' | 'contractId' | 'extra' } + LINKS: { 'twitter': never, 'mailto': 'email', 'twitter_post': 'name' | 'id' | 'limit' } + Params: { first: never, lang: never, id: never, limit: never, demo: never, siteId: never, contractId: never, extra: never, email: never, name: never } + } + " + `) + }) + + it('style /', () => { + const generated_file_path = 'src/test/ROUTES_test2.ts' + run({ + generated_file_path, + ...commonConfig, + }) + + expect(read(generated_file_path)).toMatchInlineSnapshot(` + "/** + * This file was generated by 'vite-plugin-kit-routes' + * + * >> DO NOT EDIT THIS FILE MANUALLY << + */ + + export const PAGES = { + \\"/\\": \`/\`, + \\"/subGroup\\": \`/subGroup\`, + \\"/subGroup2\\": \`/subGroup2\`, + \\"/[[lang]]/contract\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/contract\` + }, + \\"/[[lang]]/contract/[id]\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, id: string | number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/contract/\${params.id}\` + }, + \\"/[[lang]]/gp/one\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/gp/one\` + }, + \\"/[[lang]]/gp/two\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/gp/two\` + }, + \\"/[[lang]]/main\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/main\` + }, + \\"/[[lang]]/match/[id=int]\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, id: string | number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/match/\${params.id}\` + }, + \\"/[[lang]]/site\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site\` + }, + \\"/[[lang]]/site/[id]\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, id: string | number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site/\${params.id}\` + }, + \\"/[[lang]]/site_contract/[siteId]-[contractId]\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, siteId: string | number, contractId: string | number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site_contract/\${params.siteId}-\${params.contractId}\` + } + } + + export const SERVERS = { + \\"/[[lang]]/contract\\": (method: 'GET' | 'POST', params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/contract\` + }, + \\"/[[lang]]/site\\": (method: 'GET', params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site\` + }, + \\"/api/graphql\\": (method: 'GET' | 'POST') => { + return \`/api/graphql\` + } + } + + export const ACTIONS = { + \\"/[[lang]]/contract/[id]\\": (params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, id: string | number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/contract/\${params.id}\` + }, + \\"/[[lang]]/site\\": (action: 'action1' | 'action2', params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string}= {}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site?/\${action}\` + }, + \\"/[[lang]]/site_contract/[siteId]-[contractId]\\": (action: 'sendSomething', params: {lang?: 'fr' | 'en' | 'hu' | 'at' | string, siteId: string | number, contractId: string | number}) => { + return \`\${params?.lang ? \`/\${params?.lang}\`: ''}/site_contract/\${params.siteId}-\${params.contractId}?/\${action}\` + } + } + + export const LINKS = { + \\"twitter\\": \`https:/twitter.com/jycouet\`, + \\"mailto\\": (params: {email: string | number}) => { + return \`mailto:\${params.email}\` + }, + \\"twitter_post\\": (params: {name: string | number, id: string | number, limit?: number}) => { + return \`https:/twitter.com/\${params.name}/status/\${params.id}\${appendSp({ limit: params.limit })}\` + } + } + + const appendSp = (sp?: Record) => { + if (sp === undefined) return '' + const mapping = Object.entries(sp) + .filter(c => c[1] !== undefined) + .map(c => [c[0], String(c[1])]) + + const formated = new URLSearchParams(mapping).toString() + if (formated) { + return \`?\${formated}\` + } + return '' + } + + + /** + * Add this type as a generic of the vite plugin \`kitRoutes\`. + * + * Full example: + * \`\`\`ts + * import type { KIT_ROUTES } from '$lib/ROUTES' + * import { kitRoutes } from 'vite-plugin-kit-routes' + * + * kitRoutes({ + * PAGES: { + * // here, \\"paths\\" it will be typed! + * } + * }) + * \`\`\` + */ + export type KIT_ROUTES = { + PAGES: { '/': never, '/subGroup': never, '/subGroup2': never, '/[[lang]]/contract': 'lang', '/[[lang]]/contract/[id]': 'lang' | 'id', '/[[lang]]/gp/one': 'lang', '/[[lang]]/gp/two': 'lang', '/[[lang]]/main': 'lang', '/[[lang]]/match/[id=int]': 'lang' | 'id', '/[[lang]]/site': 'lang', '/[[lang]]/site/[id]': 'lang' | 'id', '/[[lang]]/site_contract/[siteId]-[contractId]': 'lang' | 'siteId' | 'contractId' } + SERVERS: { '/[[lang]]/contract': 'lang', '/[[lang]]/site': 'lang', '/api/graphql': never } + ACTIONS: { '/[[lang]]/contract/[id]': 'lang' | 'id', '/[[lang]]/site': 'lang', '/[[lang]]/site_contract/[siteId]-[contractId]': 'lang' | 'siteId' | 'contractId' } + LINKS: { 'twitter': never, 'mailto': 'email', 'twitter_post': 'name' | 'id' | 'limit' } + Params: { lang: never, id: never, siteId: never, contractId: never, email: never, name: never, limit: never } + } + " + `) + }) + + it('post_update_run', () => { + const generated_file_path = 'src/test/ROUTES_test3.ts' + run({ + generated_file_path, + post_update_run: 'echo done', + }) + }) +}) diff --git a/packages/vite-plugin-kit-routes/src/routes/+layout.svelte b/packages/vite-plugin-kit-routes/src/routes/+layout.svelte index f75352fdc..e56fa75a0 100644 --- a/packages/vite-plugin-kit-routes/src/routes/+layout.svelte +++ b/packages/vite-plugin-kit-routes/src/routes/+layout.svelte @@ -35,14 +35,14 @@ Site Paris
  • - + Go to site | - + ({ - // for testing - // generated_file_path: 'src/lib/ROUTES2.ts', - post_update_run: 'npm exec prettier ./src/lib/ROUTES.ts -- -w', + format: '_', + // default_type: 'string', // extra_search_params: 'with', - // keep_path_param_format: true, - object_keys_format: '_', + // generated_file_path: 'src/lib/another_path_for_the_file.ts', + post_update_run: 'npm exec prettier ./src/lib/ROUTES.ts -- -w', - extend: { - PAGES: { - subGroup2: { - explicit_search_params: { - first: { - required: true, - }, - }, - }, - lang_site: { - // extra_search_params: 'with', - explicit_search_params: { limit: { type: 'number' } }, - params: { - // yop: { type: 'number' }, + PAGES: { + subGroup2: { + explicit_search_params: { + first: { + required: true, }, }, - lang_site_id: { - explicit_search_params: { limit: { type: 'number' }, demo: { type: 'string' } }, - params: { - id: { type: 'string', default: '7' }, - lang: { type: "'fr' | 'hu' | undefined", default: 'fr' }, - }, + }, + lang_site: { + // extra_search_params: 'with', + explicit_search_params: { limit: { type: 'number' } }, + params: { + // yop: { type: 'number' }, }, - lang_site_contract_siteId_contractId: { - explicit_search_params: { limit: { type: 'number' } }, + }, + lang_site_id: { + explicit_search_params: { limit: { type: 'number' }, demo: { type: 'string' } }, + params: { + id: { type: 'string', default: '7' }, + lang: { type: "'fr' | 'hu' | undefined", default: 'fr' }, }, }, - SERVERS: { - // site: { - // params: { } - // } - // yop: {}, + lang_site_contract_siteId_contractId: { + explicit_search_params: { limit: { type: 'number' } }, }, - ACTIONS: { - lang_site_contract_siteId_contractId: { - explicit_search_params: { - extra: { type: "'A' | 'B'", default: 'A' }, - }, + }, + SERVERS: { + // site: { + // params: { } + // } + // yop: {}, + }, + ACTIONS: { + lang_site_contract_siteId_contractId: { + explicit_search_params: { + extra: { type: "'A' | 'B'", default: 'A' }, }, }, - LINKS: { - // reference to a hardcoded link - twitter: { href: 'https://twitter.com/jycouet' }, + }, + LINKS: { + // reference to a hardcoded link + twitter: 'https://twitter.com/jycouet', - // reference to link with params! - mailto: { href: 'mailto:[email]' }, + // reference to link with params! + mailto: 'mailto:[email]', - // reference to link with params & search params! - // https://twitter.com/jycouet/status/1727089217707159569?limit=12 - twitter_post: { - href: 'https://twitter.com/[name]/status/[id]', - explicit_search_params: { limit: { type: 'number' } }, - }, + // reference to link with params & search params! + twitter_post: { + href: 'https://twitter.com/[name]/status/[id]', + explicit_search_params: { limit: { type: 'number' } }, }, }, diff --git a/website/src/pages/docs/tools/06_vite-plugin-kit-routes.mdx b/website/src/pages/docs/tools/06_vite-plugin-kit-routes.mdx index 5ed2a0460..f6c0a63cb 100644 --- a/website/src/pages/docs/tools/06_vite-plugin-kit-routes.mdx +++ b/website/src/pages/docs/tools/06_vite-plugin-kit-routes.mdx @@ -21,10 +21,10 @@ available in your `$lib/ROUTES.ts` generated file _(always in sync)_. import { PAGES } from '$lib/ROUTES' - + Terms - + Terms + Go to site - + Go to site ``` @@ -50,10 +50,10 @@ available in your `$lib/ROUTES.ts` generated file _(always in sync)_. import { PAGES } from '$lib/ROUTES' - + Go to site - + Go to site ``` @@ -65,10 +65,10 @@ available in your `$lib/ROUTES.ts` generated file _(always in sync)_. const siteId = $page.params.siteId - // 🤞 before, random string + // 🤞 before, hardcoded string const action = `/site_contract/${siteId}?/sendSomething` - // ✅ after, all typed & make sure it exist. // 'vite-plugin-kit-routes', + const action = ACTIONS['/site_contract/${siteId}']('sendSomething', { siteId }) @@ -82,10 +82,10 @@ available in your `$lib/ROUTES.ts` generated file _(always in sync)_. import { LINKS } from '$lib/ROUTES' - + Send me a mail - + Send me a mail ``` @@ -94,12 +94,12 @@ available in your `$lib/ROUTES.ts` generated file _(always in sync)_. import { LINKS } from '$lib/ROUTES' - + Check out the post - + Check out the post @@ -142,12 +142,12 @@ your `+page.svelte` | `+server.ts` | `+page.server.ts`. - What kind of person are you: `PAGES['/terms']` or `PAGES.terms` ? -_You can choose anyway 😜_ +_You can choose anyway_ 😜 ```ts filename="vite.config.ts" kitRoutes({ - // object_keys_format: '/' (default) - object_keys_format: '_' + // format: '/' (default) + format: '_' }) ``` @@ -163,12 +163,10 @@ kitRoutes({ ```ts filename="vite.config.ts" kitRoutes({ - extend: { - PAGES: { - site: { - explicit_search_params: { - limit: { type: 'number' } - } + PAGES: { + site: { + explicit_search_params: { + limit: { type: 'number' } } } } @@ -180,12 +178,10 @@ kitRoutes({ ```ts filename="vite.config.ts" kitRoutes({ - extend: { - PAGES: { - site_id: { - params: { - id: { type: 'string' } - } + PAGES: { + site_id: { + params: { + id: { type: 'string' } } } } @@ -208,23 +204,21 @@ kitRoutes({ ```ts filename="vite.config.ts" kitRoutes({ - extend: { - LINKS: { - // reference to a hardcoded link - twitter: { href: 'https://twitter.com/jycouet' }, - // ✅ Twitter - - // reference to link with params! (Like svelteKit routes add [ ] to specify params) - mailto: { href: 'mailto:[email]' }, - // ✅ Mail - - // reference to link with params & search params! - twitter_post: { - href: 'https://twitter.com/[name]/status/[id]', - explicit_search_params: { limit: { type: 'number' } } - } - // ✅ Twitter Post + LINKS: { + // reference to a hardcoded link + twitter: 'https://twitter.com/jycouet', + // ✅ Twitter + + // reference to link with params! (Like svelteKit routes add [ ] to specify params) + mailto: 'mailto:[email]', + // ✅ Mail + + // reference to link with params & search params! + twitter_post: { + href: 'https://twitter.com/[name]/status/[id]', + explicit_search_params: { limit: { type: 'number' } } } + // ✅ Twitter Post } }) ```