vike 0.4.249-commit-f416149 → 0.4.249-commit-ec50591
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/node/vite/index.js +5 -2
- package/dist/node/vite/plugins/pluginStaticReplace/applyStaticReplace.d.ts +123 -0
- package/dist/node/vite/plugins/pluginStaticReplace/applyStaticReplace.js +404 -0
- package/dist/node/vite/plugins/pluginStaticReplace/buildFilterRolldown.d.ts +13 -0
- package/dist/node/vite/plugins/pluginStaticReplace/buildFilterRolldown.js +105 -0
- package/dist/node/vite/plugins/pluginStaticReplace.d.ts +4 -0
- package/dist/node/vite/plugins/pluginStaticReplace.js +57 -0
- package/dist/node/vite/plugins/pluginViteConfigVikeExtensions.d.ts +2 -1
- package/dist/node/vite/plugins/pluginViteConfigVikeExtensions.js +1 -3
- package/dist/node/vite/shared/importString.d.ts +50 -0
- package/dist/node/vite/shared/importString.js +64 -0
- package/dist/node/vite/shared/resolveVikeConfigInternal/configDefinitionsBuiltIn.js +7 -0
- package/dist/node/vite/shared/resolveVikeConfigInternal/pointerImports.js +11 -18
- package/dist/server/runtime/renderPageServer/csp.js +2 -0
- package/dist/types/Config/ConfigResolved.d.ts +3 -2
- package/dist/types/Config.d.ts +38 -32
- package/dist/types/index.d.ts +2 -1
- package/dist/utils/PROJECT_VERSION.d.ts +1 -1
- package/dist/utils/PROJECT_VERSION.js +1 -1
- package/package.json +4 -2
package/dist/node/vite/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import { pluginWorkaroundCssModuleHmr } from './plugins/pluginWorkaroundCssModul
|
|
|
22
22
|
import { pluginWorkaroundVite6HmrRegression } from './plugins/pluginWorkaroundVite6HmrRegression.js';
|
|
23
23
|
import { pluginReplaceConstantsPageContext } from './plugins/pluginReplaceConstantsPageContext.js';
|
|
24
24
|
import { pluginReplaceConstantsGlobalThis } from './plugins/pluginReplaceConstantsGlobalThis.js';
|
|
25
|
+
import { pluginStaticReplace } from './plugins/pluginStaticReplace.js';
|
|
25
26
|
import { pluginViteRPC } from './plugins/non-runnable-dev/pluginViteRPC.js';
|
|
26
27
|
import { pluginBuildApp } from './plugins/build/pluginBuildApp.js';
|
|
27
28
|
import { pluginDistPackageJsonFile } from './plugins/build/pluginDistPackageJsonFile.js';
|
|
@@ -33,7 +34,7 @@ import { pluginModuleBanner } from './plugins/build/pluginModuleBanner.js';
|
|
|
33
34
|
import { pluginReplaceConstantsNonRunnableDev } from './plugins/non-runnable-dev/pluginReplaceConstantsNonRunnableDev.js';
|
|
34
35
|
import { isVikeCliOrApi } from '../../shared-server-node/api-context.js';
|
|
35
36
|
import { pluginViteConfigVikeExtensions } from './plugins/pluginViteConfigVikeExtensions.js';
|
|
36
|
-
import { isOnlyResolvingUserConfig } from '../api/resolveViteConfigFromUser.js';
|
|
37
|
+
import { getVikeConfigInternalEarly, isOnlyResolvingUserConfig } from '../api/resolveViteConfigFromUser.js';
|
|
37
38
|
// We don't call this in ./onLoad.ts to avoid a cyclic dependency with utils.ts
|
|
38
39
|
setGetClientEntrySrcDev(getClientEntrySrcDev);
|
|
39
40
|
assertIsNotProductionRuntime();
|
|
@@ -42,6 +43,7 @@ function plugin(vikeVitePluginOptions = {}) {
|
|
|
42
43
|
const promise = (async () => {
|
|
43
44
|
if (skip())
|
|
44
45
|
return [];
|
|
46
|
+
const vikeConfig = await getVikeConfigInternalEarly();
|
|
45
47
|
const plugins = [
|
|
46
48
|
...pluginCommon(vikeVitePluginOptions),
|
|
47
49
|
...pluginVirtualFiles(),
|
|
@@ -58,8 +60,9 @@ function plugin(vikeVitePluginOptions = {}) {
|
|
|
58
60
|
...pluginWorkaroundVite6HmrRegression(),
|
|
59
61
|
...pluginReplaceConstantsPageContext(),
|
|
60
62
|
...pluginReplaceConstantsGlobalThis(),
|
|
63
|
+
...pluginStaticReplace(vikeConfig),
|
|
61
64
|
...pluginNonRunnabeDev(),
|
|
62
|
-
...(await pluginViteConfigVikeExtensions()),
|
|
65
|
+
...(await pluginViteConfigVikeExtensions(vikeConfig)),
|
|
63
66
|
];
|
|
64
67
|
return plugins;
|
|
65
68
|
})();
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
export { applyStaticReplace };
|
|
2
|
+
export type { StaticReplace };
|
|
3
|
+
/**
|
|
4
|
+
* Condition to match an argument value.
|
|
5
|
+
* - string starting with 'import:' matches an imported identifier
|
|
6
|
+
* - { prop, equals } matches a property value inside an object argument
|
|
7
|
+
* - { call, args } matches a call expression with specific arguments
|
|
8
|
+
* - { member, object, property } matches a member expression like $setup["ClientOnly"]
|
|
9
|
+
*/
|
|
10
|
+
type ArgCondition = string | {
|
|
11
|
+
prop: string;
|
|
12
|
+
equals: unknown;
|
|
13
|
+
} | {
|
|
14
|
+
call: string;
|
|
15
|
+
args?: Record<number, ArgCondition>;
|
|
16
|
+
} | {
|
|
17
|
+
member: true;
|
|
18
|
+
object: string;
|
|
19
|
+
property: string | ArgCondition;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Target for replace operation.
|
|
23
|
+
*/
|
|
24
|
+
type ReplaceTarget = {
|
|
25
|
+
with: unknown;
|
|
26
|
+
} | {
|
|
27
|
+
arg: number;
|
|
28
|
+
prop: string;
|
|
29
|
+
with: unknown;
|
|
30
|
+
} | {
|
|
31
|
+
arg: number;
|
|
32
|
+
with: unknown;
|
|
33
|
+
} | {
|
|
34
|
+
argsFrom: number;
|
|
35
|
+
with: unknown;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Target for remove operation.
|
|
39
|
+
*/
|
|
40
|
+
type RemoveTarget = {
|
|
41
|
+
arg: number;
|
|
42
|
+
prop: string;
|
|
43
|
+
} | {
|
|
44
|
+
arg: number;
|
|
45
|
+
} | {
|
|
46
|
+
argsFrom: number;
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Rule for static replacement/removal.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* // jsx/jsxs/jsxDEV: replace children prop with null
|
|
53
|
+
* {
|
|
54
|
+
* env: 'server',
|
|
55
|
+
* type: 'call',
|
|
56
|
+
* match: {
|
|
57
|
+
* function: ['jsx', 'jsxs', 'jsxDEV'],
|
|
58
|
+
* args: { 0: 'import:vike-react/ClientOnly:ClientOnly' }
|
|
59
|
+
* },
|
|
60
|
+
* replace: { arg: 1, prop: 'children', with: null }
|
|
61
|
+
* }
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* // createElement: remove all children (args from index 2)
|
|
65
|
+
* {
|
|
66
|
+
* env: 'server',
|
|
67
|
+
* type: 'call',
|
|
68
|
+
* match: {
|
|
69
|
+
* function: 'createElement',
|
|
70
|
+
* args: { 0: 'import:vike-react/ClientOnly:ClientOnly' }
|
|
71
|
+
* },
|
|
72
|
+
* remove: { argsFrom: 2 }
|
|
73
|
+
* }
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // ssrRenderComponent: match nested call expression and remove default slot
|
|
77
|
+
* {
|
|
78
|
+
* env: 'server',
|
|
79
|
+
* type: 'call',
|
|
80
|
+
* match: {
|
|
81
|
+
* function: 'import:vue/server-renderer:ssrRenderComponent',
|
|
82
|
+
* args: {
|
|
83
|
+
* 0: {
|
|
84
|
+
* call: 'import:vue:unref',
|
|
85
|
+
* args: { 0: 'import:vike-vue/ClientOnly:ClientOnly' }
|
|
86
|
+
* }
|
|
87
|
+
* }
|
|
88
|
+
* },
|
|
89
|
+
* remove: { arg: 2, prop: 'default' }
|
|
90
|
+
* }
|
|
91
|
+
*/
|
|
92
|
+
type StaticReplace = {
|
|
93
|
+
/** Type of transformation - currently only 'call' is supported, but can be extended in the future */
|
|
94
|
+
type?: 'call';
|
|
95
|
+
/** Environment filter: 'client' = client only, 'server' = everything except client */
|
|
96
|
+
env?: 'server' | 'client';
|
|
97
|
+
/** Match criteria */
|
|
98
|
+
match: {
|
|
99
|
+
/**
|
|
100
|
+
* Function name(s) to match.
|
|
101
|
+
* - Plain string: matches function name directly (e.g., 'jsx')
|
|
102
|
+
* - Import string: 'import:importPath:exportName' (e.g., 'import:react/jsx-runtime:jsx')
|
|
103
|
+
*/
|
|
104
|
+
function: string | string[];
|
|
105
|
+
/** Conditions on arguments: index -> condition */
|
|
106
|
+
args?: Record<number, ArgCondition>;
|
|
107
|
+
};
|
|
108
|
+
/** Replace target (optional) */
|
|
109
|
+
replace?: ReplaceTarget;
|
|
110
|
+
/** Remove target (optional) */
|
|
111
|
+
remove?: RemoveTarget;
|
|
112
|
+
};
|
|
113
|
+
type TransformResult = {
|
|
114
|
+
code: string;
|
|
115
|
+
map: any;
|
|
116
|
+
} | null;
|
|
117
|
+
type TransformInput = {
|
|
118
|
+
code: string;
|
|
119
|
+
id: string;
|
|
120
|
+
env: string;
|
|
121
|
+
options: StaticReplace[];
|
|
122
|
+
};
|
|
123
|
+
declare function applyStaticReplace({ code, id, env, options }: TransformInput): Promise<TransformResult>;
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
export { applyStaticReplace };
|
|
2
|
+
import { transformAsync } from '@babel/core';
|
|
3
|
+
import * as t from '@babel/types';
|
|
4
|
+
import { parseImportString } from '../../shared/importString.js';
|
|
5
|
+
async function applyStaticReplace({ code, id, env, options }) {
|
|
6
|
+
// 'server' means "not client" (covers ssr, cloudflare, etc.)
|
|
7
|
+
const filteredRules = options.filter((rule) => {
|
|
8
|
+
if (!rule.env)
|
|
9
|
+
return true;
|
|
10
|
+
if (rule.env === 'client')
|
|
11
|
+
return env === 'client';
|
|
12
|
+
if (rule.env === 'server')
|
|
13
|
+
return env !== 'client';
|
|
14
|
+
return false;
|
|
15
|
+
});
|
|
16
|
+
if (filteredRules.length === 0) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
try {
|
|
20
|
+
const state = {
|
|
21
|
+
modified: false,
|
|
22
|
+
imports: new Map(),
|
|
23
|
+
alreadyUnreferenced: new Set(),
|
|
24
|
+
};
|
|
25
|
+
const result = await transformAsync(code, {
|
|
26
|
+
filename: id,
|
|
27
|
+
ast: true,
|
|
28
|
+
sourceMaps: true,
|
|
29
|
+
plugins: [collectImportsPlugin(state), applyRulesPlugin(state, filteredRules), removeUnreferencedPlugin(state)],
|
|
30
|
+
});
|
|
31
|
+
if (!result?.code || !state.modified) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
return { code: result.code, map: result.map };
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
console.error(`Error transforming ${id}:`, error);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// ============================================================================
|
|
42
|
+
// Helpers
|
|
43
|
+
// ============================================================================
|
|
44
|
+
function valueToAst(value) {
|
|
45
|
+
if (value === null)
|
|
46
|
+
return t.nullLiteral();
|
|
47
|
+
if (value === undefined)
|
|
48
|
+
return t.identifier('undefined');
|
|
49
|
+
if (typeof value === 'string')
|
|
50
|
+
return t.stringLiteral(value);
|
|
51
|
+
if (typeof value === 'number')
|
|
52
|
+
return t.numericLiteral(value);
|
|
53
|
+
if (typeof value === 'boolean')
|
|
54
|
+
return t.booleanLiteral(value);
|
|
55
|
+
return t.callExpression(t.memberExpression(t.identifier('JSON'), t.identifier('parse')), [
|
|
56
|
+
t.stringLiteral(JSON.stringify(value)),
|
|
57
|
+
]);
|
|
58
|
+
}
|
|
59
|
+
function getCalleeName(callee) {
|
|
60
|
+
if (t.isIdentifier(callee))
|
|
61
|
+
return callee.name;
|
|
62
|
+
if (t.isMemberExpression(callee) && t.isIdentifier(callee.property))
|
|
63
|
+
return callee.property.name;
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if an identifier matches an import condition
|
|
68
|
+
*/
|
|
69
|
+
function matchesImport(arg, parsed, state) {
|
|
70
|
+
if (!t.isIdentifier(arg))
|
|
71
|
+
return false;
|
|
72
|
+
const imported = state.imports.get(arg.name);
|
|
73
|
+
if (!imported)
|
|
74
|
+
return false;
|
|
75
|
+
return imported.importPath === parsed.importPath && imported.exportName === parsed.exportName;
|
|
76
|
+
}
|
|
77
|
+
// ============================================================================
|
|
78
|
+
// Babel plugins
|
|
79
|
+
// ============================================================================
|
|
80
|
+
/**
|
|
81
|
+
* Collect all imports: localName -> { importPath, exportName }
|
|
82
|
+
*/
|
|
83
|
+
function collectImportsPlugin(state) {
|
|
84
|
+
return {
|
|
85
|
+
visitor: {
|
|
86
|
+
ImportDeclaration(path) {
|
|
87
|
+
const importPath = path.node.source.value;
|
|
88
|
+
for (const specifier of path.node.specifiers) {
|
|
89
|
+
let exportName;
|
|
90
|
+
if (t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) {
|
|
91
|
+
exportName = specifier.imported.name;
|
|
92
|
+
}
|
|
93
|
+
else if (t.isImportDefaultSpecifier(specifier)) {
|
|
94
|
+
exportName = 'default';
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
state.imports.set(specifier.local.name, { importPath, exportName });
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Apply replacement rules to matching call expressions
|
|
107
|
+
*/
|
|
108
|
+
function applyRulesPlugin(state, rules) {
|
|
109
|
+
return {
|
|
110
|
+
visitor: {
|
|
111
|
+
CallExpression(path) {
|
|
112
|
+
const calleeName = getCalleeName(path.node.callee);
|
|
113
|
+
if (!calleeName)
|
|
114
|
+
return;
|
|
115
|
+
for (const rule of rules) {
|
|
116
|
+
if (!matchesRule(path, rule, calleeName, state))
|
|
117
|
+
continue;
|
|
118
|
+
if (rule.replace) {
|
|
119
|
+
applyReplace(path, rule.replace, state);
|
|
120
|
+
}
|
|
121
|
+
else if (rule.remove) {
|
|
122
|
+
applyRemove(path, rule.remove, state);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Check if a call expression matches a rule
|
|
131
|
+
*/
|
|
132
|
+
function matchesRule(path, staticReplace, calleeName, state) {
|
|
133
|
+
const { match } = staticReplace;
|
|
134
|
+
// Check callee name
|
|
135
|
+
const functions = Array.isArray(match.function) ? match.function : [match.function];
|
|
136
|
+
if (!matchesCallee(path.node.callee, calleeName, functions, state))
|
|
137
|
+
return false;
|
|
138
|
+
// Check argument conditions
|
|
139
|
+
if (match.args) {
|
|
140
|
+
for (const [indexStr, condition] of Object.entries(match.args)) {
|
|
141
|
+
const index = Number(indexStr);
|
|
142
|
+
const arg = path.node.arguments[index];
|
|
143
|
+
if (!arg)
|
|
144
|
+
return false;
|
|
145
|
+
if (!matchesCondition(arg, condition, state))
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Check if callee matches any of the function patterns
|
|
153
|
+
*/
|
|
154
|
+
function matchesCallee(callee, calleeName, functions, state) {
|
|
155
|
+
for (const fn of functions) {
|
|
156
|
+
const parsed = parseImportString(fn);
|
|
157
|
+
if (parsed) {
|
|
158
|
+
// Import string: check if callee is an imported identifier
|
|
159
|
+
if (t.isIdentifier(callee)) {
|
|
160
|
+
const imported = state.imports.get(callee.name);
|
|
161
|
+
if (imported && imported.importPath === parsed.importPath && imported.exportName === parsed.exportName) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Import string: check member expression
|
|
166
|
+
if (t.isMemberExpression(callee) && t.isIdentifier(callee.object) && t.isIdentifier(callee.property)) {
|
|
167
|
+
const imported = state.imports.get(callee.object.name);
|
|
168
|
+
if (imported &&
|
|
169
|
+
imported.importPath === parsed.importPath &&
|
|
170
|
+
imported.exportName === 'default' &&
|
|
171
|
+
callee.property.name === parsed.exportName) {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
// Plain string: match function name directly
|
|
178
|
+
if (calleeName === fn)
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Check if an argument matches a condition
|
|
186
|
+
*/
|
|
187
|
+
function matchesCondition(arg, condition, state) {
|
|
188
|
+
// String condition
|
|
189
|
+
if (typeof condition === 'string') {
|
|
190
|
+
// Import condition: 'import:importPath:exportName'
|
|
191
|
+
const parsed = parseImportString(condition);
|
|
192
|
+
if (parsed) {
|
|
193
|
+
return t.isExpression(arg) && matchesImport(arg, parsed, state);
|
|
194
|
+
}
|
|
195
|
+
// Plain string: match string literal or identifier name
|
|
196
|
+
if (t.isStringLiteral(arg))
|
|
197
|
+
return arg.value === condition;
|
|
198
|
+
if (t.isIdentifier(arg))
|
|
199
|
+
return arg.name === condition;
|
|
200
|
+
return false;
|
|
201
|
+
}
|
|
202
|
+
// Call expression condition: match call with specific arguments
|
|
203
|
+
if ('call' in condition) {
|
|
204
|
+
if (!t.isCallExpression(arg))
|
|
205
|
+
return false;
|
|
206
|
+
const calleeName = getCalleeName(arg.callee);
|
|
207
|
+
if (!calleeName)
|
|
208
|
+
return false;
|
|
209
|
+
// Check if callee matches
|
|
210
|
+
const parsed = parseImportString(condition.call);
|
|
211
|
+
if (parsed) {
|
|
212
|
+
// Import string: check if callee is an imported identifier
|
|
213
|
+
if (!t.isIdentifier(arg.callee))
|
|
214
|
+
return false;
|
|
215
|
+
const imported = state.imports.get(arg.callee.name);
|
|
216
|
+
if (!imported || imported.importPath !== parsed.importPath || imported.exportName !== parsed.exportName) {
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
// Plain string: match function name directly
|
|
222
|
+
if (calleeName !== condition.call)
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
// Check argument conditions
|
|
226
|
+
if (condition.args) {
|
|
227
|
+
for (const [indexStr, argCondition] of Object.entries(condition.args)) {
|
|
228
|
+
const index = Number(indexStr);
|
|
229
|
+
const nestedArg = arg.arguments[index];
|
|
230
|
+
if (!nestedArg)
|
|
231
|
+
return false;
|
|
232
|
+
if (!matchesCondition(nestedArg, argCondition, state))
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
// Member expression condition: match $setup["ClientOnly"]
|
|
239
|
+
if ('member' in condition) {
|
|
240
|
+
if (!t.isMemberExpression(arg))
|
|
241
|
+
return false;
|
|
242
|
+
// Check object
|
|
243
|
+
if (!t.isIdentifier(arg.object) || arg.object.name !== condition.object)
|
|
244
|
+
return false;
|
|
245
|
+
// Check property
|
|
246
|
+
if (typeof condition.property === 'string') {
|
|
247
|
+
// Simple string property
|
|
248
|
+
if (t.isIdentifier(arg.property) && !arg.computed) {
|
|
249
|
+
return arg.property.name === condition.property;
|
|
250
|
+
}
|
|
251
|
+
if (t.isStringLiteral(arg.property) && arg.computed) {
|
|
252
|
+
return arg.property.value === condition.property;
|
|
253
|
+
}
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
// Nested condition on property (for future extensibility)
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Object condition: match prop value inside an object argument
|
|
262
|
+
if (!t.isObjectExpression(arg))
|
|
263
|
+
return false;
|
|
264
|
+
for (const prop of arg.properties) {
|
|
265
|
+
if (!t.isObjectProperty(prop))
|
|
266
|
+
continue;
|
|
267
|
+
if (!t.isIdentifier(prop.key) || prop.key.name !== condition.prop)
|
|
268
|
+
continue;
|
|
269
|
+
// Check value
|
|
270
|
+
if (condition.equals === null && t.isNullLiteral(prop.value))
|
|
271
|
+
return true;
|
|
272
|
+
if (condition.equals === true && t.isBooleanLiteral(prop.value) && prop.value.value === true)
|
|
273
|
+
return true;
|
|
274
|
+
if (condition.equals === false && t.isBooleanLiteral(prop.value) && prop.value.value === false)
|
|
275
|
+
return true;
|
|
276
|
+
if (typeof condition.equals === 'string' && t.isStringLiteral(prop.value) && prop.value.value === condition.equals)
|
|
277
|
+
return true;
|
|
278
|
+
if (typeof condition.equals === 'number' && t.isNumericLiteral(prop.value) && prop.value.value === condition.equals)
|
|
279
|
+
return true;
|
|
280
|
+
}
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Apply a replacement to a call expression
|
|
285
|
+
*/
|
|
286
|
+
function applyReplace(path, replace, state) {
|
|
287
|
+
// Replace the entire call expression
|
|
288
|
+
if (!('arg' in replace) && !('argsFrom' in replace)) {
|
|
289
|
+
path.replaceWith(valueToAst(replace.with));
|
|
290
|
+
state.modified = true;
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
// Replace a prop inside an object argument
|
|
294
|
+
if ('arg' in replace && 'prop' in replace) {
|
|
295
|
+
const arg = path.node.arguments[replace.arg];
|
|
296
|
+
if (!t.isObjectExpression(arg))
|
|
297
|
+
return;
|
|
298
|
+
for (const prop of arg.properties) {
|
|
299
|
+
if (!t.isObjectProperty(prop))
|
|
300
|
+
continue;
|
|
301
|
+
if (!t.isIdentifier(prop.key) || prop.key.name !== replace.prop)
|
|
302
|
+
continue;
|
|
303
|
+
prop.value = valueToAst(replace.with);
|
|
304
|
+
state.modified = true;
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
// Replace entire argument
|
|
309
|
+
else if ('arg' in replace) {
|
|
310
|
+
if (path.node.arguments.length > replace.arg) {
|
|
311
|
+
path.node.arguments[replace.arg] = valueToAst(replace.with);
|
|
312
|
+
state.modified = true;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Replace all args from index onwards with a single value
|
|
316
|
+
else if ('argsFrom' in replace) {
|
|
317
|
+
if (path.node.arguments.length > replace.argsFrom) {
|
|
318
|
+
path.node.arguments = [...path.node.arguments.slice(0, replace.argsFrom), valueToAst(replace.with)];
|
|
319
|
+
state.modified = true;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Apply a removal to a call expression
|
|
325
|
+
*/
|
|
326
|
+
function applyRemove(path, remove, state) {
|
|
327
|
+
// Remove a prop inside an object argument
|
|
328
|
+
if ('prop' in remove) {
|
|
329
|
+
const arg = path.node.arguments[remove.arg];
|
|
330
|
+
if (!t.isObjectExpression(arg))
|
|
331
|
+
return;
|
|
332
|
+
const index = arg.properties.findIndex((prop) => {
|
|
333
|
+
// Check ObjectProperty with Identifier key
|
|
334
|
+
if (t.isObjectProperty(prop) && t.isIdentifier(prop.key) && prop.key.name === remove.prop) {
|
|
335
|
+
return true;
|
|
336
|
+
}
|
|
337
|
+
// Check ObjectMethod (getter/setter)
|
|
338
|
+
if (t.isObjectMethod(prop) && t.isIdentifier(prop.key) && prop.key.name === remove.prop) {
|
|
339
|
+
return true;
|
|
340
|
+
}
|
|
341
|
+
return false;
|
|
342
|
+
});
|
|
343
|
+
if (index !== -1) {
|
|
344
|
+
arg.properties.splice(index, 1);
|
|
345
|
+
state.modified = true;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Remove entire argument
|
|
349
|
+
else if ('arg' in remove) {
|
|
350
|
+
if (path.node.arguments.length > remove.arg) {
|
|
351
|
+
path.node.arguments.splice(remove.arg, 1);
|
|
352
|
+
state.modified = true;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
// Remove all args from index onwards
|
|
356
|
+
else if ('argsFrom' in remove) {
|
|
357
|
+
if (path.node.arguments.length > remove.argsFrom) {
|
|
358
|
+
path.node.arguments = path.node.arguments.slice(0, remove.argsFrom);
|
|
359
|
+
state.modified = true;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Remove unreferenced bindings after modifications
|
|
365
|
+
*/
|
|
366
|
+
function removeUnreferencedPlugin(state) {
|
|
367
|
+
return {
|
|
368
|
+
visitor: {
|
|
369
|
+
Program: {
|
|
370
|
+
enter(program) {
|
|
371
|
+
for (const [name, binding] of Object.entries(program.scope.bindings)) {
|
|
372
|
+
if (!binding.referenced)
|
|
373
|
+
state.alreadyUnreferenced.add(name);
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
exit(program) {
|
|
377
|
+
if (!state.modified)
|
|
378
|
+
return;
|
|
379
|
+
removeUnreferenced(program, state.alreadyUnreferenced);
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function removeUnreferenced(program, alreadyUnreferenced) {
|
|
386
|
+
for (;;) {
|
|
387
|
+
program.scope.crawl();
|
|
388
|
+
let removed = false;
|
|
389
|
+
for (const [name, binding] of Object.entries(program.scope.bindings)) {
|
|
390
|
+
if (binding.referenced || alreadyUnreferenced.has(name))
|
|
391
|
+
continue;
|
|
392
|
+
const parent = binding.path.parentPath;
|
|
393
|
+
if (parent?.isImportDeclaration() && parent.node.specifiers.length === 1) {
|
|
394
|
+
parent.remove();
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
binding.path.remove();
|
|
398
|
+
}
|
|
399
|
+
removed = true;
|
|
400
|
+
}
|
|
401
|
+
if (!removed)
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export { buildFilterRolldown };
|
|
2
|
+
import type { StaticReplace } from './applyStaticReplace.js';
|
|
3
|
+
/**
|
|
4
|
+
* Build a filterRolldown from staticReplaceList by extracting all import strings.
|
|
5
|
+
* For a single entry, ALL import strings must be present (AND logic),
|
|
6
|
+
* except for call.match.function array which is OR logic.
|
|
7
|
+
* Between staticReplace entries it's OR logic.
|
|
8
|
+
*/
|
|
9
|
+
declare function buildFilterRolldown(staticReplaceList: StaticReplace[]): {
|
|
10
|
+
code: {
|
|
11
|
+
include: RegExp;
|
|
12
|
+
};
|
|
13
|
+
} | null;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export { buildFilterRolldown };
|
|
2
|
+
import { escapeRegex } from '../../utils.js';
|
|
3
|
+
import { parseImportString } from '../../shared/importString.js';
|
|
4
|
+
/**
|
|
5
|
+
* Build a filterRolldown from staticReplaceList by extracting all import strings.
|
|
6
|
+
* For a single entry, ALL import strings must be present (AND logic),
|
|
7
|
+
* except for call.match.function array which is OR logic.
|
|
8
|
+
* Between staticReplace entries it's OR logic.
|
|
9
|
+
*/
|
|
10
|
+
function buildFilterRolldown(staticReplaceList) {
|
|
11
|
+
const rulePatterns = [];
|
|
12
|
+
// Process each entry separately
|
|
13
|
+
for (const staticReplaceEntry of staticReplaceList) {
|
|
14
|
+
const importStrings = new Set();
|
|
15
|
+
const functionImportStrings = new Set();
|
|
16
|
+
// Extract function import strings separately
|
|
17
|
+
extractImportStrings(staticReplaceEntry.match.function, functionImportStrings);
|
|
18
|
+
// Extract arg import strings
|
|
19
|
+
if (staticReplaceEntry.match.args) {
|
|
20
|
+
for (const condition of Object.values(staticReplaceEntry.match.args)) {
|
|
21
|
+
extractImportStringsFromCondition(condition, importStrings);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Build pattern for this staticReplaceEntry
|
|
25
|
+
const ruleParts = [];
|
|
26
|
+
// For function imports: if array, use OR; otherwise use AND
|
|
27
|
+
if (functionImportStrings.size > 0) {
|
|
28
|
+
const functionPatterns = [];
|
|
29
|
+
for (const importStr of functionImportStrings) {
|
|
30
|
+
const parts = parseImportString(importStr);
|
|
31
|
+
if (parts) {
|
|
32
|
+
// Each function import should match both importPath and export name
|
|
33
|
+
functionPatterns.push(`(?=.*${escapeRegex(parts.importPath)})(?=.*${escapeRegex(parts.exportName)})`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// If multiple functions, they are alternatives (OR)
|
|
37
|
+
if (functionPatterns.length > 0) {
|
|
38
|
+
if (functionPatterns.length === 1) {
|
|
39
|
+
ruleParts.push(functionPatterns[0]);
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// Multiple function patterns: file must match at least one
|
|
43
|
+
ruleParts.push(`(?:${functionPatterns.join('|')})`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// For arg imports: all must be present (AND)
|
|
48
|
+
for (const importStr of importStrings) {
|
|
49
|
+
const parts = parseImportString(importStr);
|
|
50
|
+
if (parts) {
|
|
51
|
+
// Each arg import should match both importPath and export name
|
|
52
|
+
ruleParts.push(`(?=.*${escapeRegex(parts.importPath)})(?=.*${escapeRegex(parts.exportName)})`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Combine all parts for this rule with AND logic
|
|
56
|
+
if (ruleParts.length > 0) {
|
|
57
|
+
// All parts must match for this rule
|
|
58
|
+
rulePatterns.push(ruleParts.join(''));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (rulePatterns.length === 0)
|
|
62
|
+
return null;
|
|
63
|
+
// Create a regex that matches if any rule pattern matches (OR between staticReplace entries)
|
|
64
|
+
const regex = new RegExp(rulePatterns.join('|'));
|
|
65
|
+
return {
|
|
66
|
+
code: {
|
|
67
|
+
include: regex,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Extract import strings from function patterns
|
|
73
|
+
*/
|
|
74
|
+
function extractImportStrings(functions, result) {
|
|
75
|
+
const arr = Array.isArray(functions) ? functions : [functions];
|
|
76
|
+
for (const fn of arr) {
|
|
77
|
+
if (parseImportString(fn)) {
|
|
78
|
+
result.add(fn);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Extract import strings from argument conditions
|
|
84
|
+
*/
|
|
85
|
+
function extractImportStringsFromCondition(condition, result) {
|
|
86
|
+
if (typeof condition === 'string') {
|
|
87
|
+
if (parseImportString(condition)) {
|
|
88
|
+
result.add(condition);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else if (condition && typeof condition === 'object') {
|
|
92
|
+
// Handle call condition
|
|
93
|
+
if ('call' in condition && typeof condition.call === 'string') {
|
|
94
|
+
if (parseImportString(condition.call)) {
|
|
95
|
+
result.add(condition.call);
|
|
96
|
+
}
|
|
97
|
+
// Recursively check nested args
|
|
98
|
+
if (condition.args) {
|
|
99
|
+
for (const nestedCondition of Object.values(condition.args)) {
|
|
100
|
+
extractImportStringsFromCondition(nestedCondition, result);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export { pluginStaticReplace };
|
|
2
|
+
import { assert } from '../utils.js';
|
|
3
|
+
import { isViteServerSide_extraSafe } from '../shared/isViteServerSide.js';
|
|
4
|
+
import { applyStaticReplace } from './pluginStaticReplace/applyStaticReplace.js';
|
|
5
|
+
import { buildFilterRolldown } from './pluginStaticReplace/buildFilterRolldown.js';
|
|
6
|
+
function pluginStaticReplace(vikeConfig) {
|
|
7
|
+
let config;
|
|
8
|
+
const staticReplaceList = getStaticReplaceList(vikeConfig);
|
|
9
|
+
if (staticReplaceList.length === 0)
|
|
10
|
+
return [];
|
|
11
|
+
const filterRolldown = buildFilterRolldown(staticReplaceList);
|
|
12
|
+
assert(filterRolldown);
|
|
13
|
+
return [
|
|
14
|
+
{
|
|
15
|
+
name: 'vike:pluginStaticReplace',
|
|
16
|
+
enforce: 'post',
|
|
17
|
+
configResolved: {
|
|
18
|
+
async handler(config_) {
|
|
19
|
+
config = config_;
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
transform: {
|
|
23
|
+
filter: {
|
|
24
|
+
code: {
|
|
25
|
+
include: filterRolldown.code.include,
|
|
26
|
+
exclude: /node_modules/,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
async handler(code, id, options) {
|
|
30
|
+
const env = isViteServerSide_extraSafe(config, this.environment, options) ? 'server' : 'client';
|
|
31
|
+
const result = await applyStaticReplace({
|
|
32
|
+
code,
|
|
33
|
+
id,
|
|
34
|
+
env,
|
|
35
|
+
options: staticReplaceList,
|
|
36
|
+
});
|
|
37
|
+
return result;
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Extract all staticReplaceList from vikeConfig
|
|
45
|
+
*/
|
|
46
|
+
function getStaticReplaceList(vikeConfig) {
|
|
47
|
+
const staticReplaceConfigs = vikeConfig._from.configsCumulative.staticReplace;
|
|
48
|
+
if (!staticReplaceConfigs)
|
|
49
|
+
return [];
|
|
50
|
+
const staticReplaceList = [];
|
|
51
|
+
for (const configValue of staticReplaceConfigs.values) {
|
|
52
|
+
const entries = configValue.value;
|
|
53
|
+
assert(Array.isArray(entries));
|
|
54
|
+
staticReplaceList.push(...entries);
|
|
55
|
+
}
|
|
56
|
+
return staticReplaceList;
|
|
57
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { pluginViteConfigVikeExtensions };
|
|
2
2
|
import type { Plugin } from 'vite';
|
|
3
|
-
|
|
3
|
+
import type { VikeConfigInternal } from '../shared/resolveVikeConfigInternal.js';
|
|
4
|
+
declare function pluginViteConfigVikeExtensions(vikeConfig: VikeConfigInternal): Promise<Plugin[]>;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
export { pluginViteConfigVikeExtensions };
|
|
2
2
|
import { mergeConfig } from 'vite';
|
|
3
3
|
import { assertUsage, isCallable, isObject } from '../utils.js';
|
|
4
|
-
import { getVikeConfigInternalEarly } from '../../api/resolveViteConfigFromUser.js';
|
|
5
4
|
// Apply +vite
|
|
6
5
|
// - For example, Vike extensions adding Vite plugins
|
|
7
|
-
async function pluginViteConfigVikeExtensions() {
|
|
8
|
-
const vikeConfig = await getVikeConfigInternalEarly();
|
|
6
|
+
async function pluginViteConfigVikeExtensions(vikeConfig) {
|
|
9
7
|
if (vikeConfig === null)
|
|
10
8
|
return [];
|
|
11
9
|
let viteConfigFromExtensions = {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export { parseImportString };
|
|
2
|
+
export { isImportString };
|
|
3
|
+
export { serializeImportString };
|
|
4
|
+
export type { ImportString };
|
|
5
|
+
export type { ImportStringList };
|
|
6
|
+
export type { ImportStringParsed };
|
|
7
|
+
/** `import:${importPath}:${exportName}`
|
|
8
|
+
* @example import:./Layout:default
|
|
9
|
+
*/
|
|
10
|
+
type ImportString = `import:${string}:${string}`;
|
|
11
|
+
type ImportStringList = ImportString | ImportString[];
|
|
12
|
+
type ImportStringParsed = {
|
|
13
|
+
importPath: string;
|
|
14
|
+
exportName: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Parse import string in format: import:importPath:exportName
|
|
18
|
+
*
|
|
19
|
+
* @example parseImportString('import:react/jsx-runtime:jsx')
|
|
20
|
+
* // => { importPath: 'react/jsx-runtime', exportName: 'jsx' }
|
|
21
|
+
*
|
|
22
|
+
* @example parseImportString('import:./Layout:default')
|
|
23
|
+
* // => { importPath: './Layout', exportName: 'default' }
|
|
24
|
+
*
|
|
25
|
+
* @example parseImportString('import:./Layout', { legacy: true })
|
|
26
|
+
* // => { importPath: './Layout', exportName: 'default' }
|
|
27
|
+
*/
|
|
28
|
+
declare function parseImportString(importString: string, { legacy }?: {
|
|
29
|
+
legacy?: boolean;
|
|
30
|
+
}): null | ImportStringParsed;
|
|
31
|
+
/**
|
|
32
|
+
* Check if a string is an import string (starts with 'import:').
|
|
33
|
+
*
|
|
34
|
+
* @example isImportString('import:react:jsx')
|
|
35
|
+
* // => true
|
|
36
|
+
*
|
|
37
|
+
* @example isImportString('some-other-string')
|
|
38
|
+
* // => false
|
|
39
|
+
*/
|
|
40
|
+
declare function isImportString(str: string): str is ImportString;
|
|
41
|
+
/**
|
|
42
|
+
* Serialize import string from importPath and export name.
|
|
43
|
+
*
|
|
44
|
+
* @example serializeImportString({ importPath: 'react/jsx-runtime', exportName: 'jsx' })
|
|
45
|
+
* // => 'import:react/jsx-runtime:jsx'
|
|
46
|
+
*
|
|
47
|
+
* @example serializeImportString({ importPath: './Layout', exportName: 'default' })
|
|
48
|
+
* // => 'import:./Layout:default'
|
|
49
|
+
*/
|
|
50
|
+
declare function serializeImportString({ importPath, exportName }: ImportStringParsed): `import:${string}:${string}`;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export { parseImportString };
|
|
2
|
+
export { isImportString };
|
|
3
|
+
export { serializeImportString };
|
|
4
|
+
import { assert } from '../utils.js';
|
|
5
|
+
const IMPORT = 'import';
|
|
6
|
+
const SEP = ':';
|
|
7
|
+
/**
|
|
8
|
+
* Parse import string in format: import:importPath:exportName
|
|
9
|
+
*
|
|
10
|
+
* @example parseImportString('import:react/jsx-runtime:jsx')
|
|
11
|
+
* // => { importPath: 'react/jsx-runtime', exportName: 'jsx' }
|
|
12
|
+
*
|
|
13
|
+
* @example parseImportString('import:./Layout:default')
|
|
14
|
+
* // => { importPath: './Layout', exportName: 'default' }
|
|
15
|
+
*
|
|
16
|
+
* @example parseImportString('import:./Layout', { legacy: true })
|
|
17
|
+
* // => { importPath: './Layout', exportName: 'default' }
|
|
18
|
+
*/
|
|
19
|
+
function parseImportString(importString, { legacy = false } = {}) {
|
|
20
|
+
if (!isImportString(importString))
|
|
21
|
+
return null;
|
|
22
|
+
const parts = importString.split(SEP);
|
|
23
|
+
assert(parts[0] === IMPORT);
|
|
24
|
+
if (legacy && parts.length === 2) {
|
|
25
|
+
/* TODO
|
|
26
|
+
assertWarning(false, 'To-Do', { onlyOnce: true, showStackTrace: true })
|
|
27
|
+
*/
|
|
28
|
+
const exportName = 'default';
|
|
29
|
+
const importPath = parts[1];
|
|
30
|
+
assert(importPath);
|
|
31
|
+
return { importPath, exportName };
|
|
32
|
+
}
|
|
33
|
+
assert(parts.length >= 3);
|
|
34
|
+
const exportName = parts[parts.length - 1];
|
|
35
|
+
const importPath = parts.slice(1, -1).join(SEP);
|
|
36
|
+
assert(exportName);
|
|
37
|
+
assert(importPath);
|
|
38
|
+
return { importPath, exportName };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Check if a string is an import string (starts with 'import:').
|
|
42
|
+
*
|
|
43
|
+
* @example isImportString('import:react:jsx')
|
|
44
|
+
* // => true
|
|
45
|
+
*
|
|
46
|
+
* @example isImportString('some-other-string')
|
|
47
|
+
* // => false
|
|
48
|
+
*/
|
|
49
|
+
function isImportString(str) {
|
|
50
|
+
return str.startsWith(`${IMPORT}${SEP}`);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Serialize import string from importPath and export name.
|
|
54
|
+
*
|
|
55
|
+
* @example serializeImportString({ importPath: 'react/jsx-runtime', exportName: 'jsx' })
|
|
56
|
+
* // => 'import:react/jsx-runtime:jsx'
|
|
57
|
+
*
|
|
58
|
+
* @example serializeImportString({ importPath: './Layout', exportName: 'default' })
|
|
59
|
+
* // => 'import:./Layout:default'
|
|
60
|
+
*/
|
|
61
|
+
function serializeImportString({ importPath, exportName }) {
|
|
62
|
+
const importString = `${IMPORT}${SEP}${importPath}${SEP}${exportName}`;
|
|
63
|
+
return importString;
|
|
64
|
+
}
|
|
@@ -270,6 +270,13 @@ const configDefinitionsBuiltIn = {
|
|
|
270
270
|
env: { server: true },
|
|
271
271
|
cumulative: true,
|
|
272
272
|
},
|
|
273
|
+
staticReplace: {
|
|
274
|
+
env: { config: true },
|
|
275
|
+
cumulative: true,
|
|
276
|
+
/* TODO
|
|
277
|
+
vite: true,
|
|
278
|
+
*/
|
|
279
|
+
},
|
|
273
280
|
};
|
|
274
281
|
function getConfigEnv(pageConfig, configName) {
|
|
275
282
|
const source = getConfigValueSourceRelevantAnyEnv(configName, pageConfig);
|
|
@@ -5,6 +5,7 @@ export { assertPointerImportPath };
|
|
|
5
5
|
// Playground: https://github.com/brillout/acorn-playground
|
|
6
6
|
// Notes about `with { type: 'pointer' }`
|
|
7
7
|
// - It works well with TypeScript: it doesn't complain upon `with { type: 'unknown-to-typescript' }` and go-to-definition & types are preserved: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-3.html#import-attributes
|
|
8
|
+
// - Babel already supports it: https://babeljs.io/docs/babel-parser#plugins => search for `importAttributes`
|
|
8
9
|
// - Acorn support for import attributes: https://github.com/acornjs/acorn/issues/983
|
|
9
10
|
// - Acorn plugin: https://github.com/acornjs/acorn/issues/983
|
|
10
11
|
// - Isn't stage 4 yet: https://github.com/tc39/proposal-import-attributes
|
|
@@ -17,9 +18,10 @@ export { assertPointerImportPath };
|
|
|
17
18
|
// - Using a magic comment `// @vike-real-import` is probably a bad idea:
|
|
18
19
|
// - Esbuild removes comments: https://github.com/evanw/esbuild/issues/1439#issuecomment-877656182
|
|
19
20
|
// - Using source maps to track these magic comments is brittle (source maps can easily break)
|
|
20
|
-
import {
|
|
21
|
+
import { parseSync } from '@babel/core';
|
|
21
22
|
import { assert, assertUsage, assertWarning, isFilePathAbsolute, isImportPath, styleFileRE } from '../../utils.js';
|
|
22
23
|
import pc from '@brillout/picocolors';
|
|
24
|
+
import { parseImportString, isImportString, serializeImportString } from '../importString.js';
|
|
23
25
|
function transformPointerImports(code, filePathToShowToUser2, pointerImports,
|
|
24
26
|
// For ./transformPointerImports.spec.ts
|
|
25
27
|
skipWarnings) {
|
|
@@ -103,11 +105,11 @@ skipWarnings) {
|
|
|
103
105
|
return codeMod;
|
|
104
106
|
}
|
|
105
107
|
function getImports(code) {
|
|
106
|
-
const
|
|
107
|
-
ecmaVersion: 'latest',
|
|
108
|
+
const result = parseSync(code, {
|
|
108
109
|
sourceType: 'module',
|
|
109
|
-
// https://github.com/acornjs/acorn/issues/1136
|
|
110
110
|
});
|
|
111
|
+
assert(result);
|
|
112
|
+
const { body } = result.program;
|
|
111
113
|
const imports = [];
|
|
112
114
|
body.forEach((node) => {
|
|
113
115
|
if (node.type === 'ImportDeclaration')
|
|
@@ -115,16 +117,13 @@ function getImports(code) {
|
|
|
115
117
|
});
|
|
116
118
|
return imports;
|
|
117
119
|
}
|
|
118
|
-
const import_ = 'import';
|
|
119
|
-
const SEP = ':';
|
|
120
120
|
const zeroWidthSpace = '\u200b';
|
|
121
121
|
function serializePointerImportData({ importPath, exportName, importStringWasGenerated, }) {
|
|
122
122
|
const tag = importStringWasGenerated ? zeroWidthSpace : '';
|
|
123
|
-
|
|
124
|
-
return `${tag}${import_}${SEP}${importPath}${SEP}${exportName}`;
|
|
123
|
+
return `${tag}${serializeImportString({ importPath, exportName })}`;
|
|
125
124
|
}
|
|
126
125
|
function isPointerImportData(str) {
|
|
127
|
-
return str
|
|
126
|
+
return isImportString(str) || (str.startsWith(zeroWidthSpace) && isImportString(str.slice(1)));
|
|
128
127
|
}
|
|
129
128
|
function parsePointerImportData(importString) {
|
|
130
129
|
if (!isPointerImportData(importString)) {
|
|
@@ -136,15 +135,9 @@ function parsePointerImportData(importString) {
|
|
|
136
135
|
assert(zeroWidthSpace.length === 1);
|
|
137
136
|
importString = importString.slice(1);
|
|
138
137
|
}
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const importPath = parts[0];
|
|
143
|
-
return { importPath, exportName, importStringWasGenerated, importString };
|
|
144
|
-
}
|
|
145
|
-
assert(parts.length >= 2);
|
|
146
|
-
const exportName = parts[parts.length - 1];
|
|
147
|
-
const importPath = parts.slice(0, -1).join(SEP);
|
|
138
|
+
const parsed = parseImportString(importString, { legacy: !importStringWasGenerated });
|
|
139
|
+
assert(parsed);
|
|
140
|
+
const { importPath, exportName } = parsed;
|
|
148
141
|
if (importPath.startsWith('.') && !(importPath.startsWith('./') || importPath.startsWith('../'))) {
|
|
149
142
|
assert(!importStringWasGenerated);
|
|
150
143
|
assertUsage(false, `Invalid relative import path ${pc.code(importPath)} defined by ${pc.code(JSON.stringify(importString))} because it should start with ${pc.code('./')} or ${pc.code('../')}, or use an npm package import instead.`);
|
|
@@ -32,6 +32,7 @@ async function generateNonce() {
|
|
|
32
32
|
return cryptoModule.randomBytes(16).toString('base64url');
|
|
33
33
|
}
|
|
34
34
|
function inferNonceAttr(pageContext) {
|
|
35
|
+
// No need to escape the injected HTML — pageContext.cspNone is controlled by the developer, not by the website visitor (I wouldn't know why the developer would set +csp.none to a value coming from the database)
|
|
35
36
|
const nonceAttr = pageContext.cspNonce ? ` nonce="${pageContext.cspNonce}"` : '';
|
|
36
37
|
return nonceAttr;
|
|
37
38
|
}
|
|
@@ -41,5 +42,6 @@ function addCspResponseHeader(pageContext, headersResponse) {
|
|
|
41
42
|
return;
|
|
42
43
|
if (headersResponse.get('Content-Security-Policy'))
|
|
43
44
|
return;
|
|
45
|
+
// No need to sanitize the injected header — see comment above about not escaping HTML
|
|
44
46
|
headersResponse.set('Content-Security-Policy', `script-src 'self' 'nonce-${pageContext.cspNonce}'`);
|
|
45
47
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export type { ConfigResolved };
|
|
2
|
-
import type { ConfigBuiltIn, ConfigBuiltInResolved
|
|
2
|
+
import type { ConfigBuiltIn, ConfigBuiltInResolved } from '../Config.js';
|
|
3
|
+
import type { ImportStringList } from '../../node/vite/shared/importString.js';
|
|
3
4
|
type ConfigUnresolved = WithoutImportString<ConfigBuiltIn & Vike.Config>;
|
|
4
5
|
type ConfigResolvedOnly = ConfigBuiltInResolved & Vike.ConfigResolved;
|
|
5
6
|
type ConfigResolved = ConfigResolvedOnly & Omit<ConfigUnresolved, keyof ConfigResolvedOnly>;
|
|
6
7
|
type WithoutImportString<T> = {
|
|
7
|
-
[K in keyof T]: Exclude<T[K],
|
|
8
|
+
[K in keyof T]: Exclude<T[K], ImportStringList>;
|
|
8
9
|
};
|
package/dist/types/Config.d.ts
CHANGED
|
@@ -8,7 +8,6 @@ export type { HookName };
|
|
|
8
8
|
export type { HookNameOld };
|
|
9
9
|
export type { HookNamePage };
|
|
10
10
|
export type { HookNameGlobal };
|
|
11
|
-
export type { ImportString };
|
|
12
11
|
export type { Route };
|
|
13
12
|
export type { KeepScrollPosition };
|
|
14
13
|
export type { DataAsync };
|
|
@@ -47,6 +46,8 @@ import type { GlobalContext } from './GlobalContext.js';
|
|
|
47
46
|
import type { InlineConfig } from 'vite';
|
|
48
47
|
import type { PassToClientPublic } from '../server/runtime/renderPageServer/html/serializeContext.js';
|
|
49
48
|
import type { CliPreviewConfig } from '../node/api/preview.js';
|
|
49
|
+
import type { StaticReplace } from '../node/vite/plugins/pluginStaticReplace/applyStaticReplace.js';
|
|
50
|
+
import type { ImportStringList } from '../node/vite/shared/importString.js';
|
|
50
51
|
type HookNameOld = HookName | HookNameOldDesign;
|
|
51
52
|
type HookName = HookNamePage | HookNameGlobal;
|
|
52
53
|
type HookNamePage = 'onHydrationEnd' | 'onBeforePrerenderStart' | 'onBeforeRender' | 'onPageTransitionStart' | 'onPageTransitionEnd' | 'onRenderHtml' | 'onRenderClient' | 'guard' | 'data' | 'onData' | 'route';
|
|
@@ -250,12 +251,12 @@ type ConfigBuiltIn = {
|
|
|
250
251
|
*
|
|
251
252
|
* https://vike.dev/route
|
|
252
253
|
*/
|
|
253
|
-
route?: Route |
|
|
254
|
+
route?: Route | ImportStringList;
|
|
254
255
|
/** Protect page(s), e.g. forbid unauthorized access.
|
|
255
256
|
*
|
|
256
257
|
* https://vike.dev/guard
|
|
257
258
|
*/
|
|
258
|
-
guard?: GuardAsync | GuardSync |
|
|
259
|
+
guard?: GuardAsync | GuardSync | ImportStringList;
|
|
259
260
|
/**
|
|
260
261
|
* Pre-render page(s).
|
|
261
262
|
*
|
|
@@ -264,7 +265,7 @@ type ConfigBuiltIn = {
|
|
|
264
265
|
*
|
|
265
266
|
* @default false
|
|
266
267
|
*/
|
|
267
|
-
prerender?: boolean |
|
|
268
|
+
prerender?: boolean | ImportStringList | {
|
|
268
269
|
/**
|
|
269
270
|
* Allow only some of your pages to be pre-rendered.
|
|
270
271
|
*
|
|
@@ -339,32 +340,32 @@ type ConfigBuiltIn = {
|
|
|
339
340
|
*
|
|
340
341
|
* https://vike.dev/extends
|
|
341
342
|
*/
|
|
342
|
-
extends?: Config | Config[] |
|
|
343
|
+
extends?: Config | Config[] | ImportStringList;
|
|
343
344
|
/** Hook called before the page is rendered.
|
|
344
345
|
*
|
|
345
346
|
* https://vike.dev/onBeforeRender
|
|
346
347
|
*/
|
|
347
|
-
onBeforeRender?: OnBeforeRenderAsync | OnBeforeRenderSync |
|
|
348
|
+
onBeforeRender?: OnBeforeRenderAsync | OnBeforeRenderSync | ImportStringList | null;
|
|
348
349
|
/** Hook called when a `pageContext` object is created.
|
|
349
350
|
*
|
|
350
351
|
* https://vike.dev/onCreatePageContext
|
|
351
352
|
*/
|
|
352
|
-
onCreatePageContext?: ((pageContext: PageContextServer) => void) |
|
|
353
|
+
onCreatePageContext?: ((pageContext: PageContextServer) => void) | ImportStringList | null;
|
|
353
354
|
/** Hook called when an error occurs during server-side rendering.
|
|
354
355
|
*
|
|
355
356
|
* https://vike.dev/onError
|
|
356
357
|
*/
|
|
357
|
-
onError?: ((error: unknown, pageContext: null | PageContextServer) => void) |
|
|
358
|
+
onError?: ((error: unknown, pageContext: null | PageContextServer) => void) | ImportStringList | null;
|
|
358
359
|
/** Hook called when the `globalContext` object is created.
|
|
359
360
|
*
|
|
360
361
|
* https://vike.dev/onCreateGlobalContext
|
|
361
362
|
*/
|
|
362
|
-
onCreateGlobalContext?: ((globalContext: GlobalContext) => void) |
|
|
363
|
+
onCreateGlobalContext?: ((globalContext: GlobalContext) => void) | ImportStringList | null;
|
|
363
364
|
/** Hook for fetching data.
|
|
364
365
|
*
|
|
365
366
|
* https://vike.dev/data
|
|
366
367
|
*/
|
|
367
|
-
data?: DataAsync<unknown> | DataSync<unknown> |
|
|
368
|
+
data?: DataAsync<unknown> | DataSync<unknown> | ImportStringList | null;
|
|
368
369
|
/** Hook called as soon as `pageContext.data` is available.
|
|
369
370
|
*
|
|
370
371
|
* https://vike.dev/onData
|
|
@@ -374,83 +375,83 @@ type ConfigBuiltIn = {
|
|
|
374
375
|
*
|
|
375
376
|
* https://vike.dev/passToClient
|
|
376
377
|
*/
|
|
377
|
-
passToClient?: PassToClientPublic |
|
|
378
|
+
passToClient?: PassToClientPublic | ImportStringList;
|
|
378
379
|
/** Hook called when page is rendered on the client-side.
|
|
379
380
|
*
|
|
380
381
|
* https://vike.dev/onRenderClient
|
|
381
382
|
*/
|
|
382
|
-
onRenderClient?: OnRenderClientAsync | OnRenderClientSync |
|
|
383
|
+
onRenderClient?: OnRenderClientAsync | OnRenderClientSync | ImportStringList;
|
|
383
384
|
/** Hook called when page is rendered to HTML on the server-side.
|
|
384
385
|
*
|
|
385
386
|
* https://vike.dev/onRenderHtml
|
|
386
387
|
*/
|
|
387
|
-
onRenderHtml?: OnRenderHtmlAsync | OnRenderHtmlSync |
|
|
388
|
+
onRenderHtml?: OnRenderHtmlAsync | OnRenderHtmlSync | ImportStringList;
|
|
388
389
|
/** Enable async Route Functions.
|
|
389
390
|
*
|
|
390
391
|
* https://vike.dev/route-function#async
|
|
391
392
|
*/
|
|
392
|
-
iKnowThePerformanceRisksOfAsyncRouteFunctions?: boolean |
|
|
393
|
+
iKnowThePerformanceRisksOfAsyncRouteFunctions?: boolean | ImportStringList;
|
|
393
394
|
/** Change the URL root of Filesystem Routing.
|
|
394
395
|
*
|
|
395
396
|
* https://vike.dev/filesystemRoutingRoot
|
|
396
397
|
*/
|
|
397
|
-
filesystemRoutingRoot?: string |
|
|
398
|
+
filesystemRoutingRoot?: string | ImportStringList;
|
|
398
399
|
/** Page Hook called when pre-rendering starts.
|
|
399
400
|
*
|
|
400
401
|
* https://vike.dev/onPrerenderStart
|
|
401
402
|
*/
|
|
402
|
-
onPrerenderStart?: OnPrerenderStartAsync | OnPrerenderStartSync |
|
|
403
|
+
onPrerenderStart?: OnPrerenderStartAsync | OnPrerenderStartSync | ImportStringList;
|
|
403
404
|
/** Global Hook called before the whole pre-rendering process starts.
|
|
404
405
|
*
|
|
405
406
|
* https://vike.dev/onBeforePrerenderStart
|
|
406
407
|
*/
|
|
407
|
-
onBeforePrerenderStart?: OnBeforePrerenderStartAsync | OnBeforePrerenderStartSync |
|
|
408
|
+
onBeforePrerenderStart?: OnBeforePrerenderStartAsync | OnBeforePrerenderStartSync | ImportStringList;
|
|
408
409
|
/** Hook called before the URL is routed to a page.
|
|
409
410
|
*
|
|
410
411
|
* https://vike.dev/onBeforeRoute
|
|
411
412
|
*/
|
|
412
|
-
onBeforeRoute?: OnBeforeRouteAsync | OnBeforeRouteSync |
|
|
413
|
+
onBeforeRoute?: OnBeforeRouteAsync | OnBeforeRouteSync | ImportStringList;
|
|
413
414
|
/** Hook called after the page is hydrated.
|
|
414
415
|
*
|
|
415
416
|
* https://vike.dev/onHydrationEnd
|
|
416
417
|
*/
|
|
417
|
-
onHydrationEnd?: OnHydrationEndAsync | OnHydrationEndSync |
|
|
418
|
+
onHydrationEnd?: OnHydrationEndAsync | OnHydrationEndSync | ImportStringList;
|
|
418
419
|
/** Hook called before the user navigates to a new page.
|
|
419
420
|
*
|
|
420
421
|
* https://vike.dev/onPageTransitionStart
|
|
421
422
|
*/
|
|
422
|
-
onPageTransitionStart?: OnPageTransitionStartAsync | OnPageTransitionStartSync |
|
|
423
|
+
onPageTransitionStart?: OnPageTransitionStartAsync | OnPageTransitionStartSync | ImportStringList;
|
|
423
424
|
/** Hook called after the user navigates to a new page.
|
|
424
425
|
*
|
|
425
426
|
* https://vike.dev/onPageTransitionEnd
|
|
426
427
|
*/
|
|
427
|
-
onPageTransitionEnd?: OnPageTransitionEndAsync | OnPageTransitionEndSync |
|
|
428
|
+
onPageTransitionEnd?: OnPageTransitionEndAsync | OnPageTransitionEndSync | ImportStringList;
|
|
428
429
|
/** Whether the UI framework (React/Vue/Solid/...) allows the page's hydration to be aborted.
|
|
429
430
|
*
|
|
430
431
|
* https://vike.dev/hydrationCanBeAborted
|
|
431
432
|
*/
|
|
432
|
-
hydrationCanBeAborted?: boolean |
|
|
433
|
+
hydrationCanBeAborted?: boolean | ImportStringList;
|
|
433
434
|
/** Add client code.
|
|
434
435
|
*
|
|
435
436
|
* https://vike.dev/client
|
|
436
437
|
*/
|
|
437
|
-
client?: string |
|
|
438
|
+
client?: string | ImportStringList;
|
|
438
439
|
/** Enable Client Routing.
|
|
439
440
|
*
|
|
440
441
|
* https://vike.dev/clientRouting
|
|
441
442
|
*/
|
|
442
|
-
clientRouting?: boolean |
|
|
443
|
+
clientRouting?: boolean | ImportStringList;
|
|
443
444
|
/**
|
|
444
445
|
* Whether hooks are loaded on the client-side.
|
|
445
446
|
*
|
|
446
447
|
* https://vike.dev/clientHooks
|
|
447
448
|
*/
|
|
448
|
-
clientHooks?: boolean | null |
|
|
449
|
+
clientHooks?: boolean | null | ImportStringList;
|
|
449
450
|
/** Create new or modify existing configurations.
|
|
450
451
|
*
|
|
451
452
|
* https://vike.dev/meta
|
|
452
453
|
*/
|
|
453
|
-
meta?: ConfigMeta |
|
|
454
|
+
meta?: ConfigMeta | ImportStringList;
|
|
454
455
|
/** Vite configuration.
|
|
455
456
|
*
|
|
456
457
|
* https://vite.dev/config/
|
|
@@ -498,13 +499,13 @@ type ConfigBuiltIn = {
|
|
|
498
499
|
*
|
|
499
500
|
* https://vike.dev/prefetch
|
|
500
501
|
*/
|
|
501
|
-
prefetch?: PrefetchSetting |
|
|
502
|
+
prefetch?: PrefetchSetting | ImportStringList;
|
|
502
503
|
/** @deprecated Use `prefetch` setting (https://vike.dev/prefetch) instead. */
|
|
503
504
|
/** Prefetch links.
|
|
504
505
|
*
|
|
505
506
|
* https://vike.dev/prefetchStaticAssets
|
|
506
507
|
*/
|
|
507
|
-
prefetchStaticAssets?: PrefetchStaticAssets |
|
|
508
|
+
prefetchStaticAssets?: PrefetchStaticAssets | ImportStringList;
|
|
508
509
|
/** Modify the timeouts of hooks. */
|
|
509
510
|
hooksTimeout?: HooksTimeoutProvidedByUser;
|
|
510
511
|
/** `Cache-Control` HTTP header value.
|
|
@@ -587,14 +588,19 @@ type ConfigBuiltIn = {
|
|
|
587
588
|
cli?: {
|
|
588
589
|
preview?: CliPreviewConfig;
|
|
589
590
|
};
|
|
591
|
+
/**
|
|
592
|
+
* Static code transformations for optimizations like removing component children server-side.
|
|
593
|
+
*
|
|
594
|
+
* @experimental
|
|
595
|
+
*/
|
|
596
|
+
staticReplace?: StaticReplace[];
|
|
590
597
|
};
|
|
591
598
|
type ConfigBuiltInResolved = {
|
|
592
599
|
passToClient?: string[][];
|
|
593
600
|
redirects?: Record<string, string>[];
|
|
594
|
-
prerender?: Exclude<Config['prerender'],
|
|
601
|
+
prerender?: Exclude<Config['prerender'], ImportStringList | undefined>[];
|
|
595
602
|
middleware?: Function[];
|
|
596
|
-
headersResponse?: Exclude<Config['headersResponse'],
|
|
603
|
+
headersResponse?: Exclude<Config['headersResponse'], ImportStringList | undefined>[];
|
|
604
|
+
staticReplace?: StaticReplace[][];
|
|
597
605
|
};
|
|
598
606
|
type ConfigMeta = Record<string, ConfigDefinition>;
|
|
599
|
-
type ImportString = ImportStringVal | ImportStringVal[];
|
|
600
|
-
type ImportStringVal = `import:${string}`;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ export type { PrerenderContextPublic as PrerenderContext } from '../node/prerend
|
|
|
4
4
|
export type { PageContextBuiltInServer } from './PageContext.js';
|
|
5
5
|
export type { PageContextBuiltInClientWithClientRouting } from './PageContext.js';
|
|
6
6
|
export type { PageContextBuiltInClientWithServerRouting } from './PageContext.js';
|
|
7
|
-
export type { Config, ConfigMeta as Meta,
|
|
7
|
+
export type { Config, ConfigMeta as Meta, KeepScrollPosition, } from './Config.js';
|
|
8
|
+
export type { ImportString } from '../node/vite/shared/importString.js';
|
|
8
9
|
export type { DataAsync, DataSync, GuardAsync, GuardSync, OnBeforePrerenderStartAsync, OnBeforePrerenderStartSync, OnBeforeRenderAsync, OnBeforeRenderSync, OnBeforeRouteAsync, OnBeforeRouteSync, OnHydrationEndAsync, OnHydrationEndSync, OnPageTransitionEndAsync, OnPageTransitionEndSync, OnPageTransitionStartAsync, OnPageTransitionStartSync, OnPrerenderStartAsync, OnPrerenderStartSync, OnRenderClientAsync, OnRenderClientSync, OnRenderHtmlAsync, OnRenderHtmlSync, RouteAsync, RouteSync, } from './Config.js';
|
|
9
10
|
export type { ConfigResolved } from './Config/ConfigResolved.js';
|
|
10
11
|
export type { ConfigEnv } from './PageConfig.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const PROJECT_VERSION: "0.4.249-commit-
|
|
1
|
+
export declare const PROJECT_VERSION: "0.4.249-commit-ec50591";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// Automatically updated by @brillout/release-me
|
|
2
|
-
export const PROJECT_VERSION = '0.4.249-commit-
|
|
2
|
+
export const PROJECT_VERSION = '0.4.249-commit-ec50591';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vike",
|
|
3
|
-
"version": "0.4.249-commit-
|
|
3
|
+
"version": "0.4.249-commit-ec50591",
|
|
4
4
|
"repository": "https://github.com/vikejs/vike",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./server": {
|
|
@@ -118,12 +118,12 @@
|
|
|
118
118
|
}
|
|
119
119
|
},
|
|
120
120
|
"dependencies": {
|
|
121
|
+
"@babel/core": "^7.28.5",
|
|
121
122
|
"@brillout/import": "^0.2.6",
|
|
122
123
|
"@brillout/json-serializer": "^0.5.21",
|
|
123
124
|
"@brillout/picocolors": "^1.0.30",
|
|
124
125
|
"@brillout/require-shim": "^0.1.2",
|
|
125
126
|
"@brillout/vite-plugin-server-entry": "^0.7.15",
|
|
126
|
-
"acorn": "^8.0.0",
|
|
127
127
|
"cac": "^6.0.0",
|
|
128
128
|
"es-module-lexer": "^1.0.0",
|
|
129
129
|
"esbuild": ">=0.19.0",
|
|
@@ -244,7 +244,9 @@
|
|
|
244
244
|
"./universal-middleware.js"
|
|
245
245
|
],
|
|
246
246
|
"devDependencies": {
|
|
247
|
+
"@babel/types": "^7.28.5",
|
|
247
248
|
"@brillout/release-me": "^0.4.12",
|
|
249
|
+
"@types/babel__core": "^7.20.5",
|
|
248
250
|
"@types/estree": "^1.0.5",
|
|
249
251
|
"@types/node": "^20.10.5",
|
|
250
252
|
"@types/picomatch": "^3.0.2",
|