vinext 0.0.41 → 0.0.42

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 (162) hide show
  1. package/README.md +0 -1
  2. package/dist/build/client-build-config.d.ts +119 -0
  3. package/dist/build/client-build-config.js +149 -0
  4. package/dist/build/client-build-config.js.map +1 -0
  5. package/dist/build/layout-classification-types.d.ts +62 -0
  6. package/dist/build/layout-classification-types.js +1 -0
  7. package/dist/build/layout-classification.d.ts +60 -0
  8. package/dist/build/layout-classification.js +98 -0
  9. package/dist/build/layout-classification.js.map +1 -0
  10. package/dist/build/report.d.ts +15 -1
  11. package/dist/build/report.js +50 -1
  12. package/dist/build/report.js.map +1 -1
  13. package/dist/build/route-classification-manifest.d.ts +53 -0
  14. package/dist/build/route-classification-manifest.js +145 -0
  15. package/dist/build/route-classification-manifest.js.map +1 -0
  16. package/dist/build/run-prerender.js +1 -1
  17. package/dist/build/ssr-manifest.d.ts +19 -0
  18. package/dist/build/ssr-manifest.js +71 -0
  19. package/dist/build/ssr-manifest.js.map +1 -0
  20. package/dist/check.js +2 -2
  21. package/dist/check.js.map +1 -1
  22. package/dist/cli.js +1 -1
  23. package/dist/client/entry.js +1 -1
  24. package/dist/config/config-matchers.js +1 -0
  25. package/dist/config/config-matchers.js.map +1 -1
  26. package/dist/entries/app-rsc-entry.js +287 -95
  27. package/dist/entries/app-rsc-entry.js.map +1 -1
  28. package/dist/index.d.ts +1 -169
  29. package/dist/index.js +112 -432
  30. package/dist/index.js.map +1 -1
  31. package/dist/plugins/fonts.d.ts +49 -1
  32. package/dist/plugins/fonts.js +96 -3
  33. package/dist/plugins/fonts.js.map +1 -1
  34. package/dist/plugins/postcss.d.ts +27 -0
  35. package/dist/plugins/postcss.js +94 -0
  36. package/dist/plugins/postcss.js.map +1 -0
  37. package/dist/plugins/strip-server-exports.d.ts +14 -0
  38. package/dist/plugins/strip-server-exports.js +73 -0
  39. package/dist/plugins/strip-server-exports.js.map +1 -0
  40. package/dist/routing/app-router.d.ts +6 -4
  41. package/dist/routing/app-router.js +21 -22
  42. package/dist/routing/app-router.js.map +1 -1
  43. package/dist/server/app-browser-entry.js +235 -97
  44. package/dist/server/app-browser-entry.js.map +1 -1
  45. package/dist/server/app-browser-error.d.ts +8 -0
  46. package/dist/server/app-browser-error.js +9 -0
  47. package/dist/server/app-browser-error.js.map +1 -0
  48. package/dist/server/app-browser-state.d.ts +93 -0
  49. package/dist/server/app-browser-state.js +132 -0
  50. package/dist/server/app-browser-state.js.map +1 -0
  51. package/dist/server/app-elements.d.ts +92 -0
  52. package/dist/server/app-elements.js +122 -0
  53. package/dist/server/app-elements.js.map +1 -0
  54. package/dist/server/app-page-boundary-render.d.ts +2 -1
  55. package/dist/server/app-page-boundary-render.js +40 -1
  56. package/dist/server/app-page-boundary-render.js.map +1 -1
  57. package/dist/server/app-page-cache.d.ts +6 -3
  58. package/dist/server/app-page-cache.js +14 -8
  59. package/dist/server/app-page-cache.js.map +1 -1
  60. package/dist/server/app-page-execution.d.ts +36 -3
  61. package/dist/server/app-page-execution.js +50 -10
  62. package/dist/server/app-page-execution.js.map +1 -1
  63. package/dist/server/app-page-probe.d.ts +10 -4
  64. package/dist/server/app-page-probe.js +24 -15
  65. package/dist/server/app-page-probe.js.map +1 -1
  66. package/dist/server/app-page-render.d.ts +7 -4
  67. package/dist/server/app-page-render.js +13 -4
  68. package/dist/server/app-page-render.js.map +1 -1
  69. package/dist/server/app-page-request.d.ts +52 -4
  70. package/dist/server/app-page-request.js +86 -16
  71. package/dist/server/app-page-request.js.map +1 -1
  72. package/dist/server/app-page-response.d.ts +1 -0
  73. package/dist/server/app-page-response.js +1 -0
  74. package/dist/server/app-page-response.js.map +1 -1
  75. package/dist/server/app-page-route-wiring.d.ts +22 -8
  76. package/dist/server/app-page-route-wiring.js +219 -83
  77. package/dist/server/app-page-route-wiring.js.map +1 -1
  78. package/dist/server/app-render-dependency.d.ts +13 -0
  79. package/dist/server/app-render-dependency.js +35 -0
  80. package/dist/server/app-render-dependency.js.map +1 -0
  81. package/dist/server/app-route-handler-execution.d.ts +1 -0
  82. package/dist/server/app-route-handler-execution.js +1 -0
  83. package/dist/server/app-route-handler-execution.js.map +1 -1
  84. package/dist/server/app-route-handler-runtime.d.ts +1 -0
  85. package/dist/server/app-route-handler-runtime.js +26 -1
  86. package/dist/server/app-route-handler-runtime.js.map +1 -1
  87. package/dist/server/app-ssr-entry.js +6 -2
  88. package/dist/server/app-ssr-entry.js.map +1 -1
  89. package/dist/server/dev-server.js +2 -4
  90. package/dist/server/dev-server.js.map +1 -1
  91. package/dist/server/middleware.js +1 -5
  92. package/dist/server/middleware.js.map +1 -1
  93. package/dist/server/prod-server.d.ts +3 -3
  94. package/dist/server/prod-server.js +1 -1
  95. package/dist/server/prod-server.js.map +1 -1
  96. package/dist/server/request-pipeline.d.ts +2 -1
  97. package/dist/server/request-pipeline.js +34 -5
  98. package/dist/server/request-pipeline.js.map +1 -1
  99. package/dist/shims/cache-runtime.d.ts +1 -0
  100. package/dist/shims/cache-runtime.js +0 -5
  101. package/dist/shims/cache-runtime.js.map +1 -1
  102. package/dist/shims/cache.d.ts +1 -0
  103. package/dist/shims/cache.js +1 -8
  104. package/dist/shims/cache.js.map +1 -1
  105. package/dist/shims/client-hook-error.d.ts +14 -0
  106. package/dist/shims/client-hook-error.js +19 -0
  107. package/dist/shims/client-hook-error.js.map +1 -0
  108. package/dist/shims/constants.d.ts +3 -3
  109. package/dist/shims/constants.js +3 -3
  110. package/dist/shims/constants.js.map +1 -1
  111. package/dist/shims/document.d.ts +6 -6
  112. package/dist/shims/error-boundary.d.ts +4 -4
  113. package/dist/shims/error-boundary.js +1 -1
  114. package/dist/shims/error-boundary.js.map +1 -1
  115. package/dist/shims/form.d.ts +3 -3
  116. package/dist/shims/head-state.d.ts +1 -0
  117. package/dist/shims/head-state.js +0 -5
  118. package/dist/shims/head-state.js.map +1 -1
  119. package/dist/shims/headers.d.ts +11 -0
  120. package/dist/shims/headers.js +13 -10
  121. package/dist/shims/headers.js.map +1 -1
  122. package/dist/shims/i18n-state.d.ts +1 -0
  123. package/dist/shims/i18n-state.js +0 -4
  124. package/dist/shims/i18n-state.js.map +1 -1
  125. package/dist/shims/internal/app-router-context.d.ts +6 -6
  126. package/dist/shims/internal/router-context.d.ts +2 -2
  127. package/dist/shims/layout-segment-context.d.ts +2 -2
  128. package/dist/shims/link.js +19 -11
  129. package/dist/shims/link.js.map +1 -1
  130. package/dist/shims/metadata.d.ts +3 -3
  131. package/dist/shims/navigation-state.d.ts +2 -0
  132. package/dist/shims/navigation-state.js +0 -13
  133. package/dist/shims/navigation-state.js.map +1 -1
  134. package/dist/shims/navigation.d.ts +55 -8
  135. package/dist/shims/navigation.js +97 -23
  136. package/dist/shims/navigation.js.map +1 -1
  137. package/dist/shims/navigation.react-server.d.ts +14 -0
  138. package/dist/shims/navigation.react-server.js +29 -0
  139. package/dist/shims/navigation.react-server.js.map +1 -0
  140. package/dist/shims/request-context.d.ts +1 -0
  141. package/dist/shims/request-context.js +0 -9
  142. package/dist/shims/request-context.js.map +1 -1
  143. package/dist/shims/request-state-types.d.ts +1 -1
  144. package/dist/shims/router-state.d.ts +1 -0
  145. package/dist/shims/router-state.js +0 -5
  146. package/dist/shims/router-state.js.map +1 -1
  147. package/dist/shims/slot.d.ts +11 -7
  148. package/dist/shims/slot.js +28 -19
  149. package/dist/shims/slot.js.map +1 -1
  150. package/dist/shims/unified-request-context.d.ts +2 -0
  151. package/dist/shims/unified-request-context.js +0 -14
  152. package/dist/shims/unified-request-context.js.map +1 -1
  153. package/dist/utils/mdx-scan.d.ts +10 -0
  154. package/dist/utils/mdx-scan.js +36 -0
  155. package/dist/utils/mdx-scan.js.map +1 -0
  156. package/dist/utils/public-routes.d.ts +5 -0
  157. package/dist/utils/public-routes.js +50 -0
  158. package/dist/utils/public-routes.js.map +1 -0
  159. package/package.json +3 -3
  160. package/dist/plugins/fix-use-server-closure-collision.d.ts +0 -29
  161. package/dist/plugins/fix-use-server-closure-collision.js +0 -204
  162. package/dist/plugins/fix-use-server-closure-collision.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","names":[],"sources":["../../src/build/report.ts"],"sourcesContent":["/**\n * Build report — prints a Next.js-style route table after `vinext build`.\n *\n * Classifies every discovered route as:\n * ○ Static — confirmed static: force-static or revalidate=Infinity\n * ◐ ISR — statically rendered, revalidated on a timer (revalidate=N)\n * ƒ Dynamic — confirmed dynamic: force-dynamic, revalidate=0, or getServerSideProps\n * ? Unknown — no explicit config; likely dynamic but not confirmed\n * λ API — API route handler\n *\n * Classification uses regex-based static source analysis (no module\n * execution). Vite's parseAst() is NOT used because it doesn't handle\n * TypeScript syntax.\n *\n * Limitation: without running the build, we cannot detect dynamic API usage\n * (headers(), cookies(), connection(), etc.) that implicitly forces a route\n * dynamic. Routes without explicit `export const dynamic` or\n * `export const revalidate` are classified as \"unknown\" rather than \"static\"\n * to avoid false confidence.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { Route } from \"../routing/pages-router.js\";\nimport type { AppRoute } from \"../routing/app-router.js\";\nimport type { PrerenderResult } from \"./prerender.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type RouteType = \"static\" | \"isr\" | \"ssr\" | \"unknown\" | \"api\";\n\nexport type RouteRow = {\n pattern: string;\n type: RouteType;\n /** Only set for `isr` routes. */\n revalidate?: number;\n /**\n * True when the route was classified as `static` by speculative prerender\n * (i.e. was `unknown` from static analysis but rendered successfully).\n * Used by `formatBuildReport` to add a note in the legend.\n */\n prerendered?: boolean;\n};\n\n// ─── Regex-based export detection ────────────────────────────────────────────\n\n/**\n * Returns true if the source code contains a named export with the given name.\n * Handles all three common export forms:\n * export function foo() {}\n * export const foo = ...\n * export { foo }\n */\nexport function hasNamedExport(code: string, name: string): boolean {\n // Function / generator / async function declaration\n const fnRe = new RegExp(`(?:^|\\\\n)\\\\s*export\\\\s+(?:async\\\\s+)?function\\\\s+${name}\\\\b`);\n if (fnRe.test(code)) return true;\n\n // Variable declaration (const / let / var)\n const varRe = new RegExp(`(?:^|\\\\n)\\\\s*export\\\\s+(?:const|let|var)\\\\s+${name}\\\\s*[=:]`);\n if (varRe.test(code)) return true;\n\n // Re-export specifier: export { foo } or export { foo as bar }\n const reRe = new RegExp(`export\\\\s*\\\\{[^}]*\\\\b${name}\\\\b[^}]*\\\\}`);\n if (reRe.test(code)) return true;\n\n return false;\n}\n\n/**\n * Extracts the string value of `export const <name> = \"value\"`.\n * Handles optional TypeScript type annotations:\n * export const dynamic: string = \"force-dynamic\"\n * Returns null if the export is absent or not a string literal.\n */\nexport function extractExportConstString(code: string, name: string): string | null {\n const re = new RegExp(\n `^\\\\s*export\\\\s+const\\\\s+${name}\\\\s*(?::[^=]+)?\\\\s*=\\\\s*['\"]([^'\"]+)['\"]`,\n \"m\",\n );\n const m = re.exec(code);\n return m ? m[1] : null;\n}\n\n/**\n * Extracts the numeric value of `export const <name> = <number>`.\n * Supports integers, decimals, negative values, and `Infinity`.\n * Handles optional TypeScript type annotations.\n * Returns null if the export is absent or not a number.\n */\nexport function extractExportConstNumber(code: string, name: string): number | null {\n const re = new RegExp(\n `^\\\\s*export\\\\s+const\\\\s+${name}\\\\s*(?::[^=]+)?\\\\s*=\\\\s*(-?\\\\d+(?:\\\\.\\\\d+)?|Infinity)`,\n \"m\",\n );\n const m = re.exec(code);\n if (!m) return null;\n return m[1] === \"Infinity\" ? Infinity : parseFloat(m[1]);\n}\n\n/**\n * Extracts the `revalidate` value from inside a `getStaticProps` return object.\n * Looks for: revalidate: <number> or revalidate: false or revalidate: Infinity\n *\n * Returns:\n * number — a positive revalidation interval (enables ISR)\n * 0 — treat as SSR (revalidate every request)\n * false — fully static (no revalidation)\n * Infinity — fully static (treated same as false by Next.js)\n * null — no `revalidate` key found (fully static)\n */\nexport function extractGetStaticPropsRevalidate(code: string): number | false | null {\n const returnObjects = extractGetStaticPropsReturnObjects(code);\n\n if (returnObjects) {\n for (const searchSpace of returnObjects) {\n const revalidate = extractTopLevelRevalidateValue(searchSpace);\n if (revalidate !== null) return revalidate;\n }\n return null;\n }\n\n const m = /\\brevalidate\\s*:\\s*(-?\\d+(?:\\.\\d+)?|Infinity|false)\\b/.exec(code);\n if (!m) return null;\n if (m[1] === \"false\") return false;\n if (m[1] === \"Infinity\") return Infinity;\n return parseFloat(m[1]);\n}\n\nfunction extractTopLevelRevalidateValue(code: string): number | false | null {\n let braceDepth = 0;\n let parenDepth = 0;\n let bracketDepth = 0;\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let inLineComment = false;\n let inBlockComment = false;\n\n for (let i = 0; i < code.length; i++) {\n const char = code[i];\n const next = code[i + 1];\n\n if (inLineComment) {\n if (char === \"\\n\") inLineComment = false;\n continue;\n }\n\n if (inBlockComment) {\n if (char === \"*\" && next === \"/\") {\n inBlockComment = false;\n i++;\n }\n continue;\n }\n\n if (quote) {\n if (char === \"\\\\\") {\n i++;\n continue;\n }\n if (char === quote) quote = null;\n continue;\n }\n\n if (char === \"/\" && next === \"/\") {\n inLineComment = true;\n i++;\n continue;\n }\n\n if (char === \"/\" && next === \"*\") {\n inBlockComment = true;\n i++;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n continue;\n }\n\n if (char === \"{\") {\n braceDepth++;\n continue;\n }\n\n if (char === \"}\") {\n braceDepth--;\n continue;\n }\n\n if (char === \"(\") {\n parenDepth++;\n continue;\n }\n\n if (char === \")\") {\n parenDepth--;\n continue;\n }\n\n if (char === \"[\") {\n bracketDepth++;\n continue;\n }\n\n if (char === \"]\") {\n bracketDepth--;\n continue;\n }\n\n if (\n braceDepth === 1 &&\n parenDepth === 0 &&\n bracketDepth === 0 &&\n matchesKeywordAt(code, i, \"revalidate\")\n ) {\n const colonIndex = findNextNonWhitespaceIndex(code, i + \"revalidate\".length);\n if (colonIndex === -1 || code[colonIndex] !== \":\") continue;\n\n const valueStart = findNextNonWhitespaceIndex(code, colonIndex + 1);\n if (valueStart === -1) return null;\n\n const valueMatch = /^(-?\\d+(?:\\.\\d+)?|Infinity|false)\\b/.exec(code.slice(valueStart));\n if (!valueMatch) return null;\n if (valueMatch[1] === \"false\") return false;\n if (valueMatch[1] === \"Infinity\") return Infinity;\n return parseFloat(valueMatch[1]);\n }\n }\n\n return null;\n}\n\nfunction extractGetStaticPropsReturnObjects(code: string): string[] | null {\n const declarationMatch =\n /(?:^|\\n)\\s*(?:export\\s+)?(?:async\\s+)?function\\s+getStaticProps\\b|(?:^|\\n)\\s*(?:export\\s+)?(?:const|let|var)\\s+getStaticProps\\b/.exec(\n code,\n );\n if (!declarationMatch) {\n // A file can re-export getStaticProps from another module without defining\n // it locally. In that case we can't safely infer revalidate from this file,\n // so skip the whole-file fallback to avoid unrelated false positives.\n if (/(?:^|\\n)\\s*export\\s*\\{[^}]*\\bgetStaticProps\\b[^}]*\\}\\s*from\\b/.test(code)) {\n return [];\n }\n return null;\n }\n\n const declaration = extractGetStaticPropsDeclaration(code, declarationMatch);\n if (declaration === null) return [];\n\n const returnObjects = declaration.trimStart().startsWith(\"{\")\n ? collectReturnObjectsFromFunctionBody(declaration)\n : [];\n\n if (returnObjects.length > 0) return returnObjects;\n\n const arrowMatch = declaration.search(/=>\\s*\\(\\s*\\{/);\n // getStaticProps was found but contains no return objects — return empty\n // (non-null signals the caller to skip the whole-file fallback).\n if (arrowMatch === -1) return [];\n\n const braceStart = declaration.indexOf(\"{\", arrowMatch);\n if (braceStart === -1) return [];\n\n const braceEnd = findMatchingBrace(declaration, braceStart);\n if (braceEnd === -1) return [];\n\n return [declaration.slice(braceStart, braceEnd + 1)];\n}\n\nfunction extractGetStaticPropsDeclaration(\n code: string,\n declarationMatch: RegExpExecArray,\n): string | null {\n const declarationStart = declarationMatch.index;\n const declarationText = declarationMatch[0];\n const declarationTail = code.slice(declarationStart);\n\n if (declarationText.includes(\"function getStaticProps\")) {\n return extractFunctionBody(code, declarationStart + declarationText.length);\n }\n\n const functionExpressionMatch = /(?:async\\s+)?function\\b/.exec(declarationTail);\n if (functionExpressionMatch) {\n return extractFunctionBody(declarationTail, functionExpressionMatch.index);\n }\n\n const blockBodyMatch = /=>\\s*\\{/.exec(declarationTail);\n if (blockBodyMatch) {\n const braceStart = declarationTail.indexOf(\"{\", blockBodyMatch.index);\n if (braceStart === -1) return null;\n\n const braceEnd = findMatchingBrace(declarationTail, braceStart);\n if (braceEnd === -1) return null;\n\n return declarationTail.slice(braceStart, braceEnd + 1);\n }\n\n const implicitArrowMatch = declarationTail.search(/=>\\s*\\(\\s*\\{/);\n if (implicitArrowMatch === -1) return null;\n\n const implicitBraceStart = declarationTail.indexOf(\"{\", implicitArrowMatch);\n if (implicitBraceStart === -1) return null;\n\n const implicitBraceEnd = findMatchingBrace(declarationTail, implicitBraceStart);\n if (implicitBraceEnd === -1) return null;\n\n return declarationTail.slice(0, implicitBraceEnd + 1);\n}\n\nfunction extractFunctionBody(code: string, functionStart: number): string | null {\n const bodyEnd = findFunctionBodyEnd(code, functionStart);\n if (bodyEnd === -1) return null;\n\n const paramsStart = code.indexOf(\"(\", functionStart);\n if (paramsStart === -1) return null;\n\n const paramsEnd = findMatchingParen(code, paramsStart);\n if (paramsEnd === -1) return null;\n\n const bodyStart = code.indexOf(\"{\", paramsEnd + 1);\n if (bodyStart === -1) return null;\n\n return code.slice(bodyStart, bodyEnd + 1);\n}\n\nfunction collectReturnObjectsFromFunctionBody(code: string): string[] {\n const returnObjects: string[] = [];\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let inLineComment = false;\n let inBlockComment = false;\n\n for (let i = 0; i < code.length; i++) {\n const char = code[i];\n const next = code[i + 1];\n\n if (inLineComment) {\n if (char === \"\\n\") inLineComment = false;\n continue;\n }\n\n if (inBlockComment) {\n if (char === \"*\" && next === \"/\") {\n inBlockComment = false;\n i++;\n }\n continue;\n }\n\n if (quote) {\n if (char === \"\\\\\") {\n i++;\n continue;\n }\n if (char === quote) quote = null;\n continue;\n }\n\n if (char === \"/\" && next === \"/\") {\n inLineComment = true;\n i++;\n continue;\n }\n\n if (char === \"/\" && next === \"*\") {\n inBlockComment = true;\n i++;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n continue;\n }\n\n if (matchesKeywordAt(code, i, \"function\")) {\n const nestedBodyEnd = findFunctionBodyEnd(code, i);\n if (nestedBodyEnd !== -1) {\n i = nestedBodyEnd;\n }\n continue;\n }\n\n if (matchesKeywordAt(code, i, \"class\")) {\n const classBodyEnd = findClassBodyEnd(code, i);\n if (classBodyEnd !== -1) {\n i = classBodyEnd;\n }\n continue;\n }\n\n if (char === \"=\" && next === \">\") {\n const nestedBodyEnd = findArrowFunctionBodyEnd(code, i);\n if (nestedBodyEnd !== -1) {\n i = nestedBodyEnd;\n }\n continue;\n }\n\n if (\n (char >= \"A\" && char <= \"Z\") ||\n (char >= \"a\" && char <= \"z\") ||\n char === \"_\" ||\n char === \"$\" ||\n char === \"*\"\n ) {\n const methodBodyEnd = findObjectMethodBodyEnd(code, i);\n if (methodBodyEnd !== -1) {\n i = methodBodyEnd;\n continue;\n }\n }\n\n if (matchesKeywordAt(code, i, \"return\")) {\n const braceStart = findNextNonWhitespaceIndex(code, i + \"return\".length);\n if (braceStart === -1 || code[braceStart] !== \"{\") continue;\n\n const braceEnd = findMatchingBrace(code, braceStart);\n if (braceEnd === -1) continue;\n\n returnObjects.push(code.slice(braceStart, braceEnd + 1));\n i = braceEnd;\n }\n }\n\n return returnObjects;\n}\n\nfunction findFunctionBodyEnd(code: string, functionStart: number): number {\n const paramsStart = code.indexOf(\"(\", functionStart);\n if (paramsStart === -1) return -1;\n\n const paramsEnd = findMatchingParen(code, paramsStart);\n if (paramsEnd === -1) return -1;\n\n const bodyStart = code.indexOf(\"{\", paramsEnd + 1);\n if (bodyStart === -1) return -1;\n\n return findMatchingBrace(code, bodyStart);\n}\n\nfunction findClassBodyEnd(code: string, classStart: number): number {\n const bodyStart = code.indexOf(\"{\", classStart + \"class\".length);\n if (bodyStart === -1) return -1;\n\n return findMatchingBrace(code, bodyStart);\n}\n\nfunction findArrowFunctionBodyEnd(code: string, arrowIndex: number): number {\n const bodyStart = findNextNonWhitespaceIndex(code, arrowIndex + 2);\n if (bodyStart === -1 || code[bodyStart] !== \"{\") return -1;\n\n return findMatchingBrace(code, bodyStart);\n}\n\nfunction findObjectMethodBodyEnd(code: string, start: number): number {\n let i = start;\n\n if (matchesKeywordAt(code, i, \"async\")) {\n const afterAsync = findNextNonWhitespaceIndex(code, i + \"async\".length);\n if (afterAsync === -1) return -1;\n if (code[afterAsync] !== \"(\") {\n i = afterAsync;\n }\n }\n\n if (code[i] === \"*\") {\n i = findNextNonWhitespaceIndex(code, i + 1);\n if (i === -1) return -1;\n }\n\n if (!/[A-Za-z_$]/.test(code[i] ?? \"\")) return -1;\n\n const nameStart = i;\n while (/[A-Za-z0-9_$]/.test(code[i] ?? \"\")) i++;\n const name = code.slice(nameStart, i);\n\n if (\n name === \"if\" ||\n name === \"for\" ||\n name === \"while\" ||\n name === \"switch\" ||\n name === \"catch\" ||\n name === \"function\" ||\n name === \"return\" ||\n name === \"const\" ||\n name === \"let\" ||\n name === \"var\" ||\n name === \"new\"\n ) {\n return -1;\n }\n\n if (name === \"get\" || name === \"set\") {\n const afterAccessor = findNextNonWhitespaceIndex(code, i);\n if (afterAccessor === -1) return -1;\n if (code[afterAccessor] !== \"(\") {\n i = afterAccessor;\n if (!/[A-Za-z_$]/.test(code[i] ?? \"\")) return -1;\n while (/[A-Za-z0-9_$]/.test(code[i] ?? \"\")) i++;\n }\n }\n\n const paramsStart = findNextNonWhitespaceIndex(code, i);\n if (paramsStart === -1 || code[paramsStart] !== \"(\") return -1;\n\n const paramsEnd = findMatchingParen(code, paramsStart);\n if (paramsEnd === -1) return -1;\n\n const bodyStart = findNextNonWhitespaceIndex(code, paramsEnd + 1);\n if (bodyStart === -1 || code[bodyStart] !== \"{\") return -1;\n\n return findMatchingBrace(code, bodyStart);\n}\n\nfunction findNextNonWhitespaceIndex(code: string, start: number): number {\n for (let i = start; i < code.length; i++) {\n if (!/\\s/.test(code[i])) return i;\n }\n return -1;\n}\n\nfunction matchesKeywordAt(code: string, index: number, keyword: string): boolean {\n const before = index === 0 ? \"\" : code[index - 1];\n const after = code[index + keyword.length] ?? \"\";\n return (\n code.startsWith(keyword, index) &&\n (before === \"\" || !/[A-Za-z0-9_$]/.test(before)) &&\n (after === \"\" || !/[A-Za-z0-9_$]/.test(after))\n );\n}\n\nfunction findMatchingBrace(code: string, start: number): number {\n return findMatchingToken(code, start, \"{\", \"}\");\n}\n\nfunction findMatchingParen(code: string, start: number): number {\n return findMatchingToken(code, start, \"(\", \")\");\n}\n\nfunction findMatchingToken(\n code: string,\n start: number,\n openToken: string,\n closeToken: string,\n): number {\n let depth = 0;\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let inLineComment = false;\n let inBlockComment = false;\n\n for (let i = start; i < code.length; i++) {\n const char = code[i];\n const next = code[i + 1];\n\n if (inLineComment) {\n if (char === \"\\n\") inLineComment = false;\n continue;\n }\n\n if (inBlockComment) {\n if (char === \"*\" && next === \"/\") {\n inBlockComment = false;\n i++;\n }\n continue;\n }\n\n if (quote) {\n if (char === \"\\\\\") {\n i++;\n continue;\n }\n if (char === quote) quote = null;\n continue;\n }\n\n if (char === \"/\" && next === \"/\") {\n inLineComment = true;\n i++;\n continue;\n }\n\n if (char === \"/\" && next === \"*\") {\n inBlockComment = true;\n i++;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n continue;\n }\n\n if (char === openToken) {\n depth++;\n continue;\n }\n\n if (char === closeToken) {\n depth--;\n if (depth === 0) return i;\n }\n }\n\n return -1;\n}\n\n// ─── Route classification ─────────────────────────────────────────────────────\n\n/**\n * Classifies a Pages Router page file by reading its source and examining\n * which data-fetching exports it contains.\n *\n * API routes (files under pages/api/) are always `api`.\n */\nexport function classifyPagesRoute(filePath: string): {\n type: RouteType;\n revalidate?: number;\n} {\n // API routes are identified by their path\n const normalized = filePath.replace(/\\\\/g, \"/\");\n if (normalized.includes(\"/pages/api/\")) {\n return { type: \"api\" };\n }\n\n let code: string;\n try {\n code = fs.readFileSync(filePath, \"utf8\");\n } catch {\n return { type: \"unknown\" };\n }\n\n if (hasNamedExport(code, \"getServerSideProps\")) {\n return { type: \"ssr\" };\n }\n\n if (hasNamedExport(code, \"getStaticProps\")) {\n const revalidate = extractGetStaticPropsRevalidate(code);\n\n if (revalidate === null || revalidate === false || revalidate === Infinity) {\n return { type: \"static\" };\n }\n if (revalidate === 0) {\n return { type: \"ssr\" };\n }\n // Positive number → ISR\n return { type: \"isr\", revalidate };\n }\n\n return { type: \"static\" };\n}\n\n/**\n * Classifies an App Router route.\n *\n * @param pagePath Absolute path to the page.tsx (null for API-only routes)\n * @param routePath Absolute path to the route.ts handler (null for page routes)\n * @param isDynamic Whether the URL pattern contains dynamic segments\n */\nexport function classifyAppRoute(\n pagePath: string | null,\n routePath: string | null,\n isDynamic: boolean,\n): { type: RouteType; revalidate?: number } {\n // Route handlers with no page component → API\n if (routePath !== null && pagePath === null) {\n return { type: \"api\" };\n }\n\n const filePath = pagePath ?? routePath;\n if (!filePath) return { type: \"unknown\" };\n\n let code: string;\n try {\n code = fs.readFileSync(filePath, \"utf8\");\n } catch {\n return { type: \"unknown\" };\n }\n\n // Check `export const dynamic`\n const dynamicValue = extractExportConstString(code, \"dynamic\");\n if (dynamicValue === \"force-dynamic\") {\n return { type: \"ssr\" };\n }\n if (dynamicValue === \"force-static\" || dynamicValue === \"error\") {\n // \"error\" enforces static rendering — it throws if dynamic APIs are used,\n // so the page is statically rendered (same as force-static for classification).\n return { type: \"static\" };\n }\n\n // Check `export const revalidate`\n const revalidateValue = extractExportConstNumber(code, \"revalidate\");\n if (revalidateValue !== null) {\n if (revalidateValue === Infinity) return { type: \"static\" };\n if (revalidateValue === 0) return { type: \"ssr\" };\n if (revalidateValue > 0) return { type: \"isr\", revalidate: revalidateValue };\n }\n\n // Fall back to isDynamic flag (dynamic URL segments without explicit config)\n if (isDynamic) return { type: \"ssr\" };\n\n // No explicit config and no dynamic URL segments — we can't confirm static\n // without running the build (dynamic API calls like headers() are invisible\n // to static analysis). Report as unknown rather than falsely claiming static.\n return { type: \"unknown\" };\n}\n\n// ─── Row building ─────────────────────────────────────────────────────────────\n\n/**\n * Builds a sorted list of RouteRow objects from the discovered routes.\n * Routes are sorted alphabetically by path, matching filesystem order.\n *\n * When `prerenderResult` is provided, routes that were classified as `unknown`\n * by static analysis but were successfully rendered speculatively are upgraded\n * to `static` (confirmed by execution). The `prerendered` flag is set on those\n * rows so the formatter can add a legend note.\n */\nexport function buildReportRows(options: {\n pageRoutes?: Route[];\n apiRoutes?: Route[];\n appRoutes?: AppRoute[];\n prerenderResult?: PrerenderResult;\n}): RouteRow[] {\n const rows: RouteRow[] = [];\n\n // Build a set of routes that were confirmed rendered by speculative prerender.\n const renderedRoutes = new Set<string>();\n if (options.prerenderResult) {\n for (const r of options.prerenderResult.routes) {\n if (r.status === \"rendered\") renderedRoutes.add(r.route);\n }\n }\n\n for (const route of options.pageRoutes ?? []) {\n const { type, revalidate } = classifyPagesRoute(route.filePath);\n rows.push({ pattern: route.pattern, type, revalidate });\n }\n\n for (const route of options.apiRoutes ?? []) {\n rows.push({ pattern: route.pattern, type: \"api\" });\n }\n\n for (const route of options.appRoutes ?? []) {\n const { type, revalidate } = classifyAppRoute(route.pagePath, route.routePath, route.isDynamic);\n if (type === \"unknown\" && renderedRoutes.has(route.pattern)) {\n // Speculative prerender confirmed this route is static.\n rows.push({ pattern: route.pattern, type: \"static\", prerendered: true });\n } else {\n rows.push({ pattern: route.pattern, type, revalidate });\n }\n }\n\n // Sort purely by path — mirrors filesystem order, matching Next.js output style\n rows.sort((a, b) => a.pattern.localeCompare(b.pattern));\n\n return rows;\n}\n\n// ─── Formatting ───────────────────────────────────────────────────────────────\n\nconst SYMBOLS: Record<RouteType, string> = {\n static: \"○\",\n isr: \"◐\",\n ssr: \"ƒ\",\n unknown: \"?\",\n api: \"λ\",\n};\n\nconst LABELS: Record<RouteType, string> = {\n static: \"Static\",\n isr: \"ISR\",\n ssr: \"Dynamic\",\n unknown: \"Unknown\",\n api: \"API\",\n};\n\n/**\n * Formats a list of RouteRows into a Next.js-style build report string.\n *\n * Example output:\n * Route (pages)\n * ┌ ○ /\n * ├ ◐ /blog/:slug (60s)\n * ├ ƒ /dashboard\n * └ λ /api/posts\n *\n * ○ Static ◐ ISR ƒ Dynamic λ API\n */\nexport function formatBuildReport(rows: RouteRow[], routerLabel = \"app\"): string {\n if (rows.length === 0) return \"\";\n\n const lines: string[] = [];\n lines.push(` Route (${routerLabel})`);\n\n // Determine padding width from the longest pattern\n const maxPatternLen = Math.max(...rows.map((r) => r.pattern.length));\n\n rows.forEach((row, i) => {\n const isLast = i === rows.length - 1;\n const corner = rows.length === 1 ? \"─\" : i === 0 ? \"┌\" : isLast ? \"└\" : \"├\";\n const sym = SYMBOLS[row.type];\n const suffix =\n row.type === \"isr\" && row.revalidate !== undefined ? ` (${row.revalidate}s)` : \"\";\n const padding = \" \".repeat(maxPatternLen - row.pattern.length);\n lines.push(` ${corner} ${sym} ${row.pattern}${padding}${suffix}`);\n });\n\n lines.push(\"\");\n\n // Legend — only include types that appear in this report, sorted alphabetically by label\n const usedTypes = [...new Set(rows.map((r) => r.type))].sort((a, b) =>\n LABELS[a].localeCompare(LABELS[b]),\n );\n lines.push(\" \" + usedTypes.map((t) => `${SYMBOLS[t]} ${LABELS[t]}`).join(\" \"));\n\n // Explanatory note — only shown when unknown routes are present\n if (usedTypes.includes(\"unknown\")) {\n lines.push(\"\");\n lines.push(\" ? Some routes could not be classified. vinext currently uses static analysis\");\n lines.push(\n \" and cannot detect dynamic API usage (headers(), cookies(), etc.) at build time.\",\n );\n lines.push(\" Automatic classification will be improved in a future release.\");\n }\n\n // Speculative-render note — shown when any routes were confirmed static by prerender\n const hasPrerendered = rows.some((r) => r.prerendered);\n if (hasPrerendered) {\n lines.push(\"\");\n lines.push(\n \" ○ Routes marked static were confirmed by speculative prerender (attempted render\",\n );\n lines.push(\" succeeded without dynamic API usage).\");\n }\n\n return lines.join(\"\\n\");\n}\n\n// ─── Directory detection ──────────────────────────────────────────────────────\n\nexport function findDir(root: string, ...candidates: string[]): string | null {\n for (const candidate of candidates) {\n const full = path.join(root, candidate);\n try {\n if (fs.statSync(full).isDirectory()) return full;\n } catch {\n // not found or not a directory — try next candidate\n }\n }\n return null;\n}\n\n// ─── Main entry point ─────────────────────────────────────────────────────────\n\n/**\n * Scans the project at `root`, classifies all routes, and prints the\n * Next.js-style build report to stdout.\n *\n * Called at the end of `vinext build` in cli.ts.\n */\nexport async function printBuildReport(options: {\n root: string;\n pageExtensions: string[];\n prerenderResult?: PrerenderResult;\n}): Promise<void> {\n const { root } = options;\n\n const appDir = findDir(root, \"app\", \"src/app\");\n const pagesDir = findDir(root, \"pages\", \"src/pages\");\n\n if (!appDir && !pagesDir) return;\n\n if (appDir) {\n // Dynamic import to avoid loading routing code unless needed\n const { appRouter } = await import(\"../routing/app-router.js\");\n const routes = await appRouter(appDir, options.pageExtensions);\n const rows = buildReportRows({ appRoutes: routes, prerenderResult: options.prerenderResult });\n if (rows.length > 0) {\n console.log(\"\\n\" + formatBuildReport(rows, \"app\"));\n }\n }\n\n if (pagesDir) {\n const { pagesRouter, apiRouter } = await import(\"../routing/pages-router.js\");\n const [pageRoutes, apiRoutes] = await Promise.all([\n pagesRouter(pagesDir, options.pageExtensions),\n apiRouter(pagesDir, options.pageExtensions),\n ]);\n const rows = buildReportRows({\n pageRoutes,\n apiRoutes,\n prerenderResult: options.prerenderResult,\n });\n if (rows.length > 0) {\n console.log(\"\\n\" + formatBuildReport(rows, \"pages\"));\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"report.js","names":[],"sources":["../../src/build/report.ts"],"sourcesContent":["/**\n * Build report — prints a Next.js-style route table after `vinext build`.\n *\n * Classifies every discovered route as:\n * ○ Static — confirmed static: force-static or revalidate=Infinity\n * ◐ ISR — statically rendered, revalidated on a timer (revalidate=N)\n * ƒ Dynamic — confirmed dynamic: force-dynamic, revalidate=0, or getServerSideProps\n * ? Unknown — no explicit config; likely dynamic but not confirmed\n * λ API — API route handler\n *\n * Classification uses regex-based static source analysis (no module\n * execution). Vite's parseAst() is NOT used because it doesn't handle\n * TypeScript syntax.\n *\n * Limitation: without running the build, we cannot detect dynamic API usage\n * (headers(), cookies(), connection(), etc.) that implicitly forces a route\n * dynamic. Routes without explicit `export const dynamic` or\n * `export const revalidate` are classified as \"unknown\" rather than \"static\"\n * to avoid false confidence.\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport type { Route } from \"../routing/pages-router.js\";\nimport type { AppRoute } from \"../routing/app-router.js\";\nimport type { LayoutBuildClassification } from \"./layout-classification-types.js\";\nimport type { PrerenderResult } from \"./prerender.js\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type RouteType = \"static\" | \"isr\" | \"ssr\" | \"unknown\" | \"api\";\n\nexport type RouteRow = {\n pattern: string;\n type: RouteType;\n /** Only set for `isr` routes. */\n revalidate?: number;\n /**\n * True when the route was classified as `static` by speculative prerender\n * (i.e. was `unknown` from static analysis but rendered successfully).\n * Used by `formatBuildReport` to add a note in the legend.\n */\n prerendered?: boolean;\n};\n\n// ─── Regex-based export detection ────────────────────────────────────────────\n\n/**\n * Returns true if the source code contains a named export with the given name.\n * Handles all three common export forms:\n * export function foo() {}\n * export const foo = ...\n * export { foo }\n */\nexport function hasNamedExport(code: string, name: string): boolean {\n // Function / generator / async function declaration\n const fnRe = new RegExp(`(?:^|\\\\n)\\\\s*export\\\\s+(?:async\\\\s+)?function\\\\s+${name}\\\\b`);\n if (fnRe.test(code)) return true;\n\n // Variable declaration (const / let / var)\n const varRe = new RegExp(`(?:^|\\\\n)\\\\s*export\\\\s+(?:const|let|var)\\\\s+${name}\\\\s*[=:]`);\n if (varRe.test(code)) return true;\n\n // Re-export specifier: export { foo } or export { foo as bar }\n const reRe = new RegExp(`export\\\\s*\\\\{[^}]*\\\\b${name}\\\\b[^}]*\\\\}`);\n if (reRe.test(code)) return true;\n\n return false;\n}\n\n/**\n * Extracts the string value of `export const <name> = \"value\"`.\n * Handles optional TypeScript type annotations:\n * export const dynamic: string = \"force-dynamic\"\n * Returns null if the export is absent or not a string literal.\n */\nexport function extractExportConstString(code: string, name: string): string | null {\n const re = new RegExp(\n `^\\\\s*export\\\\s+const\\\\s+${name}\\\\s*(?::[^=]+)?\\\\s*=\\\\s*['\"]([^'\"]+)['\"]`,\n \"m\",\n );\n const m = re.exec(code);\n return m ? m[1] : null;\n}\n\n/**\n * Extracts the numeric value of `export const <name> = <number>`.\n * Supports integers, decimals, negative values, and `Infinity`.\n * Handles optional TypeScript type annotations.\n * Returns null if the export is absent or not a number.\n */\nexport function extractExportConstNumber(code: string, name: string): number | null {\n const re = new RegExp(\n `^\\\\s*export\\\\s+const\\\\s+${name}\\\\s*(?::[^=]+)?\\\\s*=\\\\s*(-?\\\\d+(?:\\\\.\\\\d+)?|Infinity)`,\n \"m\",\n );\n const m = re.exec(code);\n if (!m) return null;\n return m[1] === \"Infinity\" ? Infinity : parseFloat(m[1]);\n}\n\n/**\n * Extracts the `revalidate` value from inside a `getStaticProps` return object.\n * Looks for: revalidate: <number> or revalidate: false or revalidate: Infinity\n *\n * Returns:\n * number — a positive revalidation interval (enables ISR)\n * 0 — treat as SSR (revalidate every request)\n * false — fully static (no revalidation)\n * Infinity — fully static (treated same as false by Next.js)\n * null — no `revalidate` key found (fully static)\n */\nexport function extractGetStaticPropsRevalidate(code: string): number | false | null {\n const returnObjects = extractGetStaticPropsReturnObjects(code);\n\n if (returnObjects) {\n for (const searchSpace of returnObjects) {\n const revalidate = extractTopLevelRevalidateValue(searchSpace);\n if (revalidate !== null) return revalidate;\n }\n return null;\n }\n\n const m = /\\brevalidate\\s*:\\s*(-?\\d+(?:\\.\\d+)?|Infinity|false)\\b/.exec(code);\n if (!m) return null;\n if (m[1] === \"false\") return false;\n if (m[1] === \"Infinity\") return Infinity;\n return parseFloat(m[1]);\n}\n\nfunction extractTopLevelRevalidateValue(code: string): number | false | null {\n let braceDepth = 0;\n let parenDepth = 0;\n let bracketDepth = 0;\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let inLineComment = false;\n let inBlockComment = false;\n\n for (let i = 0; i < code.length; i++) {\n const char = code[i];\n const next = code[i + 1];\n\n if (inLineComment) {\n if (char === \"\\n\") inLineComment = false;\n continue;\n }\n\n if (inBlockComment) {\n if (char === \"*\" && next === \"/\") {\n inBlockComment = false;\n i++;\n }\n continue;\n }\n\n if (quote) {\n if (char === \"\\\\\") {\n i++;\n continue;\n }\n if (char === quote) quote = null;\n continue;\n }\n\n if (char === \"/\" && next === \"/\") {\n inLineComment = true;\n i++;\n continue;\n }\n\n if (char === \"/\" && next === \"*\") {\n inBlockComment = true;\n i++;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n continue;\n }\n\n if (char === \"{\") {\n braceDepth++;\n continue;\n }\n\n if (char === \"}\") {\n braceDepth--;\n continue;\n }\n\n if (char === \"(\") {\n parenDepth++;\n continue;\n }\n\n if (char === \")\") {\n parenDepth--;\n continue;\n }\n\n if (char === \"[\") {\n bracketDepth++;\n continue;\n }\n\n if (char === \"]\") {\n bracketDepth--;\n continue;\n }\n\n if (\n braceDepth === 1 &&\n parenDepth === 0 &&\n bracketDepth === 0 &&\n matchesKeywordAt(code, i, \"revalidate\")\n ) {\n const colonIndex = findNextNonWhitespaceIndex(code, i + \"revalidate\".length);\n if (colonIndex === -1 || code[colonIndex] !== \":\") continue;\n\n const valueStart = findNextNonWhitespaceIndex(code, colonIndex + 1);\n if (valueStart === -1) return null;\n\n const valueMatch = /^(-?\\d+(?:\\.\\d+)?|Infinity|false)\\b/.exec(code.slice(valueStart));\n if (!valueMatch) return null;\n if (valueMatch[1] === \"false\") return false;\n if (valueMatch[1] === \"Infinity\") return Infinity;\n return parseFloat(valueMatch[1]);\n }\n }\n\n return null;\n}\n\nfunction extractGetStaticPropsReturnObjects(code: string): string[] | null {\n const declarationMatch =\n /(?:^|\\n)\\s*(?:export\\s+)?(?:async\\s+)?function\\s+getStaticProps\\b|(?:^|\\n)\\s*(?:export\\s+)?(?:const|let|var)\\s+getStaticProps\\b/.exec(\n code,\n );\n if (!declarationMatch) {\n // A file can re-export getStaticProps from another module without defining\n // it locally. In that case we can't safely infer revalidate from this file,\n // so skip the whole-file fallback to avoid unrelated false positives.\n if (/(?:^|\\n)\\s*export\\s*\\{[^}]*\\bgetStaticProps\\b[^}]*\\}\\s*from\\b/.test(code)) {\n return [];\n }\n return null;\n }\n\n const declaration = extractGetStaticPropsDeclaration(code, declarationMatch);\n if (declaration === null) return [];\n\n const returnObjects = declaration.trimStart().startsWith(\"{\")\n ? collectReturnObjectsFromFunctionBody(declaration)\n : [];\n\n if (returnObjects.length > 0) return returnObjects;\n\n const arrowMatch = declaration.search(/=>\\s*\\(\\s*\\{/);\n // getStaticProps was found but contains no return objects — return empty\n // (non-null signals the caller to skip the whole-file fallback).\n if (arrowMatch === -1) return [];\n\n const braceStart = declaration.indexOf(\"{\", arrowMatch);\n if (braceStart === -1) return [];\n\n const braceEnd = findMatchingBrace(declaration, braceStart);\n if (braceEnd === -1) return [];\n\n return [declaration.slice(braceStart, braceEnd + 1)];\n}\n\nfunction extractGetStaticPropsDeclaration(\n code: string,\n declarationMatch: RegExpExecArray,\n): string | null {\n const declarationStart = declarationMatch.index;\n const declarationText = declarationMatch[0];\n const declarationTail = code.slice(declarationStart);\n\n if (declarationText.includes(\"function getStaticProps\")) {\n return extractFunctionBody(code, declarationStart + declarationText.length);\n }\n\n const functionExpressionMatch = /(?:async\\s+)?function\\b/.exec(declarationTail);\n if (functionExpressionMatch) {\n return extractFunctionBody(declarationTail, functionExpressionMatch.index);\n }\n\n const blockBodyMatch = /=>\\s*\\{/.exec(declarationTail);\n if (blockBodyMatch) {\n const braceStart = declarationTail.indexOf(\"{\", blockBodyMatch.index);\n if (braceStart === -1) return null;\n\n const braceEnd = findMatchingBrace(declarationTail, braceStart);\n if (braceEnd === -1) return null;\n\n return declarationTail.slice(braceStart, braceEnd + 1);\n }\n\n const implicitArrowMatch = declarationTail.search(/=>\\s*\\(\\s*\\{/);\n if (implicitArrowMatch === -1) return null;\n\n const implicitBraceStart = declarationTail.indexOf(\"{\", implicitArrowMatch);\n if (implicitBraceStart === -1) return null;\n\n const implicitBraceEnd = findMatchingBrace(declarationTail, implicitBraceStart);\n if (implicitBraceEnd === -1) return null;\n\n return declarationTail.slice(0, implicitBraceEnd + 1);\n}\n\nfunction extractFunctionBody(code: string, functionStart: number): string | null {\n const bodyEnd = findFunctionBodyEnd(code, functionStart);\n if (bodyEnd === -1) return null;\n\n const paramsStart = code.indexOf(\"(\", functionStart);\n if (paramsStart === -1) return null;\n\n const paramsEnd = findMatchingParen(code, paramsStart);\n if (paramsEnd === -1) return null;\n\n const bodyStart = code.indexOf(\"{\", paramsEnd + 1);\n if (bodyStart === -1) return null;\n\n return code.slice(bodyStart, bodyEnd + 1);\n}\n\nfunction collectReturnObjectsFromFunctionBody(code: string): string[] {\n const returnObjects: string[] = [];\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let inLineComment = false;\n let inBlockComment = false;\n\n for (let i = 0; i < code.length; i++) {\n const char = code[i];\n const next = code[i + 1];\n\n if (inLineComment) {\n if (char === \"\\n\") inLineComment = false;\n continue;\n }\n\n if (inBlockComment) {\n if (char === \"*\" && next === \"/\") {\n inBlockComment = false;\n i++;\n }\n continue;\n }\n\n if (quote) {\n if (char === \"\\\\\") {\n i++;\n continue;\n }\n if (char === quote) quote = null;\n continue;\n }\n\n if (char === \"/\" && next === \"/\") {\n inLineComment = true;\n i++;\n continue;\n }\n\n if (char === \"/\" && next === \"*\") {\n inBlockComment = true;\n i++;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n continue;\n }\n\n if (matchesKeywordAt(code, i, \"function\")) {\n const nestedBodyEnd = findFunctionBodyEnd(code, i);\n if (nestedBodyEnd !== -1) {\n i = nestedBodyEnd;\n }\n continue;\n }\n\n if (matchesKeywordAt(code, i, \"class\")) {\n const classBodyEnd = findClassBodyEnd(code, i);\n if (classBodyEnd !== -1) {\n i = classBodyEnd;\n }\n continue;\n }\n\n if (char === \"=\" && next === \">\") {\n const nestedBodyEnd = findArrowFunctionBodyEnd(code, i);\n if (nestedBodyEnd !== -1) {\n i = nestedBodyEnd;\n }\n continue;\n }\n\n if (\n (char >= \"A\" && char <= \"Z\") ||\n (char >= \"a\" && char <= \"z\") ||\n char === \"_\" ||\n char === \"$\" ||\n char === \"*\"\n ) {\n const methodBodyEnd = findObjectMethodBodyEnd(code, i);\n if (methodBodyEnd !== -1) {\n i = methodBodyEnd;\n continue;\n }\n }\n\n if (matchesKeywordAt(code, i, \"return\")) {\n const braceStart = findNextNonWhitespaceIndex(code, i + \"return\".length);\n if (braceStart === -1 || code[braceStart] !== \"{\") continue;\n\n const braceEnd = findMatchingBrace(code, braceStart);\n if (braceEnd === -1) continue;\n\n returnObjects.push(code.slice(braceStart, braceEnd + 1));\n i = braceEnd;\n }\n }\n\n return returnObjects;\n}\n\nfunction findFunctionBodyEnd(code: string, functionStart: number): number {\n const paramsStart = code.indexOf(\"(\", functionStart);\n if (paramsStart === -1) return -1;\n\n const paramsEnd = findMatchingParen(code, paramsStart);\n if (paramsEnd === -1) return -1;\n\n const bodyStart = code.indexOf(\"{\", paramsEnd + 1);\n if (bodyStart === -1) return -1;\n\n return findMatchingBrace(code, bodyStart);\n}\n\nfunction findClassBodyEnd(code: string, classStart: number): number {\n const bodyStart = code.indexOf(\"{\", classStart + \"class\".length);\n if (bodyStart === -1) return -1;\n\n return findMatchingBrace(code, bodyStart);\n}\n\nfunction findArrowFunctionBodyEnd(code: string, arrowIndex: number): number {\n const bodyStart = findNextNonWhitespaceIndex(code, arrowIndex + 2);\n if (bodyStart === -1 || code[bodyStart] !== \"{\") return -1;\n\n return findMatchingBrace(code, bodyStart);\n}\n\nfunction findObjectMethodBodyEnd(code: string, start: number): number {\n let i = start;\n\n if (matchesKeywordAt(code, i, \"async\")) {\n const afterAsync = findNextNonWhitespaceIndex(code, i + \"async\".length);\n if (afterAsync === -1) return -1;\n if (code[afterAsync] !== \"(\") {\n i = afterAsync;\n }\n }\n\n if (code[i] === \"*\") {\n i = findNextNonWhitespaceIndex(code, i + 1);\n if (i === -1) return -1;\n }\n\n if (!/[A-Za-z_$]/.test(code[i] ?? \"\")) return -1;\n\n const nameStart = i;\n while (/[A-Za-z0-9_$]/.test(code[i] ?? \"\")) i++;\n const name = code.slice(nameStart, i);\n\n if (\n name === \"if\" ||\n name === \"for\" ||\n name === \"while\" ||\n name === \"switch\" ||\n name === \"catch\" ||\n name === \"function\" ||\n name === \"return\" ||\n name === \"const\" ||\n name === \"let\" ||\n name === \"var\" ||\n name === \"new\"\n ) {\n return -1;\n }\n\n if (name === \"get\" || name === \"set\") {\n const afterAccessor = findNextNonWhitespaceIndex(code, i);\n if (afterAccessor === -1) return -1;\n if (code[afterAccessor] !== \"(\") {\n i = afterAccessor;\n if (!/[A-Za-z_$]/.test(code[i] ?? \"\")) return -1;\n while (/[A-Za-z0-9_$]/.test(code[i] ?? \"\")) i++;\n }\n }\n\n const paramsStart = findNextNonWhitespaceIndex(code, i);\n if (paramsStart === -1 || code[paramsStart] !== \"(\") return -1;\n\n const paramsEnd = findMatchingParen(code, paramsStart);\n if (paramsEnd === -1) return -1;\n\n const bodyStart = findNextNonWhitespaceIndex(code, paramsEnd + 1);\n if (bodyStart === -1 || code[bodyStart] !== \"{\") return -1;\n\n return findMatchingBrace(code, bodyStart);\n}\n\nfunction findNextNonWhitespaceIndex(code: string, start: number): number {\n for (let i = start; i < code.length; i++) {\n if (!/\\s/.test(code[i])) return i;\n }\n return -1;\n}\n\nfunction matchesKeywordAt(code: string, index: number, keyword: string): boolean {\n const before = index === 0 ? \"\" : code[index - 1];\n const after = code[index + keyword.length] ?? \"\";\n return (\n code.startsWith(keyword, index) &&\n (before === \"\" || !/[A-Za-z0-9_$]/.test(before)) &&\n (after === \"\" || !/[A-Za-z0-9_$]/.test(after))\n );\n}\n\nfunction findMatchingBrace(code: string, start: number): number {\n return findMatchingToken(code, start, \"{\", \"}\");\n}\n\nfunction findMatchingParen(code: string, start: number): number {\n return findMatchingToken(code, start, \"(\", \")\");\n}\n\nfunction findMatchingToken(\n code: string,\n start: number,\n openToken: string,\n closeToken: string,\n): number {\n let depth = 0;\n let quote: '\"' | \"'\" | \"`\" | null = null;\n let inLineComment = false;\n let inBlockComment = false;\n\n for (let i = start; i < code.length; i++) {\n const char = code[i];\n const next = code[i + 1];\n\n if (inLineComment) {\n if (char === \"\\n\") inLineComment = false;\n continue;\n }\n\n if (inBlockComment) {\n if (char === \"*\" && next === \"/\") {\n inBlockComment = false;\n i++;\n }\n continue;\n }\n\n if (quote) {\n if (char === \"\\\\\") {\n i++;\n continue;\n }\n if (char === quote) quote = null;\n continue;\n }\n\n if (char === \"/\" && next === \"/\") {\n inLineComment = true;\n i++;\n continue;\n }\n\n if (char === \"/\" && next === \"*\") {\n inBlockComment = true;\n i++;\n continue;\n }\n\n if (char === '\"' || char === \"'\" || char === \"`\") {\n quote = char;\n continue;\n }\n\n if (char === openToken) {\n depth++;\n continue;\n }\n\n if (char === closeToken) {\n depth--;\n if (depth === 0) return i;\n }\n }\n\n return -1;\n}\n\n// ─── Layout segment config classification ────────────────────────────────────\n\n/**\n * Classifies a layout file by its segment config exports (`dynamic`, `revalidate`).\n *\n * Returns a tagged `LayoutBuildClassification` carrying both the decision and\n * the specific segment-config field that produced it. `{ kind: \"absent\" }`\n * means no segment config is present and the caller should defer to the next\n * layer (module graph analysis).\n *\n * Unlike page classification, positive `revalidate` values are not meaningful\n * for layout skip decisions — ISR is a page-level concept. Only the extremes\n * (`revalidate = 0` → dynamic, `revalidate = Infinity` → static) are decisive.\n */\nexport function classifyLayoutSegmentConfig(code: string): LayoutBuildClassification {\n const dynamicValue = extractExportConstString(code, \"dynamic\");\n if (dynamicValue === \"force-dynamic\") {\n return {\n kind: \"dynamic\",\n reason: { layer: \"segment-config\", key: \"dynamic\", value: \"force-dynamic\" },\n };\n }\n if (dynamicValue === \"force-static\" || dynamicValue === \"error\") {\n return {\n kind: \"static\",\n reason: { layer: \"segment-config\", key: \"dynamic\", value: dynamicValue },\n };\n }\n\n const revalidateValue = extractExportConstNumber(code, \"revalidate\");\n if (revalidateValue === Infinity) {\n return {\n kind: \"static\",\n reason: { layer: \"segment-config\", key: \"revalidate\", value: Infinity },\n };\n }\n if (revalidateValue === 0) {\n return {\n kind: \"dynamic\",\n reason: { layer: \"segment-config\", key: \"revalidate\", value: 0 },\n };\n }\n\n return { kind: \"absent\" };\n}\n\n// ─── Route classification ─────────────────────────────────────────────────────\n\n/**\n * Classifies a Pages Router page file by reading its source and examining\n * which data-fetching exports it contains.\n *\n * API routes (files under pages/api/) are always `api`.\n */\nexport function classifyPagesRoute(filePath: string): {\n type: RouteType;\n revalidate?: number;\n} {\n // API routes are identified by their path\n const normalized = filePath.replace(/\\\\/g, \"/\");\n if (normalized.includes(\"/pages/api/\")) {\n return { type: \"api\" };\n }\n\n let code: string;\n try {\n code = fs.readFileSync(filePath, \"utf8\");\n } catch {\n return { type: \"unknown\" };\n }\n\n if (hasNamedExport(code, \"getServerSideProps\")) {\n return { type: \"ssr\" };\n }\n\n if (hasNamedExport(code, \"getStaticProps\")) {\n const revalidate = extractGetStaticPropsRevalidate(code);\n\n if (revalidate === null || revalidate === false || revalidate === Infinity) {\n return { type: \"static\" };\n }\n if (revalidate === 0) {\n return { type: \"ssr\" };\n }\n // Positive number → ISR\n return { type: \"isr\", revalidate };\n }\n\n return { type: \"static\" };\n}\n\n/**\n * Classifies an App Router route.\n *\n * @param pagePath Absolute path to the page.tsx (null for API-only routes)\n * @param routePath Absolute path to the route.ts handler (null for page routes)\n * @param isDynamic Whether the URL pattern contains dynamic segments\n */\nexport function classifyAppRoute(\n pagePath: string | null,\n routePath: string | null,\n isDynamic: boolean,\n): { type: RouteType; revalidate?: number } {\n // Route handlers with no page component → API\n if (routePath !== null && pagePath === null) {\n return { type: \"api\" };\n }\n\n const filePath = pagePath ?? routePath;\n if (!filePath) return { type: \"unknown\" };\n\n let code: string;\n try {\n code = fs.readFileSync(filePath, \"utf8\");\n } catch {\n return { type: \"unknown\" };\n }\n\n // Check `export const dynamic`\n const dynamicValue = extractExportConstString(code, \"dynamic\");\n if (dynamicValue === \"force-dynamic\") {\n return { type: \"ssr\" };\n }\n if (dynamicValue === \"force-static\" || dynamicValue === \"error\") {\n // \"error\" enforces static rendering — it throws if dynamic APIs are used,\n // so the page is statically rendered (same as force-static for classification).\n return { type: \"static\" };\n }\n\n // Check `export const revalidate`\n const revalidateValue = extractExportConstNumber(code, \"revalidate\");\n if (revalidateValue !== null) {\n if (revalidateValue === Infinity) return { type: \"static\" };\n if (revalidateValue === 0) return { type: \"ssr\" };\n if (revalidateValue > 0) return { type: \"isr\", revalidate: revalidateValue };\n }\n\n // Fall back to isDynamic flag (dynamic URL segments without explicit config)\n if (isDynamic) return { type: \"ssr\" };\n\n // No explicit config and no dynamic URL segments — we can't confirm static\n // without running the build (dynamic API calls like headers() are invisible\n // to static analysis). Report as unknown rather than falsely claiming static.\n return { type: \"unknown\" };\n}\n\n// ─── Row building ─────────────────────────────────────────────────────────────\n\n/**\n * Builds a sorted list of RouteRow objects from the discovered routes.\n * Routes are sorted alphabetically by path, matching filesystem order.\n *\n * When `prerenderResult` is provided, routes that were classified as `unknown`\n * by static analysis but were successfully rendered speculatively are upgraded\n * to `static` (confirmed by execution). The `prerendered` flag is set on those\n * rows so the formatter can add a legend note.\n */\nexport function buildReportRows(options: {\n pageRoutes?: Route[];\n apiRoutes?: Route[];\n appRoutes?: AppRoute[];\n prerenderResult?: PrerenderResult;\n}): RouteRow[] {\n const rows: RouteRow[] = [];\n\n // Build a set of routes that were confirmed rendered by speculative prerender.\n const renderedRoutes = new Set<string>();\n if (options.prerenderResult) {\n for (const r of options.prerenderResult.routes) {\n if (r.status === \"rendered\") renderedRoutes.add(r.route);\n }\n }\n\n for (const route of options.pageRoutes ?? []) {\n const { type, revalidate } = classifyPagesRoute(route.filePath);\n rows.push({ pattern: route.pattern, type, revalidate });\n }\n\n for (const route of options.apiRoutes ?? []) {\n rows.push({ pattern: route.pattern, type: \"api\" });\n }\n\n for (const route of options.appRoutes ?? []) {\n const { type, revalidate } = classifyAppRoute(route.pagePath, route.routePath, route.isDynamic);\n if (type === \"unknown\" && renderedRoutes.has(route.pattern)) {\n // Speculative prerender confirmed this route is static.\n rows.push({ pattern: route.pattern, type: \"static\", prerendered: true });\n } else {\n rows.push({ pattern: route.pattern, type, revalidate });\n }\n }\n\n // Sort purely by path — mirrors filesystem order, matching Next.js output style\n rows.sort((a, b) => a.pattern.localeCompare(b.pattern));\n\n return rows;\n}\n\n// ─── Formatting ───────────────────────────────────────────────────────────────\n\nconst SYMBOLS: Record<RouteType, string> = {\n static: \"○\",\n isr: \"◐\",\n ssr: \"ƒ\",\n unknown: \"?\",\n api: \"λ\",\n};\n\nconst LABELS: Record<RouteType, string> = {\n static: \"Static\",\n isr: \"ISR\",\n ssr: \"Dynamic\",\n unknown: \"Unknown\",\n api: \"API\",\n};\n\n/**\n * Formats a list of RouteRows into a Next.js-style build report string.\n *\n * Example output:\n * Route (pages)\n * ┌ ○ /\n * ├ ◐ /blog/:slug (60s)\n * ├ ƒ /dashboard\n * └ λ /api/posts\n *\n * ○ Static ◐ ISR ƒ Dynamic λ API\n */\nexport function formatBuildReport(rows: RouteRow[], routerLabel = \"app\"): string {\n if (rows.length === 0) return \"\";\n\n const lines: string[] = [];\n lines.push(` Route (${routerLabel})`);\n\n // Determine padding width from the longest pattern\n const maxPatternLen = Math.max(...rows.map((r) => r.pattern.length));\n\n rows.forEach((row, i) => {\n const isLast = i === rows.length - 1;\n const corner = rows.length === 1 ? \"─\" : i === 0 ? \"┌\" : isLast ? \"└\" : \"├\";\n const sym = SYMBOLS[row.type];\n const suffix =\n row.type === \"isr\" && row.revalidate !== undefined ? ` (${row.revalidate}s)` : \"\";\n const padding = \" \".repeat(maxPatternLen - row.pattern.length);\n lines.push(` ${corner} ${sym} ${row.pattern}${padding}${suffix}`);\n });\n\n lines.push(\"\");\n\n // Legend — only include types that appear in this report, sorted alphabetically by label\n const usedTypes = [...new Set(rows.map((r) => r.type))].sort((a, b) =>\n LABELS[a].localeCompare(LABELS[b]),\n );\n lines.push(\" \" + usedTypes.map((t) => `${SYMBOLS[t]} ${LABELS[t]}`).join(\" \"));\n\n // Explanatory note — only shown when unknown routes are present\n if (usedTypes.includes(\"unknown\")) {\n lines.push(\"\");\n lines.push(\" ? Some routes could not be classified. vinext currently uses static analysis\");\n lines.push(\n \" and cannot detect dynamic API usage (headers(), cookies(), etc.) at build time.\",\n );\n lines.push(\" Automatic classification will be improved in a future release.\");\n }\n\n // Speculative-render note — shown when any routes were confirmed static by prerender\n const hasPrerendered = rows.some((r) => r.prerendered);\n if (hasPrerendered) {\n lines.push(\"\");\n lines.push(\n \" ○ Routes marked static were confirmed by speculative prerender (attempted render\",\n );\n lines.push(\" succeeded without dynamic API usage).\");\n }\n\n return lines.join(\"\\n\");\n}\n\n// ─── Directory detection ──────────────────────────────────────────────────────\n\nexport function findDir(root: string, ...candidates: string[]): string | null {\n for (const candidate of candidates) {\n const full = path.join(root, candidate);\n try {\n if (fs.statSync(full).isDirectory()) return full;\n } catch {\n // not found or not a directory — try next candidate\n }\n }\n return null;\n}\n\n// ─── Main entry point ─────────────────────────────────────────────────────────\n\n/**\n * Scans the project at `root`, classifies all routes, and prints the\n * Next.js-style build report to stdout.\n *\n * Called at the end of `vinext build` in cli.ts.\n */\nexport async function printBuildReport(options: {\n root: string;\n pageExtensions: string[];\n prerenderResult?: PrerenderResult;\n}): Promise<void> {\n const { root } = options;\n\n const appDir = findDir(root, \"app\", \"src/app\");\n const pagesDir = findDir(root, \"pages\", \"src/pages\");\n\n if (!appDir && !pagesDir) return;\n\n if (appDir) {\n // Dynamic import to avoid loading routing code unless needed\n const { appRouter } = await import(\"../routing/app-router.js\");\n const routes = await appRouter(appDir, options.pageExtensions);\n const rows = buildReportRows({ appRoutes: routes, prerenderResult: options.prerenderResult });\n if (rows.length > 0) {\n console.log(\"\\n\" + formatBuildReport(rows, \"app\"));\n }\n }\n\n if (pagesDir) {\n const { pagesRouter, apiRouter } = await import(\"../routing/pages-router.js\");\n const [pageRoutes, apiRoutes] = await Promise.all([\n pagesRouter(pagesDir, options.pageExtensions),\n apiRouter(pagesDir, options.pageExtensions),\n ]);\n const rows = buildReportRows({\n pageRoutes,\n apiRoutes,\n prerenderResult: options.prerenderResult,\n });\n if (rows.length > 0) {\n console.log(\"\\n\" + formatBuildReport(rows, \"pages\"));\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsDA,SAAgB,eAAe,MAAc,MAAuB;AAGlE,KADa,IAAI,OAAO,oDAAoD,KAAK,KAAK,CAC7E,KAAK,KAAK,CAAE,QAAO;AAI5B,KADc,IAAI,OAAO,+CAA+C,KAAK,UAAU,CAC7E,KAAK,KAAK,CAAE,QAAO;AAI7B,KADa,IAAI,OAAO,wBAAwB,KAAK,aAAa,CACzD,KAAK,KAAK,CAAE,QAAO;AAE5B,QAAO;;;;;;;;AAST,SAAgB,yBAAyB,MAAc,MAA6B;CAKlF,MAAM,IAJK,IAAI,OACb,2BAA2B,KAAK,2CAChC,IACD,CACY,KAAK,KAAK;AACvB,QAAO,IAAI,EAAE,KAAK;;;;;;;;AASpB,SAAgB,yBAAyB,MAAc,MAA6B;CAKlF,MAAM,IAJK,IAAI,OACb,2BAA2B,KAAK,wDAChC,IACD,CACY,KAAK,KAAK;AACvB,KAAI,CAAC,EAAG,QAAO;AACf,QAAO,EAAE,OAAO,aAAa,WAAW,WAAW,EAAE,GAAG;;;;;;;;;;;;;AAc1D,SAAgB,gCAAgC,MAAqC;CACnF,MAAM,gBAAgB,mCAAmC,KAAK;AAE9D,KAAI,eAAe;AACjB,OAAK,MAAM,eAAe,eAAe;GACvC,MAAM,aAAa,+BAA+B,YAAY;AAC9D,OAAI,eAAe,KAAM,QAAO;;AAElC,SAAO;;CAGT,MAAM,IAAI,wDAAwD,KAAK,KAAK;AAC5E,KAAI,CAAC,EAAG,QAAO;AACf,KAAI,EAAE,OAAO,QAAS,QAAO;AAC7B,KAAI,EAAE,OAAO,WAAY,QAAO;AAChC,QAAO,WAAW,EAAE,GAAG;;AAGzB,SAAS,+BAA+B,MAAqC;CAC3E,IAAI,aAAa;CACjB,IAAI,aAAa;CACjB,IAAI,eAAe;CACnB,IAAI,QAAgC;CACpC,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;AAErB,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,OAAO,KAAK;EAClB,MAAM,OAAO,KAAK,IAAI;AAEtB,MAAI,eAAe;AACjB,OAAI,SAAS,KAAM,iBAAgB;AACnC;;AAGF,MAAI,gBAAgB;AAClB,OAAI,SAAS,OAAO,SAAS,KAAK;AAChC,qBAAiB;AACjB;;AAEF;;AAGF,MAAI,OAAO;AACT,OAAI,SAAS,MAAM;AACjB;AACA;;AAEF,OAAI,SAAS,MAAO,SAAQ;AAC5B;;AAGF,MAAI,SAAS,OAAO,SAAS,KAAK;AAChC,mBAAgB;AAChB;AACA;;AAGF,MAAI,SAAS,OAAO,SAAS,KAAK;AAChC,oBAAiB;AACjB;AACA;;AAGF,MAAI,SAAS,QAAO,SAAS,OAAO,SAAS,KAAK;AAChD,WAAQ;AACR;;AAGF,MAAI,SAAS,KAAK;AAChB;AACA;;AAGF,MAAI,SAAS,KAAK;AAChB;AACA;;AAGF,MAAI,SAAS,KAAK;AAChB;AACA;;AAGF,MAAI,SAAS,KAAK;AAChB;AACA;;AAGF,MAAI,SAAS,KAAK;AAChB;AACA;;AAGF,MAAI,SAAS,KAAK;AAChB;AACA;;AAGF,MACE,eAAe,KACf,eAAe,KACf,iBAAiB,KACjB,iBAAiB,MAAM,GAAG,aAAa,EACvC;GACA,MAAM,aAAa,2BAA2B,MAAM,IAAI,GAAoB;AAC5E,OAAI,eAAe,MAAM,KAAK,gBAAgB,IAAK;GAEnD,MAAM,aAAa,2BAA2B,MAAM,aAAa,EAAE;AACnE,OAAI,eAAe,GAAI,QAAO;GAE9B,MAAM,aAAa,sCAAsC,KAAK,KAAK,MAAM,WAAW,CAAC;AACrF,OAAI,CAAC,WAAY,QAAO;AACxB,OAAI,WAAW,OAAO,QAAS,QAAO;AACtC,OAAI,WAAW,OAAO,WAAY,QAAO;AACzC,UAAO,WAAW,WAAW,GAAG;;;AAIpC,QAAO;;AAGT,SAAS,mCAAmC,MAA+B;CACzE,MAAM,mBACJ,kIAAkI,KAChI,KACD;AACH,KAAI,CAAC,kBAAkB;AAIrB,MAAI,gEAAgE,KAAK,KAAK,CAC5E,QAAO,EAAE;AAEX,SAAO;;CAGT,MAAM,cAAc,iCAAiC,MAAM,iBAAiB;AAC5E,KAAI,gBAAgB,KAAM,QAAO,EAAE;CAEnC,MAAM,gBAAgB,YAAY,WAAW,CAAC,WAAW,IAAI,GACzD,qCAAqC,YAAY,GACjD,EAAE;AAEN,KAAI,cAAc,SAAS,EAAG,QAAO;CAErC,MAAM,aAAa,YAAY,OAAO,eAAe;AAGrD,KAAI,eAAe,GAAI,QAAO,EAAE;CAEhC,MAAM,aAAa,YAAY,QAAQ,KAAK,WAAW;AACvD,KAAI,eAAe,GAAI,QAAO,EAAE;CAEhC,MAAM,WAAW,kBAAkB,aAAa,WAAW;AAC3D,KAAI,aAAa,GAAI,QAAO,EAAE;AAE9B,QAAO,CAAC,YAAY,MAAM,YAAY,WAAW,EAAE,CAAC;;AAGtD,SAAS,iCACP,MACA,kBACe;CACf,MAAM,mBAAmB,iBAAiB;CAC1C,MAAM,kBAAkB,iBAAiB;CACzC,MAAM,kBAAkB,KAAK,MAAM,iBAAiB;AAEpD,KAAI,gBAAgB,SAAS,0BAA0B,CACrD,QAAO,oBAAoB,MAAM,mBAAmB,gBAAgB,OAAO;CAG7E,MAAM,0BAA0B,0BAA0B,KAAK,gBAAgB;AAC/E,KAAI,wBACF,QAAO,oBAAoB,iBAAiB,wBAAwB,MAAM;CAG5E,MAAM,iBAAiB,UAAU,KAAK,gBAAgB;AACtD,KAAI,gBAAgB;EAClB,MAAM,aAAa,gBAAgB,QAAQ,KAAK,eAAe,MAAM;AACrE,MAAI,eAAe,GAAI,QAAO;EAE9B,MAAM,WAAW,kBAAkB,iBAAiB,WAAW;AAC/D,MAAI,aAAa,GAAI,QAAO;AAE5B,SAAO,gBAAgB,MAAM,YAAY,WAAW,EAAE;;CAGxD,MAAM,qBAAqB,gBAAgB,OAAO,eAAe;AACjE,KAAI,uBAAuB,GAAI,QAAO;CAEtC,MAAM,qBAAqB,gBAAgB,QAAQ,KAAK,mBAAmB;AAC3E,KAAI,uBAAuB,GAAI,QAAO;CAEtC,MAAM,mBAAmB,kBAAkB,iBAAiB,mBAAmB;AAC/E,KAAI,qBAAqB,GAAI,QAAO;AAEpC,QAAO,gBAAgB,MAAM,GAAG,mBAAmB,EAAE;;AAGvD,SAAS,oBAAoB,MAAc,eAAsC;CAC/E,MAAM,UAAU,oBAAoB,MAAM,cAAc;AACxD,KAAI,YAAY,GAAI,QAAO;CAE3B,MAAM,cAAc,KAAK,QAAQ,KAAK,cAAc;AACpD,KAAI,gBAAgB,GAAI,QAAO;CAE/B,MAAM,YAAY,kBAAkB,MAAM,YAAY;AACtD,KAAI,cAAc,GAAI,QAAO;CAE7B,MAAM,YAAY,KAAK,QAAQ,KAAK,YAAY,EAAE;AAClD,KAAI,cAAc,GAAI,QAAO;AAE7B,QAAO,KAAK,MAAM,WAAW,UAAU,EAAE;;AAG3C,SAAS,qCAAqC,MAAwB;CACpE,MAAM,gBAA0B,EAAE;CAClC,IAAI,QAAgC;CACpC,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;AAErB,MAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,OAAO,KAAK;EAClB,MAAM,OAAO,KAAK,IAAI;AAEtB,MAAI,eAAe;AACjB,OAAI,SAAS,KAAM,iBAAgB;AACnC;;AAGF,MAAI,gBAAgB;AAClB,OAAI,SAAS,OAAO,SAAS,KAAK;AAChC,qBAAiB;AACjB;;AAEF;;AAGF,MAAI,OAAO;AACT,OAAI,SAAS,MAAM;AACjB;AACA;;AAEF,OAAI,SAAS,MAAO,SAAQ;AAC5B;;AAGF,MAAI,SAAS,OAAO,SAAS,KAAK;AAChC,mBAAgB;AAChB;AACA;;AAGF,MAAI,SAAS,OAAO,SAAS,KAAK;AAChC,oBAAiB;AACjB;AACA;;AAGF,MAAI,SAAS,QAAO,SAAS,OAAO,SAAS,KAAK;AAChD,WAAQ;AACR;;AAGF,MAAI,iBAAiB,MAAM,GAAG,WAAW,EAAE;GACzC,MAAM,gBAAgB,oBAAoB,MAAM,EAAE;AAClD,OAAI,kBAAkB,GACpB,KAAI;AAEN;;AAGF,MAAI,iBAAiB,MAAM,GAAG,QAAQ,EAAE;GACtC,MAAM,eAAe,iBAAiB,MAAM,EAAE;AAC9C,OAAI,iBAAiB,GACnB,KAAI;AAEN;;AAGF,MAAI,SAAS,OAAO,SAAS,KAAK;GAChC,MAAM,gBAAgB,yBAAyB,MAAM,EAAE;AACvD,OAAI,kBAAkB,GACpB,KAAI;AAEN;;AAGF,MACG,QAAQ,OAAO,QAAQ,OACvB,QAAQ,OAAO,QAAQ,OACxB,SAAS,OACT,SAAS,OACT,SAAS,KACT;GACA,MAAM,gBAAgB,wBAAwB,MAAM,EAAE;AACtD,OAAI,kBAAkB,IAAI;AACxB,QAAI;AACJ;;;AAIJ,MAAI,iBAAiB,MAAM,GAAG,SAAS,EAAE;GACvC,MAAM,aAAa,2BAA2B,MAAM,IAAI,EAAgB;AACxE,OAAI,eAAe,MAAM,KAAK,gBAAgB,IAAK;GAEnD,MAAM,WAAW,kBAAkB,MAAM,WAAW;AACpD,OAAI,aAAa,GAAI;AAErB,iBAAc,KAAK,KAAK,MAAM,YAAY,WAAW,EAAE,CAAC;AACxD,OAAI;;;AAIR,QAAO;;AAGT,SAAS,oBAAoB,MAAc,eAA+B;CACxE,MAAM,cAAc,KAAK,QAAQ,KAAK,cAAc;AACpD,KAAI,gBAAgB,GAAI,QAAO;CAE/B,MAAM,YAAY,kBAAkB,MAAM,YAAY;AACtD,KAAI,cAAc,GAAI,QAAO;CAE7B,MAAM,YAAY,KAAK,QAAQ,KAAK,YAAY,EAAE;AAClD,KAAI,cAAc,GAAI,QAAO;AAE7B,QAAO,kBAAkB,MAAM,UAAU;;AAG3C,SAAS,iBAAiB,MAAc,YAA4B;CAClE,MAAM,YAAY,KAAK,QAAQ,KAAK,aAAa,EAAe;AAChE,KAAI,cAAc,GAAI,QAAO;AAE7B,QAAO,kBAAkB,MAAM,UAAU;;AAG3C,SAAS,yBAAyB,MAAc,YAA4B;CAC1E,MAAM,YAAY,2BAA2B,MAAM,aAAa,EAAE;AAClE,KAAI,cAAc,MAAM,KAAK,eAAe,IAAK,QAAO;AAExD,QAAO,kBAAkB,MAAM,UAAU;;AAG3C,SAAS,wBAAwB,MAAc,OAAuB;CACpE,IAAI,IAAI;AAER,KAAI,iBAAiB,MAAM,GAAG,QAAQ,EAAE;EACtC,MAAM,aAAa,2BAA2B,MAAM,IAAI,EAAe;AACvE,MAAI,eAAe,GAAI,QAAO;AAC9B,MAAI,KAAK,gBAAgB,IACvB,KAAI;;AAIR,KAAI,KAAK,OAAO,KAAK;AACnB,MAAI,2BAA2B,MAAM,IAAI,EAAE;AAC3C,MAAI,MAAM,GAAI,QAAO;;AAGvB,KAAI,CAAC,aAAa,KAAK,KAAK,MAAM,GAAG,CAAE,QAAO;CAE9C,MAAM,YAAY;AAClB,QAAO,gBAAgB,KAAK,KAAK,MAAM,GAAG,CAAE;CAC5C,MAAM,OAAO,KAAK,MAAM,WAAW,EAAE;AAErC,KACE,SAAS,QACT,SAAS,SACT,SAAS,WACT,SAAS,YACT,SAAS,WACT,SAAS,cACT,SAAS,YACT,SAAS,WACT,SAAS,SACT,SAAS,SACT,SAAS,MAET,QAAO;AAGT,KAAI,SAAS,SAAS,SAAS,OAAO;EACpC,MAAM,gBAAgB,2BAA2B,MAAM,EAAE;AACzD,MAAI,kBAAkB,GAAI,QAAO;AACjC,MAAI,KAAK,mBAAmB,KAAK;AAC/B,OAAI;AACJ,OAAI,CAAC,aAAa,KAAK,KAAK,MAAM,GAAG,CAAE,QAAO;AAC9C,UAAO,gBAAgB,KAAK,KAAK,MAAM,GAAG,CAAE;;;CAIhD,MAAM,cAAc,2BAA2B,MAAM,EAAE;AACvD,KAAI,gBAAgB,MAAM,KAAK,iBAAiB,IAAK,QAAO;CAE5D,MAAM,YAAY,kBAAkB,MAAM,YAAY;AACtD,KAAI,cAAc,GAAI,QAAO;CAE7B,MAAM,YAAY,2BAA2B,MAAM,YAAY,EAAE;AACjE,KAAI,cAAc,MAAM,KAAK,eAAe,IAAK,QAAO;AAExD,QAAO,kBAAkB,MAAM,UAAU;;AAG3C,SAAS,2BAA2B,MAAc,OAAuB;AACvE,MAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IACnC,KAAI,CAAC,KAAK,KAAK,KAAK,GAAG,CAAE,QAAO;AAElC,QAAO;;AAGT,SAAS,iBAAiB,MAAc,OAAe,SAA0B;CAC/E,MAAM,SAAS,UAAU,IAAI,KAAK,KAAK,QAAQ;CAC/C,MAAM,QAAQ,KAAK,QAAQ,QAAQ,WAAW;AAC9C,QACE,KAAK,WAAW,SAAS,MAAM,KAC9B,WAAW,MAAM,CAAC,gBAAgB,KAAK,OAAO,MAC9C,UAAU,MAAM,CAAC,gBAAgB,KAAK,MAAM;;AAIjD,SAAS,kBAAkB,MAAc,OAAuB;AAC9D,QAAO,kBAAkB,MAAM,OAAO,KAAK,IAAI;;AAGjD,SAAS,kBAAkB,MAAc,OAAuB;AAC9D,QAAO,kBAAkB,MAAM,OAAO,KAAK,IAAI;;AAGjD,SAAS,kBACP,MACA,OACA,WACA,YACQ;CACR,IAAI,QAAQ;CACZ,IAAI,QAAgC;CACpC,IAAI,gBAAgB;CACpB,IAAI,iBAAiB;AAErB,MAAK,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,KAAK;EACxC,MAAM,OAAO,KAAK;EAClB,MAAM,OAAO,KAAK,IAAI;AAEtB,MAAI,eAAe;AACjB,OAAI,SAAS,KAAM,iBAAgB;AACnC;;AAGF,MAAI,gBAAgB;AAClB,OAAI,SAAS,OAAO,SAAS,KAAK;AAChC,qBAAiB;AACjB;;AAEF;;AAGF,MAAI,OAAO;AACT,OAAI,SAAS,MAAM;AACjB;AACA;;AAEF,OAAI,SAAS,MAAO,SAAQ;AAC5B;;AAGF,MAAI,SAAS,OAAO,SAAS,KAAK;AAChC,mBAAgB;AAChB;AACA;;AAGF,MAAI,SAAS,OAAO,SAAS,KAAK;AAChC,oBAAiB;AACjB;AACA;;AAGF,MAAI,SAAS,QAAO,SAAS,OAAO,SAAS,KAAK;AAChD,WAAQ;AACR;;AAGF,MAAI,SAAS,WAAW;AACtB;AACA;;AAGF,MAAI,SAAS,YAAY;AACvB;AACA,OAAI,UAAU,EAAG,QAAO;;;AAI5B,QAAO;;;;;;;;;;;;;;AAiBT,SAAgB,4BAA4B,MAAyC;CACnF,MAAM,eAAe,yBAAyB,MAAM,UAAU;AAC9D,KAAI,iBAAiB,gBACnB,QAAO;EACL,MAAM;EACN,QAAQ;GAAE,OAAO;GAAkB,KAAK;GAAW,OAAO;GAAiB;EAC5E;AAEH,KAAI,iBAAiB,kBAAkB,iBAAiB,QACtD,QAAO;EACL,MAAM;EACN,QAAQ;GAAE,OAAO;GAAkB,KAAK;GAAW,OAAO;GAAc;EACzE;CAGH,MAAM,kBAAkB,yBAAyB,MAAM,aAAa;AACpE,KAAI,oBAAoB,SACtB,QAAO;EACL,MAAM;EACN,QAAQ;GAAE,OAAO;GAAkB,KAAK;GAAc,OAAO;GAAU;EACxE;AAEH,KAAI,oBAAoB,EACtB,QAAO;EACL,MAAM;EACN,QAAQ;GAAE,OAAO;GAAkB,KAAK;GAAc,OAAO;GAAG;EACjE;AAGH,QAAO,EAAE,MAAM,UAAU;;;;;;;;AAW3B,SAAgB,mBAAmB,UAGjC;AAGA,KADmB,SAAS,QAAQ,OAAO,IAAI,CAChC,SAAS,cAAc,CACpC,QAAO,EAAE,MAAM,OAAO;CAGxB,IAAI;AACJ,KAAI;AACF,SAAO,GAAG,aAAa,UAAU,OAAO;SAClC;AACN,SAAO,EAAE,MAAM,WAAW;;AAG5B,KAAI,eAAe,MAAM,qBAAqB,CAC5C,QAAO,EAAE,MAAM,OAAO;AAGxB,KAAI,eAAe,MAAM,iBAAiB,EAAE;EAC1C,MAAM,aAAa,gCAAgC,KAAK;AAExD,MAAI,eAAe,QAAQ,eAAe,SAAS,eAAe,SAChE,QAAO,EAAE,MAAM,UAAU;AAE3B,MAAI,eAAe,EACjB,QAAO,EAAE,MAAM,OAAO;AAGxB,SAAO;GAAE,MAAM;GAAO;GAAY;;AAGpC,QAAO,EAAE,MAAM,UAAU;;;;;;;;;AAU3B,SAAgB,iBACd,UACA,WACA,WAC0C;AAE1C,KAAI,cAAc,QAAQ,aAAa,KACrC,QAAO,EAAE,MAAM,OAAO;CAGxB,MAAM,WAAW,YAAY;AAC7B,KAAI,CAAC,SAAU,QAAO,EAAE,MAAM,WAAW;CAEzC,IAAI;AACJ,KAAI;AACF,SAAO,GAAG,aAAa,UAAU,OAAO;SAClC;AACN,SAAO,EAAE,MAAM,WAAW;;CAI5B,MAAM,eAAe,yBAAyB,MAAM,UAAU;AAC9D,KAAI,iBAAiB,gBACnB,QAAO,EAAE,MAAM,OAAO;AAExB,KAAI,iBAAiB,kBAAkB,iBAAiB,QAGtD,QAAO,EAAE,MAAM,UAAU;CAI3B,MAAM,kBAAkB,yBAAyB,MAAM,aAAa;AACpE,KAAI,oBAAoB,MAAM;AAC5B,MAAI,oBAAoB,SAAU,QAAO,EAAE,MAAM,UAAU;AAC3D,MAAI,oBAAoB,EAAG,QAAO,EAAE,MAAM,OAAO;AACjD,MAAI,kBAAkB,EAAG,QAAO;GAAE,MAAM;GAAO,YAAY;GAAiB;;AAI9E,KAAI,UAAW,QAAO,EAAE,MAAM,OAAO;AAKrC,QAAO,EAAE,MAAM,WAAW;;;;;;;;;;;AAc5B,SAAgB,gBAAgB,SAKjB;CACb,MAAM,OAAmB,EAAE;CAG3B,MAAM,iCAAiB,IAAI,KAAa;AACxC,KAAI,QAAQ;OACL,MAAM,KAAK,QAAQ,gBAAgB,OACtC,KAAI,EAAE,WAAW,WAAY,gBAAe,IAAI,EAAE,MAAM;;AAI5D,MAAK,MAAM,SAAS,QAAQ,cAAc,EAAE,EAAE;EAC5C,MAAM,EAAE,MAAM,eAAe,mBAAmB,MAAM,SAAS;AAC/D,OAAK,KAAK;GAAE,SAAS,MAAM;GAAS;GAAM;GAAY,CAAC;;AAGzD,MAAK,MAAM,SAAS,QAAQ,aAAa,EAAE,CACzC,MAAK,KAAK;EAAE,SAAS,MAAM;EAAS,MAAM;EAAO,CAAC;AAGpD,MAAK,MAAM,SAAS,QAAQ,aAAa,EAAE,EAAE;EAC3C,MAAM,EAAE,MAAM,eAAe,iBAAiB,MAAM,UAAU,MAAM,WAAW,MAAM,UAAU;AAC/F,MAAI,SAAS,aAAa,eAAe,IAAI,MAAM,QAAQ,CAEzD,MAAK,KAAK;GAAE,SAAS,MAAM;GAAS,MAAM;GAAU,aAAa;GAAM,CAAC;MAExE,MAAK,KAAK;GAAE,SAAS,MAAM;GAAS;GAAM;GAAY,CAAC;;AAK3D,MAAK,MAAM,GAAG,MAAM,EAAE,QAAQ,cAAc,EAAE,QAAQ,CAAC;AAEvD,QAAO;;AAKT,MAAM,UAAqC;CACzC,QAAQ;CACR,KAAK;CACL,KAAK;CACL,SAAS;CACT,KAAK;CACN;AAED,MAAM,SAAoC;CACxC,QAAQ;CACR,KAAK;CACL,KAAK;CACL,SAAS;CACT,KAAK;CACN;;;;;;;;;;;;;AAcD,SAAgB,kBAAkB,MAAkB,cAAc,OAAe;AAC/E,KAAI,KAAK,WAAW,EAAG,QAAO;CAE9B,MAAM,QAAkB,EAAE;AAC1B,OAAM,KAAK,YAAY,YAAY,GAAG;CAGtC,MAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,EAAE,QAAQ,OAAO,CAAC;AAEpE,MAAK,SAAS,KAAK,MAAM;EACvB,MAAM,SAAS,MAAM,KAAK,SAAS;EACnC,MAAM,SAAS,KAAK,WAAW,IAAI,MAAM,MAAM,IAAI,MAAM,SAAS,MAAM;EACxE,MAAM,MAAM,QAAQ,IAAI;EACxB,MAAM,SACJ,IAAI,SAAS,SAAS,IAAI,eAAe,KAAA,IAAY,MAAM,IAAI,WAAW,MAAM;EAClF,MAAM,UAAU,IAAI,OAAO,gBAAgB,IAAI,QAAQ,OAAO;AAC9D,QAAM,KAAK,KAAK,OAAO,GAAG,IAAI,GAAG,IAAI,UAAU,UAAU,SAAS;GAClE;AAEF,OAAM,KAAK,GAAG;CAGd,MAAM,YAAY,CAAC,GAAG,IAAI,IAAI,KAAK,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,MAC/D,OAAO,GAAG,cAAc,OAAO,GAAG,CACnC;AACD,OAAM,KAAK,OAAO,UAAU,KAAK,MAAM,GAAG,QAAQ,GAAG,GAAG,OAAO,KAAK,CAAC,KAAK,KAAK,CAAC;AAGhF,KAAI,UAAU,SAAS,UAAU,EAAE;AACjC,QAAM,KAAK,GAAG;AACd,QAAM,KAAK,iFAAiF;AAC5F,QAAM,KACJ,sFACD;AACD,QAAM,KAAK,qEAAqE;;AAKlF,KADuB,KAAK,MAAM,MAAM,EAAE,YAAY,EAClC;AAClB,QAAM,KAAK,GAAG;AACd,QAAM,KACJ,qFACD;AACD,QAAM,KAAK,4CAA4C;;AAGzD,QAAO,MAAM,KAAK,KAAK;;AAKzB,SAAgB,QAAQ,MAAc,GAAG,YAAqC;AAC5E,MAAK,MAAM,aAAa,YAAY;EAClC,MAAM,OAAO,KAAK,KAAK,MAAM,UAAU;AACvC,MAAI;AACF,OAAI,GAAG,SAAS,KAAK,CAAC,aAAa,CAAE,QAAO;UACtC;;AAIV,QAAO;;;;;;;;AAWT,eAAsB,iBAAiB,SAIrB;CAChB,MAAM,EAAE,SAAS;CAEjB,MAAM,SAAS,QAAQ,MAAM,OAAO,UAAU;CAC9C,MAAM,WAAW,QAAQ,MAAM,SAAS,YAAY;AAEpD,KAAI,CAAC,UAAU,CAAC,SAAU;AAE1B,KAAI,QAAQ;EAEV,MAAM,EAAE,cAAc,MAAM,OAAO;EAEnC,MAAM,OAAO,gBAAgB;GAAE,WADhB,MAAM,UAAU,QAAQ,QAAQ,eAAe;GACZ,iBAAiB,QAAQ;GAAiB,CAAC;AAC7F,MAAI,KAAK,SAAS,EAChB,SAAQ,IAAI,OAAO,kBAAkB,MAAM,MAAM,CAAC;;AAItD,KAAI,UAAU;EACZ,MAAM,EAAE,aAAa,cAAc,MAAM,OAAO;EAChD,MAAM,CAAC,YAAY,aAAa,MAAM,QAAQ,IAAI,CAChD,YAAY,UAAU,QAAQ,eAAe,EAC7C,UAAU,UAAU,QAAQ,eAAe,CAC5C,CAAC;EACF,MAAM,OAAO,gBAAgB;GAC3B;GACA;GACA,iBAAiB,QAAQ;GAC1B,CAAC;AACF,MAAI,KAAK,SAAS,EAChB,SAAQ,IAAI,OAAO,kBAAkB,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,53 @@
