From b9fc188ae64072983276cfbb6449f90014e85674 Mon Sep 17 00:00:00 2001 From: Andreas Fehn Date: Sun, 31 Dec 2023 11:52:29 +0100 Subject: [PATCH] Add array search params (#585) * allow array search params * make array search params more type safe * join array values by default * lint * export appendSp * extract string or undefined helper * default to split mode * expand array test routes * changeset * add array params to tests --- .changeset/afraid-hats-invent.md | 5 + .../vite-plugin-kit-routes/src/lib/ROUTES.ts | 65 ++++++++--- .../vite-plugin-kit-routes/src/lib/format.ts | 40 +++++-- .../vite-plugin-kit-routes/src/lib/plugin.ts | 89 +++++++++++---- .../src/lib/plugins.spec.ts | 14 +++ .../src/routes/+layout.svelte | 4 +- .../src/routes/spArray/+page.svelte | 10 ++ .../src/routes/spArrayComma/+page.svelte | 10 ++ .../src/test/ROUTES_base.ts | 54 ++++++--- .../src/test/ROUTES_format-object-path.ts | 64 +++++++---- .../ROUTES_format-object-path_shortened.ts | 62 +++++++--- .../src/test/ROUTES_format-object-symbol.ts | 70 ++++++++---- .../ROUTES_format-object-symbol_shortened.ts | 68 +++++++---- .../ROUTES_format-route-and-object-path.ts | 64 +++++++---- ..._format-route-and-object-path_shortened.ts | 62 +++++++--- .../ROUTES_format-route-and-object-symbol.ts | 64 +++++++---- ...ormat-route-and-object-symbol_shortened.ts | 62 +++++++--- .../src/test/ROUTES_format-route-path.ts | 64 +++++++---- .../ROUTES_format-route-path_shortened.ts | 62 +++++++--- .../src/test/ROUTES_format-route-symbol.ts | 64 +++++++---- .../ROUTES_format-route-symbol_shortened.ts | 62 +++++++--- .../src/test/ROUTES_format-variables.ts | 106 +++++++++++------- .../test/ROUTES_format-variables_shortened.ts | 106 +++++++++++------- .../src/test/ROUTES_post-update.ts | 54 ++++++--- .../vite-plugin-kit-routes/vite.config.ts | 6 + 25 files changed, 957 insertions(+), 374 deletions(-) create mode 100644 .changeset/afraid-hats-invent.md create mode 100644 packages/vite-plugin-kit-routes/src/routes/spArray/+page.svelte create mode 100644 packages/vite-plugin-kit-routes/src/routes/spArrayComma/+page.svelte diff --git a/.changeset/afraid-hats-invent.md b/.changeset/afraid-hats-invent.md new file mode 100644 index 00000000..b62e66e8 --- /dev/null +++ b/.changeset/afraid-hats-invent.md @@ -0,0 +1,5 @@ +--- +'vite-plugin-kit-routes': minor +--- + +support array search parameters diff --git a/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts b/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts index 8ea028ec..9a8d70b8 100644 --- a/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts +++ b/packages/vite-plugin-kit-routes/src/lib/ROUTES.ts @@ -61,8 +61,8 @@ const PAGES = { params.lang = params.lang ?? 'fr' params.id = params.id ?? 'Vienna' return `${params?.lang ? `/${params?.lang}` : ''}/site/${params.id}${appendSp({ - limit: params?.limit, - demo: params?.demo, + limit: params.limit, + demo: params.demo, })}` }, '/site_contract/[siteId]-[contractId]': (params: { @@ -73,7 +73,7 @@ const PAGES = { }) => { return `${params?.lang ? `/${params?.lang}` : ''}/site_contract/${params.siteId}-${ params.contractId - }${appendSp({ limit: params?.limit })}` + }${appendSp({ limit: params.limit })}` }, '/a/[...rest]/z': (params: { rest: (string | number)[] }) => { return `/a/${params.rest?.join('/')}/z` @@ -84,6 +84,12 @@ const PAGES = { '/sp': (sp?: Record) => { return `/sp${appendSp(sp)}` }, + '/spArray': (params: { ids: number[] }) => { + return `/spArray${appendSp({ ids: params.ids })}` + }, + '/spArrayComma': (params: { ids: number[] }) => { + return `/spArrayComma${appendSp({ ids: String(params.ids) })}` + }, } /** @@ -118,7 +124,7 @@ const ACTIONS = { limit?: number }) => { return `${params?.lang ? `/${params?.lang}` : ''}/contract/${params.id}${appendSp({ - limit: params?.limit, + limit: params.limit, })}` }, 'create /site': (params?: { @@ -154,7 +160,7 @@ const ACTIONS = { params.extra = params.extra ?? 'A' return `${params?.lang ? `/${params?.lang}` : ''}/site_contract/${params.siteId}-${ params.contractId - }?/send${appendSp({ extra: params?.extra }, '&')}` + }?/send${appendSp({ extra: params.extra }, '&')}` }, } @@ -169,25 +175,41 @@ const LINKS = { gravatar: (params: { str: string; s?: number; d?: 'retro' | 'identicon' }) => { params.s = params.s ?? 75 params.d = params.d ?? 'identicon' - return `https://www.gravatar.com/avatar/${params.str}${appendSp({ - s: params?.s, - d: params?.d, - })}` + return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params.s, d: params.d })}` }, } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = ( + sp?: Record, + prefix: '?' | '&' = '?', +) => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -209,6 +231,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -275,6 +305,8 @@ export type KIT_ROUTES = { '/lay/root-layout': never '/lay/skip': never '/sp': never + '/spArray': never + '/spArrayComma': never } SERVERS: { 'GET /server_func_get': never @@ -304,6 +336,7 @@ export type KIT_ROUTES = { siteId: never contractId: never rest: never + ids: never locale: never redirectTo: never extra: never diff --git a/packages/vite-plugin-kit-routes/src/lib/format.ts b/packages/vite-plugin-kit-routes/src/lib/format.ts index 8d5d4db1..54cb4ee9 100644 --- a/packages/vite-plugin-kit-routes/src/lib/format.ts +++ b/packages/vite-plugin-kit-routes/src/lib/format.ts @@ -19,18 +19,34 @@ export const format = (margin: { left?: number; top?: number; bottom?: number }, ) } -export const appendSp = `/** +export const appendSp = `type ParamValue = string | number | undefined + +/** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 \`\${prefix}\${formated}\` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return \`\${prefix}\${formatted}\` } return '' } @@ -50,6 +66,14 @@ export const currentSp = () => { record[key] = value } return record +} + +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) }` export const routeFn = `// route function helpers diff --git a/packages/vite-plugin-kit-routes/src/lib/plugin.ts b/packages/vite-plugin-kit-routes/src/lib/plugin.ts index 9f1da81f..4127dc60 100644 --- a/packages/vite-plugin-kit-routes/src/lib/plugin.ts +++ b/packages/vite-plugin-kit-routes/src/lib/plugin.ts @@ -234,6 +234,14 @@ export type ExtendParam = { export type ExplicitSearchParam = ExtendParam & { required?: boolean + /** + * Controls how arrays are converted into parameters. + * `join` will join elements with `,` into a single parameter. + * With `split` the parameter will be repeated for each element. + * + * @default 'split' + */ + arrayMode?: 'join' | 'split' } export const log = new Log('Kit Routes') @@ -521,26 +529,50 @@ export function buildMetadata( const params = [] + let isAllOptional = paramsFromPath.filter(c => !c.optional).length === 0 + const paramsReq = paramsFromPath.filter(c => !c.optional) + // custom search Param? - let explicit_search_params_to_function: string[] = [] + const explicit_search_params_to_function: [param: string, val: string][] = [] if (customConf.explicit_search_params) { + let someParamsHaveDefault = paramsFromPath.filter(c => c.default !== undefined).length > 0 + Object.entries(customConf.explicit_search_params).forEach(sp => { - paramsFromPath.push({ + const param = { name: sp[0], optional: !sp[1].required, type: sp[1].type, default: sp[1].default, isArray: false, - }) - explicit_search_params_to_function.push( - `${sp[0]}: params${sp[1].required ? '' : '?'}.${sp[0]}`, - ) + } + + paramsFromPath.push(param) + + if (sp[1].required) { + isAllOptional = false + paramsReq.push(param) + } + if (sp[1].default !== undefined) { + someParamsHaveDefault = true + } + }) + + let paramsIsOptional = isAllOptional + if (options.format_short && paramsReq.length === 1) { + paramsIsOptional = true + } + if (someParamsHaveDefault) { + paramsIsOptional = false + } + + Object.entries(customConf.explicit_search_params).forEach(sp => { + const val = `params${paramsIsOptional ? '?' : ''}.${sp[0]}` + + explicit_search_params_to_function.push([sp[0], getSpValue(val, sp[1])]) }) } - let isAllOptional = paramsFromPath.filter(c => !c.optional).length === 0 if (paramsFromPath.length > 0) { - const paramsReq = paramsFromPath.filter(c => !c.optional) if (options.format_short && paramsReq.length === 1) { // If only ONE required param, and we have only one, then let's put params optional isAllOptional = true @@ -550,10 +582,11 @@ export function buildMetadata( // If it's in the explicite and it's THIS one, let's change the array... if ( explicit_search_params_to_function.length === 1 && - explicit_search_params_to_function[0] === - `${paramsReq[0].name}: params${!paramsReq[0].optional ? '' : '?'}.${paramsReq[0].name}` + explicit_search_params_to_function[0][0] === paramsReq[0].name ) { - explicit_search_params_to_function = [paramsReq[0].name] + const sp = customConf.explicit_search_params![paramsReq[0].name] + + explicit_search_params_to_function[0][1] = getSpValue(paramsReq[0].name, sp) } else { // in params toRet = toRet.replaceAll(`params.${paramsReq[0].name}`, paramsReq[0].name) @@ -562,6 +595,10 @@ export function buildMetadata( params.push(`params${isAllOptional ? '?' : ''}: { ${formatArgs(paramsFromPath, options)} }`) } + const explicit_search_params = explicit_search_params_to_function + .map(([param, val]) => (param === val ? param : `${param}: ${val}`)) + .join(', ') + let fullSP = '' const wExtraSP = (customConf.extra_search_params === 'default' && useWithAppendSp) || @@ -574,11 +611,9 @@ export function buildMetadata( } else if (wExtraSP && customConf.explicit_search_params) { params.push(`sp?: Record`) // We want explicite to be stronger and override sp - fullSP = - `\${appendSp({ ...sp, ${explicit_search_params_to_function.join(', ')}` + - ` }${appendSpPrefix})}` + fullSP = `\${appendSp({ ...sp, ${explicit_search_params} }${appendSpPrefix})}` } else if (!wExtraSP && customConf.explicit_search_params) { - fullSP = `\${appendSp({ ${explicit_search_params_to_function.join(', ')} }${appendSpPrefix})}` + fullSP = `\${appendSp({ ${explicit_search_params} }${appendSpPrefix})}` } let paramsDefaults = paramsFromPath @@ -609,6 +644,18 @@ export function buildMetadata( return baseToReturn } +function getSpValue(rawValue: string, param: ExplicitSearchParam) { + if (param.arrayMode === 'join') { + if (param.required || param.default !== undefined) { + return `String(${rawValue})` + } + + return `StringOrUndefined(${rawValue})` + } + + return rawValue +} + export function extractParamsFromPath(path: string, o: Options): Param[] { const options = getDefaultOption(o) const paramPattern = /\[+([^\]]+)]+/g @@ -786,9 +833,9 @@ export const run = (atStart: boolean, o?: Options) => { if (allOk) { const result = write(options.generated_file_path, [ `/* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */${options?.path_base ? `\nimport { base } from '$app/paths'` : ''} `, @@ -804,7 +851,7 @@ ${c.files return ( `export const ${c.type.slice(0, -1)}_${key.keyToUse} = (${key.strParams}) => {` + `${format({ bottom: 0, top: 1, left: 2 }, key.strDefault)} - return ${key.strReturn} + return ${key.strReturn} }` ) } else { @@ -848,12 +895,12 @@ ${options?.format?.includes('object') ? `export ` : ``}` + // types `/** * 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, key of object will be typed! @@ -861,7 +908,7 @@ ${options?.format?.includes('object') ? `export ` : ``}` + * }) * \`\`\` */ -export type KIT_ROUTES = { +export type KIT_ROUTES = { ${objTypes .map(c => { return ` ${c.type}${arrayToRecord( 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 cca33a51..9ef24545 100644 --- a/packages/vite-plugin-kit-routes/src/lib/plugins.spec.ts +++ b/packages/vite-plugin-kit-routes/src/lib/plugins.spec.ts @@ -349,6 +349,12 @@ describe('run()', async () => { site_contract_siteId_contractId: { explicit_search_params: { limit: { type: 'number' } }, }, + spArray: { + explicit_search_params: { ids: { type: 'number[]', required: true } }, + }, + spArrayComma: { + explicit_search_params: { ids: { type: 'number[]', required: true, arrayMode: 'join' } }, + }, }, SERVERS: {}, ACTIONS: { @@ -824,6 +830,8 @@ describe('rmv Helper', () => { "lay/+layout.svelte", "page_server_woAction/+page.server.ts", "sp/+page.svelte", + "spArray/+page.svelte", + "spArrayComma/+page.svelte", ] `) }) @@ -870,6 +878,8 @@ describe('rmv Helper', () => { "lay/+layout.svelte", "page_server_woAction/+page.server.ts", "sp/+page.svelte", + "spArray/+page.svelte", + "spArrayComma/+page.svelte", ] `) @@ -909,6 +919,8 @@ describe('rmv Helper', () => { "lay/+layout.svelte", "page_server_woAction/+page.server.ts", "sp/+page.svelte", + "spArray/+page.svelte", + "spArrayComma/+page.svelte", ] `) }) @@ -951,6 +963,8 @@ describe('rmv Helper', () => { "lay/+layout.svelte", "page_server_woAction/+page.server.ts", "sp/+page.svelte", + "spArray/+page.svelte", + "spArrayComma/+page.svelte", ] `) }) diff --git a/packages/vite-plugin-kit-routes/src/routes/+layout.svelte b/packages/vite-plugin-kit-routes/src/routes/+layout.svelte index 3d1579c5..35e66727 100644 --- a/packages/vite-plugin-kit-routes/src/routes/+layout.svelte +++ b/packages/vite-plugin-kit-routes/src/routes/+layout.svelte @@ -82,7 +82,9 @@ Layout Skip
  • - Search Params + Search Params | + Array Search Params | + Array Search Params (comma-separated)
  • diff --git a/packages/vite-plugin-kit-routes/src/routes/spArray/+page.svelte b/packages/vite-plugin-kit-routes/src/routes/spArray/+page.svelte new file mode 100644 index 00000000..1bdd4369 --- /dev/null +++ b/packages/vite-plugin-kit-routes/src/routes/spArray/+page.svelte @@ -0,0 +1,10 @@ + + +

    Array Search Params

    + +
    {JSON.stringify({ raw, parsed }, null, 2)}
    diff --git a/packages/vite-plugin-kit-routes/src/routes/spArrayComma/+page.svelte b/packages/vite-plugin-kit-routes/src/routes/spArrayComma/+page.svelte new file mode 100644 index 00000000..4c468b5a --- /dev/null +++ b/packages/vite-plugin-kit-routes/src/routes/spArrayComma/+page.svelte @@ -0,0 +1,10 @@ + + +

    Array Search Params (comma-separated)

    + +
    {JSON.stringify({ raw, parsed }, null, 2)}
    diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_base.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_base.ts index 039335ff..4d121599 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_base.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_base.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ import { base } from '$app/paths' @@ -50,7 +50,9 @@ const PAGES = { "/lay/normal": `${base}/lay/normal`, "/lay/root-layout": `${base}/lay/root-layout`, "/lay/skip": `${base}/lay/skip`, - "/sp": `${base}/sp` + "/sp": `${base}/sp`, + "/spArray": `${base}/spArray`, + "/spArrayComma": `${base}/spArrayComma` } /** @@ -106,18 +108,34 @@ const LINKS = { } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -139,6 +157,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -168,12 +194,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -181,8 +207,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'id' | 'lang', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never } +export type KIT_ROUTES = { + PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'id' | 'lang', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never, '/spArray': never, '/spArrayComma': never } SERVERS: { 'GET /server_func_get': never, 'POST /server_func_post': never, 'GET /contract': 'lang', 'POST /contract': 'lang', 'GET /site': 'lang', 'GET /api/graphql': never, 'POST /api/graphql': never, 'GET /data/errors/[locale].json': 'locale' } ACTIONS: { 'default /contract/[id]': 'id' | 'lang', 'create /site': 'lang', 'update /site/[id]': 'id' | 'lang', 'delete /site/[id]': 'id' | 'lang', 'noSatisfies /site_contract': 'lang', 'send /site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang' } LINKS: Record diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-path.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-path.ts index ed6588f0..309ec9ed 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-path.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-path.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ export const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "/site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "/a/[...rest]/z": (params: { rest: (string | number)[] }) => { return `/a/${params.rest?.join('/')}/z` @@ -54,7 +54,9 @@ export const PAGES = { "/lay/normal": `/lay/normal`, "/lay/root-layout": `/lay/root-layout`, "/lay/skip": `/lay/skip`, - "/sp": `/sp` + "/sp": `/sp`, + "/spArray": `/spArray`, + "/spArrayComma": `/spArrayComma` } /** @@ -84,7 +86,7 @@ export const SERVERS = { */ export const ACTIONS = { "default /contract/[id]": (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params.limit })}` }, "create /site": (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` @@ -100,7 +102,7 @@ export const ACTIONS = { }, "send /site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -115,22 +117,38 @@ export const LINKS = { "gravatar": (params: { str: (string | number), s?: (number), d?: ("retro" | "identicon") }) => { params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -152,14 +170,22 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + /** * 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, key of object will be typed! @@ -167,8 +193,8 @@ export const currentSp = () => { * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never } +export type KIT_ROUTES = { + PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never, '/spArray': never, '/spArrayComma': never } SERVERS: { 'GET /server_func_get': never, 'POST /server_func_post': never, 'GET /contract': 'lang', 'POST /contract': 'lang', 'GET /site': 'lang', 'GET /api/graphql': never, 'POST /api/graphql': never, 'GET /data/errors/[locale].json': 'locale' } ACTIONS: { 'default /contract/[id]': 'id' | 'lang', 'create /site': 'lang', 'update /site/[id]': 'id' | 'lang', 'delete /site/[id]': 'id' | 'lang', 'noSatisfies /site_contract': 'lang', 'send /site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-path_shortened.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-path_shortened.ts index 543ce5ae..506ad881 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-path_shortened.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-path_shortened.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ export const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "/site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "/a/[...rest]/z": (rest: (string | number)[], params?: { }) => { return `/a/${rest?.join('/')}/z` @@ -54,7 +54,9 @@ export const PAGES = { "/lay/normal": `/lay/normal`, "/lay/root-layout": `/lay/root-layout`, "/lay/skip": `/lay/skip`, - "/sp": `/sp` + "/sp": `/sp`, + "/spArray": `/spArray`, + "/spArrayComma": `/spArrayComma` } /** @@ -100,7 +102,7 @@ export const ACTIONS = { }, "send /site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -116,22 +118,38 @@ export const LINKS = { params = params ?? {} params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -153,14 +171,22 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + /** * 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, key of object will be typed! @@ -168,8 +194,8 @@ export const currentSp = () => { * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'lang' | 'id', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'lang' | 'id', '/match/[id=int]': 'lang' | 'id', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never } +export type KIT_ROUTES = { + PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'lang' | 'id', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'lang' | 'id', '/match/[id=int]': 'lang' | 'id', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never, '/spArray': never, '/spArrayComma': never } SERVERS: { 'GET /server_func_get': never, 'POST /server_func_post': never, 'GET /contract': 'lang', 'POST /contract': 'lang', 'GET /site': 'lang', 'GET /api/graphql': never, 'POST /api/graphql': never, 'GET /data/errors/[locale].json': 'locale' } ACTIONS: { 'default /contract/[id]': 'lang' | 'id', 'create /site': 'lang', 'update /site/[id]': 'lang' | 'id', 'delete /site/[id]': 'lang' | 'id', 'noSatisfies /site_contract': 'lang', 'send /site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-symbol.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-symbol.ts index 93bd9d37..91a73e25 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-symbol.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-symbol.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ export const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "a_rest_z": (params: { rest: (string | number)[] }) => { return `/a/${params.rest?.join('/')}/z` @@ -54,7 +54,13 @@ export const PAGES = { "lay_normal": `/lay/normal`, "lay_root_layout": `/lay/root-layout`, "lay_skip": `/lay/skip`, - "sp": `/sp` + "sp": `/sp`, + "spArray": (params: { ids: (number[]) }) => { + return `/spArray${appendSp({ ids: params.ids })}` + }, + "spArrayComma": (params: { ids: (number[]) }) => { + return `/spArrayComma${appendSp({ ids: String(params.ids) })}` + } } /** @@ -84,7 +90,7 @@ export const SERVERS = { */ export const ACTIONS = { "default_contract_id": (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params.limit })}` }, "create_site": (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` @@ -100,7 +106,7 @@ export const ACTIONS = { }, "send_site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -115,22 +121,38 @@ export const LINKS = { "gravatar": (params: { str: (string | number), s?: (number), d?: ("retro" | "identicon") }) => { params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -152,14 +174,22 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + /** * 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, key of object will be typed! @@ -167,10 +197,10 @@ export const currentSp = () => { * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'id' | 'lang', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'id' | 'lang', 'match_id_int': 'id' | 'lang', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never } +export type KIT_ROUTES = { + PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'id' | 'lang', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'id' | 'lang', 'match_id_int': 'id' | 'lang', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never, 'spArray': never, 'spArrayComma': never } SERVERS: { 'GET_server_func_get': never, 'POST_server_func_post': never, 'GET_contract': 'lang', 'POST_contract': 'lang', 'GET_site': 'lang', 'GET_api_graphql': never, 'POST_api_graphql': never, 'GET_data_errors_locale_json': 'locale' } ACTIONS: { 'default_contract_id': 'id' | 'lang', 'create_site': 'lang', 'update_site_id': 'id' | 'lang', 'delete_site_id': 'id' | 'lang', 'noSatisfies_site_contract': 'lang', 'send_site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } - Params: { first: never, lang: never, id: never, limit: never, demo: never, siteId: never, contractId: never, rest: never, locale: never, extra: never, name: never, str: never, s: never, d: never } + Params: { first: never, lang: never, id: never, limit: never, demo: never, siteId: never, contractId: never, rest: never, ids: never, locale: never, extra: never, name: never, str: never, s: never, d: never } } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-symbol_shortened.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-symbol_shortened.ts index c3b80c1c..ef001da3 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-symbol_shortened.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-object-symbol_shortened.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ export const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "a_rest_z": (rest: (string | number)[], params?: { }) => { return `/a/${rest?.join('/')}/z` @@ -54,7 +54,13 @@ export const PAGES = { "lay_normal": `/lay/normal`, "lay_root_layout": `/lay/root-layout`, "lay_skip": `/lay/skip`, - "sp": `/sp` + "sp": `/sp`, + "spArray": (ids: (number[]), params?: { }) => { + return `/spArray${appendSp({ ids })}` + }, + "spArrayComma": (ids: (number[]), params?: { }) => { + return `/spArrayComma${appendSp({ ids: String(ids) })}` + } } /** @@ -100,7 +106,7 @@ export const ACTIONS = { }, "send_site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -116,22 +122,38 @@ export const LINKS = { params = params ?? {} params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -153,14 +175,22 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + /** * 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, key of object will be typed! @@ -168,10 +198,10 @@ export const currentSp = () => { * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'lang' | 'id', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'lang' | 'id', 'match_id_int': 'lang' | 'id', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never } +export type KIT_ROUTES = { + PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'lang' | 'id', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'lang' | 'id', 'match_id_int': 'lang' | 'id', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never, 'spArray': never, 'spArrayComma': never } SERVERS: { 'GET_server_func_get': never, 'POST_server_func_post': never, 'GET_contract': 'lang', 'POST_contract': 'lang', 'GET_site': 'lang', 'GET_api_graphql': never, 'POST_api_graphql': never, 'GET_data_errors_locale_json': 'locale' } ACTIONS: { 'default_contract_id': 'lang' | 'id', 'create_site': 'lang', 'update_site_id': 'lang' | 'id', 'delete_site_id': 'lang' | 'id', 'noSatisfies_site_contract': 'lang', 'send_site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } - Params: { first: never, lang: never, id: never, limit: never, demo: never, siteId: never, contractId: never, rest: never, locale: never, extra: never, name: never, str: never, s: never, d: never } + Params: { first: never, lang: never, id: never, limit: never, demo: never, siteId: never, contractId: never, rest: never, ids: never, locale: never, extra: never, name: never, str: never, s: never, d: never } } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-path.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-path.ts index 412598de..a05b5b56 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-path.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-path.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ export const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "/site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "/a/[...rest]/z": (params: { rest: (string | number)[] }) => { return `/a/${params.rest?.join('/')}/z` @@ -54,7 +54,9 @@ export const PAGES = { "/lay/normal": `/lay/normal`, "/lay/root-layout": `/lay/root-layout`, "/lay/skip": `/lay/skip`, - "/sp": `/sp` + "/sp": `/sp`, + "/spArray": `/spArray`, + "/spArrayComma": `/spArrayComma` } /** @@ -84,7 +86,7 @@ export const SERVERS = { */ export const ACTIONS = { "default /contract/[id]": (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params.limit })}` }, "create /site": (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` @@ -100,7 +102,7 @@ export const ACTIONS = { }, "send /site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -115,22 +117,38 @@ export const LINKS = { "gravatar": (params: { str: (string | number), s?: (number), d?: ("retro" | "identicon") }) => { params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -152,6 +170,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -181,12 +207,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -194,8 +220,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never } +export type KIT_ROUTES = { + PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never, '/spArray': never, '/spArrayComma': never } SERVERS: { 'GET /server_func_get': never, 'POST /server_func_post': never, 'GET /contract': 'lang', 'POST /contract': 'lang', 'GET /site': 'lang', 'GET /api/graphql': never, 'POST /api/graphql': never, 'GET /data/errors/[locale].json': 'locale' } ACTIONS: { 'default /contract/[id]': 'id' | 'lang', 'create /site': 'lang', 'update /site/[id]': 'id' | 'lang', 'delete /site/[id]': 'id' | 'lang', 'noSatisfies /site_contract': 'lang', 'send /site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-path_shortened.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-path_shortened.ts index 8e937489..4d84f4e1 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-path_shortened.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-path_shortened.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ export const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "/site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "/a/[...rest]/z": (rest: (string | number)[], params?: { }) => { return `/a/${rest?.join('/')}/z` @@ -54,7 +54,9 @@ export const PAGES = { "/lay/normal": `/lay/normal`, "/lay/root-layout": `/lay/root-layout`, "/lay/skip": `/lay/skip`, - "/sp": `/sp` + "/sp": `/sp`, + "/spArray": `/spArray`, + "/spArrayComma": `/spArrayComma` } /** @@ -100,7 +102,7 @@ export const ACTIONS = { }, "send /site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -116,22 +118,38 @@ export const LINKS = { params = params ?? {} params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -153,6 +171,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -182,12 +208,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -195,8 +221,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'lang' | 'id', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'lang' | 'id', '/match/[id=int]': 'lang' | 'id', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never } +export type KIT_ROUTES = { + PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'lang' | 'id', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'lang' | 'id', '/match/[id=int]': 'lang' | 'id', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never, '/spArray': never, '/spArrayComma': never } SERVERS: { 'GET /server_func_get': never, 'POST /server_func_post': never, 'GET /contract': 'lang', 'POST /contract': 'lang', 'GET /site': 'lang', 'GET /api/graphql': never, 'POST /api/graphql': never, 'GET /data/errors/[locale].json': 'locale' } ACTIONS: { 'default /contract/[id]': 'lang' | 'id', 'create /site': 'lang', 'update /site/[id]': 'lang' | 'id', 'delete /site/[id]': 'lang' | 'id', 'noSatisfies /site_contract': 'lang', 'send /site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-symbol.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-symbol.ts index b03bbe9d..c84f08e0 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-symbol.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-symbol.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ export const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "a_rest_z": (params: { rest: (string | number)[] }) => { return `/a/${params.rest?.join('/')}/z` @@ -54,7 +54,9 @@ export const PAGES = { "lay_normal": `/lay/normal`, "lay_root_layout": `/lay/root-layout`, "lay_skip": `/lay/skip`, - "sp": `/sp` + "sp": `/sp`, + "spArray": `/spArray`, + "spArrayComma": `/spArrayComma` } /** @@ -84,7 +86,7 @@ export const SERVERS = { */ export const ACTIONS = { "default contract_id": (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params.limit })}` }, "create site": (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` @@ -100,7 +102,7 @@ export const ACTIONS = { }, "send site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -115,22 +117,38 @@ export const LINKS = { "gravatar": (params: { str: (string | number), s?: (number), d?: ("retro" | "identicon") }) => { params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -152,6 +170,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -181,12 +207,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -194,8 +220,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'id' | 'lang', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'id' | 'lang', 'match_id_int': 'id' | 'lang', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never } +export type KIT_ROUTES = { + PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'id' | 'lang', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'id' | 'lang', 'match_id_int': 'id' | 'lang', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never, 'spArray': never, 'spArrayComma': never } SERVERS: { 'GET server_func_get': never, 'POST server_func_post': never, 'GET contract': 'lang', 'POST contract': 'lang', 'GET site': 'lang', 'GET api_graphql': never, 'POST api_graphql': never, 'GET data_errors_locale_json': 'locale' } ACTIONS: { 'default contract_id': 'id' | 'lang', 'create site': 'lang', 'update site_id': 'id' | 'lang', 'delete site_id': 'id' | 'lang', 'noSatisfies site_contract': 'lang', 'send site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-symbol_shortened.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-symbol_shortened.ts index 7b5c8e54..b3709397 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-symbol_shortened.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-and-object-symbol_shortened.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ export const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "a_rest_z": (rest: (string | number)[], params?: { }) => { return `/a/${rest?.join('/')}/z` @@ -54,7 +54,9 @@ export const PAGES = { "lay_normal": `/lay/normal`, "lay_root_layout": `/lay/root-layout`, "lay_skip": `/lay/skip`, - "sp": `/sp` + "sp": `/sp`, + "spArray": `/spArray`, + "spArrayComma": `/spArrayComma` } /** @@ -100,7 +102,7 @@ export const ACTIONS = { }, "send site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -116,22 +118,38 @@ export const LINKS = { params = params ?? {} params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -153,6 +171,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -182,12 +208,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -195,8 +221,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'lang' | 'id', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'lang' | 'id', 'match_id_int': 'lang' | 'id', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never } +export type KIT_ROUTES = { + PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'lang' | 'id', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'lang' | 'id', 'match_id_int': 'lang' | 'id', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never, 'spArray': never, 'spArrayComma': never } SERVERS: { 'GET server_func_get': never, 'POST server_func_post': never, 'GET contract': 'lang', 'POST contract': 'lang', 'GET site': 'lang', 'GET api_graphql': never, 'POST api_graphql': never, 'GET data_errors_locale_json': 'locale' } ACTIONS: { 'default contract_id': 'lang' | 'id', 'create site': 'lang', 'update site_id': 'lang' | 'id', 'delete site_id': 'lang' | 'id', 'noSatisfies site_contract': 'lang', 'send site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-path.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-path.ts index 71ee9f44..ff5bb71f 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-path.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-path.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "/site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "/a/[...rest]/z": (params: { rest: (string | number)[] }) => { return `/a/${params.rest?.join('/')}/z` @@ -54,7 +54,9 @@ const PAGES = { "/lay/normal": `/lay/normal`, "/lay/root-layout": `/lay/root-layout`, "/lay/skip": `/lay/skip`, - "/sp": `/sp` + "/sp": `/sp`, + "/spArray": `/spArray`, + "/spArrayComma": `/spArrayComma` } /** @@ -84,7 +86,7 @@ const SERVERS = { */ const ACTIONS = { "default /contract/[id]": (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params.limit })}` }, "create /site": (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` @@ -100,7 +102,7 @@ const ACTIONS = { }, "send /site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -115,22 +117,38 @@ const LINKS = { "gravatar": (params: { str: (string | number), s?: (number), d?: ("retro" | "identicon") }) => { params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -152,6 +170,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -181,12 +207,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -194,8 +220,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never } +export type KIT_ROUTES = { + PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never, '/spArray': never, '/spArrayComma': never } SERVERS: { 'GET /server_func_get': never, 'POST /server_func_post': never, 'GET /contract': 'lang', 'POST /contract': 'lang', 'GET /site': 'lang', 'GET /api/graphql': never, 'POST /api/graphql': never, 'GET /data/errors/[locale].json': 'locale' } ACTIONS: { 'default /contract/[id]': 'id' | 'lang', 'create /site': 'lang', 'update /site/[id]': 'id' | 'lang', 'delete /site/[id]': 'id' | 'lang', 'noSatisfies /site_contract': 'lang', 'send /site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-path_shortened.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-path_shortened.ts index 1e1cedc4..da28aba7 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-path_shortened.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-path_shortened.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "/site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "/a/[...rest]/z": (rest: (string | number)[], params?: { }) => { return `/a/${rest?.join('/')}/z` @@ -54,7 +54,9 @@ const PAGES = { "/lay/normal": `/lay/normal`, "/lay/root-layout": `/lay/root-layout`, "/lay/skip": `/lay/skip`, - "/sp": `/sp` + "/sp": `/sp`, + "/spArray": `/spArray`, + "/spArrayComma": `/spArrayComma` } /** @@ -100,7 +102,7 @@ const ACTIONS = { }, "send /site_contract/[siteId]-[contractId]": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -116,22 +118,38 @@ const LINKS = { params = params ?? {} params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -153,6 +171,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -182,12 +208,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -195,8 +221,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'lang' | 'id', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'lang' | 'id', '/match/[id=int]': 'lang' | 'id', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never } +export type KIT_ROUTES = { + PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'lang' | 'id', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'lang' | 'id', '/match/[id=int]': 'lang' | 'id', '/site': 'lang', '/site/[id]': 'lang' | 'id', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never, '/spArray': never, '/spArrayComma': never } SERVERS: { 'GET /server_func_get': never, 'POST /server_func_post': never, 'GET /contract': 'lang', 'POST /contract': 'lang', 'GET /site': 'lang', 'GET /api/graphql': never, 'POST /api/graphql': never, 'GET /data/errors/[locale].json': 'locale' } ACTIONS: { 'default /contract/[id]': 'lang' | 'id', 'create /site': 'lang', 'update /site/[id]': 'lang' | 'id', 'delete /site/[id]': 'lang' | 'id', 'noSatisfies /site_contract': 'lang', 'send /site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-symbol.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-symbol.ts index b7660fc7..c006b204 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-symbol.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-symbol.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "a_rest_z": (params: { rest: (string | number)[] }) => { return `/a/${params.rest?.join('/')}/z` @@ -54,7 +54,9 @@ const PAGES = { "lay_normal": `/lay/normal`, "lay_root_layout": `/lay/root-layout`, "lay_skip": `/lay/skip`, - "sp": `/sp` + "sp": `/sp`, + "spArray": `/spArray`, + "spArrayComma": `/spArrayComma` } /** @@ -84,7 +86,7 @@ const SERVERS = { */ const ACTIONS = { "default contract_id": (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params.limit })}` }, "create site": (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` @@ -100,7 +102,7 @@ const ACTIONS = { }, "send site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -115,22 +117,38 @@ const LINKS = { "gravatar": (params: { str: (string | number), s?: (number), d?: ("retro" | "identicon") }) => { params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -152,6 +170,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -181,12 +207,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -194,8 +220,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'id' | 'lang', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'id' | 'lang', 'match_id_int': 'id' | 'lang', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never } +export type KIT_ROUTES = { + PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'id' | 'lang', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'id' | 'lang', 'match_id_int': 'id' | 'lang', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never, 'spArray': never, 'spArrayComma': never } SERVERS: { 'GET server_func_get': never, 'POST server_func_post': never, 'GET contract': 'lang', 'POST contract': 'lang', 'GET site': 'lang', 'GET api_graphql': never, 'POST api_graphql': never, 'GET data_errors_locale_json': 'locale' } ACTIONS: { 'default contract_id': 'id' | 'lang', 'create site': 'lang', 'update site_id': 'id' | 'lang', 'delete site_id': 'id' | 'lang', 'noSatisfies site_contract': 'lang', 'send site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-symbol_shortened.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-symbol_shortened.ts index 8edea596..250c0f51 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-symbol_shortened.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-route-symbol_shortened.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -43,10 +43,10 @@ const PAGES = { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` }, "site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` }, "a_rest_z": (rest: (string | number)[], params?: { }) => { return `/a/${rest?.join('/')}/z` @@ -54,7 +54,9 @@ const PAGES = { "lay_normal": `/lay/normal`, "lay_root_layout": `/lay/root-layout`, "lay_skip": `/lay/skip`, - "sp": `/sp` + "sp": `/sp`, + "spArray": `/spArray`, + "spArrayComma": `/spArrayComma` } /** @@ -100,7 +102,7 @@ const ACTIONS = { }, "send site_contract_siteId_contractId": (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } } @@ -116,22 +118,38 @@ const LINKS = { params = params ?? {} params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params.s, d: params.d })}` } } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -153,6 +171,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -182,12 +208,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -195,8 +221,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'lang' | 'id', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'lang' | 'id', 'match_id_int': 'lang' | 'id', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never } +export type KIT_ROUTES = { + PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'lang' | 'id', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'lang' | 'id', 'match_id_int': 'lang' | 'id', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never, 'spArray': never, 'spArrayComma': never } SERVERS: { 'GET server_func_get': never, 'POST server_func_post': never, 'GET contract': 'lang', 'POST contract': 'lang', 'GET site': 'lang', 'GET api_graphql': never, 'POST api_graphql': never, 'GET data_errors_locale_json': 'locale' } ACTIONS: { 'default contract_id': 'lang' | 'id', 'create site': 'lang', 'update site_id': 'lang' | 'id', 'delete site_id': 'lang' | 'id', 'noSatisfies site_contract': 'lang', 'send site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-variables.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-variables.ts index cfbd831d..478d8cdb 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-variables.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-variables.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -12,48 +12,54 @@ export const PAGE__ROOT = `/` export const PAGE_subGroup = `/subGroup` export const PAGE_subGroup_user = `/subGroup/user` export const PAGE_subGroup2 = (params: { first: (string | number) }) => { - return `/subGroup2${appendSp({ first: params.first })}` + return `/subGroup2${appendSp({ first: params.first })}` } export const PAGE_contract = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }, sp?: Record) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract${appendSp(sp)}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract${appendSp(sp)}` } export const PAGE_contract_id = (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}` } export const PAGE_gp_one = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/gp/one` + return `${params?.lang ? `/${params?.lang}`: ''}/gp/one` } export const PAGE_gp_two = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/gp/two` + return `${params?.lang ? `/${params?.lang}`: ''}/gp/two` } export const PAGE_main = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/main` + return `${params?.lang ? `/${params?.lang}`: ''}/main` } export const PAGE_match_id_ab = (params: { id: (Parameters[0]), lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/match/${params.id}` + return `${params?.lang ? `/${params?.lang}`: ''}/match/${params.id}` } export const PAGE_match_id_int = (params: { id: (number), lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/match/${params.id}` + return `${params?.lang ? `/${params?.lang}`: ''}/match/${params.id}` } export const PAGE_site = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }, sp?: Record) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site${appendSp({ ...sp, limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site${appendSp({ ...sp, limit: params?.limit })}` } export const PAGE_site_id = (params?: { lang?: ('fr' | 'hu' | undefined), id?: (string), limit?: (number), demo?: (string) }) => { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` } export const PAGE_site_contract_siteId_contractId = (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` } export const PAGE_a_rest_z = (params: { rest: (string | number)[] }) => { - return `/a/${params.rest?.join('/')}/z` + return `/a/${params.rest?.join('/')}/z` } export const PAGE_lay_normal = `/lay/normal` export const PAGE_lay_root_layout = `/lay/root-layout` export const PAGE_lay_skip = `/lay/skip` export const PAGE_sp = `/sp` +export const PAGE_spArray = (params: { ids: (number[]) }) => { + return `/spArray${appendSp({ ids: params.ids })}` +} +export const PAGE_spArrayComma = (params: { ids: (number[]) }) => { + return `/spArrayComma${appendSp({ ids: String(params.ids) })}` +} /** * SERVERS @@ -61,41 +67,41 @@ export const PAGE_sp = `/sp` export const SERVER_GET_server_func_get = `/server_func_get` export const SERVER_POST_server_func_post = `/server_func_post` export const SERVER_GET_contract = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract` + return `${params?.lang ? `/${params?.lang}`: ''}/contract` } export const SERVER_POST_contract = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract` + return `${params?.lang ? `/${params?.lang}`: ''}/contract` } export const SERVER_GET_site = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site` + return `${params?.lang ? `/${params?.lang}`: ''}/site` } export const SERVER_GET_api_graphql = `/api/graphql` export const SERVER_POST_api_graphql = `/api/graphql` export const SERVER_GET_data_errors_locale_json = (params: { locale: (string | number) }) => { - return `/data/errors/${params.locale}.json` + return `/data/errors/${params.locale}.json` } /** * ACTIONS */ export const ACTION_default_contract_id = (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${params.id}${appendSp({ limit: params.limit })}` } export const ACTION_create_site = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` + return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` } export const ACTION_update_site_id = (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}?/update` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}?/update` } export const ACTION_delete_site_id = (params: { id: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}?/delete` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}?/delete` } export const ACTION_noSatisfies_site_contract = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract?/noSatisfies` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract?/noSatisfies` } export const ACTION_send_site_contract_siteId_contractId = (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } /** @@ -103,26 +109,42 @@ export const ACTION_send_site_contract_siteId_contractId = (params: { siteId: (s */ export const LINK_twitter = `https://twitter.com/jycouet` export const LINK_twitter_post = (params: { name: (string | number), id: (string | number) }) => { - return `https://twitter.com/${params.name}/status/${params.id}` + return `https://twitter.com/${params.name}/status/${params.id}` } export const LINK_gravatar = (params: { str: (string | number), s?: (number), d?: ("retro" | "identicon") }) => { params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${params.str}${appendSp({ s: params.s, d: params.d })}` } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -144,14 +166,22 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + /** * 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, key of object will be typed! @@ -159,10 +189,10 @@ export const currentSp = () => { * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'id' | 'lang', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'id' | 'lang', 'match_id_int': 'id' | 'lang', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never } +export type KIT_ROUTES = { + PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'id' | 'lang', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'id' | 'lang', 'match_id_int': 'id' | 'lang', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never, 'spArray': never, 'spArrayComma': never } SERVERS: { 'GET_server_func_get': never, 'POST_server_func_post': never, 'GET_contract': 'lang', 'POST_contract': 'lang', 'GET_site': 'lang', 'GET_api_graphql': never, 'POST_api_graphql': never, 'GET_data_errors_locale_json': 'locale' } ACTIONS: { 'default_contract_id': 'id' | 'lang', 'create_site': 'lang', 'update_site_id': 'id' | 'lang', 'delete_site_id': 'id' | 'lang', 'noSatisfies_site_contract': 'lang', 'send_site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } - Params: { first: never, lang: never, id: never, limit: never, demo: never, siteId: never, contractId: never, rest: never, locale: never, extra: never, name: never, str: never, s: never, d: never } + Params: { first: never, lang: never, id: never, limit: never, demo: never, siteId: never, contractId: never, rest: never, ids: never, locale: never, extra: never, name: never, str: never, s: never, d: never } } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-variables_shortened.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-variables_shortened.ts index 3993886b..1b0bbc3a 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_format-variables_shortened.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_format-variables_shortened.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -12,48 +12,54 @@ export const PAGE__ROOT = `/` export const PAGE_subGroup = `/subGroup` export const PAGE_subGroup_user = `/subGroup/user` export const PAGE_subGroup2 = (first: (string | number), params?: { }) => { - return `/subGroup2${appendSp({ first })}` + return `/subGroup2${appendSp({ first })}` } export const PAGE_contract = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }, sp?: Record) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract${appendSp(sp)}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract${appendSp(sp)}` } export const PAGE_contract_id = (id: (string | number), params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${id}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${id}` } export const PAGE_gp_one = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/gp/one` + return `${params?.lang ? `/${params?.lang}`: ''}/gp/one` } export const PAGE_gp_two = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/gp/two` + return `${params?.lang ? `/${params?.lang}`: ''}/gp/two` } export const PAGE_main = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/main` + return `${params?.lang ? `/${params?.lang}`: ''}/main` } export const PAGE_match_id_ab = (id: (Parameters[0]), params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/match/${id}` + return `${params?.lang ? `/${params?.lang}`: ''}/match/${id}` } export const PAGE_match_id_int = (id: (number), params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/match/${id}` + return `${params?.lang ? `/${params?.lang}`: ''}/match/${id}` } export const PAGE_site = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }, sp?: Record) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site${appendSp({ ...sp, limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site${appendSp({ ...sp, limit: params?.limit })}` } export const PAGE_site_id = (params?: { lang?: ('fr' | 'hu' | undefined), id?: (string), limit?: (number), demo?: (string) }) => { params = params ?? {} params.lang = params.lang ?? "fr"; params.id = params.id ?? "Vienna"; - return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params?.limit, demo: params?.demo })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${params.id}${appendSp({ limit: params.limit, demo: params.demo })}` } export const PAGE_site_contract_siteId_contractId = (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}${appendSp({ limit: params.limit })}` } export const PAGE_a_rest_z = (rest: (string | number)[], params?: { }) => { - return `/a/${rest?.join('/')}/z` + return `/a/${rest?.join('/')}/z` } export const PAGE_lay_normal = `/lay/normal` export const PAGE_lay_root_layout = `/lay/root-layout` export const PAGE_lay_skip = `/lay/skip` export const PAGE_sp = `/sp` +export const PAGE_spArray = (ids: (number[]), params?: { }) => { + return `/spArray${appendSp({ ids })}` +} +export const PAGE_spArrayComma = (ids: (number[]), params?: { }) => { + return `/spArrayComma${appendSp({ ids: String(ids) })}` +} /** * SERVERS @@ -61,41 +67,41 @@ export const PAGE_sp = `/sp` export const SERVER_GET_server_func_get = `/server_func_get` export const SERVER_POST_server_func_post = `/server_func_post` export const SERVER_GET_contract = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract` + return `${params?.lang ? `/${params?.lang}`: ''}/contract` } export const SERVER_POST_contract = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract` + return `${params?.lang ? `/${params?.lang}`: ''}/contract` } export const SERVER_GET_site = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site` + return `${params?.lang ? `/${params?.lang}`: ''}/site` } export const SERVER_GET_api_graphql = `/api/graphql` export const SERVER_POST_api_graphql = `/api/graphql` export const SERVER_GET_data_errors_locale_json = (locale: (string | number), params?: { }) => { - return `/data/errors/${locale}.json` + return `/data/errors/${locale}.json` } /** * ACTIONS */ export const ACTION_default_contract_id = (id: (string | number), params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string), limit?: (number) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/contract/${id}${appendSp({ limit: params?.limit })}` + return `${params?.lang ? `/${params?.lang}`: ''}/contract/${id}${appendSp({ limit: params?.limit })}` } export const ACTION_create_site = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` + return `${params?.lang ? `/${params?.lang}`: ''}/site?/create` } export const ACTION_update_site_id = (id: (string | number), params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site/${id}?/update` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${id}?/update` } export const ACTION_delete_site_id = (id: (string | number), params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site/${id}?/delete` + return `${params?.lang ? `/${params?.lang}`: ''}/site/${id}?/delete` } export const ACTION_noSatisfies_site_contract = (params?: { lang?: ('fr' | 'en' | 'hu' | 'at' | string) }) => { - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract?/noSatisfies` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract?/noSatisfies` } export const ACTION_send_site_contract_siteId_contractId = (params: { siteId: (string | number), contractId: (string | number), lang?: ('fr' | 'en' | 'hu' | 'at' | string), extra?: ('A' | 'B') }) => { params.extra = params.extra ?? "A"; - return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params?.extra }, '&')}` + return `${params?.lang ? `/${params?.lang}`: ''}/site_contract/${params.siteId}-${params.contractId}?/send${appendSp({ extra: params.extra }, '&')}` } /** @@ -103,27 +109,43 @@ export const ACTION_send_site_contract_siteId_contractId = (params: { siteId: (s */ export const LINK_twitter = `https://twitter.com/jycouet` export const LINK_twitter_post = (params: { name: (string | number), id: (string | number) }) => { - return `https://twitter.com/${params.name}/status/${params.id}` + return `https://twitter.com/${params.name}/status/${params.id}` } export const LINK_gravatar = (str: (string | number), params?: { s?: (number), d?: ("retro" | "identicon") }) => { params = params ?? {} params.s = params.s ?? 75; params.d = params.d ?? "identicon"; - return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params?.s, d: params?.d })}` + return `https://www.gravatar.com/avatar/${str}${appendSp({ s: params.s, d: params.d })}` } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -145,14 +167,22 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + /** * 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, key of object will be typed! @@ -160,10 +190,10 @@ export const currentSp = () => { * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'lang' | 'id', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'lang' | 'id', 'match_id_int': 'lang' | 'id', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never } +export type KIT_ROUTES = { + PAGES: { '_ROOT': never, 'subGroup': never, 'subGroup_user': never, 'subGroup2': never, 'contract': 'lang', 'contract_id': 'lang' | 'id', 'gp_one': 'lang', 'gp_two': 'lang', 'main': 'lang', 'match_id_ab': 'lang' | 'id', 'match_id_int': 'lang' | 'id', 'site': 'lang', 'site_id': 'lang' | 'id', 'site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang', 'a_rest_z': 'rest', 'lay_normal': never, 'lay_root_layout': never, 'lay_skip': never, 'sp': never, 'spArray': never, 'spArrayComma': never } SERVERS: { 'GET_server_func_get': never, 'POST_server_func_post': never, 'GET_contract': 'lang', 'POST_contract': 'lang', 'GET_site': 'lang', 'GET_api_graphql': never, 'POST_api_graphql': never, 'GET_data_errors_locale_json': 'locale' } ACTIONS: { 'default_contract_id': 'lang' | 'id', 'create_site': 'lang', 'update_site_id': 'lang' | 'id', 'delete_site_id': 'lang' | 'id', 'noSatisfies_site_contract': 'lang', 'send_site_contract_siteId_contractId': 'siteId' | 'contractId' | 'lang' } LINKS: { 'twitter': never, 'twitter_post': 'name' | 'id', 'gravatar': 'str' } - Params: { first: never, lang: never, id: never, limit: never, demo: never, siteId: never, contractId: never, rest: never, locale: never, extra: never, name: never, str: never, s: never, d: never } + Params: { first: never, lang: never, id: never, limit: never, demo: never, siteId: never, contractId: never, rest: never, ids: never, locale: never, extra: never, name: never, str: never, s: never, d: never } } diff --git a/packages/vite-plugin-kit-routes/src/test/ROUTES_post-update.ts b/packages/vite-plugin-kit-routes/src/test/ROUTES_post-update.ts index eac6b94e..10ee8f96 100644 --- a/packages/vite-plugin-kit-routes/src/test/ROUTES_post-update.ts +++ b/packages/vite-plugin-kit-routes/src/test/ROUTES_post-update.ts @@ -1,7 +1,7 @@ /* eslint-disable */ -/** +/** * This file was generated by 'vite-plugin-kit-routes' - * + * * >> DO NOT EDIT THIS FILE MANUALLY << */ @@ -49,7 +49,9 @@ const PAGES = { "/lay/normal": `/lay/normal`, "/lay/root-layout": `/lay/root-layout`, "/lay/skip": `/lay/skip`, - "/sp": `/sp` + "/sp": `/sp`, + "/spArray": `/spArray`, + "/spArrayComma": `/spArrayComma` } /** @@ -105,18 +107,34 @@ const LINKS = { } +type ParamValue = string | number | undefined + /** * Append search params to a string */ -const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { +export const appendSp = (sp?: Record, prefix: '?' | '&' = '?') => { 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 `${prefix}${formated}` + const params = new URLSearchParams() + const append = (n: string, v: ParamValue) => { + if (v !== undefined) { + params.append(n, String(v)) + } + } + + for (const [name, val] of Object.entries(sp)) { + if (Array.isArray(val)) { + for (const v of val) { + append(name, v) + } + } else { + append(name, val) + } + } + + const formatted = params.toString() + if (formatted) { + return `${prefix}${formatted}` } return '' } @@ -138,6 +156,14 @@ export const currentSp = () => { return record } +function StringOrUndefined(val: any) { + if (val === undefined) { + return undefined + } + + return String(val) +} + // route function helpers type NonFunctionKeys = { [K in keyof T]: T[K] extends Function ? never : K }[keyof T] type FunctionKeys = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] @@ -167,12 +193,12 @@ export function route(key: T, ...params: any[]): strin /** * 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, key of object will be typed! @@ -180,8 +206,8 @@ export function route(key: T, ...params: any[]): strin * }) * ``` */ -export type KIT_ROUTES = { - PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'id' | 'lang', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never } +export type KIT_ROUTES = { + PAGES: { '/': never, '/subGroup': never, '/subGroup/user': never, '/subGroup2': never, '/contract': 'lang', '/contract/[id]': 'id' | 'lang', '/gp/one': 'lang', '/gp/two': 'lang', '/main': 'lang', '/match/[id=ab]': 'id' | 'lang', '/match/[id=int]': 'id' | 'lang', '/site': 'lang', '/site/[id]': 'id' | 'lang', '/site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang', '/a/[...rest]/z': 'rest', '/lay/normal': never, '/lay/root-layout': never, '/lay/skip': never, '/sp': never, '/spArray': never, '/spArrayComma': never } SERVERS: { 'GET /server_func_get': never, 'POST /server_func_post': never, 'GET /contract': 'lang', 'POST /contract': 'lang', 'GET /site': 'lang', 'GET /api/graphql': never, 'POST /api/graphql': never, 'GET /data/errors/[locale].json': 'locale' } ACTIONS: { 'default /contract/[id]': 'id' | 'lang', 'create /site': 'lang', 'update /site/[id]': 'id' | 'lang', 'delete /site/[id]': 'id' | 'lang', 'noSatisfies /site_contract': 'lang', 'send /site_contract/[siteId]-[contractId]': 'siteId' | 'contractId' | 'lang' } LINKS: Record diff --git a/packages/vite-plugin-kit-routes/vite.config.ts b/packages/vite-plugin-kit-routes/vite.config.ts index 93094259..45c7ea64 100644 --- a/packages/vite-plugin-kit-routes/vite.config.ts +++ b/packages/vite-plugin-kit-routes/vite.config.ts @@ -59,6 +59,12 @@ export default defineConfig({ '/site_contract/[siteId]-[contractId]': { explicit_search_params: { limit: { type: 'number' } }, }, + '/spArray': { + explicit_search_params: { ids: { type: 'number[]', required: true } }, + }, + '/spArrayComma': { + explicit_search_params: { ids: { type: 'number[]', required: true, arrayMode: 'join' } }, + }, }, SERVERS: { // site: {