vike 0.4.249-commit-55681da → 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.
@@ -18,7 +18,7 @@ type ScrollPosition = {
18
18
  };
19
19
  declare function saveScrollPosition(): void;
20
20
  declare function pushHistoryState(url: string, overwriteLastHistoryEntry: boolean): void;
21
- declare function replaceHistoryStateOriginal(state: unknown, url: Parameters<typeof window.history.replaceState>[2]): void;
21
+ declare function replaceHistoryStateOriginal(state: unknown, url?: Parameters<typeof window.history.replaceState>[2]): void;
22
22
  type HistoryInfo = {
23
23
  url: `/${string}`;
24
24
  state: StateEnhanced;
@@ -4,7 +4,7 @@ export { onPopStateBegin };
4
4
  export { saveScrollPosition };
5
5
  export { initHistory };
6
6
  import { getCurrentUrl } from '../shared/getCurrentUrl.js';
7
- import { assert, assertUsage, getGlobalObject, isObject, deepEqual, redirectHard } from './utils.js';
7
+ import { assert, assertUsage, getGlobalObject, isObject, redirectHard } from './utils.js';
8
8
  const globalObject = getGlobalObject('history.ts', {
9
9
  monkeyPatched: false,
10
10
  previous: undefined,
@@ -102,26 +102,19 @@ function monkeyPatchHistoryAPI() {
102
102
  triggeredBy: 'user',
103
103
  },
104
104
  };
105
- assertIsEnhanced(state);
106
105
  funcOriginal(state, ...rest);
107
- // TO-DO/eventually remove excessive assertions to save client-side KBs
108
- assert(isEqual(state, window.history.state));
106
+ assertIsEnhanced(window.history.state);
109
107
  globalObject.previous = getHistoryInfo();
110
108
  // Workaround https://github.com/vikejs/vike/issues/2504#issuecomment-3149764736
111
109
  queueMicrotask(() => {
112
- if (isEqual(state, window.history.state))
110
+ if (isEnhanced(window.history.state))
113
111
  return;
114
112
  Object.assign(state, window.history.state);
115
- assertIsEnhanced(state);
116
- replaceHistoryStateOriginal(state, rest[1]);
117
- assert(isEqual(state, window.history.state));
113
+ replaceHistoryStateOriginal(state);
118
114
  });
119
115
  };
120
116
  });
121
117
  }
122
- function isEqual(state1, state2) {
123
- return deepEqual(state1?.vike, state2?.vike);
124
- }
125
118
  function isEnhanced(state) {
126
119
  if (state?.vike) {
127
120
  /* We don't use the assert() below to save client-side KBs.
@@ -21,5 +21,4 @@ export * from '../../utils/PROJECT_VERSION.js';
21
21
  export * from '../../utils/genPromise.js';
22
22
  export * from '../../utils/catchInfiniteLoop.js';
23
23
  export * from '../../utils/changeEnumerable.js';
24
- export * from '../../utils/deepEqual.js';
25
24
  export * from '../../utils/cast.js';
@@ -25,5 +25,4 @@ export * from '../../utils/PROJECT_VERSION.js';
25
25
  export * from '../../utils/genPromise.js';
26
26
  export * from '../../utils/catchInfiniteLoop.js';
27
27
  export * from '../../utils/changeEnumerable.js';
28
- export * from '../../utils/deepEqual.js';
29
28
  export * from '../../utils/cast.js';
@@ -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;