1
+ import { ClassificationReason, ModuleGraphStaticReason } from "./layout-classification-types.js";
2
+ import { AppRoute } from "../routing/app-router.js";
3
+
4
+ //#region src/build/route-classification-manifest.d.ts
5
+ type Layer1Class = "static" | "dynamic";
6
+ type RouteManifestEntry = {
7
+ /** Route pattern for diagnostics (e.g. "/blog/:slug"). */pattern: string; /** Absolute file paths for each layout, ordered root → leaf. */
8
+ layoutPaths: string[]; /** Layer 1 (segment config) results keyed by numeric layout index. */
9
+ layer1: Map<number, Layer1Class>;
10
+ /**
11
+ * Structured reasons for every Layer 1 decision, keyed by the same layout
12
+ * index. Always populated in lockstep with `layer1` so the debug channel
13
+ * can surface which segment-config field produced the decision.
14
+ */
15
+ layer1Reasons: Map<number, ClassificationReason>;
16
+ };
17
+ type RouteClassificationManifest = {
18
+ routes: RouteManifestEntry[];
19
+ };
20
+ /**
21
+ * Reads each layout's source at build time and runs Layer 1 segment-config
22
+ * classification. Fails loudly if any layout file is missing — a missing
23
+ * layout means the routing scan and the filesystem have drifted, and shipping
24
+ * a build in that state would silently break layout rendering.
25
+ */
26
+ declare function collectRouteClassificationManifest(routes: readonly AppRoute[]): RouteClassificationManifest;
27
+ /**
28
+ * Builds a JavaScript arrow-function expression that dispatches route index
29
+ * to a pre-computed `Map<layoutIndex, "static" | "dynamic">` of build-time
30
+ * classifications. The returned string is suitable for embedding into the
31
+ * generated RSC entry via `generateBundle`.
32
+ *
33
+ * `layer2PerRoute` is typed to only carry `"static"` entries — the
34
+ * module-graph classifier can only prove static, so "needs-probe" results
35
+ * are omitted by the caller before this map is constructed.
36
+ */
37
+ declare function buildGenerateBundleReplacement(manifest: RouteClassificationManifest, layer2PerRoute: ReadonlyMap<number, ReadonlyMap<number, ModuleGraphStaticReason>>): string;
38
+ /**
39
+ * Sibling of `buildGenerateBundleReplacement`: emits a dispatch function
40
+ * that returns `Map<layoutIndex, ClassificationReason>` per route.
41
+ *
42
+ * The runtime consults this map only when `VINEXT_DEBUG_CLASSIFICATION` is
43
+ * set, and the plugin only patches this dispatcher into the built bundle when
44
+ * that env var is present at build time.
45
+ *
46
+ * Layer 1 priority applies the same way as in `buildGenerateBundleReplacement`:
47
+ * a segment-config reason must override a module-graph reason for the same
48
+ * layout index.
49
+ */
50
+ declare function buildReasonsReplacement(manifest: RouteClassificationManifest, layer2PerRoute: ReadonlyMap<number, ReadonlyMap<number, ModuleGraphStaticReason>>): string;
51
+ //#endregion
52
+ export { Layer1Class, RouteClassificationManifest, RouteManifestEntry, buildGenerateBundleReplacement, buildReasonsReplacement, collectRouteClassificationManifest };
53
+ //# sourceMappingURL=route-classification-manifest.d.ts.map
@@ -0,0 +1,145 @@
1
+ import { classifyLayoutSegmentConfig } from "./report.js";
2
+ import fs from "node:fs";
3
+ //#region src/build/route-classification-manifest.ts
4
+ /**
5
+ * Build-time layout classification manifest.
6
+ *
7
+ * Bridges the classifier in `./layout-classification.ts` with the RSC entry
8
+ * codegen so that the per-layout static/dynamic classifications produced at
9
+ * build time are visible to the runtime probe loop in
10
+ * `server/app-page-execution.ts`.
11
+ *
12
+ * The runtime probe looks up entries by numeric `layoutIndex`, so this module
13
+ * is responsible for flattening the classifier's string-keyed layout IDs into
14
+ * a per-route, index-keyed structure that can be emitted from codegen.
15
+ */
16
+ /**
17
+ * Reads each layout's source at build time and runs Layer 1 segment-config
18
+ * classification. Fails loudly if any layout file is missing — a missing
19
+ * layout means the routing scan and the filesystem have drifted, and shipping
20
+ * a build in that state would silently break layout rendering.
21
+ */
22
+ function collectRouteClassificationManifest(routes) {
23
+ const manifestRoutes = [];
24
+ const sourceCache = /* @__PURE__ */ new Map();
25
+ for (const route of routes) {
26
+ const layer1 = /* @__PURE__ */ new Map();
27
+ const layer1Reasons = /* @__PURE__ */ new Map();
28
+ for (let layoutIndex = 0; layoutIndex < route.layouts.length; layoutIndex++) {
29
+ const layoutPath = route.layouts[layoutIndex];
30
+ let source = sourceCache.get(layoutPath);
31
+ if (source === void 0) try {
32
+ source = fs.readFileSync(layoutPath, "utf8");
33
+ sourceCache.set(layoutPath, source);
34
+ } catch (cause) {
35
+ throw new Error(`vinext: failed to read layout for route ${route.pattern} at ${layoutPath}`, { cause });
36
+ }
37
+ const result = classifyLayoutSegmentConfig(source);
38
+ if (result.kind === "static" || result.kind === "dynamic") {
39
+ layer1.set(layoutIndex, result.kind);
40
+ layer1Reasons.set(layoutIndex, result.reason);
41
+ }
42
+ }
43
+ manifestRoutes.push({
44
+ pattern: route.pattern,
45
+ layoutPaths: [...route.layouts],
46
+ layer1,
47
+ layer1Reasons
48
+ });
49
+ }
50
+ return { routes: manifestRoutes };
51
+ }
52
+ /**
53
+ * Merges Layer 1 (segment config) and Layer 2 (module graph) into a single
54
+ * per-route map, applying the Layer-1-wins priority rule.
55
+ *
56
+ * Layer 1 always takes priority over Layer 2 for the same layout index:
57
+ * segment config is a user-authored guarantee, so a layout that explicitly
58
+ * says `force-dynamic` must never be demoted to "static" because its module
59
+ * graph happened to be clean.
60
+ */
61
+ function mergeLayersForRoute(route, layer2) {
62
+ const merged = /* @__PURE__ */ new Map();
63
+ if (layer2) for (const [layoutIdx, reason] of layer2) merged.set(layoutIdx, {
64
+ kind: "static",
65
+ reason
66
+ });
67
+ for (const [layoutIdx, kind] of route.layer1) {
68
+ const reason = route.layer1Reasons.get(layoutIdx);
69
+ if (reason === void 0) throw new Error(`vinext: layout ${layoutIdx} in route ${route.pattern} has a Layer 1 decision without a reason`);
70
+ merged.set(layoutIdx, {
71
+ kind,
72
+ reason
73
+ });
74
+ }
75
+ return merged;
76
+ }
77
+ function serializeReasonExpression(reason) {
78
+ switch (reason.layer) {
79
+ case "segment-config": {
80
+ const value = reason.value === Infinity ? "Infinity" : JSON.stringify(reason.value);
81
+ return `{ layer: "segment-config", key: ${JSON.stringify(reason.key)}, value: ${value} }`;
82
+ }
83
+ case "module-graph": {
84
+ const props = [`layer: "module-graph"`, `result: ${JSON.stringify(reason.result)}`];
85
+ if (reason.firstShimMatch !== void 0) props.push(`firstShimMatch: ${JSON.stringify(reason.firstShimMatch)}`);
86
+ return `{ ${props.join(", ")} }`;
87
+ }
88
+ case "runtime-probe": {
89
+ const props = [`layer: "runtime-probe"`, `outcome: ${JSON.stringify(reason.outcome)}`];
90
+ if (reason.error !== void 0) props.push(`error: ${JSON.stringify(reason.error)}`);
91
+ return `{ ${props.join(", ")} }`;
92
+ }
93
+ case "no-classifier": return `{ layer: "no-classifier" }`;
94
+ }
95
+ }
96
+ function buildRouteDispatchReplacement(manifest, layer2PerRoute, serializeEntry) {
97
+ const cases = [];
98
+ for (let routeIdx = 0; routeIdx < manifest.routes.length; routeIdx++) {
99
+ const route = manifest.routes[routeIdx];
100
+ const merged = mergeLayersForRoute(route, layer2PerRoute.get(routeIdx));
101
+ if (merged.size === 0) continue;
102
+ const entries = [...merged.entries()].sort((a, b) => a[0] - b[0]).map(([idx, value]) => `[${idx}, ${serializeEntry(value)}]`).join(", ");
103
+ cases.push(` case ${routeIdx}: return new Map([${entries}]);`);
104
+ }
105
+ return [
106
+ "(routeIdx) => {",
107
+ " switch (routeIdx) {",
108
+ ...cases,
109
+ " default: return null;",
110
+ " }",
111
+ " }"
112
+ ].join("\n");
113
+ }
114
+ /**
115
+ * Builds a JavaScript arrow-function expression that dispatches route index
116
+ * to a pre-computed `Map<layoutIndex, "static" | "dynamic">` of build-time
117
+ * classifications. The returned string is suitable for embedding into the
118
+ * generated RSC entry via `generateBundle`.
119
+ *
120
+ * `layer2PerRoute` is typed to only carry `"static"` entries — the
121
+ * module-graph classifier can only prove static, so "needs-probe" results
122
+ * are omitted by the caller before this map is constructed.
123
+ */
124
+ function buildGenerateBundleReplacement(manifest, layer2PerRoute) {
125
+ return buildRouteDispatchReplacement(manifest, layer2PerRoute, (value) => JSON.stringify(value.kind));
126
+ }
127
+ /**
128
+ * Sibling of `buildGenerateBundleReplacement`: emits a dispatch function
129
+ * that returns `Map<layoutIndex, ClassificationReason>` per route.
130
+ *
131
+ * The runtime consults this map only when `VINEXT_DEBUG_CLASSIFICATION` is
132
+ * set, and the plugin only patches this dispatcher into the built bundle when
133
+ * that env var is present at build time.
134
+ *
135
+ * Layer 1 priority applies the same way as in `buildGenerateBundleReplacement`:
136
+ * a segment-config reason must override a module-graph reason for the same
137
+ * layout index.
138
+ */
139
+ function buildReasonsReplacement(manifest, layer2PerRoute) {
140
+ return buildRouteDispatchReplacement(manifest, layer2PerRoute, (value) => serializeReasonExpression(value.reason));
141
+ }
142
+ //#endregion
143
+ export { buildGenerateBundleReplacement, buildReasonsReplacement, collectRouteClassificationManifest };
144
+
145
+ //# sourceMappingURL=route-classification-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route-classification-manifest.js","names":[],"sources":["../../src/build/route-classification-manifest.ts"],"sourcesContent":["/**\n * Build-time layout classification manifest.\n *\n * Bridges the classifier in `./layout-classification.ts` with the RSC entry\n * codegen so that the per-layout static/dynamic classifications produced at\n * build time are visible to the runtime probe loop in\n * `server/app-page-execution.ts`.\n *\n * The runtime probe looks up entries by numeric `layoutIndex`, so this module\n * is responsible for flattening the classifier's string-keyed layout IDs into\n * a per-route, index-keyed structure that can be emitted from codegen.\n */\n\nimport fs from \"node:fs\";\nimport type { AppRoute } from \"../routing/app-router.js\";\nimport type {\n ClassificationReason,\n LayoutBuildClassification,\n ModuleGraphStaticReason,\n} from \"./layout-classification-types.js\";\nimport { classifyLayoutSegmentConfig } from \"./report.js\";\n\nexport type Layer1Class = \"static\" | \"dynamic\";\n\nexport type RouteManifestEntry = {\n /** Route pattern for diagnostics (e.g. \"/blog/:slug\"). */\n pattern: string;\n /** Absolute file paths for each layout, ordered root → leaf. */\n layoutPaths: string[];\n /** Layer 1 (segment config) results keyed by numeric layout index. */\n layer1: Map<number, Layer1Class>;\n /**\n * Structured reasons for every Layer 1 decision, keyed by the same layout\n * index. Always populated in lockstep with `layer1` so the debug channel\n * can surface which segment-config field produced the decision.\n */\n layer1Reasons: Map<number, ClassificationReason>;\n};\n\nexport type RouteClassificationManifest = {\n routes: RouteManifestEntry[];\n};\n\n/**\n * Reads each layout's source at build time and runs Layer 1 segment-config\n * classification. Fails loudly if any layout file is missing — a missing\n * layout means the routing scan and the filesystem have drifted, and shipping\n * a build in that state would silently break layout rendering.\n */\nexport function collectRouteClassificationManifest(\n routes: readonly AppRoute[],\n): RouteClassificationManifest {\n const manifestRoutes: RouteManifestEntry[] = [];\n const sourceCache = new Map<string, string>();\n\n for (const route of routes) {\n const layer1 = new Map<number, Layer1Class>();\n const layer1Reasons = new Map<number, ClassificationReason>();\n\n for (let layoutIndex = 0; layoutIndex < route.layouts.length; layoutIndex++) {\n const layoutPath = route.layouts[layoutIndex]!;\n let source = sourceCache.get(layoutPath);\n if (source === undefined) {\n try {\n source = fs.readFileSync(layoutPath, \"utf8\");\n sourceCache.set(layoutPath, source);\n } catch (cause) {\n throw new Error(\n `vinext: failed to read layout for route ${route.pattern} at ${layoutPath}`,\n { cause },\n );\n }\n }\n const result = classifyLayoutSegmentConfig(source);\n if (result.kind === \"static\" || result.kind === \"dynamic\") {\n layer1.set(layoutIndex, result.kind);\n layer1Reasons.set(layoutIndex, result.reason);\n }\n }\n\n manifestRoutes.push({\n pattern: route.pattern,\n layoutPaths: [...route.layouts],\n layer1,\n layer1Reasons,\n });\n }\n\n return { routes: manifestRoutes };\n}\n\n/**\n * Merge output entry. `mergeLayersForRoute` never emits the `absent` variant\n * of `LayoutBuildClassification`, so this narrows the type and lets\n * downstream callers read `.reason` without branching on `kind`.\n */\ntype MergedLayoutClassification = Exclude<LayoutBuildClassification, { kind: \"absent\" }>;\n\n/**\n * Merges Layer 1 (segment config) and Layer 2 (module graph) into a single\n * per-route map, applying the Layer-1-wins priority rule.\n *\n * Layer 1 always takes priority over Layer 2 for the same layout index:\n * segment config is a user-authored guarantee, so a layout that explicitly\n * says `force-dynamic` must never be demoted to \"static\" because its module\n * graph happened to be clean.\n */\nfunction mergeLayersForRoute(\n route: RouteManifestEntry,\n layer2: ReadonlyMap<number, ModuleGraphStaticReason> | undefined,\n): Map<number, MergedLayoutClassification> {\n const merged = new Map<number, MergedLayoutClassification>();\n\n if (layer2) {\n for (const [layoutIdx, reason] of layer2) {\n merged.set(layoutIdx, {\n kind: \"static\",\n reason,\n });\n }\n }\n\n for (const [layoutIdx, kind] of route.layer1) {\n const reason = route.layer1Reasons.get(layoutIdx);\n if (reason === undefined) {\n throw new Error(\n `vinext: layout ${layoutIdx} in route ${route.pattern} has a Layer 1 decision without a reason`,\n );\n }\n merged.set(layoutIdx, { kind, reason });\n }\n\n return merged;\n}\n\nfunction serializeReasonExpression(reason: ClassificationReason): string {\n switch (reason.layer) {\n case \"segment-config\": {\n // Infinity must be checked first: JSON.stringify(Infinity) produces \"null\".\n const value = reason.value === Infinity ? \"Infinity\" : JSON.stringify(reason.value);\n return `{ layer: \"segment-config\", key: ${JSON.stringify(reason.key)}, value: ${value} }`;\n }\n case \"module-graph\": {\n const props = [`layer: \"module-graph\"`, `result: ${JSON.stringify(reason.result)}`];\n if (reason.firstShimMatch !== undefined) {\n props.push(`firstShimMatch: ${JSON.stringify(reason.firstShimMatch)}`);\n }\n return `{ ${props.join(\", \")} }`;\n }\n // The two arms below are not reachable from the current build-time pipeline\n // (only segment-config and module-graph reasons flow into this function).\n // They are present for type exhaustiveness and so that #843's debug sidecar\n // can extend this function to cover all ClassificationReason variants without\n // a separate serializer. Narrowing the parameter type to only the build-time\n // variants requires propagating through LayoutBuildClassification in report.ts;\n // deferred to a follow-up.\n case \"runtime-probe\": {\n const props = [`layer: \"runtime-probe\"`, `outcome: ${JSON.stringify(reason.outcome)}`];\n if (reason.error !== undefined) {\n props.push(`error: ${JSON.stringify(reason.error)}`);\n }\n return `{ ${props.join(\", \")} }`;\n }\n case \"no-classifier\":\n return `{ layer: \"no-classifier\" }`;\n }\n}\n\nfunction buildRouteDispatchReplacement(\n manifest: RouteClassificationManifest,\n layer2PerRoute: ReadonlyMap<number, ReadonlyMap<number, ModuleGraphStaticReason>>,\n serializeEntry: (value: MergedLayoutClassification) => string,\n): string {\n const cases: string[] = [];\n\n for (let routeIdx = 0; routeIdx < manifest.routes.length; routeIdx++) {\n const route = manifest.routes[routeIdx]!;\n const merged = mergeLayersForRoute(route, layer2PerRoute.get(routeIdx));\n\n if (merged.size === 0) continue;\n\n const entries = [...merged.entries()]\n .sort((a, b) => a[0] - b[0])\n .map(([idx, value]) => `[${idx}, ${serializeEntry(value)}]`)\n .join(\", \");\n cases.push(` case ${routeIdx}: return new Map([${entries}]);`);\n }\n\n return [\n \"(routeIdx) => {\",\n \" switch (routeIdx) {\",\n ...cases,\n \" default: return null;\",\n \" }\",\n \" }\",\n ].join(\"\\n\");\n}\n\n/**\n * Builds a JavaScript arrow-function expression that dispatches route index\n * to a pre-computed `Map<layoutIndex, \"static\" | \"dynamic\">` of build-time\n * classifications. The returned string is suitable for embedding into the\n * generated RSC entry via `generateBundle`.\n *\n * `layer2PerRoute` is typed to only carry `\"static\"` entries — the\n * module-graph classifier can only prove static, so \"needs-probe\" results\n * are omitted by the caller before this map is constructed.\n */\nexport function buildGenerateBundleReplacement(\n manifest: RouteClassificationManifest,\n layer2PerRoute: ReadonlyMap<number, ReadonlyMap<number, ModuleGraphStaticReason>>,\n): string {\n return buildRouteDispatchReplacement(manifest, layer2PerRoute, (value) =>\n JSON.stringify(value.kind),\n );\n}\n\n/**\n * Sibling of `buildGenerateBundleReplacement`: emits a dispatch function\n * that returns `Map<layoutIndex, ClassificationReason>` per route.\n *\n * The runtime consults this map only when `VINEXT_DEBUG_CLASSIFICATION` is\n * set, and the plugin only patches this dispatcher into the built bundle when\n * that env var is present at build time.\n *\n * Layer 1 priority applies the same way as in `buildGenerateBundleReplacement`:\n * a segment-config reason must override a module-graph reason for the same\n * layout index.\n */\nexport function buildReasonsReplacement(\n manifest: RouteClassificationManifest,\n layer2PerRoute: ReadonlyMap<number, ReadonlyMap<number, ModuleGraphStaticReason>>,\n): string {\n return buildRouteDispatchReplacement(manifest, layer2PerRoute, (value) =>\n serializeReasonExpression(value.reason),\n );\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { apiRouter, pagesRouter } from "../routing/pages-router.js";
2
2
  import { appRouter } from "../routing/app-router.js";
