@mokup/shared 1.1.1 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/dist/config-core.cjs +9 -0
  2. package/dist/config-core.d.cts +4 -0
  3. package/dist/config-core.d.mts +4 -0
  4. package/dist/config-core.d.ts +4 -0
  5. package/dist/config-core.mjs +6 -0
  6. package/dist/config-utils.cjs +179 -0
  7. package/dist/config-utils.d.cts +62 -0
  8. package/dist/config-utils.d.mts +62 -0
  9. package/dist/config-utils.d.ts +62 -0
  10. package/dist/config-utils.mjs +171 -0
  11. package/dist/define-config.cjs +168 -0
  12. package/dist/define-config.d.cts +20 -0
  13. package/dist/define-config.d.mts +20 -0
  14. package/dist/define-config.d.ts +20 -0
  15. package/dist/define-config.mjs +166 -0
  16. package/dist/index.cjs +48 -0
  17. package/dist/index.d.cts +10 -98
  18. package/dist/index.d.mts +10 -98
  19. package/dist/index.d.ts +10 -98
  20. package/dist/index.mjs +18 -1
  21. package/dist/jsonc-utils.cjs +25 -0
  22. package/dist/jsonc-utils.d.cts +7 -0
  23. package/dist/jsonc-utils.d.mts +7 -0
  24. package/dist/jsonc-utils.d.ts +7 -0
  25. package/dist/jsonc-utils.mjs +23 -0
  26. package/dist/load-rules.cjs +39 -0
  27. package/dist/load-rules.d.cts +14 -0
  28. package/dist/load-rules.d.mts +14 -0
  29. package/dist/load-rules.d.ts +14 -0
  30. package/dist/load-rules.mjs +37 -0
  31. package/dist/mock-files.cjs +65 -0
  32. package/dist/mock-files.d.cts +10 -0
  33. package/dist/mock-files.d.mts +10 -0
  34. package/dist/mock-files.d.ts +10 -0
  35. package/dist/mock-files.mjs +61 -0
  36. package/dist/module-loader.cjs +93 -0
  37. package/dist/module-loader.d.cts +13 -0
  38. package/dist/module-loader.d.mts +13 -0
  39. package/dist/module-loader.d.ts +13 -0
  40. package/dist/module-loader.mjs +83 -0
  41. package/dist/path-utils.cjs +2 -2
  42. package/dist/playground-grouping.cjs +3 -3
  43. package/dist/route-constants.cjs +30 -0
  44. package/dist/route-constants.d.cts +7 -0
  45. package/dist/route-constants.d.mts +7 -0
  46. package/dist/route-constants.d.ts +7 -0
  47. package/dist/route-constants.mjs +24 -0
  48. package/dist/route-utils.cjs +126 -0
  49. package/dist/route-utils.d.cts +42 -0
  50. package/dist/route-utils.d.mts +42 -0
  51. package/dist/route-utils.d.ts +42 -0
  52. package/dist/route-utils.mjs +124 -0
  53. package/dist/scan-utils.cjs +39 -0
  54. package/dist/scan-utils.d.cts +114 -0
  55. package/dist/scan-utils.d.mts +114 -0
  56. package/dist/scan-utils.d.ts +114 -0
  57. package/dist/scan-utils.mjs +34 -0
  58. package/package.json +67 -19
