vite-plugin-taro 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/dist/node/plugins/h5/transform-app.js +1 -1
  2. package/dist/node/plugins/wx/dev/plugins.js +1 -1
  3. package/dist/node/plugins/wx/dev/wx-dev-options.js +1 -1
  4. package/dist/node/plugins/wx/{module.js → module/module.js} +2 -2
  5. package/dist/node/plugins/wx/placer/placement.d.ts +1 -0
  6. package/dist/node/plugins/wx/placer/placement.js +1 -1
  7. package/dist/node/plugins/wx/placer/placer.d.ts +17 -1
  8. package/dist/node/plugins/wx/placer/placer.js +25 -1
  9. package/dist/node/plugins/wx/plugins.js +1 -1
  10. package/dist/node/plugins/wx/render/capsule.d.ts +35 -3
  11. package/dist/node/plugins/wx/render/capsule.js +53 -12
  12. package/dist/node/plugins/wx/render/native.d.ts +20 -2
  13. package/dist/node/plugins/wx/render/native.js +539 -35
  14. package/dist/node/plugins/wx/render/system-js/string-editor.d.ts +24 -0
  15. package/dist/node/plugins/wx/render/system-js/string-editor.js +93 -0
  16. package/dist/node/plugins/wx/render/system-js/system-js.d.ts +23 -0
  17. package/dist/node/plugins/wx/render/system-js/system-js.js +602 -0
  18. package/dist/node/plugins/wx/render/transport.js +3 -3
  19. package/dist/node/plugins/wx/resolve/resolver.js +1 -1
  20. package/dist/node/plugins/wx/resolve/specialize-bootstrap.js +1 -1
  21. package/dist/node/plugins/wx/resolve/specialize-page-capsule.js +1 -1
  22. package/dist/node/utils/transform.d.ts +0 -3
  23. package/dist/node/utils/transform.js +0 -23
  24. package/package.json +8 -6
  25. package/src/node/plugins/h5/transform-app.ts +1 -1
  26. package/src/node/plugins/wx/dev/plugins.ts +1 -1
  27. package/src/node/plugins/wx/dev/wx-dev-options.ts +1 -1
  28. package/src/node/plugins/wx/{module.ts → module/module.ts} +2 -2
  29. package/src/node/plugins/wx/placer/placement.ts +1 -1
  30. package/src/node/plugins/wx/placer/placer.ts +27 -2
  31. package/src/node/plugins/wx/plugins.ts +1 -1
  32. package/src/node/plugins/wx/render/capsule.ts +53 -17
  33. package/src/node/plugins/wx/render/native.ts +670 -55
  34. package/src/node/plugins/wx/render/system-js/string-editor.ts +115 -0
  35. package/src/node/plugins/wx/render/system-js/system-js.ts +831 -0
  36. package/src/node/plugins/wx/render/transport.ts +3 -3
  37. package/src/node/plugins/wx/resolve/resolver.ts +1 -1
  38. package/src/node/plugins/wx/resolve/specialize-bootstrap.ts +1 -1
  39. package/src/node/plugins/wx/resolve/specialize-page-capsule.ts +1 -1
  40. package/src/node/utils/transform.ts +0 -30
  41. package/dist/node/plugins/wx/render/capsule-wrapper.d.ts +0 -3
  42. package/dist/node/plugins/wx/render/capsule-wrapper.js +0 -64
  43. package/src/node/plugins/wx/render/capsule-wrapper.ts +0 -86
  44. /package/dist/node/plugins/wx/{chunk-path.d.ts → module/chunk-path.d.ts} +0 -0
  45. /package/dist/node/plugins/wx/{chunk-path.js → module/chunk-path.js} +0 -0
  46. /package/dist/node/plugins/wx/{module.d.ts → module/module.d.ts} +0 -0
  47. /package/src/node/plugins/wx/{chunk-path.ts → module/chunk-path.ts} +0 -0
