mokup 1.0.3 → 2.0.0
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.
- package/dist/index.d.cts +15 -6
- package/dist/index.d.mts +15 -6
- package/dist/index.d.ts +15 -6
- package/dist/shared/{mokup.Cvbs0IQE.cjs → mokup.CvPjMpMJ.cjs} +149 -10
- package/dist/shared/{mokup.BJg257y9.mjs → mokup.U2S5CHgY.mjs} +147 -8
- package/dist/vite.cjs +116 -27
- package/dist/vite.d.cts +4 -4
- package/dist/vite.d.mts +4 -4
- package/dist/vite.d.ts +4 -4
- package/dist/vite.mjs +116 -27
- package/dist/webpack.cjs +46 -13
- package/dist/webpack.d.cts +4 -4
- package/dist/webpack.d.mts +4 -4
- package/dist/webpack.d.ts +4 -4
- package/dist/webpack.mjs +46 -13
- package/package.json +5 -5
package/dist/index.d.cts
CHANGED
|
@@ -6,6 +6,7 @@ type RequestHandler = (context: Context) => Response | Promise<Response> | unkno
|
|
|
6
6
|
type RouteResponse = unknown | RequestHandler;
|
|
7
7
|
interface RouteRule {
|
|
8
8
|
handler: RouteResponse;
|
|
9
|
+
enabled?: boolean;
|
|
9
10
|
status?: number;
|
|
10
11
|
headers?: Record<string, string>;
|
|
11
12
|
delay?: number;
|
|
@@ -19,11 +20,18 @@ interface ServiceWorkerOptions {
|
|
|
19
20
|
fallback?: boolean;
|
|
20
21
|
basePath?: string | string[];
|
|
21
22
|
}
|
|
23
|
+
type PlaygroundOptionsInput = boolean | {
|
|
24
|
+
path?: string;
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
} | undefined;
|
|
22
27
|
interface RouteDirectoryConfig {
|
|
23
28
|
headers?: Record<string, string>;
|
|
24
29
|
status?: number;
|
|
25
30
|
delay?: number;
|
|
26
31
|
enabled?: boolean;
|
|
32
|
+
ignorePrefix?: string | string[];
|
|
33
|
+
include?: RegExp | RegExp[];
|
|
34
|
+
exclude?: RegExp | RegExp[];
|
|
27
35
|
middleware?: MiddlewareHandler | MiddlewareHandler[];
|
|
28
36
|
}
|
|
29
37
|
interface VitePluginOptions {
|
|
@@ -31,15 +39,16 @@ interface VitePluginOptions {
|
|
|
31
39
|
prefix?: string;
|
|
32
40
|
include?: RegExp | RegExp[];
|
|
33
41
|
exclude?: RegExp | RegExp[];
|
|
42
|
+
ignorePrefix?: string | string[];
|
|
34
43
|
watch?: boolean;
|
|
35
44
|
log?: boolean;
|
|
36
45
|
mode?: RuntimeMode;
|
|
37
46
|
sw?: ServiceWorkerOptions;
|
|
38
|
-
playground?: boolean | {
|
|
39
|
-
path?: string;
|
|
40
|
-
enabled?: boolean;
|
|
41
|
-
};
|
|
42
47
|
}
|
|
43
|
-
|
|
48
|
+
interface MokupPluginOptions {
|
|
49
|
+
entries?: VitePluginOptions | VitePluginOptions[];
|
|
50
|
+
playground?: PlaygroundOptionsInput;
|
|
51
|
+
}
|
|
52
|
+
type VitePluginOptionsInput = MokupPluginOptions;
|
|
44
53
|
|
|
45
|
-
export type { HttpMethod, RequestHandler, RouteDirectoryConfig, RouteResponse, RouteRule, RuntimeMode, ServiceWorkerOptions, VitePluginOptions, VitePluginOptionsInput };
|
|
54
|
+
export type { HttpMethod, MokupPluginOptions, PlaygroundOptionsInput, RequestHandler, RouteDirectoryConfig, RouteResponse, RouteRule, RuntimeMode, ServiceWorkerOptions, VitePluginOptions, VitePluginOptionsInput };
|
package/dist/index.d.mts
CHANGED
|
@@ -6,6 +6,7 @@ type RequestHandler = (context: Context) => Response | Promise<Response> | unkno
|
|
|
6
6
|
type RouteResponse = unknown | RequestHandler;
|
|
7
7
|
interface RouteRule {
|
|
8
8
|
handler: RouteResponse;
|
|
9
|
+
enabled?: boolean;
|
|
9
10
|
status?: number;
|
|
10
11
|
headers?: Record<string, string>;
|
|
11
12
|
delay?: number;
|
|
@@ -19,11 +20,18 @@ interface ServiceWorkerOptions {
|
|
|
19
20
|
fallback?: boolean;
|
|
20
21
|
basePath?: string | string[];
|
|
21
22
|
}
|
|
23
|
+
type PlaygroundOptionsInput = boolean | {
|
|
24
|
+
path?: string;
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
} | undefined;
|
|
22
27
|
interface RouteDirectoryConfig {
|
|
23
28
|
headers?: Record<string, string>;
|
|
24
29
|
status?: number;
|
|
25
30
|
delay?: number;
|
|
26
31
|
enabled?: boolean;
|
|
32
|
+
ignorePrefix?: string | string[];
|
|
33
|
+
include?: RegExp | RegExp[];
|
|
34
|
+
exclude?: RegExp | RegExp[];
|
|
27
35
|
middleware?: MiddlewareHandler | MiddlewareHandler[];
|
|
28
36
|
}
|
|
29
37
|
interface VitePluginOptions {
|
|
@@ -31,15 +39,16 @@ interface VitePluginOptions {
|
|
|
31
39
|
prefix?: string;
|
|
32
40
|
include?: RegExp | RegExp[];
|
|
33
41
|
exclude?: RegExp | RegExp[];
|
|
42
|
+
ignorePrefix?: string | string[];
|
|
34
43
|
watch?: boolean;
|
|
35
44
|
log?: boolean;
|
|
36
45
|
mode?: RuntimeMode;
|
|
37
46
|
sw?: ServiceWorkerOptions;
|
|
38
|
-
playground?: boolean | {
|
|
39
|
-
path?: string;
|
|
40
|
-
enabled?: boolean;
|
|
41
|
-
};
|
|
42
47
|
}
|
|
43
|
-
|
|
48
|
+
interface MokupPluginOptions {
|
|
49
|
+
entries?: VitePluginOptions | VitePluginOptions[];
|
|
50
|
+
playground?: PlaygroundOptionsInput;
|
|
51
|
+
}
|
|
52
|
+
type VitePluginOptionsInput = MokupPluginOptions;
|
|
44
53
|
|
|
45
|
-
export type { HttpMethod, RequestHandler, RouteDirectoryConfig, RouteResponse, RouteRule, RuntimeMode, ServiceWorkerOptions, VitePluginOptions, VitePluginOptionsInput };
|
|
54
|
+
export type { HttpMethod, MokupPluginOptions, PlaygroundOptionsInput, RequestHandler, RouteDirectoryConfig, RouteResponse, RouteRule, RuntimeMode, ServiceWorkerOptions, VitePluginOptions, VitePluginOptionsInput };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ type RequestHandler = (context: Context) => Response | Promise<Response> | unkno
|
|
|
6
6
|
type RouteResponse = unknown | RequestHandler;
|
|
7
7
|
interface RouteRule {
|
|
8
8
|
handler: RouteResponse;
|
|
9
|
+
enabled?: boolean;
|
|
9
10
|
status?: number;
|
|
10
11
|
headers?: Record<string, string>;
|
|
11
12
|
delay?: number;
|
|
@@ -19,11 +20,18 @@ interface ServiceWorkerOptions {
|
|
|
19
20
|
fallback?: boolean;
|
|
20
21
|
basePath?: string | string[];
|
|
21
22
|
}
|
|
23
|
+
type PlaygroundOptionsInput = boolean | {
|
|
24
|
+
path?: string;
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
} | undefined;
|
|
22
27
|
interface RouteDirectoryConfig {
|
|
23
28
|
headers?: Record<string, string>;
|
|
24
29
|
status?: number;
|
|
25
30
|
delay?: number;
|
|
26
31
|
enabled?: boolean;
|
|
32
|
+
ignorePrefix?: string | string[];
|
|
33
|
+
include?: RegExp | RegExp[];
|
|
34
|
+
exclude?: RegExp | RegExp[];
|
|
27
35
|
middleware?: MiddlewareHandler | MiddlewareHandler[];
|
|
28
36
|
}
|
|
29
37
|
interface VitePluginOptions {
|
|
@@ -31,15 +39,16 @@ interface VitePluginOptions {
|
|
|
31
39
|
prefix?: string;
|
|
32
40
|
include?: RegExp | RegExp[];
|
|
33
41
|
exclude?: RegExp | RegExp[];
|
|
42
|
+
ignorePrefix?: string | string[];
|
|
34
43
|
watch?: boolean;
|
|
35
44
|
log?: boolean;
|
|
36
45
|
mode?: RuntimeMode;
|
|
37
46
|
sw?: ServiceWorkerOptions;
|
|
38
|
-
playground?: boolean | {
|
|
39
|
-
path?: string;
|
|
40
|
-
enabled?: boolean;
|
|
41
|
-
};
|
|
42
47
|
}
|
|
43
|
-
|
|
48
|
+
interface MokupPluginOptions {
|
|
49
|
+
entries?: VitePluginOptions | VitePluginOptions[];
|
|
50
|
+
playground?: PlaygroundOptionsInput;
|
|
51
|
+
}
|
|
52
|
+
type VitePluginOptionsInput = MokupPluginOptions;
|
|
44
53
|
|
|
45
|
-
export type { HttpMethod, RequestHandler, RouteDirectoryConfig, RouteResponse, RouteRule, RuntimeMode, ServiceWorkerOptions, VitePluginOptions, VitePluginOptionsInput };
|
|
54
|
+
export type { HttpMethod, MokupPluginOptions, PlaygroundOptionsInput, RequestHandler, RouteDirectoryConfig, RouteResponse, RouteRule, RuntimeMode, ServiceWorkerOptions, VitePluginOptions, VitePluginOptionsInput };
|
|
@@ -114,6 +114,20 @@ function matchesFilter(file, include, exclude) {
|
|
|
114
114
|
}
|
|
115
115
|
return true;
|
|
116
116
|
}
|
|
117
|
+
function normalizeIgnorePrefix(value, fallback = ["."]) {
|
|
118
|
+
const list = typeof value === "undefined" ? fallback : Array.isArray(value) ? value : [value];
|
|
119
|
+
return list.filter((entry) => typeof entry === "string" && entry.length > 0);
|
|
120
|
+
}
|
|
121
|
+
function hasIgnoredPrefix(file, rootDir, prefixes) {
|
|
122
|
+
if (prefixes.length === 0) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const relativePath = toPosix(pathe.relative(rootDir, file));
|
|
126
|
+
const segments = relativePath.split("/");
|
|
127
|
+
return segments.some(
|
|
128
|
+
(segment) => prefixes.some((prefix) => segment.startsWith(prefix))
|
|
129
|
+
);
|
|
130
|
+
}
|
|
117
131
|
function delay(ms) {
|
|
118
132
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
119
133
|
}
|
|
@@ -336,7 +350,7 @@ function createMiddleware(getApp, logger) {
|
|
|
336
350
|
};
|
|
337
351
|
}
|
|
338
352
|
|
|
339
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.
|
|
353
|
+
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.CvPjMpMJ.cjs', document.baseURI).href)));
|
|
340
354
|
const mimeTypes = {
|
|
341
355
|
".html": "text/html; charset=utf-8",
|
|
342
356
|
".css": "text/css; charset=utf-8",
|
|
@@ -494,6 +508,20 @@ function resolveGroupRoot(dirs, serverRoot) {
|
|
|
494
508
|
}
|
|
495
509
|
return common;
|
|
496
510
|
}
|
|
511
|
+
const disabledReasonSet = /* @__PURE__ */ new Set([
|
|
512
|
+
"disabled",
|
|
513
|
+
"disabled-dir",
|
|
514
|
+
"exclude",
|
|
515
|
+
"ignore-prefix",
|
|
516
|
+
"include",
|
|
517
|
+
"unknown"
|
|
518
|
+
]);
|
|
519
|
+
function normalizeDisabledReason(reason) {
|
|
520
|
+
if (reason && disabledReasonSet.has(reason)) {
|
|
521
|
+
return reason;
|
|
522
|
+
}
|
|
523
|
+
return "unknown";
|
|
524
|
+
}
|
|
497
525
|
function formatRouteFile(file, root) {
|
|
498
526
|
if (!root) {
|
|
499
527
|
return toPosixPath(file);
|
|
@@ -554,6 +582,24 @@ function toPlaygroundRoute(route, root, groups) {
|
|
|
554
582
|
group: matchedGroup?.label
|
|
555
583
|
};
|
|
556
584
|
}
|
|
585
|
+
function toPlaygroundDisabledRoute(route, root, groups) {
|
|
586
|
+
const matchedGroup = resolveRouteGroup(route.file, groups);
|
|
587
|
+
const disabled = {
|
|
588
|
+
file: formatRouteFile(route.file, root),
|
|
589
|
+
reason: normalizeDisabledReason(route.reason)
|
|
590
|
+
};
|
|
591
|
+
if (typeof route.method !== "undefined") {
|
|
592
|
+
disabled.method = route.method;
|
|
593
|
+
}
|
|
594
|
+
if (typeof route.url !== "undefined") {
|
|
595
|
+
disabled.url = route.url;
|
|
596
|
+
}
|
|
597
|
+
if (matchedGroup) {
|
|
598
|
+
disabled.groupKey = matchedGroup.key;
|
|
599
|
+
disabled.group = matchedGroup.label;
|
|
600
|
+
}
|
|
601
|
+
return disabled;
|
|
602
|
+
}
|
|
557
603
|
function createPlaygroundMiddleware(params) {
|
|
558
604
|
const distDir = resolvePlaygroundDist();
|
|
559
605
|
const playgroundPath = params.config.path;
|
|
@@ -601,12 +647,14 @@ function createPlaygroundMiddleware(params) {
|
|
|
601
647
|
const baseRoot = resolveGroupRoot(dirs, server?.config?.root);
|
|
602
648
|
const groups = resolveGroups(dirs, baseRoot);
|
|
603
649
|
const routes = params.getRoutes();
|
|
650
|
+
const disabledRoutes = params.getDisabledRoutes?.() ?? [];
|
|
604
651
|
sendJson(res, {
|
|
605
652
|
basePath: matchedPath,
|
|
606
653
|
root: baseRoot,
|
|
607
654
|
count: routes.length,
|
|
608
655
|
groups: groups.map((group) => ({ key: group.key, label: group.label })),
|
|
609
|
-
routes: routes.map((route) => toPlaygroundRoute(route, baseRoot, groups))
|
|
656
|
+
routes: routes.map((route) => toPlaygroundRoute(route, baseRoot, groups)),
|
|
657
|
+
disabled: disabledRoutes.map((route) => toPlaygroundDisabledRoute(route, baseRoot, groups))
|
|
610
658
|
});
|
|
611
659
|
return;
|
|
612
660
|
}
|
|
@@ -754,7 +802,7 @@ const configExtensions = [".ts", ".js", ".mjs", ".cjs"];
|
|
|
754
802
|
async function loadModule$1(file) {
|
|
755
803
|
const ext = configExtensions.find((extension) => file.endsWith(extension));
|
|
756
804
|
if (ext === ".cjs") {
|
|
757
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.
|
|
805
|
+
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.CvPjMpMJ.cjs', document.baseURI).href)));
|
|
758
806
|
delete require$1.cache[file];
|
|
759
807
|
return require$1(file);
|
|
760
808
|
}
|
|
@@ -882,6 +930,15 @@ async function resolveDirectoryConfig(params) {
|
|
|
882
930
|
if (typeof config.enabled === "boolean") {
|
|
883
931
|
merged.enabled = config.enabled;
|
|
884
932
|
}
|
|
933
|
+
if (typeof config.ignorePrefix !== "undefined") {
|
|
934
|
+
merged.ignorePrefix = config.ignorePrefix;
|
|
935
|
+
}
|
|
936
|
+
if (typeof config.include !== "undefined") {
|
|
937
|
+
merged.include = config.include;
|
|
938
|
+
}
|
|
939
|
+
if (typeof config.exclude !== "undefined") {
|
|
940
|
+
merged.exclude = config.exclude;
|
|
941
|
+
}
|
|
885
942
|
const normalized = normalizeMiddlewares(config.middleware, configPath, logger);
|
|
886
943
|
if (normalized.length > 0) {
|
|
887
944
|
merged.middlewares.push(...normalized);
|
|
@@ -938,7 +995,7 @@ function isSupportedFile(file) {
|
|
|
938
995
|
async function loadModule(file) {
|
|
939
996
|
const ext = pathe.extname(file).toLowerCase();
|
|
940
997
|
if (ext === ".cjs") {
|
|
941
|
-
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.
|
|
998
|
+
const require$1 = node_module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/mokup.CvPjMpMJ.cjs', document.baseURI).href)));
|
|
942
999
|
delete require$1.cache[file];
|
|
943
1000
|
return require$1(file);
|
|
944
1001
|
}
|
|
@@ -1024,19 +1081,52 @@ async function loadRules(file, server, logger) {
|
|
|
1024
1081
|
return [value];
|
|
1025
1082
|
}
|
|
1026
1083
|
|
|
1084
|
+
const silentLogger = {
|
|
1085
|
+
info: () => {
|
|
1086
|
+
},
|
|
1087
|
+
warn: () => {
|
|
1088
|
+
},
|
|
1089
|
+
error: () => {
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
function resolveSkipRoute(params) {
|
|
1093
|
+
const derived = params.derived ?? deriveRouteFromFile(params.file, params.rootDir, silentLogger);
|
|
1094
|
+
if (!derived?.method) {
|
|
1095
|
+
return null;
|
|
1096
|
+
}
|
|
1097
|
+
const resolved = resolveRule({
|
|
1098
|
+
rule: { handler: null },
|
|
1099
|
+
derivedTemplate: derived.template,
|
|
1100
|
+
derivedMethod: derived.method,
|
|
1101
|
+
prefix: params.prefix,
|
|
1102
|
+
file: params.file,
|
|
1103
|
+
logger: silentLogger
|
|
1104
|
+
});
|
|
1105
|
+
if (!resolved) {
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
return {
|
|
1109
|
+
method: resolved.method,
|
|
1110
|
+
url: resolved.template
|
|
1111
|
+
};
|
|
1112
|
+
}
|
|
1113
|
+
function buildSkipInfo(file, reason, resolved) {
|
|
1114
|
+
const info = { file, reason };
|
|
1115
|
+
if (resolved) {
|
|
1116
|
+
info.method = resolved.method;
|
|
1117
|
+
info.url = resolved.url;
|
|
1118
|
+
}
|
|
1119
|
+
return info;
|
|
1120
|
+
}
|
|
1027
1121
|
async function scanRoutes(params) {
|
|
1028
1122
|
const routes = [];
|
|
1029
1123
|
const seen = /* @__PURE__ */ new Set();
|
|
1030
1124
|
const files = await collectFiles(params.dirs);
|
|
1125
|
+
const globalIgnorePrefix = normalizeIgnorePrefix(params.ignorePrefix);
|
|
1031
1126
|
const configCache = /* @__PURE__ */ new Map();
|
|
1032
1127
|
const fileCache = /* @__PURE__ */ new Map();
|
|
1128
|
+
const shouldCollectSkip = typeof params.onSkip === "function";
|
|
1033
1129
|
for (const fileInfo of files) {
|
|
1034
|
-
if (!isSupportedFile(fileInfo.file)) {
|
|
1035
|
-
continue;
|
|
1036
|
-
}
|
|
1037
|
-
if (!matchesFilter(fileInfo.file, params.include, params.exclude)) {
|
|
1038
|
-
continue;
|
|
1039
|
-
}
|
|
1040
1130
|
const configParams = {
|
|
1041
1131
|
file: fileInfo.file,
|
|
1042
1132
|
rootDir: fileInfo.rootDir,
|
|
@@ -1049,6 +1139,43 @@ async function scanRoutes(params) {
|
|
|
1049
1139
|
}
|
|
1050
1140
|
const config = await resolveDirectoryConfig(configParams);
|
|
1051
1141
|
if (config.enabled === false) {
|
|
1142
|
+
if (shouldCollectSkip && isSupportedFile(fileInfo.file)) {
|
|
1143
|
+
const resolved = resolveSkipRoute({
|
|
1144
|
+
file: fileInfo.file,
|
|
1145
|
+
rootDir: fileInfo.rootDir,
|
|
1146
|
+
prefix: params.prefix
|
|
1147
|
+
});
|
|
1148
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "disabled-dir", resolved));
|
|
1149
|
+
}
|
|
1150
|
+
continue;
|
|
1151
|
+
}
|
|
1152
|
+
const effectiveIgnorePrefix = typeof config.ignorePrefix !== "undefined" ? normalizeIgnorePrefix(config.ignorePrefix, []) : globalIgnorePrefix;
|
|
1153
|
+
if (hasIgnoredPrefix(fileInfo.file, fileInfo.rootDir, effectiveIgnorePrefix)) {
|
|
1154
|
+
if (shouldCollectSkip && isSupportedFile(fileInfo.file)) {
|
|
1155
|
+
const resolved = resolveSkipRoute({
|
|
1156
|
+
file: fileInfo.file,
|
|
1157
|
+
rootDir: fileInfo.rootDir,
|
|
1158
|
+
prefix: params.prefix
|
|
1159
|
+
});
|
|
1160
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "ignore-prefix", resolved));
|
|
1161
|
+
}
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
if (!isSupportedFile(fileInfo.file)) {
|
|
1165
|
+
continue;
|
|
1166
|
+
}
|
|
1167
|
+
const effectiveInclude = typeof config.include !== "undefined" ? config.include : params.include;
|
|
1168
|
+
const effectiveExclude = typeof config.exclude !== "undefined" ? config.exclude : params.exclude;
|
|
1169
|
+
if (!matchesFilter(fileInfo.file, effectiveInclude, effectiveExclude)) {
|
|
1170
|
+
if (shouldCollectSkip) {
|
|
1171
|
+
const resolved = resolveSkipRoute({
|
|
1172
|
+
file: fileInfo.file,
|
|
1173
|
+
rootDir: fileInfo.rootDir,
|
|
1174
|
+
prefix: params.prefix
|
|
1175
|
+
});
|
|
1176
|
+
const reason = effectiveExclude && matchesFilter(fileInfo.file, void 0, effectiveExclude) ? "exclude" : "include";
|
|
1177
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, reason, resolved));
|
|
1178
|
+
}
|
|
1052
1179
|
continue;
|
|
1053
1180
|
}
|
|
1054
1181
|
const derived = deriveRouteFromFile(fileInfo.file, fileInfo.rootDir, params.logger);
|
|
@@ -1060,6 +1187,18 @@ async function scanRoutes(params) {
|
|
|
1060
1187
|
if (!rule || typeof rule !== "object") {
|
|
1061
1188
|
continue;
|
|
1062
1189
|
}
|
|
1190
|
+
if (rule.enabled === false) {
|
|
1191
|
+
if (shouldCollectSkip) {
|
|
1192
|
+
const resolved2 = resolveSkipRoute({
|
|
1193
|
+
file: fileInfo.file,
|
|
1194
|
+
rootDir: fileInfo.rootDir,
|
|
1195
|
+
prefix: params.prefix,
|
|
1196
|
+
derived
|
|
1197
|
+
});
|
|
1198
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "disabled", resolved2));
|
|
1199
|
+
}
|
|
1200
|
+
continue;
|
|
1201
|
+
}
|
|
1063
1202
|
const ruleValue = rule;
|
|
1064
1203
|
const unsupportedKeys = ["response", "url", "method"].filter(
|
|
1065
1204
|
(key2) => key2 in ruleValue
|
|
@@ -3,7 +3,7 @@ import { Hono, PatternRouter } from '@mokup/shared/hono';
|
|
|
3
3
|
import { promises } from 'node:fs';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
5
|
import { cwd } from 'node:process';
|
|
6
|
-
import { resolve, isAbsolute, join, normalize, extname, dirname,
|
|
6
|
+
import { resolve, isAbsolute, relative, join, normalize, extname, dirname, basename } from '@mokup/shared/pathe';
|
|
7
7
|
import { pathToFileURL } from 'node:url';
|
|
8
8
|
import { build } from '@mokup/shared/esbuild';
|
|
9
9
|
import { parse } from '@mokup/shared/jsonc-parser';
|
|
@@ -111,6 +111,20 @@ function matchesFilter(file, include, exclude) {
|
|
|
111
111
|
}
|
|
112
112
|
return true;
|
|
113
113
|
}
|
|
114
|
+
function normalizeIgnorePrefix(value, fallback = ["."]) {
|
|
115
|
+
const list = typeof value === "undefined" ? fallback : Array.isArray(value) ? value : [value];
|
|
116
|
+
return list.filter((entry) => typeof entry === "string" && entry.length > 0);
|
|
117
|
+
}
|
|
118
|
+
function hasIgnoredPrefix(file, rootDir, prefixes) {
|
|
119
|
+
if (prefixes.length === 0) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
const relativePath = toPosix(relative(rootDir, file));
|
|
123
|
+
const segments = relativePath.split("/");
|
|
124
|
+
return segments.some(
|
|
125
|
+
(segment) => prefixes.some((prefix) => segment.startsWith(prefix))
|
|
126
|
+
);
|
|
127
|
+
}
|
|
114
128
|
function delay(ms) {
|
|
115
129
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
116
130
|
}
|
|
@@ -491,6 +505,20 @@ function resolveGroupRoot(dirs, serverRoot) {
|
|
|
491
505
|
}
|
|
492
506
|
return common;
|
|
493
507
|
}
|
|
508
|
+
const disabledReasonSet = /* @__PURE__ */ new Set([
|
|
509
|
+
"disabled",
|
|
510
|
+
"disabled-dir",
|
|
511
|
+
"exclude",
|
|
512
|
+
"ignore-prefix",
|
|
513
|
+
"include",
|
|
514
|
+
"unknown"
|
|
515
|
+
]);
|
|
516
|
+
function normalizeDisabledReason(reason) {
|
|
517
|
+
if (reason && disabledReasonSet.has(reason)) {
|
|
518
|
+
return reason;
|
|
519
|
+
}
|
|
520
|
+
return "unknown";
|
|
521
|
+
}
|
|
494
522
|
function formatRouteFile(file, root) {
|
|
495
523
|
if (!root) {
|
|
496
524
|
return toPosixPath(file);
|
|
@@ -551,6 +579,24 @@ function toPlaygroundRoute(route, root, groups) {
|
|
|
551
579
|
group: matchedGroup?.label
|
|
552
580
|
};
|
|
553
581
|
}
|
|
582
|
+
function toPlaygroundDisabledRoute(route, root, groups) {
|
|
583
|
+
const matchedGroup = resolveRouteGroup(route.file, groups);
|
|
584
|
+
const disabled = {
|
|
585
|
+
file: formatRouteFile(route.file, root),
|
|
586
|
+
reason: normalizeDisabledReason(route.reason)
|
|
587
|
+
};
|
|
588
|
+
if (typeof route.method !== "undefined") {
|
|
589
|
+
disabled.method = route.method;
|
|
590
|
+
}
|
|
591
|
+
if (typeof route.url !== "undefined") {
|
|
592
|
+
disabled.url = route.url;
|
|
593
|
+
}
|
|
594
|
+
if (matchedGroup) {
|
|
595
|
+
disabled.groupKey = matchedGroup.key;
|
|
596
|
+
disabled.group = matchedGroup.label;
|
|
597
|
+
}
|
|
598
|
+
return disabled;
|
|
599
|
+
}
|
|
554
600
|
function createPlaygroundMiddleware(params) {
|
|
555
601
|
const distDir = resolvePlaygroundDist();
|
|
556
602
|
const playgroundPath = params.config.path;
|
|
@@ -598,12 +644,14 @@ function createPlaygroundMiddleware(params) {
|
|
|
598
644
|
const baseRoot = resolveGroupRoot(dirs, server?.config?.root);
|
|
599
645
|
const groups = resolveGroups(dirs, baseRoot);
|
|
600
646
|
const routes = params.getRoutes();
|
|
647
|
+
const disabledRoutes = params.getDisabledRoutes?.() ?? [];
|
|
601
648
|
sendJson(res, {
|
|
602
649
|
basePath: matchedPath,
|
|
603
650
|
root: baseRoot,
|
|
604
651
|
count: routes.length,
|
|
605
652
|
groups: groups.map((group) => ({ key: group.key, label: group.label })),
|
|
606
|
-
routes: routes.map((route) => toPlaygroundRoute(route, baseRoot, groups))
|
|
653
|
+
routes: routes.map((route) => toPlaygroundRoute(route, baseRoot, groups)),
|
|
654
|
+
disabled: disabledRoutes.map((route) => toPlaygroundDisabledRoute(route, baseRoot, groups))
|
|
607
655
|
});
|
|
608
656
|
return;
|
|
609
657
|
}
|
|
@@ -879,6 +927,15 @@ async function resolveDirectoryConfig(params) {
|
|
|
879
927
|
if (typeof config.enabled === "boolean") {
|
|
880
928
|
merged.enabled = config.enabled;
|
|
881
929
|
}
|
|
930
|
+
if (typeof config.ignorePrefix !== "undefined") {
|
|
931
|
+
merged.ignorePrefix = config.ignorePrefix;
|
|
932
|
+
}
|
|
933
|
+
if (typeof config.include !== "undefined") {
|
|
934
|
+
merged.include = config.include;
|
|
935
|
+
}
|
|
936
|
+
if (typeof config.exclude !== "undefined") {
|
|
937
|
+
merged.exclude = config.exclude;
|
|
938
|
+
}
|
|
882
939
|
const normalized = normalizeMiddlewares(config.middleware, configPath, logger);
|
|
883
940
|
if (normalized.length > 0) {
|
|
884
941
|
merged.middlewares.push(...normalized);
|
|
@@ -1021,19 +1078,52 @@ async function loadRules(file, server, logger) {
|
|
|
1021
1078
|
return [value];
|
|
1022
1079
|
}
|
|
1023
1080
|
|
|
1081
|
+
const silentLogger = {
|
|
1082
|
+
info: () => {
|
|
1083
|
+
},
|
|
1084
|
+
warn: () => {
|
|
1085
|
+
},
|
|
1086
|
+
error: () => {
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
1089
|
+
function resolveSkipRoute(params) {
|
|
1090
|
+
const derived = params.derived ?? deriveRouteFromFile(params.file, params.rootDir, silentLogger);
|
|
1091
|
+
if (!derived?.method) {
|
|
1092
|
+
return null;
|
|
1093
|
+
}
|
|
1094
|
+
const resolved = resolveRule({
|
|
1095
|
+
rule: { handler: null },
|
|
1096
|
+
derivedTemplate: derived.template,
|
|
1097
|
+
derivedMethod: derived.method,
|
|
1098
|
+
prefix: params.prefix,
|
|
1099
|
+
file: params.file,
|
|
1100
|
+
logger: silentLogger
|
|
1101
|
+
});
|
|
1102
|
+
if (!resolved) {
|
|
1103
|
+
return null;
|
|
1104
|
+
}
|
|
1105
|
+
return {
|
|
1106
|
+
method: resolved.method,
|
|
1107
|
+
url: resolved.template
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
function buildSkipInfo(file, reason, resolved) {
|
|
1111
|
+
const info = { file, reason };
|
|
1112
|
+
if (resolved) {
|
|
1113
|
+
info.method = resolved.method;
|
|
1114
|
+
info.url = resolved.url;
|
|
1115
|
+
}
|
|
1116
|
+
return info;
|
|
1117
|
+
}
|
|
1024
1118
|
async function scanRoutes(params) {
|
|
1025
1119
|
const routes = [];
|
|
1026
1120
|
const seen = /* @__PURE__ */ new Set();
|
|
1027
1121
|
const files = await collectFiles(params.dirs);
|
|
1122
|
+
const globalIgnorePrefix = normalizeIgnorePrefix(params.ignorePrefix);
|
|
1028
1123
|
const configCache = /* @__PURE__ */ new Map();
|
|
1029
1124
|
const fileCache = /* @__PURE__ */ new Map();
|
|
1125
|
+
const shouldCollectSkip = typeof params.onSkip === "function";
|
|
1030
1126
|
for (const fileInfo of files) {
|
|
1031
|
-
if (!isSupportedFile(fileInfo.file)) {
|
|
1032
|
-
continue;
|
|
1033
|
-
}
|
|
1034
|
-
if (!matchesFilter(fileInfo.file, params.include, params.exclude)) {
|
|
1035
|
-
continue;
|
|
1036
|
-
}
|
|
1037
1127
|
const configParams = {
|
|
1038
1128
|
file: fileInfo.file,
|
|
1039
1129
|
rootDir: fileInfo.rootDir,
|
|
@@ -1046,6 +1136,43 @@ async function scanRoutes(params) {
|
|
|
1046
1136
|
}
|
|
1047
1137
|
const config = await resolveDirectoryConfig(configParams);
|
|
1048
1138
|
if (config.enabled === false) {
|
|
1139
|
+
if (shouldCollectSkip && isSupportedFile(fileInfo.file)) {
|
|
1140
|
+
const resolved = resolveSkipRoute({
|
|
1141
|
+
file: fileInfo.file,
|
|
1142
|
+
rootDir: fileInfo.rootDir,
|
|
1143
|
+
prefix: params.prefix
|
|
1144
|
+
});
|
|
1145
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "disabled-dir", resolved));
|
|
1146
|
+
}
|
|
1147
|
+
continue;
|
|
1148
|
+
}
|
|
1149
|
+
const effectiveIgnorePrefix = typeof config.ignorePrefix !== "undefined" ? normalizeIgnorePrefix(config.ignorePrefix, []) : globalIgnorePrefix;
|
|
1150
|
+
if (hasIgnoredPrefix(fileInfo.file, fileInfo.rootDir, effectiveIgnorePrefix)) {
|
|
1151
|
+
if (shouldCollectSkip && isSupportedFile(fileInfo.file)) {
|
|
1152
|
+
const resolved = resolveSkipRoute({
|
|
1153
|
+
file: fileInfo.file,
|
|
1154
|
+
rootDir: fileInfo.rootDir,
|
|
1155
|
+
prefix: params.prefix
|
|
1156
|
+
});
|
|
1157
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "ignore-prefix", resolved));
|
|
1158
|
+
}
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
if (!isSupportedFile(fileInfo.file)) {
|
|
1162
|
+
continue;
|
|
1163
|
+
}
|
|
1164
|
+
const effectiveInclude = typeof config.include !== "undefined" ? config.include : params.include;
|
|
1165
|
+
const effectiveExclude = typeof config.exclude !== "undefined" ? config.exclude : params.exclude;
|
|
1166
|
+
if (!matchesFilter(fileInfo.file, effectiveInclude, effectiveExclude)) {
|
|
1167
|
+
if (shouldCollectSkip) {
|
|
1168
|
+
const resolved = resolveSkipRoute({
|
|
1169
|
+
file: fileInfo.file,
|
|
1170
|
+
rootDir: fileInfo.rootDir,
|
|
1171
|
+
prefix: params.prefix
|
|
1172
|
+
});
|
|
1173
|
+
const reason = effectiveExclude && matchesFilter(fileInfo.file, void 0, effectiveExclude) ? "exclude" : "include";
|
|
1174
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, reason, resolved));
|
|
1175
|
+
}
|
|
1049
1176
|
continue;
|
|
1050
1177
|
}
|
|
1051
1178
|
const derived = deriveRouteFromFile(fileInfo.file, fileInfo.rootDir, params.logger);
|
|
@@ -1057,6 +1184,18 @@ async function scanRoutes(params) {
|
|
|
1057
1184
|
if (!rule || typeof rule !== "object") {
|
|
1058
1185
|
continue;
|
|
1059
1186
|
}
|
|
1187
|
+
if (rule.enabled === false) {
|
|
1188
|
+
if (shouldCollectSkip) {
|
|
1189
|
+
const resolved2 = resolveSkipRoute({
|
|
1190
|
+
file: fileInfo.file,
|
|
1191
|
+
rootDir: fileInfo.rootDir,
|
|
1192
|
+
prefix: params.prefix,
|
|
1193
|
+
derived
|
|
1194
|
+
});
|
|
1195
|
+
params.onSkip?.(buildSkipInfo(fileInfo.file, "disabled", resolved2));
|
|
1196
|
+
}
|
|
1197
|
+
continue;
|
|
1198
|
+
}
|
|
1060
1199
|
const ruleValue = rule;
|
|
1061
1200
|
const unsupportedKeys = ["response", "url", "method"].filter(
|
|
1062
1201
|
(key2) => key2 in ruleValue
|