diff --git a/.changeset/fifty-ants-argue.md b/.changeset/fifty-ants-argue.md new file mode 100644 index 000000000..ddbd65356 --- /dev/null +++ b/.changeset/fifty-ants-argue.md @@ -0,0 +1,5 @@ +--- +'vite-plugin-kit-routes': patch +--- + +fix group routes management diff --git a/.changeset/popular-bears-tan.md b/.changeset/popular-bears-tan.md new file mode 100644 index 000000000..90d05e386 --- /dev/null +++ b/.changeset/popular-bears-tan.md @@ -0,0 +1,5 @@ +--- +'vite-plugin-kit-routes': patch +--- + +manage optional params diff --git a/.changeset/wet-insects-retire.md b/.changeset/wet-insects-retire.md new file mode 100644 index 000000000..9bd98544b --- /dev/null +++ b/.changeset/wet-insects-retire.md @@ -0,0 +1,5 @@ +--- +'vite-plugin-kit-routes': patch +--- + +manage matchers diff --git a/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts b/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts index 0fd15dc93..6b572702d 100644 --- a/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts +++ b/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts @@ -1,38 +1,50 @@ export const PAGES = { - _ROOT: (sp?: Record) => { + _ROOT: (sp?: Record) => { return `/${appendSp(sp)}` }, - contract: (sp?: Record) => { + contract: (sp?: Record) => { return `/contract${appendSp(sp)}` }, - contract_id: (params: { id: string }, sp?: Record) => { + contract_id: (params: { id: string | number }, sp?: Record) => { return `/contract/${params.id}${appendSp(sp)}` }, - site: (sp?: Record) => { + gp_logged_one: (sp?: Record) => { + return `/gp/one${appendSp(sp)}` + }, + gp_public_two: (sp?: Record) => { + return `/gp/two${appendSp(sp)}` + }, + lang_lang: (params?: { lang?: string | number }, sp?: Record) => { + return `/lang/${params?.lang ?? ''}${appendSp(sp)}` + }, + match_id_int: (params: { id: string | number }, sp?: Record) => { + return `/match/${params.id}${appendSp(sp)}` + }, + site: (sp?: Record) => { return `/site${appendSp(sp)}` }, - site_id: (params: { id: string }, sp?: Record) => { + site_id: (params: { id: string | number }, sp?: Record) => { return `/site/${params.id}${appendSp(sp)}` }, site_contract_siteId_contractId: ( - params: { siteId: string; contractId: string }, - sp?: Record, + params: { siteId: string | number; contractId: string | number }, + sp?: Record, ) => { return `/site_contract/${params.siteId}-${params.contractId}${appendSp(sp)}` }, } export const SERVERS = { - contract: (method: 'GET' | 'POST', sp?: Record) => { + contract: (method: 'GET' | 'POST', sp?: Record) => { return `/contract${appendSp(sp)}` }, - site: (method: 'GET', sp?: Record) => { + site: (method: 'GET', sp?: Record) => { return `/site${appendSp(sp)}` }, } export const ACTIONS = { - contract_id: (params: { id: string }) => { + contract_id: (params: { id: string | number }) => { return `/contract/${params.id}` }, site: (action: 'action1' | 'action2') => { @@ -40,13 +52,13 @@ export const ACTIONS = { }, site_contract_siteId_contractId: ( action: 'sendSomething', - params: { siteId: string; contractId: string }, + params: { siteId: string | number; contractId: string | number }, ) => { return `/site_contract/${params.siteId}-${params.contractId}?/${action}` }, } -const appendSp = (sp?: Record) => { +const appendSp = (sp?: Record) => { if (sp === undefined) return '' - return `?${new URLSearchParams(sp || {}).toString()}` + return `?${new URLSearchParams((sp as Record) || {}).toString()}` } diff --git a/packages/vite-plugin-kit-routes/src/lib/index.ts b/packages/vite-plugin-kit-routes/src/lib/index.ts index 6bac8ff61..f3f3bd387 100644 --- a/packages/vite-plugin-kit-routes/src/lib/index.ts +++ b/packages/vite-plugin-kit-routes/src/lib/index.ts @@ -42,7 +42,7 @@ export function formatKey(key: string, options?: Options) { return key } - const toReplace = ['/', '[', ']', '(', ')', '-'] + const toReplace = ['/', '[', ']', '(', ')', '-', '='] let toRet = key .split('') .map(c => (toReplace.includes(c) ? '_' : c)) @@ -74,6 +74,7 @@ const log = new Log('Kit Routes') const getFileKeys = ( lookFor: '+page.svelte' | '+page.server.ts' | '+server.ts', options?: Options, + withAppendSp?: boolean, ) => { const files = readdirSync(routes_path(), { recursive: true }) as string[] return ( @@ -83,29 +84,56 @@ const getFileKeys = ( // Keep the sorting at this level, it will make more sense .sort() .map(file => { - return { toUse: formatKey(file, options), original: file } + const paramsFromPath = extractParamsFromPath(file) + const href = file.replace(/\([^)]*\)/g, '').replace(/\/+/g, '/') + let toRet = href + paramsFromPath.params.forEach(c => { + const sMatcher = `${c.matcher ? `=${c.matcher}` : ''}` + if (c.optional) { + toRet = toRet.replaceAll(`[[${c.name + sMatcher}]]`, `\${params?.${c.name} ?? ''}`) + } else { + toRet = toRet.replaceAll(`[${c.name + sMatcher}]`, `\${params.${c.name}}`) + } + }) + return { + toUse: formatKey(file, options), + original: file, + paramsFromPath, + toReturn: `${toRet}${withAppendSp ? `\${appendSp(sp)}` : ``}`, + } }) ) } -function formatExtractParamsFromPath(file_path: string) { - return extractParamsFromPath(file_path).map(c => `${c}: string`) -} - -export function extractParamsFromPath(path: string): string[] { - // Use a regular expression to match parameter placeholders like '[param]' - const paramPattern = /\[([^\]]+)]/g +export function extractParamsFromPath(path: string): { + params: { name: string; optional: boolean; matcher?: string }[] + formatArgs: string[] + isAllOptional: boolean +} { + const paramPattern = /\[+([^\]]+)]+/g const params = [] let match while ((match = paramPattern.exec(path)) !== null) { - // The matched parameter name is in the first capturing group - params.push(match[1]) + // Check if it's surrounded by double brackets indicating an optional parameter + const isOptional = match[0].startsWith('[[') + const matcher = match[1].split('=') + if (matcher.length === 2) { + params.push({ + // name: `${matcher[0]}_${matcher[1]}`, + name: matcher[0], + optional: isOptional, + matcher: matcher[1], + }) + } else { + params.push({ name: match[1], optional: isOptional }) + } } - return params + const format = params.map(c => `${c.name}${c.optional ? '?' : ''}: string | number`) + const isAllOptional = params.filter(c => !c.optional).length === 0 + return { params, formatArgs: format, isAllOptional } } - const getMethodsOfServerFiles = (path: string) => { const code = read(`${routes_path()}/${path}/${'+server.ts'}`) @@ -164,55 +192,51 @@ const getActionsOfServerPages = (path: string) => { } const run = (options?: Options) => { - const pages = getFileKeys('+page.svelte', options) - const server = getFileKeys('+page.server.ts', options) - const files_server = getFileKeys('+server.ts', options) + const pages = getFileKeys('+page.svelte', options, true) + const servers = getFileKeys('+server.ts', options, true) + const pages_server = getFileKeys('+page.server.ts', options) const result = write(generated_file_path(options), [ `export const PAGES = { ${pages .map(key => { const params = [] - const pFormPath = formatExtractParamsFromPath(key.original) - if (pFormPath.length > 0) { - params.push(`params: {${pFormPath}}`) + if (key.paramsFromPath.params.length > 0) { + params.push( + `params${key.paramsFromPath.isAllOptional ? '?' : ''}: {${ + key.paramsFromPath.formatArgs + }}`, + ) } - params.push(`sp?: Record`) - return ( - `"${key.toUse}": (${params.join(', ')}) => ` + - `{ return \`${key.original - .replaceAll('[', '${params.') - .replaceAll(']', '}')}\${appendSp(sp)}\` }` - ) + params.push(`sp?: Record`) + return `"${key.toUse}": (${params.join(', ')}) => { return \`${key.toReturn}\` }` }) .join(',\n ')} } export const SERVERS = { - ${files_server + ${servers .map(key => { const params = [] const methods = getMethodsOfServerFiles(key.original) if (methods.length > 0) { params.push(`method: ${methods.map(c => `'${c}'`).join(' | ')}`) } - const pFormPath = formatExtractParamsFromPath(key.original) - if (pFormPath.length > 0) { - params.push(`params: {${pFormPath}}`) + if (key.paramsFromPath.params.length > 0) { + params.push( + `params${key.paramsFromPath.isAllOptional ? '?' : ''}: {${ + key.paramsFromPath.formatArgs + }}`, + ) } - params.push(`sp?: Record`) - return ( - `"${key.toUse}": (${params.join(', ')}) => ` + - `{ return \`${key.original - .replaceAll('[', '${params.') - .replaceAll(']', '}')}\${appendSp(sp)}\` }` - ) + params.push(`sp?: Record`) + return `"${key.toUse}": (${params.join(', ')}) => { return \`${key.toReturn}\` }` }) .join(',\n ')} } export const ACTIONS = { - ${server + ${pages_server .map(key => { const params = [] const actions = getActionsOfServerPages(key.original) @@ -222,26 +246,25 @@ export const ACTIONS = { } else { params.push(`action: ${actions.map(c => `'${c}'`).join(' | ')}`) actionsFormat = `?/\${action}` - // actionsFormat = `coucou` } - const pFormPath = formatExtractParamsFromPath(key.original) - if (pFormPath.length > 0) { - params.push(`params: {${pFormPath}}`) + if (key.paramsFromPath.params.length > 0) { + params.push( + `params${key.paramsFromPath.isAllOptional ? '?' : ''}: {${ + key.paramsFromPath.formatArgs + }}`, + ) } return ( `"${key.toUse}": (${params.join(', ')}) => ` + - `{ return \`` + - `${key.original.replaceAll('[', '${params.').replaceAll(']', '}')}` + - `${actionsFormat}` + - `\`}` + ` { return \`${key.toReturn}${actionsFormat}\` }` ) }) .join(',\n ')} } -const appendSp = (sp?: Record) => { +const appendSp = (sp?: Record) => { if (sp === undefined) return '' - return \`?\${new URLSearchParams(sp || {}).toString()}\` + return \`?\${new URLSearchParams(sp as Record || {}).toString()}\` } `, ]) 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 74eaf4d42..b72548a64 100644 --- a/packages/vite-plugin-kit-routes/src/lib/plugins.spec.ts +++ b/packages/vite-plugin-kit-routes/src/lib/plugins.spec.ts @@ -4,28 +4,84 @@ import { extractParamsFromPath, formatKey } from './index.js' describe('vite-plugin-kit-routes', () => { it('get id', async () => { expect(extractParamsFromPath('/site/[id]')).toMatchInlineSnapshot(` - [ - "id", - ] + { + "formatArgs": [ + "id: string | number", + ], + "isAllOptional": false, + "params": [ + { + "name": "id", + "optional": false, + }, + ], + } `) }) it('get params & id', async () => { expect(extractParamsFromPath('/site/[param]/[id]')).toMatchInlineSnapshot(` - [ - "param", - "id", - ] + { + "formatArgs": [ + "param: string | number", + "id: string | number", + ], + "isAllOptional": false, + "params": [ + { + "name": "param", + "optional": false, + }, + { + "name": "id", + "optional": false, + }, + ], + } `) }) it('get params & id', async () => { expect(extractParamsFromPath('/[param]site/[yop](group)/[id]')).toMatchInlineSnapshot(` - [ - "param", - "yop", - "id", - ] + { + "formatArgs": [ + "param: string | number", + "yop: string | number", + "id: string | number", + ], + "isAllOptional": false, + "params": [ + { + "name": "param", + "optional": false, + }, + { + "name": "yop", + "optional": false, + }, + { + "name": "id", + "optional": false, + }, + ], + } + `) + }) + + it('get optional param', async () => { + expect(extractParamsFromPath('/lang/[[lang]]')).toMatchInlineSnapshot(` + { + "formatArgs": [ + "lang?: string | number", + ], + "isAllOptional": true, + "params": [ + { + "name": "lang", + "optional": true, + }, + ], + } `) }) diff --git a/packages/vite-plugin-kit-routes/src/params/int.ts b/packages/vite-plugin-kit-routes/src/params/int.ts new file mode 100644 index 000000000..b8c1f374c --- /dev/null +++ b/packages/vite-plugin-kit-routes/src/params/int.ts @@ -0,0 +1,5 @@ +import type { ParamMatcher } from '@sveltejs/kit' + +export const match: ParamMatcher = param => { + return /^\d+$/.test(param) +} diff --git a/packages/vite-plugin-kit-routes/src/routes/+layout.svelte b/packages/vite-plugin-kit-routes/src/routes/+layout.svelte index edb17d01b..688b51392 100644 --- a/packages/vite-plugin-kit-routes/src/routes/+layout.svelte +++ b/packages/vite-plugin-kit-routes/src/routes/+layout.svelte @@ -13,12 +13,31 @@
diff --git a/packages/vite-plugin-kit-routes/src/routes/gp/(logged)/one/+page.svelte b/packages/vite-plugin-kit-routes/src/routes/gp/(logged)/one/+page.svelte new file mode 100644 index 000000000..94160746e --- /dev/null +++ b/packages/vite-plugin-kit-routes/src/routes/gp/(logged)/one/+page.svelte @@ -0,0 +1 @@ +

Logged One

diff --git a/packages/vite-plugin-kit-routes/src/routes/gp/(public)/two/+page.svelte b/packages/vite-plugin-kit-routes/src/routes/gp/(public)/two/+page.svelte new file mode 100644 index 000000000..feda6d904 --- /dev/null +++ b/packages/vite-plugin-kit-routes/src/routes/gp/(public)/two/+page.svelte @@ -0,0 +1 @@ +

Public Two

diff --git a/packages/vite-plugin-kit-routes/src/routes/lang/[[lang]]/+page.svelte b/packages/vite-plugin-kit-routes/src/routes/lang/[[lang]]/+page.svelte new file mode 100644 index 000000000..78f5961ca --- /dev/null +++ b/packages/vite-plugin-kit-routes/src/routes/lang/[[lang]]/+page.svelte @@ -0,0 +1,5 @@ + + +

Lang [{$page.params.lang}]

diff --git a/packages/vite-plugin-kit-routes/src/routes/match/[id=int]/+page.svelte b/packages/vite-plugin-kit-routes/src/routes/match/[id=int]/+page.svelte new file mode 100644 index 000000000..702f5640d --- /dev/null +++ b/packages/vite-plugin-kit-routes/src/routes/match/[id=int]/+page.svelte @@ -0,0 +1,5 @@ + + +

Match id [{$page.params.id}]

diff --git a/packages/vite-plugin-kit-routes/src/routes/site/+page.svelte b/packages/vite-plugin-kit-routes/src/routes/site/+page.svelte index c10c6a1a5..4171f95b9 100644 --- a/packages/vite-plugin-kit-routes/src/routes/site/+page.svelte +++ b/packages/vite-plugin-kit-routes/src/routes/site/+page.svelte @@ -1 +1,7 @@ + +

Sites

+ +
limit: {$page.url.searchParams.get('limit')}