@navita/extraction 3.0.0-next.0

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/toAmd.mjs ADDED
@@ -0,0 +1,192 @@
1
+ import "node:path";
2
+ import "node:url";
3
+ import.meta.url;
4
+ import { importedName, patternNames } from "./ast.mjs";
5
+ import { getParser } from "./loadOxc.mjs";
6
+ //#region src/toAmd.ts
7
+ /**
8
+ * Convert an ES module (already TypeScript-stripped) into a single AMD
9
+ * `define([...deps], function (require, exports, ...modules) { ... })` call
10
+ * expression — the shape `@navita/core`'s evaluator expects.
11
+ */
12
+ function esmToAmd(code, { dropUnusedImports }) {
13
+ const { program } = getParser().parseSync("module.js", code, {
14
+ lang: "js",
15
+ sourceType: "module"
16
+ });
17
+ const body = program.body;
18
+ const sources = [];
19
+ const sourceIndex = /* @__PURE__ */ new Map();
20
+ const sideEffectSources = [];
21
+ const sourceInfoFor = (source) => {
22
+ let info = sourceIndex.get(source);
23
+ if (!info) {
24
+ info = {
25
+ source,
26
+ specs: [],
27
+ param: ""
28
+ };
29
+ sourceIndex.set(source, info);
30
+ sources.push(info);
31
+ }
32
+ return info;
33
+ };
34
+ for (const stmt of body) {
35
+ if (stmt.type !== "ImportDeclaration") continue;
36
+ const source = stmt.source.value;
37
+ const specifiers = stmt.specifiers || [];
38
+ if (specifiers.length === 0) {
39
+ sideEffectSources.push(source);
40
+ continue;
41
+ }
42
+ const info = sourceInfoFor(source);
43
+ for (const spec of specifiers) if (spec.type === "ImportDefaultSpecifier") info.specs.push({
44
+ kind: "default",
45
+ local: spec.local.name
46
+ });
47
+ else if (spec.type === "ImportNamespaceSpecifier") info.specs.push({
48
+ kind: "namespace",
49
+ local: spec.local.name
50
+ });
51
+ else info.specs.push({
52
+ kind: "named",
53
+ imported: importedName(spec),
54
+ local: spec.local.name
55
+ });
56
+ }
57
+ const referenced = /* @__PURE__ */ new Set();
58
+ if (dropUnusedImports) for (const stmt of body) {
59
+ if (stmt.type === "ImportDeclaration") continue;
60
+ collectIdentifierNames(stmt, referenced);
61
+ }
62
+ const keptSources = [];
63
+ for (const info of sources) {
64
+ const specs = dropUnusedImports ? info.specs.filter((s) => referenced.has(s.local)) : info.specs;
65
+ if (specs.length === 0) continue;
66
+ info.specs = specs;
67
+ keptSources.push(info);
68
+ }
69
+ const keptSideEffects = dropUnusedImports ? [] : sideEffectSources;
70
+ keptSources.forEach((info, i) => {
71
+ info.param = `_navita_import_${i}`;
72
+ });
73
+ const sideEffectParams = keptSideEffects.map((_, i) => `_navita_side_${i}`);
74
+ const deps = [
75
+ "\"require\"",
76
+ "\"exports\"",
77
+ ...keptSources.map((info) => JSON.stringify(info.source)),
78
+ ...keptSideEffects.map((source) => JSON.stringify(source))
79
+ ];
80
+ const params = [
81
+ "require",
82
+ "exports",
83
+ ...keptSources.map((info) => info.param),
84
+ ...sideEffectParams
85
+ ];
86
+ const lines = [];
87
+ let reexportCounter = 0;
88
+ const nextReexportNs = () => `_navita_reexport_${reexportCounter++}`;
89
+ for (const info of keptSources) lines.push(...destructure(info));
90
+ for (const stmt of body) {
91
+ if (stmt.type === "ImportDeclaration") continue;
92
+ emitStatement(stmt, code, lines, nextReexportNs);
93
+ }
94
+ const bodyText = lines.join("\n");
95
+ return `define([${deps.join(", ")}], function (${params.join(", ")}) {\n${bodyText}\n})`;
96
+ }
97
+ function destructure(info) {
98
+ const lines = [];
99
+ const named = [];
100
+ for (const spec of info.specs) if (spec.kind === "named") named.push(spec.imported === spec.local ? spec.local : `${spec.imported}: ${spec.local}`);
101
+ else if (spec.kind === "namespace") lines.push(`const ${spec.local} = ${info.param};`);
102
+ else lines.push(`const ${spec.local} = ${info.param} && ${info.param}.__esModule ? ${info.param}.default : (${info.param}.default !== undefined ? ${info.param}.default : ${info.param});`);
103
+ if (named.length > 0) lines.push(`const { ${named.join(", ")} } = ${info.param};`);
104
+ return lines;
105
+ }
106
+ function emitStatement(stmt, code, lines, nextReexportNs) {
107
+ switch (stmt.type) {
108
+ case "ExportNamedDeclaration":
109
+ if (stmt.declaration) {
110
+ const decl = stmt.declaration;
111
+ lines.push(code.slice(decl.start, decl.end));
112
+ for (const name of declaredNames(decl)) lines.push(`exports.${name} = ${name};`);
113
+ return;
114
+ }
115
+ if (stmt.source) {
116
+ const ns = nextReexportNs();
117
+ lines.push(`const ${ns} = require(${JSON.stringify(stmt.source.value)});`);
118
+ for (const spec of stmt.specifiers || []) lines.push(`exports.${spec.exported.name} = ${ns}.${spec.local.name};`);
119
+ return;
120
+ }
121
+ for (const spec of stmt.specifiers || []) lines.push(`exports.${spec.exported.name} = ${spec.local.name};`);
122
+ return;
123
+ case "ExportDefaultDeclaration": {
124
+ const decl = stmt.declaration;
125
+ if (decl.type === "FunctionDeclaration" || decl.type === "ClassDeclaration") if (decl.id) {
126
+ lines.push(code.slice(decl.start, decl.end));
127
+ lines.push(`exports.default = ${decl.id.name};`);
128
+ } else lines.push(`exports.default = ${code.slice(decl.start, decl.end)};`);
129
+ else lines.push(`exports.default = ${code.slice(decl.start, decl.end)};`);
130
+ return;
131
+ }
132
+ case "ExportAllDeclaration": {
133
+ const ns = nextReexportNs();
134
+ lines.push(`const ${ns} = require(${JSON.stringify(stmt.source.value)});`);
135
+ if (stmt.exported) lines.push(`exports.${stmt.exported.name} = ${ns};`);
136
+ else lines.push(`for (const _k in ${ns}) { if (_k !== "default") exports[_k] = ${ns}[_k]; }`);
137
+ return;
138
+ }
139
+ default: lines.push(code.slice(stmt.start, stmt.end));
140
+ }
141
+ }
142
+ function declaredNames(decl) {
143
+ if (decl.type === "VariableDeclaration") {
144
+ const names = [];
145
+ for (const d of decl.declarations) patternNames(d.id, names);
146
+ return names;
147
+ }
148
+ if (decl.type === "FunctionDeclaration" || decl.type === "ClassDeclaration") return decl.id ? [decl.id.name] : [];
149
+ return [];
150
+ }
151
+ const SKIP_KEYS = /* @__PURE__ */ new Set([
152
+ "type",
153
+ "start",
154
+ "end",
155
+ "range",
156
+ "loc",
157
+ "parent"
158
+ ]);
159
+ /** Collect identifier names referenced in a subtree (skip static member/key). */
160
+ function collectIdentifierNames(node, out) {
161
+ if (!node || typeof node !== "object") return;
162
+ if (Array.isArray(node)) {
163
+ for (const child of node) collectIdentifierNames(child, out);
164
+ return;
165
+ }
166
+ const n = node;
167
+ switch (n.type) {
168
+ case "Identifier":
169
+ case "IdentifierReference":
170
+ out.add(n.name);
171
+ return;
172
+ case "MemberExpression":
173
+ case "StaticMemberExpression":
174
+ case "ComputedMemberExpression":
175
+ if (n.computed) collectIdentifierNames(n.property, out);
176
+ collectIdentifierNames(n.object, out);
177
+ return;
178
+ case "Property":
179
+ case "ObjectProperty":
180
+ if (n.computed) collectIdentifierNames(n.key, out);
181
+ collectIdentifierNames(n.value, out);
182
+ return;
183
+ default: break;
184
+ }
185
+ for (const key in n) {
186
+ if (SKIP_KEYS.has(key)) continue;
187
+ const value = n[key];
188
+ if (value && typeof value === "object") collectIdentifierNames(value, out);
189
+ }
190
+ }
191
+ //#endregion
192
+ export { esmToAmd };