vinext 0.0.53 → 0.0.54
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/inline-css.d.ts +7 -0
- package/dist/build/inline-css.js +50 -0
- package/dist/build/inline-css.js.map +1 -0
- package/dist/build/prerender.js +2 -1
- package/dist/build/prerender.js.map +1 -1
- package/dist/check.js +4 -0
- package/dist/check.js.map +1 -1
- package/dist/client/navigation-runtime.d.ts +2 -1
- package/dist/client/navigation-runtime.js.map +1 -1
- package/dist/client/window-next.d.ts +7 -0
- package/dist/client/window-next.js.map +1 -1
- package/dist/config/next-config.d.ts +83 -1
- package/dist/config/next-config.js +131 -2
- package/dist/config/next-config.js.map +1 -1
- package/dist/deploy.js +13 -0
- package/dist/deploy.js.map +1 -1
- package/dist/entries/app-browser-entry.d.ts +11 -1
- package/dist/entries/app-browser-entry.js +16 -6
- package/dist/entries/app-browser-entry.js.map +1 -1
- package/dist/entries/app-rsc-entry.d.ts +8 -1
- package/dist/entries/app-rsc-entry.js +18 -5
- package/dist/entries/app-rsc-entry.js.map +1 -1
- package/dist/entries/app-rsc-manifest.d.ts +21 -1
- package/dist/entries/app-rsc-manifest.js +6 -4
- package/dist/entries/app-rsc-manifest.js.map +1 -1
- package/dist/entries/pages-client-entry.d.ts +4 -1
- package/dist/entries/pages-client-entry.js +18 -2
- package/dist/entries/pages-client-entry.js.map +1 -1
- package/dist/entries/pages-server-entry.js +82 -4
- package/dist/entries/pages-server-entry.js.map +1 -1
- package/dist/entries/runtime-entry-module.d.ts +1 -10
- package/dist/entries/runtime-entry-module.js +2 -12
- package/dist/entries/runtime-entry-module.js.map +1 -1
- package/dist/index.js +63 -5
- package/dist/index.js.map +1 -1
- package/dist/plugins/remove-console.d.ts +16 -0
- package/dist/plugins/remove-console.js +176 -0
- package/dist/plugins/remove-console.js.map +1 -0
- package/dist/routing/app-route-graph.d.ts +24 -1
- package/dist/routing/app-route-graph.js +52 -4
- package/dist/routing/app-route-graph.js.map +1 -1
- package/dist/routing/app-router.d.ts +2 -2
- package/dist/routing/app-router.js +2 -2
- package/dist/routing/app-router.js.map +1 -1
- package/dist/routing/file-matcher.d.ts +21 -1
- package/dist/routing/file-matcher.js +39 -1
- package/dist/routing/file-matcher.js.map +1 -1
- package/dist/routing/pages-router.d.ts +1 -1
- package/dist/routing/pages-router.js +10 -3
- package/dist/routing/pages-router.js.map +1 -1
- package/dist/server/api-handler.js +1 -1
- package/dist/server/app-browser-entry.js +25 -16
- package/dist/server/app-browser-entry.js.map +1 -1
- package/dist/server/app-browser-navigation-controller.d.ts +2 -0
- package/dist/server/app-browser-navigation-controller.js +4 -0
- package/dist/server/app-browser-navigation-controller.js.map +1 -1
- package/dist/server/app-elements-wire.d.ts +13 -4
- package/dist/server/app-elements-wire.js +10 -1
- package/dist/server/app-elements-wire.js.map +1 -1
- package/dist/server/app-elements.d.ts +2 -2
- package/dist/server/app-elements.js +2 -2
- package/dist/server/app-elements.js.map +1 -1
- package/dist/server/app-fallback-renderer.d.ts +15 -5
- package/dist/server/app-fallback-renderer.js +10 -4
- package/dist/server/app-fallback-renderer.js.map +1 -1
- package/dist/server/app-inline-css-client.d.ts +7 -0
- package/dist/server/app-inline-css-client.js +37 -0
- package/dist/server/app-inline-css-client.js.map +1 -0
- package/dist/server/app-page-boundary.d.ts +21 -1
- package/dist/server/app-page-boundary.js +28 -3
- package/dist/server/app-page-boundary.js.map +1 -1
- package/dist/server/app-page-cache.d.ts +7 -3
- package/dist/server/app-page-cache.js +7 -7
- package/dist/server/app-page-cache.js.map +1 -1
- package/dist/server/app-page-dispatch.d.ts +10 -1
- package/dist/server/app-page-dispatch.js +126 -79
- package/dist/server/app-page-dispatch.js.map +1 -1
- package/dist/server/app-page-element-builder.js +12 -28
- package/dist/server/app-page-element-builder.js.map +1 -1
- package/dist/server/app-page-render-identity.d.ts +22 -0
- package/dist/server/app-page-render-identity.js +42 -0
- package/dist/server/app-page-render-identity.js.map +1 -0
- package/dist/server/app-page-render.d.ts +8 -1
- package/dist/server/app-page-render.js +4 -1
- package/dist/server/app-page-render.js.map +1 -1
- package/dist/server/app-page-request.d.ts +6 -3
- package/dist/server/app-page-request.js +5 -2
- package/dist/server/app-page-request.js.map +1 -1
- package/dist/server/app-page-response.js +2 -2
- package/dist/server/app-page-response.js.map +1 -1
- package/dist/server/app-page-route-wiring.d.ts +15 -0
- package/dist/server/app-page-route-wiring.js +7 -5
- package/dist/server/app-page-route-wiring.js.map +1 -1
- package/dist/server/app-page-stream.d.ts +11 -0
- package/dist/server/app-page-stream.js +1 -0
- package/dist/server/app-page-stream.js.map +1 -1
- package/dist/server/app-route-handler-response.js +37 -5
- package/dist/server/app-route-handler-response.js.map +1 -1
- package/dist/server/app-rsc-handler.d.ts +14 -3
- package/dist/server/app-rsc-handler.js +45 -5
- package/dist/server/app-rsc-handler.js.map +1 -1
- package/dist/server/app-rsc-request-normalization.d.ts +2 -1
- package/dist/server/app-rsc-request-normalization.js +3 -2
- package/dist/server/app-rsc-request-normalization.js.map +1 -1
- package/dist/server/app-server-action-execution.d.ts +21 -3
- package/dist/server/app-server-action-execution.js +42 -7
- package/dist/server/app-server-action-execution.js.map +1 -1
- package/dist/server/app-ssr-entry.d.ts +6 -0
- package/dist/server/app-ssr-entry.js +22 -7
- package/dist/server/app-ssr-entry.js.map +1 -1
- package/dist/server/app-ssr-error-meta.js +3 -3
- package/dist/server/app-ssr-error-meta.js.map +1 -1
- package/dist/server/app-ssr-stream.d.ts +2 -1
- package/dist/server/app-ssr-stream.js +176 -31
- package/dist/server/app-ssr-stream.js.map +1 -1
- package/dist/server/client-trace-metadata.d.ts +31 -0
- package/dist/server/client-trace-metadata.js +83 -0
- package/dist/server/client-trace-metadata.js.map +1 -0
- package/dist/server/cookie-utils.d.ts +13 -0
- package/dist/server/cookie-utils.js +20 -0
- package/dist/server/cookie-utils.js.map +1 -0
- package/dist/server/dev-server.d.ts +8 -1
- package/dist/server/dev-server.js +34 -5
- package/dist/server/dev-server.js.map +1 -1
- package/dist/server/html.d.ts +2 -1
- package/dist/server/html.js +6 -1
- package/dist/server/html.js.map +1 -1
- package/dist/server/isr-cache.d.ts +7 -5
- package/dist/server/isr-cache.js +17 -6
- package/dist/server/isr-cache.js.map +1 -1
- package/dist/server/middleware-runtime.js +1 -2
- package/dist/server/middleware-runtime.js.map +1 -1
- package/dist/server/pages-document-initial-props.d.ts +7 -0
- package/dist/server/pages-document-initial-props.js +14 -0
- package/dist/server/pages-document-initial-props.js.map +1 -0
- package/dist/server/pages-page-data.js +3 -0
- package/dist/server/pages-page-data.js.map +1 -1
- package/dist/server/pages-page-method.d.ts +48 -0
- package/dist/server/pages-page-method.js +19 -0
- package/dist/server/pages-page-method.js.map +1 -0
- package/dist/server/pages-page-response.d.ts +6 -0
- package/dist/server/pages-page-response.js +10 -3
- package/dist/server/pages-page-response.js.map +1 -1
- package/dist/server/pages-serializable-props.d.ts +25 -0
- package/dist/server/pages-serializable-props.js +69 -0
- package/dist/server/pages-serializable-props.js.map +1 -0
- package/dist/server/prod-server.js +3 -0
- package/dist/server/prod-server.js.map +1 -1
- package/dist/server/server-action-not-found.js +3 -2
- package/dist/server/server-action-not-found.js.map +1 -1
- package/dist/server/static-file-cache.js +2 -1
- package/dist/server/static-file-cache.js.map +1 -1
- package/dist/shims/app-router-scroll-state.d.ts +4 -2
- package/dist/shims/app-router-scroll-state.js +16 -3
- package/dist/shims/app-router-scroll-state.js.map +1 -1
- package/dist/shims/app-router-scroll.d.ts +16 -2
- package/dist/shims/app-router-scroll.js +18 -3
- package/dist/shims/app-router-scroll.js.map +1 -1
- package/dist/shims/cache.d.ts +6 -0
- package/dist/shims/cache.js +7 -0
- package/dist/shims/cache.js.map +1 -1
- package/dist/shims/error.js +3 -0
- package/dist/shims/error.js.map +1 -1
- package/dist/shims/headers.d.ts +7 -0
- package/dist/shims/headers.js +9 -1
- package/dist/shims/headers.js.map +1 -1
- package/dist/shims/internal/app-route-detection.d.ts +37 -0
- package/dist/shims/internal/app-route-detection.js +69 -0
- package/dist/shims/internal/app-route-detection.js.map +1 -0
- package/dist/shims/link.d.ts +18 -2
- package/dist/shims/link.js +70 -6
- package/dist/shims/link.js.map +1 -1
- package/dist/shims/metadata.d.ts +7 -6
- package/dist/shims/metadata.js +9 -5
- package/dist/shims/metadata.js.map +1 -1
- package/dist/shims/navigation.d.ts +1 -2
- package/dist/shims/navigation.js +63 -12
- package/dist/shims/navigation.js.map +1 -1
- package/dist/shims/router.d.ts +5 -0
- package/dist/shims/router.js +14 -4
- package/dist/shims/router.js.map +1 -1
- package/dist/shims/script.d.ts +11 -1
- package/dist/shims/script.js +75 -6
- package/dist/shims/script.js.map +1 -1
- package/dist/utils/path.d.ts +13 -0
- package/dist/utils/path.js +16 -0
- package/dist/utils/path.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/plugins/remove-console.d.ts
|
|
2
|
+
type RemoveConsoleConfig = boolean | {
|
|
3
|
+
exclude: string[];
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* Walk the AST body looking for expression statements whose expression is a
|
|
7
|
+
* CallExpression with a callee of `console.<identifier>`. When found, check
|
|
8
|
+
* that the name is not in the excluded set and that `console` is not shadowed
|
|
9
|
+
* at this scope. If all conditions pass, replace the entire statement with `;`.
|
|
10
|
+
*
|
|
11
|
+
* Returns `null` if no console calls are removed.
|
|
12
|
+
*/
|
|
13
|
+
declare function removeConsoleCalls(code: string, config: RemoveConsoleConfig): string | null;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { removeConsoleCalls };
|
|
16
|
+
//# sourceMappingURL=remove-console.d.ts.map
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { parseAst } from "vite";
|
|
2
|
+
import MagicString from "magic-string";
|
|
3
|
+
//#region src/plugins/remove-console.ts
|
|
4
|
+
/**
|
|
5
|
+
* Strip `console.*` calls from client bundle code.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors Next.js's SWC `remove_console` transform:
|
|
8
|
+
* - Strips all `console.<method>()` calls regardless of context (top-level,
|
|
9
|
+
* JSX expressions, function arguments, return values, ternary branches)
|
|
10
|
+
* - Replaces removed calls with `void 0` to keep the AST valid in every
|
|
11
|
+
* position a CallExpression can appear
|
|
12
|
+
* - Respects `exclude: ["error"]` to preserve certain methods (case-insensitive)
|
|
13
|
+
* - Preserves calls when `console` is shadowed (local variable, function
|
|
14
|
+
* parameter, or destructured binding)
|
|
15
|
+
* - Preserves computed property access `console[prop]()`
|
|
16
|
+
*
|
|
17
|
+
* Uses Vite's `parseAst` (OXC/acorn) for parsing and `MagicString` for
|
|
18
|
+
* surgical source replacement. Returns `null` when no changes are made.
|
|
19
|
+
*/
|
|
20
|
+
const SCOPE_ENTERING_TYPES = new Set([
|
|
21
|
+
"FunctionDeclaration",
|
|
22
|
+
"FunctionExpression",
|
|
23
|
+
"ArrowFunctionExpression"
|
|
24
|
+
]);
|
|
25
|
+
/**
|
|
26
|
+
* Walk the AST body looking for expression statements whose expression is a
|
|
27
|
+
* CallExpression with a callee of `console.<identifier>`. When found, check
|
|
28
|
+
* that the name is not in the excluded set and that `console` is not shadowed
|
|
29
|
+
* at this scope. If all conditions pass, replace the entire statement with `;`.
|
|
30
|
+
*
|
|
31
|
+
* Returns `null` if no console calls are removed.
|
|
32
|
+
*/
|
|
33
|
+
function removeConsoleCalls(code, config) {
|
|
34
|
+
if (config === false) return null;
|
|
35
|
+
const excluded = typeof config === "object" ? new Set(config.exclude.map((s) => s.toLowerCase())) : /* @__PURE__ */ new Set();
|
|
36
|
+
if (!code.match(/\bconsole\b/)) return null;
|
|
37
|
+
let ast;
|
|
38
|
+
try {
|
|
39
|
+
ast = parseAst(code);
|
|
40
|
+
} catch {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const scopeStack = [{ shadowed: false }];
|
|
44
|
+
function currentScope() {
|
|
45
|
+
return scopeStack[scopeStack.length - 1];
|
|
46
|
+
}
|
|
47
|
+
function pushScope() {
|
|
48
|
+
scopeStack.push({ shadowed: currentScope().shadowed });
|
|
49
|
+
}
|
|
50
|
+
function popScope() {
|
|
51
|
+
scopeStack.pop();
|
|
52
|
+
}
|
|
53
|
+
const s = new MagicString(code);
|
|
54
|
+
let changed = false;
|
|
55
|
+
/**
|
|
56
|
+
* Check if a node introduces a binding named "console" and mark scope.
|
|
57
|
+
* Recurses into all binding-pattern node types (destructuring shapes,
|
|
58
|
+
* defaults, rest elements).
|
|
59
|
+
*/
|
|
60
|
+
function checkBinding(node) {
|
|
61
|
+
if (!node) return;
|
|
62
|
+
switch (node.type) {
|
|
63
|
+
case "Identifier":
|
|
64
|
+
if (node.name === "console") currentScope().shadowed = true;
|
|
65
|
+
break;
|
|
66
|
+
case "ObjectPattern":
|
|
67
|
+
for (const prop of node.properties) checkBinding(prop);
|
|
68
|
+
break;
|
|
69
|
+
case "Property": {
|
|
70
|
+
const propertyNode = node;
|
|
71
|
+
if (propertyNode.value) checkBinding(propertyNode.value);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case "ArrayPattern": {
|
|
75
|
+
const elements = node.elements;
|
|
76
|
+
if (elements) for (const el of elements) checkBinding(el);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
case "AssignmentPattern": {
|
|
80
|
+
const left = node.left;
|
|
81
|
+
checkBinding(left);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
case "RestElement": {
|
|
85
|
+
const argument = node.argument;
|
|
86
|
+
checkBinding(argument);
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
default: break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Check if an identifier refers to the *global* console.
|
|
94
|
+
* It's global only when:
|
|
95
|
+
* 1. Its name is "console"
|
|
96
|
+
* 2. No local binding of that name shadows it at this point
|
|
97
|
+
*/
|
|
98
|
+
function isGlobalConsole(node) {
|
|
99
|
+
return node.type === "Identifier" && node.name === "console" && !currentScope().shadowed;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Determine if a call expression is a `console.<method>()` that should be
|
|
103
|
+
* removed. The callee must be a MemberExpression with:
|
|
104
|
+
* - object: Identifier "console" (global, not shadowed)
|
|
105
|
+
* - property: Identifier (NOT computed — computed access like
|
|
106
|
+
* `console[prop]()` is preserved per Next.js behavior)
|
|
107
|
+
* The method name must NOT be in the excluded set.
|
|
108
|
+
*/
|
|
109
|
+
function shouldRemove(node) {
|
|
110
|
+
if (node.type !== "CallExpression") return false;
|
|
111
|
+
const callee = node.callee;
|
|
112
|
+
if (callee.type !== "MemberExpression") return false;
|
|
113
|
+
if (callee.computed) return false;
|
|
114
|
+
if (!isGlobalConsole(callee.object)) return false;
|
|
115
|
+
const prop = callee.property;
|
|
116
|
+
if (prop.type !== "Identifier") return false;
|
|
117
|
+
const method = prop.name.toLowerCase();
|
|
118
|
+
if (excluded.has(method)) return false;
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Recursively walk a node tree, managing scope for shadow detection.
|
|
123
|
+
* When a CallExpression matches `console.<method>()`, replace it with
|
|
124
|
+
* `void 0`. If the call is the sole expression of an ExpressionStatement,
|
|
125
|
+
* replace the entire statement with `;` for cleaner output.
|
|
126
|
+
*/
|
|
127
|
+
function walk(node, parent) {
|
|
128
|
+
if (!node) return;
|
|
129
|
+
if (node.type === "CallExpression" && shouldRemove(node)) {
|
|
130
|
+
if (parent?.type === "ExpressionStatement") s.overwrite(parent.start, parent.end, ";");
|
|
131
|
+
else s.overwrite(node.start, node.end, "void 0");
|
|
132
|
+
changed = true;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
if (node.type === "FunctionDeclaration" || node.type === "ClassDeclaration") {
|
|
136
|
+
const id = node.id;
|
|
137
|
+
checkBinding(id);
|
|
138
|
+
}
|
|
139
|
+
const isScopeEntering = SCOPE_ENTERING_TYPES.has(node.type);
|
|
140
|
+
if (isScopeEntering) {
|
|
141
|
+
pushScope();
|
|
142
|
+
if (node.type === "FunctionExpression") {
|
|
143
|
+
const id = node.id;
|
|
144
|
+
checkBinding(id);
|
|
145
|
+
}
|
|
146
|
+
const params = node.params;
|
|
147
|
+
if (params) for (const param of params) checkBinding(param);
|
|
148
|
+
}
|
|
149
|
+
const isCatchScope = node.type === "CatchClause";
|
|
150
|
+
if (isCatchScope) {
|
|
151
|
+
pushScope();
|
|
152
|
+
const param = node.param;
|
|
153
|
+
if (param) checkBinding(param);
|
|
154
|
+
}
|
|
155
|
+
const isBlockScope = node.type === "BlockStatement" || node.type === "Program" || node.type === "SwitchCase";
|
|
156
|
+
if (isBlockScope && !isScopeEntering) pushScope();
|
|
157
|
+
if (node.type === "VariableDeclaration") for (const decl of node.declarations ?? []) checkBinding(decl.id);
|
|
158
|
+
for (const key of Object.keys(node)) {
|
|
159
|
+
if (key === "parent" || key === "start" || key === "end") continue;
|
|
160
|
+
const child = node[key];
|
|
161
|
+
if (child && typeof child === "object") {
|
|
162
|
+
if (Array.isArray(child)) {
|
|
163
|
+
for (const item of child) if (item && typeof item === "object" && "type" in item) walk(item, node);
|
|
164
|
+
} else if ("type" in child) walk(child, node);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (isScopeEntering || isBlockScope || isCatchScope) popScope();
|
|
168
|
+
}
|
|
169
|
+
for (const node of ast.body) walk(node);
|
|
170
|
+
if (!changed) return null;
|
|
171
|
+
return s.toString();
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
export { removeConsoleCalls };
|
|
175
|
+
|
|
176
|
+
//# sourceMappingURL=remove-console.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-console.js","names":[],"sources":["../../src/plugins/remove-console.ts"],"sourcesContent":["/**\n * Strip `console.*` calls from client bundle code.\n *\n * Mirrors Next.js's SWC `remove_console` transform:\n * - Strips all `console.<method>()` calls regardless of context (top-level,\n * JSX expressions, function arguments, return values, ternary branches)\n * - Replaces removed calls with `void 0` to keep the AST valid in every\n * position a CallExpression can appear\n * - Respects `exclude: [\"error\"]` to preserve certain methods (case-insensitive)\n * - Preserves calls when `console` is shadowed (local variable, function\n * parameter, or destructured binding)\n * - Preserves computed property access `console[prop]()`\n *\n * Uses Vite's `parseAst` (OXC/acorn) for parsing and `MagicString` for\n * surgical source replacement. Returns `null` when no changes are made.\n */\nimport { parseAst } from \"vite\";\nimport MagicString from \"magic-string\";\n\ntype ASTNode = ReturnType<typeof parseAst>[\"body\"][number][\"parent\"];\ntype BindingNode = Extract<ASTNode, { type: string }>;\n\ntype RemoveConsoleConfig = boolean | { exclude: string[] };\n\n// Node types that introduce a new function-style scope. Hoisted to a module-\n// level Set so the membership check in walk() is O(1) and doesn't allocate\n// per recursive call.\nconst SCOPE_ENTERING_TYPES = new Set([\n \"FunctionDeclaration\",\n \"FunctionExpression\",\n \"ArrowFunctionExpression\",\n]);\n\n/**\n * Walk the AST body looking for expression statements whose expression is a\n * CallExpression with a callee of `console.<identifier>`. When found, check\n * that the name is not in the excluded set and that `console` is not shadowed\n * at this scope. If all conditions pass, replace the entire statement with `;`.\n *\n * Returns `null` if no console calls are removed.\n */\nexport function removeConsoleCalls(code: string, config: RemoveConsoleConfig): string | null {\n if (config === false) return null;\n\n const excluded =\n typeof config === \"object\"\n ? new Set(config.exclude.map((s) => s.toLowerCase()))\n : new Set<string>();\n\n // Fast path: if there's no bare \"console\" reference, skip parsing.\n // This avoids the parse cost for the vast majority of modules.\n const consoleMatch = code.match(/\\bconsole\\b/);\n if (!consoleMatch) return null;\n\n let ast: ReturnType<typeof parseAst>;\n try {\n ast = parseAst(code);\n } catch {\n // If parsing fails (shouldn't happen post-transform), bail out\n return null;\n }\n\n // Collect shadowing scopes: tracks whether there's a local binding named\n // \"console\" in the current or any parent scope. We do a simple top-down\n // walk maintaining a stack of scope frames. Each function/arrow/block\n // introduces a new frame. When we see a declaration/parameter of name\n // \"console\", that frame (and its descendants) are shadowed.\n type Scope = { shadowed: boolean };\n const scopeStack: Scope[] = [{ shadowed: false }];\n\n function currentScope(): Scope {\n return scopeStack[scopeStack.length - 1]!;\n }\n\n function pushScope(): void {\n // Child inherits parent shadowed status\n scopeStack.push({ shadowed: currentScope().shadowed });\n }\n\n function popScope(): void {\n scopeStack.pop();\n }\n\n const s = new MagicString(code);\n let changed = false;\n\n /**\n * Check if a node introduces a binding named \"console\" and mark scope.\n * Recurses into all binding-pattern node types (destructuring shapes,\n * defaults, rest elements).\n */\n function checkBinding(node: BindingNode | null | undefined): void {\n if (!node) return;\n // oxlint-disable-next-line typescript/switch-exhaustiveness-check\n switch (node.type) {\n case \"Identifier\": {\n if (node.name === \"console\") {\n currentScope().shadowed = true;\n }\n break;\n }\n case \"ObjectPattern\": {\n for (const prop of node.properties) {\n checkBinding(prop as BindingNode);\n }\n break;\n }\n case \"Property\": {\n // For `{ key: value }` and `{ console }` (shorthand) — the binding name\n // is in `value`, not `key`. Recurse so AssignmentPattern defaults,\n // nested patterns, etc. are all handled.\n const propertyNode = node as unknown as { value?: BindingNode };\n if (propertyNode.value) checkBinding(propertyNode.value);\n break;\n }\n case \"ArrayPattern\": {\n // oxlint-disable-next-line typescript/no-explicit-any\n const elements = (node as any).elements as Array<BindingNode | null> | undefined;\n if (elements) {\n for (const el of elements) {\n checkBinding(el);\n }\n }\n break;\n }\n case \"AssignmentPattern\": {\n // `x = default` — the binding is `left`, the default value is `right`.\n // oxlint-disable-next-line typescript/no-explicit-any\n const left = (node as any).left as BindingNode | undefined;\n checkBinding(left);\n break;\n }\n case \"RestElement\": {\n // `...x` — the binding is `argument`.\n // oxlint-disable-next-line typescript/no-explicit-any\n const argument = (node as any).argument as BindingNode | undefined;\n checkBinding(argument);\n break;\n }\n default:\n break;\n }\n }\n\n /**\n * Check if an identifier refers to the *global* console.\n * It's global only when:\n * 1. Its name is \"console\"\n * 2. No local binding of that name shadows it at this point\n */\n function isGlobalConsole(node: BindingNode): boolean {\n return node.type === \"Identifier\" && node.name === \"console\" && !currentScope().shadowed;\n }\n\n /**\n * Determine if a call expression is a `console.<method>()` that should be\n * removed. The callee must be a MemberExpression with:\n * - object: Identifier \"console\" (global, not shadowed)\n * - property: Identifier (NOT computed — computed access like\n * `console[prop]()` is preserved per Next.js behavior)\n * The method name must NOT be in the excluded set.\n */\n function shouldRemove(node: BindingNode): boolean {\n if (node.type !== \"CallExpression\") return false;\n const callee = node.callee;\n if (callee.type !== \"MemberExpression\") return false;\n\n // Only handle dot access: console.log() — skip computed: console[prop]()\n if (callee.computed) return false;\n\n // The object must be the global console identifier\n if (!isGlobalConsole(callee.object)) return false;\n\n // Property must be an identifier (e.g., \"log\", \"warn\")\n const prop = callee.property;\n if (prop.type !== \"Identifier\") return false;\n\n const method = prop.name.toLowerCase();\n if (excluded.has(method)) return false;\n\n return true;\n }\n\n /**\n * Recursively walk a node tree, managing scope for shadow detection.\n * When a CallExpression matches `console.<method>()`, replace it with\n * `void 0`. If the call is the sole expression of an ExpressionStatement,\n * replace the entire statement with `;` for cleaner output.\n */\n function walk(node: ASTNode, parent?: ASTNode): void {\n if (!node) return;\n\n if (node.type === \"CallExpression\" && shouldRemove(node)) {\n if (parent?.type === \"ExpressionStatement\") {\n // Replace the whole statement so we don't leave `void 0;` litter\n s.overwrite(parent.start, parent.end, \";\");\n } else {\n s.overwrite(node.start, node.end, \"void 0\");\n }\n changed = true;\n return; // don't recurse into children of a removed call\n }\n\n // `function console() {}` and `class console {}` bind `console` in the\n // *enclosing* scope (function declarations are hoisted to function/module\n // scope, class declarations are block-scoped). Check `id` against the\n // current scope BEFORE pushing the function's own scope, so the binding\n // is visible both outside and inside the function (via scope inheritance).\n if (node.type === \"FunctionDeclaration\" || node.type === \"ClassDeclaration\") {\n // oxlint-disable-next-line typescript/no-explicit-any\n const id = (node as any).id as BindingNode | undefined;\n checkBinding(id);\n }\n\n const isScopeEntering = SCOPE_ENTERING_TYPES.has(node.type);\n if (isScopeEntering) {\n pushScope();\n\n // Named FunctionExpressions (`const x = function console() {}`) bind\n // their name only in their *own* scope — not the enclosing one — so\n // mark after pushing.\n if (node.type === \"FunctionExpression\") {\n // oxlint-disable-next-line typescript/no-explicit-any\n const id = (node as any).id as BindingNode | undefined;\n checkBinding(id);\n }\n\n // Mark params/destructured params\n // oxlint-disable-next-line typescript/no-explicit-any\n const params = (node as any).params as ASTNode[] | undefined;\n if (params) {\n for (const param of params) {\n checkBinding(param as BindingNode);\n }\n }\n }\n\n // CatchClause introduces a binding for its param (`catch (e) { ... }`).\n // If the param shadows \"console\", the catch block must treat console as\n // local. We push a scope just for the param binding; the BlockStatement\n // body below will push its own scope on top, which inherits the shadow.\n const isCatchScope = node.type === \"CatchClause\";\n if (isCatchScope) {\n pushScope();\n // oxlint-disable-next-line typescript/no-explicit-any\n const param = (node as any).param as BindingNode | undefined;\n if (param) {\n checkBinding(param);\n }\n }\n\n // Also enter a new scope for BlockStatement / Program bodies so that\n // variable declarations are checked in the right frame.\n //\n // KNOWN LIMITATION: `var` is function-scoped, not block-scoped. A `var\n // console = ...` inside a nested block (if/for/etc.) is hoisted to the\n // enclosing function, but we treat it as block-scoped here, so console\n // references after the block exits its scope frame will be incorrectly\n // stripped. `let`/`const` are block-scoped so this only affects `var`.\n // In real-world code, shadowing `console` with `var` is exceedingly rare.\n const isBlockScope =\n node.type === \"BlockStatement\" || node.type === \"Program\" || node.type === \"SwitchCase\";\n if (isBlockScope && !isScopeEntering) {\n pushScope();\n }\n\n // Check for local variable declarations of \"console\"\n if (node.type === \"VariableDeclaration\") {\n // oxlint-disable-next-line typescript/no-explicit-any\n for (const decl of (node as any).declarations ?? []) {\n checkBinding(decl.id as BindingNode);\n }\n }\n\n // Recurse into child nodes, passing current node as parent\n for (const key of Object.keys(node)) {\n if (key === \"parent\" || key === \"start\" || key === \"end\") continue;\n // oxlint-disable-next-line typescript/no-explicit-any\n const child = (node as any)[key];\n if (child && typeof child === \"object\") {\n if (Array.isArray(child)) {\n for (const item of child) {\n if (item && typeof item === \"object\" && \"type\" in item) {\n walk(item as BindingNode, node);\n }\n }\n } else if (\"type\" in child) {\n walk(child as BindingNode, node);\n }\n }\n }\n\n if (isScopeEntering || isBlockScope || isCatchScope) {\n popScope();\n }\n }\n\n for (const node of ast.body) {\n walk(node);\n }\n\n if (!changed) return null;\n return s.toString();\n}\n"],"mappings":"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"}
|
|
@@ -281,6 +281,29 @@ declare function convertSegmentsToRouteParts(segments: readonly string[]): {
|
|
|
281
281
|
params: string[];
|
|
282
282
|
isDynamic: boolean;
|
|
283
283
|
} | null;
|
|
284
|
+
/**
|
|
285
|
+
* Returns the unique static sibling segment names at each dynamic URL level
|
|
286
|
+
* of the matched route. Mirrors Next.js's `getStaticSiblingSegments` from
|
|
287
|
+
* the next-app-loader: for `/products/[id]` with a sibling route at
|
|
288
|
+
* `/products/sale`, the dynamic `[id]` segment has `staticSiblings: ['sale']`.
|
|
289
|
+
*
|
|
290
|
+
* The returned list flattens siblings across all dynamic positions and is
|
|
291
|
+
* intended for the RSC payload — the client router uses it to determine if
|
|
292
|
+
* a cached dynamic-route prefetch can be reused when navigating to a static
|
|
293
|
+
* sibling URL.
|
|
294
|
+
*
|
|
295
|
+
* Ported from Next.js: packages/next/src/build/webpack/loaders/next-app-loader/index.ts
|
|
296
|
+
* (getStaticSiblingSegments).
|
|
297
|
+
*
|
|
298
|
+
* Route group segments and parallel-route slot segments are part of the
|
|
299
|
+
* filesystem tree but not the URL namespace — sibling computation is done on
|
|
300
|
+
* the URL-level `patternParts`, so they are correctly transparent here.
|
|
301
|
+
*/
|
|
302
|
+
declare function computeAppRouteStaticSiblings(allRoutes: readonly {
|
|
303
|
+
patternParts?: readonly string[] | null;
|
|
304
|
+
}[], matchedRoute: {
|
|
305
|
+
patternParts?: readonly string[] | null;
|
|
306
|
+
}): string[];
|
|
284
307
|
//#endregion
|
|
285
|
-
export { AppRoute, AppRouteGraphParallelSlot, AppRouteGraphRoute, AppRouteSemanticIds, GraphVersion, InterceptingRoute, ParallelSlot, RootBoundaryId, RouteManifest, RouteManifestBoundary, RouteManifestBoundaryOutcome, RouteManifestDefault, RouteManifestInterception, RouteManifestLayout, RouteManifestPage, RouteManifestRootBoundary, RouteManifestRoute, RouteManifestRouteHandler, RouteManifestSlot, RouteManifestSlotBinding, RouteManifestSlotBindingState, RouteManifestTemplate, StaticSegmentGraph, buildAppRouteGraph, computeRootParamNames, convertSegmentsToRouteParts, isInvisibleSegment };
|
|
308
|
+
export { AppRoute, AppRouteGraphParallelSlot, AppRouteGraphRoute, AppRouteSemanticIds, GraphVersion, InterceptingRoute, ParallelSlot, RootBoundaryId, RouteManifest, RouteManifestBoundary, RouteManifestBoundaryOutcome, RouteManifestDefault, RouteManifestInterception, RouteManifestLayout, RouteManifestPage, RouteManifestRootBoundary, RouteManifestRoute, RouteManifestRouteHandler, RouteManifestSlot, RouteManifestSlotBinding, RouteManifestSlotBindingState, RouteManifestTemplate, StaticSegmentGraph, buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, isInvisibleSegment };
|
|
286
309
|
//# sourceMappingURL=app-route-graph.d.ts.map
|
|
@@ -329,7 +329,7 @@ function createRouteManifestGraphVersion(segmentGraph) {
|
|
|
329
329
|
}
|
|
330
330
|
async function buildAppRouteGraph(appDir, matcher) {
|
|
331
331
|
const routes = [];
|
|
332
|
-
const excludeDir = (name) => name.startsWith("@") || name.startsWith("_") || isInterceptionMarkerDir(name);
|
|
332
|
+
const excludeDir = (name) => name.startsWith("@") && name !== "@children" || name.startsWith("_") || isInterceptionMarkerDir(name);
|
|
333
333
|
for await (const file of scanWithExtensions("**/page", appDir, matcher.extensions, excludeDir)) {
|
|
334
334
|
const route = fileToAppRoute(file, appDir, "page", matcher);
|
|
335
335
|
if (route) routes.push(route);
|
|
@@ -367,7 +367,7 @@ async function buildAppRouteGraph(appDir, matcher) {
|
|
|
367
367
|
}
|
|
368
368
|
function hasParallelSlotDirectory(dir) {
|
|
369
369
|
try {
|
|
370
|
-
return fs.readdirSync(dir, { withFileTypes: true }).some((entry) => entry.isDirectory() && entry.name.startsWith("@"));
|
|
370
|
+
return fs.readdirSync(dir, { withFileTypes: true }).some((entry) => entry.isDirectory() && entry.name.startsWith("@") && entry.name !== "@children");
|
|
371
371
|
} catch {
|
|
372
372
|
return false;
|
|
373
373
|
}
|
|
@@ -555,7 +555,12 @@ function findSlotSubPages(slotDir, matcher) {
|
|
|
555
555
|
* Convert a file path relative to app/ into an AppRoute.
|
|
556
556
|
*/
|
|
557
557
|
function fileToAppRoute(file, appDir, type, matcher) {
|
|
558
|
-
|
|
558
|
+
let dir = path.dirname(file);
|
|
559
|
+
if (type === "page" && dir !== "." && path.basename(dir) === "@children") {
|
|
560
|
+
const parent = path.dirname(dir);
|
|
561
|
+
dir = parent === "" || parent === "." ? "." : parent;
|
|
562
|
+
}
|
|
563
|
+
return directoryToAppRoute(dir, appDir, matcher, type === "page" ? path.join(appDir, file) : null, type === "route" ? path.join(appDir, file) : null);
|
|
559
564
|
}
|
|
560
565
|
function directoryToAppRoute(dir, appDir, matcher, pagePath, routePath) {
|
|
561
566
|
const segments = dir === "." ? [] : dir.split(path.sep);
|
|
@@ -981,6 +986,7 @@ function discoverParallelSlots(dir, appDir, matcher) {
|
|
|
981
986
|
const slots = [];
|
|
982
987
|
for (const entry of entries) {
|
|
983
988
|
if (!entry.isDirectory() || !entry.name.startsWith("@")) continue;
|
|
989
|
+
if (entry.name === "@children") continue;
|
|
984
990
|
const slotName = entry.name.slice(1);
|
|
985
991
|
const slotDir = path.join(dir, entry.name);
|
|
986
992
|
const pagePath = findFile(slotDir, "page", matcher);
|
|
@@ -1284,7 +1290,49 @@ function joinRoutePattern(basePattern, subPath) {
|
|
|
1284
1290
|
if (!subPath) return basePattern;
|
|
1285
1291
|
return basePattern === "/" ? `/${subPath}` : `${basePattern}/${subPath}`;
|
|
1286
1292
|
}
|
|
1293
|
+
/**
|
|
1294
|
+
* Returns the unique static sibling segment names at each dynamic URL level
|
|
1295
|
+
* of the matched route. Mirrors Next.js's `getStaticSiblingSegments` from
|
|
1296
|
+
* the next-app-loader: for `/products/[id]` with a sibling route at
|
|
1297
|
+
* `/products/sale`, the dynamic `[id]` segment has `staticSiblings: ['sale']`.
|
|
1298
|
+
*
|
|
1299
|
+
* The returned list flattens siblings across all dynamic positions and is
|
|
1300
|
+
* intended for the RSC payload — the client router uses it to determine if
|
|
1301
|
+
* a cached dynamic-route prefetch can be reused when navigating to a static
|
|
1302
|
+
* sibling URL.
|
|
1303
|
+
*
|
|
1304
|
+
* Ported from Next.js: packages/next/src/build/webpack/loaders/next-app-loader/index.ts
|
|
1305
|
+
* (getStaticSiblingSegments).
|
|
1306
|
+
*
|
|
1307
|
+
* Route group segments and parallel-route slot segments are part of the
|
|
1308
|
+
* filesystem tree but not the URL namespace — sibling computation is done on
|
|
1309
|
+
* the URL-level `patternParts`, so they are correctly transparent here.
|
|
1310
|
+
*/
|
|
1311
|
+
function computeAppRouteStaticSiblings(allRoutes, matchedRoute) {
|
|
1312
|
+
const siblings = /* @__PURE__ */ new Set();
|
|
1313
|
+
const parts = matchedRoute.patternParts;
|
|
1314
|
+
if (!parts) return [];
|
|
1315
|
+
for (let level = 0; level < parts.length; level++) {
|
|
1316
|
+
const segmentAtLevel = parts[level];
|
|
1317
|
+
if (!segmentAtLevel.startsWith(":")) continue;
|
|
1318
|
+
for (const otherRoute of allRoutes) {
|
|
1319
|
+
const otherParts = otherRoute.patternParts;
|
|
1320
|
+
if (!otherParts || otherParts.length <= level) continue;
|
|
1321
|
+
let prefixMatches = true;
|
|
1322
|
+
for (let i = 0; i < level; i++) if (parts[i] !== otherParts[i]) {
|
|
1323
|
+
prefixMatches = false;
|
|
1324
|
+
break;
|
|
1325
|
+
}
|
|
1326
|
+
if (!prefixMatches) continue;
|
|
1327
|
+
const otherSegmentAtLevel = otherParts[level];
|
|
1328
|
+
if (otherSegmentAtLevel === segmentAtLevel) continue;
|
|
1329
|
+
if (otherSegmentAtLevel.startsWith(":")) continue;
|
|
1330
|
+
siblings.add(otherSegmentAtLevel);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1333
|
+
return Array.from(siblings);
|
|
1334
|
+
}
|
|
1287
1335
|
//#endregion
|
|
1288
|
-
export { buildAppRouteGraph, computeRootParamNames, convertSegmentsToRouteParts, isInvisibleSegment };
|
|
1336
|
+
export { buildAppRouteGraph, computeAppRouteStaticSiblings, computeRootParamNames, convertSegmentsToRouteParts, isInvisibleSegment };
|
|
1289
1337
|
|
|
1290
1338
|
//# sourceMappingURL=app-route-graph.js.map
|