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/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 utils from "@suseejs/utils";
19
- function removeExportExpressionHandler(compilerOptions) {
20
- return ({ file, content }) => {
21
- const sourceFile = ts.createSourceFile(file, content, ts.ScriptTarget.Latest, true);
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 { factory } = context;
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
- return { file, content: _content };
35
+ const { content, ...rest } = depsTree;
36
+ return { content: _content, ...rest };
70
37
  };
71
- }
72
- function removeImportExpressionHandler(removedStatements, compilerOptions) {
73
- return ({ file, content }) => {
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
- async function bundler({ depsFiles, compilerOptions, renameDuplicates, }) {
196
- const reName = renameDuplicates ?? true;
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
- if (reName) {
205
- depsFiles = await duplicateHandlers.renamed(depsFiles, namesMap, callNameMap, importNameMap, exportNameMap, compilerOptions);
206
- }
207
- else {
208
- depsFiles = await duplicateHandlers.notRenamed(depsFiles, namesMap, compilerOptions);
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 utils.wait(1000);
211
- depsFiles = await anonymous(depsFiles, exportDefaultExportNameMap, exportDefaultImportNameMap, compilerOptions);
212
- await utils.wait(1000);
1131
+ await utilities.wait(1000);
1132
+ // 4. Remove Imports
213
1133
  const removeImports = resolves([
214
- [removeImportExpressionHandler, removedStatements, compilerOptions],
1134
+ [bundleCreator, removeImportsVisitor, compilerOptions, removedStatements],
215
1135
  ]);
216
1136
  const removeImport = await removeImports.concurrent();
217
1137
  depsFiles = depsFiles.map(removeImport[0]);
218
- await utils.wait(1000);
1138
+ await utilities.wait(500);
1139
+ // 5. Remove Exports from dependencies only
219
1140
  const removeExports = resolves([
220
- [removeExportExpressionHandler, compilerOptions],
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 = mergeImports(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 utils.wait(1000);
244
- const content = `${importStatements}\n${depFilesContent}\n${mainFileContent}`;
245
- return content;
246
- }
247
- function checkExports(file, str) {
248
- const sourceFile = ts.createSourceFile(file, str, ts.ScriptTarget.Latest, true);
249
- let nameExport = false;
250
- let defExport = false;
251
- const transformer = (context) => {
252
- const visitor = (node) => {
253
- if (ts.isExportAssignment(node) &&
254
- !node.isExportEquals &&
255
- node.modifiers === undefined &&
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
- else if (ts.isNamedExports(node)) {
284
- nameExport = true;
285
- }
286
- else if (ts.isVariableStatement(node) ||
287
- ts.isFunctionDeclaration(node) ||
288
- ts.isInterfaceDeclaration(node) ||
289
- ts.isTypeAliasDeclaration(node)) {
290
- const isInsideNamespace = (n) => {
291
- let current = n.parent;
292
- while (current) {
293
- if (ts.isModuleDeclaration(current) &&
294
- current.flags === ts.NodeFlags.Namespace) {
295
- return true;
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
- const createHost = (sourceCode, fileName) => {
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
- function replaceInTs(fileName, sourceCode, compilerOptions) {
368
- const sourceFile = ts.createSourceFile(fileName, sourceCode, ts.ScriptTarget.Latest, true);
369
- const transformer = (context) => {
370
- const { factory } = context;
371
- const visitor = (node) => {
372
- if (ts.isExportAssignment(node) &&
373
- node.modifiers === undefined &&
374
- !node.isExportEquals) {
375
- return factory.createExportAssignment(node.modifiers, true, node.expression);
376
- }
377
- return ts.visitEachChild(node, visitor, context);
378
- };
379
- return (rootNode) => ts.visitNode(rootNode, visitor);
380
- };
381
- return transformFunction(transformer, sourceFile, compilerOptions);
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
- async function clearFolder(folderPath) {
384
- folderPath = path.resolve(process.cwd(), folderPath);
385
- try {
386
- const entries = await fs.promises.readdir(folderPath, {
387
- withFileTypes: true,
388
- });
389
- await Promise.all(entries.map((entry) => fs.promises.rm(path.join(folderPath, entry.name), {
390
- recursive: true,
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
- catch (error) {
394
- if (error.code !== "ENOENT") {
395
- throw error;
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
- async function writeCompileFile(file, content) {
400
- const filePath = ts.sys.resolvePath(file);
401
- const dir = path.dirname(filePath);
402
- if (!ts.sys.directoryExists(dir)) {
403
- await fs.promises.mkdir(dir, { recursive: true });
404
- }
405
- await utils.wait(500);
406
- await fs.promises.writeFile(filePath, content);
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 Compilers {
409
- constructor(options) {
410
- this._target = options?.target ?? "both";
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
- async commonjs(sourceCode, fileName, compilerOptions, isMain, hooks, isUpdate = true) {
424
- console.time(tcolor.green("Compiled Commonjs"));
425
- const ck = checkExports(fileName, sourceCode);
426
- if (ck.defExport && ck.nameExport) {
427
- console.warn(tcolor.yellow("Both name export and default export are exported from your project,that will effect on default export for commonjs output"));
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
- if (ck.defExport && !ck.nameExport) {
436
- const ext = utils.extname(outName);
437
- if (ext === ".js") {
438
- content = replaceInJs(fileName, content, compilerOptions);
439
- }
440
- if (ext === ".ts") {
441
- content = replaceInTs(fileName, content, compilerOptions);
442
- }
443
- }
444
- if (hooks?.length) {
445
- for (const hook of hooks) {
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 (isUpdate) {
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 utils.wait(500);
473
- if (this._target !== "both" && this._target !== "esm") {
474
- await clearFolder(utils.dirname(outName));
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.green("Compiled Commonjs"));
1422
+ console.timeEnd(tcolor.cyan(`Compiled commonjs for ${_name} export path`));
479
1423
  }
480
- async esm(sourceCode, fileName, compilerOptions, isMain, hooks, isUpdate = true) {
481
- console.time(tcolor.green("Compiled ESM"));
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 (hooks?.length) {
489
- for (const hook of hooks) {
490
- if (hook.async) {
491
- content = await hook.func(content, outName);
492
- }
493
- else {
494
- content = hook.func(content, outName);
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
- if (isUpdate) {
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 && this._target === "both" && this.files.esm) {
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 utils.wait(500);
513
- if (this._target !== "commonjs") {
514
- await clearFolder(utils.dirname(outName));
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.green("Compiled ESM"));
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
- const depsCheck = {
522
- types(deps, compilerOptions) {
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 = deps.map((i) => i.file);
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
- ext(deps) {
557
- const tsExt = new Set([".ts", ".mts", ".cts", ".tsx"]);
558
- for (const dep of deps) {
559
- const ext = utils.extname(dep.file);
560
- if (!tsExt.has(ext)) {
561
- console.error(tcolor.magenta(`${dep.file} has no valid TypeScript extension`));
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 unknowCount = 0;
571
- for (const dep of deps) {
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
- unknowCount++;
1629
+ unknownCount++;
623
1630
  }
624
1631
  }
625
- if (unknowCount) {
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
- nodeCheck(nodeEnvOption, nodeModules) {
636
- if (!nodeEnvOption && nodeModules.length > 0) {
637
- console.error();
638
- ts.sys.exit(1);
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 make(deps, compilerOptions, nodeModules, nodeEnv = true) {
1652
+ }
1653
+ async function init(_dep, options) {
643
1654
  const res = resolves([
644
- [depsCheck.ext, deps],
645
- [depsCheck.nodeCheck, nodeEnv, nodeModules],
646
- [depsCheck.moduleType, deps],
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
- return {
749
- depFiles,
750
- modOpts,
751
- generalOptions,
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 duplicates = [];
1685
+ const duplicateExportPaths = [];
773
1686
  for (const obj of entries) {
774
1687
  const value = obj.exportPath;
775
1688
  if (objectStore[value]) {
776
- duplicates.push(`"${value}"`);
1689
+ duplicateExportPaths.push(`"${value}"`);
777
1690
  }
778
1691
  else {
779
1692
  objectStore[value] = true;
780
1693
  }
781
1694
  }
782
- if (duplicates.length > 0) {
783
- console.error(tcolor.magenta(`Duplicate export paths/path (${duplicates.join(",")}) found in your susee.config file , that will error for bundled output`));
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 utils.wait(1000);
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
- entryPoints: config.entryPoints,
806
- postProcessHooks: config.postProcessHooks ?? [],
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
- const isCjs = (files) => files.commonjs && files.commonjsTypes;
813
- const isEsm = (files) => files.esm && files.esmTypes;
814
- function getExports(files, exportPath) {
815
- return isCjs(files) && isEsm(files)
816
- ? {
817
- [exportPath]: {
818
- import: {
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
- async function writePackage(files, exportPath) {
849
- let isMain = true;
850
- if (exportPath !== ".") {
851
- isMain = false;
852
- }
853
- const pkgFile = utils.resolvePath("package.json");
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
- _main = main ? { main: main } : {};
877
- _module = module ? { module: module } : {};
878
- _types = types ? { types: types } : {};
879
- const normalizedExports = exports && typeof exports === "object" && !Array.isArray(exports)
880
- ? { ...exports }
881
- : {};
882
- _exports = {
883
- exports: { ...normalizedExports, ...getExports(files, exportPath) },
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
- await utils.wait(1000);
887
- const pkgJson = {
888
- name,
889
- version,
890
- description,
891
- type,
892
- ..._main,
893
- ..._types,
894
- ..._module,
895
- ..._exports,
896
- ...rest,
897
- };
898
- utils.writeFile(pkgFile, JSON.stringify(pkgJson, null, 2));
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
- async function susee() {
901
- const config = await getConfig();
902
- console.info(tcolor.cyan("Start Bundle"));
903
- const compile = async (e) => {
904
- const target = e.moduleType ? e.moduleType : "esm";
905
- const configPath = e.tsconfigFilePath;
906
- const ent = await entry({
907
- entryPath: e.entry,
908
- exportPath: e.exportPath,
909
- configPath: e.tsconfigFilePath,
910
- nodeEnv: config.nodeEnv,
911
- });
912
- const sourceCode = await bundler({
913
- depsFiles: ent.depFiles,
914
- compilerOptions: ent.generalOptions,
915
- renameDuplicates: config.renameDuplicates,
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
- const mdOpts = ent.modOpts;
918
- const cjsOpts = mdOpts.commonjs();
919
- const esmOpts = mdOpts.esm();
920
- const compiler = new Compilers({ target, configPath });
921
- if (target === "commonjs") {
922
- await compiler.commonjs(sourceCode, e.entry, cjsOpts.compilerOptions, cjsOpts.isMain, config.postProcessHooks, config.allowUpdatePackageJson);
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 if (target === "esm") {
925
- await compiler.esm(sourceCode, e.entry, esmOpts.compilerOptions, esmOpts.isMain, config.postProcessHooks, config.allowUpdatePackageJson);
1849
+ else {
1850
+ types = ["node"];
926
1851
  }
927
- else if (target === "both") {
928
- await compiler.esm(sourceCode, e.entry, esmOpts.compilerOptions, esmOpts.isMain, config.postProcessHooks, config.allowUpdatePackageJson);
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
- await utils.wait(1000);
933
- if (config.allowUpdatePackageJson) {
934
- await writePackage(compiler.files, e.exportPath);
1855
+ else {
1856
+ lib = ["ESNext"];
935
1857
  }
936
- };
937
- for (const entry of config.entryPoints) {
938
- const entName = entry.exportPath === "." ? "main" : entry.exportPath.slice(2);
939
- await utils.wait(1000);
940
- console.info(tcolor.cyan(`Start ${tcolor.green("->")} "${entName}" export path`));
941
- await compile(entry);
942
- console.info(tcolor.cyan(`End ${tcolor.green("->")} "${entName}" export path`));
943
- if (config.entryPoints.indexOf(entry) + 1 < config.entryPoints.length) {
944
- console.info("-----------------------------------");
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
- console.info(tcolor.cyan("Finished Bundle"));
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