@@ -1,45 +1,549 @@
1
- import { types } from '@babel/core';
2
- import transformModulesCommonjs from '@babel/plugin-transform-modules-commonjs';
3
- import { transformWithBabel } from '../../../utils/transform.js';
4
- import { resolveLogicalChunkReference, resolvePhysicalChunkReference } from '../chunk-path.js';
5
- import { getWxEntryRole } from '../module.js';
6
- /** Renders a native module while activating its statically imported capsules through SystemJS. */
1
+ import { isReferenceIdentifier, ScopeTracker, walk } from 'oxc-walker';
2
+ import { RolldownMagicString } from 'rolldown';
3
+ import { parseSync } from 'rolldown/utils';
4
+ import { resolveLogicalChunkReference, resolvePhysicalChunkReference } from '../module/chunk-path.js';
5
+ import { getWxEntryRole } from '../module/module.js';
6
+ /**
7
+ * Materializes one final native/amphibious Rolldown chunk as executable WX CommonJS.
8
+ *
9
+ * The transform performs four semantic operations:
10
+ *
11
+ * 1. Static ESM imports are hoisted into source-order `require` calls. Named imports remain property reads from the required
12
+ * namespace so they observe current values. Default and namespace imports receive Babel-compatible CommonJS interop.
13
+ * 2. An import whose target owns a capsule entry is not passed to native `require`. It becomes
14
+ * `global.System.importSync(logicalChunkId)`, synchronously linking the capsule before the native lifecycle call.
15
+ * 3. Local exports are published at declaration and mutation points. Imported re-exports use getters, while assignments and
16
+ * updates notify every alias without changing expression completion values or accidentally matching shadowed bindings.
17
+ * 4. ESM top-level `this` becomes `undefined`. Direct imported calls and tags are explicitly unbound so converting an import
18
+ * into a namespace property does not introduce a false CommonJS receiver.
19
+ *
20
+ * Static dependency loading is emitted before the untouched module body because ESM evaluates dependencies before body
21
+ * statements regardless of where import declarations appear textually. Generated helper names are allocated against every
22
+ * source identifier. Source maps use the same range edits when requested; WX development disables them and keeps this path
23
+ * focused on startup latency.
24
+ */
7
25
  export function renderNative({ code, chunk, chunks, sourcemap }) {
8
- return transformWithBabel(code, chunk.fileName, [connectNativeCapsulesPlugin(chunk.fileName, chunks), transformModulesCommonjs], sourcemap);
26
+ const parsed = parseSync(chunk.fileName, code);
27
+ if (parsed.errors.length > 0) {
28
+ const diagnostics = parsed.errors.map((error) => error.message).join('; ');
29
+ throw new Error(`Failed to parse ${chunk.fileName} with Oxc: ${diagnostics}`);
30
+ }
31
+ // Analysis owns grammar validation, scope resolution, helper allocation, and physical-to-logical capsule classification.
32
+ // It completes before an editor exists, so failure cannot leak a partially rewritten chunk into Rolldown's output graph.
33
+ const model = analyzeNativeModule(parsed.program, chunk, chunks);
34
+ const editor = new RolldownMagicString(code, { filename: chunk.fileName });
35
+ // Expression edits split untouched source ranges first. Declaration replacement runs afterwards because MagicString must
36
+ // not split a range after that complete range has already been overwritten or removed.
37
+ rewriteExpressionSemantics(editor, model, chunk.fileName);
38
+ rewriteTopLevelThis(editor, model.program);
39
+ rewriteModuleDeclarations(editor, model);
40
+ const hasExports = model.exportNamesByLocal.size > 0;
41
+ const helpers = renderInteropHelpers(model);
42
+ const postfixTemp = model.usesPostfixTemp ? `var ${model.postfixTemp};` : '';
43
+ const imports = renderImports(model);
44
+ if (hasExports) {
45
+ editor.prepend(`"use strict";Object.defineProperty(exports,"__esModule",{value:true});${helpers}${postfixTemp}${imports}`);
46
+ }
47
+ else {
48
+ editor.prepend(`"use strict";${helpers}${postfixTemp}${imports}`);
49
+ }
50
+ return {
51
+ code: editor.toString(),
52
+ map: sourcemap ? createSourceMap(editor, chunk.fileName) : null
53
+ };
9
54
  }
