vinext 0.0.28 → 0.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build/report.d.ts +117 -0
- package/dist/build/report.d.ts.map +1 -0
- package/dist/build/report.js +303 -0
- package/dist/build/report.js.map +1 -0
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +11 -7
- package/dist/check.js.map +1 -1
- package/dist/cli.js +106 -9
- package/dist/cli.js.map +1 -1
- package/dist/cloudflare/kv-cache-handler.d.ts.map +1 -1
- package/dist/cloudflare/kv-cache-handler.js +58 -42
- package/dist/cloudflare/kv-cache-handler.js.map +1 -1
- package/dist/cloudflare/tpr.d.ts +10 -0
- package/dist/cloudflare/tpr.d.ts.map +1 -1
- package/dist/cloudflare/tpr.js +36 -41
- package/dist/cloudflare/tpr.js.map +1 -1
- package/dist/config/next-config.d.ts.map +1 -1
- package/dist/config/next-config.js +16 -0
- package/dist/config/next-config.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +1 -1
- package/dist/entries/app-rsc-entry.d.ts.map +1 -1
- package/dist/entries/app-rsc-entry.js +225 -186
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.d.ts.map +1 -1
- package/dist/entries/pages-server-entry.js +192 -91
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +121 -40
- package/dist/index.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -0
- package/dist/routing/app-router.d.ts.map +1 -1
- package/dist/routing/app-router.js +131 -104
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/pages-router.d.ts.map +1 -1
- package/dist/routing/pages-router.js +17 -57
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/routing/route-trie.d.ts +57 -0
- package/dist/routing/route-trie.d.ts.map +1 -0
- package/dist/routing/route-trie.js +160 -0
- package/dist/routing/route-trie.js.map +1 -0
- package/dist/routing/route-validation.d.ts.map +1 -1
- package/dist/routing/route-validation.js +13 -1
- package/dist/routing/route-validation.js.map +1 -1
- package/dist/routing/utils.d.ts +19 -0
- package/dist/routing/utils.d.ts.map +1 -1
- package/dist/routing/utils.js +47 -0
- package/dist/routing/utils.js.map +1 -1
- package/dist/server/api-handler.d.ts.map +1 -1
- package/dist/server/api-handler.js +28 -13
- package/dist/server/api-handler.js.map +1 -1
- package/dist/server/app-router-entry.js +1 -1
- package/dist/server/app-router-entry.js.map +1 -1
- package/dist/server/dev-server.d.ts +2 -1
- package/dist/server/dev-server.d.ts.map +1 -1
- package/dist/server/dev-server.js +167 -115
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/image-optimization.d.ts.map +1 -1
- package/dist/server/image-optimization.js +24 -12
- package/dist/server/image-optimization.js.map +1 -1
- package/dist/server/instrumentation.d.ts.map +1 -1
- package/dist/server/instrumentation.js +17 -8
- package/dist/server/instrumentation.js.map +1 -1
- package/dist/server/isr-cache.d.ts.map +1 -1
- package/dist/server/isr-cache.js +8 -3
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/metadata-routes.d.ts.map +1 -1
- package/dist/server/metadata-routes.js +56 -18
- package/dist/server/metadata-routes.js.map +1 -1
- package/dist/server/middleware-codegen.d.ts +10 -0
- package/dist/server/middleware-codegen.d.ts.map +1 -1
- package/dist/server/middleware-codegen.js +76 -4
- package/dist/server/middleware-codegen.js.map +1 -1
- package/dist/server/middleware.d.ts.map +1 -1
- package/dist/server/middleware.js +52 -7
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/pages-i18n.d.ts +50 -0
- package/dist/server/pages-i18n.d.ts.map +1 -0
- package/dist/server/pages-i18n.js +152 -0
- package/dist/server/pages-i18n.js.map +1 -0
- package/dist/server/prod-server.d.ts +8 -2
- package/dist/server/prod-server.d.ts.map +1 -1
- package/dist/server/prod-server.js +60 -20
- package/dist/server/prod-server.js.map +1 -1
- package/dist/shims/cache-runtime.d.ts +3 -0
- package/dist/shims/cache-runtime.d.ts.map +1 -1
- package/dist/shims/cache-runtime.js +22 -5
- package/dist/shims/cache-runtime.js.map +1 -1
- package/dist/shims/cache.d.ts +3 -0
- package/dist/shims/cache.d.ts.map +1 -1
- package/dist/shims/cache.js +21 -12
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/constants.d.ts.map +1 -1
- package/dist/shims/constants.js +0 -1
- package/dist/shims/constants.js.map +1 -1
- package/dist/shims/fetch-cache.d.ts +14 -0
- package/dist/shims/fetch-cache.d.ts.map +1 -1
- package/dist/shims/fetch-cache.js +102 -37
- package/dist/shims/fetch-cache.js.map +1 -1
- package/dist/shims/head-state.d.ts +4 -0
- package/dist/shims/head-state.d.ts.map +1 -1
- package/dist/shims/head-state.js +14 -11
- package/dist/shims/head-state.js.map +1 -1
- package/dist/shims/head.d.ts +4 -2
- package/dist/shims/head.d.ts.map +1 -1
- package/dist/shims/head.js +162 -52
- package/dist/shims/head.js.map +1 -1
- package/dist/shims/headers.d.ts +8 -1
- package/dist/shims/headers.d.ts.map +1 -1
- package/dist/shims/headers.js +23 -34
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/i18n-context.d.ts +27 -0
- package/dist/shims/i18n-context.d.ts.map +1 -0
- package/dist/shims/i18n-context.js +57 -0
- package/dist/shims/i18n-context.js.map +1 -0
- package/dist/shims/i18n-state.d.ts +20 -0
- package/dist/shims/i18n-state.d.ts.map +1 -0
- package/dist/shims/i18n-state.js +53 -0
- package/dist/shims/i18n-state.js.map +1 -0
- package/dist/shims/image.d.ts +2 -0
- package/dist/shims/image.d.ts.map +1 -1
- package/dist/shims/image.js +14 -6
- package/dist/shims/image.js.map +1 -1
- package/dist/shims/internal/utils.d.ts +1 -0
- package/dist/shims/internal/utils.d.ts.map +1 -1
- package/dist/shims/internal/utils.js.map +1 -1
- package/dist/shims/link.d.ts.map +1 -1
- package/dist/shims/link.js +38 -54
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +78 -22
- package/dist/shims/metadata.d.ts.map +1 -1
- package/dist/shims/metadata.js +96 -28
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation-state.d.ts +14 -0
- package/dist/shims/navigation-state.d.ts.map +1 -1
- package/dist/shims/navigation-state.js +33 -15
- package/dist/shims/navigation-state.js.map +1 -1
- package/dist/shims/navigation.d.ts +2 -0
- package/dist/shims/navigation.d.ts.map +1 -1
- package/dist/shims/navigation.js +80 -51
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/request-context.d.ts.map +1 -1
- package/dist/shims/request-context.js +9 -0
- package/dist/shims/request-context.js.map +1 -1
- package/dist/shims/request-state-types.d.ts +11 -0
- package/dist/shims/request-state-types.d.ts.map +1 -0
- package/dist/shims/request-state-types.js +2 -0
- package/dist/shims/request-state-types.js.map +1 -0
- package/dist/shims/router-state.d.ts +11 -0
- package/dist/shims/router-state.d.ts.map +1 -1
- package/dist/shims/router-state.js +10 -8
- package/dist/shims/router-state.js.map +1 -1
- package/dist/shims/router.d.ts +4 -0
- package/dist/shims/router.d.ts.map +1 -1
- package/dist/shims/router.js +130 -40
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/server.d.ts +8 -1
- package/dist/shims/server.d.ts.map +1 -1
- package/dist/shims/server.js +52 -6
- package/dist/shims/server.js.map +1 -1
- package/dist/shims/unified-request-context.d.ts +66 -0
- package/dist/shims/unified-request-context.d.ts.map +1 -0
- package/dist/shims/unified-request-context.js +116 -0
- package/dist/shims/unified-request-context.js.map +1 -0
- package/dist/shims/url-utils.d.ts +20 -6
- package/dist/shims/url-utils.d.ts.map +1 -1
- package/dist/shims/url-utils.js +79 -0
- package/dist/shims/url-utils.js.map +1 -1
- package/dist/utils/domain-locale.d.ts +18 -0
- package/dist/utils/domain-locale.d.ts.map +1 -0
- package/dist/utils/domain-locale.js +64 -0
- package/dist/utils/domain-locale.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build report — prints a Next.js-style route table after `vinext build`.
|
|
3
|
+
*
|
|
4
|
+
* Classifies every discovered route as:
|
|
5
|
+
* ○ Static — confirmed static: force-static or revalidate=Infinity
|
|
6
|
+
* ◐ ISR — statically rendered, revalidated on a timer (revalidate=N)
|
|
7
|
+
* ƒ Dynamic — confirmed dynamic: force-dynamic, revalidate=0, or getServerSideProps
|
|
8
|
+
* ? Unknown — no explicit config; likely dynamic but not confirmed
|
|
9
|
+
* λ API — API route handler
|
|
10
|
+
*
|
|
11
|
+
* Classification uses regex-based static source analysis (no module
|
|
12
|
+
* execution). Vite's parseAst() is NOT used because it doesn't handle
|
|
13
|
+
* TypeScript syntax.
|
|
14
|
+
*
|
|
15
|
+
* Limitation: without running the build, we cannot detect dynamic API usage
|
|
16
|
+
* (headers(), cookies(), connection(), etc.) that implicitly forces a route
|
|
17
|
+
* dynamic. Routes without explicit `export const dynamic` or
|
|
18
|
+
* `export const revalidate` are classified as "unknown" rather than "static"
|
|
19
|
+
* to avoid false confidence.
|
|
20
|
+
*/
|
|
21
|
+
import type { Route } from "../routing/pages-router.js";
|
|
22
|
+
import type { AppRoute } from "../routing/app-router.js";
|
|
23
|
+
export type RouteType = "static" | "isr" | "ssr" | "unknown" | "api";
|
|
24
|
+
export interface RouteRow {
|
|
25
|
+
pattern: string;
|
|
26
|
+
type: RouteType;
|
|
27
|
+
/** Only set for `isr` routes. */
|
|
28
|
+
revalidate?: number;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns true if the source code contains a named export with the given name.
|
|
32
|
+
* Handles all three common export forms:
|
|
33
|
+
* export function foo() {}
|
|
34
|
+
* export const foo = ...
|
|
35
|
+
* export { foo }
|
|
36
|
+
*/
|
|
37
|
+
export declare function hasNamedExport(code: string, name: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Extracts the string value of `export const <name> = "value"`.
|
|
40
|
+
* Handles optional TypeScript type annotations:
|
|
41
|
+
* export const dynamic: string = "force-dynamic"
|
|
42
|
+
* Returns null if the export is absent or not a string literal.
|
|
43
|
+
*/
|
|
44
|
+
export declare function extractExportConstString(code: string, name: string): string | null;
|
|
45
|
+
/**
|
|
46
|
+
* Extracts the numeric value of `export const <name> = <number>`.
|
|
47
|
+
* Supports integers, decimals, negative values, and `Infinity`.
|
|
48
|
+
* Handles optional TypeScript type annotations.
|
|
49
|
+
* Returns null if the export is absent or not a number.
|
|
50
|
+
*/
|
|
51
|
+
export declare function extractExportConstNumber(code: string, name: string): number | null;
|
|
52
|
+
/**
|
|
53
|
+
* Extracts the `revalidate` value from inside a `getStaticProps` return object.
|
|
54
|
+
* Looks for: revalidate: <number> or revalidate: false or revalidate: Infinity
|
|
55
|
+
*
|
|
56
|
+
* Returns:
|
|
57
|
+
* number — a positive revalidation interval (enables ISR)
|
|
58
|
+
* 0 — treat as SSR (revalidate every request)
|
|
59
|
+
* false — fully static (no revalidation)
|
|
60
|
+
* Infinity — fully static (treated same as false by Next.js)
|
|
61
|
+
* null — no `revalidate` key found (fully static)
|
|
62
|
+
*/
|
|
63
|
+
export declare function extractGetStaticPropsRevalidate(code: string): number | false | null;
|
|
64
|
+
/**
|
|
65
|
+
* Classifies a Pages Router page file by reading its source and examining
|
|
66
|
+
* which data-fetching exports it contains.
|
|
67
|
+
*
|
|
68
|
+
* API routes (files under pages/api/) are always `api`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function classifyPagesRoute(filePath: string): {
|
|
71
|
+
type: RouteType;
|
|
72
|
+
revalidate?: number;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Classifies an App Router route.
|
|
76
|
+
*
|
|
77
|
+
* @param pagePath Absolute path to the page.tsx (null for API-only routes)
|
|
78
|
+
* @param routePath Absolute path to the route.ts handler (null for page routes)
|
|
79
|
+
* @param isDynamic Whether the URL pattern contains dynamic segments
|
|
80
|
+
*/
|
|
81
|
+
export declare function classifyAppRoute(pagePath: string | null, routePath: string | null, isDynamic: boolean): {
|
|
82
|
+
type: RouteType;
|
|
83
|
+
revalidate?: number;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Builds a sorted list of RouteRow objects from the discovered routes.
|
|
87
|
+
* Routes are sorted alphabetically by path, matching filesystem order.
|
|
88
|
+
*/
|
|
89
|
+
export declare function buildReportRows(options: {
|
|
90
|
+
pageRoutes?: Route[];
|
|
91
|
+
apiRoutes?: Route[];
|
|
92
|
+
appRoutes?: AppRoute[];
|
|
93
|
+
}): RouteRow[];
|
|
94
|
+
/**
|
|
95
|
+
* Formats a list of RouteRows into a Next.js-style build report string.
|
|
96
|
+
*
|
|
97
|
+
* Example output:
|
|
98
|
+
* Route (pages)
|
|
99
|
+
* ┌ ○ /
|
|
100
|
+
* ├ ◐ /blog/:slug (60s)
|
|
101
|
+
* ├ ƒ /dashboard
|
|
102
|
+
* └ λ /api/posts
|
|
103
|
+
*
|
|
104
|
+
* ○ Static ◐ ISR ƒ Dynamic λ API
|
|
105
|
+
*/
|
|
106
|
+
export declare function formatBuildReport(rows: RouteRow[], routerLabel?: string): string;
|
|
107
|
+
/**
|
|
108
|
+
* Scans the project at `root`, classifies all routes, and prints the
|
|
109
|
+
* Next.js-style build report to stdout.
|
|
110
|
+
*
|
|
111
|
+
* Called at the end of `vinext build` in cli.ts.
|
|
112
|
+
*/
|
|
113
|
+
export declare function printBuildReport(options: {
|
|
114
|
+
root: string;
|
|
115
|
+
pageExtensions?: string[];
|
|
116
|
+
}): Promise<void>;
|
|
117
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/build/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAIzD,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,CAAC;AAErE,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,SAAS,CAAC;IAChB,iCAAiC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAclE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOlF;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQlF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,IAAI,CAYnF;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG;IACpD,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAgCA;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,MAAM,GAAG,IAAI,EACvB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,SAAS,EAAE,OAAO,GACjB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CA0C1C;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;CACxB,GAAG,QAAQ,EAAE,CAqBb;AAoBD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,WAAW,SAAQ,GAAG,MAAM,CAsC/E;AAcD;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BhB"}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build report — prints a Next.js-style route table after `vinext build`.
|
|
3
|
+
*
|
|
4
|
+
* Classifies every discovered route as:
|
|
5
|
+
* ○ Static — confirmed static: force-static or revalidate=Infinity
|
|
6
|
+
* ◐ ISR — statically rendered, revalidated on a timer (revalidate=N)
|
|
7
|
+
* ƒ Dynamic — confirmed dynamic: force-dynamic, revalidate=0, or getServerSideProps
|
|
8
|
+
* ? Unknown — no explicit config; likely dynamic but not confirmed
|
|
9
|
+
* λ API — API route handler
|
|
10
|
+
*
|
|
11
|
+
* Classification uses regex-based static source analysis (no module
|
|
12
|
+
* execution). Vite's parseAst() is NOT used because it doesn't handle
|
|
13
|
+
* TypeScript syntax.
|
|
14
|
+
*
|
|
15
|
+
* Limitation: without running the build, we cannot detect dynamic API usage
|
|
16
|
+
* (headers(), cookies(), connection(), etc.) that implicitly forces a route
|
|
17
|
+
* dynamic. Routes without explicit `export const dynamic` or
|
|
18
|
+
* `export const revalidate` are classified as "unknown" rather than "static"
|
|
19
|
+
* to avoid false confidence.
|
|
20
|
+
*/
|
|
21
|
+
import fs from "node:fs";
|
|
22
|
+
import path from "node:path";
|
|
23
|
+
// ─── Regex-based export detection ────────────────────────────────────────────
|
|
24
|
+
/**
|
|
25
|
+
* Returns true if the source code contains a named export with the given name.
|
|
26
|
+
* Handles all three common export forms:
|
|
27
|
+
* export function foo() {}
|
|
28
|
+
* export const foo = ...
|
|
29
|
+
* export { foo }
|
|
30
|
+
*/
|
|
31
|
+
export function hasNamedExport(code, name) {
|
|
32
|
+
// Function / generator / async function declaration
|
|
33
|
+
const fnRe = new RegExp(`(?:^|\\n)\\s*export\\s+(?:async\\s+)?function\\s+${name}\\b`);
|
|
34
|
+
if (fnRe.test(code))
|
|
35
|
+
return true;
|
|
36
|
+
// Variable declaration (const / let / var)
|
|
37
|
+
const varRe = new RegExp(`(?:^|\\n)\\s*export\\s+(?:const|let|var)\\s+${name}\\s*[=:]`);
|
|
38
|
+
if (varRe.test(code))
|
|
39
|
+
return true;
|
|
40
|
+
// Re-export specifier: export { foo } or export { foo as bar }
|
|
41
|
+
const reRe = new RegExp(`export\\s*\\{[^}]*\\b${name}\\b[^}]*\\}`);
|
|
42
|
+
if (reRe.test(code))
|
|
43
|
+
return true;
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Extracts the string value of `export const <name> = "value"`.
|
|
48
|
+
* Handles optional TypeScript type annotations:
|
|
49
|
+
* export const dynamic: string = "force-dynamic"
|
|
50
|
+
* Returns null if the export is absent or not a string literal.
|
|
51
|
+
*/
|
|
52
|
+
export function extractExportConstString(code, name) {
|
|
53
|
+
const re = new RegExp(`(?:^|\\n)\\s*export\\s+const\\s+${name}\\s*(?::[^=]+)?\\s*=\\s*['"]([^'"]+)['"]`, "m");
|
|
54
|
+
const m = re.exec(code);
|
|
55
|
+
return m ? m[1] : null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Extracts the numeric value of `export const <name> = <number>`.
|
|
59
|
+
* Supports integers, decimals, negative values, and `Infinity`.
|
|
60
|
+
* Handles optional TypeScript type annotations.
|
|
61
|
+
* Returns null if the export is absent or not a number.
|
|
62
|
+
*/
|
|
63
|
+
export function extractExportConstNumber(code, name) {
|
|
64
|
+
const re = new RegExp(`(?:^|\\n)\\s*export\\s+const\\s+${name}\\s*(?::[^=]+)?\\s*=\\s*(-?\\d+(?:\\.\\d+)?|Infinity)`, "m");
|
|
65
|
+
const m = re.exec(code);
|
|
66
|
+
if (!m)
|
|
67
|
+
return null;
|
|
68
|
+
return m[1] === "Infinity" ? Infinity : parseFloat(m[1]);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Extracts the `revalidate` value from inside a `getStaticProps` return object.
|
|
72
|
+
* Looks for: revalidate: <number> or revalidate: false or revalidate: Infinity
|
|
73
|
+
*
|
|
74
|
+
* Returns:
|
|
75
|
+
* number — a positive revalidation interval (enables ISR)
|
|
76
|
+
* 0 — treat as SSR (revalidate every request)
|
|
77
|
+
* false — fully static (no revalidation)
|
|
78
|
+
* Infinity — fully static (treated same as false by Next.js)
|
|
79
|
+
* null — no `revalidate` key found (fully static)
|
|
80
|
+
*/
|
|
81
|
+
export function extractGetStaticPropsRevalidate(code) {
|
|
82
|
+
// TODO: This regex matches `revalidate:` anywhere in the file, not scoped to
|
|
83
|
+
// the getStaticProps return object. A config object or comment elsewhere in
|
|
84
|
+
// the file (e.g. `const defaults = { revalidate: 30 }`) could produce a false
|
|
85
|
+
// positive. Rare in practice, but a proper AST-based approach would be more
|
|
86
|
+
// accurate.
|
|
87
|
+
const re = /\brevalidate\s*:\s*(-?\d+(?:\.\d+)?|Infinity|false)\b/;
|
|
88
|
+
const m = re.exec(code);
|
|
89
|
+
if (!m)
|
|
90
|
+
return null;
|
|
91
|
+
if (m[1] === "false")
|
|
92
|
+
return false;
|
|
93
|
+
if (m[1] === "Infinity")
|
|
94
|
+
return Infinity;
|
|
95
|
+
return parseFloat(m[1]);
|
|
96
|
+
}
|
|
97
|
+
// ─── Route classification ─────────────────────────────────────────────────────
|
|
98
|
+
/**
|
|
99
|
+
* Classifies a Pages Router page file by reading its source and examining
|
|
100
|
+
* which data-fetching exports it contains.
|
|
101
|
+
*
|
|
102
|
+
* API routes (files under pages/api/) are always `api`.
|
|
103
|
+
*/
|
|
104
|
+
export function classifyPagesRoute(filePath) {
|
|
105
|
+
// API routes are identified by their path
|
|
106
|
+
const normalized = filePath.replace(/\\/g, "/");
|
|
107
|
+
if (normalized.includes("/pages/api/")) {
|
|
108
|
+
return { type: "api" };
|
|
109
|
+
}
|
|
110
|
+
let code;
|
|
111
|
+
try {
|
|
112
|
+
code = fs.readFileSync(filePath, "utf8");
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return { type: "unknown" };
|
|
116
|
+
}
|
|
117
|
+
if (hasNamedExport(code, "getServerSideProps")) {
|
|
118
|
+
return { type: "ssr" };
|
|
119
|
+
}
|
|
120
|
+
if (hasNamedExport(code, "getStaticProps")) {
|
|
121
|
+
const revalidate = extractGetStaticPropsRevalidate(code);
|
|
122
|
+
if (revalidate === null || revalidate === false || revalidate === Infinity) {
|
|
123
|
+
return { type: "static" };
|
|
124
|
+
}
|
|
125
|
+
if (revalidate === 0) {
|
|
126
|
+
return { type: "ssr" };
|
|
127
|
+
}
|
|
128
|
+
// Positive number → ISR
|
|
129
|
+
return { type: "isr", revalidate };
|
|
130
|
+
}
|
|
131
|
+
return { type: "static" };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Classifies an App Router route.
|
|
135
|
+
*
|
|
136
|
+
* @param pagePath Absolute path to the page.tsx (null for API-only routes)
|
|
137
|
+
* @param routePath Absolute path to the route.ts handler (null for page routes)
|
|
138
|
+
* @param isDynamic Whether the URL pattern contains dynamic segments
|
|
139
|
+
*/
|
|
140
|
+
export function classifyAppRoute(pagePath, routePath, isDynamic) {
|
|
141
|
+
// Route handlers with no page component → API
|
|
142
|
+
if (routePath !== null && pagePath === null) {
|
|
143
|
+
return { type: "api" };
|
|
144
|
+
}
|
|
145
|
+
const filePath = pagePath ?? routePath;
|
|
146
|
+
if (!filePath)
|
|
147
|
+
return { type: "unknown" };
|
|
148
|
+
let code;
|
|
149
|
+
try {
|
|
150
|
+
code = fs.readFileSync(filePath, "utf8");
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return { type: "unknown" };
|
|
154
|
+
}
|
|
155
|
+
// Check `export const dynamic`
|
|
156
|
+
const dynamicValue = extractExportConstString(code, "dynamic");
|
|
157
|
+
if (dynamicValue === "force-dynamic") {
|
|
158
|
+
return { type: "ssr" };
|
|
159
|
+
}
|
|
160
|
+
if (dynamicValue === "force-static" || dynamicValue === "error") {
|
|
161
|
+
// "error" enforces static rendering — it throws if dynamic APIs are used,
|
|
162
|
+
// so the page is statically rendered (same as force-static for classification).
|
|
163
|
+
return { type: "static" };
|
|
164
|
+
}
|
|
165
|
+
// Check `export const revalidate`
|
|
166
|
+
const revalidateValue = extractExportConstNumber(code, "revalidate");
|
|
167
|
+
if (revalidateValue !== null) {
|
|
168
|
+
if (revalidateValue === Infinity)
|
|
169
|
+
return { type: "static" };
|
|
170
|
+
if (revalidateValue === 0)
|
|
171
|
+
return { type: "ssr" };
|
|
172
|
+
if (revalidateValue > 0)
|
|
173
|
+
return { type: "isr", revalidate: revalidateValue };
|
|
174
|
+
}
|
|
175
|
+
// Fall back to isDynamic flag (dynamic URL segments without explicit config)
|
|
176
|
+
if (isDynamic)
|
|
177
|
+
return { type: "ssr" };
|
|
178
|
+
// No explicit config and no dynamic URL segments — we can't confirm static
|
|
179
|
+
// without running the build (dynamic API calls like headers() are invisible
|
|
180
|
+
// to static analysis). Report as unknown rather than falsely claiming static.
|
|
181
|
+
return { type: "unknown" };
|
|
182
|
+
}
|
|
183
|
+
// ─── Row building ─────────────────────────────────────────────────────────────
|
|
184
|
+
/**
|
|
185
|
+
* Builds a sorted list of RouteRow objects from the discovered routes.
|
|
186
|
+
* Routes are sorted alphabetically by path, matching filesystem order.
|
|
187
|
+
*/
|
|
188
|
+
export function buildReportRows(options) {
|
|
189
|
+
const rows = [];
|
|
190
|
+
for (const route of options.pageRoutes ?? []) {
|
|
191
|
+
const { type, revalidate } = classifyPagesRoute(route.filePath);
|
|
192
|
+
rows.push({ pattern: route.pattern, type, revalidate });
|
|
193
|
+
}
|
|
194
|
+
for (const route of options.apiRoutes ?? []) {
|
|
195
|
+
rows.push({ pattern: route.pattern, type: "api" });
|
|
196
|
+
}
|
|
197
|
+
for (const route of options.appRoutes ?? []) {
|
|
198
|
+
const { type, revalidate } = classifyAppRoute(route.pagePath, route.routePath, route.isDynamic);
|
|
199
|
+
rows.push({ pattern: route.pattern, type, revalidate });
|
|
200
|
+
}
|
|
201
|
+
// Sort purely by path — mirrors filesystem order, matching Next.js output style
|
|
202
|
+
rows.sort((a, b) => a.pattern.localeCompare(b.pattern));
|
|
203
|
+
return rows;
|
|
204
|
+
}
|
|
205
|
+
// ─── Formatting ───────────────────────────────────────────────────────────────
|
|
206
|
+
const SYMBOLS = {
|
|
207
|
+
static: "○",
|
|
208
|
+
isr: "◐",
|
|
209
|
+
ssr: "ƒ",
|
|
210
|
+
unknown: "?",
|
|
211
|
+
api: "λ",
|
|
212
|
+
};
|
|
213
|
+
const LABELS = {
|
|
214
|
+
static: "Static",
|
|
215
|
+
isr: "ISR",
|
|
216
|
+
ssr: "Dynamic",
|
|
217
|
+
unknown: "Unknown",
|
|
218
|
+
api: "API",
|
|
219
|
+
};
|
|
220
|
+
/**
|
|
221
|
+
* Formats a list of RouteRows into a Next.js-style build report string.
|
|
222
|
+
*
|
|
223
|
+
* Example output:
|
|
224
|
+
* Route (pages)
|
|
225
|
+
* ┌ ○ /
|
|
226
|
+
* ├ ◐ /blog/:slug (60s)
|
|
227
|
+
* ├ ƒ /dashboard
|
|
228
|
+
* └ λ /api/posts
|
|
229
|
+
*
|
|
230
|
+
* ○ Static ◐ ISR ƒ Dynamic λ API
|
|
231
|
+
*/
|
|
232
|
+
export function formatBuildReport(rows, routerLabel = "app") {
|
|
233
|
+
if (rows.length === 0)
|
|
234
|
+
return "";
|
|
235
|
+
const lines = [];
|
|
236
|
+
lines.push(` Route (${routerLabel})`);
|
|
237
|
+
// Determine padding width from the longest pattern
|
|
238
|
+
const maxPatternLen = Math.max(...rows.map((r) => r.pattern.length));
|
|
239
|
+
rows.forEach((row, i) => {
|
|
240
|
+
const isLast = i === rows.length - 1;
|
|
241
|
+
const corner = i === 0 ? "┌" : isLast ? "└" : "├";
|
|
242
|
+
const sym = SYMBOLS[row.type];
|
|
243
|
+
const suffix = row.type === "isr" && row.revalidate !== undefined ? ` (${row.revalidate}s)` : "";
|
|
244
|
+
const padding = " ".repeat(maxPatternLen - row.pattern.length);
|
|
245
|
+
lines.push(` ${corner} ${sym} ${row.pattern}${padding}${suffix}`);
|
|
246
|
+
});
|
|
247
|
+
lines.push("");
|
|
248
|
+
// Legend — only include types that appear in this report, sorted alphabetically by label
|
|
249
|
+
const usedTypes = [...new Set(rows.map((r) => r.type))].sort((a, b) => LABELS[a].localeCompare(LABELS[b]));
|
|
250
|
+
lines.push(" " + usedTypes.map((t) => `${SYMBOLS[t]} ${LABELS[t]}`).join(" "));
|
|
251
|
+
// Explanatory note — only shown when unknown routes are present
|
|
252
|
+
if (usedTypes.includes("unknown")) {
|
|
253
|
+
lines.push("");
|
|
254
|
+
lines.push(" ? Some routes could not be classified. vinext currently uses static analysis");
|
|
255
|
+
lines.push(" and cannot detect dynamic API usage (headers(), cookies(), etc.) at build time.");
|
|
256
|
+
lines.push(" Automatic classification will be improved in a future release.");
|
|
257
|
+
}
|
|
258
|
+
return lines.join("\n");
|
|
259
|
+
}
|
|
260
|
+
// ─── Directory detection ──────────────────────────────────────────────────────
|
|
261
|
+
function findDir(root, ...candidates) {
|
|
262
|
+
for (const candidate of candidates) {
|
|
263
|
+
const full = path.join(root, candidate);
|
|
264
|
+
if (fs.existsSync(full) && fs.statSync(full).isDirectory())
|
|
265
|
+
return full;
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
// ─── Main entry point ─────────────────────────────────────────────────────────
|
|
270
|
+
/**
|
|
271
|
+
* Scans the project at `root`, classifies all routes, and prints the
|
|
272
|
+
* Next.js-style build report to stdout.
|
|
273
|
+
*
|
|
274
|
+
* Called at the end of `vinext build` in cli.ts.
|
|
275
|
+
*/
|
|
276
|
+
export async function printBuildReport(options) {
|
|
277
|
+
const { root } = options;
|
|
278
|
+
const appDir = findDir(root, "app", "src/app");
|
|
279
|
+
const pagesDir = findDir(root, "pages", "src/pages");
|
|
280
|
+
if (!appDir && !pagesDir)
|
|
281
|
+
return;
|
|
282
|
+
if (appDir) {
|
|
283
|
+
// Dynamic import to avoid loading routing code unless needed
|
|
284
|
+
const { appRouter } = await import("../routing/app-router.js");
|
|
285
|
+
const routes = await appRouter(appDir, options.pageExtensions);
|
|
286
|
+
const rows = buildReportRows({ appRoutes: routes });
|
|
287
|
+
if (rows.length > 0) {
|
|
288
|
+
console.log("\n" + formatBuildReport(rows, "app"));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (pagesDir) {
|
|
292
|
+
const { pagesRouter, apiRouter } = await import("../routing/pages-router.js");
|
|
293
|
+
const [pageRoutes, apiRoutes] = await Promise.all([
|
|
294
|
+
pagesRouter(pagesDir, options.pageExtensions),
|
|
295
|
+
apiRouter(pagesDir, options.pageExtensions),
|
|
296
|
+
]);
|
|
297
|
+
const rows = buildReportRows({ pageRoutes, apiRoutes });
|
|
298
|
+
if (rows.length > 0) {
|
|
299
|
+
console.log("\n" + formatBuildReport(rows, "pages"));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/build/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAe7B,gFAAgF;AAEhF;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,IAAY;IACvD,oDAAoD;IACpD,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,oDAAoD,IAAI,KAAK,CAAC,CAAC;IACvF,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEjC,2CAA2C;IAC3C,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,+CAA+C,IAAI,UAAU,CAAC,CAAC;IACxF,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,+DAA+D;IAC/D,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC,wBAAwB,IAAI,aAAa,CAAC,CAAC;IACnE,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEjC,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY,EAAE,IAAY;IACjE,MAAM,EAAE,GAAG,IAAI,MAAM,CACnB,mCAAmC,IAAI,0CAA0C,EACjF,GAAG,CACJ,CAAC;IACF,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAY,EAAE,IAAY;IACjE,MAAM,EAAE,GAAG,IAAI,MAAM,CACnB,mCAAmC,IAAI,uDAAuD,EAC9F,GAAG,CACJ,CAAC;IACF,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,+BAA+B,CAAC,IAAY;IAC1D,6EAA6E;IAC7E,4EAA4E;IAC5E,8EAA8E;IAC9E,4EAA4E;IAC5E,YAAY;IACZ,MAAM,EAAE,GAAG,uDAAuD,CAAC;IACnE,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,IAAI,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACpB,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACnC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,UAAU;QAAE,OAAO,QAAQ,CAAC;IACzC,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED,iFAAiF;AAEjF;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IAIjD,0CAA0C;IAC1C,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAChD,IAAI,UAAU,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;QACvC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,cAAc,CAAC,IAAI,EAAE,oBAAoB,CAAC,EAAE,CAAC;QAC/C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IAED,IAAI,cAAc,CAAC,IAAI,EAAE,gBAAgB,CAAC,EAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,+BAA+B,CAAC,IAAI,CAAC,CAAC;QAEzD,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,KAAK,KAAK,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;YAC3E,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC5B,CAAC;QACD,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;QACD,wBAAwB;QACxB,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IACrC,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;AAC5B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAAuB,EACvB,SAAwB,EACxB,SAAkB;IAElB,8CAA8C;IAC9C,IAAI,SAAS,KAAK,IAAI,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QAC5C,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,IAAI,SAAS,CAAC;IACvC,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAE1C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7B,CAAC;IAED,+BAA+B;IAC/B,MAAM,YAAY,GAAG,wBAAwB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC/D,IAAI,YAAY,KAAK,eAAe,EAAE,CAAC;QACrC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,YAAY,KAAK,cAAc,IAAI,YAAY,KAAK,OAAO,EAAE,CAAC;QAChE,0EAA0E;QAC1E,gFAAgF;QAChF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAC5B,CAAC;IAED,kCAAkC;IAClC,MAAM,eAAe,GAAG,wBAAwB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACrE,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;QAC7B,IAAI,eAAe,KAAK,QAAQ;YAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAC5D,IAAI,eAAe,KAAK,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAClD,IAAI,eAAe,GAAG,CAAC;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,CAAC;IAC/E,CAAC;IAED,6EAA6E;IAC7E,IAAI,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IAEtC,2EAA2E;IAC3E,4EAA4E;IAC5E,8EAA8E;IAC9E,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;AAC7B,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,OAI/B;IACC,MAAM,IAAI,GAAe,EAAE,CAAC;IAE5B,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;QAC7C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChE,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QAC5C,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;QAC5C,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,gBAAgB,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;QAChG,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,gFAAgF;IAChF,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAExD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iFAAiF;AAEjF,MAAM,OAAO,GAA8B;IACzC,MAAM,EAAE,GAAG;IACX,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,OAAO,EAAE,GAAG;IACZ,GAAG,EAAE,GAAG;CACT,CAAC;AAEF,MAAM,MAAM,GAA8B;IACxC,MAAM,EAAE,QAAQ;IAChB,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,SAAS;IACd,OAAO,EAAE,SAAS;IAClB,GAAG,EAAE,KAAK;CACX,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAgB,EAAE,WAAW,GAAG,KAAK;IACrE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,YAAY,WAAW,GAAG,CAAC,CAAC;IAEvC,mDAAmD;IACnD,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAErE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACtB,MAAM,MAAM,GAAG,CAAC,KAAK,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACrC,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;QAClD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC9B,MAAM,MAAM,GACV,GAAG,CAAC,IAAI,KAAK,KAAK,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACrF,MAAM,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,aAAa,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC/D,KAAK,CAAC,IAAI,CAAC,KAAK,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,GAAG,OAAO,GAAG,MAAM,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEf,yFAAyF;IACzF,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACpE,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CACnC,CAAC;IACF,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAEjF,gEAAgE;IAChE,IAAI,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAC;QAC7F,KAAK,CAAC,IAAI,CACR,qFAAqF,CACtF,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;IACnF,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,iFAAiF;AAEjF,SAAS,OAAO,CAAC,IAAY,EAAE,GAAG,UAAoB;IACpD,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACxC,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE;YAAE,OAAO,IAAI,CAAC;IAC1E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,iFAAiF;AAEjF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAGtC;IACC,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAEzB,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAErD,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ;QAAE,OAAO;IAEjC,IAAI,MAAM,EAAE,CAAC;QACX,6DAA6D;QAC7D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;QAC/D,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC;QAC/D,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;QACpD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,4BAA4B,CAAC,CAAC;QAC9E,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAChD,WAAW,CAAC,QAAQ,EAAE,OAAO,CAAC,cAAc,CAAC;YAC7C,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,cAAc,CAAC;SAC5C,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,eAAe,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;QACxD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;AACH,CAAC","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\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport type RouteType = \"static\" | \"isr\" | \"ssr\" | \"unknown\" | \"api\";\n\nexport interface RouteRow {\n pattern: string;\n type: RouteType;\n /** Only set for `isr` routes. */\n revalidate?: number;\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 `(?:^|\\\\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 `(?:^|\\\\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 // TODO: This regex matches `revalidate:` anywhere in the file, not scoped to\n // the getStaticProps return object. A config object or comment elsewhere in\n // the file (e.g. `const defaults = { revalidate: 30 }`) could produce a false\n // positive. Rare in practice, but a proper AST-based approach would be more\n // accurate.\n const re = /\\brevalidate\\s*:\\s*(-?\\d+(?:\\.\\d+)?|Infinity|false)\\b/;\n const m = re.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\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 */\nexport function buildReportRows(options: {\n pageRoutes?: Route[];\n apiRoutes?: Route[];\n appRoutes?: AppRoute[];\n}): RouteRow[] {\n const rows: RouteRow[] = [];\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 rows.push({ pattern: route.pattern, type, revalidate });\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 = 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 return lines.join(\"\\n\");\n}\n\n// ─── Directory detection ──────────────────────────────────────────────────────\n\nfunction findDir(root: string, ...candidates: string[]): string | null {\n for (const candidate of candidates) {\n const full = path.join(root, candidate);\n if (fs.existsSync(full) && fs.statSync(full).isDirectory()) return full;\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}): 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 });\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({ pageRoutes, apiRoutes });\n if (rows.length > 0) {\n console.log(\"\\n\" + formatBuildReport(rows, \"pages\"));\n }\n }\n}\n"]}
|
package/dist/check.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,KAAK,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,aAAa,CAAC;AAEtD,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,KAAK,MAAM,GAAG,WAAW,GAAG,SAAS,GAAG,aAAa,CAAC;AAEtD,UAAU,SAAS;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,SAAS,EAAE,SAAS,EAAE,CAAC;IACvB,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AA0JD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAkErD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAsFvD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAyBxD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CA0K1D;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAqBlD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAyH7F"}
|
package/dist/check.js
CHANGED
|
@@ -51,7 +51,7 @@ const CONFIG_SUPPORT = {
|
|
|
51
51
|
redirects: { status: "supported" },
|
|
52
52
|
rewrites: { status: "supported" },
|
|
53
53
|
headers: { status: "supported" },
|
|
54
|
-
i18n: { status: "supported", detail: "path-prefix routing
|
|
54
|
+
i18n: { status: "supported", detail: "path-prefix routing; domain routing for Pages Router" },
|
|
55
55
|
env: { status: "supported" },
|
|
56
56
|
images: { status: "partial", detail: "remotePatterns validated, no local optimization" },
|
|
57
57
|
allowedDevOrigins: { status: "supported", detail: "dev server cross-origin allowlist" },
|
|
@@ -67,7 +67,10 @@ const CONFIG_SUPPORT = {
|
|
|
67
67
|
status: "supported",
|
|
68
68
|
detail: "server actions via 'use server' directive",
|
|
69
69
|
},
|
|
70
|
-
"i18n.domains": {
|
|
70
|
+
"i18n.domains": {
|
|
71
|
+
status: "partial",
|
|
72
|
+
detail: "supported for Pages Router; App Router unchanged",
|
|
73
|
+
},
|
|
71
74
|
reactStrictMode: { status: "supported", detail: "always enabled" },
|
|
72
75
|
poweredByHeader: {
|
|
73
76
|
status: "supported",
|
|
@@ -171,15 +174,16 @@ export function scanImports(root) {
|
|
|
171
174
|
if (!importUsage.has(normalized))
|
|
172
175
|
importUsage.set(normalized, []);
|
|
173
176
|
const relFile = path.relative(root, file);
|
|
174
|
-
|
|
175
|
-
|
|
177
|
+
const usedInFiles = importUsage.get(normalized) ?? [];
|
|
178
|
+
if (!usedInFiles.includes(relFile)) {
|
|
179
|
+
usedInFiles.push(relFile);
|
|
176
180
|
}
|
|
177
181
|
}
|
|
178
182
|
}
|
|
179
183
|
}
|
|
180
184
|
const items = [];
|
|
181
185
|
for (const [mod, usedFiles] of importUsage) {
|
|
182
|
-
const support = IMPORT_SUPPORT[mod];
|
|
186
|
+
const support = IMPORT_SUPPORT[mod.startsWith("next/") && mod.endsWith(".js") ? mod.replace(/\.js$/, "") : mod];
|
|
183
187
|
if (support) {
|
|
184
188
|
items.push({
|
|
185
189
|
name: mod,
|
|
@@ -334,7 +338,7 @@ export function checkConventions(root) {
|
|
|
334
338
|
const hasProxy = fs.existsSync(path.join(root, "proxy.ts")) || fs.existsSync(path.join(root, "proxy.js"));
|
|
335
339
|
const hasMiddleware = fs.existsSync(path.join(root, "middleware.ts")) ||
|
|
336
340
|
fs.existsSync(path.join(root, "middleware.js"));
|
|
337
|
-
if (
|
|
341
|
+
if (pagesDir !== null) {
|
|
338
342
|
const isSrc = pagesDir.includes(path.join("src", "pages"));
|
|
339
343
|
items.push({
|
|
340
344
|
name: isSrc ? "Pages Router (src/pages/)" : "Pages Router (pages/)",
|
|
@@ -359,7 +363,7 @@ export function checkConventions(root) {
|
|
|
359
363
|
items.push({ name: "Custom _document", status: "supported" });
|
|
360
364
|
}
|
|
361
365
|
}
|
|
362
|
-
if (
|
|
366
|
+
if (appDirPath !== null) {
|
|
363
367
|
const isSrc = appDirPath.includes(path.join("src", "app"));
|
|
364
368
|
items.push({
|
|
365
369
|
name: isSrc ? "App Router (src/app/)" : "App Router (app/)",
|