susee 0.1.1 → 0.1.3
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/README.md +77 -96
- package/bin/index.mjs +1 -1
- package/dist/index.cjs +1555 -552
- package/dist/index.cjs.map +8 -1
- package/dist/index.d.cts +16 -15
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +16 -15
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1543 -540
- package/dist/index.mjs.map +8 -1
- package/package.json +13 -13
package/dist/index.mjs
CHANGED
|
@@ -6,100 +6,44 @@ this file except in compliance with the License. You may obtain a copy of the
|
|
|
6
6
|
License at http://www.apache.org/licenses/LICENSE-2.0
|
|
7
7
|
***************************************************************************** */
|
|
8
8
|
import TsConfig from "@suseejs/tsconfig";
|
|
9
|
-
import anonymous from "@suseejs/anonymous";
|
|
10
9
|
import dependencies from "@suseejs/dependencies";
|
|
11
|
-
import duplicateHandlers from "@suseejs/duplicates";
|
|
12
10
|
import fs from "node:fs";
|
|
13
11
|
import path from "node:path";
|
|
14
12
|
import resolves from "@phothinmaung/resolves";
|
|
15
13
|
import tcolor from "@suseejs/tcolor";
|
|
16
14
|
import transformFunction from "@suseejs/transformer";
|
|
17
15
|
import ts from "typescript";
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
import utilities from "@suseejs/utils";
|
|
17
|
+
import { Buffer } from "node:buffer";
|
|
18
|
+
//src/lib/bundle/bundleCreator.ts
|
|
19
|
+
/**
|
|
20
|
+
* Creates a BundleCreator function that transforms a DepsFile with a given BundleVisitor and typescript compiler options.
|
|
21
|
+
* @param {BundleVisitor} bundleVisitor - a BundleVisitor function that takes a context, depsTree, sourceFile, and any number of arguments.
|
|
22
|
+
* @param {ts.CompilerOptions} compilerOptions - typescript compiler options.
|
|
23
|
+
* @param {...any} args - any number of arguments to pass to the BundleVisitor function.
|
|
24
|
+
* @returns {BundleCreator} a BundleCreator function that takes a DepsFile and returns a transformed DepsFile.
|
|
25
|
+
*/
|
|
26
|
+
const bundleCreator = (bundleVisitor, compilerOptions, ...args) => {
|
|
27
|
+
return (depsTree) => {
|
|
28
|
+
const sourceFile = ts.createSourceFile(depsTree.file, depsTree.content, ts.ScriptTarget.Latest, true);
|
|
22
29
|
const transformer = (context) => {
|
|
23
|
-
const
|
|
24
|
-
const visitor = (node) => {
|
|
25
|
-
if (ts.isFunctionDeclaration(node) ||
|
|
26
|
-
ts.isClassDeclaration(node) ||
|
|
27
|
-
ts.isInterfaceDeclaration(node) ||
|
|
28
|
-
ts.isTypeAliasDeclaration(node) ||
|
|
29
|
-
ts.isEnumDeclaration(node) ||
|
|
30
|
-
ts.isVariableStatement(node)) {
|
|
31
|
-
const modifiers = node.modifiers?.filter((m) => m.kind !== ts.SyntaxKind.ExportKeyword &&
|
|
32
|
-
m.kind !== ts.SyntaxKind.DefaultKeyword);
|
|
33
|
-
if (modifiers?.length !== node.modifiers?.length) {
|
|
34
|
-
if (ts.isFunctionDeclaration(node)) {
|
|
35
|
-
return factory.updateFunctionDeclaration(node, modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body);
|
|
36
|
-
}
|
|
37
|
-
if (ts.isClassDeclaration(node)) {
|
|
38
|
-
return factory.updateClassDeclaration(node, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members);
|
|
39
|
-
}
|
|
40
|
-
if (ts.isInterfaceDeclaration(node)) {
|
|
41
|
-
return factory.updateInterfaceDeclaration(node, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members);
|
|
42
|
-
}
|
|
43
|
-
if (ts.isTypeAliasDeclaration(node)) {
|
|
44
|
-
return factory.updateTypeAliasDeclaration(node, modifiers, node.name, node.typeParameters, node.type);
|
|
45
|
-
}
|
|
46
|
-
if (ts.isEnumDeclaration(node)) {
|
|
47
|
-
return factory.updateEnumDeclaration(node, modifiers, node.name, node.members);
|
|
48
|
-
}
|
|
49
|
-
if (ts.isVariableStatement(node)) {
|
|
50
|
-
return factory.updateVariableStatement(node, modifiers, node.declarationList);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
if (ts.isExportDeclaration(node)) {
|
|
55
|
-
return factory.createEmptyStatement();
|
|
56
|
-
}
|
|
57
|
-
if (ts.isExportAssignment(node)) {
|
|
58
|
-
const expr = node.expression;
|
|
59
|
-
if (ts.isIdentifier(expr)) {
|
|
60
|
-
return factory.createEmptyStatement();
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return ts.visitEachChild(node, visitor, context);
|
|
64
|
-
};
|
|
30
|
+
const visitor = bundleVisitor(context, depsTree, sourceFile, ...args);
|
|
65
31
|
return (rootNode) => ts.visitNode(rootNode, visitor);
|
|
66
32
|
};
|
|
67
33
|
let _content = transformFunction(transformer, sourceFile, compilerOptions);
|
|
68
34
|
_content = _content.replace(/^s*;\s*$/gm, "").trim();
|
|
69
|
-
|
|
35
|
+
const { content, ...rest } = depsTree;
|
|
36
|
+
return { content: _content, ...rest };
|
|
70
37
|
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const sourceFile = ts.createSourceFile(file, content, ts.ScriptTarget.Latest, true);
|
|
75
|
-
const transformer = (context) => {
|
|
76
|
-
const { factory } = context;
|
|
77
|
-
const visitor = (node) => {
|
|
78
|
-
if (ts.isImportDeclaration(node)) {
|
|
79
|
-
const text = node.getText(sourceFile);
|
|
80
|
-
removedStatements.push(text);
|
|
81
|
-
return factory.createEmptyStatement();
|
|
82
|
-
}
|
|
83
|
-
if (ts.isImportEqualsDeclaration(node)) {
|
|
84
|
-
const text = node.getText(sourceFile);
|
|
85
|
-
removedStatements.push(text);
|
|
86
|
-
return factory.createEmptyStatement();
|
|
87
|
-
}
|
|
88
|
-
return ts.visitEachChild(node, visitor, context);
|
|
89
|
-
};
|
|
90
|
-
return (rootNode) => ts.visitNode(rootNode, visitor);
|
|
91
|
-
};
|
|
92
|
-
let _content = transformFunction(transformer, sourceFile, compilerOptions);
|
|
93
|
-
_content = _content.replace(/^s*;\s*$/gm, "").trim();
|
|
94
|
-
return { file, content: _content };
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
function mergeImports(imports) {
|
|
38
|
+
};
|
|
39
|
+
//src/lib/bundle/mergeImportsStatement.ts
|
|
40
|
+
function mergeImportsStatement(imports) {
|
|
98
41
|
const importMap = new Map();
|
|
99
42
|
const typeImportMap = new Map();
|
|
100
43
|
const defaultImports = new Map();
|
|
101
44
|
const typeDefaultImports = new Map();
|
|
102
45
|
const namespaceImports = new Map();
|
|
46
|
+
// Parse each import statement
|
|
103
47
|
for (const importStr of imports) {
|
|
104
48
|
const importMatch = importStr.match(/import\s+(?:type\s+)?(?:(.*?)\s+from\s+)?["']([^"']+)["'];?/);
|
|
105
49
|
if (!importMatch)
|
|
@@ -108,6 +52,7 @@ function mergeImports(imports) {
|
|
|
108
52
|
const isTypeImport = importStr.includes("import type");
|
|
109
53
|
const modulePath = _modulePath;
|
|
110
54
|
if (!importClause) {
|
|
55
|
+
// Default import or side-effect import
|
|
111
56
|
const defaultMatch = importStr.match(/import\s+(?:type\s+)?(\w+)/);
|
|
112
57
|
if (defaultMatch) {
|
|
113
58
|
const importName = defaultMatch[1];
|
|
@@ -119,6 +64,7 @@ function mergeImports(imports) {
|
|
|
119
64
|
continue;
|
|
120
65
|
}
|
|
121
66
|
if (importClause.startsWith("{")) {
|
|
67
|
+
// Named imports: import { a, b } from 'module'
|
|
122
68
|
const targetMap = isTypeImport ? typeImportMap : importMap;
|
|
123
69
|
if (!targetMap.has(modulePath))
|
|
124
70
|
targetMap.set(modulePath, new Set());
|
|
@@ -127,9 +73,11 @@ function mergeImports(imports) {
|
|
|
127
73
|
.split(",")
|
|
128
74
|
.map((s) => s.trim())
|
|
129
75
|
.filter(Boolean);
|
|
76
|
+
// biome-ignore lint/suspicious/useIterableCallbackReturn : just add name for names each
|
|
130
77
|
names.forEach((name) => targetMap.get(modulePath)?.add(name));
|
|
131
78
|
}
|
|
132
79
|
else if (importClause.startsWith("* as")) {
|
|
80
|
+
// Namespace import: import * as name from 'module'
|
|
133
81
|
const namespaceMatch = importClause.match(/\*\s+as\s+(\w+)/);
|
|
134
82
|
if (namespaceMatch) {
|
|
135
83
|
const namespaceName = namespaceMatch[1];
|
|
@@ -139,6 +87,7 @@ function mergeImports(imports) {
|
|
|
139
87
|
}
|
|
140
88
|
}
|
|
141
89
|
else {
|
|
90
|
+
// Default import: import name from 'module'
|
|
142
91
|
const targetMap = isTypeImport ? typeDefaultImports : defaultImports;
|
|
143
92
|
if (!targetMap.has(modulePath))
|
|
144
93
|
targetMap.set(modulePath, new Set());
|
|
@@ -146,8 +95,10 @@ function mergeImports(imports) {
|
|
|
146
95
|
}
|
|
147
96
|
}
|
|
148
97
|
const mergedImports = [];
|
|
98
|
+
// Process named imports - remove type imports that have regular imports
|
|
149
99
|
for (const [modulePath, regularNames] of importMap) {
|
|
150
100
|
const typeNames = typeImportMap.get(modulePath) || new Set();
|
|
101
|
+
// Only include type names that don't have regular imports
|
|
151
102
|
const finalNames = new Set([...regularNames]);
|
|
152
103
|
for (const typeName of typeNames) {
|
|
153
104
|
if (!regularNames.has(typeName)) {
|
|
@@ -159,14 +110,17 @@ function mergeImports(imports) {
|
|
|
159
110
|
mergedImports.push(`import { ${importNames} } from "${modulePath}";`);
|
|
160
111
|
}
|
|
161
112
|
}
|
|
113
|
+
// Add remaining type-only imports (where no regular imports exist for the module)
|
|
162
114
|
for (const [modulePath, typeNames] of typeImportMap) {
|
|
163
115
|
if (!importMap.has(modulePath) && typeNames.size > 0) {
|
|
164
116
|
const importNames = Array.from(typeNames).sort().join(", ");
|
|
165
117
|
mergedImports.push(`import type { ${importNames} } from "${modulePath}";`);
|
|
166
118
|
}
|
|
167
119
|
}
|
|
120
|
+
// Process default imports - remove type default imports that have regular default imports
|
|
168
121
|
for (const [modulePath, regularDefaultNames] of defaultImports) {
|
|
169
122
|
const typeDefaultNames = typeDefaultImports.get(modulePath) || new Set();
|
|
123
|
+
// Only include type default names that don't have regular default imports
|
|
170
124
|
const finalNames = new Set([...regularDefaultNames]);
|
|
171
125
|
for (const typeName of typeDefaultNames) {
|
|
172
126
|
if (!regularDefaultNames.has(typeName)) {
|
|
@@ -178,12 +132,14 @@ function mergeImports(imports) {
|
|
|
178
132
|
mergedImports.push(`import ${importNames} from "${modulePath}";`);
|
|
179
133
|
}
|
|
180
134
|
}
|
|
135
|
+
// Add remaining type-only default imports
|
|
181
136
|
for (const [modulePath, typeDefaultNames] of typeDefaultImports) {
|
|
182
137
|
if (!defaultImports.has(modulePath) && typeDefaultNames.size > 0) {
|
|
183
138
|
const importNames = Array.from(typeDefaultNames).join(", ");
|
|
184
139
|
mergedImports.push(`import type ${importNames} from "${modulePath}";`);
|
|
185
140
|
}
|
|
186
141
|
}
|
|
142
|
+
// Process namespace imports
|
|
187
143
|
for (const [modulePath, names] of namespaceImports) {
|
|
188
144
|
if (names.size > 0) {
|
|
189
145
|
const importNames = Array.from(names).join(", ");
|
|
@@ -192,8 +148,852 @@ function mergeImports(imports) {
|
|
|
192
148
|
}
|
|
193
149
|
return mergedImports.sort();
|
|
194
150
|
}
|
|
195
|
-
|
|
196
|
-
|
|
151
|
+
//src/lib/bundle/visitors/anonymousCallExpression.ts
|
|
152
|
+
/**
|
|
153
|
+
* A BundleVisitor that updates the call expression, property access expression, and new expression
|
|
154
|
+
* with the anonymous default import name.
|
|
155
|
+
*/
|
|
156
|
+
const anonymousCallExpressionVisitor = (context, depsTree, _sourceFile, exportDefaultImportNameMap) => {
|
|
157
|
+
const { factory } = context;
|
|
158
|
+
const visit = (node) => {
|
|
159
|
+
if (ts.isCallExpression(node)) {
|
|
160
|
+
if (ts.isIdentifier(node.expression)) {
|
|
161
|
+
const base = node.expression.text;
|
|
162
|
+
const mapping = exportDefaultImportNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
163
|
+
if (mapping) {
|
|
164
|
+
return factory.updateCallExpression(node, factory.createIdentifier(mapping.newName), node.typeArguments, node.arguments);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
else if (ts.isPropertyAccessExpression(node)) {
|
|
169
|
+
if (ts.isIdentifier(node.expression)) {
|
|
170
|
+
const base = node.expression.text;
|
|
171
|
+
const mapping = exportDefaultImportNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
172
|
+
if (mapping) {
|
|
173
|
+
return factory.updatePropertyAccessExpression(node, factory.createIdentifier(mapping.newName), node.name);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
else if (ts.isNewExpression(node)) {
|
|
178
|
+
if (ts.isIdentifier(node.expression)) {
|
|
179
|
+
const base = node.expression.text;
|
|
180
|
+
const mapping = exportDefaultImportNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
181
|
+
if (mapping) {
|
|
182
|
+
return factory.updateNewExpression(node, factory.createIdentifier(mapping.newName), node.typeArguments, node.arguments);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// for export specifier it is focus on entry file
|
|
186
|
+
}
|
|
187
|
+
else if (ts.isExportSpecifier(node)) {
|
|
188
|
+
if (ts.isIdentifier(node.name)) {
|
|
189
|
+
const base = node.name.text;
|
|
190
|
+
const mapping = exportDefaultImportNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
191
|
+
if (mapping) {
|
|
192
|
+
return factory.updateExportSpecifier(node, node.isTypeOnly, node.propertyName, factory.createIdentifier(mapping.newName));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return ts.visitEachChild(node, visit, context);
|
|
197
|
+
};
|
|
198
|
+
return visit;
|
|
199
|
+
};
|
|
200
|
+
//src/lib/bundle/visitors/visitorHelpers.ts
|
|
201
|
+
const normalizePathKey = (filePath) => {
|
|
202
|
+
const parsed = path.parse(filePath);
|
|
203
|
+
let noExt = path.join(parsed.dir, parsed.name);
|
|
204
|
+
if (parsed.name === "index") {
|
|
205
|
+
noExt = parsed.dir;
|
|
206
|
+
}
|
|
207
|
+
return path.normalize(noExt);
|
|
208
|
+
};
|
|
209
|
+
const getFileKey = (filePath) => normalizePathKey(filePath);
|
|
210
|
+
const getModuleKeyFromSpecifier = (moduleSpecifier, sourceFile, containingFile) => {
|
|
211
|
+
let spec = "";
|
|
212
|
+
if (ts.isStringLiteral(moduleSpecifier)) {
|
|
213
|
+
spec = moduleSpecifier.text;
|
|
214
|
+
}
|
|
215
|
+
else {
|
|
216
|
+
spec = moduleSpecifier.getText(sourceFile).replace(/^['"]|['"]$/g, "");
|
|
217
|
+
}
|
|
218
|
+
if (spec.startsWith(".") || spec.startsWith("/")) {
|
|
219
|
+
const baseDir = path.dirname(containingFile);
|
|
220
|
+
return normalizePathKey(path.resolve(baseDir, spec));
|
|
221
|
+
}
|
|
222
|
+
return spec;
|
|
223
|
+
};
|
|
224
|
+
function uniqueName() {
|
|
225
|
+
const storedPrefix = new Map();
|
|
226
|
+
const obj = {
|
|
227
|
+
setPrefix({ key, value }) {
|
|
228
|
+
const names = [];
|
|
229
|
+
let _fix;
|
|
230
|
+
if (storedPrefix.has(key)) {
|
|
231
|
+
console.warn(`${key} already exist`);
|
|
232
|
+
throw new Error();
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
_fix = value;
|
|
236
|
+
storedPrefix.set(key, value);
|
|
237
|
+
}
|
|
238
|
+
function getName(input) {
|
|
239
|
+
const length = names.length;
|
|
240
|
+
const _name = _fix
|
|
241
|
+
? `${_fix}${input}_${length + 1}`
|
|
242
|
+
: `$nyein${input}_${length + 1}`;
|
|
243
|
+
names.push(_name);
|
|
244
|
+
return _name;
|
|
245
|
+
}
|
|
246
|
+
return { getName };
|
|
247
|
+
},
|
|
248
|
+
getPrefix(key) {
|
|
249
|
+
if (storedPrefix.has(key)) {
|
|
250
|
+
return storedPrefix.get(key);
|
|
251
|
+
}
|
|
252
|
+
},
|
|
253
|
+
};
|
|
254
|
+
return obj;
|
|
255
|
+
}
|
|
256
|
+
//src/lib/bundle/visitors/anonymousExport.ts
|
|
257
|
+
const prefixKey = "AnonymousName";
|
|
258
|
+
const genName = uniqueName().setPrefix({ key: prefixKey, value: "a_" });
|
|
259
|
+
/**
|
|
260
|
+
* A BundleVisitor that updates the call expression, property access expression, and new expression
|
|
261
|
+
* with the anonymous default import name.
|
|
262
|
+
*/
|
|
263
|
+
const anonymousExportVisitor = (context, depsTree, sourceFile, exportDefaultExportNameMap) => {
|
|
264
|
+
const { factory } = context;
|
|
265
|
+
const visit = (node) => {
|
|
266
|
+
const fileName = path.basename(depsTree.file).split(".")[0];
|
|
267
|
+
if ((ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node)) &&
|
|
268
|
+
node.name === undefined) {
|
|
269
|
+
let exp = false;
|
|
270
|
+
let def = false;
|
|
271
|
+
node.modifiers?.forEach((mod) => {
|
|
272
|
+
if (mod.kind === ts.SyntaxKind.ExportKeyword) {
|
|
273
|
+
exp = true;
|
|
274
|
+
}
|
|
275
|
+
if (mod.kind === ts.SyntaxKind.DefaultKeyword) {
|
|
276
|
+
def = true;
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
if (exp && def) {
|
|
280
|
+
const base = genName.getName(fileName);
|
|
281
|
+
exportDefaultExportNameMap.push({
|
|
282
|
+
base,
|
|
283
|
+
file: fileName,
|
|
284
|
+
newName: base,
|
|
285
|
+
isEd: true,
|
|
286
|
+
});
|
|
287
|
+
if (ts.isFunctionDeclaration(node)) {
|
|
288
|
+
return factory.updateFunctionDeclaration(node, node.modifiers, node.asteriskToken, factory.createIdentifier(base), node.typeParameters, node.parameters, node.type, node.body);
|
|
289
|
+
}
|
|
290
|
+
else if (ts.isClassDeclaration(node)) {
|
|
291
|
+
return factory.updateClassDeclaration(node, node.modifiers, factory.createIdentifier(base), node.typeParameters, node.heritageClauses, node.members);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
else if (ts.isExportAssignment(node) &&
|
|
296
|
+
!node.name &&
|
|
297
|
+
!node.isExportEquals) {
|
|
298
|
+
if (ts.isArrowFunction(node.expression)) {
|
|
299
|
+
const base = genName.getName(fileName);
|
|
300
|
+
const arrowFunctionNode = factory.createArrowFunction(node.expression.modifiers, node.expression.typeParameters, node.expression.parameters, node.expression.type, node.expression.equalsGreaterThanToken, node.expression.body);
|
|
301
|
+
const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), node.expression.exclamationToken, node.expression.type, arrowFunctionNode);
|
|
302
|
+
const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts.NodeFlags.Const);
|
|
303
|
+
const variableStatementNode = factory.createVariableStatement(node.expression.modifiers, variableDeclarationListNode);
|
|
304
|
+
const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
|
|
305
|
+
exportDefaultExportNameMap.push({
|
|
306
|
+
base,
|
|
307
|
+
file: fileName,
|
|
308
|
+
newName: base,
|
|
309
|
+
isEd: true,
|
|
310
|
+
});
|
|
311
|
+
return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
|
|
312
|
+
}
|
|
313
|
+
else if (ts.isObjectLiteralExpression(node.expression)) {
|
|
314
|
+
const base = genName.getName(fileName);
|
|
315
|
+
const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), undefined, undefined, node.expression);
|
|
316
|
+
const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts.NodeFlags.Const);
|
|
317
|
+
const variableStatementNode = factory.createVariableStatement(undefined, variableDeclarationListNode);
|
|
318
|
+
const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
|
|
319
|
+
exportDefaultExportNameMap.push({
|
|
320
|
+
base,
|
|
321
|
+
file: fileName,
|
|
322
|
+
newName: base,
|
|
323
|
+
isEd: true,
|
|
324
|
+
});
|
|
325
|
+
return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
|
|
326
|
+
}
|
|
327
|
+
else if (ts.isArrayLiteralExpression(node.expression)) {
|
|
328
|
+
const base = genName.getName(fileName);
|
|
329
|
+
const arrayLiteralExpressionNode = factory.createArrayLiteralExpression(node.expression.elements, true);
|
|
330
|
+
const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), undefined, undefined, arrayLiteralExpressionNode);
|
|
331
|
+
const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts.NodeFlags.Const);
|
|
332
|
+
const variableStatementNode = factory.createVariableStatement(undefined, variableDeclarationListNode);
|
|
333
|
+
const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
|
|
334
|
+
exportDefaultExportNameMap.push({
|
|
335
|
+
base,
|
|
336
|
+
file: fileName,
|
|
337
|
+
newName: base,
|
|
338
|
+
isEd: true,
|
|
339
|
+
});
|
|
340
|
+
return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
|
|
341
|
+
}
|
|
342
|
+
else if (ts.isStringLiteral(node.expression)) {
|
|
343
|
+
const base = genName.getName(fileName);
|
|
344
|
+
const stringLiteralNode = factory.createStringLiteral(node.expression.text);
|
|
345
|
+
const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), undefined, undefined, stringLiteralNode);
|
|
346
|
+
const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts.NodeFlags.Const);
|
|
347
|
+
const variableStatementNode = factory.createVariableStatement(undefined, variableDeclarationListNode);
|
|
348
|
+
const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
|
|
349
|
+
exportDefaultExportNameMap.push({
|
|
350
|
+
base,
|
|
351
|
+
file: fileName,
|
|
352
|
+
newName: base,
|
|
353
|
+
isEd: true,
|
|
354
|
+
});
|
|
355
|
+
return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
|
|
356
|
+
}
|
|
357
|
+
else if (ts.isNumericLiteral(node.expression)) {
|
|
358
|
+
const base = genName.getName(fileName);
|
|
359
|
+
const numericLiteralNode = factory.createNumericLiteral(node.expression.text);
|
|
360
|
+
const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), undefined, undefined, numericLiteralNode);
|
|
361
|
+
const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts.NodeFlags.Const);
|
|
362
|
+
const variableStatementNode = factory.createVariableStatement(undefined, variableDeclarationListNode);
|
|
363
|
+
const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
|
|
364
|
+
exportDefaultExportNameMap.push({
|
|
365
|
+
base,
|
|
366
|
+
file: fileName,
|
|
367
|
+
newName: base,
|
|
368
|
+
isEd: true,
|
|
369
|
+
});
|
|
370
|
+
return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
|
|
371
|
+
}
|
|
372
|
+
} //
|
|
373
|
+
return ts.visitEachChild(node, visit, context);
|
|
374
|
+
};
|
|
375
|
+
return visit;
|
|
376
|
+
};
|
|
377
|
+
//src/lib/bundle/visitors/anonymousImport.ts
|
|
378
|
+
/**
|
|
379
|
+
* A BundleVisitor that updates the import declaration, property access expression, and new expression
|
|
380
|
+
* with the anonymous default import name.
|
|
381
|
+
*/
|
|
382
|
+
const anonymousImportVisitor = (context, depsTree, sourceFile, exportDefaultExportNameMap, exportDefaultImportNameMap) => {
|
|
383
|
+
const { factory } = context;
|
|
384
|
+
const visit = (node) => {
|
|
385
|
+
if (ts.isImportDeclaration(node)) {
|
|
386
|
+
const fileName = node.moduleSpecifier.getText(sourceFile);
|
|
387
|
+
const _name = path.basename(fileName).split(".")[0].trim();
|
|
388
|
+
// check only import default expression
|
|
389
|
+
if (node.importClause?.name && ts.isIdentifier(node.importClause.name)) {
|
|
390
|
+
const base = node.importClause.name.text.trim();
|
|
391
|
+
const mapping = exportDefaultExportNameMap.find((v) => v.file === _name);
|
|
392
|
+
if (mapping) {
|
|
393
|
+
exportDefaultImportNameMap.push({
|
|
394
|
+
base,
|
|
395
|
+
file: depsTree.file,
|
|
396
|
+
newName: mapping.newName,
|
|
397
|
+
isEd: true,
|
|
398
|
+
});
|
|
399
|
+
const newImportClause = factory.updateImportClause(node.importClause, node.importClause.phaseModifier, factory.createIdentifier(mapping.newName), node.importClause.namedBindings);
|
|
400
|
+
return factory.updateImportDeclaration(node, node.modifiers, newImportClause, node.moduleSpecifier, node.attributes);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return ts.visitEachChild(node, visit, context);
|
|
405
|
+
};
|
|
406
|
+
return visit;
|
|
407
|
+
};
|
|
408
|
+
//src/lib/bundle/visitors/duplicateCallExpression.ts
|
|
409
|
+
/**
|
|
410
|
+
* A BundleVisitor that updates the call expression, property access expression, and new expression
|
|
411
|
+
* with the anonymous default import name.
|
|
412
|
+
*/
|
|
413
|
+
const duplicateCallExpressionVisitor = (context, depsTree, _sourceFile, callNameMap, importNameMap) => {
|
|
414
|
+
const { factory } = context;
|
|
415
|
+
const visit = (node) => {
|
|
416
|
+
if (ts.isCallExpression(node)) {
|
|
417
|
+
if (ts.isIdentifier(node.expression)) {
|
|
418
|
+
const base = node.expression.text;
|
|
419
|
+
let new_name = null;
|
|
420
|
+
const mapping = callNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
421
|
+
const importMapping = importNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
422
|
+
if (mapping) {
|
|
423
|
+
new_name = mapping.newName;
|
|
424
|
+
}
|
|
425
|
+
else if (importMapping) {
|
|
426
|
+
new_name = importMapping.newName;
|
|
427
|
+
//flag.push(new_name);
|
|
428
|
+
}
|
|
429
|
+
if (new_name) {
|
|
430
|
+
return factory.updateCallExpression(node, factory.createIdentifier(new_name), node.typeArguments, node.arguments);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
else if (ts.isPropertyAccessExpression(node)) {
|
|
435
|
+
if (ts.isIdentifier(node.expression)) {
|
|
436
|
+
const base = node.expression.text;
|
|
437
|
+
let new_name = null;
|
|
438
|
+
const mapping = callNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
439
|
+
const importMapping = importNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
440
|
+
if (mapping) {
|
|
441
|
+
new_name = mapping.newName;
|
|
442
|
+
}
|
|
443
|
+
else if (importMapping) {
|
|
444
|
+
new_name = importMapping.newName;
|
|
445
|
+
}
|
|
446
|
+
if (new_name) {
|
|
447
|
+
return factory.updatePropertyAccessExpression(node, factory.createIdentifier(new_name), node.name);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
else if (ts.isNewExpression(node)) {
|
|
452
|
+
if (ts.isIdentifier(node.expression)) {
|
|
453
|
+
const base = node.expression.text;
|
|
454
|
+
let new_name = null;
|
|
455
|
+
const mapping = callNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
456
|
+
const importMapping = importNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
457
|
+
if (mapping) {
|
|
458
|
+
new_name = mapping.newName;
|
|
459
|
+
}
|
|
460
|
+
else if (importMapping) {
|
|
461
|
+
new_name = importMapping.newName;
|
|
462
|
+
}
|
|
463
|
+
if (new_name) {
|
|
464
|
+
return factory.updateNewExpression(node, factory.createIdentifier(new_name), node.typeArguments, node.arguments);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
/* ----------------------Returns for visitor function------------------------------- */
|
|
469
|
+
return ts.visitEachChild(node, visit, context);
|
|
470
|
+
};
|
|
471
|
+
return visit;
|
|
472
|
+
};
|
|
473
|
+
//src/lib/bundle/visitors/duplicateCollection.ts
|
|
474
|
+
/**
|
|
475
|
+
* A BundleVisitor that updates the collection (variable, function, class, etc)
|
|
476
|
+
* declaration with the anonymous default import name.
|
|
477
|
+
*
|
|
478
|
+
* @param {BundleVisitor} context - The BundleVisitor context.
|
|
479
|
+
* @param {DepsTree} depsTree - The deps tree object.
|
|
480
|
+
* @param {SourceFile} sourceFile - The source file object.
|
|
481
|
+
* @param {DuplicatesNameMap} namesMap - The DuplicatesNameMap object.
|
|
482
|
+
* @return {NodeVisit} visit - The NodeVisit function.
|
|
483
|
+
*/
|
|
484
|
+
const duplicateCollectionVisitor = (context, depsTree, _sourceFile, namesMap) => {
|
|
485
|
+
//const { factory } = context;
|
|
486
|
+
const visit = (node, isGlobalScope = true) => {
|
|
487
|
+
// Global declarations များကိုသာ collect လုပ်မယ်
|
|
488
|
+
if (isGlobalScope) {
|
|
489
|
+
// Variable statements (const, let, var)
|
|
490
|
+
if (ts.isVariableStatement(node)) {
|
|
491
|
+
node.declarationList.declarations.forEach((decl) => {
|
|
492
|
+
if (ts.isIdentifier(decl.name)) {
|
|
493
|
+
const $name = decl.name.text;
|
|
494
|
+
if (!namesMap.has($name)) {
|
|
495
|
+
namesMap.set($name, new Set([{ file: depsTree.file }]));
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
// biome-ignore lint/style/noNonNullAssertion : !namesMap.has($name) before
|
|
499
|
+
namesMap.get($name).add({ file: depsTree.file });
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
// Function, Class, Enum, Interface, Type declarations
|
|
505
|
+
else if (ts.isFunctionDeclaration(node) ||
|
|
506
|
+
ts.isClassDeclaration(node) ||
|
|
507
|
+
ts.isEnumDeclaration(node) ||
|
|
508
|
+
ts.isInterfaceDeclaration(node) ||
|
|
509
|
+
ts.isTypeAliasDeclaration(node)) {
|
|
510
|
+
const $name = node.name?.text;
|
|
511
|
+
if ($name) {
|
|
512
|
+
if (!namesMap.has($name)) {
|
|
513
|
+
namesMap.set($name, new Set([{ file: depsTree.file }]));
|
|
514
|
+
}
|
|
515
|
+
else {
|
|
516
|
+
// biome-ignore lint/style/noNonNullAssertion : !namesMap.has($name) before
|
|
517
|
+
namesMap.get($name).add({ file: depsTree.file });
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
// Local scope ထဲရောက်သွားတဲ့ node တွေအတွက် recursive visit
|
|
523
|
+
if (ts.isBlock(node) ||
|
|
524
|
+
ts.isFunctionDeclaration(node) ||
|
|
525
|
+
ts.isFunctionExpression(node) ||
|
|
526
|
+
ts.isArrowFunction(node) ||
|
|
527
|
+
ts.isMethodDeclaration(node) ||
|
|
528
|
+
ts.isClassDeclaration(node)) {
|
|
529
|
+
// Local scope ထဲကို ဝင်သွားပြီဆိုတာနဲ့ isGlobalScope = false
|
|
530
|
+
if (ts.isBlock(node)) {
|
|
531
|
+
ts.visitNodes(node.statements, (child) => visit(child, false));
|
|
532
|
+
}
|
|
533
|
+
else {
|
|
534
|
+
ts.forEachChild(node, (child) => {
|
|
535
|
+
visit(child, false);
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
else {
|
|
540
|
+
// Global scope ထဲဆက်ရှိနေတဲ့ node တွေအတွက်
|
|
541
|
+
return ts.visitEachChild(node, (child) => visit(child, isGlobalScope), context);
|
|
542
|
+
}
|
|
543
|
+
/* ----------------------Returns for visitNode function------------------------------- */
|
|
544
|
+
return node;
|
|
545
|
+
};
|
|
546
|
+
return visit;
|
|
547
|
+
};
|
|
548
|
+
//src/lib/bundle/visitors/duplicateExportExpression.ts
|
|
549
|
+
/**
|
|
550
|
+
* A BundleVisitor that updates the call expression, property access expression, and new expression
|
|
551
|
+
* with the anonymous default import name.
|
|
552
|
+
*/
|
|
553
|
+
const duplicateExportExpressionVisitor = (context, depsTree, _sourceFile, callNameMap, importNameMap, exportNameMap) => {
|
|
554
|
+
const { factory } = context;
|
|
555
|
+
const visit = (node) => {
|
|
556
|
+
if (ts.isExportSpecifier(node)) {
|
|
557
|
+
if (ts.isIdentifier(node.name)) {
|
|
558
|
+
const base = node.name.text;
|
|
559
|
+
let new_name = null;
|
|
560
|
+
const mapping = callNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
561
|
+
const importMapping = importNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
562
|
+
if (mapping) {
|
|
563
|
+
exportNameMap.push({
|
|
564
|
+
base,
|
|
565
|
+
file: getFileKey(depsTree.file),
|
|
566
|
+
newName: mapping.newName,
|
|
567
|
+
});
|
|
568
|
+
new_name = mapping.newName;
|
|
569
|
+
}
|
|
570
|
+
else if (importMapping) {
|
|
571
|
+
new_name = importMapping.newName;
|
|
572
|
+
}
|
|
573
|
+
if (new_name) {
|
|
574
|
+
return factory.updateExportSpecifier(node, node.isTypeOnly, node.propertyName, factory.createIdentifier(new_name));
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
else if (ts.isExportAssignment(node)) {
|
|
579
|
+
const expr = node.expression;
|
|
580
|
+
if (ts.isIdentifier(expr)) {
|
|
581
|
+
const base = expr.text;
|
|
582
|
+
let new_name = null;
|
|
583
|
+
const mapping = callNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
584
|
+
const importMapping = importNameMap.find((m) => m.base === base && m.file === depsTree.file);
|
|
585
|
+
if (mapping) {
|
|
586
|
+
exportNameMap.push({
|
|
587
|
+
base,
|
|
588
|
+
file: getFileKey(depsTree.file),
|
|
589
|
+
newName: mapping.newName,
|
|
590
|
+
});
|
|
591
|
+
new_name = mapping.newName;
|
|
592
|
+
}
|
|
593
|
+
else if (importMapping) {
|
|
594
|
+
new_name = importMapping.newName;
|
|
595
|
+
}
|
|
596
|
+
if (new_name) {
|
|
597
|
+
return factory.updateExportAssignment(node, node.modifiers, factory.createIdentifier(new_name));
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
/* ----------------------Returns for visitor function------------------------------- */
|
|
602
|
+
return ts.visitEachChild(node, visit, context);
|
|
603
|
+
};
|
|
604
|
+
return visit;
|
|
605
|
+
};
|
|
606
|
+
//src/lib/bundle/visitors/duplicateImportExpression.ts
|
|
607
|
+
/**
|
|
608
|
+
* A BundleVisitor that updates the import declaration, property access expression, and new expression
|
|
609
|
+
* with the anonymous default import name.
|
|
610
|
+
*
|
|
611
|
+
* @param {BundleVisitor} context - The BundleVisitor context.
|
|
612
|
+
* @param {DepsTree} depsTree - The deps tree object.
|
|
613
|
+
* @param {SourceFile} sourceFile - The source file object.
|
|
614
|
+
* @param {NamesSets} exportNameMap - The export name map object.
|
|
615
|
+
* @param {NamesSets} importNameMap - The import name map object.
|
|
616
|
+
* @return {NodeVisit} visit - The NodeVisit function.
|
|
617
|
+
*/
|
|
618
|
+
const duplicateImportExpressionVisitor = (context, depsTree, sourceFile, exportNameMap, importNameMap) => {
|
|
619
|
+
const { factory } = context;
|
|
620
|
+
const visit = (node) => {
|
|
621
|
+
if (ts.isImportDeclaration(node)) {
|
|
622
|
+
const moduleKey = getModuleKeyFromSpecifier(node.moduleSpecifier, sourceFile, depsTree.file);
|
|
623
|
+
let baseNames = [];
|
|
624
|
+
if (node.importClause?.namedBindings &&
|
|
625
|
+
ts.isNamedImports(node.importClause.namedBindings)) {
|
|
626
|
+
baseNames = node.importClause.namedBindings.elements.map((el) => el.name.text.trim());
|
|
627
|
+
}
|
|
628
|
+
// import default expression
|
|
629
|
+
if (node.importClause?.name && ts.isIdentifier(node.importClause.name)) {
|
|
630
|
+
const base = node.importClause.name.text.trim();
|
|
631
|
+
const mapping = exportNameMap.find((m) => m.base === base && m.file === moduleKey);
|
|
632
|
+
if (mapping) {
|
|
633
|
+
importNameMap.push({
|
|
634
|
+
base: mapping.base,
|
|
635
|
+
file: depsTree.file,
|
|
636
|
+
newName: mapping.newName,
|
|
637
|
+
});
|
|
638
|
+
const newImportClause = factory.updateImportClause(node.importClause, node.importClause.phaseModifier, factory.createIdentifier(mapping.newName), node.importClause.namedBindings);
|
|
639
|
+
return factory.updateImportDeclaration(node, node.modifiers, newImportClause, node.moduleSpecifier, node.attributes);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
// import name , `import{ ... }`
|
|
643
|
+
if (baseNames.length > 0 &&
|
|
644
|
+
node.importClause &&
|
|
645
|
+
node.importClause.namedBindings &&
|
|
646
|
+
ts.isNamedImports(node.importClause.namedBindings)) {
|
|
647
|
+
const updatedElements = node.importClause.namedBindings.elements.map((el) => {
|
|
648
|
+
const mapping = exportNameMap.find((m) => m.base === el.name.text.trim() && m.file === moduleKey);
|
|
649
|
+
if (mapping) {
|
|
650
|
+
importNameMap.push({
|
|
651
|
+
base: mapping.base,
|
|
652
|
+
file: depsTree.file,
|
|
653
|
+
newName: mapping.newName,
|
|
654
|
+
});
|
|
655
|
+
return factory.updateImportSpecifier(el, el.isTypeOnly, el.propertyName, factory.createIdentifier(mapping.newName));
|
|
656
|
+
}
|
|
657
|
+
return el;
|
|
658
|
+
});
|
|
659
|
+
const newNamedImports = factory.updateNamedImports(node.importClause.namedBindings, updatedElements);
|
|
660
|
+
const newImportClause = factory.updateImportClause(node.importClause, node.importClause.phaseModifier, node.importClause.name, newNamedImports);
|
|
661
|
+
return factory.updateImportDeclaration(node, node.modifiers, newImportClause, node.moduleSpecifier, node.attributes);
|
|
662
|
+
}
|
|
663
|
+
} //&&
|
|
664
|
+
/* ----------------------Returns for visitor function------------------------------- */
|
|
665
|
+
return ts.visitEachChild(node, visit, context);
|
|
666
|
+
};
|
|
667
|
+
return visit;
|
|
668
|
+
};
|
|
669
|
+
//src/lib/bundle/visitors/duplicateUpdate.ts
|
|
670
|
+
const dupName = uniqueName().setPrefix({
|
|
671
|
+
key: "DuplicatesNames",
|
|
672
|
+
value: "d_",
|
|
673
|
+
});
|
|
674
|
+
/**
|
|
675
|
+
* A BundleVisitor that updates the variable declaration, function declaration, and class declaration
|
|
676
|
+
* with the duplicates name.
|
|
677
|
+
*
|
|
678
|
+
* @param {BundleVisitor} context - The BundleVisitor context.
|
|
679
|
+
* @param {DepsTree} depsTree - The deps tree object.
|
|
680
|
+
* @param {SourceFile} sourceFile - The source file object.
|
|
681
|
+
* @param {DuplicatesNameMap} namesMap - The DuplicatesNameMap object.
|
|
682
|
+
* @param {NamesSets} callNameMap - The NamesSets object.
|
|
683
|
+
* @return {NodeVisit} visit - The NodeVisit function.
|
|
684
|
+
*/
|
|
685
|
+
const duplicateUpdateVisitor = (context, depsTree, _sourceFile, namesMap, callNameMap) => {
|
|
686
|
+
const { factory } = context;
|
|
687
|
+
const visit = (node) => {
|
|
688
|
+
if (ts.isVariableStatement(node)) {
|
|
689
|
+
const newDeclarations = node.declarationList.declarations.map((decl) => {
|
|
690
|
+
if (ts.isIdentifier(decl.name)) {
|
|
691
|
+
const base = decl.name.text;
|
|
692
|
+
// biome-ignore lint/style/noNonNullAssertion : namesMap.has(base) before that get just only size
|
|
693
|
+
if (namesMap.has(base) && namesMap.get(base).size > 1) {
|
|
694
|
+
const newName = dupName.getName(base);
|
|
695
|
+
callNameMap.push({ base, file: depsTree.file, newName });
|
|
696
|
+
return factory.updateVariableDeclaration(decl, factory.createIdentifier(newName), decl.exclamationToken, decl.type, decl.initializer);
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
return decl;
|
|
700
|
+
});
|
|
701
|
+
const newDeclList = factory.updateVariableDeclarationList(node.declarationList, newDeclarations);
|
|
702
|
+
return factory.updateVariableStatement(node, node.modifiers, newDeclList);
|
|
703
|
+
}
|
|
704
|
+
else if (ts.isFunctionDeclaration(node)) {
|
|
705
|
+
if (node.name && ts.isIdentifier(node.name)) {
|
|
706
|
+
const base = node.name.text;
|
|
707
|
+
// biome-ignore lint/style/noNonNullAssertion : namesMap.has(base) before that get just only size
|
|
708
|
+
if (namesMap.has(base) && namesMap.get(base).size > 1) {
|
|
709
|
+
const newName = dupName.getName(base);
|
|
710
|
+
callNameMap.push({ base, file: depsTree.file, newName });
|
|
711
|
+
return factory.updateFunctionDeclaration(node, node.modifiers, node.asteriskToken, factory.createIdentifier(newName), node.typeParameters, node.parameters, node.type, node.body);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
else if (ts.isClassDeclaration(node)) {
|
|
716
|
+
if (node.name && ts.isIdentifier(node.name)) {
|
|
717
|
+
const base = node.name.text;
|
|
718
|
+
// biome-ignore lint/style/noNonNullAssertion : namesMap.has(base) before that get just only size
|
|
719
|
+
if (namesMap.has(base) && namesMap.get(base).size > 1) {
|
|
720
|
+
const newName = dupName.getName(base);
|
|
721
|
+
callNameMap.push({ base, file: depsTree.file, newName });
|
|
722
|
+
return factory.updateClassDeclaration(node, node.modifiers, factory.createIdentifier(newName), node.typeParameters, node.heritageClauses, node.members);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
/* ----------------------Returns for visitor function------------------------------- */
|
|
727
|
+
return ts.visitEachChild(node, visit, context);
|
|
728
|
+
};
|
|
729
|
+
return visit;
|
|
730
|
+
};
|
|
731
|
+
//src/lib/bundle/visitors/removeExports.ts
|
|
732
|
+
/**
|
|
733
|
+
* A BundleVisitor that removes all exports from the given source file.
|
|
734
|
+
* It does so by stripping "export" modifiers from function, class, interface, type alias, enum, and variable declarations,
|
|
735
|
+
* and by removing "export { foo }" and "export default" declarations entirely.
|
|
736
|
+
*/
|
|
737
|
+
const removeExportsVisitor = (context) => {
|
|
738
|
+
const { factory } = context;
|
|
739
|
+
const visit = (node) => {
|
|
740
|
+
// --- Case 1: Strip "export" modifiers ---
|
|
741
|
+
const inside_nameSpace = utilities.isInsideNamespace(node);
|
|
742
|
+
if (!inside_nameSpace) {
|
|
743
|
+
if (ts.isFunctionDeclaration(node) ||
|
|
744
|
+
ts.isClassDeclaration(node) ||
|
|
745
|
+
ts.isInterfaceDeclaration(node) ||
|
|
746
|
+
ts.isTypeAliasDeclaration(node) ||
|
|
747
|
+
ts.isEnumDeclaration(node) ||
|
|
748
|
+
ts.isVariableStatement(node)) {
|
|
749
|
+
const modifiers = node.modifiers?.filter((m) => m.kind !== ts.SyntaxKind.ExportKeyword &&
|
|
750
|
+
m.kind !== ts.SyntaxKind.DefaultKeyword);
|
|
751
|
+
if (modifiers?.length !== node.modifiers?.length) {
|
|
752
|
+
// If the node has an export modifier, remove it.
|
|
753
|
+
// If the node is a function, class, interface, type alias, enum or variable declaration,
|
|
754
|
+
// update the declaration by removing the export modifier.
|
|
755
|
+
if (ts.isFunctionDeclaration(node)) {
|
|
756
|
+
return factory.updateFunctionDeclaration(node, modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body);
|
|
757
|
+
} // function
|
|
758
|
+
if (ts.isClassDeclaration(node)) {
|
|
759
|
+
return factory.updateClassDeclaration(node, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members);
|
|
760
|
+
} // class
|
|
761
|
+
if (ts.isInterfaceDeclaration(node)) {
|
|
762
|
+
return factory.updateInterfaceDeclaration(node, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members);
|
|
763
|
+
} // interface
|
|
764
|
+
if (ts.isTypeAliasDeclaration(node)) {
|
|
765
|
+
return factory.updateTypeAliasDeclaration(node, modifiers, node.name, node.typeParameters, node.type);
|
|
766
|
+
} // types
|
|
767
|
+
if (ts.isEnumDeclaration(node)) {
|
|
768
|
+
return factory.updateEnumDeclaration(node, modifiers, node.name, node.members);
|
|
769
|
+
} //enum
|
|
770
|
+
if (ts.isVariableStatement(node)) {
|
|
771
|
+
return factory.updateVariableStatement(node, modifiers, node.declarationList);
|
|
772
|
+
} // vars
|
|
773
|
+
} //--
|
|
774
|
+
} // --- Case 1
|
|
775
|
+
}
|
|
776
|
+
// --- Case 2: Remove "export { foo }" entirely ---
|
|
777
|
+
if (ts.isExportDeclaration(node)) {
|
|
778
|
+
// If the node is an export declaration, remove it.
|
|
779
|
+
return factory.createEmptyStatement();
|
|
780
|
+
}
|
|
781
|
+
// --- Case 3: Handle "export default ..." ---
|
|
782
|
+
if (ts.isExportAssignment(node)) {
|
|
783
|
+
const expr = node.expression;
|
|
784
|
+
// export default Foo; -> remove line
|
|
785
|
+
if (ts.isIdentifier(expr)) {
|
|
786
|
+
return factory.createEmptyStatement();
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
// --------- Visitor Return ------------------//
|
|
790
|
+
return ts.visitEachChild(node, visit, context);
|
|
791
|
+
};
|
|
792
|
+
return visit;
|
|
793
|
+
};
|
|
794
|
+
//src/lib/bundle/visitors/removeImports.ts
|
|
795
|
+
let properties = [];
|
|
796
|
+
const typeObj = {};
|
|
797
|
+
const typesNames = [];
|
|
798
|
+
function findProperty(node) {
|
|
799
|
+
const properties = [];
|
|
800
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.expression)) {
|
|
801
|
+
properties.push(node.expression.text);
|
|
802
|
+
}
|
|
803
|
+
node.forEachChild((n) => findProperty(n));
|
|
804
|
+
return properties;
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* A BundleVisitor that removes import declarations and import equals declarations from a TypeScript program.
|
|
808
|
+
* The visitor collects the names of type-only import-equals and emits a named/default type import if the type-only import-equals is not a namespace-type alias.
|
|
809
|
+
* The visitor also collects the names of type-only imports of namespace-type aliases and emits a namespace type import if the type-only import-equals is not a namespace-type alias.
|
|
810
|
+
*/
|
|
811
|
+
const removeImportsVisitor = (context, depsTree, sourceFile, removedStatements) => {
|
|
812
|
+
// Pre-scan: collect names of type-only import-equals (these are namespace-type aliases)
|
|
813
|
+
// import type NameSpace = require("foo")
|
|
814
|
+
const typeOnlyImportEquals = new Set();
|
|
815
|
+
for (const stmt of sourceFile.statements) {
|
|
816
|
+
if (ts.isImportEqualsDeclaration(stmt) && stmt.isTypeOnly) {
|
|
817
|
+
const moduleReference = stmt.moduleReference;
|
|
818
|
+
if (ts.isExternalModuleReference(moduleReference) &&
|
|
819
|
+
ts.isStringLiteral(moduleReference.expression)) {
|
|
820
|
+
typeOnlyImportEquals.add(stmt.name.text);
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
const { factory } = context;
|
|
825
|
+
const visit = (node) => {
|
|
826
|
+
properties = [...properties, ...findProperty(node)];
|
|
827
|
+
const obj = {
|
|
828
|
+
isNamespace: false,
|
|
829
|
+
isTypeOnly: false,
|
|
830
|
+
isTypeNamespace: false,
|
|
831
|
+
source: "",
|
|
832
|
+
importedString: undefined,
|
|
833
|
+
importedObject: undefined,
|
|
834
|
+
};
|
|
835
|
+
// --- Case: TypeReference with QualifiedName (collect type usage)
|
|
836
|
+
if (ts.isTypeReferenceNode(node) &&
|
|
837
|
+
ts.isQualifiedName(node.typeName) &&
|
|
838
|
+
ts.isIdentifier(node.typeName.left) &&
|
|
839
|
+
ts.isIdentifier(node.typeName.right)) {
|
|
840
|
+
const left = node.typeName.left.text;
|
|
841
|
+
const right = node.typeName.right.text;
|
|
842
|
+
typesNames.push(left);
|
|
843
|
+
if (left in typeObj) {
|
|
844
|
+
typeObj[left]?.push(right);
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
typeObj[left] = [right];
|
|
848
|
+
}
|
|
849
|
+
// If this qualified name refers to a type-only import-equals alias, DO NOT rewrite.
|
|
850
|
+
// Rewriting (Foo.Bar -> Bar) was intended to support converting to named imports,
|
|
851
|
+
// but for type-only namespace imports we will emit `import type * as Foo from "..."`.
|
|
852
|
+
if (utilities.checkModuleType(sourceFile, depsTree.file).isCommonJs) {
|
|
853
|
+
if (left !== "ts" && !typeOnlyImportEquals.has(left)) {
|
|
854
|
+
return factory.updateTypeReferenceNode(node, factory.createIdentifier(right), undefined);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
// ------------------------
|
|
859
|
+
if (ts.isImportDeclaration(node)) {
|
|
860
|
+
// --- Case 1: Import declarations
|
|
861
|
+
const text = node.getText(sourceFile);
|
|
862
|
+
removedStatements.push(text);
|
|
863
|
+
return factory.createEmptyStatement();
|
|
864
|
+
}
|
|
865
|
+
//--- Case 2: Import equals declarations
|
|
866
|
+
if (ts.isImportEqualsDeclaration(node)) {
|
|
867
|
+
const name = node.name.text;
|
|
868
|
+
const moduleReference = node.moduleReference;
|
|
869
|
+
if (node.isTypeOnly) {
|
|
870
|
+
obj.isTypeOnly = true;
|
|
871
|
+
}
|
|
872
|
+
obj.importedString = name;
|
|
873
|
+
if (!obj.isTypeOnly) {
|
|
874
|
+
if (properties.includes(name)) {
|
|
875
|
+
obj.isNamespace = true;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
if (ts.isExternalModuleReference(moduleReference) &&
|
|
879
|
+
ts.isStringLiteral(moduleReference.expression)) {
|
|
880
|
+
obj.source = moduleReference.expression.text;
|
|
881
|
+
}
|
|
882
|
+
let t;
|
|
883
|
+
if (obj.importedString && !obj.importedObject) {
|
|
884
|
+
if (obj.isTypeOnly) {
|
|
885
|
+
// If this import-equals was a type-only namespace alias, emit a namespace type import
|
|
886
|
+
if (typeOnlyImportEquals.has(obj.importedString)) {
|
|
887
|
+
t = `import type * as ${obj.importedString} from "${obj.source}";`;
|
|
888
|
+
}
|
|
889
|
+
else {
|
|
890
|
+
// otherwise try to emit a named/default type import (existing behavior)
|
|
891
|
+
if (typesNames.includes(obj.importedString)) {
|
|
892
|
+
t = `import type { ${typeObj[obj.importedString]?.join(",")} } from "${obj.source}";`;
|
|
893
|
+
}
|
|
894
|
+
else {
|
|
895
|
+
t = `import type ${obj.importedString} from "${obj.source}";`;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
else {
|
|
900
|
+
if (obj.isNamespace && obj.source && obj.source !== "typescript") {
|
|
901
|
+
t = `import * as ${obj.importedString} from "${obj.source}";`;
|
|
902
|
+
}
|
|
903
|
+
else {
|
|
904
|
+
t = `import ${obj.importedString} from "${obj.source}";`;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
if (!obj.importedString && obj.importedObject) {
|
|
909
|
+
t = `import { ${obj.importedObject.join(", ")} } from "${obj.source}";`;
|
|
910
|
+
}
|
|
911
|
+
// removed
|
|
912
|
+
if (t) {
|
|
913
|
+
removedStatements.push(t);
|
|
914
|
+
return factory.createEmptyStatement();
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
// --- Case 3: Require imports
|
|
918
|
+
if (ts.isVariableStatement(node)) {
|
|
919
|
+
const decls = node.declarationList.declarations;
|
|
920
|
+
if (decls.length === 1) {
|
|
921
|
+
const decl = decls[0];
|
|
922
|
+
if (decl.initializer &&
|
|
923
|
+
ts.isCallExpression(decl.initializer) &&
|
|
924
|
+
ts.isIdentifier(decl.initializer.expression) &&
|
|
925
|
+
decl.initializer.expression.escapedText === "require") {
|
|
926
|
+
// imported from
|
|
927
|
+
const arg = decl.initializer.arguments[0];
|
|
928
|
+
if (ts.isStringLiteral(arg)) {
|
|
929
|
+
obj.source = arg.text;
|
|
930
|
+
}
|
|
931
|
+
if (ts.isIdentifier(decl.name)) {
|
|
932
|
+
const _n = decl.name.text;
|
|
933
|
+
obj.importedString = _n;
|
|
934
|
+
if (properties.includes(_n)) {
|
|
935
|
+
obj.isNamespace = true;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
else if (ts.isObjectBindingPattern(decl.name)) {
|
|
939
|
+
const _names = [];
|
|
940
|
+
for (const ele of decl.name.elements) {
|
|
941
|
+
if (ts.isIdentifier(ele.name)) {
|
|
942
|
+
_names.push(ele.name.text);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
if (_names.length > 0) {
|
|
946
|
+
obj.importedObject = _names;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
let tt;
|
|
950
|
+
if (obj.importedString && !obj.importedObject) {
|
|
951
|
+
if (obj.isNamespace) {
|
|
952
|
+
tt = `import * as ${obj.importedString} from "${obj.source}";`;
|
|
953
|
+
}
|
|
954
|
+
else {
|
|
955
|
+
tt = `import ${obj.importedString} from "${obj.source}";`;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
if (!obj.importedString && obj.importedObject) {
|
|
959
|
+
tt = `import { ${obj.importedObject.join(", ")} } from "${obj.source}";`;
|
|
960
|
+
}
|
|
961
|
+
if (tt) {
|
|
962
|
+
removedStatements.push(tt);
|
|
963
|
+
return factory.createEmptyStatement();
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
// --------- Visitor Return ------------------//
|
|
969
|
+
return ts.visitEachChild(node, visit, context);
|
|
970
|
+
};
|
|
971
|
+
return visit;
|
|
972
|
+
};
|
|
973
|
+
//src/lib/bundle/index.ts
|
|
974
|
+
// ------------------------------------------------------------------------------------//
|
|
975
|
+
/**
|
|
976
|
+
* Bundles a TypeScript project into a single file.
|
|
977
|
+
* This function takes a {@link CollatedPoint} object as input and returns a {@link BundleResultPoint} object.
|
|
978
|
+
* The function applies the following steps:
|
|
979
|
+
* 1. Call dependency plugins.
|
|
980
|
+
* 2. Handle duplicates.
|
|
981
|
+
* 3. Handling anonymous imports and exports.
|
|
982
|
+
* 4. Remove Imports.
|
|
983
|
+
* 5. Remove Exports from dependencies only.
|
|
984
|
+
* 6. Handle imported statements.
|
|
985
|
+
* 7. Create final content.
|
|
986
|
+
* 8. Call pre-process plugins.
|
|
987
|
+
* 9. Returns.
|
|
988
|
+
* @param {CollatedPoint} point - A {@link CollatedPoint} object.
|
|
989
|
+
* @returns {Promise<BundleResultPoint>} - A promise resolves with a {@link BundleResultPoint} object.
|
|
990
|
+
*/
|
|
991
|
+
async function bundler(point) {
|
|
992
|
+
let depsFiles = point.depFiles;
|
|
993
|
+
const reName = point.rename;
|
|
994
|
+
const compilerOptions = point.tsOptions.default;
|
|
995
|
+
const plugins = point.plugins;
|
|
996
|
+
// construct maps
|
|
197
997
|
const namesMap = new Map();
|
|
198
998
|
const callNameMap = [];
|
|
199
999
|
const importNameMap = [];
|
|
@@ -201,30 +1001,156 @@ async function bundler({ depsFiles, compilerOptions, renameDuplicates, }) {
|
|
|
201
1001
|
const exportDefaultExportNameMap = [];
|
|
202
1002
|
const exportDefaultImportNameMap = [];
|
|
203
1003
|
let removedStatements = [];
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
1004
|
+
const duplicate = async (reName) => {
|
|
1005
|
+
if (reName) {
|
|
1006
|
+
// order is important here
|
|
1007
|
+
const re_name = resolves([
|
|
1008
|
+
// collector
|
|
1009
|
+
[bundleCreator, duplicateCollectionVisitor, compilerOptions, namesMap],
|
|
1010
|
+
// update
|
|
1011
|
+
[
|
|
1012
|
+
bundleCreator,
|
|
1013
|
+
duplicateUpdateVisitor,
|
|
1014
|
+
compilerOptions,
|
|
1015
|
+
namesMap,
|
|
1016
|
+
callNameMap,
|
|
1017
|
+
],
|
|
1018
|
+
// call exp
|
|
1019
|
+
[
|
|
1020
|
+
bundleCreator,
|
|
1021
|
+
duplicateCallExpressionVisitor,
|
|
1022
|
+
compilerOptions,
|
|
1023
|
+
callNameMap,
|
|
1024
|
+
importNameMap,
|
|
1025
|
+
],
|
|
1026
|
+
// export exp
|
|
1027
|
+
[
|
|
1028
|
+
bundleCreator,
|
|
1029
|
+
duplicateExportExpressionVisitor,
|
|
1030
|
+
compilerOptions,
|
|
1031
|
+
importNameMap,
|
|
1032
|
+
exportNameMap,
|
|
1033
|
+
],
|
|
1034
|
+
// import exp
|
|
1035
|
+
[
|
|
1036
|
+
bundleCreator,
|
|
1037
|
+
duplicateImportExpressionVisitor,
|
|
1038
|
+
compilerOptions,
|
|
1039
|
+
exportNameMap,
|
|
1040
|
+
importNameMap,
|
|
1041
|
+
],
|
|
1042
|
+
// export exp again
|
|
1043
|
+
[
|
|
1044
|
+
bundleCreator,
|
|
1045
|
+
duplicateExportExpressionVisitor,
|
|
1046
|
+
compilerOptions,
|
|
1047
|
+
importNameMap,
|
|
1048
|
+
exportNameMap,
|
|
1049
|
+
],
|
|
1050
|
+
// export exp again
|
|
1051
|
+
[
|
|
1052
|
+
bundleCreator,
|
|
1053
|
+
duplicateExportExpressionVisitor,
|
|
1054
|
+
compilerOptions,
|
|
1055
|
+
importNameMap,
|
|
1056
|
+
exportNameMap,
|
|
1057
|
+
],
|
|
1058
|
+
]); // re_name
|
|
1059
|
+
const re_name_call = await re_name.concurrent();
|
|
1060
|
+
for (const call of re_name_call) {
|
|
1061
|
+
await utilities.wait(500);
|
|
1062
|
+
depsFiles = depsFiles.map(call);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
else {
|
|
1066
|
+
let _err = false;
|
|
1067
|
+
const un_rename = resolves([
|
|
1068
|
+
// collector
|
|
1069
|
+
[bundleCreator, duplicateCollectionVisitor, compilerOptions, namesMap],
|
|
1070
|
+
]);
|
|
1071
|
+
const un_rename_call = await un_rename.concurrent();
|
|
1072
|
+
depsFiles.map(un_rename_call[0]);
|
|
1073
|
+
await utilities.wait(1000);
|
|
1074
|
+
namesMap.forEach((files, name) => {
|
|
1075
|
+
if (files.size > 1) {
|
|
1076
|
+
_err = true;
|
|
1077
|
+
console.warn(`Name -> ${name} declared in multiple files :`);
|
|
1078
|
+
// biome-ignore lint/suspicious/useIterableCallbackReturn : just log warn
|
|
1079
|
+
files.forEach((f) => console.warn(` - ${f.file}`));
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
await utilities.wait(1000);
|
|
1083
|
+
if (_err) {
|
|
1084
|
+
process.exit(1);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
};
|
|
1088
|
+
// 1. Call dependency plugins
|
|
1089
|
+
if (plugins.length) {
|
|
1090
|
+
for (let plugin of plugins) {
|
|
1091
|
+
plugin = typeof plugin === "function" ? plugin() : plugin;
|
|
1092
|
+
if (plugin.type === "dependency") {
|
|
1093
|
+
if (plugin.async) {
|
|
1094
|
+
depsFiles = await plugin.func(depsFiles);
|
|
1095
|
+
}
|
|
1096
|
+
else {
|
|
1097
|
+
depsFiles = plugin.func(depsFiles);
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
} //--
|
|
1102
|
+
await utilities.wait(1000);
|
|
1103
|
+
// 2. Handle duplicates
|
|
1104
|
+
await duplicate(reName);
|
|
1105
|
+
// 3. Handling anonymous imports and exports
|
|
1106
|
+
const anonymous = resolves([
|
|
1107
|
+
[
|
|
1108
|
+
bundleCreator,
|
|
1109
|
+
anonymousExportVisitor,
|
|
1110
|
+
compilerOptions,
|
|
1111
|
+
exportDefaultExportNameMap,
|
|
1112
|
+
],
|
|
1113
|
+
[
|
|
1114
|
+
bundleCreator,
|
|
1115
|
+
anonymousImportVisitor,
|
|
1116
|
+
compilerOptions,
|
|
1117
|
+
exportDefaultImportNameMap,
|
|
1118
|
+
exportDefaultImportNameMap,
|
|
1119
|
+
],
|
|
1120
|
+
[
|
|
1121
|
+
bundleCreator,
|
|
1122
|
+
anonymousCallExpressionVisitor,
|
|
1123
|
+
compilerOptions,
|
|
1124
|
+
exportDefaultImportNameMap,
|
|
1125
|
+
],
|
|
1126
|
+
]);
|
|
1127
|
+
const anonymousCall = await anonymous.concurrent();
|
|
1128
|
+
for (const call of anonymousCall) {
|
|
1129
|
+
depsFiles = depsFiles.map(call);
|
|
209
1130
|
}
|
|
210
|
-
await
|
|
211
|
-
|
|
212
|
-
await utils.wait(1000);
|
|
1131
|
+
await utilities.wait(1000);
|
|
1132
|
+
// 4. Remove Imports
|
|
213
1133
|
const removeImports = resolves([
|
|
214
|
-
[
|
|
1134
|
+
[bundleCreator, removeImportsVisitor, compilerOptions, removedStatements],
|
|
215
1135
|
]);
|
|
216
1136
|
const removeImport = await removeImports.concurrent();
|
|
217
1137
|
depsFiles = depsFiles.map(removeImport[0]);
|
|
218
|
-
await
|
|
1138
|
+
await utilities.wait(500);
|
|
1139
|
+
// 5. Remove Exports from dependencies only
|
|
219
1140
|
const removeExports = resolves([
|
|
220
|
-
[
|
|
1141
|
+
[bundleCreator, removeExportsVisitor, compilerOptions],
|
|
221
1142
|
]);
|
|
222
1143
|
const removeExport = await removeExports.concurrent();
|
|
1144
|
+
// not remove exports from entry file
|
|
223
1145
|
const deps_files = depsFiles.slice(0, -1).map(removeExport[0]);
|
|
224
1146
|
const mainFile = depsFiles.slice(-1);
|
|
1147
|
+
// 6. Handle imported statements
|
|
1148
|
+
// filter removed statements , that not from local like `./` or `../`
|
|
225
1149
|
const regexp = /["']((?!\.\/|\.\.\/)[^"']+)["']/;
|
|
226
1150
|
removedStatements = removedStatements.filter((i) => regexp.test(i));
|
|
227
|
-
removedStatements =
|
|
1151
|
+
removedStatements = mergeImportsStatement(removedStatements);
|
|
1152
|
+
// 7. Create final content
|
|
1153
|
+
// make sure all imports are at the top of file
|
|
228
1154
|
const importStatements = removedStatements.join("\n").trim();
|
|
229
1155
|
const depFilesContent = deps_files
|
|
230
1156
|
.map((i) => {
|
|
@@ -240,80 +1166,48 @@ async function bundler({ depsFiles, compilerOptions, renameDuplicates, }) {
|
|
|
240
1166
|
})
|
|
241
1167
|
.join("\n")
|
|
242
1168
|
.trim();
|
|
243
|
-
await
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
ts.isIdentifier(node.expression)) {
|
|
257
|
-
defExport = true;
|
|
258
|
-
}
|
|
259
|
-
else if (ts.isFunctionDeclaration(node) ||
|
|
260
|
-
ts.isClassDeclaration(node)) {
|
|
261
|
-
let exp = false;
|
|
262
|
-
let def = false;
|
|
263
|
-
node.modifiers?.forEach((mod) => {
|
|
264
|
-
if (mod.kind === ts.SyntaxKind.ExportKeyword) {
|
|
265
|
-
exp = true;
|
|
266
|
-
}
|
|
267
|
-
if (mod.kind === ts.SyntaxKind.DefaultKeyword) {
|
|
268
|
-
def = true;
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
if (exp && def)
|
|
272
|
-
defExport = true;
|
|
273
|
-
}
|
|
274
|
-
else if (ts.isExportAssignment(node) &&
|
|
275
|
-
ts.isObjectLiteralExpression(node.expression)) {
|
|
276
|
-
const pros = node.expression.properties;
|
|
277
|
-
for (const pro of pros) {
|
|
278
|
-
if (pro.name && ts.isIdentifier(pro.name)) {
|
|
279
|
-
defExport = true;
|
|
280
|
-
}
|
|
1169
|
+
await utilities.wait(1000);
|
|
1170
|
+
// text join order is important here
|
|
1171
|
+
let content = `${importStatements}\n${depFilesContent}\n${mainFileContent}`;
|
|
1172
|
+
// 8. Call pre-process plugins
|
|
1173
|
+
if (plugins.length) {
|
|
1174
|
+
for (let plugin of plugins) {
|
|
1175
|
+
plugin = typeof plugin === "function" ? plugin() : plugin;
|
|
1176
|
+
if (plugin.type === "pre-process") {
|
|
1177
|
+
if (plugin.async) {
|
|
1178
|
+
content = await plugin.func(content);
|
|
1179
|
+
}
|
|
1180
|
+
else {
|
|
1181
|
+
content = plugin.func(content);
|
|
281
1182
|
}
|
|
282
1183
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
current = current.parent;
|
|
298
|
-
}
|
|
299
|
-
return false;
|
|
300
|
-
};
|
|
301
|
-
node?.modifiers?.forEach((mod) => {
|
|
302
|
-
if (mod.kind === ts.SyntaxKind.ExportKeyword) {
|
|
303
|
-
if (!isInsideNamespace(node)) {
|
|
304
|
-
nameExport = true;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
return ts.visitEachChild(node, visitor, context);
|
|
310
|
-
};
|
|
311
|
-
return (rootNode) => ts.visitNode(rootNode, visitor);
|
|
1184
|
+
}
|
|
1185
|
+
} //--
|
|
1186
|
+
// 9. Returns
|
|
1187
|
+
return { bundledContent: content, ...point };
|
|
1188
|
+
}
|
|
1189
|
+
async function bundle(object) {
|
|
1190
|
+
const points = [];
|
|
1191
|
+
for (const point of object.points) {
|
|
1192
|
+
const _point = await bundler(point);
|
|
1193
|
+
points.push(_point);
|
|
1194
|
+
}
|
|
1195
|
+
return {
|
|
1196
|
+
points,
|
|
1197
|
+
allowUpdatePackageJson: object.allowUpdatePackageJson,
|
|
312
1198
|
};
|
|
313
|
-
ts.transform(sourceFile, [transformer]);
|
|
314
|
-
return { nameExport, defExport };
|
|
315
1199
|
}
|
|
316
|
-
|
|
1200
|
+
//src/lib/compile/host.ts
|
|
1201
|
+
/**
|
|
1202
|
+
* Creates a ts.CompilerHost that can be used with the typescript compiler.
|
|
1203
|
+
* This host is designed to be used with in-memory compilation and will
|
|
1204
|
+
* return the source file for the given fileName and will write all output
|
|
1205
|
+
* files to the createdFiles object.
|
|
1206
|
+
* @param {string} sourceCode - the source code to compile
|
|
1207
|
+
* @param {string} fileName - the name of the file to compile
|
|
1208
|
+
* @returns {{createdFiles: Record<string, string>, host: ts.CompilerHost}}
|
|
1209
|
+
*/
|
|
1210
|
+
function createHost(sourceCode, fileName) {
|
|
317
1211
|
const createdFiles = {};
|
|
318
1212
|
const host = {
|
|
319
1213
|
getSourceFile: (file, languageVersion) => {
|
|
@@ -335,80 +1229,129 @@ const createHost = (sourceCode, fileName) => {
|
|
|
335
1229
|
getNewLine: () => "\n",
|
|
336
1230
|
};
|
|
337
1231
|
return { createdFiles, host };
|
|
338
|
-
};
|
|
339
|
-
function replaceInJs(fileName, sourceCode, compilerOptions) {
|
|
340
|
-
const sourceFile = ts.createSourceFile(fileName, sourceCode, ts.ScriptTarget.Latest, true);
|
|
341
|
-
const transformer = (context) => {
|
|
342
|
-
const { factory } = context;
|
|
343
|
-
const visitor = (node) => {
|
|
344
|
-
if (ts.isExpressionStatement(node)) {
|
|
345
|
-
const expr = node.expression;
|
|
346
|
-
if (ts.isBinaryExpression(expr) &&
|
|
347
|
-
ts.isPropertyAccessExpression(expr.left) &&
|
|
348
|
-
ts.isIdentifier(expr.left.expression) &&
|
|
349
|
-
expr.left.expression.escapedText === "exports" &&
|
|
350
|
-
ts.isIdentifier(expr.left.name) &&
|
|
351
|
-
expr.left.name.escapedText === "default" &&
|
|
352
|
-
expr.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
353
|
-
ts.isIdentifier(expr.right)) {
|
|
354
|
-
const newLeftExpr = factory.createIdentifier("module");
|
|
355
|
-
const newName = factory.createIdentifier("exports");
|
|
356
|
-
const newLeft = factory.updatePropertyAccessExpression(expr.left, newLeftExpr, newName);
|
|
357
|
-
const newExpr = factory.updateBinaryExpression(expr, newLeft, expr.operatorToken, expr.right);
|
|
358
|
-
return factory.updateExpressionStatement(node, newExpr);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
return ts.visitEachChild(node, visitor, context);
|
|
362
|
-
};
|
|
363
|
-
return (rootNode) => ts.visitNode(rootNode, visitor);
|
|
364
|
-
};
|
|
365
|
-
return transformFunction(transformer, sourceFile, compilerOptions);
|
|
366
1232
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
1233
|
+
//src/lib/compile/package.ts
|
|
1234
|
+
const isCjs = (files) => files.commonjs && files.commonjsTypes;
|
|
1235
|
+
const isEsm = (files) => files.esm && files.esmTypes;
|
|
1236
|
+
/**
|
|
1237
|
+
* Builds a package exports mapping for the given output files and export path.
|
|
1238
|
+
*
|
|
1239
|
+
* Produces the appropriate export shape based on whether CommonJS and/or ESM
|
|
1240
|
+
* artifacts are present, including their default entry points and type
|
|
1241
|
+
* definitions. If neither format is available, returns an empty object.
|
|
1242
|
+
*
|
|
1243
|
+
* @param files - The build output file paths for CommonJS/ESM and their types.
|
|
1244
|
+
* @param exportPath - The subpath export key (e.g. "." or "./feature").
|
|
1245
|
+
* @returns A {@link Exports} object describing the package exports map.
|
|
1246
|
+
*/
|
|
1247
|
+
function getExports(files, exportPath) {
|
|
1248
|
+
return isCjs(files) && isEsm(files)
|
|
1249
|
+
? {
|
|
1250
|
+
[exportPath]: {
|
|
1251
|
+
import: {
|
|
1252
|
+
types: `./${path.relative(process.cwd(), files.esmTypes)}`,
|
|
1253
|
+
default: `./${path.relative(process.cwd(), files.esm)}`,
|
|
1254
|
+
},
|
|
1255
|
+
require: {
|
|
1256
|
+
types: `./${path.relative(process.cwd(), files.commonjsTypes)}`,
|
|
1257
|
+
default: `./${path.relative(process.cwd(), files.commonjs)}`,
|
|
1258
|
+
},
|
|
1259
|
+
},
|
|
1260
|
+
}
|
|
1261
|
+
: isCjs(files) && !isEsm(files)
|
|
1262
|
+
? {
|
|
1263
|
+
[exportPath]: {
|
|
1264
|
+
require: {
|
|
1265
|
+
types: `./${path.relative(process.cwd(), files.commonjsTypes)}`,
|
|
1266
|
+
default: `./${path.relative(process.cwd(), files.commonjs)}`,
|
|
1267
|
+
},
|
|
1268
|
+
},
|
|
1269
|
+
}
|
|
1270
|
+
: !isCjs(files) && isEsm(files)
|
|
1271
|
+
? {
|
|
1272
|
+
[exportPath]: {
|
|
1273
|
+
import: {
|
|
1274
|
+
types: `./${path.relative(process.cwd(), files.esmTypes)}`,
|
|
1275
|
+
default: `./${path.relative(process.cwd(), files.esm)}`,
|
|
1276
|
+
},
|
|
1277
|
+
},
|
|
1278
|
+
}
|
|
1279
|
+
: {};
|
|
382
1280
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
1281
|
+
/**
|
|
1282
|
+
* Writes an updated `package.json` based on output files and export path.
|
|
1283
|
+
*
|
|
1284
|
+
* Determines module type (ESM/CommonJS), adjusts `main`, `module`, `types`,
|
|
1285
|
+
* and `exports` fields, and preserves other existing fields from the
|
|
1286
|
+
* current `package.json`.
|
|
1287
|
+
*
|
|
1288
|
+
* @param files - The generated output files used to populate entry points.
|
|
1289
|
+
* @param exportPath - The export path for subpath exports; "." denotes main export.
|
|
1290
|
+
*/
|
|
1291
|
+
async function writePackage(files, exportPath) {
|
|
1292
|
+
let isMain = true;
|
|
1293
|
+
if (exportPath !== ".") {
|
|
1294
|
+
isMain = false;
|
|
392
1295
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
1296
|
+
const pkgFile = ts.sys.resolvePath("package.json");
|
|
1297
|
+
const _pkgtext = fs.readFileSync(pkgFile, "utf8");
|
|
1298
|
+
const pkgtext = JSON.parse(_pkgtext);
|
|
1299
|
+
let { name, version, description, main, module, type, types, exports, ...rest } = pkgtext;
|
|
1300
|
+
await utilities.wait(500);
|
|
1301
|
+
type = "module";
|
|
1302
|
+
let _main = {};
|
|
1303
|
+
let _module = {};
|
|
1304
|
+
let _types = {};
|
|
1305
|
+
let _exports = {};
|
|
1306
|
+
if (isMain) {
|
|
1307
|
+
_main = files.main
|
|
1308
|
+
? { main: path.relative(process.cwd(), files.main) }
|
|
1309
|
+
: {};
|
|
1310
|
+
_module = files.module
|
|
1311
|
+
? { module: path.relative(process.cwd(), files.module) }
|
|
1312
|
+
: {};
|
|
1313
|
+
_types = files.types
|
|
1314
|
+
? { types: path.relative(process.cwd(), files.types) }
|
|
1315
|
+
: {};
|
|
1316
|
+
_exports = { exports: { ...getExports(files, exportPath) } };
|
|
397
1317
|
}
|
|
1318
|
+
else {
|
|
1319
|
+
_main = main ? { main: main } : {};
|
|
1320
|
+
_module = module ? { module: module } : {};
|
|
1321
|
+
_types = types ? { types: types } : {};
|
|
1322
|
+
const normalizedExports = exports && typeof exports === "object" && !Array.isArray(exports)
|
|
1323
|
+
? { ...exports }
|
|
1324
|
+
: {};
|
|
1325
|
+
_exports = {
|
|
1326
|
+
exports: { ...normalizedExports, ...getExports(files, exportPath) },
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1329
|
+
await utilities.wait(1000);
|
|
1330
|
+
const pkgJson = {
|
|
1331
|
+
name,
|
|
1332
|
+
version,
|
|
1333
|
+
description,
|
|
1334
|
+
type,
|
|
1335
|
+
..._main,
|
|
1336
|
+
..._types,
|
|
1337
|
+
..._module,
|
|
1338
|
+
..._exports,
|
|
1339
|
+
...rest,
|
|
1340
|
+
};
|
|
1341
|
+
utilities.writeCompileFile(pkgFile, JSON.stringify(pkgJson, null, 2));
|
|
398
1342
|
}
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
1343
|
+
//src/lib/compile/index.ts
|
|
1344
|
+
function splitCamelCase(str) {
|
|
1345
|
+
const splitString = str
|
|
1346
|
+
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
1347
|
+
.replace(/(_|-|\/)([a-z] || [A-Z])/g, " ")
|
|
1348
|
+
.replace(/([A-Z])/g, (match) => match.toLowerCase())
|
|
1349
|
+
.replace(/^([a-z])/, (match) => match.toUpperCase());
|
|
1350
|
+
return splitString;
|
|
407
1351
|
}
|
|
408
|
-
class
|
|
409
|
-
constructor(
|
|
410
|
-
this.
|
|
411
|
-
this._configPath = options?.configPath;
|
|
1352
|
+
class Compiler {
|
|
1353
|
+
constructor(object) {
|
|
1354
|
+
this.object = object;
|
|
412
1355
|
this.files = {
|
|
413
1356
|
commonjs: undefined,
|
|
414
1357
|
commonjsTypes: undefined,
|
|
@@ -418,48 +1361,49 @@ class Compilers {
|
|
|
418
1361
|
module: undefined,
|
|
419
1362
|
types: undefined,
|
|
420
1363
|
};
|
|
421
|
-
this.outDir = "";
|
|
422
1364
|
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
1365
|
+
_isUpdate() {
|
|
1366
|
+
return this.object.allowUpdatePackageJson;
|
|
1367
|
+
}
|
|
1368
|
+
async _commonjs(point) {
|
|
1369
|
+
const isMain = point.exportPath === ".";
|
|
1370
|
+
const _name = isMain ? "Main" : splitCamelCase(point.exportPath.slice(2));
|
|
1371
|
+
console.time(tcolor.cyan(`Compiled commonjs for ${_name} export path`));
|
|
1372
|
+
// init
|
|
1373
|
+
const fileName = point.fileName;
|
|
1374
|
+
const sourceCode = point.bundledContent;
|
|
1375
|
+
const format = point.format;
|
|
1376
|
+
const plugins = point.plugins;
|
|
1377
|
+
const compilerOptions = point.tsOptions.cjs;
|
|
1378
|
+
// create host
|
|
429
1379
|
const _host = createHost(sourceCode, fileName);
|
|
430
1380
|
const createdFiles = _host.createdFiles;
|
|
431
1381
|
const host = _host.host;
|
|
432
1382
|
const program = ts.createProgram([fileName], compilerOptions, host);
|
|
433
1383
|
program.emit();
|
|
434
1384
|
Object.entries(createdFiles).map(async ([outName, content]) => {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
if (hook.async) {
|
|
447
|
-
content = await hook.func(content, outName);
|
|
448
|
-
}
|
|
449
|
-
else {
|
|
450
|
-
content = hook.func(content, outName);
|
|
1385
|
+
// ------------------------------------
|
|
1386
|
+
if (plugins.length) {
|
|
1387
|
+
for (let plugin of plugins) {
|
|
1388
|
+
plugin = typeof plugin === "function" ? plugin() : plugin;
|
|
1389
|
+
if (plugin.type === "post-process") {
|
|
1390
|
+
if (plugin.async) {
|
|
1391
|
+
content = await plugin.func(content, outName);
|
|
1392
|
+
}
|
|
1393
|
+
else {
|
|
1394
|
+
content = plugin.func(content, outName);
|
|
1395
|
+
}
|
|
451
1396
|
}
|
|
452
1397
|
}
|
|
453
1398
|
}
|
|
454
|
-
if (
|
|
1399
|
+
if (this._isUpdate()) {
|
|
455
1400
|
if (outName.match(/.js/g)) {
|
|
456
1401
|
this.files.commonjs = outName.replace(/.js/g, ".cjs");
|
|
457
1402
|
}
|
|
458
1403
|
if (outName.match(/.d.ts/g)) {
|
|
459
1404
|
this.files.commonjsTypes = outName.replace(/.d.ts/g, ".d.cts");
|
|
460
1405
|
}
|
|
461
|
-
if (isMain &&
|
|
462
|
-
(this._target === "both" || this._target === "commonjs")) {
|
|
1406
|
+
if (isMain && (format === "both" || format === "commonjs")) {
|
|
463
1407
|
if (this.files.commonjs)
|
|
464
1408
|
this.files.main = this.files.commonjs;
|
|
465
1409
|
if (this.files.commonjsTypes)
|
|
@@ -469,61 +1413,121 @@ class Compilers {
|
|
|
469
1413
|
outName = outName.replace(/.js/g, ".cjs");
|
|
470
1414
|
outName = outName.replace(/.map.js/g, ".map.cjs");
|
|
471
1415
|
outName = outName.replace(/.d.ts/g, ".d.cts");
|
|
472
|
-
await
|
|
473
|
-
if (
|
|
474
|
-
await clearFolder(
|
|
1416
|
+
await utilities.wait(500);
|
|
1417
|
+
if (format === "commonjs") {
|
|
1418
|
+
await utilities.clearFolder(path.dirname(outName));
|
|
475
1419
|
}
|
|
476
|
-
await writeCompileFile(outName, content);
|
|
1420
|
+
await utilities.writeCompileFile(outName, content);
|
|
477
1421
|
});
|
|
478
|
-
console.timeEnd(tcolor.
|
|
1422
|
+
console.timeEnd(tcolor.cyan(`Compiled commonjs for ${_name} export path`));
|
|
479
1423
|
}
|
|
480
|
-
async
|
|
481
|
-
|
|
1424
|
+
async _esm(point) {
|
|
1425
|
+
const isMain = point.exportPath === ".";
|
|
1426
|
+
const _name = isMain ? "Main" : splitCamelCase(point.exportPath.slice(2));
|
|
1427
|
+
console.time(tcolor.cyan(`Compiled esm for ${_name} export path`));
|
|
1428
|
+
// init
|
|
1429
|
+
const fileName = point.fileName;
|
|
1430
|
+
const sourceCode = point.bundledContent;
|
|
1431
|
+
const format = point.format;
|
|
1432
|
+
const plugins = point.plugins;
|
|
1433
|
+
const compilerOptions = point.tsOptions.esm;
|
|
1434
|
+
// create host
|
|
482
1435
|
const _host = createHost(sourceCode, fileName);
|
|
483
1436
|
const createdFiles = _host.createdFiles;
|
|
484
1437
|
const host = _host.host;
|
|
485
1438
|
const program = ts.createProgram([fileName], compilerOptions, host);
|
|
486
1439
|
program.emit();
|
|
487
1440
|
Object.entries(createdFiles).map(async ([outName, content]) => {
|
|
488
|
-
if (
|
|
489
|
-
for (
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
1441
|
+
if (plugins.length) {
|
|
1442
|
+
for (let plugin of plugins) {
|
|
1443
|
+
plugin = typeof plugin === "function" ? plugin() : plugin;
|
|
1444
|
+
if (plugin.type === "post-process") {
|
|
1445
|
+
if (plugin.async) {
|
|
1446
|
+
content = await plugin.func(content, outName);
|
|
1447
|
+
}
|
|
1448
|
+
else {
|
|
1449
|
+
content = plugin.func(content, outName);
|
|
1450
|
+
}
|
|
495
1451
|
}
|
|
496
1452
|
}
|
|
497
1453
|
}
|
|
498
|
-
|
|
1454
|
+
// ------------------------------------------
|
|
1455
|
+
if (this._isUpdate()) {
|
|
499
1456
|
if (outName.match(/.js/g)) {
|
|
500
1457
|
this.files.esm = outName.replace(/.js/g, ".mjs");
|
|
501
1458
|
}
|
|
502
1459
|
if (outName.match(/.d.ts/g)) {
|
|
503
1460
|
this.files.esmTypes = outName.replace(/.d.ts/g, ".d.mts");
|
|
504
1461
|
}
|
|
505
|
-
if (isMain &&
|
|
1462
|
+
if (isMain && format === "both" && this.files.esm) {
|
|
506
1463
|
this.files.module = this.files.esm;
|
|
507
1464
|
}
|
|
508
1465
|
}
|
|
509
1466
|
outName = outName.replace(/.js/g, ".mjs");
|
|
510
1467
|
outName = outName.replace(/.map.js/g, ".map.mjs");
|
|
511
1468
|
outName = outName.replace(/.d.ts/g, ".d.mts");
|
|
512
|
-
await
|
|
513
|
-
if (
|
|
514
|
-
await clearFolder(
|
|
1469
|
+
await utilities.wait(500);
|
|
1470
|
+
if (format !== "commonjs") {
|
|
1471
|
+
await utilities.clearFolder(path.dirname(outName));
|
|
515
1472
|
}
|
|
516
|
-
await writeCompileFile(outName, content);
|
|
1473
|
+
await utilities.writeCompileFile(outName, content);
|
|
517
1474
|
});
|
|
518
|
-
console.timeEnd(tcolor.
|
|
1475
|
+
console.timeEnd(tcolor.cyan(`Compiled esm for ${_name} export path`));
|
|
1476
|
+
}
|
|
1477
|
+
/**
|
|
1478
|
+
* Compile bundled code for each entry point.
|
|
1479
|
+
* This function will iterate through each entry point and compile code according to the format specified.
|
|
1480
|
+
* If the format is "commonjs", it will compile the code into commonjs format.
|
|
1481
|
+
* If the format is "esm", it will compile the code into esm format.
|
|
1482
|
+
* If the format is "both", it will compile the code into both commonjs and esm formats.
|
|
1483
|
+
* If the allowUpdatePackageJson flag is set to true, it will update the package.json according to the compiled file paths.
|
|
1484
|
+
*/
|
|
1485
|
+
async compile() {
|
|
1486
|
+
for (const point of this.object.points) {
|
|
1487
|
+
await utilities.wait(500);
|
|
1488
|
+
switch (point.format) {
|
|
1489
|
+
case "commonjs":
|
|
1490
|
+
await this._commonjs(point);
|
|
1491
|
+
if (this._isUpdate()) {
|
|
1492
|
+
await writePackage(this.files, point.exportPath);
|
|
1493
|
+
}
|
|
1494
|
+
break;
|
|
1495
|
+
case "esm":
|
|
1496
|
+
await this._esm(point);
|
|
1497
|
+
if (this._isUpdate()) {
|
|
1498
|
+
await writePackage(this.files, point.exportPath);
|
|
1499
|
+
}
|
|
1500
|
+
break;
|
|
1501
|
+
case "both":
|
|
1502
|
+
await this._esm(point);
|
|
1503
|
+
await utilities.wait(1000);
|
|
1504
|
+
await this._commonjs(point);
|
|
1505
|
+
if (this._isUpdate()) {
|
|
1506
|
+
await writePackage(this.files, point.exportPath);
|
|
1507
|
+
}
|
|
1508
|
+
break;
|
|
1509
|
+
}
|
|
1510
|
+
await utilities.wait(500);
|
|
1511
|
+
}
|
|
519
1512
|
}
|
|
520
1513
|
}
|
|
521
|
-
|
|
522
|
-
|
|
1514
|
+
//src/lib/init/checks.ts
|
|
1515
|
+
var checks;
|
|
1516
|
+
(function (checks) {
|
|
1517
|
+
/**
|
|
1518
|
+
* Checks the given dependencies for type errors. If any type errors are found,
|
|
1519
|
+
* an error message is printed to the console and the process exits with a code of 1.
|
|
1520
|
+
* @param dep The dependencies to check for type errors
|
|
1521
|
+
* @param compilerOptions The compiler options to use when checking for type errors
|
|
1522
|
+
* @returns true if no type errors are found, false otherwise
|
|
1523
|
+
*/
|
|
1524
|
+
function typesCheck(dep, compilerOptions) {
|
|
523
1525
|
if (!compilerOptions.noCheck) {
|
|
524
|
-
const filePaths =
|
|
1526
|
+
const filePaths = dep.map((i) => i.file);
|
|
525
1527
|
let _err = false;
|
|
1528
|
+
// Create program
|
|
526
1529
|
const program = ts.createProgram(filePaths, compilerOptions);
|
|
1530
|
+
// Check each file individually for immediate feedback
|
|
527
1531
|
for (const filePath of filePaths) {
|
|
528
1532
|
const sourceFile = program.getSourceFile(filePath);
|
|
529
1533
|
if (!sourceFile) {
|
|
@@ -552,28 +1556,25 @@ const depsCheck = {
|
|
|
552
1556
|
return true;
|
|
553
1557
|
}
|
|
554
1558
|
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
ts.sys.exit(1);
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
return true;
|
|
566
|
-
},
|
|
567
|
-
moduleType(deps) {
|
|
1559
|
+
}
|
|
1560
|
+
/**
|
|
1561
|
+
* Check the module type of the given dependencies.
|
|
1562
|
+
* @param _dep The dependencies to check for module type
|
|
1563
|
+
* @returns true if all dependencies are ESM, false otherwise
|
|
1564
|
+
*/
|
|
1565
|
+
function moduleType(_dep) {
|
|
568
1566
|
let _esmCount = 0;
|
|
569
1567
|
let cjsCount = 0;
|
|
570
|
-
let
|
|
571
|
-
for (const dep of
|
|
1568
|
+
let unknownCount = 0;
|
|
1569
|
+
for (const dep of _dep) {
|
|
572
1570
|
try {
|
|
1571
|
+
// Create a TypeScript source file
|
|
573
1572
|
const sourceFile = ts.createSourceFile(dep.file, dep.content, ts.ScriptTarget.Latest, true);
|
|
574
1573
|
let hasESMImports = false;
|
|
575
1574
|
let hasCommonJS = false;
|
|
1575
|
+
// Walk through the AST to detect module syntax
|
|
576
1576
|
function walk(node) {
|
|
1577
|
+
// Check for ESM import/export syntax
|
|
577
1578
|
if (ts.isImportDeclaration(node) ||
|
|
578
1579
|
ts.isImportEqualsDeclaration(node) ||
|
|
579
1580
|
ts.isExportDeclaration(node) ||
|
|
@@ -581,6 +1582,7 @@ const depsCheck = {
|
|
|
581
1582
|
ts.isExportAssignment(node)) {
|
|
582
1583
|
hasESMImports = true;
|
|
583
1584
|
}
|
|
1585
|
+
// Check for export modifier on declarations
|
|
584
1586
|
if ((ts.isVariableStatement(node) ||
|
|
585
1587
|
ts.isFunctionDeclaration(node) ||
|
|
586
1588
|
ts.isInterfaceDeclaration(node) ||
|
|
@@ -590,6 +1592,7 @@ const depsCheck = {
|
|
|
590
1592
|
node.modifiers?.some((mod) => mod.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
591
1593
|
hasESMImports = true;
|
|
592
1594
|
}
|
|
1595
|
+
// Check for CommonJS require/exports
|
|
593
1596
|
if (ts.isCallExpression(node)) {
|
|
594
1597
|
if (ts.isIdentifier(node.expression) &&
|
|
595
1598
|
node.expression.text === "require" &&
|
|
@@ -597,6 +1600,7 @@ const depsCheck = {
|
|
|
597
1600
|
hasCommonJS = true;
|
|
598
1601
|
}
|
|
599
1602
|
}
|
|
1603
|
+
// Check for module.exports or exports.xxx
|
|
600
1604
|
if (ts.isPropertyAccessExpression(node)) {
|
|
601
1605
|
const text = node.getText(sourceFile);
|
|
602
1606
|
if (text.startsWith("module.exports") ||
|
|
@@ -604,9 +1608,11 @@ const depsCheck = {
|
|
|
604
1608
|
hasCommonJS = true;
|
|
605
1609
|
}
|
|
606
1610
|
}
|
|
1611
|
+
// Continue walking the AST
|
|
607
1612
|
ts.forEachChild(node, walk);
|
|
608
1613
|
}
|
|
609
1614
|
walk(sourceFile);
|
|
1615
|
+
// Determine the module format based on what we found
|
|
610
1616
|
if (hasESMImports && !hasCommonJS) {
|
|
611
1617
|
_esmCount++;
|
|
612
1618
|
}
|
|
@@ -614,15 +1620,16 @@ const depsCheck = {
|
|
|
614
1620
|
cjsCount++;
|
|
615
1621
|
}
|
|
616
1622
|
else if (hasESMImports && hasCommonJS) {
|
|
1623
|
+
// Mixed - probably ESM with dynamic imports or similar
|
|
617
1624
|
_esmCount++;
|
|
618
1625
|
}
|
|
619
1626
|
}
|
|
620
1627
|
catch (error) {
|
|
621
1628
|
console.error(tcolor.magenta(`Error checking module format for ${dep.file} : \n ${error}`));
|
|
622
|
-
|
|
1629
|
+
unknownCount++;
|
|
623
1630
|
}
|
|
624
1631
|
}
|
|
625
|
-
if (
|
|
1632
|
+
if (unknownCount) {
|
|
626
1633
|
console.error(tcolor.magenta("Unknown error when checking module types in the dependencies tree."));
|
|
627
1634
|
ts.sys.exit(1);
|
|
628
1635
|
}
|
|
@@ -631,126 +1638,31 @@ const depsCheck = {
|
|
|
631
1638
|
ts.sys.exit(1);
|
|
632
1639
|
}
|
|
633
1640
|
return true;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
1641
|
+
}
|
|
1642
|
+
function ext(_dep) {
|
|
1643
|
+
const tsExt = new Set([".ts", ".mts", ".cts", ".tsx"]);
|
|
1644
|
+
for (const dep of _dep) {
|
|
1645
|
+
const ext = path.extname(dep.file);
|
|
1646
|
+
if (!tsExt.has(ext)) {
|
|
1647
|
+
console.error(tcolor.magenta(`${dep.file} has no valid TypeScript extension`));
|
|
1648
|
+
ts.sys.exit(1);
|
|
1649
|
+
}
|
|
639
1650
|
}
|
|
640
1651
|
return true;
|
|
641
|
-
}
|
|
642
|
-
async
|
|
1652
|
+
}
|
|
1653
|
+
async function init(_dep, options) {
|
|
643
1654
|
const res = resolves([
|
|
644
|
-
[
|
|
645
|
-
[
|
|
646
|
-
[
|
|
647
|
-
[depsCheck.types, deps, compilerOptions],
|
|
1655
|
+
[ext, _dep],
|
|
1656
|
+
[moduleType, _dep],
|
|
1657
|
+
[typesCheck, _dep, options],
|
|
648
1658
|
]);
|
|
649
1659
|
const results = await res.concurrent();
|
|
650
1660
|
return results.every((r) => r === true);
|
|
651
|
-
},
|
|
652
|
-
};
|
|
653
|
-
async function getDependencies(entry) {
|
|
654
|
-
const deps = await dependencies(entry);
|
|
655
|
-
const sorted = deps.sort();
|
|
656
|
-
const circularMessages = [];
|
|
657
|
-
const nodeModules = deps.node();
|
|
658
|
-
const depFiles = [];
|
|
659
|
-
await utils.wait(100);
|
|
660
|
-
for (const dep of sorted) {
|
|
661
|
-
const file = utils.resolvePath(dep);
|
|
662
|
-
const content = utils.readFile(file);
|
|
663
|
-
depFiles.push({ file, content });
|
|
664
|
-
}
|
|
665
|
-
const circular = deps
|
|
666
|
-
.mutual()
|
|
667
|
-
.map((i) => `${i[0]} -> ${i[1]} \n ${i[1]} -> ${i[0]} \n`);
|
|
668
|
-
const unknown = deps.warn().map((i) => `${i}\n`);
|
|
669
|
-
if (circular.length)
|
|
670
|
-
circularMessages.push(circular.join(""));
|
|
671
|
-
if (unknown.length)
|
|
672
|
-
circularMessages.push(unknown.join(""));
|
|
673
|
-
return {
|
|
674
|
-
depFiles,
|
|
675
|
-
sorted,
|
|
676
|
-
circularMessages,
|
|
677
|
-
nodeModules,
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
const getCompilerOptions = (exportPath, configPath) => {
|
|
681
|
-
const config = new TsConfig(configPath);
|
|
682
|
-
const generalOptions = () => config.getCompilerOptions();
|
|
683
|
-
const commonjs = () => {
|
|
684
|
-
const _config = new TsConfig(configPath);
|
|
685
|
-
_config.addCompilerOptions({ outDir: "dist" });
|
|
686
|
-
_config.removeCompilerOption("rootDir");
|
|
687
|
-
_config.removeCompilerOption("module");
|
|
688
|
-
const _options = _config.getCompilerOptions();
|
|
689
|
-
let out_dir = _options.outDir;
|
|
690
|
-
let isMain = true;
|
|
691
|
-
if (exportPath !== ".") {
|
|
692
|
-
out_dir = `${out_dir}/${exportPath.slice(2)}`;
|
|
693
|
-
isMain = false;
|
|
694
|
-
}
|
|
695
|
-
const { outDir, module, ...restOptions } = _options;
|
|
696
|
-
const compilerOptions = {
|
|
697
|
-
outDir: out_dir,
|
|
698
|
-
module: ts.ModuleKind.CommonJS,
|
|
699
|
-
...restOptions,
|
|
700
|
-
};
|
|
701
|
-
return {
|
|
702
|
-
isMain,
|
|
703
|
-
compilerOptions,
|
|
704
|
-
out_dir,
|
|
705
|
-
};
|
|
706
|
-
};
|
|
707
|
-
const esm = () => {
|
|
708
|
-
const __config = new TsConfig(configPath);
|
|
709
|
-
__config.addCompilerOptions({ outDir: "dist" });
|
|
710
|
-
__config.removeCompilerOption("rootDir");
|
|
711
|
-
const _options = __config.getCompilerOptions();
|
|
712
|
-
let out_dir = _options.outDir;
|
|
713
|
-
let isMain = true;
|
|
714
|
-
if (exportPath !== ".") {
|
|
715
|
-
out_dir = `${out_dir}/${exportPath.slice(2)}`;
|
|
716
|
-
isMain = false;
|
|
717
|
-
}
|
|
718
|
-
const { outDir, module, ...restOptions } = _options;
|
|
719
|
-
const compilerOptions = {
|
|
720
|
-
outDir: out_dir,
|
|
721
|
-
module: ts.ModuleKind.ES2022,
|
|
722
|
-
...restOptions,
|
|
723
|
-
};
|
|
724
|
-
return {
|
|
725
|
-
isMain,
|
|
726
|
-
compilerOptions,
|
|
727
|
-
out_dir,
|
|
728
|
-
};
|
|
729
|
-
};
|
|
730
|
-
return { commonjs, esm, generalOptions };
|
|
731
|
-
};
|
|
732
|
-
async function entry({ entryPath, exportPath, configPath, nodeEnv, }) {
|
|
733
|
-
const deps = await getDependencies(entryPath);
|
|
734
|
-
const depFiles = deps.depFiles;
|
|
735
|
-
const nodeModules = deps.nodeModules;
|
|
736
|
-
await utils.wait(1000);
|
|
737
|
-
const opts = getCompilerOptions(exportPath, configPath);
|
|
738
|
-
const generalOptions = opts.generalOptions();
|
|
739
|
-
const modOpts = {
|
|
740
|
-
commonjs: () => opts.commonjs(),
|
|
741
|
-
esm: () => opts.esm(),
|
|
742
|
-
};
|
|
743
|
-
await utils.wait(1000);
|
|
744
|
-
const checked = await depsCheck.make(depFiles, generalOptions, nodeModules, nodeEnv);
|
|
745
|
-
if (!checked) {
|
|
746
|
-
ts.sys.exit(1);
|
|
747
1661
|
}
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
};
|
|
753
|
-
}
|
|
1662
|
+
checks.init = init;
|
|
1663
|
+
})(checks || (checks = {}));
|
|
1664
|
+
//src/lib/init/config.ts
|
|
1665
|
+
// -------------
|
|
754
1666
|
const getConfigPath = () => {
|
|
755
1667
|
const fileNames = ["susee.config.ts", "susee.config.js", "susee.config.mjs"];
|
|
756
1668
|
let configFile;
|
|
@@ -763,24 +1675,25 @@ const getConfigPath = () => {
|
|
|
763
1675
|
}
|
|
764
1676
|
return configFile;
|
|
765
1677
|
};
|
|
1678
|
+
//---------
|
|
766
1679
|
function checkEntries(entries) {
|
|
767
1680
|
if (entries.length < 1) {
|
|
768
1681
|
console.error(tcolor.magenta(`No entry found in susee.config file, at least one entry required`));
|
|
769
1682
|
ts.sys.exit(1);
|
|
770
1683
|
}
|
|
771
1684
|
const objectStore = {};
|
|
772
|
-
const
|
|
1685
|
+
const duplicateExportPaths = [];
|
|
773
1686
|
for (const obj of entries) {
|
|
774
1687
|
const value = obj.exportPath;
|
|
775
1688
|
if (objectStore[value]) {
|
|
776
|
-
|
|
1689
|
+
duplicateExportPaths.push(`"${value}"`);
|
|
777
1690
|
}
|
|
778
1691
|
else {
|
|
779
1692
|
objectStore[value] = true;
|
|
780
1693
|
}
|
|
781
1694
|
}
|
|
782
|
-
if (
|
|
783
|
-
console.error(tcolor.magenta(`Duplicate export paths/path (${
|
|
1695
|
+
if (duplicateExportPaths.length > 0) {
|
|
1696
|
+
console.error(tcolor.magenta(`Duplicate export paths/path (${duplicateExportPaths.join(",")}) found in your susee.config file , that will error for bundled output`));
|
|
784
1697
|
ts.sys.exit(1);
|
|
785
1698
|
}
|
|
786
1699
|
for (const obj of entries) {
|
|
@@ -790,6 +1703,11 @@ function checkEntries(entries) {
|
|
|
790
1703
|
}
|
|
791
1704
|
}
|
|
792
1705
|
}
|
|
1706
|
+
/**
|
|
1707
|
+
* Get SuSee configuration from susee.config file (susee.config.ts, susee.config.js, susee.config.mjs)
|
|
1708
|
+
* @returns {Promise<ConfigReturns>} - SuSee configuration
|
|
1709
|
+
* @throws {Error} - when no susee.config file found
|
|
1710
|
+
*/
|
|
793
1711
|
async function getConfig() {
|
|
794
1712
|
const configPath = getConfigPath();
|
|
795
1713
|
if (configPath === undefined) {
|
|
@@ -800,151 +1718,236 @@ async function getConfig() {
|
|
|
800
1718
|
const config = _default.default;
|
|
801
1719
|
const entryCheck = resolves([[checkEntries, config.entryPoints]]);
|
|
802
1720
|
await entryCheck.series();
|
|
803
|
-
await
|
|
1721
|
+
await utilities.wait(1000);
|
|
1722
|
+
const points = [];
|
|
1723
|
+
for (const ent of config.entryPoints) {
|
|
1724
|
+
const point = {
|
|
1725
|
+
entry: ent.entry,
|
|
1726
|
+
exportPath: ent.exportPath,
|
|
1727
|
+
format: ent.format ?? "esm",
|
|
1728
|
+
tsconfigFilePath: ent.tsconfigFilePath ?? undefined,
|
|
1729
|
+
renameDuplicates: ent.renameDuplicates ?? true,
|
|
1730
|
+
// TODO check for defined out dir here or in config.ts
|
|
1731
|
+
outDir: config.outDir ?? "dist",
|
|
1732
|
+
};
|
|
1733
|
+
points.push(point);
|
|
1734
|
+
}
|
|
804
1735
|
return {
|
|
805
|
-
|
|
806
|
-
|
|
1736
|
+
points,
|
|
1737
|
+
plugins: config.plugins ?? [],
|
|
807
1738
|
allowUpdatePackageJson: config.allowUpdatePackageJson ?? true,
|
|
808
|
-
nodeEnv: config.nodeEnv ?? true,
|
|
809
|
-
renameDuplicates: config.renameDuplicates ?? true,
|
|
810
1739
|
};
|
|
811
1740
|
}
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
function
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
default: `./${path.relative(process.cwd(), files.esm)}`,
|
|
820
|
-
types: `./${path.relative(process.cwd(), files.esmTypes)}`,
|
|
821
|
-
},
|
|
822
|
-
require: {
|
|
823
|
-
default: `./${path.relative(process.cwd(), files.commonjs)}`,
|
|
824
|
-
types: `./${path.relative(process.cwd(), files.commonjsTypes)}`,
|
|
825
|
-
},
|
|
826
|
-
},
|
|
827
|
-
}
|
|
828
|
-
: isCjs(files) && !isEsm(files)
|
|
829
|
-
? {
|
|
830
|
-
[exportPath]: {
|
|
831
|
-
require: {
|
|
832
|
-
default: `./${path.relative(process.cwd(), files.commonjs)}`,
|
|
833
|
-
types: `./${path.relative(process.cwd(), files.commonjsTypes)}`,
|
|
834
|
-
},
|
|
835
|
-
},
|
|
836
|
-
}
|
|
837
|
-
: !isCjs(files) && isEsm(files)
|
|
838
|
-
? {
|
|
839
|
-
[exportPath]: {
|
|
840
|
-
import: {
|
|
841
|
-
default: `./${path.relative(process.cwd(), files.esm)}`,
|
|
842
|
-
types: `./${path.relative(process.cwd(), files.esmTypes)}`,
|
|
843
|
-
},
|
|
844
|
-
},
|
|
845
|
-
}
|
|
846
|
-
: {};
|
|
1741
|
+
//src/lib/init/deps.ts
|
|
1742
|
+
//---------------
|
|
1743
|
+
async function fileSizes(path) {
|
|
1744
|
+
const s = await fs.promises.stat(path);
|
|
1745
|
+
const logical = s.size; // bytes in file
|
|
1746
|
+
const allocated = s.blocks !== null ? s.blocks * 512 : null; // bytes actually allocated (POSIX)
|
|
1747
|
+
return { logical, allocated };
|
|
847
1748
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
const _pkgtext = utils.readFile(pkgFile);
|
|
855
|
-
const pkgtext = JSON.parse(_pkgtext);
|
|
856
|
-
let { name, version, description, main, module, type, types, exports, ...rest } = pkgtext;
|
|
857
|
-
await utils.wait(500);
|
|
858
|
-
type = isEsm(files) ? "module" : "commonjs";
|
|
859
|
-
let _main = {};
|
|
860
|
-
let _module = {};
|
|
861
|
-
let _types = {};
|
|
862
|
-
let _exports = {};
|
|
863
|
-
if (isMain) {
|
|
864
|
-
_main = files.main
|
|
865
|
-
? { main: path.relative(process.cwd(), files.main) }
|
|
866
|
-
: {};
|
|
867
|
-
_module = files.module
|
|
868
|
-
? { module: path.relative(process.cwd(), files.module) }
|
|
869
|
-
: {};
|
|
870
|
-
_types = files.types
|
|
871
|
-
? { types: path.relative(process.cwd(), files.types) }
|
|
872
|
-
: {};
|
|
873
|
-
_exports = { exports: { ...getExports(files, exportPath) } };
|
|
1749
|
+
const checkExport = (str, file) => {
|
|
1750
|
+
const esmRex = /export default .*/gm;
|
|
1751
|
+
const cjsRex = /export = .*/gm;
|
|
1752
|
+
const ctsRex = /.cts/g;
|
|
1753
|
+
if (str.match(esmRex) || (str.match(cjsRex) && file.match(ctsRex))) {
|
|
1754
|
+
return true;
|
|
874
1755
|
}
|
|
875
1756
|
else {
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
1757
|
+
return false;
|
|
1758
|
+
}
|
|
1759
|
+
};
|
|
1760
|
+
/**
|
|
1761
|
+
* Generate dependencies graph for given entry file.
|
|
1762
|
+
*
|
|
1763
|
+
* This function will return an array of dependencies file objects.
|
|
1764
|
+
* Each object will contain the following properties:
|
|
1765
|
+
* - file: path to the file
|
|
1766
|
+
* - content: content of the file
|
|
1767
|
+
* - length: length of the content in bytes
|
|
1768
|
+
* - includeDefExport: whether the file includes export default or export = statement
|
|
1769
|
+
* - size: an object containing the following properties:
|
|
1770
|
+
* - logical: size of the file in bytes
|
|
1771
|
+
* - allocated: size of the file in bytes on disk
|
|
1772
|
+
* - utf8: size of the file in bytes when encoded in utf8
|
|
1773
|
+
* - buffBytes: size of the file in bytes when encoded in buffer
|
|
1774
|
+
*
|
|
1775
|
+
* @param {string} entryFile - path to the entry file
|
|
1776
|
+
* @param {SuseePlugins} plugins - array of plugins
|
|
1777
|
+
* @returns {Promise<DepsFiles>}
|
|
1778
|
+
*/
|
|
1779
|
+
async function generateDependencies(entryFile, plugins) {
|
|
1780
|
+
const deps = await dependencies(entryFile);
|
|
1781
|
+
const sorted = deps.sort(); // get dependencies graph
|
|
1782
|
+
let depsFiles = [];
|
|
1783
|
+
await utilities.wait(1000);
|
|
1784
|
+
for (const dep of sorted) {
|
|
1785
|
+
const file = ts.sys.resolvePath(dep);
|
|
1786
|
+
const content = await fs.promises.readFile(file, "utf8");
|
|
1787
|
+
const s = await fileSizes(file);
|
|
1788
|
+
const length = content.length;
|
|
1789
|
+
const includeDefExport = checkExport(content, file);
|
|
1790
|
+
const _files = {
|
|
1791
|
+
file,
|
|
1792
|
+
content,
|
|
1793
|
+
length,
|
|
1794
|
+
includeDefExport,
|
|
1795
|
+
size: {
|
|
1796
|
+
logical: s.logical,
|
|
1797
|
+
allocated: s.allocated,
|
|
1798
|
+
utf8: new TextEncoder().encode(content).length,
|
|
1799
|
+
buffBytes: Buffer.byteLength(content, "utf8"),
|
|
1800
|
+
},
|
|
884
1801
|
};
|
|
1802
|
+
depsFiles.push(_files);
|
|
885
1803
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
1804
|
+
// call dependency plugins
|
|
1805
|
+
if (plugins.length) {
|
|
1806
|
+
for (const plugin of plugins) {
|
|
1807
|
+
const _plug = typeof plugin === "function" ? plugin() : plugin;
|
|
1808
|
+
if (_plug.type === "dependency") {
|
|
1809
|
+
if (_plug.async) {
|
|
1810
|
+
depsFiles = await _plug.func(depsFiles);
|
|
1811
|
+
}
|
|
1812
|
+
else {
|
|
1813
|
+
depsFiles = _plug.func(depsFiles);
|
|
1814
|
+
}
|
|
1815
|
+
await utilities.wait(1000);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
return depsFiles;
|
|
899
1820
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
1821
|
+
//src/lib/init/tsCompilerOptions.ts
|
|
1822
|
+
class GetOptions {
|
|
1823
|
+
constructor(point) {
|
|
1824
|
+
this._point = point;
|
|
1825
|
+
this._options = {};
|
|
1826
|
+
}
|
|
1827
|
+
__init() {
|
|
1828
|
+
const __opts = new TsConfig(this._point.tsconfigFilePath);
|
|
1829
|
+
const __outDir = this._point.exportPath === "."
|
|
1830
|
+
? this._point.outDir
|
|
1831
|
+
: `${this._point.outDir}/${this._point.exportPath.slice(2)}`;
|
|
1832
|
+
__opts.removeCompilerOption("rootDir");
|
|
1833
|
+
__opts.removeCompilerOption("module");
|
|
1834
|
+
__opts.editCompilerOptions({
|
|
1835
|
+
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
1836
|
+
outDir: __outDir,
|
|
916
1837
|
});
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
1838
|
+
this._options = __opts.getCompilerOptions();
|
|
1839
|
+
}
|
|
1840
|
+
__init2() {
|
|
1841
|
+
this.__init();
|
|
1842
|
+
let { types, lib, ...restOptions } = this._options;
|
|
1843
|
+
// normalize types into an array
|
|
1844
|
+
if (types) {
|
|
1845
|
+
if (!types.includes("node")) {
|
|
1846
|
+
types = ["node", ...types];
|
|
1847
|
+
}
|
|
923
1848
|
}
|
|
924
|
-
else
|
|
925
|
-
|
|
1849
|
+
else {
|
|
1850
|
+
types = ["node"];
|
|
926
1851
|
}
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
await utils.wait(1000);
|
|
930
|
-
await compiler.commonjs(sourceCode, e.entry, cjsOpts.compilerOptions, cjsOpts.isMain, config.postProcessHooks, config.allowUpdatePackageJson);
|
|
1852
|
+
if (lib) {
|
|
1853
|
+
lib = [...new Set(["ESNext", ...lib])];
|
|
931
1854
|
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
await writePackage(compiler.files, e.exportPath);
|
|
1855
|
+
else {
|
|
1856
|
+
lib = ["ESNext"];
|
|
935
1857
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1858
|
+
return { types, lib, ...restOptions };
|
|
1859
|
+
}
|
|
1860
|
+
get commonjs() {
|
|
1861
|
+
const opts = this.__init2();
|
|
1862
|
+
const { module, ...rest } = opts;
|
|
1863
|
+
return { module: ts.ModuleKind.CommonJS, ...rest };
|
|
1864
|
+
}
|
|
1865
|
+
get esm() {
|
|
1866
|
+
const opts = this.__init2();
|
|
1867
|
+
const { module, ...rest } = opts;
|
|
1868
|
+
return { module: ts.ModuleKind.ES2020, ...rest };
|
|
1869
|
+
}
|
|
1870
|
+
get default() {
|
|
1871
|
+
return this.__init2();
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
/**
|
|
1875
|
+
* Returns an instance of GetOptions, which provides various methods
|
|
1876
|
+
* to generate different sets of compiler options based on the
|
|
1877
|
+
* given Point.
|
|
1878
|
+
*
|
|
1879
|
+
* @param {Point} point - The point to generate compiler options for.
|
|
1880
|
+
* @returns {GetOptions}
|
|
1881
|
+
*/
|
|
1882
|
+
function getOptions(point) {
|
|
1883
|
+
return new GetOptions(point);
|
|
1884
|
+
}
|
|
1885
|
+
//src/lib/init/index.ts
|
|
1886
|
+
/**
|
|
1887
|
+
* This function takes a susee configuration object and returns a promise that resolves with a `CollatedReturn` object.
|
|
1888
|
+
* The function iterates over the `points` array in the susee configuration object.
|
|
1889
|
+
* For each point, it generates the dependencies using the `generateDependencies` function.
|
|
1890
|
+
* It then checks if the dependencies are valid using the `checks.init` function.
|
|
1891
|
+
* If the dependencies are invalid, it exits the process with code 1.
|
|
1892
|
+
* If the dependencies are valid, it constructs a `CollatedPoint` object and adds it to the result array.
|
|
1893
|
+
* Finally, it returns a `CollatedReturn` object with the result array and the `allowUpdatePackageJson` flag.
|
|
1894
|
+
*/
|
|
1895
|
+
async function collections() {
|
|
1896
|
+
const __config = await getConfig();
|
|
1897
|
+
const points = __config.points;
|
|
1898
|
+
const result = [];
|
|
1899
|
+
for (const point of points) {
|
|
1900
|
+
const __opts = getOptions(point);
|
|
1901
|
+
const __deps = await generateDependencies(point.entry, __config.plugins);
|
|
1902
|
+
const checked = await checks.init(__deps, __opts.esm);
|
|
1903
|
+
if (!checked) {
|
|
1904
|
+
ts.sys.exit(1);
|
|
945
1905
|
}
|
|
1906
|
+
const c = {
|
|
1907
|
+
fileName: point.entry,
|
|
1908
|
+
exportPath: point.exportPath,
|
|
1909
|
+
format: point.format,
|
|
1910
|
+
rename: point.renameDuplicates,
|
|
1911
|
+
outDir: point.outDir,
|
|
1912
|
+
tsOptions: {
|
|
1913
|
+
cjs: __opts.commonjs,
|
|
1914
|
+
esm: __opts.esm,
|
|
1915
|
+
default: __opts.default,
|
|
1916
|
+
},
|
|
1917
|
+
depFiles: __deps,
|
|
1918
|
+
plugins: __config.plugins,
|
|
1919
|
+
};
|
|
1920
|
+
result.push(c);
|
|
946
1921
|
}
|
|
947
|
-
|
|
1922
|
+
return {
|
|
1923
|
+
points: result,
|
|
1924
|
+
allowUpdatePackageJson: __config.allowUpdatePackageJson,
|
|
1925
|
+
};
|
|
1926
|
+
}
|
|
1927
|
+
//src/index.ts
|
|
1928
|
+
/**
|
|
1929
|
+
* Bundles a TypeScript project into a single file.
|
|
1930
|
+
* The function takes a {@link SuSeeConfig} object as input and returns a promise resolves with a bundled result.
|
|
1931
|
+
* The function applies the following steps:
|
|
1932
|
+
* 1. Call dependency plugins.
|
|
1933
|
+
* 2. Handle duplicates.
|
|
1934
|
+
* 3. Handling anonymous imports and exports.
|
|
1935
|
+
* 4. Remove Imports.
|
|
1936
|
+
* 5. Remove Exports from dependencies only.
|
|
1937
|
+
* 6. Handle imported statements.
|
|
1938
|
+
* 7. Create final content.
|
|
1939
|
+
* 8. Call pre-process plugins.
|
|
1940
|
+
* 9. Returns.
|
|
1941
|
+
*/
|
|
1942
|
+
async function susee() {
|
|
1943
|
+
console.info(`${tcolor.green("Start")} : ${tcolor.cyan("bundling")}`);
|
|
1944
|
+
const collected = await collections();
|
|
1945
|
+
await utilities.wait(1000);
|
|
1946
|
+
const bundled = await bundle(collected);
|
|
1947
|
+
await utilities.wait(1000);
|
|
1948
|
+
const compiler = new Compiler(bundled);
|
|
1949
|
+
await compiler.compile();
|
|
1950
|
+
console.info(`${tcolor.green("End")} : ${tcolor.cyan("bundling")}`);
|
|
948
1951
|
}
|
|
949
1952
|
export { susee };
|
|
950
1953
|
//# sourceMappingURL=index.js.map
|