@@ -0,0 +1,83 @@
1
+ import { writeFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { tmpdir } from 'node:os';
4
+ import process from 'node:process';
5
+ import { pathToFileURL } from 'node:url';
6
+ import { resolve, extname } from 'pathe';
7
+
8
+ function createTsxConfigFile(options) {
9
+ const config = {
10
+ compilerOptions: {
11
+ baseUrl: options.baseUrl,
12
+ paths: options.paths
13
+ }
14
+ };
15
+ const configPath = options.fileName ?? resolve(tmpdir(), `mokup-tsx-${process.pid}.json`);
16
+ writeFileSync(configPath, `${JSON.stringify(config, null, 2)}
17
+ `, "utf8");
18
+ return configPath;
19
+ }
20
+ let sourceMapsEnabled = false;
21
+ let tsxRegisterPromise = null;
22
+ let tsxRegisteredConfig = null;
23
+ function resetModuleLoaderForTests() {
24
+ sourceMapsEnabled = false;
25
+ tsxRegisterPromise = null;
26
+ tsxRegisteredConfig = null;
27
+ }
28
+ function ensureSourceMapsEnabled() {
29
+ if (sourceMapsEnabled) {
30
+ return;
31
+ }
32
+ const setSourceMapsEnabled = process.setSourceMapsEnabled;
33
+ if (typeof setSourceMapsEnabled === "function") {
34
+ setSourceMapsEnabled(true);
35
+ }
36
+ sourceMapsEnabled = true;
37
+ }
38
+ async function ensureTsxRegister(tsconfigPath) {
39
+ const desired = tsconfigPath ?? null;
40
+ if (tsxRegisterPromise) {
41
+ await tsxRegisterPromise;
42
+ if (desired && tsxRegisteredConfig !== desired) {
43
+ tsxRegisterPromise = (async () => {
44
+ ensureSourceMapsEnabled();
45
+ const { register } = await import('tsx/esm/api');
46
+ register({ tsconfig: desired });
47
+ tsxRegisteredConfig = desired;
48
+ })();
49
+ await tsxRegisterPromise;
50
+ }
51
+ return tsxRegisterPromise;
52
+ }
53
+ tsxRegisterPromise = (async () => {
54
+ ensureSourceMapsEnabled();
55
+ const { register } = await import('tsx/esm/api');
56
+ if (desired) {
57
+ register({ tsconfig: desired });
58
+ tsxRegisteredConfig = desired;
59
+ } else {
60
+ register();
61
+ tsxRegisteredConfig = null;
62
+ }
63
+ })();
64
+ return tsxRegisterPromise;
65
+ }
66
+ async function loadModule(file, options) {
67
+ const ext = extname(file).toLowerCase();
68
+ if (ext === ".cjs") {
69
+ const require = createRequire(import.meta.url);
70
+ delete require.cache[file];
71
+ return require(file);
72
+ }
73
+ if (ext === ".js" || ext === ".mjs") {
74
+ return import(`${pathToFileURL(file).href}?t=${Date.now()}`);
75
+ }
76
+ if (ext === ".ts") {
77
+ await ensureTsxRegister(options?.tsconfigPath ?? null);
78
+ return import(`${pathToFileURL(file).href}?t=${Date.now()}`);
79
+ }
80
+ return null;
81
+ }
82
+
83
+ export { createTsxConfigFile, ensureTsxRegister, loadModule, resetModuleLoaderForTests };
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- const node_process = require('node:process');
3
+ const process = require('node:process');
4
4
  const pathe = require('pathe');
5
5
 
6
6
  function isWindowsLikePath(normalized) {
7
- return node_process.platform === "win32" || /^[a-z]:\//i.test(normalized) || normalized.startsWith("//");
7
+ return process.platform === "win32" || /^[a-z]:\//i.test(normalized) || normalized.startsWith("//");
8
8
  }
9
9
  function toPosix(value) {
10
10
  return value.replace(/\\/g, "/");
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const node_process = require('node:process');
3
+ const process = require('node:process');
4
4
  const pathe = require('pathe');
5
5
  const pathUtils = require('./path-utils.cjs');
6
6
 
@@ -14,7 +14,7 @@ function isAncestor(parent, child) {
14
14
  }
15
15
  function resolveGroupRoot(dirs, serverRoot) {
16
16
  if (!dirs || dirs.length === 0) {
17
- return serverRoot ?? node_process.cwd();
17
+ return serverRoot ?? process.cwd();
18
18
  }
19
19
  if (serverRoot) {
20
20
  const normalizedRoot = normalizePath(serverRoot);
@@ -38,7 +38,7 @@ function resolveGroupRoot(dirs, serverRoot) {
38
38
  }
39
39
  }
40
40
  if (!common || common === "/") {
41
- return serverRoot ?? node_process.cwd();
41
+ return serverRoot ?? process.cwd();
42
42
  }
43
43
  return common;
44
44
  }
@@ -0,0 +1,30 @@
1
+ 'use strict';
2
+
3
+ const methodSet = /* @__PURE__ */ new Set([
4
+ "GET",
5
+ "POST",
6
+ "PUT",
7
+ "PATCH",
8
+ "DELETE",
9
+ "OPTIONS",
10
+ "HEAD"
11
+ ]);
12
+ const methodSuffixSet = new Set(
13
+ Array.from(methodSet, (method) => method.toLowerCase())
14
+ );
15
+ const supportedExtensions = /* @__PURE__ */ new Set([
16
+ ".json",
17
+ ".jsonc",
18
+ ".ts",
19
+ ".js",
20
+ ".mjs",
21
+ ".cjs"
22
+ ]);
23
+ const configExtensions = [".ts", ".js", ".mjs", ".cjs"];
24
+ const jsonExtensions = /* @__PURE__ */ new Set([".json", ".jsonc"]);
25
+
26
+ exports.configExtensions = configExtensions;
27
+ exports.jsonExtensions = jsonExtensions;
28
+ exports.methodSet = methodSet;
29
+ exports.methodSuffixSet = methodSuffixSet;
30
+ exports.supportedExtensions = supportedExtensions;
@@ -0,0 +1,7 @@
1
+ declare const methodSet: Set<string>;
2
+ declare const methodSuffixSet: Set<string>;
3
+ declare const supportedExtensions: Set<string>;
4
+ declare const configExtensions: readonly [".ts", ".js", ".mjs", ".cjs"];
5
+ declare const jsonExtensions: Set<string>;
6
+
7
+ export { configExtensions, jsonExtensions, methodSet, methodSuffixSet, supportedExtensions };
@@ -0,0 +1,7 @@
1
+ declare const methodSet: Set<string>;
2
+ declare const methodSuffixSet: Set<string>;
3
+ declare const supportedExtensions: Set<string>;
4
+ declare const configExtensions: readonly [".ts", ".js", ".mjs", ".cjs"];
5
+ declare const jsonExtensions: Set<string>;
6
+
7
+ export { configExtensions, jsonExtensions, methodSet, methodSuffixSet, supportedExtensions };
@@ -0,0 +1,7 @@
1
+ declare const methodSet: Set<string>;
2
+ declare const methodSuffixSet: Set<string>;
3
+ declare const supportedExtensions: Set<string>;
4
+ declare const configExtensions: readonly [".ts", ".js", ".mjs", ".cjs"];
5
+ declare const jsonExtensions: Set<string>;
6
+
7
+ export { configExtensions, jsonExtensions, methodSet, methodSuffixSet, supportedExtensions };
@@ -0,0 +1,24 @@
1
+ const methodSet = /* @__PURE__ */ new Set([
2
+ "GET",
3
+ "POST",
4
+ "PUT",
5
+ "PATCH",
6
+ "DELETE",
7
+ "OPTIONS",
8
+ "HEAD"
9
+ ]);
10
+ const methodSuffixSet = new Set(
11
+ Array.from(methodSet, (method) => method.toLowerCase())
12
+ );
13
+ const supportedExtensions = /* @__PURE__ */ new Set([
14
+ ".json",
15
+ ".jsonc",
16
+ ".ts",
17
+ ".js",
18
+ ".mjs",
19
+ ".cjs"
20
+ ]);
21
+ const configExtensions = [".ts", ".js", ".mjs", ".cjs"];
22
+ const jsonExtensions = /* @__PURE__ */ new Set([".json", ".jsonc"]);
23
+
24
+ export { configExtensions, jsonExtensions, methodSet, methodSuffixSet, supportedExtensions };
@@ -0,0 +1,126 @@
1
+ 'use strict';
2
+
3
+ const pathUtils = require('./path-utils.cjs');
4
+ const pathe = require('pathe');
5
+ const routeConstants = require('./route-constants.cjs');
6
+ const scanUtils = require('./scan-utils.cjs');
7
+ require('node:process');
8
+
9
+ function createRouteUtils(params) {
10
+ const { parseRouteTemplate, compareRouteScore } = params;
11
+ function resolveTemplate(template, prefix) {
12
+ const normalized = template.startsWith("/") ? template : `/${template}`;
13
+ if (!prefix) {
14
+ return normalized;
15
+ }
16
+ const normalizedPrefix = scanUtils.normalizePrefix(prefix);
17
+ if (!normalizedPrefix) {
18
+ return normalized;
19
+ }
20
+ if (normalized === normalizedPrefix || normalized.startsWith(`${normalizedPrefix}/`)) {
21
+ return normalized;
22
+ }
23
+ if (normalized === "/") {
24
+ return `${normalizedPrefix}/`;
25
+ }
26
+ return `${normalizedPrefix}${normalized}`;
27
+ }
28
+ function stripMethodSuffix(base) {
29
+ const segments = base.split(".");
30
+ const last = segments.at(-1);
31
+ if (last && routeConstants.methodSuffixSet.has(last.toLowerCase())) {
32
+ segments.pop();
33
+ return {
34
+ name: segments.join("."),
35
+ method: last.toUpperCase()
36
+ };
37
+ }
38
+ return {
39
+ name: base,
40
+ method: void 0
41
+ };
42
+ }
43
+ function deriveRouteFromFile(file, rootDir, warn) {
44
+ const rel = pathUtils.toPosix(pathe.relative(rootDir, file));
45
+ const ext = pathe.extname(rel);
46
+ const withoutExt = rel.slice(0, rel.length - ext.length);
47
+ const dir = pathe.dirname(withoutExt);
48
+ const base = pathe.basename(withoutExt);
49
+ const { name, method } = stripMethodSuffix(base);
50
+ const resolvedMethod = method ?? (routeConstants.jsonExtensions.has(ext) ? "GET" : void 0);
51
+ if (!resolvedMethod) {
52
+ warn?.(`Skip mock without method suffix: ${file}`);
53
+ return null;
54
+ }
55
+ if (!name) {
56
+ warn?.(`Skip mock with empty route name: ${file}`);
57
+ return null;
58
+ }
59
+ const joined = dir === "." ? name : pathe.join(dir, name);
60
+ const segments = pathUtils.toPosix(joined).split("/");
61
+ if (segments.at(-1) === "index") {
62
+ segments.pop();
63
+ }
64
+ const template = segments.length === 0 ? "/" : `/${segments.join("/")}`;
65
+ const parsed = parseRouteTemplate(template);
66
+ if (parsed.errors.length > 0) {
67
+ for (const error of parsed.errors) {
68
+ warn?.(`${error} in ${file}`);
69
+ }
70
+ return null;
71
+ }
72
+ for (const warning of parsed.warnings) {
73
+ warn?.(`${warning} in ${file}`);
74
+ }
75
+ return {
76
+ template: parsed.template,
77
+ method: resolvedMethod,
78
+ tokens: parsed.tokens,
79
+ score: parsed.score
80
+ };
81
+ }
82
+ function resolveRule(input) {
83
+ const method = input.derivedMethod;
84
+ if (!method) {
85
+ input.warn?.(`Skip mock without method suffix: ${input.file}`);
86
+ return null;
87
+ }
88
+ const template = resolveTemplate(input.derivedTemplate, input.prefix);
89
+ const parsed = parseRouteTemplate(template);
90
+ if (parsed.errors.length > 0) {
91
+ for (const error of parsed.errors) {
92
+ input.warn?.(`${error} in ${input.file}`);
93
+ }
94
+ return null;
95
+ }
96
+ for (const warning of parsed.warnings) {
97
+ input.warn?.(`${warning} in ${input.file}`);
98
+ }
99
+ const base = {
100
+ template: parsed.template,
101
+ method,
102
+ tokens: parsed.tokens,
103
+ score: parsed.score
104
+ };
105
+ return input.build ? input.build(base, input.rule) : base;
106
+ }
107
+ function sortRoutes(routes) {
108
+ return routes.sort((a, b) => {
109
+ if (a.method !== b.method) {
110
+ return a.method.localeCompare(b.method);
111
+ }
112
+ const scoreCompare = compareRouteScore(a.score, b.score);
113
+ if (scoreCompare !== 0) {
114
+ return scoreCompare;
115
+ }
116
+ return a.template.localeCompare(b.template);
117
+ });
118
+ }
119
+ return {
120
+ deriveRouteFromFile,
121
+ resolveRule,
122
+ sortRoutes
123
+ };
124
+ }
125
+
126
+ exports.createRouteUtils = createRouteUtils;
@@ -0,0 +1,42 @@
1
+ interface RouteParserResult<TToken = unknown> {
2
+ template: string;
3
+ tokens: TToken[];
4
+ score: number[];
5
+ errors: string[];
6
+ warnings: string[];
7
+ }
8
+ type RouteParser<TToken = unknown> = (template: string) => RouteParserResult<TToken>;
9
+ type RouteScoreComparator = (a: number[], b: number[]) => number;
10
+ interface DerivedRoute<TToken = unknown> {
11
+ template: string;
12
+ method: string;
13
+ tokens: TToken[];
14
+ score: number[];
15
+ }
16
+ declare function createRouteUtils<TToken = unknown, TRule extends {
17
+ handler: unknown;
18
+ } = {
19
+ handler: unknown;
20
+ }>(params: {
21
+ parseRouteTemplate: RouteParser<TToken>;
22
+ compareRouteScore: RouteScoreComparator;
23
+ }): {
24
+ deriveRouteFromFile: (file: string, rootDir: string, warn?: (message: string) => void) => DerivedRoute<TToken> | null;
25
+ resolveRule: <TOutput = DerivedRoute<TToken>>(input: {
26
+ rule: TRule;
27
+ derivedTemplate: string;
28
+ derivedMethod?: string;
29
+ prefix: string;
30
+ file: string;
31
+ warn?: (message: string) => void;
32
+ build?: (base: DerivedRoute<TToken>, rule: TRule) => TOutput;
33
+ }) => TOutput | null;
34
+ sortRoutes: <TRoute extends {
35
+ method: string;
36
+ score: number[];
37
+ template: string;
38
+ }>(routes: TRoute[]) => TRoute[];
39
+ };
40
+
41
+ export { createRouteUtils };
42
+ export type { DerivedRoute, RouteParser, RouteParserResult, RouteScoreComparator };
@@ -0,0 +1,42 @@
1
+ interface RouteParserResult<TToken = unknown> {
2
+ template: string;
3
+ tokens: TToken[];
4
+ score: number[];
5
+ errors: string[];
6
+ warnings: string[];
7
+ }
8
+ type RouteParser<TToken = unknown> = (template: string) => RouteParserResult<TToken>;
9
+ type RouteScoreComparator = (a: number[], b: number[]) => number;
10
+ interface DerivedRoute<TToken = unknown> {
11
+ template: string;
12
+ method: string;
13
+ tokens: TToken[];
14
+ score: number[];
15
+ }
16
+ declare function createRouteUtils<TToken = unknown, TRule extends {
17
+ handler: unknown;
18
+ } = {
19
+ handler: unknown;
20
+ }>(params: {
21
+ parseRouteTemplate: RouteParser<TToken>;
22
+ compareRouteScore: RouteScoreComparator;
23
+ }): {
24
+ deriveRouteFromFile: (file: string, rootDir: string, warn?: (message: string) => void) => DerivedRoute<TToken> | null;
25
+ resolveRule: <TOutput = DerivedRoute<TToken>>(input: {
26
+ rule: TRule;
27
+ derivedTemplate: string;
28
+ derivedMethod?: string;
29
+ prefix: string;
30
+ file: string;
31
+ warn?: (message: string) => void;
32
+ build?: (base: DerivedRoute<TToken>, rule: TRule) => TOutput;
33
+ }) => TOutput | null;
34
+ sortRoutes: <TRoute extends {
35
+ method: string;
36
+ score: number[];
37
+ template: string;
38
+ }>(routes: TRoute[]) => TRoute[];
39
+ };
40
+
41
+ export { createRouteUtils };
42
+ export type { DerivedRoute, RouteParser, RouteParserResult, RouteScoreComparator };
@@ -0,0 +1,42 @@
1
+ interface RouteParserResult<TToken = unknown> {
2
+ template: string;
3
+ tokens: TToken[];
4
+ score: number[];
5
+ errors: string[];
6
+ warnings: string[];
7
+ }
8
+ type RouteParser<TToken = unknown> = (template: string) => RouteParserResult<TToken>;
9
+ type RouteScoreComparator = (a: number[], b: number[]) => number;
10
+ interface DerivedRoute<TToken = unknown> {
11
+ template: string;
12
+ method: string;
13
+ tokens: TToken[];
14
+ score: number[];
15
+ }
16
+ declare function createRouteUtils<TToken = unknown, TRule extends {
17
+ handler: unknown;
18
+ } = {
19
+ handler: unknown;
20
+ }>(params: {
21
+ parseRouteTemplate: RouteParser<TToken>;
22
+ compareRouteScore: RouteScoreComparator;
23
+ }): {
24
+ deriveRouteFromFile: (file: string, rootDir: string, warn?: (message: string) => void) => DerivedRoute<TToken> | null;
25
+ resolveRule: <TOutput = DerivedRoute<TToken>>(input: {
26
+ rule: TRule;
27
+ derivedTemplate: string;
28
+ derivedMethod?: string;
29
+ prefix: string;
30
+ file: string;
31
+ warn?: (message: string) => void;
32
+ build?: (base: DerivedRoute<TToken>, rule: TRule) => TOutput;
33
+ }) => TOutput | null;
34
+ sortRoutes: <TRoute extends {
35
+ method: string;
36
+ score: number[];
37
+ template: string;
38
+ }>(routes: TRoute[]) => TRoute[];
39
+ };
40
+
41
+ export { createRouteUtils };
42
+ export type { DerivedRoute, RouteParser, RouteParserResult, RouteScoreComparator };
@@ -0,0 +1,124 @@
1
+ import { toPosix } from './path-utils.mjs';
2
+ import { relative, extname, dirname, basename, join } from 'pathe';
3
+ import { jsonExtensions, methodSuffixSet } from './route-constants.mjs';
4
+ import { normalizePrefix } from './scan-utils.mjs';
5
+ import 'node:process';
6
+
7
+ function createRouteUtils(params) {
8
+ const { parseRouteTemplate, compareRouteScore } = params;
9
+ function resolveTemplate(template, prefix) {
10
+ const normalized = template.startsWith("/") ? template : `/${template}`;
11
+ if (!prefix) {
12
+ return normalized;
13
+ }
14
+ const normalizedPrefix = normalizePrefix(prefix);
15
+ if (!normalizedPrefix) {
16
+ return normalized;
17
+ }
18
+ if (normalized === normalizedPrefix || normalized.startsWith(`${normalizedPrefix}/`)) {
19
+ return normalized;
20
+ }
21
+ if (normalized === "/") {
22
+ return `${normalizedPrefix}/`;
23
+ }
24
+ return `${normalizedPrefix}${normalized}`;
25
+ }
26
+ function stripMethodSuffix(base) {
27
+ const segments = base.split(".");
28
+ const last = segments.at(-1);
29
+ if (last && methodSuffixSet.has(last.toLowerCase())) {
30
+ segments.pop();
31
+ return {
32
+ name: segments.join("."),
33
+ method: last.toUpperCase()
34
+ };
35
+ }
36
+ return {
37
+ name: base,
38
+ method: void 0
39
+ };
40
+ }
41
+ function deriveRouteFromFile(file, rootDir, warn) {
42
+ const rel = toPosix(relative(rootDir, file));
43
+ const ext = extname(rel);
44
+ const withoutExt = rel.slice(0, rel.length - ext.length);
45
+ const dir = dirname(withoutExt);
46
+ const base = basename(withoutExt);
47
+ const { name, method } = stripMethodSuffix(base);
48
+ const resolvedMethod = method ?? (jsonExtensions.has(ext) ? "GET" : void 0);
49
+ if (!resolvedMethod) {
50
+ warn?.(`Skip mock without method suffix: ${file}`);
51
+ return null;
52
+ }
53
+ if (!name) {
54
+ warn?.(`Skip mock with empty route name: ${file}`);
55
+ return null;
56
+ }
57
+ const joined = dir === "." ? name : join(dir, name);
58
+ const segments = toPosix(joined).split("/");
59
+ if (segments.at(-1) === "index") {
60
+ segments.pop();
61
+ }
62
+ const template = segments.length === 0 ? "/" : `/${segments.join("/")}`;
63
+ const parsed = parseRouteTemplate(template);
64
+ if (parsed.errors.length > 0) {
65
+ for (const error of parsed.errors) {
66
+ warn?.(`${error} in ${file}`);
67
+ }
68
+ return null;
69
+ }
70
+ for (const warning of parsed.warnings) {
71
+ warn?.(`${warning} in ${file}`);
72
+ }
73
+ return {
74
+ template: parsed.template,
75
+ method: resolvedMethod,
76
+ tokens: parsed.tokens,
77
+ score: parsed.score
78
+ };
79
+ }
80
+ function resolveRule(input) {
81
+ const method = input.derivedMethod;
82
+ if (!method) {
83
+ input.warn?.(`Skip mock without method suffix: ${input.file}`);
84
+ return null;
85
+ }
86
+ const template = resolveTemplate(input.derivedTemplate, input.prefix);
87
+ const parsed = parseRouteTemplate(template);
88
+ if (parsed.errors.length > 0) {
89
+ for (const error of parsed.errors) {
90
+ input.warn?.(`${error} in ${input.file}`);
91
+ }
92
+ return null;
93
+ }
94
+ for (const warning of parsed.warnings) {
95
+ input.warn?.(`${warning} in ${input.file}`);
96
+ }
97
+ const base = {
98
+ template: parsed.template,
99
+ method,
100
+ tokens: parsed.tokens,
101
+ score: parsed.score
102
+ };
103
+ return input.build ? input.build(base, input.rule) : base;
104
+ }
105
+ function sortRoutes(routes) {
106
+ return routes.sort((a, b) => {
107
+ if (a.method !== b.method) {
108
+ return a.method.localeCompare(b.method);
109
+ }
110
+ const scoreCompare = compareRouteScore(a.score, b.score);
111
+ if (scoreCompare !== 0) {
112
+ return scoreCompare;
113
+ }
114
+ return a.template.localeCompare(b.template);
115
+ });
116
+ }
117
+ return {
118
+ deriveRouteFromFile,
119
+ resolveRule,
120
+ sortRoutes
121
+ };
122
+ }
123
+
124
+ export { createRouteUtils };
@@ -0,0 +1,39 @@
1
+ 'use strict';
2
+
3
+ const pathe = require('pathe');
4
+ const routeConstants = require('./route-constants.cjs');
5
+
6
+ function normalizeMethod(method) {
7
+ if (!method) {
8
+ return void 0;
9
+ }
10
+ const normalized = method.toUpperCase();
11
+ if (routeConstants.methodSet.has(normalized)) {
12
+ return normalized;
13
+ }
14
+ return void 0;
15
+ }
16
+ function normalizePrefix(prefix) {
17
+ if (!prefix) {
18
+ return "";
19
+ }
20
+ const normalized = prefix.startsWith("/") ? prefix : `/${prefix}`;
21
+ return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
22
+ }
23
+ function resolveDirs(dir, root) {
24
+ const raw = typeof dir === "function" ? dir(root) : dir;
25
+ const resolved = Array.isArray(raw) ? raw : raw ? [raw] : ["mock"];
26
+ const normalized = resolved.map(
27
+ (entry) => pathe.isAbsolute(entry) ? entry : pathe.resolve(root, entry)
28
+ );
29
+ return Array.from(new Set(normalized));
30
+ }
31
+ function normalizeIgnorePrefix(value, fallback = ["."]) {
32
+ const list = typeof value === "undefined" ? fallback : Array.isArray(value) ? value : [value];
33
+ return list.filter((entry) => typeof entry === "string" && entry.length > 0);
34
+ }
35
+
36
+ exports.normalizeIgnorePrefix = normalizeIgnorePrefix;
37
+ exports.normalizeMethod = normalizeMethod;
38
+ exports.normalizePrefix = normalizePrefix;
39
+ exports.resolveDirs = resolveDirs;