3
- import { loadNextConfig, resolveNextConfig } from "../config/next-config.js";
4
3
  import { findDir } from "./report.js";
4
+ import { loadNextConfig, resolveNextConfig } from "../config/next-config.js";
5
5
  import { readPrerenderSecret } from "./server-manifest.js";
6
6
  import { startProdServer } from "../server/prod-server.js";
7
7
  import { prerenderApp, prerenderPages, writePrerenderIndex } from "./prerender.js";
@@ -0,0 +1,19 @@
1
+ //#region src/build/ssr-manifest.d.ts
2
+ type BundleBackfillChunk = {
3
+ type: "chunk";
4
+ fileName: string;
5
+ imports?: string[];
6
+ modules?: Record<string, unknown>;
7
+ viteMetadata?: {
8
+ importedCss?: Set<string>;
9
+ importedAssets?: Set<string>;
10
+ };
11
+ };
12
+ declare function tryRealpathSync(candidate: string): string | null;
13
+ declare function relativeWithinRoot(root: string, moduleId: string): string | null;
14
+ declare function augmentSsrManifestFromBundle(ssrManifest: Record<string, string[]>, bundle: Record<string, BundleBackfillChunk | {
15
+ type: string;
16
+ }>, root: string, base?: string): Record<string, string[]>;
17
+ //#endregion
18
+ export { BundleBackfillChunk, augmentSsrManifestFromBundle, relativeWithinRoot, tryRealpathSync };
19
+ //# sourceMappingURL=ssr-manifest.d.ts.map
@@ -0,0 +1,71 @@
1
+ import { manifestFileWithBase, normalizeManifestFile } from "../utils/manifest-paths.js";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ //#region src/build/ssr-manifest.ts
5
+ function tryRealpathSync(candidate) {
6
+ try {
7
+ return fs.realpathSync.native(candidate);
8
+ } catch {
9
+ return null;
10
+ }
11
+ }
12
+ function isWindowsAbsolutePath(candidate) {
13
+ return /^[a-zA-Z]:[\\/]/.test(candidate) || candidate.startsWith("\\\\");
14
+ }
15
+ function relativeWithinRoot(root, moduleId) {
16
+ const relativeId = (isWindowsAbsolutePath(root) || isWindowsAbsolutePath(moduleId) ? path.win32.relative(root, moduleId) : path.relative(root, moduleId)).replace(/\\/g, "/");
17
+ if (!relativeId || relativeId === ".." || relativeId.startsWith("../")) return null;
18
+ return relativeId;
19
+ }
20
+ function normalizeManifestModuleId(moduleId, root) {
21
+ const normalizedId = moduleId.replace(/\\/g, "/");
22
+ if (normalizedId.startsWith("\0")) return normalizedId;
23
+ if (normalizedId.startsWith("node_modules/") || normalizedId.includes("/node_modules/")) return normalizedId;
24
+ if (!isWindowsAbsolutePath(moduleId) && !path.isAbsolute(moduleId)) {
25
+ if (!normalizedId.startsWith(".") && !normalizedId.includes("../")) return normalizedId;
26
+ }
27
+ const rootCandidates = new Set([root]);
28
+ const realRoot = tryRealpathSync(root);
29
+ if (realRoot) rootCandidates.add(realRoot);
30
+ const moduleCandidates = /* @__PURE__ */ new Set();
31
+ if (isWindowsAbsolutePath(moduleId) || path.isAbsolute(moduleId)) moduleCandidates.add(moduleId);
32
+ else moduleCandidates.add(path.resolve(root, moduleId));
33
+ for (const candidate of moduleCandidates) {
34
+ const realCandidate = tryRealpathSync(candidate);
35
+ if (realCandidate) moduleCandidates.add(realCandidate);
36
+ }
37
+ for (const rootCandidate of rootCandidates) for (const moduleCandidate of moduleCandidates) {
38
+ const relativeId = relativeWithinRoot(rootCandidate, moduleCandidate);
39
+ if (relativeId) return relativeId;
40
+ }
41
+ return normalizedId;
42
+ }
43
+ function augmentSsrManifestFromBundle(ssrManifest, bundle, root, base = "/") {
44
+ const nextManifest = {};
45
+ for (const [key, files] of Object.entries(ssrManifest)) {
46
+ const normalizedKey = normalizeManifestModuleId(key, root);
47
+ if (!nextManifest[normalizedKey]) nextManifest[normalizedKey] = /* @__PURE__ */ new Set();
48
+ for (const file of files) nextManifest[normalizedKey].add(normalizeManifestFile(file));
49
+ }
50
+ for (const item of Object.values(bundle)) {
51
+ if (item.type !== "chunk") continue;
52
+ const chunk = item;
53
+ const files = /* @__PURE__ */ new Set();
54
+ files.add(manifestFileWithBase(chunk.fileName, base));
55
+ for (const importedFile of chunk.imports ?? []) files.add(manifestFileWithBase(importedFile, base));
56
+ for (const cssFile of chunk.viteMetadata?.importedCss ?? []) files.add(manifestFileWithBase(cssFile, base));
57
+ for (const assetFile of chunk.viteMetadata?.importedAssets ?? []) files.add(manifestFileWithBase(assetFile, base));
58
+ for (const moduleId of Object.keys(chunk.modules ?? {})) {
59
+ const key = normalizeManifestModuleId(moduleId, root);
60
+ if (key.startsWith("node_modules/") || key.includes("/node_modules/")) continue;
61
+ if (key.startsWith("\0")) continue;
62
+ if (!nextManifest[key]) nextManifest[key] = /* @__PURE__ */ new Set();
63
+ for (const file of files) nextManifest[key].add(file);
64
+ }
65
+ }
66
+ return Object.fromEntries(Object.entries(nextManifest).map(([key, files]) => [key, [...files]]));
67
+ }
68
+ //#endregion
69
+ export { augmentSsrManifestFromBundle, relativeWithinRoot, tryRealpathSync };
70
+
71
+ //# sourceMappingURL=ssr-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ssr-manifest.js","names":[],"sources":["../../src/build/ssr-manifest.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { normalizeManifestFile, manifestFileWithBase } from \"../utils/manifest-paths.js\";\n\nexport type BundleBackfillChunk = {\n type: \"chunk\";\n fileName: string;\n imports?: string[];\n modules?: Record<string, unknown>;\n viteMetadata?: {\n importedCss?: Set<string>;\n importedAssets?: Set<string>;\n };\n};\n\nexport function tryRealpathSync(candidate: string): string | null {\n try {\n return fs.realpathSync.native(candidate);\n } catch {\n return null;\n }\n}\n\nfunction isWindowsAbsolutePath(candidate: string): boolean {\n return /^[a-zA-Z]:[\\\\/]/.test(candidate) || candidate.startsWith(\"\\\\\\\\\");\n}\n\nexport function relativeWithinRoot(root: string, moduleId: string): string | null {\n const useWindowsPath = isWindowsAbsolutePath(root) || isWindowsAbsolutePath(moduleId);\n const relativeId = (\n useWindowsPath ? path.win32.relative(root, moduleId) : path.relative(root, moduleId)\n ).replace(/\\\\/g, \"/\");\n // path.relative(root, root) returns \"\", which is not a usable manifest key and should be\n // treated the same as \"outside root\" for this helper.\n if (!relativeId || relativeId === \"..\" || relativeId.startsWith(\"../\")) return null;\n return relativeId;\n}\n\nfunction normalizeManifestModuleId(moduleId: string, root: string): string {\n const normalizedId = moduleId.replace(/\\\\/g, \"/\");\n if (normalizedId.startsWith(\"\\0\")) return normalizedId;\n if (normalizedId.startsWith(\"node_modules/\") || normalizedId.includes(\"/node_modules/\")) {\n return normalizedId;\n }\n\n if (!isWindowsAbsolutePath(moduleId) && !path.isAbsolute(moduleId)) {\n if (!normalizedId.startsWith(\".\") && !normalizedId.includes(\"../\")) {\n // Preserve bare specifiers like \"pages/counter.tsx\". These are already\n // stable manifest keys and resolving them against root would rewrite them\n // into filesystem paths that no longer match the bundle/module graph.\n return normalizedId;\n }\n }\n\n const rootCandidates = new Set<string>([root]);\n const realRoot = tryRealpathSync(root);\n if (realRoot) rootCandidates.add(realRoot);\n\n const moduleCandidates = new Set<string>();\n if (isWindowsAbsolutePath(moduleId) || path.isAbsolute(moduleId)) {\n moduleCandidates.add(moduleId);\n } else {\n moduleCandidates.add(path.resolve(root, moduleId));\n }\n\n for (const candidate of moduleCandidates) {\n const realCandidate = tryRealpathSync(candidate);\n // Set iteration stays live as entries are appended, so this also checks the\n // realpath variant without needing a second pass or an intermediate array.\n if (realCandidate) moduleCandidates.add(realCandidate);\n }\n\n for (const rootCandidate of rootCandidates) {\n for (const moduleCandidate of moduleCandidates) {\n const relativeId = relativeWithinRoot(rootCandidate, moduleCandidate);\n if (relativeId) return relativeId;\n }\n }\n\n return normalizedId;\n}\n\nexport function augmentSsrManifestFromBundle(\n ssrManifest: Record<string, string[]>,\n bundle: Record<string, BundleBackfillChunk | { type: string }>,\n root: string,\n base = \"/\",\n): Record<string, string[]> {\n const nextManifest = {} as Record<string, Set<string>>;\n\n for (const [key, files] of Object.entries(ssrManifest)) {\n const normalizedKey = normalizeManifestModuleId(key, root);\n if (!nextManifest[normalizedKey]) nextManifest[normalizedKey] = new Set<string>();\n for (const file of files) {\n nextManifest[normalizedKey].add(normalizeManifestFile(file));\n }\n }\n\n for (const item of Object.values(bundle)) {\n if (item.type !== \"chunk\") continue;\n const chunk = item as BundleBackfillChunk;\n\n const files = new Set<string>();\n files.add(manifestFileWithBase(chunk.fileName, base));\n for (const importedFile of chunk.imports ?? []) {\n files.add(manifestFileWithBase(importedFile, base));\n }\n for (const cssFile of chunk.viteMetadata?.importedCss ?? []) {\n files.add(manifestFileWithBase(cssFile, base));\n }\n for (const assetFile of chunk.viteMetadata?.importedAssets ?? []) {\n files.add(manifestFileWithBase(assetFile, base));\n }\n\n for (const moduleId of Object.keys(chunk.modules ?? {})) {\n const key = normalizeManifestModuleId(moduleId, root);\n if (key.startsWith(\"node_modules/\") || key.includes(\"/node_modules/\")) continue;\n if (key.startsWith(\"\\0\")) continue;\n if (!nextManifest[key]) nextManifest[key] = new Set<string>();\n for (const file of files) {\n nextManifest[key].add(file);\n }\n }\n }\n\n return Object.fromEntries(\n Object.entries(nextManifest).map(([key, files]) => [key, [...files]]),\n ) as Record<string, string[]>;\n}\n"],"mappings":"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"}
package/dist/check.js CHANGED
@@ -185,8 +185,8 @@ const CONFIG_SUPPORT = {
185
185
  detail: "supported for Pages Router; App Router unchanged"
186
186
  },
187
187
  reactStrictMode: {
188
- status: "supported",
189
- detail: "always enabled"
188
+ status: "partial",
189
+ detail: "config option recognized but not yet enforced; root is not wrapped in <React.StrictMode>"
190
190
  },
191
191
  poweredByHeader: {
192
192
  status: "supported",