diff --git a/examples/handlers/avengers/heroes/[id]/$time/post.ts b/examples/handlers/avengers/heroes/[id]/[$time]/post.ts similarity index 100% rename from examples/handlers/avengers/heroes/[id]/$time/post.ts rename to examples/handlers/avengers/heroes/[id]/[$time]/post.ts diff --git a/examples/tsconfig.json b/examples/tsconfig.json index c61df63..c8d9020 100644 --- a/examples/tsconfig.json +++ b/examples/tsconfig.json @@ -48,12 +48,12 @@ /* Source Map Options */ // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ - "inlineSourceMap": true /* Emit a single file with source maps instead of having a separate file. */, + "inlineSourceMap": true /* Emit a single file with source maps instead of having a separate file. */ // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ /* Experimental Options */ // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ // "emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */ - "include": ["handlers/**/*.ts", "interface/**/*.ts", "server.ts"], - "exclude": ["example/**", "dist/**", "**/erdia_eg", "**/.configs/**", "**/docs/**/*"] - } + }, + "include": ["handlers/**/*.ts", "interface/**/*.ts", "server.ts"], + "exclude": ["example/**", "dist/**", "**/erdia_eg", "**/.configs/**", "**/docs/**/*"] } diff --git a/src/cli/commands/routeCommandSyncHandler.ts b/src/cli/commands/routeCommandSyncHandler.ts index 89eb79d..98b4657 100644 --- a/src/cli/commands/routeCommandSyncHandler.ts +++ b/src/cli/commands/routeCommandSyncHandler.ts @@ -45,7 +45,7 @@ export async function routeCommandSyncHandler(options: TRouteOption) { const table = createTable(routings.routes); if (routings.reasons.length > 0) { - ReasonContainer.it.add(...routings.reasons); + ReasonContainer.it.add(...ReasonContainer.aggregate(routings.reasons)); show('log', ReasonContainer.it.show()); } diff --git a/src/compilers/routes/getRouteHandler.ts b/src/compilers/routes/getRouteHandler.ts index ad60f96..1b68636 100644 --- a/src/compilers/routes/getRouteHandler.ts +++ b/src/compilers/routes/getRouteHandler.ts @@ -13,6 +13,7 @@ import { validateTypeReferences } from '#/compilers/validators/validateTypeRefer import type { IBaseOption } from '#/configs/interfaces/IBaseOption'; import { getImportConfigurationFromResolutions } from '#/generators/getImportConfigurationFromResolutions'; import { getExtraMethod } from '#/routes/extractors/getExtraMethod'; +import { getRouteMap } from '#/routes/extractors/getRouteMap'; import type { IRouteConfiguration } from '#/routes/interfaces/IRouteConfiguration'; import { getRoutePath } from '#/routes/paths/getRoutePath'; import { appendPostfixHash } from '#/tools/appendPostfixHash'; @@ -41,7 +42,8 @@ export async function getRouteHandler( const typeReferenceNodes = parameter == null ? [] : getTypeReferences(parameter); const isValidTypeReference = validateTypeReferences(sourceFile, typeReferenceNodes); const extraMethods = await getExtraMethod(sourceFile.getFilePath().toString()); - const routePathConfiguration = await getRoutePath(relativeFilePath); + const routePathMap = await getRouteMap(sourceFile.getFilePath().toString()); + const routePathConfiguration = await getRoutePath(relativeFilePath, routePathMap); const routeOptions = getRouteOptions(sourceFile); const importedModules = [ ...getResolvedImportedModules({ diff --git a/src/modules/ReasonContainer.ts b/src/modules/ReasonContainer.ts index 3320003..594cb87 100644 --- a/src/modules/ReasonContainer.ts +++ b/src/modules/ReasonContainer.ts @@ -20,6 +20,20 @@ export class ReasonContainer { ReasonContainer.#isBootstrap = true; } + static aggregate(reasons: IReason[]): IReason[] { + const aggregated = reasons.reduce>( + (aggregation, reason) => { + return { ...aggregation, [reason.type]: [...aggregation[reason.type], reason] }; + }, + { + error: [], + warn: [], + }, + ); + + return [...aggregated.warn, ...aggregated.error]; + } + #reasons: IReason[]; constructor() { diff --git a/src/modules/files/getIncludePatterns.ts b/src/modules/files/getIncludePatterns.ts index 5685cf0..0f1b169 100644 --- a/src/modules/files/getIncludePatterns.ts +++ b/src/modules/files/getIncludePatterns.ts @@ -1,5 +1,6 @@ import type { IBaseOption } from '#/configs/interfaces/IBaseOption'; import { getFileScope } from '#/modules/files/getFileScope'; +import { escape } from 'glob'; import { isDescendant } from 'my-node-fp'; import type * as tsm from 'ts-morph'; @@ -19,6 +20,7 @@ export function getIncludePatterns( } const filePaths = tsconfig.fileNames.filter((filePath) => isDescendant(projectDirPath, filePath)); + const escaped = filePaths.map((filePath) => escape(filePath)); - return filePaths; + return escaped; } diff --git a/src/routes/extractors/__tests__/route.map.test.ts b/src/routes/extractors/__tests__/route.map.test.ts index 775aed3..a2220e2 100644 --- a/src/routes/extractors/__tests__/route.map.test.ts +++ b/src/routes/extractors/__tests__/route.map.test.ts @@ -7,14 +7,14 @@ const emptyMap = new Map(); describe('getRouteMap', () => { it('successfully load map', async () => { - const dirPath = path.join(process.cwd(), 'examples', 'handlers', 'avengers', 'heroes', '[id]', '$time'); + const dirPath = path.join(process.cwd(), 'examples', 'handlers', 'avengers', 'heroes', '[id]', '[$time]'); const filePath = path.join(dirPath, 'post.ts'); const r01 = await getRouteMap(filePath); expect(r01).toMatchObject(map); }); it('exception', async () => { - const dirPath = path.join(process.cwd(), 'examples', 'handlers', 'avengers', 'heroes', '[id]', '$time'); + const dirPath = path.join(process.cwd(), 'examples', 'handlers', 'avengers', 'heroes', '[id]', '[$time]'); const filePath = path.join(dirPath, 'post333.ts333'); const r01 = await getRouteMap(filePath); expect(r01).toMatchObject(emptyMap); diff --git a/src/routes/paths/__tests__/evaluate.test.ts b/src/routes/paths/__tests__/evaluate.test.ts index c5c1d86..c452bfa 100644 --- a/src/routes/paths/__tests__/evaluate.test.ts +++ b/src/routes/paths/__tests__/evaluate.test.ts @@ -100,6 +100,26 @@ describe('evaluateRoutePath', () => { ]); }); + it('replace variable', () => { + const inp = '[$time]'; + const r01 = getRouteVariables(inp); + + expect(r01).toMatchObject([ + { matched: '[$time]', kind: CE_ROUTE_PATH_KIND.REPLACE, nullable: false, variable: 'time' }, + ]); + }); + + it('replace variables', () => { + const inp = '[$time]-[$name]'; + const r01 = getRouteVariables(inp); + + expect(r01).toMatchObject([ + { matched: '[$time]', kind: 4, nullable: false, variable: 'time' }, + { matched: '-', kind: 5, nullable: false, variable: '-' }, + { matched: '[$name]', kind: 4, nullable: false, variable: 'name' }, + ]); + }); + it('mixed multiple variable', () => { const inp = '[[kind]]-[[wildcard]]-[id]'; const r01 = getRouteVariables(inp); diff --git a/src/routes/paths/getRoutePath.ts b/src/routes/paths/getRoutePath.ts index 324888c..4fc901f 100644 --- a/src/routes/paths/getRoutePath.ts +++ b/src/routes/paths/getRoutePath.ts @@ -1,5 +1,4 @@ import { CE_ROUTE_INFO_KIND } from '#/routes/const-enum/CE_ROUTE_INFO_KIND'; -import { getRouteMap } from '#/routes/extractors/getRouteMap'; import type { IRoutePathSummary } from '#/routes/interfaces/IRoutePathSummary'; import { evaluteRouteVariable } from '#/routes/paths/evaluteRouteVariable'; import { getRouteVariables } from '#/routes/paths/getRouteVariables'; @@ -8,16 +7,19 @@ import { basenames, replaceSepToPosix, startSepAppend } from 'my-node-fp'; import path from 'node:path'; import urljoin from 'url-join'; -export async function getRoutePath(filePath: string): Promise { +export async function getRoutePath(filePath: string, map: Map): Promise { const urlPath = replaceSepToPosix(filePath); const filename = basenames(urlPath, ['.ts', '.mts', '.cts']); const dirname = path.dirname(urlPath); - const map = await getRouteMap(filePath); const evaluates = dirname .split(path.posix.sep) .filter((endpoint) => endpoint !== '') - .map((endpoint) => getRouteVariables(endpoint).map((variable) => evaluteRouteVariable(variable, map))); + .map((endpoint) => { + const variables = getRouteVariables(endpoint); + const evaluateds = variables.map((variable) => evaluteRouteVariable(variable, map)); + return evaluateds; + }); const joined = urljoin(evaluates.map((evaluate) => evaluate.join('')));