@decantr/verifier 3.5.0 → 3.5.4

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.js CHANGED
@@ -2363,6 +2363,8 @@ var STYLE_EXTENSIONS = /* @__PURE__ */ new Set([".css", ".scss", ".sass", ".less
2363
2363
  var PAGE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".js", ".jsx", ".vue", ".svelte", ".html"]);
2364
2364
  var ROUTE_VARIABLE_NAMES = "(?:path|pathname|route|currentPath|currentRoute|locationPath|activePath)";
2365
2365
  var ROUTE_ASSET_EXTENSION_RE = /\.(?:avif|bmp|css|gif|ico|jpeg|jpg|js|json|map|mp4|pdf|png|svg|webp|woff2?)$/i;
2366
+ var JSX_ROUTE_PATH_RE = /<(?:Route|[A-Z][\w.]*Route)\b[^>]*\bpath\s*=\s*(?:"([^"]+)"|'([^']+)'|{\s*"([^"]+)"\s*}|{\s*'([^']+)'\s*}|{\s*`([^`]+)`\s*})/g;
2367
+ var OBJECT_ROUTE_PATH_RE = /\bpath\s*:\s*(?:"([^"]+)"|'([^']+)'|`([^`]+)`)/g;
2366
2368
  var MAX_FILE_READ_BYTES = 512 * 1024;
2367
2369
  var MAX_WALK_FILES = 5e3;
2368
2370
  var MAX_REPORT_ROUTES = 80;