10
- /** Converts only cross-runtime static imports; ordinary native dependencies remain CommonJS imports. */
11
- function connectNativeCapsulesPlugin(fileName, chunks) {
55
+ /**
56
+ * Builds the immutable semantic model consumed by all rewrite passes.
57
+ *
58
+ * Import classification needs the complete rendered chunk graph: a relative path alone cannot reveal whether native require
59
+ * should execute the target or SystemJS should link it as a capsule. ScopeTracker is frozen after declaration collection so
60
+ * later reference walks can distinguish module cells from same-named parameters and nested locals.
61
+ */
62
+ function analyzeNativeModule(program, chunk, chunks) {
63
+ const identifierNames = collectIdentifierNames(program);
64
+ const exportNamesByLocal = new Map();
65
+ const imports = [];
66
+ const importBindingsByLocal = new Map();
67
+ let hasDirectEval = false;
68
+ walk(program, {
69
+ enter(node) {
70
+ if (node.type === 'CallExpression' && node.callee.type === 'Identifier' && node.callee.name === 'eval') {
71
+ hasDirectEval = true;
72
+ }
73
+ }
74
+ });
75
+ if (hasDirectEval)
76
+ throw unsupported(chunk.fileName, 'direct eval');
77
+ for (const node of program.body) {
78
+ switch (node.type) {
79
+ case 'ImportDeclaration': {
80
+ requirePlainImport(node, chunk.fileName);
81
+ const capsule = getImportedCapsule(chunk.fileName, node.source.value, chunks);
82
+ if (capsule) {
83
+ const [specifier] = node.specifiers;
84
+ if (node.specifiers.length !== 1 || !specifier || specifier.type === 'ImportNamespaceSpecifier') {
85
+ throw new Error(`Expected one capsule value import from ${capsule.fileName} in ${chunk.fileName}`);
86
+ }
87
+ imports.push({
88
+ bindings: [],
89
+ capsuleBinding: {
90
+ imported: specifier.type === 'ImportDefaultSpecifier'
91
+ ? 'default'
92
+ : moduleExportName(specifier.imported),
93
+ local: specifier.local.name,
94
+ logicalId: resolveLogicalChunkReference(chunk.fileName, node.source.value)
95
+ },
96
+ interop: 'none',
97
+ namespace: '',
98
+ reference: node.source.value
99
+ });
100
+ continue;
101
+ }
102
+ const namespace = takeGeneratedName('__nativeImport', identifierNames);
103
+ const bindings = node.specifiers.map((specifier) => {
104
+ const binding = {
105
+ imported: specifier.type === 'ImportNamespaceSpecifier'
106
+ ? null
107
+ : specifier.type === 'ImportDefaultSpecifier'
108
+ ? 'default'
109
+ : moduleExportName(specifier.imported),
110
+ local: specifier.local.name,
111
+ namespace
112
+ };
113
+ importBindingsByLocal.set(binding.local, binding);
114
+ return binding;
115
+ });
116
+ imports.push({
117
+ bindings,
118
+ capsuleBinding: null,
119
+ interop: importInterop(node),
120
+ namespace,
121
+ reference: node.source.value
122
+ });
123
+ break;
124
+ }
125
+ case 'ExportNamedDeclaration':
126
+ collectFinalExports(node, exportNamesByLocal, chunk.fileName);
127
+ break;
128
+ case 'ExportDefaultDeclaration':
129
+ case 'ExportAllDeclaration':
130
+ throw unsupported(chunk.fileName, `source-level ${node.type}`);
131
+ }
132
+ }
133
+ const defaultInterop = takeGeneratedName('__nativeDefault', identifierNames);
134
+ const namespaceInterop = takeGeneratedName('__nativeNamespace', identifierNames);
135
+ const postfixTemp = takeGeneratedName('__nativePostfix', identifierNames);
136
+ const scopes = new ScopeTracker({ preserveExitedScopes: true });
137
+ walk(program, { scopeTracker: scopes });
138
+ scopes.freeze();
139
+ const usesPostfixTemp = hasPostfixExportUpdate(program, scopes, exportNamesByLocal);
12
140
  return {
13
- name: 'vpt:connect-native-capsules',
14
- visitor: {
15
- ImportDeclaration(importPath) {
16
- const reference = importPath.node.source.value;
17
- if (!reference.startsWith('./') && !reference.startsWith('../')) {
18
- return;
141
+ defaultInterop,
142
+ exportNamesByLocal,
143
+ imports,
144
+ importBindingsByLocal,
145
+ namespaceInterop,
146
+ postfixTemp,
147
+ program,
148
+ scopes,
149
+ usesPostfixTemp
150
+ };
151
+ }
152
+ /**
153
+ * Removes syntax that WX cannot parse and adds declaration-time CommonJS publication without regenerating other source.
154
+ * Import execution itself is emitted in the generated header; removing declarations here retains comments and all unrelated
155
+ * Rolldown output byte-for-byte. Final export lists publish only imported getters because local cells were already instrumented
156
+ * at their declarations and writes.
157
+ */
158
+ function rewriteModuleDeclarations(editor, model) {
159
+ for (const node of model.program.body) {
160
+ switch (node.type) {
161
+ case 'ImportDeclaration':
162
+ // Static imports execute before every module body statement regardless of their textual position.
163
+ editor.remove(node.start, node.end);
164
+ break;
165
+ case 'ExportNamedDeclaration':
166
+ if (node.declaration) {
167
+ // Strip only the export keyword; declaration publication is handled at its initializer or end boundary.
168
+ editor.remove(node.start, node.declaration.start);
169
+ rewriteExportedDeclaration(editor, node.declaration, model.exportNamesByLocal);
19
170
  }
20
- const physicalChunkId = resolvePhysicalChunkReference(fileName, reference);
21
- const importedChunk = chunks[physicalChunkId];
22
- if (!importedChunk || getWxEntryRole(importedChunk) !== 'capsule') {
23
- return;
171
+ else {
172
+ editor.overwrite(node.start, node.end, renderExportList(node.specifiers, model));
24
173
  }
25
- const [specifier] = importPath.node.specifiers;
26
- if (importPath.node.specifiers.length !== 1 ||
27
- !specifier ||
28
- types.isImportNamespaceSpecifier(specifier)) {
29
- throw new Error(`Expected one capsule value import from ${physicalChunkId} in ${fileName}`);
174
+ break;
175
+ case 'VariableDeclaration':
176
+ publishVariableInitializers(editor, node, model.exportNamesByLocal);
177
+ break;
178
+ case 'FunctionDeclaration':
179
+ if (node.id)
180
+ publishAfter(editor, node.end, node.id.name, model.exportNamesByLocal);
181
+ break;
182
+ case 'ClassDeclaration':
183
+ if (node.id)
184
+ publishAfter(editor, node.end, node.id.name, model.exportNamesByLocal);
185
+ break;
186
+ }
187
+ }
188
+ }
189
+ /**
190
+ * Rewrites imported references and live-export mutations in one scope-aware O(n) pass.
191
+ *
192
+ * A named import such as `fn` becomes a namespace property read. In call or tag position it is wrapped as `(0, ns.fn)` to
193
+ * preserve ESM's unbound receiver; in `new fn()` it remains `ns.fn` because construction has no method receiver. Exported
194
+ * writes are instrumented only when ScopeTracker resolves the target to the root module declaration.
195
+ */
196
+ function rewriteExpressionSemantics(editor, model, filename) {
197
+ // This mutable traversal stack exists only to see through explicit ParenthesizedExpression nodes around imported calls.
198
+ const ancestors = [];
199
+ walk(model.program, {
200
+ scopeTracker: model.scopes,
201
+ enter(node, parent) {
202
+ if (node.type === 'Identifier' &&
203
+ parent?.type !== 'ImportDeclaration' &&
204
+ isReferenceIdentifier(node, parent)) {
205
+ const binding = model.importBindingsByLocal.get(node.name);
206
+ const declaration = binding ? model.scopes.getDeclaration(node.name) : null;
207
+ if (binding && declaration?.type === 'Import') {
208
+ const context = importedReferenceContext(node, parent, ancestors);
209
+ const imported = importedExpression(binding);
210
+ const replacement = context === 'unbound' ? `(0,${imported})` : imported;
211
+ // Replacing `{ imported }` with `{ imported: namespace.imported }` preserves shorthand property keys.
212
+ editor.overwrite(node.start, node.end, parent?.type === 'Property' && parent.shorthand && parent.value === node
213
+ ? `${node.name}:${replacement}`
214
+ : replacement);
30
215
  }
31
- const imported = types.isImportDefaultSpecifier(specifier)
32
- ? types.identifier('default')
33
- : specifier.imported;
34
- const importedConfig = types.memberExpression(createSyncImport(resolveLogicalChunkReference(fileName, reference)), types.cloneNode(imported), types.isStringLiteral(imported));
35
- importPath.replaceWith(types.variableDeclaration('const', [
36
- types.variableDeclarator(types.cloneNode(specifier.local), importedConfig)
37
- ]));
38
216
  }
217
+ switch (node.type) {
218
+ case 'AssignmentExpression':
219
+ rewriteExportAssignment(editor, node.left, node.start, model, filename);
220
+ break;
221
+ case 'UpdateExpression':
222
+ rewriteExportUpdate(editor, node, model);
223
+ break;
224
+ case 'ForInStatement':
225
+ case 'ForOfStatement':
226
+ if (node.left.type !== 'VariableDeclaration') {
227
+ requireNoExportedPattern(node.left, model, filename);
228
+ }
229
+ break;
230
+ }
231
+ ancestors.push(node);
232
+ },
233
+ leave() {
234
+ ancestors.pop();
39
235
  }
40
- };
236
+ });
41
237
  }
42
- /** Creates one synchronous lookup through the canonical output chunk ID. */
43
- function createSyncImport(chunkId) {
44
- return types.callExpression(types.memberExpression(types.memberExpression(types.identifier('global'), types.identifier('System')), types.identifier('importSync')), [types.stringLiteral(chunkId)]);
238
+ /** Prefixes a direct exported assignment; assignment operators already preserve their own completion value. */
239
+ function rewriteExportAssignment(editor, target, start, model, filename) {
240
+ if (target.type === 'Identifier') {
241
+ const names = exportedRootNames(target.name, model);
242
+ if (names.length > 0)
243
+ editor.prependLeft(start, exportAssignmentPrefix(names));
244
+ return;
245
+ }
246
+ requireNoExportedPattern(target, model, filename);
247
+ }
248
+ /** Publishes the updated cell while retaining the distinct prefix/postfix expression result. */
249
+ function rewriteExportUpdate(editor, update, model) {
250
+ if (update.argument.type !== 'Identifier')
251
+ return;
252
+ const names = exportedRootNames(update.argument.name, model);
253
+ if (names.length === 0)
254
+ return;
255
+ if (update.prefix) {
256
+ editor.prependLeft(update.start, exportAssignmentPrefix(names));
257
+ return;
258
+ }
259
+ editor.prependLeft(update.start, `(${model.postfixTemp}=`);
260
+ editor.appendRight(update.end, `,${exportAssignmentExpression(names, update.argument.name)},${model.postfixTemp})`);
261
+ }
262
+ /** Rejects destructuring writes because wrapping them would change their completion value. */
263
+ function requireNoExportedPattern(target, model, filename) {
264
+ const exported = bindingNames(target).filter((name) => exportedRootNames(name, model).length > 0);
265
+ if (exported.length > 0) {
266
+ throw unsupported(filename, `destructuring write to exported binding ${JSON.stringify(exported[0])}`);
267
+ }
268
+ }
269
+ function exportedRootNames(local, model) {
270
+ const names = model.exportNamesByLocal.get(local) ?? [];
271
+ if (names.length === 0)
272
+ return names;
273
+ return model.scopes.getDeclaration(local)?.scope === '' ? names : [];
274
+ }
275
+ /** Detects whether the generated declaration header needs one postfix completion-value cell. */
276
+ function hasPostfixExportUpdate(program, scopes, exportNamesByLocal) {
277
+ let found = false;
278
+ walk(program, {
279
+ scopeTracker: scopes,
280
+ enter(node) {
281
+ if (found || node.type !== 'UpdateExpression' || node.prefix || node.argument.type !== 'Identifier')
282
+ return;
283
+ const names = exportNamesByLocal.get(node.argument.name) ?? [];
284
+ if (names.length > 0 && scopes.getDeclaration(node.argument.name)?.scope === '')
285
+ found = true;
286
+ }
287
+ });
288
+ return found;
289
+ }
290
+ /** Rewrites ESM top-level this, including arrow functions that lexically inherit it. */
291
+ function rewriteTopLevelThis(editor, program) {
292
+ let thisBoundaryDepth = 0;
293
+ walk(program, {
294
+ enter(node) {
295
+ if (isThisBoundary(node))
296
+ thisBoundaryDepth += 1;
297
+ if (node.type === 'ThisExpression' && thisBoundaryDepth === 0)
298
+ editor.overwrite(node.start, node.end, 'void 0');
299
+ },
300
+ leave(node) {
301
+ if (isThisBoundary(node))
302
+ thisBoundaryDepth -= 1;
303
+ }
304
+ });
305
+ }
306
+ /** Records aliases from Rolldown's normalized terminal `export { ... }` declaration. */
307
+ function collectFinalExports(declaration, exportNamesByLocal, filename) {
308
+ if (declaration.source || declaration.attributes.length > 0 || declaration.exportKind === 'type') {
309
+ throw unsupported(filename, 're-exports, export attributes, or type-only exports');
310
+ }
311
+ if (declaration.declaration) {
312
+ for (const local of declarationBindingNames(declaration.declaration, filename)) {
313
+ const names = exportNamesByLocal.get(local) ?? [];
314
+ names.push(local);
315
+ if (!exportNamesByLocal.has(local))
316
+ exportNamesByLocal.set(local, names);
317
+ }
318
+ return;
319
+ }
320
+ for (const specifier of declaration.specifiers) {
321
+ const local = moduleExportName(specifier.local);
322
+ const names = exportNamesByLocal.get(local) ?? [];
323
+ names.push(moduleExportName(specifier.exported));
324
+ if (!exportNamesByLocal.has(local))
325
+ exportNamesByLocal.set(local, names);
326
+ }
327
+ }
328
+ /** Applies publication edits to a declaration wrapped by `export`. */
329
+ function rewriteExportedDeclaration(editor, declaration, exportNamesByLocal) {
330
+ switch (declaration.type) {
331
+ case 'VariableDeclaration':
332
+ publishVariableInitializers(editor, declaration, exportNamesByLocal);
333
+ break;
334
+ case 'FunctionDeclaration':
335
+ case 'ClassDeclaration':
336
+ if (declaration.id)
337
+ publishAfter(editor, declaration.end, declaration.id.name, exportNamesByLocal);
338
+ break;
339
+ }
340
+ }
341
+ /** Emits execute-time export assignments, using getters for imported cells to preserve live reads. */
342
+ function renderExportList(specifiers, model) {
343
+ return specifiers
344
+ .map((specifier) => {
345
+ const local = moduleExportName(specifier.local);
346
+ const exported = moduleExportName(specifier.exported);
347
+ const imported = model.importBindingsByLocal.get(local);
348
+ return imported
349
+ ? `Object.defineProperty(exports,${JSON.stringify(exported)},{enumerable:true,get:function(){return ${importedExpression(imported)}}});`
350
+ : '';
351
+ })
352
+ .join('');
353
+ }
354
+ /** Publishes top-level initialized variables at their original initialization point. */
355
+ function publishVariableInitializers(editor, declaration, exportNamesByLocal) {
356
+ for (const declarator of declaration.declarations) {
357
+ if (declarator.id.type !== 'Identifier') {
358
+ const exported = bindingNames(declarator.id).filter((name) => exportNamesByLocal.has(name));
359
+ if (exported.length > 0)
360
+ throw unsupported('native chunk', 'exported destructuring declaration');
361
+ continue;
362
+ }
363
+ const names = exportNamesByLocal.get(declarator.id.name) ?? [];
364
+ if (names.length === 0)
365
+ continue;
366
+ if (declarator.init) {
367
+ editor.prependLeft(declarator.init.start, exportAssignmentPrefix(names));
368
+ }
369
+ else {
370
+ editor.appendRight(declarator.end, `=${exportAssignmentExpression(names, 'void 0')}`);
371
+ }
372
+ }
373
+ }
374
+ /** Publishes declaration values that become initialized only after their declaration executes. */
375
+ function publishAfter(editor, end, local, exportNamesByLocal) {
376
+ const names = exportNamesByLocal.get(local) ?? [];
377
+ if (names.length > 0)
378
+ editor.appendRight(end, `;${exportAssignmentExpression(names, local)};`);
379
+ }
380
+ function exportAssignmentPrefix(names) {
381
+ return names.reduce((prefix, name) => `exports[${JSON.stringify(name)}]=${prefix}`, '');
382
+ }
383
+ function exportAssignmentExpression(names, value) {
384
+ return `${exportAssignmentPrefix(names)}${value}`;
385
+ }
386
+ /**
387
+ * Imported functions are ESM references, not namespace methods. A direct call must therefore discard the generated
388
+ * namespace receiver with `(0, value)()`. The same comma expression preserves unbound optional calls and tag invocation;
389
+ * constructors remain plain references because `new` does not derive a receiver from a member expression.
390
+ */
391
+ function importedReferenceContext(node, parent, ancestors) {
392
+ let expression = node;
393
+ let semanticParent = parent;
394
+ let ancestorIndex = ancestors.length - 1;
395
+ while (semanticParent?.type === 'ParenthesizedExpression' && semanticParent.expression === expression) {
396
+ expression = semanticParent;
397
+ ancestorIndex -= 1;
398
+ semanticParent = ancestors[ancestorIndex] ?? null;
399
+ }
400
+ if (semanticParent?.type === 'CallExpression' && semanticParent.callee === expression)
401
+ return 'unbound';
402
+ if (semanticParent?.type === 'NewExpression' && semanticParent.callee === expression)
403
+ return 'plain';
404
+ if (semanticParent?.type === 'TaggedTemplateExpression' && semanticParent.tag === expression)
405
+ return 'unbound';
406
+ return 'plain';
407
+ }
408
+ function importedExpression(binding) {
409
+ return binding.imported === null ? binding.namespace : memberExpression(binding.namespace, binding.imported);
410
+ }
411
+ function memberExpression(object, property) {
412
+ return /^[$A-Z_a-z][$\w]*$/.test(property) ? `${object}.${property}` : `${object}[${JSON.stringify(property)}]`;
413
+ }
414
+ function getImportedCapsule(fileName, reference, chunks) {
415
+ if (!reference.startsWith('./') && !reference.startsWith('../'))
416
+ return undefined;
417
+ const imported = chunks[resolvePhysicalChunkReference(fileName, reference)];
418
+ return imported && getWxEntryRole(imported) === 'capsule' ? imported : undefined;
419
+ }
420
+ /**
421
+ * Renders the dependency header in original import order.
422
+ *
423
+ * Side-effect imports always remain standalone `require` calls. Ordinary value imports share one required namespace per final
424
+ * import declaration, while cross-domain capsule imports synchronously ask SystemJS for the namespace under its package-neutral
425
+ * logical ID. Physical package placement remains the transport's responsibility.
426
+ */
427
+ function renderImports(model) {
428
+ return model.imports
429
+ .map((importModel) => {
430
+ if (importModel.capsuleBinding) {
431
+ const { imported, local, logicalId } = importModel.capsuleBinding;
432
+ const namespace = `global.System.importSync(${JSON.stringify(logicalId)})`;
433
+ return `var ${local}=${memberExpression(namespace, imported)};`;
434
+ }
435
+ const requireCall = `require(${JSON.stringify(importModel.reference)})`;
436
+ if (importModel.bindings.length === 0)
437
+ return `${requireCall};`;
438
+ const importedValue = importModel.interop === 'default'
439
+ ? `${model.defaultInterop}(${requireCall})`
440
+ : importModel.interop === 'namespace'
441
+ ? `${model.namespaceInterop}(${requireCall})`
442
+ : requireCall;
443
+ return `var ${importModel.namespace}=${importedValue};`;
444
+ })
445
+ .join('');
446
+ }
447
+ /** Selects Babel-compatible wrapping for default and namespace imports from CommonJS values. */
448
+ function importInterop(declaration) {
449
+ if (declaration.specifiers.some((specifier) => specifier.type === 'ImportNamespaceSpecifier'))
450
+ return 'namespace';
451
+ if (declaration.specifiers.some((specifier) => specifier.type === 'ImportDefaultSpecifier'))
452
+ return 'default';
453
+ return 'none';
454
+ }
455
+ /** Emits interop helpers only when an analyzed import needs them. */
456
+ function renderInteropHelpers(model) {
457
+ const kinds = new Set(model.imports.map(({ interop }) => interop));
458
+ const defaultHelper = kinds.has('default')
459
+ ? `function ${model.defaultInterop}(value){return value&&value.__esModule?value:{default:value};}`
460
+ : '';
461
+ const namespaceHelper = kinds.has('namespace')
462
+ ? `function ${model.namespaceInterop}(value){if(value&&value.__esModule)return value;var namespace={default:value};if(value!==null&&(typeof value==="object"||typeof value==="function")){for(var key in value)if(key!=="default"&&Object.prototype.hasOwnProperty.call(value,key))Object.defineProperty(namespace,key,{enumerable:true,get:function(key){return function(){return value[key]}}(key)});}return namespace;}`
463
+ : '';
464
+ return `${defaultHelper}${namespaceHelper}`;
465
+ }
466
+ function requirePlainImport(declaration, filename) {
467
+ if (declaration.phase || declaration.attributes.length > 0 || declaration.importKind === 'type') {
468
+ throw unsupported(filename, 'import phases, attributes, or type-only imports');
469
+ }
470
+ }
471
+ /** Collects every occupied identifier before helper allocation. */
472
+ function collectIdentifierNames(program) {
473
+ const names = new Set();
474
+ walk(program, {
475
+ enter(node) {
476
+ if (node.type === 'Identifier')
477
+ names.add(node.name);
478
+ }
479
+ });
480
+ return names;
481
+ }
482
+ function takeGeneratedName(base, used) {
483
+ let suffix = 0;
484
+ let candidate = base;
485
+ while (used.has(candidate)) {
486
+ suffix += 1;
487
+ candidate = `${base}${suffix}`;
488
+ }
489
+ used.add(candidate);
490
+ return candidate;
491
+ }
492
+ function moduleExportName(name) {
493
+ return name.type === 'Literal' ? String(name.value) : name.name;
494
+ }
495
+ function declarationBindingNames(declaration, filename) {
496
+ switch (declaration.type) {
497
+ case 'VariableDeclaration':
498
+ return declaration.declarations.flatMap(({ id }) => bindingNames(id));
499
+ case 'FunctionDeclaration':
500
+ case 'ClassDeclaration':
501
+ if (declaration.id)
502
+ return [declaration.id.name];
503
+ throw unsupported(filename, 'anonymous declaration export');
504
+ default:
505
+ throw unsupported(filename, `declaration export ${declaration.type}`);
506
+ }
507
+ }
508
+ function bindingNames(pattern) {
509
+ switch (pattern.type) {
510
+ case 'Identifier':
511
+ return [pattern.name];
512
+ case 'AssignmentPattern':
513
+ return bindingNames(pattern.left);
514
+ case 'ArrayPattern':
515
+ return pattern.elements.flatMap((element) => (element ? bindingNames(element) : []));
516
+ case 'ObjectPattern':
517
+ return pattern.properties.flatMap((property) => property.type === 'Property' ? bindingNames(property.value) : bindingNames(property.argument));
518
+ case 'RestElement':
519
+ return bindingNames(pattern.argument);
520
+ default:
521
+ return [];
522
+ }
523
+ }
524
+ function isThisBoundary(node) {
525
+ return (node.type === 'FunctionDeclaration' ||
526
+ node.type === 'FunctionExpression' ||
527
+ node.type === 'ClassDeclaration' ||
528
+ node.type === 'ClassExpression');
529
+ }
530
+ function unsupported(filename, construct) {
531
+ return new Error(`Unsupported final Rolldown native chunk ${filename}: ${construct}`);
532
+ }
533
+ function createSourceMap(editor, filename) {
534
+ const generated = editor.generateMap({
535
+ file: filename,
536
+ hires: 'boundary',
537
+ includeContent: true,
538
+ source: filename
539
+ });
540
+ return {
541
+ version: generated.version,
542
+ file: generated.file,
543
+ sources: generated.sources,
544
+ sourcesContent: generated.sourcesContent,
545
+ names: generated.names,
546
+ mappings: generated.mappings,
547
+ ...(generated.x_google_ignoreList ? { x_google_ignoreList: generated.x_google_ignoreList } : {})
548
+ };
45
549
  }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Records non-overlapping range edits and renders them in one source-order pass.
3
+ *
4
+ * Final WX development chunks do not request source maps. RolldownMagicString's repeated relocation of hundreds of hoisted
5
+ * functions is considerably more expensive than the semantic analysis itself, so this editor keeps the same range operations
6
+ * while avoiding a mutable chunk graph when no mappings can be observed.
7
+ */
8
+ export declare class StringEditor {
9
+ #private;
10
+ readonly original: string;
11
+ constructor(original: string);
12
+ /** Records a half-open replacement; semantic passes guarantee ranges are nested or disjoint. */
13
+ overwrite(start: number, end: number, content: string): void;
14
+ /** Removes a range and discards insertions that were owned only by that removed source. */
15
+ remove(start: number, end: number): void;
16
+ /** Inserts before prior insertions at a boundary, matching MagicString's prependLeft ordering. */
17
+ prependLeft(position: number, content: string): void;
18
+ /** Inserts after prior insertions at the left side of a boundary. */
19
+ appendLeft(position: number, content: string): void;
20
+ /** Matches the subset of appendRight ordering used by the capsule compiler. */
21
+ appendRight(position: number, content: string): void;
22
+ /** Materializes one source slice without mutating its edit journal, allowing functions to be rendered before relocation. */
23
+ render(start: number, end: number): string;
24
+ }