@jay-framework/stack-route-scanner 0.25.1 → 0.25.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.
- package/dist/index.d.mts +25 -2
- package/dist/index.mjs +25 -5
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -33,6 +33,24 @@ type JayRoute = {
|
|
|
33
33
|
devOnly?: boolean;
|
|
34
34
|
};
|
|
35
35
|
type JayRoutes = JayRoute[];
|
|
36
|
+
/**
|
|
37
|
+
* A reserved top-level error-page folder (Design Log #218). `pages/404/`, `pages/5xx/`, etc. are
|
|
38
|
+
* not routable; they are collected here instead of in {@link JayRoutes}.
|
|
39
|
+
*/
|
|
40
|
+
type JayErrorPage = {
|
|
41
|
+
/** HTTP status token: exact (`404`, `502`) or family (`4xx`, `5xx`). */
|
|
42
|
+
token: string;
|
|
43
|
+
jayHtmlPath: string;
|
|
44
|
+
compPath: string;
|
|
45
|
+
};
|
|
46
|
+
type JayErrorPages = JayErrorPage[];
|
|
47
|
+
/** Result of a route scan: navigable routes plus reserved error pages (DL#218). */
|
|
48
|
+
interface ScanResult {
|
|
49
|
+
routes: JayRoutes;
|
|
50
|
+
errorPages: JayErrorPages;
|
|
51
|
+
}
|
|
52
|
+
/** True when a top-level folder name is a reserved HTTP status token (DL#218). */
|
|
53
|
+
declare function isStatusToken(name: string): boolean;
|
|
36
54
|
interface ScanFilesOptions {
|
|
37
55
|
jayHtmlFilename: string;
|
|
38
56
|
compFilename: string;
|
|
@@ -55,8 +73,13 @@ declare function createRoute(routePath: string, jayHtmlPath: string, compPath: s
|
|
|
55
73
|
devOnly?: boolean;
|
|
56
74
|
clientCompPath?: string;
|
|
57
75
|
}): JayRoute;
|
|
58
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Scan a pages directory for navigable routes and reserved error pages (DL#218).
|
|
78
|
+
*
|
|
79
|
+
* Returns `{ routes, errorPages }`. Callers that only need routes destructure `{ routes }`.
|
|
80
|
+
*/
|
|
81
|
+
declare function scanRoutes(baseDir: string, options: ScanFilesOptions): Promise<ScanResult>;
|
|
59
82
|
|
|
60
83
|
declare function routeToExpressRoute(route: JayRoute): string;
|
|
61
84
|
|
|
62
|
-
export { type JayRoute, type JayRouteParam, JayRouteParamType, type JayRouteSegment, type JayRoutes, type ScanFilesOptions, createRoute, parseRouteSegments, routeToExpressRoute, scanRoutes, sortRoutesByPriority };
|
|
85
|
+
export { type JayErrorPage, type JayErrorPages, type JayRoute, type JayRouteParam, JayRouteParamType, type JayRouteSegment, type JayRoutes, type ScanFilesOptions, type ScanResult, createRoute, isStatusToken, parseRouteSegments, routeToExpressRoute, scanRoutes, sortRoutesByPriority };
|
package/dist/index.mjs
CHANGED
|
@@ -9,6 +9,10 @@ var JayRouteParamType = /* @__PURE__ */ ((JayRouteParamType2) => {
|
|
|
9
9
|
JayRouteParamType2[JayRouteParamType2["optional"] = 2] = "optional";
|
|
10
10
|
return JayRouteParamType2;
|
|
11
11
|
})(JayRouteParamType || {});
|
|
12
|
+
const STATUS_TOKEN = /^([1-5][0-9]{2}|[1-5]xx)$/;
|
|
13
|
+
function isStatusToken(name) {
|
|
14
|
+
return STATUS_TOKEN.test(name);
|
|
15
|
+
}
|
|
12
16
|
const PARSE_PARAM = /^\[(\[)?(\.\.\.)?([^\]]+)\]?\]$/;
|
|
13
17
|
function convertToRoutePath(BASE_DIR, jayHtmlPath, { jayHtmlFilename, compFilename }) {
|
|
14
18
|
let rawRoute = jayHtmlPath.replace(BASE_DIR, "").replace(`/${jayHtmlFilename}`, "").replace("\\", "/");
|
|
@@ -29,14 +33,22 @@ function convertToRoutePath(BASE_DIR, jayHtmlPath, { jayHtmlFilename, compFilena
|
|
|
29
33
|
return { segments, jayHtmlPath, compPath, rawRoute };
|
|
30
34
|
}
|
|
31
35
|
const IGNORED_DIRS = /* @__PURE__ */ new Set(["build", "node_modules", "dist", ".git"]);
|
|
32
|
-
async function scanDirectory(BASE_DIR, directory, options) {
|
|
36
|
+
async function scanDirectory(BASE_DIR, directory, options, depth = 0) {
|
|
33
37
|
let routes = [];
|
|
38
|
+
let errorPages = [];
|
|
34
39
|
const items = await promises.readdir(directory, { withFileTypes: true });
|
|
35
40
|
for (const item of items) {
|
|
36
41
|
const fullPath = path.join(directory, item.name);
|
|
37
42
|
if (item.isDirectory()) {
|
|
38
43
|
if (IGNORED_DIRS.has(item.name)) continue;
|
|
39
|
-
|
|
44
|
+
if (depth === 0 && isStatusToken(item.name)) {
|
|
45
|
+
const errorPage = toErrorPage(item.name, fullPath, options);
|
|
46
|
+
if (errorPage) errorPages.push(errorPage);
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const nested = await scanDirectory(BASE_DIR, fullPath, options, depth + 1);
|
|
50
|
+
routes = [...routes, ...nested.routes];
|
|
51
|
+
errorPages = [...errorPages, ...nested.errorPages];
|
|
40
52
|
} else if (item.name === options.jayHtmlFilename) {
|
|
41
53
|
const route = convertToRoutePath(BASE_DIR, fullPath, options);
|
|
42
54
|
const { params, validations } = await parseHeadlessProps(fullPath);
|
|
@@ -69,7 +81,14 @@ async function scanDirectory(BASE_DIR, directory, options) {
|
|
|
69
81
|
routes.push(route);
|
|
70
82
|
}
|
|
71
83
|
}
|
|
72
|
-
return routes;
|
|
84
|
+
return { routes, errorPages };
|
|
85
|
+
}
|
|
86
|
+
function toErrorPage(token, folderPath, { jayHtmlFilename, compFilename }) {
|
|
87
|
+
const jayHtmlPath = path.join(folderPath, jayHtmlFilename);
|
|
88
|
+
if (!existsSync(jayHtmlPath)) return void 0;
|
|
89
|
+
const candidateCompPath = path.join(folderPath, compFilename);
|
|
90
|
+
const compPath = existsSync(candidateCompPath) ? candidateCompPath : "";
|
|
91
|
+
return { token, jayHtmlPath, compPath };
|
|
73
92
|
}
|
|
74
93
|
function getSegmentPriority(segment) {
|
|
75
94
|
if (typeof segment === "string") return 0;
|
|
@@ -174,7 +193,7 @@ function createRoute(routePath, jayHtmlPath, compPath, componentExport, options)
|
|
|
174
193
|
}
|
|
175
194
|
async function scanRoutes(baseDir, options) {
|
|
176
195
|
const BASE_DIR = path.resolve(baseDir);
|
|
177
|
-
const routes = await scanDirectory(BASE_DIR, BASE_DIR, options);
|
|
196
|
+
const { routes, errorPages } = await scanDirectory(BASE_DIR, BASE_DIR, options);
|
|
178
197
|
const sortedRoutes = sortRoutesByPriority(routes);
|
|
179
198
|
const routesWithParams = sortedRoutes.filter((r) => r.inferredParams);
|
|
180
199
|
if (routesWithParams.length > 0) {
|
|
@@ -183,7 +202,7 @@ async function scanRoutes(baseDir, options) {
|
|
|
183
202
|
getLogger().info(` ${route.rawRoute} → ${JSON.stringify(route.inferredParams)}`);
|
|
184
203
|
}
|
|
185
204
|
}
|
|
186
|
-
return sortedRoutes;
|
|
205
|
+
return { routes: sortedRoutes, errorPages };
|
|
187
206
|
}
|
|
188
207
|
function routeToExpressRoute(route) {
|
|
189
208
|
const parts = [];
|
|
@@ -203,6 +222,7 @@ function routeToExpressRoute(route) {
|
|
|
203
222
|
export {
|
|
204
223
|
JayRouteParamType,
|
|
205
224
|
createRoute,
|
|
225
|
+
isStatusToken,
|
|
206
226
|
parseRouteSegments,
|
|
207
227
|
routeToExpressRoute,
|
|
208
228
|
scanRoutes,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jay-framework/stack-route-scanner",
|
|
3
|
-
"version": "0.25.
|
|
3
|
+
"version": "0.25.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.mts",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"readme.md"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@jay-framework/logger": "^0.25.
|
|
12
|
+
"@jay-framework/logger": "^0.25.2",
|
|
13
13
|
"node-html-parser": "^6.1.12",
|
|
14
14
|
"yaml": "^2.3.4"
|
|
15
15
|
},
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"test:watch": "vitest"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@jay-framework/dev-environment": "^0.25.
|
|
28
|
+
"@jay-framework/dev-environment": "^0.25.2",
|
|
29
29
|
"@types/node": "^20.11.5",
|
|
30
30
|
"nodemon": "^3.0.3",
|
|
31
31
|
"replace-in-file": "^7.1.0",
|