@@ -2629,9 +2631,12 @@ function fileRouteFromPath(file, baseDir) {
2629
2631
  function scanFileRoutes(projectRoot, baseDir, extensions = PAGE_EXTENSIONS) {
2630
2632
  const fullBase = join3(projectRoot, baseDir);
2631
2633
  if (!existsSync3(fullBase)) return [];
2632
- return walkFiles(fullBase, { extensions }).map((file) => {
2634
+ return walkFiles(fullBase, { extensions }).flatMap((file) => {
2635
+ const baseName = file.split("/").pop() ?? file;
2636
+ const routeFileName = baseName.slice(0, -extname3(baseName).length);
2637
+ if (routeFileName.startsWith("_")) return [];
2633
2638
  const rel = relative3(projectRoot, join3(fullBase, file)).replace(/\\/g, "/");
2634
- return { path: fileRouteFromPath(rel, baseDir), file: rel, hasLayout: false };
2639
+ return [{ path: fileRouteFromPath(rel, baseDir), file: rel, hasLayout: false }];
2635
2640
  });
2636
2641
  }
2637
2642
  function scanReactRouter(projectRoot) {
@@ -2642,37 +2647,57 @@ function scanReactRouter(projectRoot) {
2642
2647
  const content = readTextFile(join3(projectRoot, file));
2643
2648
  if (!content) continue;
2644
2649
  if (content.includes("HashRouter") || content.includes("createHashRouter")) hashRouting = true;
2645
- const jsxRouteRegex = /<Route\b[^>]*\bpath\s*=\s*["']([^"']+)["']/g;
2646
- for (const match of content.matchAll(jsxRouteRegex)) {
2647
- const route = normalizeDetectedRouteLiteral(match[1] || "/");
2648
- if (route) routes.set(route, { path: route, file, hasLayout: false });
2650
+ for (const match of content.matchAll(JSX_ROUTE_PATH_RE)) {
2651
+ const literal = firstRouteLiteralMatch(match);
2652
+ for (const route of normalizeDetectedRouteLiterals(literal || "/")) {
2653
+ routes.set(route, { path: route, file, hasLayout: false });
2654
+ }
2649
2655
  }
2650
- const objectRouteRegex = /\bpath\s*:\s*["']([^"']+)["']/g;
2651
- for (const match of content.matchAll(objectRouteRegex)) {
2652
- const route = normalizeDetectedRouteLiteral(match[1] || "/");
2653
- if (route) routes.set(route, { path: route, file, hasLayout: false });
2656
+ for (const match of content.matchAll(OBJECT_ROUTE_PATH_RE)) {
2657
+ const literal = firstRouteLiteralMatch(match);
2658
+ for (const route of normalizeDetectedRouteLiterals(literal || "/")) {
2659
+ routes.set(route, { path: route, file, hasLayout: false });
2660
+ }
2654
2661
  }
2655
2662
  for (const route of detectPathnameBranchRoutes(content)) {
2656
2663
  routes.set(route, { path: route, file, hasLayout: false });
2657
2664
  }
2665
+ for (const route of detectDeclarativeRouteSpecRoutes(content)) {
2666
+ routes.set(route, { path: route, file, hasLayout: false });
2667
+ }
2658
2668
  }
2659
2669
  return { routes: [...routes.values()], hashRouting };
2660
2670
  }
2661
- function normalizeDetectedRouteLiteral(value) {
2662
- const cleaned = value.trim().split(/[?#]/)[0];
2663
- if (!cleaned || cleaned === "/") return "/";
2664
- if (cleaned === "*" || cleaned === "**" || cleaned.startsWith("#")) return null;
2665
- if (!cleaned.startsWith("/") || cleaned.startsWith("//")) return null;
2666
- if (ROUTE_ASSET_EXTENSION_RE.test(cleaned)) return null;
2667
- return cleaned.replace(/\/+$/g, "") || "/";
2671
+ function firstRouteLiteralMatch(match) {
2672
+ return match.slice(1).find((value) => typeof value === "string") ?? null;
2673
+ }
2674
+ function normalizeDetectedRouteLiterals(value) {
2675
+ const withoutHash = value.trim().split("#")[0];
2676
+ const cleaned = withoutHash.includes("?") && !withoutHash.endsWith(")?") ? withoutHash.split("?")[0] : withoutHash;
2677
+ if (!cleaned || cleaned === "/") return ["/"];
2678
+ if (cleaned === "*" || cleaned === "**" || cleaned.startsWith("#")) return [];
2679
+ if (cleaned === "/*" || cleaned === "/**") return [];
2680
+ if (!cleaned.startsWith("/") || cleaned.startsWith("//")) return [];
2681
+ if (ROUTE_ASSET_EXTENSION_RE.test(cleaned)) return [];
2682
+ const optionalGroup = cleaned.match(/^\/\(([^()]+)\)\?$/);
2683
+ if (optionalGroup) {
2684
+ return [
2685
+ "/",
2686
+ ...optionalGroup[1].split("|").map((segment) => segment.trim()).filter(Boolean).map((segment) => `/${segment}`)
2687
+ ];
2688
+ }
2689
+ const withoutTrailingWildcard = cleaned.endsWith("*") && !cleaned.endsWith("/*") && !/:\w+\*$/.test(cleaned) ? cleaned.slice(0, -1) : cleaned;
2690
+ const normalized = withoutTrailingWildcard.replace(/\/+$/g, "") || "/";
2691
+ if (normalized === "/*" || normalized === "/**") return [];
2692
+ return [normalized];
2668
2693
  }
2669
2694
  function collectRouteLiterals(pattern, content, routes) {
2670
2695
  let count = 0;
2671
2696
  for (const match of content.matchAll(pattern)) {
2672
- const route = normalizeDetectedRouteLiteral(match[1] ?? "");
2673
- if (!route) continue;
2674
- routes.add(route);
2675
- count += 1;
2697
+ for (const route of normalizeDetectedRouteLiterals(match[1] ?? "")) {
2698
+ routes.add(route);
2699
+ count += 1;
2700
+ }
2676
2701
  }
2677
2702
  return count;
2678
2703
  }
@@ -2695,6 +2720,17 @@ function detectPathnameBranchRoutes(content) {
2695
2720
  }
2696
2721
  return [...routes];
2697
2722
  }
2723
+ function detectDeclarativeRouteSpecRoutes(content) {
2724
+ const routes = /* @__PURE__ */ new Set();
2725
+ const hasRouteSpecSignal = content.includes("@wasp.sh/spec") || /\b(?:const|export\s+const)\s+\w*Spec\b/.test(content) || /\bapp\s*\(\s*\{[\s\S]*\bspec\s*:/.test(content);
2726
+ if (!hasRouteSpecSignal) return [];
2727
+ collectRouteLiterals(
2728
+ /\broute\s*\(\s*["'`][^"'`]*["'`]\s*,\s*["'`](\/[^"'`]*)["'`]\s*,\s*page\s*\(/g,
2729
+ content,
2730
+ routes
2731
+ );
2732
+ return [...routes];
2733
+ }
2698
2734
  function scanRoutes(projectRoot, detection) {
2699
2735
  const appRoutes = ["src/app", "app"].flatMap(
2700
2736
  (dir) => existsSync3(join3(projectRoot, dir)) ? walkNextAppRoutes(join3(projectRoot, dir), projectRoot, []) : []