@rainfw/core 0.2.0 → 0.2.1
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/package.json +3 -2
- package/scripts/generate.js +78 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rainfw/core",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "A TypeScript web framework for Cloudflare Workers",
|
|
5
5
|
"bin": {
|
|
6
6
|
"rainjs": "./cli/index.js"
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
"test:generate": "node --test tests/generate.test.js",
|
|
22
22
|
"bench": "node scripts/bench.js",
|
|
23
23
|
"build:pkg": "tsc -p tsconfig.build.json && node -e \"require('fs').writeFileSync('dist/package.json',JSON.stringify({type:'module'}))\"",
|
|
24
|
-
"prepublishOnly": "npm run build:pkg"
|
|
24
|
+
"prepublishOnly": "npm run build:pkg",
|
|
25
|
+
"release": "npm run ci && npm publish --access public"
|
|
25
26
|
},
|
|
26
27
|
"keywords": [
|
|
27
28
|
"cloudflare-workers",
|
package/scripts/generate.js
CHANGED
|
@@ -271,6 +271,13 @@ function bundleClientFilesSync(clientFiles, srcDir) {
|
|
|
271
271
|
return scripts;
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
+
function stripRouteGroupSegments(filePath) {
|
|
275
|
+
return filePath
|
|
276
|
+
.split("/")
|
|
277
|
+
.filter((segment) => !/^\(.+\)$/.test(segment))
|
|
278
|
+
.join("/");
|
|
279
|
+
}
|
|
280
|
+
|
|
274
281
|
function routePathToDir(filePath) {
|
|
275
282
|
return filePath
|
|
276
283
|
.replace(/\\/g, "/")
|
|
@@ -285,6 +292,7 @@ function middlewareImportName(filePath) {
|
|
|
285
292
|
.replace(/\//g, "_")
|
|
286
293
|
.replace(/\[/g, "$")
|
|
287
294
|
.replace(/\]/g, "")
|
|
295
|
+
.replace(/[()]/g, "")
|
|
288
296
|
.replace(/-/g, "_")
|
|
289
297
|
.replace(/_+$/, "");
|
|
290
298
|
return `mw_${base || "root"}`;
|
|
@@ -307,6 +315,7 @@ function layoutPathToDir(filePath) {
|
|
|
307
315
|
function pageFilePathToUrlPath(filePath) {
|
|
308
316
|
let urlPath = filePath.replace(/\.tsx?$/, "");
|
|
309
317
|
urlPath = urlPath.replace(/\\/g, "/");
|
|
318
|
+
urlPath = stripRouteGroupSegments(urlPath);
|
|
310
319
|
urlPath = urlPath.replace(/\[([^\]]+)\]/g, ":$1");
|
|
311
320
|
urlPath = urlPath.replace(/\/page$/, "");
|
|
312
321
|
if (urlPath === "page") urlPath = "";
|
|
@@ -322,6 +331,7 @@ function pageFilePathToImportName(filePath) {
|
|
|
322
331
|
.replace(/\//g, "_")
|
|
323
332
|
.replace(/\[/g, "$")
|
|
324
333
|
.replace(/\]/g, "")
|
|
334
|
+
.replace(/[()]/g, "")
|
|
325
335
|
.replace(/-/g, "_")
|
|
326
336
|
);
|
|
327
337
|
}
|
|
@@ -333,6 +343,7 @@ function layoutImportName(filePath) {
|
|
|
333
343
|
.replace(/\//g, "_")
|
|
334
344
|
.replace(/\[/g, "$")
|
|
335
345
|
.replace(/\]/g, "")
|
|
346
|
+
.replace(/[()]/g, "")
|
|
336
347
|
.replace(/-/g, "_")
|
|
337
348
|
.replace(/_+$/, "");
|
|
338
349
|
return `layout_${base || "root"}`;
|
|
@@ -402,6 +413,63 @@ function validateNoPageRouteColocation(routeFiles, pageFiles) {
|
|
|
402
413
|
}
|
|
403
414
|
}
|
|
404
415
|
|
|
416
|
+
const routeUrlMap = new Map();
|
|
417
|
+
for (const f of routeFiles) {
|
|
418
|
+
routeUrlMap.set(filePathToUrlPath(f), f);
|
|
419
|
+
}
|
|
420
|
+
for (const pageFile of pageFiles) {
|
|
421
|
+
const url = pageFilePathToUrlPath(pageFile);
|
|
422
|
+
const conflicting = routeUrlMap.get(url);
|
|
423
|
+
if (conflicting) {
|
|
424
|
+
const pageDir = pageFilePathToDir(pageFile);
|
|
425
|
+
if (!routeDirs.has(pageDir)) {
|
|
426
|
+
errors.push(
|
|
427
|
+
`[Rain] Error: page "${pageFile}" and route "${conflicting}" resolve to the same URL path "${url}":\n` +
|
|
428
|
+
" → This conflict occurs because route group folders are stripped from URLs.\n" +
|
|
429
|
+
" → Move one of them to a different URL path.",
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return errors;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function validateNoDuplicateUrls(routeFiles, pageFiles) {
|
|
439
|
+
const errors = [];
|
|
440
|
+
|
|
441
|
+
const routeUrlMap = new Map();
|
|
442
|
+
for (const f of routeFiles) {
|
|
443
|
+
const url = filePathToUrlPath(f);
|
|
444
|
+
if (routeUrlMap.has(url)) {
|
|
445
|
+
errors.push(
|
|
446
|
+
`[Rain] Error: multiple route files resolve to the same URL path "${url}":\n` +
|
|
447
|
+
` → ${routeUrlMap.get(url)}\n` +
|
|
448
|
+
` → ${f}\n` +
|
|
449
|
+
" → Route group folders are stripped from URLs.\n" +
|
|
450
|
+
" → Rename one of the routes to avoid the conflict.",
|
|
451
|
+
);
|
|
452
|
+
} else {
|
|
453
|
+
routeUrlMap.set(url, f);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const pageUrlMap = new Map();
|
|
458
|
+
for (const f of pageFiles) {
|
|
459
|
+
const url = pageFilePathToUrlPath(f);
|
|
460
|
+
if (pageUrlMap.has(url)) {
|
|
461
|
+
errors.push(
|
|
462
|
+
`[Rain] Error: multiple page files resolve to the same URL path "${url}":\n` +
|
|
463
|
+
` → ${pageUrlMap.get(url)}\n` +
|
|
464
|
+
` → ${f}\n` +
|
|
465
|
+
" → Route group folders are stripped from URLs.\n" +
|
|
466
|
+
" → Rename one of the pages to avoid the conflict.",
|
|
467
|
+
);
|
|
468
|
+
} else {
|
|
469
|
+
pageUrlMap.set(url, f);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
|
|
405
473
|
return errors;
|
|
406
474
|
}
|
|
407
475
|
|
|
@@ -429,6 +497,7 @@ function getMiddlewaresForRoute(routeFile, middlewareFiles) {
|
|
|
429
497
|
function filePathToUrlPath(filePath) {
|
|
430
498
|
let urlPath = filePath.replace(/\.tsx?$/, "");
|
|
431
499
|
urlPath = urlPath.replace(/\\/g, "/");
|
|
500
|
+
urlPath = stripRouteGroupSegments(urlPath);
|
|
432
501
|
urlPath = urlPath.replace(/\[([^\]]+)\]/g, ":$1");
|
|
433
502
|
urlPath = urlPath.replace(/\/route$/, "");
|
|
434
503
|
if (urlPath === "route") urlPath = "";
|
|
@@ -444,6 +513,7 @@ function filePathToImportName(filePath) {
|
|
|
444
513
|
.replace(/\//g, "_")
|
|
445
514
|
.replace(/\[/g, "$")
|
|
446
515
|
.replace(/\]/g, "")
|
|
516
|
+
.replace(/[()]/g, "")
|
|
447
517
|
.replace(/-/g, "_")
|
|
448
518
|
);
|
|
449
519
|
}
|
|
@@ -750,6 +820,12 @@ function generate() {
|
|
|
750
820
|
process.exit(1);
|
|
751
821
|
}
|
|
752
822
|
|
|
823
|
+
const duplicateErrors = validateNoDuplicateUrls(files, pageFiles);
|
|
824
|
+
for (const err of duplicateErrors) {
|
|
825
|
+
console.error(err);
|
|
826
|
+
process.exit(1);
|
|
827
|
+
}
|
|
828
|
+
|
|
753
829
|
const hasRootLayout = layoutFiles.some((f) => layoutPathToDir(f) === "");
|
|
754
830
|
|
|
755
831
|
processMiddlewares(middlewareFiles, imports);
|
|
@@ -832,6 +908,8 @@ module.exports = {
|
|
|
832
908
|
detectUseClientDirective,
|
|
833
909
|
bundleClientFilesSync,
|
|
834
910
|
validateNoPageRouteColocation,
|
|
911
|
+
validateNoDuplicateUrls,
|
|
912
|
+
stripRouteGroupSegments,
|
|
835
913
|
ROUTES_DIR,
|
|
836
914
|
ENTRY_FILE,
|
|
837
915
|
HTTP_METHODS,
|