susee 1.6.2 → 2.0.1

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.cjs DELETED
@@ -1,3476 +0,0 @@
1
- /*! *****************************************************************************
2
- Copyright (c) Pho Thin Mg <phothinmg@disroot.org>
3
-
4
- Licensed under the Apache License, Version 2.0 (the "License"); you may not use
5
- this file except in compliance with the License. You may obtain a copy of the
6
- License at http://www.apache.org/licenses/LICENSE-2.0
7
- ***************************************************************************** */
8
-
9
- "use strict";
10
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- var desc = Object.getOwnPropertyDescriptor(m, k);
13
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
14
- desc = { enumerable: true, get: function() { return m[k]; } };
15
- }
16
- Object.defineProperty(o, k2, desc);
17
- }) : (function(o, m, k, k2) {
18
- if (k2 === undefined) k2 = k;
19
- o[k2] = m[k];
20
- }));
21
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
22
- Object.defineProperty(o, "default", { enumerable: true, value: v });
23
- }) : function(o, v) {
24
- o["default"] = v;
25
- });
26
- var __importStar = (this && this.__importStar) || (function () {
27
- var ownKeys = function(o) {
28
- ownKeys = Object.getOwnPropertyNames || function (o) {
29
- var ar = [];
30
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
31
- return ar;
32
- };
33
- return ownKeys(o);
34
- };
35
- return function (mod) {
36
- if (mod && mod.__esModule) return mod;
37
- var result = {};
38
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
39
- __setModuleDefault(result, mod);
40
- return result;
41
- };
42
- })();
43
- var __importDefault = (this && this.__importDefault) || function (mod) {
44
- return (mod && mod.__esModule) ? mod : { "default": mod };
45
- };
46
- Object.defineProperty(exports, "__esModule", { value: true });
47
- exports.build = build;
48
- exports.suseeBundler = bundle;
49
- exports.suseeCliBuild = suseeCliBuild;
50
- const node_fs_1 = __importDefault(require("node:fs"));
51
- const node_module_1 = __importDefault(require("node:module"));
52
- const node_path_1 = __importDefault(require("node:path"));
53
- const node_process_1 = __importDefault(require("node:process"));
54
- const promises_1 = __importDefault(require("node:readline/promises"));
55
- const color_1 = __importDefault(require("@suseejs/color"));
56
- const ts6_1 = __importDefault(require("@suseejs/ts6"));
57
- //src/helpers/files.ts
58
- var files;
59
- (function (files_1) {
60
- const root = node_process_1.default.cwd();
61
- function resolvePath(pathStr) {
62
- return node_path_1.default.resolve(root, pathStr);
63
- }
64
- files_1.resolvePath = resolvePath;
65
- function relativePath(pathStr) {
66
- return node_path_1.default.relative(root, pathStr);
67
- }
68
- files_1.relativePath = relativePath;
69
- function joinPath(...paths) {
70
- return node_path_1.default.join(...paths);
71
- }
72
- files_1.joinPath = joinPath;
73
- function existsPath(pathStr) {
74
- return node_fs_1.default.existsSync(resolvePath(pathStr));
75
- }
76
- files_1.existsPath = existsPath;
77
- async function deleteFile(filePath) {
78
- if (existsPath(filePath)) {
79
- await node_fs_1.default.promises.unlink(filePath);
80
- }
81
- }
82
- files_1.deleteFile = deleteFile;
83
- async function readFile(filePath) {
84
- if (!existsPath(filePath)) {
85
- console.error(color_1.default.magenta(`> ${filePath} does not exists `));
86
- node_process_1.default.exit(1);
87
- }
88
- filePath = resolvePath(filePath);
89
- const readContent = await node_fs_1.default.promises.readFile(filePath);
90
- return {
91
- str: readContent.toString("utf8"),
92
- bytes: readContent.byteLength,
93
- };
94
- }
95
- files_1.readFile = readFile;
96
- async function readJsonFile(filePath) {
97
- const read = await readFile(filePath);
98
- return JSON.parse(read.str);
99
- }
100
- files_1.readJsonFile = readJsonFile;
101
- async function createDirectory(dirPath) {
102
- dirPath = resolvePath(dirPath);
103
- if (!existsPath(dirPath)) {
104
- await node_fs_1.default.promises.mkdir(dirPath, { recursive: true });
105
- }
106
- }
107
- files_1.createDirectory = createDirectory;
108
- function parentPath(filePath) {
109
- return node_path_1.default.dirname(resolvePath(filePath));
110
- }
111
- files_1.parentPath = parentPath;
112
- async function writeFile(filePath, content) {
113
- if (existsPath(filePath))
114
- await deleteFile(filePath);
115
- await createDirectory(parentPath(filePath));
116
- filePath = resolvePath(filePath);
117
- await node_fs_1.default.promises.writeFile(filePath, content);
118
- }
119
- files_1.writeFile = writeFile;
120
- async function clearFolder(folderPath) {
121
- folderPath = resolvePath(folderPath);
122
- try {
123
- const entries = await node_fs_1.default.promises.readdir(folderPath, {
124
- withFileTypes: true,
125
- });
126
- await Promise.all(entries.map((entry) => node_fs_1.default.promises.rm(node_path_1.default.join(folderPath, entry.name), {
127
- recursive: true,
128
- })));
129
- }
130
- catch (error) {
131
- // biome-ignore lint/suspicious/noExplicitAny: error code
132
- if (error.code !== "ENOENT") {
133
- throw error;
134
- }
135
- }
136
- }
137
- files_1.clearFolder = clearFolder;
138
- // -------------------------------------------------------------------------------------------//
139
- const isCjs = (files) => files.commonjs && files.commonjsTypes;
140
- const isEsm = (files) => files.esm && files.esmTypes;
141
- function getExports(files, exportPath) {
142
- return isCjs(files) && isEsm(files)
143
- ? {
144
- [exportPath]: {
145
- import: {
146
- types: `./${node_path_1.default.relative(node_process_1.default.cwd(), files.esmTypes)}`,
147
- default: `./${node_path_1.default.relative(node_process_1.default.cwd(), files.esm)}`,
148
- },
149
- require: {
150
- types: `./${node_path_1.default.relative(node_process_1.default.cwd(), files.commonjsTypes)}`,
151
- default: `./${node_path_1.default.relative(node_process_1.default.cwd(), files.commonjs)}`,
152
- },
153
- },
154
- }
155
- : isCjs(files) && !isEsm(files)
156
- ? {
157
- [exportPath]: {
158
- require: {
159
- types: `./${node_path_1.default.relative(node_process_1.default.cwd(), files.commonjsTypes)}`,
160
- default: `./${node_path_1.default.relative(node_process_1.default.cwd(), files.commonjs)}`,
161
- },
162
- },
163
- }
164
- : !isCjs(files) && isEsm(files)
165
- ? {
166
- [exportPath]: {
167
- import: {
168
- types: `./${node_path_1.default.relative(node_process_1.default.cwd(), files.esmTypes)}`,
169
- default: `./${node_path_1.default.relative(node_process_1.default.cwd(), files.esm)}`,
170
- },
171
- },
172
- }
173
- : {};
174
- }
175
- async function writePackageJson(files, exportPath) {
176
- let isMain = true;
177
- if (exportPath !== ".") {
178
- isMain = false;
179
- }
180
- const pkgFile = resolvePath("package.json");
181
- const pkgtext = await readJsonFile(pkgFile);
182
- let { name, version, description, main, module, type, types, exports, ...rest } = pkgtext;
183
- type = "module";
184
- let _main = {};
185
- let _module = {};
186
- let _types = {};
187
- let _exports = {};
188
- if (isMain) {
189
- _main = files.main
190
- ? { main: node_path_1.default.relative(node_process_1.default.cwd(), files.main) }
191
- : {};
192
- _module = files.module
193
- ? { module: node_path_1.default.relative(node_process_1.default.cwd(), files.module) }
194
- : {};
195
- _types = files.types
196
- ? { types: node_path_1.default.relative(node_process_1.default.cwd(), files.types) }
197
- : {};
198
- _exports = { exports: { ...getExports(files, exportPath) } };
199
- }
200
- else {
201
- _main = main ? { main: main } : {};
202
- _module = module ? { module: module } : {};
203
- _types = types ? { types: types } : {};
204
- const normalizedExports = exports && typeof exports === "object" && !Array.isArray(exports)
205
- ? { ...exports }
206
- : {};
207
- _exports = {
208
- exports: { ...normalizedExports, ...getExports(files, exportPath) },
209
- };
210
- }
211
- const pkgJson = {
212
- name,
213
- version,
214
- description,
215
- type,
216
- ..._main,
217
- ..._types,
218
- ..._module,
219
- ..._exports,
220
- ...rest,
221
- };
222
- await writeFile(pkgFile, JSON.stringify(pkgJson, null, 2));
223
- }
224
- files_1.writePackageJson = writePackageJson;
225
- })(files || (files = {}));
226
- //src/helpers/utilities.ts
227
- var utils;
228
- (function (utils) {
229
- let checks;
230
- (function (checks) {
231
- checks.moduleType = (content, file) => {
232
- let _esmCount = 0;
233
- let cjsCount = 0;
234
- let unknownCount = 0;
235
- const sourceFile = ts6_1.default.createSourceFile(file, content, ts6_1.default.ScriptTarget.Latest, true);
236
- try {
237
- let hasESMImports = false;
238
- let hasCommonJS = false;
239
- // Walk through the AST to detect module syntax
240
- function walk(node) {
241
- // Check for ESM import/export syntax
242
- if (ts6_1.default.isImportDeclaration(node) ||
243
- ts6_1.default.isImportEqualsDeclaration(node) ||
244
- ts6_1.default.isExportDeclaration(node) ||
245
- ts6_1.default.isExportSpecifier(node) ||
246
- ts6_1.default.isExportAssignment(node)) {
247
- hasESMImports = true;
248
- }
249
- // Check for export modifier on declarations
250
- if ((ts6_1.default.isVariableStatement(node) ||
251
- ts6_1.default.isFunctionDeclaration(node) ||
252
- ts6_1.default.isInterfaceDeclaration(node) ||
253
- ts6_1.default.isTypeAliasDeclaration(node) ||
254
- ts6_1.default.isEnumDeclaration(node) ||
255
- ts6_1.default.isClassDeclaration(node)) &&
256
- node.modifiers?.some((mod) => mod.kind === ts6_1.default.SyntaxKind.ExportKeyword)) {
257
- hasESMImports = true;
258
- }
259
- // Check for CommonJS require/exports
260
- if (ts6_1.default.isCallExpression(node)) {
261
- if (ts6_1.default.isIdentifier(node.expression) &&
262
- node.expression.text === "require" &&
263
- node.arguments.length > 0) {
264
- hasCommonJS = true;
265
- }
266
- }
267
- // Check for module.exports or exports.xxx
268
- if (ts6_1.default.isPropertyAccessExpression(node)) {
269
- const text = node.getText(sourceFile);
270
- if (text.startsWith("module.exports") ||
271
- text.startsWith("exports.")) {
272
- hasCommonJS = true;
273
- }
274
- }
275
- // Continue walking the AST
276
- ts6_1.default.forEachChild(node, walk);
277
- } //---
278
- walk(sourceFile);
279
- // Determine the module format based on what we found
280
- if (hasESMImports && !hasCommonJS) {
281
- _esmCount++;
282
- }
283
- else if (hasCommonJS && !hasESMImports) {
284
- cjsCount++;
285
- }
286
- else if (hasESMImports && hasCommonJS) {
287
- // Mixed - probably ESM with dynamic imports or similar
288
- _esmCount++;
289
- }
290
- }
291
- catch (error) {
292
- console.error(color_1.default.magenta(`Error checking module format for ${file} : \n ${error}`));
293
- unknownCount++;
294
- }
295
- if (unknownCount > 0) {
296
- console.error(color_1.default.magenta(`Error checking module format.`));
297
- ts6_1.default.sys.exit(1);
298
- }
299
- return {
300
- isCommonJs: cjsCount > 0,
301
- isEsm: _esmCount > 0,
302
- };
303
- };
304
- /**
305
- * Checks if the given code string contains JSX syntax.
306
- * @param code The content of the file as a string.
307
- * @returns true if the file contains JSX, false otherwise.
308
- */
309
- function isJsxContent(code) {
310
- const sourceFile = ts6_1.default.createSourceFile("file.tsx", code, ts6_1.default.ScriptTarget.Latest,
311
- /*setParentNodes*/ true, ts6_1.default.ScriptKind.TSX);
312
- let containsJsx = false;
313
- function visitor(node) {
314
- // Check for JSX Elements, Self Closing Elements, or JSX Fragments
315
- if (ts6_1.default.isJsxElement(node) ||
316
- ts6_1.default.isJsxSelfClosingElement(node) ||
317
- ts6_1.default.isJsxFragment(node)) {
318
- containsJsx = true;
319
- return;
320
- }
321
- ts6_1.default.forEachChild(node, visitor);
322
- }
323
- visitor(sourceFile);
324
- return containsJsx;
325
- }
326
- checks.isJsxContent = isJsxContent;
327
- /**
328
- * Checks if a given node is inside a namespace declaration.
329
- * It does this by traversing up the parent nodes until it finds a module declaration with the namespace flag set.
330
- * @param n The node to check.
331
- * @returns true if the node is inside a namespace declaration, false otherwise.
332
- */
333
- checks.isInsideNamespace = (n) => {
334
- let current = n.parent;
335
- while (current) {
336
- if (ts6_1.default.isModuleDeclaration(current) &&
337
- current.flags === ts6_1.default.NodeFlags.Namespace) {
338
- return true;
339
- }
340
- current = current.parent;
341
- }
342
- return false;
343
- };
344
- /**
345
- * Check if a given module is a Node.js built-in module.
346
- * @param {string} input - The module to check.
347
- * @returns {boolean} True if the module is a Node.js built-in module, false otherwise.
348
- */
349
- checks.isNodeBuiltinModule = (input) => {
350
- const nodeModuleSpecifier = "node:";
351
- const nodeBuiltinModules = new Set(node_module_1.default.builtinModules);
352
- return (input.startsWith(nodeModuleSpecifier) || nodeBuiltinModules.has(input));
353
- };
354
- })(checks = utils.checks || (utils.checks = {})); // namespace checks
355
- let promises;
356
- (function (promises) {
357
- function isPromiseFun(fun) {
358
- return (Object.prototype.toString.call(fun) === "[object AsyncFunction]" ||
359
- fun.constructor.name === "AsyncFunction");
360
- }
361
- function walkPromise(param) {
362
- const fn = param[0];
363
- const args = param.slice(1);
364
- if (isPromiseFun(fn)) {
365
- return async () => await fn(...args);
366
- }
367
- else {
368
- return async () => fn(...args);
369
- }
370
- }
371
- function resolve(params) {
372
- const funs = params.map((w) => walkPromise(w));
373
- const series = async () => {
374
- const results = [];
375
- for (const [index, task] of funs.entries()) {
376
- try {
377
- const result = await task();
378
- results.push(result);
379
- }
380
- catch (error) {
381
- console.error(`Error in task ${index + 1}`);
382
- throw error;
383
- }
384
- }
385
- return results;
386
- };
387
- const concurrent = async () => {
388
- try {
389
- return await Promise.all(funs.map((f) => f()));
390
- }
391
- catch (error) {
392
- console.error("One of the functions rejected:", error);
393
- throw error;
394
- }
395
- };
396
- const allSettled = async () => {
397
- try {
398
- const settled = await Promise.allSettled(funs.map((f) => f()));
399
- const fulfilled = settled.filter((re) => re.status === "fulfilled");
400
- const rejected = settled.filter((re) => re.status === "rejected");
401
- if (rejected.length > 0) {
402
- console.warn("One of the functions rejected:", rejected[0]?.reason);
403
- node_process_1.default.exit(1);
404
- }
405
- return fulfilled.map((re) => re.value);
406
- }
407
- catch (error) {
408
- console.error("One of the functions rejected:", error);
409
- throw error;
410
- }
411
- };
412
- return {
413
- series: series,
414
- concurrent: concurrent,
415
- allSettled: allSettled,
416
- };
417
- }
418
- promises.resolve = resolve;
419
- async function run(fun, time, ...args) {
420
- return new Promise((resolve, reject) => {
421
- try {
422
- const t = time ? 0 : time;
423
- const result = fun(...args);
424
- setTimeout(() => resolve(result), t);
425
- }
426
- catch (error) {
427
- reject(error);
428
- }
429
- });
430
- }
431
- promises.run = run;
432
- // biome-ignore-end lint/suspicious/noExplicitAny: unknown
433
- })(promises = utils.promises || (utils.promises = {})); // namespace promises
434
- let gen;
435
- (function (gen) {
436
- gen.mergeStringArr = (input) => {
437
- return input.reduce((prev, curr) => prev.concat(curr), []);
438
- };
439
- function splitCamelCase(str) {
440
- const splitString = str
441
- .replace(/([a-z])([A-Z])/g, "$1 $2")
442
- .replace(/(_|-|\/)([a-z] || [A-Z])/g, " ")
443
- .replace(/([A-Z])/g, (match) => match.toLowerCase())
444
- .replace(/^([a-z])/, (match) => match.toUpperCase());
445
- return splitString;
446
- }
447
- gen.splitCamelCase = splitCamelCase;
448
- function packageJson() {
449
- const packageContent = node_fs_1.default.readFileSync(node_path_1.default.resolve(node_process_1.default.cwd(), "package.json"), "utf8");
450
- const pkg = JSON.parse(packageContent);
451
- const name = pkg.name ?? "";
452
- const version = pkg.version ?? "";
453
- /**
454
- * Get package name and version
455
- * @returns {string}
456
- */
457
- const pkgNameVersion = () => {
458
- let pkg_nv = "";
459
- if (name !== "" && version !== "") {
460
- pkg_nv = `${name}@${version}`;
461
- }
462
- else if (name !== "" && version === "") {
463
- pkg_nv = `${name}`;
464
- }
465
- else if (name === "" && version !== "") {
466
- pkg_nv = `the project@${version}`;
467
- }
468
- else {
469
- pkg_nv = "the project";
470
- }
471
- return pkg_nv;
472
- };
473
- const dependencies = () => {
474
- const deps = Object.keys(pkg.dependencies ?? {});
475
- const devDeps = Object.keys(pkg.devDependencies ?? {});
476
- return [...deps, ...devDeps];
477
- };
478
- // -----------------------------------------
479
- return { pkgNameVersion, dependencies };
480
- }
481
- gen.packageJson = packageJson;
482
- /**
483
- * Merge a list of import statements into a minimal set of import statements.
484
- * The algorithm works by grouping imports by module path and then merging them into a single import statement.
485
- * Type imports are processed first, and then regular imports are processed.
486
- * The resulting import statements are sorted alphabetically by module path.
487
- * @param imports - A list of import statements to merge.
488
- * @returns A list of merged import statements.
489
- */
490
- function mergeImportsStatement(imports) {
491
- const importMap = new Map();
492
- const typeImportMap = new Map();
493
- const defaultImports = new Map();
494
- const typeDefaultImports = new Map();
495
- const namespaceImports = new Map();
496
- // Parse each import statement
497
- for (const importStr of imports) {
498
- const importMatch = importStr.match(/import\s+(?:type\s+)?(?:(.*?)\s+from\s+)?["']([^"']+)["'];?/);
499
- if (!importMatch)
500
- continue;
501
- const [, importClause, _modulePath] = importMatch;
502
- const isTypeImport = importStr.includes("import type");
503
- const modulePath = _modulePath;
504
- if (!importClause) {
505
- // Default import or side-effect import
506
- const defaultMatch = importStr.match(/import\s+(?:type\s+)?(\w+)/);
507
- if (defaultMatch) {
508
- const importName = defaultMatch[1];
509
- const targetMap = isTypeImport
510
- ? typeDefaultImports
511
- : defaultImports;
512
- if (!targetMap.has(modulePath))
513
- targetMap.set(modulePath, new Set());
514
- targetMap.get(modulePath)?.add(importName);
515
- }
516
- continue;
517
- }
518
- if (importClause.startsWith("{")) {
519
- // Named imports: import { a, b } from 'module'
520
- const targetMap = isTypeImport ? typeImportMap : importMap;
521
- if (!targetMap.has(modulePath))
522
- targetMap.set(modulePath, new Set());
523
- const names = importClause
524
- .replace(/[{}]/g, "")
525
- .split(",")
526
- .map((s) => s.trim())
527
- .filter(Boolean);
528
- names.forEach((name) => targetMap.get(modulePath)?.add(name));
529
- }
530
- else if (importClause.startsWith("* as")) {
531
- // Namespace import: import * as name from 'module'
532
- const namespaceMatch = importClause.match(/\*\s+as\s+(\w+)/);
533
- if (namespaceMatch) {
534
- const namespaceName = namespaceMatch[1];
535
- if (!namespaceImports.has(modulePath))
536
- namespaceImports.set(modulePath, new Set());
537
- namespaceImports.get(modulePath)?.add(namespaceName);
538
- }
539
- }
540
- else {
541
- // Default import: import name from 'module'
542
- const targetMap = isTypeImport ? typeDefaultImports : defaultImports;
543
- if (!targetMap.has(modulePath))
544
- targetMap.set(modulePath, new Set());
545
- targetMap.get(modulePath)?.add(importClause.trim());
546
- }
547
- }
548
- const mergedImports = [];
549
- // Process named imports - remove type imports that have regular imports
550
- for (const [modulePath, regularNames] of importMap) {
551
- const typeNames = typeImportMap.get(modulePath) || new Set();
552
- // Only include type names that don't have regular imports
553
- const finalNames = new Set([...regularNames]);
554
- for (const typeName of typeNames) {
555
- if (!regularNames.has(typeName)) {
556
- finalNames.add(typeName);
557
- }
558
- }
559
- if (finalNames.size > 0) {
560
- const importNames = Array.from(finalNames).sort().join(", ");
561
- mergedImports.push(`import { ${importNames} } from "${modulePath}";`);
562
- }
563
- }
564
- // Add remaining type-only imports (where no regular imports exist for the module)
565
- for (const [modulePath, typeNames] of typeImportMap) {
566
- if (!importMap.has(modulePath) && typeNames.size > 0) {
567
- const importNames = Array.from(typeNames).sort().join(", ");
568
- mergedImports.push(`import type { ${importNames} } from "${modulePath}";`);
569
- }
570
- }
571
- // Process default imports - remove type default imports that have regular default imports
572
- for (const [modulePath, regularDefaultNames] of defaultImports) {
573
- const typeDefaultNames = typeDefaultImports.get(modulePath) || new Set();
574
- // Only include type default names that don't have regular default imports
575
- const finalNames = new Set([...regularDefaultNames]);
576
- for (const typeName of typeDefaultNames) {
577
- if (!regularDefaultNames.has(typeName)) {
578
- finalNames.add(typeName);
579
- }
580
- }
581
- if (finalNames.size > 0) {
582
- const importNames = Array.from(finalNames).join(", ");
583
- mergedImports.push(`import ${importNames} from "${modulePath}";`);
584
- }
585
- }
586
- // Add remaining type-only default imports
587
- for (const [modulePath, typeDefaultNames] of typeDefaultImports) {
588
- if (!defaultImports.has(modulePath) && typeDefaultNames.size > 0) {
589
- const importNames = Array.from(typeDefaultNames).join(", ");
590
- mergedImports.push(`import type ${importNames} from "${modulePath}";`);
591
- }
592
- }
593
- // Process namespace imports
594
- for (const [modulePath, names] of namespaceImports) {
595
- if (names.size > 0) {
596
- const importNames = Array.from(names).join(", ");
597
- mergedImports.push(`import * as ${importNames} from "${modulePath}";`);
598
- }
599
- }
600
- return mergedImports.sort();
601
- } //--
602
- gen.mergeImportsStatement = mergeImportsStatement;
603
- /**
604
- * Applies a given transformer to a source file and returns the modified code.
605
- * @param transformer A transformer factory that will be called with the source file.
606
- * @param sourceFile The source file to which the transformer will be applied.
607
- * @param compilerOptions Compiler options to use when applying the transformer.
608
- * @returns The modified code after applying the transformer.
609
- */
610
- function transformFunction(transformer, sourceFile, compilerOptions) {
611
- const transformationResult = ts6_1.default.transform(sourceFile, [transformer], compilerOptions);
612
- const transformedSourceFile = transformationResult.transformed[0];
613
- const printer = ts6_1.default.createPrinter({
614
- newLine: ts6_1.default.NewLineKind.LineFeed,
615
- removeComments: false,
616
- });
617
- const modifiedCode = printer.printFile(transformedSourceFile);
618
- transformationResult.dispose();
619
- return modifiedCode;
620
- } //--
621
- gen.transformFunction = transformFunction;
622
- /**
623
- * Finds all the properties accessed in the given node.
624
- * @param {ts6.Node} node - The node to search through.
625
- * @returns {string[]} - An array of all the properties accessed.
626
- */
627
- function findProperty(node) {
628
- const properties = [];
629
- function walk(n) {
630
- if (ts6_1.default.isPropertyAccessExpression(n) &&
631
- ts6_1.default.isIdentifier(n.expression)) {
632
- properties.push(n.expression.text);
633
- }
634
- n.forEachChild(walk);
635
- }
636
- walk(node);
637
- return properties;
638
- }
639
- gen.findProperty = findProperty;
640
- })(gen = utils.gen || (utils.gen = {})); // namespace gen
641
- })(utils || (utils = {})); // namespace utils
642
- const getScopeNodeLabel = (sourceFile, node, index) => {
643
- if (ts6_1.default.isModuleDeclaration(node)) {
644
- return `namespace:${node.name.getText(sourceFile)}`;
645
- }
646
- if (ts6_1.default.isClassDeclaration(node)) {
647
- return `class:${node.name?.text ?? `anonymous-${index}`}`;
648
- }
649
- if (ts6_1.default.isFunctionDeclaration(node) || ts6_1.default.isFunctionExpression(node)) {
650
- return `function:${node.name?.text ?? `anonymous-${index}`}`;
651
- }
652
- if (ts6_1.default.isArrowFunction(node)) {
653
- return `arrow:${index}`;
654
- }
655
- if (ts6_1.default.isMethodDeclaration(node)) {
656
- return `method:${node.name.getText(sourceFile)}`;
657
- }
658
- if (ts6_1.default.isBlock(node)) {
659
- return `block:${index}`;
660
- }
661
- return `${ts6_1.default.SyntaxKind[node.kind].toLowerCase()}:${index}`;
662
- };
663
- const getScopeKey = (file, scopeStack) => {
664
- if (scopeStack.length === 0) {
665
- return "global";
666
- }
667
- return `${file}::${scopeStack.join(" > ")}`;
668
- };
669
- const isScopeNode = (node) => ts6_1.default.isModuleDeclaration(node) ||
670
- ts6_1.default.isClassDeclaration(node) ||
671
- ts6_1.default.isFunctionDeclaration(node) ||
672
- ts6_1.default.isFunctionExpression(node) ||
673
- ts6_1.default.isArrowFunction(node) ||
674
- ts6_1.default.isMethodDeclaration(node) ||
675
- ts6_1.default.isBlock(node);
676
- const collectDeclarationNames = (node) => {
677
- if (ts6_1.default.isVariableStatement(node)) {
678
- return node.declarationList.declarations.flatMap((decl) => {
679
- if (!ts6_1.default.isIdentifier(decl.name)) {
680
- return [];
681
- }
682
- return [{ name: decl.name.text, positionNode: decl.name }];
683
- });
684
- }
685
- if (ts6_1.default.isFunctionDeclaration(node) ||
686
- ts6_1.default.isClassDeclaration(node) ||
687
- ts6_1.default.isEnumDeclaration(node) ||
688
- ts6_1.default.isInterfaceDeclaration(node) ||
689
- ts6_1.default.isTypeAliasDeclaration(node)) {
690
- if (node.name) {
691
- return [{ name: node.name.text, positionNode: node.name }];
692
- }
693
- }
694
- return [];
695
- };
696
- const collectDuplicateDeclarations = (deps, bundledSourceFile) => {
697
- const duplicateNameMap = new Map();
698
- const addDuplicateDeclaration = (scopeKey, name, file, sourceFile, positionNode) => {
699
- const { line, character } = sourceFile.getLineAndCharacterOfPosition(positionNode.getStart(sourceFile));
700
- const location = {
701
- file,
702
- line: line + 1,
703
- column: character + 1,
704
- };
705
- const duplicateKey = `${scopeKey}::${name}`;
706
- if (!duplicateNameMap.has(duplicateKey)) {
707
- duplicateNameMap.set(duplicateKey, {
708
- name,
709
- locations: new Set([location]),
710
- });
711
- return;
712
- }
713
- duplicateNameMap.get(duplicateKey)?.locations.add(location);
714
- };
715
- const collectFile = (file, sourceFile, node, scopeStack = []) => {
716
- const scopeKey = getScopeKey(file, scopeStack);
717
- for (const declaration of collectDeclarationNames(node)) {
718
- addDuplicateDeclaration(scopeKey, declaration.name, file, sourceFile, declaration.positionNode);
719
- }
720
- if (isScopeNode(node)) {
721
- const nextScopeStack = [
722
- ...scopeStack,
723
- getScopeNodeLabel(sourceFile, node, node.getStart(sourceFile)),
724
- ];
725
- ts6_1.default.forEachChild(node, (child) => {
726
- collectFile(file, sourceFile, child, nextScopeStack);
727
- });
728
- return;
729
- }
730
- ts6_1.default.forEachChild(node, (child) => {
731
- collectFile(file, sourceFile, child, scopeStack);
732
- });
733
- };
734
- for (const dep of deps) {
735
- const sourceFile = bundledSourceFile(dep.file, dep.content);
736
- collectFile(dep.file, sourceFile, sourceFile);
737
- }
738
- return duplicateNameMap;
739
- };
740
- const checkDuplicates = (tree, bundledSourceFile) => {
741
- let _err = false;
742
- const duplicateNameMap = collectDuplicateDeclarations(tree.depFiles, bundledSourceFile);
743
- duplicateNameMap.forEach(({ name, locations }) => {
744
- if (locations.size > 1) {
745
- _err = true;
746
- console.warn(color_1.default.yellow("[susee:error]"));
747
- console.warn(" Duplicate declarations found in your dependencies tree as follows:");
748
- console.warn(` - "${color_1.default.magenta(name)}" declared in multiple files : `);
749
- locations.forEach((f) => console.warn(` - ${f.file}:${f.line}:${f.column}`));
750
- console.info("Please rename these with different names to avoid duplicate declarations.");
751
- }
752
- });
753
- if (_err) {
754
- node_process_1.default.exit(1);
755
- }
756
- return tree;
757
- };
758
- //src/dependencies/graph.ts
759
- // ----------------------------------------------------Handlers------------------------------------------------------//
760
- function handleImports(node, processFn) {
761
- // Handle : import declaration
762
- if (ts6_1.default.isImportDeclaration(node) && node.moduleSpecifier) {
763
- const moduleText = node.moduleSpecifier
764
- .getText()
765
- .replace(/^['"`]|['"`]$/g, "");
766
- processFn(moduleText);
767
- return;
768
- } //--
769
- // Recursively visit all children
770
- ts6_1.default.forEachChild(node, (n) => handleImports(n, processFn));
771
- }
772
- function handleImportEqual(node, processFn) {
773
- // Handle : import equal declaration
774
- if (ts6_1.default.isImportEqualsDeclaration(node) &&
775
- ts6_1.default.isExternalModuleReference(node.moduleReference) &&
776
- ts6_1.default.isStringLiteral(node.moduleReference.expression)) {
777
- const moduleText = node.moduleReference.expression.text;
778
- processFn(moduleText);
779
- return;
780
- } //--
781
- // Recursively visit all children
782
- ts6_1.default.forEachChild(node, (n) => handleImportEqual(n, processFn));
783
- }
784
- function handleAwaitImport(node, processFn) {
785
- // Handle : import equal declaration
786
- if (ts6_1.default.isAwaitExpression(node) &&
787
- ts6_1.default.isCallExpression(node.expression) &&
788
- node.expression.expression.kind === ts6_1.default.SyntaxKind.ImportKeyword) {
789
- const firstArg = node.expression.arguments[0];
790
- if (firstArg && ts6_1.default.isStringLiteral(firstArg)) {
791
- processFn(firstArg.text);
792
- }
793
- return;
794
- } //--
795
- // Recursively visit all children
796
- ts6_1.default.forEachChild(node, (n) => handleAwaitImport(n, processFn));
797
- }
798
- function handleRequire(node, processFn) {
799
- // Handle : require calls , `var foo = require("foo")`
800
- // can't handle import equal statement like `import foo = require("foo")`
801
- if (ts6_1.default.isCallExpression(node) &&
802
- ts6_1.default.isIdentifier(node.expression) &&
803
- node.expression.text === "require" &&
804
- node.arguments.length > 0) {
805
- // if expression callExpression node's text equal to require
806
- // index 0 of arguments is moduleText
807
- // I didn't use forEach or for-off loop to avoid multiple processing.
808
- const firstArg = node.arguments[0];
809
- if (firstArg && ts6_1.default.isStringLiteral(firstArg)) {
810
- processFn(firstArg.text);
811
- }
812
- return; // Skip children for property access require calls
813
- }
814
- // Handle : property access like `var foo = require("foo").foo`
815
- if (ts6_1.default.isPropertyAccessExpression(node) &&
816
- ts6_1.default.isCallExpression(node.expression) &&
817
- ts6_1.default.isIdentifier(node.expression.expression) &&
818
- node.expression.expression.text === "require" &&
819
- node.expression.arguments.length > 0) {
820
- const firstArg = node.expression.arguments[0];
821
- if (firstArg && ts6_1.default.isStringLiteral(firstArg)) {
822
- processFn(firstArg.text);
823
- }
824
- return; // Skip children for property access require calls
825
- }
826
- // Recursively visit all children (except for require calls we already processed)
827
- ts6_1.default.forEachChild(node, (n) => handleRequire(n, processFn));
828
- }
829
- function handlers(node, processFn) {
830
- Promise.all([
831
- handleImports(node, processFn),
832
- handleRequire(node, processFn),
833
- handleImportEqual(node, processFn),
834
- handleAwaitImport(node, processFn),
835
- ]);
836
- }
837
- // resolved extensions
838
- const allowedExtensions = new Set([
839
- "js",
840
- "cjs",
841
- "mjs",
842
- "ts",
843
- "mts",
844
- "cts",
845
- "jsx",
846
- "tsx",
847
- "json",
848
- ]);
849
- function isDir(filePath) {
850
- try {
851
- const stat = node_fs_1.default.lstatSync(filePath);
852
- return stat.isDirectory();
853
- }
854
- catch (err) {
855
- if (typeof err === "object" &&
856
- err !== null &&
857
- "code" in err &&
858
- // biome-ignore lint/suspicious/noExplicitAny: for error log only
859
- err.code === "ENOENT") {
860
- return false;
861
- }
862
- throw err;
863
- }
864
- }
865
- function getFileName(input) {
866
- const namePart = node_path_1.default.basename(input).split(".")[0];
867
- return namePart ? namePart.trim() : "";
868
- }
869
- function getExtensionName(input) {
870
- return node_path_1.default.basename(input).split(".")[1]?.trim() || "";
871
- }
872
- function resolveExtension(filePath) {
873
- let result;
874
- let ext;
875
- let isDirPath = false;
876
- // If it's a directory, look for index file
877
- if (isDir(filePath)) {
878
- const files = node_fs_1.default.readdirSync(filePath);
879
- const found = files.find((file) => getFileName(file) === "index" &&
880
- allowedExtensions.has(getExtensionName(file)));
881
- if (found) {
882
- result = node_path_1.default.join(filePath, found);
883
- ext = getExtensionName(found);
884
- isDirPath = true;
885
- }
886
- else {
887
- console.error(`${filePath} is a directory and no index file with JS/TS extension found.`); // ----------------------------------------------------------------------------------------------------------//
888
- node_process_1.default.exit(1);
889
- }
890
- }
891
- else {
892
- // Not a directory: try to resolve extension
893
- const dirName = node_path_1.default.dirname(filePath);
894
- const baseName = node_path_1.default.basename(filePath);
895
- const [fileName, extName = ""] = baseName.split(".");
896
- // const files = fs.globSync(
897
- // `${dirName}/**/*.{js,cjs,mjs,ts,cts,mts,jsx,tsx}`
898
- // );
899
- const files = ts6_1.default.sys.readDirectory(dirName);
900
- const match = files
901
- .map((f) => {
902
- const [name, ext = ""] = node_path_1.default.basename(f).split(".");
903
- return { name, ext };
904
- })
905
- .find((f) => f.name === fileName && allowedExtensions.has(f.ext));
906
- if (match) {
907
- if (!extName) {
908
- result = `${filePath}.${match.ext}`;
909
- ext = match.ext;
910
- }
911
- else if (extName === match.ext) {
912
- result = filePath;
913
- ext = match.ext;
914
- }
915
- else {
916
- const safeExtName = extName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
917
- result = filePath.replace(new RegExp(`\\.${safeExtName}$`), `.${match.ext}`);
918
- ext = match.ext;
919
- }
920
- }
921
- else {
922
- // If not found, maybe it's a directory import (e.g. ./lib)
923
- if (isDir(filePath)) {
924
- const files = node_fs_1.default.readdirSync(filePath);
925
- const found = files.find((file) => getFileName(file) === "index" &&
926
- allowedExtensions.has(getExtensionName(file)));
927
- if (found) {
928
- result = node_path_1.default.join(filePath, found);
929
- ext = getExtensionName(found);
930
- isDirPath = true;
931
- }
932
- }
933
- }
934
- }
935
- if (!(result && ext)) {
936
- console.error(`When checking ${filePath}, it's not a file or file with unsupported extension`);
937
- node_process_1.default.exit(1);
938
- }
939
- return { result, ext, isDirPath };
940
- }
941
- function collectDependencies(entry, collectedDependencies, root) {
942
- const dependencies = [];
943
- const visited = new Set();
944
- const collectedNpmModules = [];
945
- const collectedNodeModules = [];
946
- const collectedWarning = [];
947
- function visit(file, index) {
948
- const absPath = node_path_1.default.resolve(root, file);
949
- if (visited.has(absPath))
950
- return;
951
- visited.add(absPath);
952
- const { result: checkedAbsPath } = resolveExtension(absPath);
953
- if (!node_fs_1.default.existsSync(checkedAbsPath)) {
954
- dependencies.push({
955
- file: absPath,
956
- index,
957
- importFiles: [],
958
- });
959
- collectedWarning.push([`File not found: ${checkedAbsPath}`]);
960
- }
961
- const content = node_fs_1.default.readFileSync(checkedAbsPath, "utf8");
962
- const sourceFile = ts6_1.default.createSourceFile(file, content, ts6_1.default.ScriptTarget.Latest, true);
963
- const importFiles = [];
964
- const warn = [];
965
- const npmModules = [];
966
- const nodeModules = [];
967
- function processModule(moduleText) {
968
- // Handle : Imported local dependencies of a file.
969
- if (moduleText.startsWith(".") || moduleText.startsWith("..")) {
970
- // Try to resolve as file or directory
971
- const resolvedModulePath = node_path_1.default.resolve(node_path_1.default.dirname(checkedAbsPath), moduleText);
972
- // biome-ignore lint/suspicious/noExplicitAny: just let
973
- let resolved = {};
974
- try {
975
- resolved = resolveExtension(resolvedModulePath);
976
- }
977
- catch {
978
- // fallback: treat as file with extension
979
- resolved = {
980
- result: resolvedModulePath,
981
- ext: node_path_1.default.extname(resolvedModulePath).slice(1),
982
- isDirPath: false,
983
- };
984
- }
985
- const relImport = node_path_1.default.relative(root, resolved.result);
986
- importFiles.push(relImport);
987
- }
988
- // Handle : Imported dependencies of node builtin modules of a file.
989
- else if (node_module_1.default.builtinModules.includes(moduleText)) {
990
- nodeModules.push(moduleText);
991
- }
992
- // Handle : Imported npm dependencies of a file
993
- // Handle : Imported npm dependencies of a file, by checking local package.json
994
- // currently only check for these dependencies are installed or not, depend on project's package.json
995
- // TODO try for provide information such as exported files , to use in bundle process
996
- else if (collectedDependencies.includes(moduleText)) {
997
- npmModules.push(moduleText);
998
- }
999
- // Unknown dependencies
1000
- // local dependencies are checked before by resolveExtension function.
1001
- // TODO try for analyze these errors and provide analyzed report.
1002
- else {
1003
- warn.push(moduleText);
1004
- }
1005
- }
1006
- ts6_1.default.forEachChild(sourceFile, (node) => handlers(node, processModule));
1007
- dependencies.push({
1008
- file: absPath,
1009
- index,
1010
- importFiles,
1011
- });
1012
- collectedNpmModules.push(npmModules);
1013
- collectedNodeModules.push(nodeModules);
1014
- collectedWarning.push(warn);
1015
- importFiles.forEach((depFile) => visit(depFile, dependencies.length));
1016
- }
1017
- visit(entry, 0);
1018
- return {
1019
- dependencies,
1020
- collectedNodeModules,
1021
- collectedNpmModules,
1022
- collectedWarning,
1023
- };
1024
- }
1025
- //
1026
- function getPackageJson() {
1027
- const packageContent = node_fs_1.default.readFileSync(node_path_1.default.resolve(node_process_1.default.cwd(), "package.json"), "utf8");
1028
- const pkg = JSON.parse(packageContent);
1029
- const deps = Object.keys(pkg.dependencies ?? {});
1030
- const devDeps = Object.keys(pkg.devDependencies ?? {});
1031
- return [...deps, ...devDeps];
1032
- }
1033
- // Topological sort of a directed acyclic graph (DAG)
1034
- function topoSort(tree) {
1035
- const visited = new Set();
1036
- const sorted = [];
1037
- function visit(node) {
1038
- if (visited.has(node))
1039
- return;
1040
- visited.add(node);
1041
- (tree[node] || []).forEach(visit);
1042
- sorted.push(node);
1043
- }
1044
- Object.keys(tree).forEach(visit);
1045
- return sorted; // reverse for correct order
1046
- }
1047
- // Create a dependency graph from a list of collected dependencies
1048
- const createGraph = (deps) => {
1049
- const graph = {};
1050
- for (const dep of deps) {
1051
- const _name = node_path_1.default.relative(node_process_1.default.cwd(), dep.file);
1052
- graph[_name] = dep.importFiles;
1053
- }
1054
- return graph;
1055
- };
1056
- function generateGraph(entry) {
1057
- const root = node_process_1.default.cwd();
1058
- const collectedDependencies = getPackageJson();
1059
- const collectedData = collectDependencies(entry, collectedDependencies, root);
1060
- const graphObj = collectedData.dependencies;
1061
- const npmModules = utils.gen.mergeStringArr(collectedData.collectedNpmModules);
1062
- const nodeModules = utils.gen.mergeStringArr(collectedData.collectedNodeModules);
1063
- const warning = utils.gen.mergeStringArr(collectedData.collectedWarning);
1064
- const depsObj = createGraph(graphObj);
1065
- const sortedGraph = topoSort(depsObj);
1066
- return {
1067
- sort: () => sortedGraph,
1068
- npm: () => npmModules,
1069
- node: () => nodeModules,
1070
- deps: () => depsObj,
1071
- warn: () => warning,
1072
- };
1073
- }
1074
- //src/dependencies/index.ts
1075
- async function generateDependencies(entry, bundledSourceFile) {
1076
- const graph = generateGraph(entry);
1077
- const sorted = graph.sort();
1078
- const npm = graph.npm();
1079
- const nodes = graph.node();
1080
- const warns = graph.warn();
1081
- const tree = {
1082
- entry,
1083
- npm,
1084
- nodes,
1085
- warns,
1086
- depFiles: [],
1087
- };
1088
- const entryBase = node_path_1.default.basename(entry);
1089
- for (const file of sorted) {
1090
- const fileBase = node_path_1.default.basename(file);
1091
- const fileExt = node_path_1.default.extname(file);
1092
- const read = await files.readFile(file);
1093
- const content = read.str;
1094
- const bytes = read.bytes;
1095
- const mt = utils.checks.moduleType(content, file);
1096
- const moduleType = fileExt === ".json" ? "json" : mt.isCommonJs ? "cjs" : "esm";
1097
- const isJsx = utils.checks.isJsxContent(content);
1098
- const isEntry = entryBase === fileBase;
1099
- tree.depFiles.push({
1100
- file,
1101
- content,
1102
- bytes,
1103
- moduleType,
1104
- fileExt: fileExt,
1105
- is_jsx: isJsx,
1106
- is_entry: isEntry,
1107
- });
1108
- }
1109
- return checkDuplicates(tree, bundledSourceFile);
1110
- }
1111
- //src/helpers/profile.ts
1112
- const profileEnvName = "SUSEE_PROFILE";
1113
- const isProfileEnabled = () => {
1114
- const value = node_process_1.default.env[profileEnvName];
1115
- return value === "1" || value === "true";
1116
- };
1117
- const setProfileEnabled = (enabled) => {
1118
- if (enabled) {
1119
- node_process_1.default.env[profileEnvName] = "1";
1120
- return;
1121
- }
1122
- delete node_process_1.default.env[profileEnvName];
1123
- };
1124
- const formatProfileMs = (start) => {
1125
- return `${(Number(node_process_1.default.hrtime.bigint() - start) / 1000000).toFixed(1)}ms`;
1126
- };
1127
- const logProfilePhase = (scope, phase, start) => {
1128
- if (!isProfileEnabled())
1129
- return;
1130
- console.log(`[SUSEE_PROFILE][${scope}] ${phase}: ${formatProfileMs(start)}`);
1131
- };
1132
- //src/bundler/lib/helpers.ts
1133
- const isJSON = (tree) => {
1134
- const json = tree.depFiles.find((file) => file.fileExt === ".json" && file.moduleType === "json");
1135
- return !!json;
1136
- };
1137
- const jsonExtToTs = (file) => {
1138
- if (node_path_1.default.extname(file) === ".json") {
1139
- return file.replace(/.json/g, ".ts");
1140
- }
1141
- else {
1142
- return file;
1143
- }
1144
- };
1145
- const createBundledSourceFile = (file, content) => {
1146
- return ts6_1.default.createSourceFile(jsonExtToTs(file), content, ts6_1.default.ScriptTarget.Latest, true);
1147
- };
1148
- const transformBundledSource = (sourceFile, compilerOptions, transformer) => {
1149
- return utils.gen.transformFunction(transformer, sourceFile, compilerOptions);
1150
- };
1151
- const normalizePathKey = (filePath) => {
1152
- const parsed = node_path_1.default.parse(filePath);
1153
- let noExt = node_path_1.default.join(parsed.dir, parsed.name);
1154
- if (parsed.name === "index") {
1155
- noExt = parsed.dir;
1156
- }
1157
- return node_path_1.default.normalize(noExt);
1158
- };
1159
- const getFileKey = (filePath) => normalizePathKey(filePath);
1160
- const getModuleKeyFromSpecifier = (moduleSpecifier, sourceFile, containingFile) => {
1161
- let spec = "";
1162
- if (ts6_1.default.isStringLiteral(moduleSpecifier)) {
1163
- spec = moduleSpecifier.text;
1164
- }
1165
- else {
1166
- spec = moduleSpecifier.getText(sourceFile).replace(/^['"]|['"]$/g, "");
1167
- }
1168
- if (spec.startsWith(".") || spec.startsWith("/")) {
1169
- const baseDir = node_path_1.default.dirname(containingFile);
1170
- const resolved = node_path_1.default.isAbsolute(containingFile)
1171
- ? node_path_1.default.resolve(baseDir, spec)
1172
- : node_path_1.default.normalize(node_path_1.default.join(baseDir, spec));
1173
- return normalizePathKey(resolved);
1174
- }
1175
- return spec;
1176
- };
1177
- //src/bundler/lib/uniqueName.ts
1178
- class UniqueName {
1179
- _storedPrefix;
1180
- constructor() {
1181
- this._storedPrefix = new Map();
1182
- }
1183
- setPrefix({ key, value }) {
1184
- if (this._storedPrefix.has(key)) {
1185
- const [_prefix, count] = this._storedPrefix.get(key);
1186
- this._storedPrefix.set(key, [value, count + 1]);
1187
- }
1188
- else {
1189
- this._storedPrefix.set(key, [value, 0]);
1190
- }
1191
- return this;
1192
- }
1193
- getName(key, input) {
1194
- const [prefix, count] = this._storedPrefix.get(key) || [];
1195
- const _name = prefix
1196
- ? `${prefix}${input}_${(count ?? 0) + 1}`
1197
- : `__susee__${input}_${(count ?? 0) + 1}`;
1198
- this._storedPrefix.set(key, [prefix ?? "__susee__", (count ?? 0) + 1]);
1199
- return _name;
1200
- }
1201
- getPrefix(key) {
1202
- const [prefix] = this._storedPrefix.get(key) || [];
1203
- return prefix;
1204
- }
1205
- }
1206
- const uniqueName = new UniqueName();
1207
- //src/bundler/lib/anonymous.ts
1208
- const anonymousExportNameMap = [];
1209
- const anonymousImportNameMap = [];
1210
- const anonymousPrefixKey = "AnonymousName";
1211
- const createAnonymousNameGenerator = () => uniqueName.setPrefix({
1212
- key: anonymousPrefixKey,
1213
- value: "susee__anonymous__",
1214
- });
1215
- let anonymousName = createAnonymousNameGenerator();
1216
- function anonymousCallExpressionHandler(compilerOptions) {
1217
- return ({ file, content, ...rest }) => {
1218
- const sourceFile = createBundledSourceFile(file, content);
1219
- const transformer = (context) => {
1220
- const { factory } = context;
1221
- function visitor(node) {
1222
- if (ts6_1.default.isCallExpression(node)) {
1223
- if (ts6_1.default.isIdentifier(node.expression)) {
1224
- const base = node.expression.text;
1225
- const mapping = anonymousImportNameMap.find((m) => m.base === base && m.file === file);
1226
- if (mapping) {
1227
- return factory.updateCallExpression(node, factory.createIdentifier(mapping.newName), node.typeArguments, node.arguments);
1228
- }
1229
- }
1230
- }
1231
- else if (ts6_1.default.isPropertyAccessExpression(node)) {
1232
- if (ts6_1.default.isIdentifier(node.expression)) {
1233
- const base = node.expression.text;
1234
- const mapping = anonymousImportNameMap.find((m) => m.base === base && m.file === file);
1235
- if (mapping) {
1236
- return factory.updatePropertyAccessExpression(node, factory.createIdentifier(mapping.newName), node.name);
1237
- }
1238
- }
1239
- }
1240
- else if (ts6_1.default.isNewExpression(node)) {
1241
- if (ts6_1.default.isIdentifier(node.expression)) {
1242
- const base = node.expression.text;
1243
- const mapping = anonymousImportNameMap.find((m) => m.base === base && m.file === file);
1244
- if (mapping) {
1245
- return factory.updateNewExpression(node, factory.createIdentifier(mapping.newName), node.typeArguments, node.arguments);
1246
- }
1247
- }
1248
- // for export specifier it is focus on entry file
1249
- }
1250
- else if (ts6_1.default.isExportSpecifier(node)) {
1251
- if (ts6_1.default.isIdentifier(node.name)) {
1252
- const base = node.name.text;
1253
- const mapping = anonymousImportNameMap.find((m) => m.base === base && m.file === file);
1254
- if (mapping) {
1255
- return factory.updateExportSpecifier(node, node.isTypeOnly, node.propertyName, factory.createIdentifier(mapping.newName));
1256
- }
1257
- }
1258
- }
1259
- return ts6_1.default.visitEachChild(node, visitor, context);
1260
- }
1261
- return (rootNode) => ts6_1.default.visitNode(rootNode, visitor);
1262
- };
1263
- const _content = transformBundledSource(sourceFile, compilerOptions, transformer);
1264
- return { file, content: _content, ...rest };
1265
- };
1266
- }
1267
- //--
1268
- function anonymousExportHandler(compilerOptions) {
1269
- return ({ file, content, ...rest }) => {
1270
- const sourceFile = createBundledSourceFile(file, content);
1271
- /**
1272
- * A transformer that handles anonymous default exports by assigning them a name
1273
- *
1274
- * @param {ts6.TransformationContext} context - transformation context
1275
- * @returns {ts6.Transformer<ts6.SourceFile>} - transformer
1276
- */
1277
- const transformer = (context) => {
1278
- const { factory } = context;
1279
- function visitor(node) {
1280
- const fileName = node_path_1.default.basename(file).split(".")[0];
1281
- if ((ts6_1.default.isFunctionDeclaration(node) || ts6_1.default.isClassDeclaration(node)) &&
1282
- node.name === undefined) {
1283
- let exp = false;
1284
- let def = false;
1285
- node.modifiers?.forEach((mod) => {
1286
- if (mod.kind === ts6_1.default.SyntaxKind.ExportKeyword) {
1287
- exp = true;
1288
- }
1289
- if (mod.kind === ts6_1.default.SyntaxKind.DefaultKeyword) {
1290
- def = true;
1291
- }
1292
- });
1293
- if (exp && def) {
1294
- const base = anonymousName.getName(anonymousPrefixKey, fileName);
1295
- anonymousExportNameMap.push({
1296
- base,
1297
- file: fileName,
1298
- newName: base,
1299
- isEd: true,
1300
- });
1301
- if (ts6_1.default.isFunctionDeclaration(node)) {
1302
- return factory.updateFunctionDeclaration(node, node.modifiers, node.asteriskToken, factory.createIdentifier(base), node.typeParameters, node.parameters, node.type, node.body);
1303
- }
1304
- else if (ts6_1.default.isClassDeclaration(node)) {
1305
- return factory.updateClassDeclaration(node, node.modifiers, factory.createIdentifier(base), node.typeParameters, node.heritageClauses, node.members);
1306
- }
1307
- }
1308
- }
1309
- else if (ts6_1.default.isExportAssignment(node) &&
1310
- !node.isExportEquals &&
1311
- node.name === undefined) {
1312
- if (ts6_1.default.isArrowFunction(node.expression)) {
1313
- const base = anonymousName.getName(anonymousPrefixKey, fileName);
1314
- const arrowFunctionNode = factory.createArrowFunction(node.expression.modifiers, node.expression.typeParameters, node.expression.parameters, node.expression.type, node.expression.equalsGreaterThanToken, node.expression.body);
1315
- const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), node.expression.exclamationToken, node.expression.type, arrowFunctionNode);
1316
- const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts6_1.default.NodeFlags.Const);
1317
- const variableStatementNode = factory.createVariableStatement(node.expression.modifiers, variableDeclarationListNode);
1318
- const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
1319
- anonymousExportNameMap.push({
1320
- base,
1321
- file: fileName,
1322
- newName: base,
1323
- isEd: true,
1324
- });
1325
- return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
1326
- }
1327
- else if (ts6_1.default.isObjectLiteralExpression(node.expression)) {
1328
- const base = anonymousName.getName(anonymousPrefixKey, fileName);
1329
- const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), undefined, undefined, node.expression);
1330
- const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts6_1.default.NodeFlags.Const);
1331
- const variableStatementNode = factory.createVariableStatement(undefined, variableDeclarationListNode);
1332
- const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
1333
- anonymousExportNameMap.push({
1334
- base,
1335
- file: fileName,
1336
- newName: base,
1337
- isEd: true,
1338
- });
1339
- return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
1340
- }
1341
- else if (ts6_1.default.isArrayLiteralExpression(node.expression)) {
1342
- const base = anonymousName.getName(anonymousPrefixKey, fileName);
1343
- const arrayLiteralExpressionNode = factory.createArrayLiteralExpression(node.expression.elements, true);
1344
- const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), undefined, undefined, arrayLiteralExpressionNode);
1345
- const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts6_1.default.NodeFlags.Const);
1346
- const variableStatementNode = factory.createVariableStatement(undefined, variableDeclarationListNode);
1347
- const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
1348
- anonymousExportNameMap.push({
1349
- base,
1350
- file: fileName,
1351
- newName: base,
1352
- isEd: true,
1353
- });
1354
- return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
1355
- }
1356
- else if (ts6_1.default.isStringLiteral(node.expression)) {
1357
- const base = anonymousName.getName(anonymousPrefixKey, fileName);
1358
- const stringLiteralNode = factory.createStringLiteral(node.expression.text);
1359
- const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), undefined, undefined, stringLiteralNode);
1360
- const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts6_1.default.NodeFlags.Const);
1361
- const variableStatementNode = factory.createVariableStatement(undefined, variableDeclarationListNode);
1362
- const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
1363
- anonymousExportNameMap.push({
1364
- base,
1365
- file: fileName,
1366
- newName: base,
1367
- isEd: true,
1368
- });
1369
- return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
1370
- }
1371
- else if (ts6_1.default.isNumericLiteral(node.expression)) {
1372
- const base = anonymousName.getName(anonymousPrefixKey, fileName);
1373
- const numericLiteralNode = factory.createNumericLiteral(node.expression.text);
1374
- const variableDeclarationNode = factory.createVariableDeclaration(factory.createIdentifier(base), undefined, undefined, numericLiteralNode);
1375
- const variableDeclarationListNode = factory.createVariableDeclarationList([variableDeclarationNode], ts6_1.default.NodeFlags.Const);
1376
- const variableStatementNode = factory.createVariableStatement(undefined, variableDeclarationListNode);
1377
- const exportAssignmentNode = factory.createExportAssignment(undefined, undefined, factory.createIdentifier(base));
1378
- anonymousExportNameMap.push({
1379
- base,
1380
- file: fileName,
1381
- newName: base,
1382
- isEd: true,
1383
- });
1384
- return factory.updateSourceFile(sourceFile, [variableStatementNode, exportAssignmentNode], sourceFile.isDeclarationFile, sourceFile.referencedFiles, sourceFile.typeReferenceDirectives, sourceFile.hasNoDefaultLib, sourceFile.libReferenceDirectives);
1385
- }
1386
- } //
1387
- return ts6_1.default.visitEachChild(node, visitor, context);
1388
- }
1389
- return (rootNode) => ts6_1.default.visitNode(rootNode, visitor);
1390
- };
1391
- const _content = transformBundledSource(sourceFile, compilerOptions, transformer);
1392
- return { file, content: _content, ...rest };
1393
- };
1394
- }
1395
- //--
1396
- function anonymousImportHandler(compilerOptions) {
1397
- return ({ file, content, ...rest }) => {
1398
- const sourceFile = createBundledSourceFile(file, content);
1399
- const transformer = (context) => {
1400
- const { factory } = context;
1401
- function visitor(node) {
1402
- if (ts6_1.default.isImportDeclaration(node)) {
1403
- const fileName = node.moduleSpecifier.getText(sourceFile);
1404
- const _name = node_path_1.default.basename(fileName).split(".")[0].trim();
1405
- // check only import default expression
1406
- if (node.importClause?.name &&
1407
- ts6_1.default.isIdentifier(node.importClause.name)) {
1408
- const base = node.importClause.name.text.trim();
1409
- const mapping = anonymousExportNameMap.find((v) => v.file === _name);
1410
- if (mapping) {
1411
- anonymousImportNameMap.push({
1412
- base,
1413
- file,
1414
- newName: mapping.newName,
1415
- isEd: true,
1416
- });
1417
- const newImportClause = factory.updateImportClause(node.importClause, node.importClause.phaseModifier, factory.createIdentifier(mapping.newName), node.importClause.namedBindings);
1418
- return factory.updateImportDeclaration(node, node.modifiers, newImportClause, node.moduleSpecifier, node.attributes);
1419
- }
1420
- }
1421
- }
1422
- return ts6_1.default.visitEachChild(node, visitor, context);
1423
- }
1424
- return (rootNode) => ts6_1.default.visitNode(rootNode, visitor);
1425
- };
1426
- const _content = transformBundledSource(sourceFile, compilerOptions, transformer);
1427
- return { file, content: _content, ...rest };
1428
- };
1429
- }
1430
- //--
1431
- function resetAnonymousState() {
1432
- anonymousExportNameMap.length = 0;
1433
- anonymousImportNameMap.length = 0;
1434
- anonymousName = createAnonymousNameGenerator();
1435
- }
1436
- const anonymousHandler = async (deps, compilerOptions) => {
1437
- resetAnonymousState();
1438
- const anonymous = utils.promises.resolve([
1439
- [anonymousExportHandler, compilerOptions],
1440
- [anonymousImportHandler, compilerOptions],
1441
- [anonymousCallExpressionHandler, compilerOptions],
1442
- ]);
1443
- const anons = await anonymous.concurrent();
1444
- for (const anon of anons) {
1445
- deps = deps.map(anon);
1446
- }
1447
- return deps;
1448
- };
1449
- //src/bundler/lib/exportDefault.ts
1450
- const exportDefaultExportNameMap = [];
1451
- const exportDefaultImportNameMap = [];
1452
- const exportDefaultPrefixKey = "ExportDefault";
1453
- const createExportDefaultNameGenerator = () => uniqueName.setPrefix({
1454
- key: exportDefaultPrefixKey,
1455
- value: "susee__exportDefault__",
1456
- });
1457
- let exportDefaultName = createExportDefaultNameGenerator();
1458
- const toNameLookupKey = (file, base) => `${file}\u0000${base}`;
1459
- const createNameLookup = (sets) => {
1460
- const lookup = new Map();
1461
- for (const set of sets) {
1462
- lookup.set(toNameLookupKey(set.file, set.base), set.newName);
1463
- }
1464
- return lookup;
1465
- };
1466
- const getMappedName = (lookup, file, base) => {
1467
- return lookup.get(toNameLookupKey(file, base));
1468
- };
1469
- const hasExportDefaultModifiers = (node) => {
1470
- let exp = false;
1471
- let def = false;
1472
- node.modifiers?.forEach((mod) => {
1473
- if (mod.kind === ts6_1.default.SyntaxKind.ExportKeyword) {
1474
- exp = true;
1475
- }
1476
- if (mod.kind === ts6_1.default.SyntaxKind.DefaultKeyword) {
1477
- def = true;
1478
- }
1479
- });
1480
- return exp && def;
1481
- };
1482
- const collectExportDefaultMappings = (deps) => {
1483
- for (const dep of deps) {
1484
- if (dep.fileExt === ".json" || dep.is_entry) {
1485
- continue;
1486
- }
1487
- const fileKey = getFileKey(dep.file);
1488
- const sourceFile = createBundledSourceFile(dep.file, dep.content);
1489
- for (const statement of sourceFile.statements) {
1490
- if ((ts6_1.default.isFunctionDeclaration(statement) ||
1491
- ts6_1.default.isClassDeclaration(statement)) &&
1492
- statement.name &&
1493
- ts6_1.default.isIdentifier(statement.name) &&
1494
- hasExportDefaultModifiers(statement)) {
1495
- const baseName = statement.name.text;
1496
- const newName = exportDefaultName.getName(exportDefaultPrefixKey, baseName);
1497
- exportDefaultExportNameMap.push({
1498
- base: baseName,
1499
- file: fileKey,
1500
- newName,
1501
- isEd: true,
1502
- });
1503
- break;
1504
- }
1505
- if (ts6_1.default.isExportAssignment(statement) &&
1506
- !statement.isExportEquals &&
1507
- ts6_1.default.isIdentifier(statement.expression)) {
1508
- const baseName = statement.expression.text;
1509
- const newName = exportDefaultName.getName(exportDefaultPrefixKey, baseName);
1510
- exportDefaultExportNameMap.push({
1511
- base: baseName,
1512
- file: fileKey,
1513
- newName,
1514
- isEd: true,
1515
- });
1516
- break;
1517
- }
1518
- }
1519
- }
1520
- };
1521
- // -----------------------
1522
- function exportDefaultImportAndUsageHandler(compilerOptions) {
1523
- return ({ file, content, fileExt, ...rest }) => {
1524
- if (fileExt === ".json")
1525
- return { file, content, fileExt, ...rest };
1526
- const sourceFile = createBundledSourceFile(file, content);
1527
- const transformer = (context) => {
1528
- const { factory } = context;
1529
- const exportLookup = createNameLookup(exportDefaultExportNameMap);
1530
- const importLookup = new Map();
1531
- const resolveMappedName = (base) => importLookup.get(base);
1532
- const isDeclarationName = (node) => {
1533
- const parent = node.parent;
1534
- if ((ts6_1.default.isVariableDeclaration(parent) ||
1535
- ts6_1.default.isFunctionDeclaration(parent) ||
1536
- ts6_1.default.isClassDeclaration(parent) ||
1537
- ts6_1.default.isParameter(parent) ||
1538
- ts6_1.default.isTypeAliasDeclaration(parent) ||
1539
- ts6_1.default.isInterfaceDeclaration(parent) ||
1540
- ts6_1.default.isEnumDeclaration(parent) ||
1541
- ts6_1.default.isImportClause(parent) ||
1542
- ts6_1.default.isNamespaceImport(parent) ||
1543
- ts6_1.default.isImportSpecifier(parent) ||
1544
- ts6_1.default.isExportSpecifier(parent) ||
1545
- ts6_1.default.isTypeParameterDeclaration(parent)) &&
1546
- parent.name === node) {
1547
- return true;
1548
- }
1549
- if ((ts6_1.default.isPropertyDeclaration(parent) ||
1550
- ts6_1.default.isMethodDeclaration(parent)) &&
1551
- parent.name === node) {
1552
- return true;
1553
- }
1554
- return false;
1555
- };
1556
- function visitor(node) {
1557
- if (ts6_1.default.isImportDeclaration(node)) {
1558
- const moduleKey = getModuleKeyFromSpecifier(node.moduleSpecifier, sourceFile, file);
1559
- if (node.importClause?.name &&
1560
- ts6_1.default.isIdentifier(node.importClause.name)) {
1561
- const base = node.importClause.name.text.trim();
1562
- const mappedName = getMappedName(exportLookup, moduleKey, base);
1563
- if (mappedName) {
1564
- importLookup.set(base, mappedName);
1565
- exportDefaultImportNameMap.push({
1566
- base,
1567
- file,
1568
- newName: mappedName,
1569
- isEd: true,
1570
- });
1571
- const newImportClause = factory.updateImportClause(node.importClause, node.importClause.phaseModifier, factory.createIdentifier(mappedName), node.importClause.namedBindings);
1572
- return factory.updateImportDeclaration(node, node.modifiers, newImportClause, node.moduleSpecifier, node.attributes);
1573
- }
1574
- }
1575
- }
1576
- if (ts6_1.default.isCallExpression(node)) {
1577
- if (ts6_1.default.isIdentifier(node.expression)) {
1578
- const newName = resolveMappedName(node.expression.text);
1579
- if (newName) {
1580
- return factory.updateCallExpression(node, factory.createIdentifier(newName), node.typeArguments, node.arguments);
1581
- }
1582
- }
1583
- }
1584
- else if (ts6_1.default.isPropertyAccessExpression(node)) {
1585
- if (ts6_1.default.isIdentifier(node.expression)) {
1586
- const newName = resolveMappedName(node.expression.text);
1587
- if (newName) {
1588
- return factory.updatePropertyAccessExpression(node, factory.createIdentifier(newName), node.name);
1589
- }
1590
- }
1591
- }
1592
- else if (ts6_1.default.isNewExpression(node)) {
1593
- if (ts6_1.default.isIdentifier(node.expression)) {
1594
- const newName = resolveMappedName(node.expression.text);
1595
- if (newName) {
1596
- return factory.updateNewExpression(node, factory.createIdentifier(newName), node.typeArguments, node.arguments);
1597
- }
1598
- }
1599
- // for export specifier it is focus on entry file
1600
- }
1601
- else if (ts6_1.default.isExportSpecifier(node)) {
1602
- if (ts6_1.default.isIdentifier(node.name)) {
1603
- const newName = resolveMappedName(node.name.text);
1604
- if (newName) {
1605
- return factory.updateExportSpecifier(node, node.isTypeOnly, node.propertyName, factory.createIdentifier(newName));
1606
- }
1607
- }
1608
- }
1609
- else if (ts6_1.default.isIdentifier(node) && !isDeclarationName(node)) {
1610
- if (ts6_1.default.isPropertyAccessExpression(node.parent) &&
1611
- node.parent.name === node) {
1612
- return node;
1613
- }
1614
- if (ts6_1.default.isPropertyAssignment(node.parent) &&
1615
- node.parent.name === node) {
1616
- return node;
1617
- }
1618
- const newName = resolveMappedName(node.text);
1619
- if (newName) {
1620
- if (ts6_1.default.isShorthandPropertyAssignment(node.parent) &&
1621
- node.parent.name === node) {
1622
- return factory.createPropertyAssignment(factory.createIdentifier(node.text), factory.createIdentifier(newName));
1623
- }
1624
- return factory.createIdentifier(newName);
1625
- }
1626
- }
1627
- // return : visitor
1628
- return ts6_1.default.visitEachChild(node, visitor, context);
1629
- }
1630
- // return : transform
1631
- return (rootNode) => ts6_1.default.visitNode(rootNode, visitor);
1632
- };
1633
- const _content = transformBundledSource(sourceFile, compilerOptions, transformer);
1634
- // return : handler
1635
- return { file, content: _content, fileExt, ...rest };
1636
- };
1637
- }
1638
- //--
1639
- function exportDefaultLocalHandler(compilerOptions) {
1640
- return ({ file, content, fileExt, is_entry, ...rest }) => {
1641
- if (fileExt === ".json")
1642
- return { file, content, fileExt, is_entry, ...rest };
1643
- const fileName = getFileKey(file);
1644
- // const exportLookup = createNameLookup(exportDefaultExportNameMap);
1645
- // const mappedName = getMappedName(exportLookup, fileName, fileName);
1646
- const localMapping = exportDefaultExportNameMap.find((n) => n.file === fileName);
1647
- if (is_entry || !localMapping)
1648
- return { file, content, fileExt, is_entry, ...rest };
1649
- const sourceFile = createBundledSourceFile(file, content);
1650
- const transformer = (context) => {
1651
- const { factory } = context;
1652
- const { base: baseName, newName } = localMapping;
1653
- const isDeclarationName = (node) => {
1654
- const parent = node.parent;
1655
- if ((ts6_1.default.isVariableDeclaration(parent) ||
1656
- ts6_1.default.isFunctionDeclaration(parent) ||
1657
- ts6_1.default.isClassDeclaration(parent) ||
1658
- ts6_1.default.isParameter(parent) ||
1659
- ts6_1.default.isTypeAliasDeclaration(parent) ||
1660
- ts6_1.default.isInterfaceDeclaration(parent) ||
1661
- ts6_1.default.isEnumDeclaration(parent) ||
1662
- ts6_1.default.isImportClause(parent) ||
1663
- ts6_1.default.isNamespaceImport(parent) ||
1664
- ts6_1.default.isImportSpecifier(parent) ||
1665
- ts6_1.default.isExportSpecifier(parent) ||
1666
- ts6_1.default.isTypeParameterDeclaration(parent)) &&
1667
- parent.name === node) {
1668
- return true;
1669
- }
1670
- if ((ts6_1.default.isPropertyDeclaration(parent) ||
1671
- ts6_1.default.isMethodDeclaration(parent)) &&
1672
- parent.name === node) {
1673
- return true;
1674
- }
1675
- return false;
1676
- };
1677
- function visitor(node) {
1678
- if (ts6_1.default.isExportAssignment(node) &&
1679
- !node.isExportEquals &&
1680
- ts6_1.default.isIdentifier(node.expression) &&
1681
- node.expression.text === baseName) {
1682
- return factory.updateExportAssignment(node, node.modifiers, factory.createIdentifier(newName));
1683
- }
1684
- if (ts6_1.default.isCallExpression(node)) {
1685
- if (ts6_1.default.isIdentifier(node.expression) &&
1686
- node.expression.text === baseName) {
1687
- return factory.updateCallExpression(node, factory.createIdentifier(newName), node.typeArguments, node.arguments);
1688
- }
1689
- }
1690
- else if (ts6_1.default.isPropertyAccessExpression(node)) {
1691
- if (ts6_1.default.isIdentifier(node.expression) &&
1692
- node.expression.text === baseName) {
1693
- return factory.updatePropertyAccessExpression(node, factory.createIdentifier(newName), node.name);
1694
- }
1695
- }
1696
- else if (ts6_1.default.isNewExpression(node)) {
1697
- if (ts6_1.default.isIdentifier(node.expression) &&
1698
- node.expression.text === baseName) {
1699
- return factory.updateNewExpression(node, factory.createIdentifier(newName), node.typeArguments, node.arguments);
1700
- }
1701
- }
1702
- else if (ts6_1.default.isIdentifier(node) &&
1703
- node.text === baseName &&
1704
- !isDeclarationName(node)) {
1705
- if (ts6_1.default.isPropertyAccessExpression(node.parent) &&
1706
- node.parent.name === node) {
1707
- return node;
1708
- }
1709
- if (ts6_1.default.isPropertyAssignment(node.parent) &&
1710
- node.parent.name === node) {
1711
- return node;
1712
- }
1713
- if (ts6_1.default.isShorthandPropertyAssignment(node.parent) &&
1714
- node.parent.name === node) {
1715
- return factory.createPropertyAssignment(factory.createIdentifier(node.text), factory.createIdentifier(newName));
1716
- }
1717
- return factory.createIdentifier(newName);
1718
- }
1719
- if (ts6_1.default.isFunctionDeclaration(node) || ts6_1.default.isClassDeclaration(node)) {
1720
- if (node.name &&
1721
- ts6_1.default.isIdentifier(node.name) &&
1722
- node.name.text === baseName) {
1723
- if (ts6_1.default.isFunctionDeclaration(node)) {
1724
- const visitedNode = ts6_1.default.visitEachChild(node, visitor, context);
1725
- return factory.updateFunctionDeclaration(visitedNode, visitedNode.modifiers, visitedNode.asteriskToken, factory.createIdentifier(newName), visitedNode.typeParameters, visitedNode.parameters, visitedNode.type, visitedNode.body);
1726
- }
1727
- const visitedNode = ts6_1.default.visitEachChild(node, visitor, context);
1728
- return factory.updateClassDeclaration(visitedNode, visitedNode.modifiers, factory.createIdentifier(newName), visitedNode.typeParameters, visitedNode.heritageClauses, visitedNode.members);
1729
- }
1730
- }
1731
- else if (ts6_1.default.isVariableStatement(node)) {
1732
- const declarations = node.declarationList.declarations;
1733
- let changed = false;
1734
- const updatedDeclarations = declarations.map((decl) => {
1735
- if (ts6_1.default.isIdentifier(decl.name) && decl.name.text === baseName) {
1736
- changed = true;
1737
- return factory.updateVariableDeclaration(decl, factory.createIdentifier(newName), decl.exclamationToken, decl.type, decl.initializer);
1738
- }
1739
- return decl;
1740
- });
1741
- if (changed) {
1742
- return factory.updateVariableStatement(node, node.modifiers, factory.updateVariableDeclarationList(node.declarationList, updatedDeclarations));
1743
- }
1744
- }
1745
- return ts6_1.default.visitEachChild(node, visitor, context);
1746
- }
1747
- return (rootNode) => ts6_1.default.visitNode(rootNode, visitor);
1748
- };
1749
- const _content = transformBundledSource(sourceFile, compilerOptions, transformer);
1750
- return { file, content: _content, fileExt, is_entry, ...rest };
1751
- };
1752
- }
1753
- //--
1754
- function resetExportDefaultState() {
1755
- exportDefaultExportNameMap.length = 0;
1756
- exportDefaultImportNameMap.length = 0;
1757
- exportDefaultName = createExportDefaultNameGenerator();
1758
- }
1759
- const exportDefaultHandler = async (deps, compilerOptions) => {
1760
- resetExportDefaultState();
1761
- collectExportDefaultMappings(deps);
1762
- deps = deps.map(exportDefaultLocalHandler(compilerOptions));
1763
- deps = deps.map(exportDefaultImportAndUsageHandler(compilerOptions));
1764
- return deps;
1765
- };
1766
- //src/bundler/lib/remove.ts
1767
- const properties = [];
1768
- const propertiesSet = new Set();
1769
- const typeObj = {};
1770
- const typesNames = new Set();
1771
- function esmExportRemoveHandler(compilerOptions) {
1772
- return ({ file, content, ...rest }) => {
1773
- const sourceFile = createBundledSourceFile(file, content);
1774
- const transformer = (context) => {
1775
- const { factory } = context;
1776
- const visitor = (node) => {
1777
- // --- Case 1: Strip "export" modifiers ---
1778
- const inside_nameSpace = utils.checks.isInsideNamespace(node);
1779
- if (!inside_nameSpace) {
1780
- if (ts6_1.default.isFunctionDeclaration(node) ||
1781
- ts6_1.default.isClassDeclaration(node) ||
1782
- ts6_1.default.isInterfaceDeclaration(node) ||
1783
- ts6_1.default.isTypeAliasDeclaration(node) ||
1784
- ts6_1.default.isEnumDeclaration(node) ||
1785
- ts6_1.default.isVariableStatement(node)) {
1786
- const modifiers = node.modifiers?.filter((m) => m.kind !== ts6_1.default.SyntaxKind.ExportKeyword &&
1787
- m.kind !== ts6_1.default.SyntaxKind.DefaultKeyword);
1788
- if (modifiers?.length !== node.modifiers?.length) {
1789
- // If the node has an export modifier, remove it.
1790
- // If the node is a function, class, interface, type alias, enum or variable declaration,
1791
- // update the declaration by removing the export modifier.
1792
- if (ts6_1.default.isFunctionDeclaration(node)) {
1793
- return factory.updateFunctionDeclaration(node, modifiers, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body);
1794
- } // function
1795
- if (ts6_1.default.isClassDeclaration(node)) {
1796
- return factory.updateClassDeclaration(node, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members);
1797
- } // class
1798
- if (ts6_1.default.isInterfaceDeclaration(node)) {
1799
- return factory.updateInterfaceDeclaration(node, modifiers, node.name, node.typeParameters, node.heritageClauses, node.members);
1800
- } // interface
1801
- if (ts6_1.default.isTypeAliasDeclaration(node)) {
1802
- return factory.updateTypeAliasDeclaration(node, modifiers, node.name, node.typeParameters, node.type);
1803
- } // types
1804
- if (ts6_1.default.isEnumDeclaration(node)) {
1805
- return factory.updateEnumDeclaration(node, modifiers, node.name, node.members);
1806
- } //enum
1807
- if (ts6_1.default.isVariableStatement(node)) {
1808
- return factory.updateVariableStatement(node, modifiers, node.declarationList);
1809
- } // vars
1810
- } //--
1811
- } // --- Case 1
1812
- }
1813
- // --- Case 2: Remove "export { foo }" entirely ---
1814
- if (ts6_1.default.isExportDeclaration(node)) {
1815
- // If the node is an export declaration, remove it.
1816
- return factory.createEmptyStatement();
1817
- }
1818
- // --- Case 3: Handle "export default ..." ---
1819
- if (ts6_1.default.isExportAssignment(node)) {
1820
- const expr = node.expression;
1821
- // export default Foo; -> remove line
1822
- if (ts6_1.default.isIdentifier(expr)) {
1823
- return factory.createEmptyStatement();
1824
- }
1825
- }
1826
- /* ----------------------Returns for visitor function------------------------------- */
1827
- return ts6_1.default.visitEachChild(node, visitor, context);
1828
- };
1829
- /* --------------------Returns for transformer function--------------------------------- */
1830
- return (rootNode) => ts6_1.default.visitNode(rootNode, visitor);
1831
- };
1832
- /* --------------------Returns for main handler function--------------------------------- */
1833
- const _content = transformBundledSource(sourceFile, compilerOptions, transformer);
1834
- return { file, content: _content, ...rest };
1835
- };
1836
- }
1837
- function importAllRemoveHandler(removedStatements, compilerOptions) {
1838
- return ({ file, content, ...rest }) => {
1839
- const sourceFile = createBundledSourceFile(file, content);
1840
- const isCommonJsFile = utils.checks.moduleType(content, file).isCommonJs;
1841
- const transformer = (context) => {
1842
- // Pre-scan: collect names of type-only import-equals (these are namespace-type aliases)
1843
- // import type NameSpace = require("foo")
1844
- const typeOnlyImportEquals = new Set();
1845
- for (const stmt of sourceFile.statements) {
1846
- if (ts6_1.default.isImportEqualsDeclaration(stmt) && stmt.isTypeOnly) {
1847
- const moduleReference = stmt.moduleReference;
1848
- if (ts6_1.default.isExternalModuleReference(moduleReference) &&
1849
- ts6_1.default.isStringLiteral(moduleReference.expression)) {
1850
- typeOnlyImportEquals.add(stmt.name.text);
1851
- }
1852
- }
1853
- }
1854
- const { factory } = context;
1855
- const visitor = (node) => {
1856
- if (ts6_1.default.isPropertyAccessExpression(node) &&
1857
- ts6_1.default.isIdentifier(node.expression)) {
1858
- properties.push(node.expression.text);
1859
- propertiesSet.add(node.expression.text);
1860
- }
1861
- const obj = {
1862
- isNamespace: false,
1863
- isTypeOnly: false,
1864
- isTypeNamespace: false,
1865
- source: "",
1866
- importedString: undefined,
1867
- importedObject: undefined,
1868
- };
1869
- // --- Case: TypeReference with QualifiedName (collect type usage)
1870
- if (ts6_1.default.isTypeReferenceNode(node) &&
1871
- ts6_1.default.isQualifiedName(node.typeName) &&
1872
- ts6_1.default.isIdentifier(node.typeName.left) &&
1873
- ts6_1.default.isIdentifier(node.typeName.right)) {
1874
- const left = node.typeName.left.text;
1875
- const right = node.typeName.right.text;
1876
- typesNames.add(left);
1877
- if (left in typeObj) {
1878
- typeObj[left]?.push(right);
1879
- }
1880
- else {
1881
- typeObj[left] = [right];
1882
- }
1883
- // If this qualified name refers to a type-only import-equals alias, DO NOT rewrite.
1884
- // Rewriting (Foo.Bar -> Bar) was intended to support converting to named imports,
1885
- // but for type-only namespace imports we will emit `import type * as Foo from "..."`.
1886
- if (isCommonJsFile) {
1887
- if (left !== "ts" && !typeOnlyImportEquals.has(left)) {
1888
- return factory.updateTypeReferenceNode(node, factory.createIdentifier(right), undefined);
1889
- }
1890
- }
1891
- }
1892
- // ------------------------
1893
- if (ts6_1.default.isImportDeclaration(node)) {
1894
- // --- Case 1: Import declarations
1895
- const text = node.getText(sourceFile);
1896
- removedStatements.push(text);
1897
- return factory.createEmptyStatement();
1898
- }
1899
- //--- Case 2: Import equals declarations
1900
- if (ts6_1.default.isImportEqualsDeclaration(node)) {
1901
- const name = node.name.text;
1902
- const moduleReference = node.moduleReference;
1903
- if (node.isTypeOnly) {
1904
- obj.isTypeOnly = true;
1905
- }
1906
- obj.importedString = name;
1907
- if (!obj.isTypeOnly) {
1908
- if (propertiesSet.has(name)) {
1909
- obj.isNamespace = true;
1910
- }
1911
- }
1912
- if (ts6_1.default.isExternalModuleReference(moduleReference) &&
1913
- ts6_1.default.isStringLiteral(moduleReference.expression)) {
1914
- obj.source = moduleReference.expression.text;
1915
- }
1916
- let t;
1917
- if (obj.importedString && !obj.importedObject) {
1918
- if (obj.isTypeOnly) {
1919
- // If this import-equals was a type-only namespace alias, emit a namespace type import
1920
- if (typeOnlyImportEquals.has(obj.importedString)) {
1921
- t = `import type * as ${obj.importedString} from "${obj.source}";`;
1922
- }
1923
- else {
1924
- // otherwise try to emit a named/default type import (existing behavior)
1925
- if (typesNames.has(obj.importedString)) {
1926
- t = `import type { ${typeObj[obj.importedString]?.join(",")} } from "${obj.source}";`;
1927
- }
1928
- else {
1929
- t = `import type ${obj.importedString} from "${obj.source}";`;
1930
- }
1931
- }
1932
- }
1933
- else {
1934
- if (obj.isNamespace &&
1935
- obj.source &&
1936
- obj.source !== "typescript") {
1937
- t = `import * as ${obj.importedString} from "${obj.source}";`;
1938
- }
1939
- else {
1940
- t = `import ${obj.importedString} from "${obj.source}";`;
1941
- }
1942
- }
1943
- }
1944
- if (!obj.importedString && obj.importedObject) {
1945
- t = `import { ${obj.importedObject.join(", ")} } from "${obj.source}";`;
1946
- }
1947
- // removed
1948
- if (t) {
1949
- removedStatements.push(t);
1950
- return factory.createEmptyStatement();
1951
- }
1952
- }
1953
- // --- Case 3: Require imports
1954
- if (ts6_1.default.isVariableStatement(node)) {
1955
- const decls = node.declarationList.declarations;
1956
- if (decls.length === 1) {
1957
- const decl = decls[0];
1958
- if (decl.initializer &&
1959
- ts6_1.default.isCallExpression(decl.initializer) &&
1960
- ts6_1.default.isIdentifier(decl.initializer.expression) &&
1961
- decl.initializer.expression.escapedText === "require") {
1962
- // imported from
1963
- const arg = decl.initializer.arguments[0];
1964
- if (ts6_1.default.isStringLiteral(arg)) {
1965
- obj.source = arg.text;
1966
- }
1967
- if (ts6_1.default.isIdentifier(decl.name)) {
1968
- const _n = decl.name.text;
1969
- obj.importedString = _n;
1970
- if (propertiesSet.has(_n)) {
1971
- obj.isNamespace = true;
1972
- }
1973
- }
1974
- else if (ts6_1.default.isObjectBindingPattern(decl.name)) {
1975
- const _names = [];
1976
- for (const ele of decl.name.elements) {
1977
- if (ts6_1.default.isIdentifier(ele.name)) {
1978
- _names.push(ele.name.text);
1979
- }
1980
- }
1981
- if (_names.length > 0) {
1982
- obj.importedObject = _names;
1983
- }
1984
- }
1985
- let tt;
1986
- if (obj.importedString && !obj.importedObject) {
1987
- if (obj.isNamespace) {
1988
- tt = `import * as ${obj.importedString} from "${obj.source}";`;
1989
- }
1990
- else {
1991
- tt = `import ${obj.importedString} from "${obj.source}";`;
1992
- }
1993
- }
1994
- if (!obj.importedString && obj.importedObject) {
1995
- tt = `import { ${obj.importedObject.join(", ")} } from "${obj.source}";`;
1996
- }
1997
- if (tt) {
1998
- removedStatements.push(tt);
1999
- return factory.createEmptyStatement();
2000
- }
2001
- }
2002
- }
2003
- }
2004
- /* ----------------------Returns for visitor function------------------------------- */
2005
- return ts6_1.default.visitEachChild(node, visitor, context);
2006
- };
2007
- /* --------------------Returns for transformer function--------------------------------- */
2008
- return (rootNode) => ts6_1.default.visitNode(rootNode, visitor);
2009
- };
2010
- /* --------------------Returns for main handler function--------------------------------- */
2011
- const _content = transformBundledSource(sourceFile, compilerOptions, transformer);
2012
- return { file, content: _content, ...rest };
2013
- };
2014
- }
2015
- const removeHandlers = async (removedStatements, compilerOptions) => {
2016
- const resolved = utils.promises.resolve([
2017
- [importAllRemoveHandler, removedStatements, compilerOptions],
2018
- [esmExportRemoveHandler, compilerOptions],
2019
- ]);
2020
- return await resolved.series();
2021
- };
2022
- //src/bundler/lib/resolveJSON.ts
2023
- const jsonPrefix = "__jsonModule__";
2024
- const jsonModuleExportNameMap = [];
2025
- const jsonModuleImportNameMap = [];
2026
- const toIdentifier = (input) => {
2027
- const cleaned = input.replace(/[^A-Za-z0-9_$]/g, "_");
2028
- const startsValid = /^[A-Za-z_$]/.test(cleaned);
2029
- return `${jsonPrefix}${startsValid ? cleaned : `_${cleaned}`}`;
2030
- };
2031
- const toJsonModuleCode = (varName, content, file) => {
2032
- let parsed;
2033
- try {
2034
- parsed = JSON.parse(content);
2035
- }
2036
- catch {
2037
- throw new Error(`Invalid JSON syntax in dependency file: ${file}`);
2038
- }
2039
- const jsonObject = JSON.stringify(parsed);
2040
- return `const ${varName} = ${jsonObject};\nexport default ${varName}`;
2041
- };
2042
- const resolveJSONHandler = async (deps) => {
2043
- const scopedNameCount = new Map();
2044
- const nextDeps = deps.map((dep) => {
2045
- if (dep.moduleType !== "json" || dep.fileExt !== ".json") {
2046
- return dep;
2047
- }
2048
- const fileName = node_path_1.default.basename(dep.file).split(".")[0];
2049
- const fileKey = getFileKey(dep.file);
2050
- const keyName = toIdentifier(fileKey);
2051
- const count = scopedNameCount.get(keyName) ?? 0;
2052
- const jsonVarName = count === 0 ? keyName : `${keyName}_${count + 1}`;
2053
- scopedNameCount.set(keyName, count + 1);
2054
- jsonModuleExportNameMap.push({
2055
- base: jsonVarName,
2056
- file: fileName,
2057
- newName: jsonVarName,
2058
- isEd: true,
2059
- });
2060
- return {
2061
- ...dep,
2062
- content: toJsonModuleCode(jsonVarName, dep.content, dep.file),
2063
- moduleType: "esm",
2064
- };
2065
- });
2066
- return nextDeps;
2067
- };
2068
- //--
2069
- function jsonModuleImportHandler(compilerOptions) {
2070
- return ({ file, content, fileExt, ...rest }) => {
2071
- const sourceFile = createBundledSourceFile(file, content);
2072
- const transformer = (context) => {
2073
- const { factory } = context;
2074
- function visitor(node) {
2075
- if (ts6_1.default.isImportDeclaration(node)) {
2076
- const fileName = node.moduleSpecifier.getText(sourceFile);
2077
- const _name = node_path_1.default.basename(fileName).split(".")[0].trim();
2078
- // check only import default expression
2079
- if (node.importClause?.name &&
2080
- ts6_1.default.isIdentifier(node.importClause.name)) {
2081
- const base = node.importClause.name.text.trim();
2082
- const mapping = jsonModuleExportNameMap.find((v) => v.file === _name);
2083
- if (mapping) {
2084
- jsonModuleImportNameMap.push({
2085
- base,
2086
- file,
2087
- newName: mapping.newName,
2088
- isEd: true,
2089
- });
2090
- const newImportClause = factory.updateImportClause(node.importClause, node.importClause.phaseModifier, factory.createIdentifier(mapping.newName), node.importClause.namedBindings);
2091
- return factory.updateImportDeclaration(node, node.modifiers, newImportClause, node.moduleSpecifier, node.attributes);
2092
- }
2093
- }
2094
- }
2095
- return ts6_1.default.visitEachChild(node, visitor, context);
2096
- }
2097
- return (rootNode) => ts6_1.default.visitNode(rootNode, visitor);
2098
- };
2099
- const _content = transformBundledSource(sourceFile, compilerOptions, transformer);
2100
- return { file, content: _content, fileExt, ...rest };
2101
- };
2102
- }
2103
- //--
2104
- function jsonModuleCallExpressionHandler(compilerOptions) {
2105
- return ({ file, content, fileExt, ...rest }) => {
2106
- const sourceFile = createBundledSourceFile(file, content);
2107
- const transformer = (context) => {
2108
- const { factory } = context;
2109
- function visitor(node) {
2110
- if (ts6_1.default.isCallExpression(node)) {
2111
- if (ts6_1.default.isIdentifier(node.expression)) {
2112
- const base = node.expression.text;
2113
- const mapping = jsonModuleImportNameMap.find((m) => m.base === base && m.file === file);
2114
- if (mapping) {
2115
- return factory.updateCallExpression(node, factory.createIdentifier(mapping.newName), node.typeArguments, node.arguments);
2116
- }
2117
- }
2118
- }
2119
- else if (ts6_1.default.isPropertyAccessExpression(node)) {
2120
- if (ts6_1.default.isIdentifier(node.expression)) {
2121
- const base = node.expression.text;
2122
- const mapping = jsonModuleImportNameMap.find((m) => m.base === base && m.file === file);
2123
- if (mapping) {
2124
- return factory.updatePropertyAccessExpression(node, factory.createIdentifier(mapping.newName), node.name);
2125
- }
2126
- }
2127
- }
2128
- else if (ts6_1.default.isNewExpression(node)) {
2129
- if (ts6_1.default.isIdentifier(node.expression)) {
2130
- const base = node.expression.text;
2131
- const mapping = jsonModuleImportNameMap.find((m) => m.base === base && m.file === file);
2132
- if (mapping) {
2133
- return factory.updateNewExpression(node, factory.createIdentifier(mapping.newName), node.typeArguments, node.arguments);
2134
- }
2135
- }
2136
- // for export specifier it is focus on entry file
2137
- }
2138
- else if (ts6_1.default.isExportSpecifier(node)) {
2139
- if (ts6_1.default.isIdentifier(node.name)) {
2140
- const base = node.name.text;
2141
- const mapping = jsonModuleImportNameMap.find((m) => m.base === base && m.file === file);
2142
- if (mapping) {
2143
- return factory.updateExportSpecifier(node, node.isTypeOnly, node.propertyName, factory.createIdentifier(mapping.newName));
2144
- }
2145
- }
2146
- }
2147
- return ts6_1.default.visitEachChild(node, visitor, context);
2148
- }
2149
- return (rootNode) => ts6_1.default.visitNode(rootNode, visitor);
2150
- };
2151
- const _content = transformBundledSource(sourceFile, compilerOptions, transformer);
2152
- return { file, content: _content, fileExt, ...rest };
2153
- };
2154
- }
2155
- //--
2156
- async function jsonModuleHandlers(deps, compilerOptions) {
2157
- deps = await resolveJSONHandler(deps);
2158
- deps = deps.map((dep) => jsonModuleImportHandler(compilerOptions)(dep));
2159
- deps = deps.map((dep) => jsonModuleCallExpressionHandler(compilerOptions)(dep));
2160
- return deps;
2161
- }
2162
- function collectBindingNames(name, out) {
2163
- if (ts6_1.default.isIdentifier(name))
2164
- out.push(name.text);
2165
- else if (ts6_1.default.isObjectBindingPattern(name) ||
2166
- ts6_1.default.isArrayBindingPattern(name)) {
2167
- name.elements.forEach((el) => {
2168
- if (ts6_1.default.isBindingElement(el) && el.name)
2169
- collectBindingNames(el.name, out);
2170
- });
2171
- }
2172
- }
2173
- /**
2174
- * Clear unused top-level declarations from a TypeScript source string.
2175
- * - Removes only unused named import specifiers.
2176
- * - Removes entire import declarations when an unused default or namespace import is present.
2177
- * - Removes function and class declarations when their name is unused.
2178
- * - Removes entire variable statements when none of the declared identifiers are used.
2179
- *
2180
- * Limitations: this works on a single-file basis and does not analyze cross-file usages.
2181
- */
2182
- function susee__anonymous__unusedCode_2(content, file, compilerOptions, options = { treatExportsAsUsed: true }) {
2183
- const sourceFile = createBundledSourceFile(file, content);
2184
- const defined = new Map();
2185
- const used = new Set();
2186
- const markDefined = (name, exported = false) => {
2187
- const prev = defined.get(name);
2188
- defined.set(name, { exported: !!prev?.exported || exported });
2189
- };
2190
- // First pass: collect defined names (imports, vars, funcs, classes) and used identifiers
2191
- const collect = (node) => {
2192
- // Definitions
2193
- if (ts6_1.default.isImportDeclaration(node) && node.importClause) {
2194
- const ic = node.importClause;
2195
- if (ic.name && ts6_1.default.isIdentifier(ic.name))
2196
- markDefined(ic.name.text, false);
2197
- if (ic.namedBindings) {
2198
- if (ts6_1.default.isNamedImports(ic.namedBindings)) {
2199
- ic.namedBindings.elements.forEach((ele) => {
2200
- if (ts6_1.default.isImportSpecifier(ele) && ts6_1.default.isIdentifier(ele.name))
2201
- markDefined(ele.name.text, false);
2202
- });
2203
- }
2204
- else if (ts6_1.default.isNamespaceImport(ic.namedBindings) &&
2205
- ts6_1.default.isIdentifier(ic.namedBindings.name)) {
2206
- markDefined(ic.namedBindings.name.text, false);
2207
- }
2208
- }
2209
- }
2210
- else if (ts6_1.default.isImportEqualsDeclaration(node) &&
2211
- ts6_1.default.isIdentifier(node.name)) {
2212
- markDefined(node.name.text, false);
2213
- }
2214
- else if (ts6_1.default.isVariableStatement(node)) {
2215
- const exported = node.modifiers?.some((m) => m.kind === ts6_1.default.SyntaxKind.ExportKeyword) ??
2216
- false;
2217
- node.declarationList.declarations.forEach((d) => {
2218
- collectBindingNames(d.name, []);
2219
- const names = [];
2220
- collectBindingNames(d.name, names);
2221
- names.forEach((n) => markDefined(n, exported));
2222
- });
2223
- }
2224
- else if (ts6_1.default.isFunctionDeclaration(node) &&
2225
- node.name &&
2226
- ts6_1.default.isIdentifier(node.name)) {
2227
- const exported = node.modifiers?.some((m) => m.kind === ts6_1.default.SyntaxKind.ExportKeyword) ??
2228
- false;
2229
- markDefined(node.name.text, exported);
2230
- }
2231
- else if (ts6_1.default.isClassDeclaration(node) &&
2232
- node.name &&
2233
- ts6_1.default.isIdentifier(node.name)) {
2234
- const exported = node.modifiers?.some((m) => m.kind === ts6_1.default.SyntaxKind.ExportKeyword) ??
2235
- false;
2236
- markDefined(node.name.text, exported);
2237
- }
2238
- // Usage: any identifier that is not a declaration name is considered a use
2239
- if (ts6_1.default.isIdentifier(node)) {
2240
- const parent = node.parent;
2241
- const isDeclarationName = (ts6_1.default.isVariableDeclaration(parent) && parent.name === node) ||
2242
- (ts6_1.default.isFunctionDeclaration(parent) && parent.name === node) ||
2243
- (ts6_1.default.isClassDeclaration(parent) && parent.name === node) ||
2244
- (ts6_1.default.isImportClause(parent) && parent.name === node) ||
2245
- (ts6_1.default.isImportSpecifier(parent) && parent.name === node) ||
2246
- (ts6_1.default.isNamespaceImport(parent) && parent.name === node) ||
2247
- (ts6_1.default.isBindingElement(parent) && parent.name === node) ||
2248
- (ts6_1.default.isParameter(parent) && parent.name === node);
2249
- if (!isDeclarationName)
2250
- used.add(node.text);
2251
- }
2252
- ts6_1.default.forEachChild(node, collect);
2253
- };
2254
- collect(sourceFile);
2255
- // Determine unused names
2256
- const unused = new Set();
2257
- defined.forEach((meta, name) => {
2258
- if (used.has(name))
2259
- return;
2260
- if (options.treatExportsAsUsed && meta.exported)
2261
- return;
2262
- unused.add(name);
2263
- });
2264
- // Transformer: remove nodes that are unused according to rules
2265
- const transformer = (context) => {
2266
- const visitor = (node) => {
2267
- // ImportDeclaration:
2268
- // - remove whole statement when default/namespace import is unused
2269
- // - otherwise remove only unused named specifiers
2270
- if (ts6_1.default.isImportDeclaration(node) && node.importClause) {
2271
- const ic = node.importClause;
2272
- const defaultName = ic.name && ts6_1.default.isIdentifier(ic.name) ? ic.name.text : undefined;
2273
- let namespaceName;
2274
- const namedElements = [];
2275
- if (ic.namedBindings) {
2276
- if (ts6_1.default.isNamedImports(ic.namedBindings)) {
2277
- ic.namedBindings.elements.forEach((ele) => {
2278
- if (ts6_1.default.isImportSpecifier(ele) && ts6_1.default.isIdentifier(ele.name))
2279
- namedElements.push(ele);
2280
- });
2281
- }
2282
- else if (ts6_1.default.isNamespaceImport(ic.namedBindings) &&
2283
- ts6_1.default.isIdentifier(ic.namedBindings.name)) {
2284
- namespaceName = ic.namedBindings.name.text;
2285
- }
2286
- }
2287
- const defaultUsed = defaultName ? !unused.has(defaultName) : false;
2288
- const namespaceUsed = namespaceName
2289
- ? !unused.has(namespaceName)
2290
- : false;
2291
- const keptNamed = namedElements.filter((ele) => !unused.has(ele.name.text));
2292
- if ((defaultName && !defaultUsed) ||
2293
- (namespaceName && !namespaceUsed)) {
2294
- return ts6_1.default.factory.createNotEmittedStatement(node);
2295
- }
2296
- if (namedElements.length > 0 &&
2297
- keptNamed.length === 0 &&
2298
- !defaultName) {
2299
- return ts6_1.default.factory.createNotEmittedStatement(node);
2300
- }
2301
- if (keptNamed.length !== namedElements.length) {
2302
- const newImportClause = ts6_1.default.factory.createImportClause(false, defaultName ? ts6_1.default.factory.createIdentifier(defaultName) : undefined, ts6_1.default.factory.createNamedImports(keptNamed));
2303
- return ts6_1.default.factory.updateImportDeclaration(node, node.modifiers, newImportClause, node.moduleSpecifier,
2304
- // biome-ignore lint/suspicious/noExplicitAny : ts
2305
- node.assertClause);
2306
- }
2307
- return node;
2308
- }
2309
- // FunctionDeclaration / ClassDeclaration: remove if named and unused
2310
- if ((ts6_1.default.isFunctionDeclaration(node) || ts6_1.default.isClassDeclaration(node)) &&
2311
- node.name &&
2312
- ts6_1.default.isIdentifier(node.name)) {
2313
- if (unused.has(node.name.text))
2314
- return ts6_1.default.factory.createNotEmittedStatement(node);
2315
- return node;
2316
- }
2317
- // VariableStatement: remove whole statement only if none of declared names are used
2318
- if (ts6_1.default.isVariableStatement(node)) {
2319
- const names = [];
2320
- node.declarationList.declarations.forEach((d) => collectBindingNames(d.name, names));
2321
- const anyUsed = names.some((n) => !unused.has(n));
2322
- if (!anyUsed)
2323
- return ts6_1.default.factory.createNotEmittedStatement(node);
2324
- return node;
2325
- }
2326
- return ts6_1.default.visitEachChild(node, visitor, context);
2327
- };
2328
- return (root) => ts6_1.default.visitNode(root, visitor);
2329
- };
2330
- const output = transformBundledSource(sourceFile, compilerOptions, transformer);
2331
- return output;
2332
- }
2333
- //src/bundler/index.ts
2334
- const logBundlerPhase = (entry, phase, start) => {
2335
- logProfilePhase(`bundler:${node_path_1.default.basename(entry)}`, phase, start);
2336
- };
2337
- async function bundler(entry, plugins = [], warning = false) {
2338
- const bundlerStart = node_process_1.default.hrtime.bigint();
2339
- let removedStatements = [];
2340
- const compilerOptions = ts6_1.default.getDefaultCompilerOptions();
2341
- let phaseStart = node_process_1.default.hrtime.bigint();
2342
- const tree = await generateDependencies(entry, createBundledSourceFile);
2343
- logBundlerPhase(entry, "generateDependencies", phaseStart);
2344
- // check for warning from generated dependencies graph
2345
- if (warning && tree.warns.length > 0) {
2346
- console.warn(tree.warns.join("\n"));
2347
- node_process_1.default.exit(1);
2348
- }
2349
- let depsFiles = tree.depFiles;
2350
- // 1. Resolve JSON Modules
2351
- if (isJSON(tree)) {
2352
- phaseStart = node_process_1.default.hrtime.bigint();
2353
- depsFiles = await jsonModuleHandlers(depsFiles, compilerOptions);
2354
- logBundlerPhase(entry, "resolveJSON", phaseStart);
2355
- }
2356
- // 2. Parse Dependency Plugins
2357
- if (plugins.length > 0) {
2358
- for (const plugin of plugins) {
2359
- const _plugin = typeof plugin === "function" ? plugin() : plugin;
2360
- if (_plugin.type === "dependency") {
2361
- phaseStart = node_process_1.default.hrtime.bigint();
2362
- if (_plugin.async) {
2363
- depsFiles = await _plugin.func(depsFiles, compilerOptions);
2364
- }
2365
- else {
2366
- depsFiles = _plugin.func(depsFiles, compilerOptions);
2367
- }
2368
- logBundlerPhase(entry, `dependencyPlugin:${_plugin.name ?? "anonymous"}`, phaseStart);
2369
- }
2370
- }
2371
- }
2372
- // 3. Check for commonjs modules
2373
- const isCommonjs = depsFiles.find((file) => file.moduleType === "cjs");
2374
- if (isCommonjs) {
2375
- console.error(`Bundler found commonjs module/modules in dependencies tree.Please use "@suseejs/commonjs-plugin" to solve it.`);
2376
- node_process_1.default.exit(1);
2377
- }
2378
- // 4. Handling Export Default
2379
- phaseStart = node_process_1.default.hrtime.bigint();
2380
- depsFiles = await exportDefaultHandler(depsFiles, compilerOptions);
2381
- logBundlerPhase(entry, "exportDefault", phaseStart);
2382
- // 5. Handling Anonymous Imports/Exports
2383
- phaseStart = node_process_1.default.hrtime.bigint();
2384
- depsFiles = await anonymousHandler(depsFiles, compilerOptions);
2385
- logBundlerPhase(entry, "anonymous", phaseStart);
2386
- // 6. Duplicate top-level declarations are validated during dependency generation.
2387
- // Susee fails fast and asks callers to fix conflicting names in source files.
2388
- // 7. Handling Remove Imports/Exports
2389
- phaseStart = node_process_1.default.hrtime.bigint();
2390
- const removed = await removeHandlers(removedStatements, compilerOptions);
2391
- // 7.1 Remove Imports
2392
- depsFiles = depsFiles.map(removed[0]);
2393
- // 7.2 Remove Exports
2394
- // Remove Exports from dependency files only
2395
- // not remove exports from entry file
2396
- const deps_files = depsFiles.slice(0, -1).map(removed[1]);
2397
- const mainFile = depsFiles.slice(-1);
2398
- logBundlerPhase(entry, "removeImportsExports", phaseStart);
2399
- // 8. Handling Imported Statements
2400
- // filter removed statements , that not from local like `./` or `../`
2401
- phaseStart = node_process_1.default.hrtime.bigint();
2402
- const regexp = /^\s*import(?:[\s\S]*?\sfrom\s+)?["']((?!\.{1,2}\/)[^"']+)["']/;
2403
- removedStatements = removedStatements.filter((i) => regexp.test(i));
2404
- removedStatements = utils.gen.mergeImportsStatement(removedStatements);
2405
- const importStatements = removedStatements.join("\n").trim();
2406
- logBundlerPhase(entry, "mergeImports", phaseStart);
2407
- // 9. Merge all content from dependencies tree
2408
- // 9.1 Merge dependency files content.
2409
- phaseStart = node_process_1.default.hrtime.bigint();
2410
- const depFilesContent = deps_files
2411
- .map((i) => {
2412
- const file = `//${node_path_1.default.relative(node_process_1.default.cwd(), i.file)}`;
2413
- return `${file}\n${i.content}`;
2414
- })
2415
- .join("\n")
2416
- .trim();
2417
- // 9.2 Create entry content
2418
- const mainFileContent = mainFile
2419
- .map((i) => {
2420
- const file = `//${node_path_1.default.relative(node_process_1.default.cwd(), i.file)}`;
2421
- return `${file}\n${i.content}`;
2422
- })
2423
- .join("\n")
2424
- .trim();
2425
- // 9.3 Merge all into one
2426
- // text join order is important here
2427
- // make sure all imports are at the top of file
2428
- let content = `${importStatements}\n${depFilesContent}\n${mainFileContent}`;
2429
- // some additional steps
2430
- // remove ";" that are remain after removing imports
2431
- content = content.replace(/^s*;\s*$/gm, "").trim();
2432
- logBundlerPhase(entry, "mergeContent", phaseStart);
2433
- // clean unused code
2434
- phaseStart = node_process_1.default.hrtime.bigint();
2435
- content = susee__anonymous__unusedCode_2(content, tree.entry, compilerOptions);
2436
- logBundlerPhase(entry, "cleanUnusedCode", phaseStart);
2437
- // 10. Call pre-process plugins
2438
- if (plugins.length > 0) {
2439
- for (const plugin of plugins) {
2440
- const _plugin = typeof plugin === "function" ? plugin() : plugin;
2441
- if (_plugin.type === "pre-process") {
2442
- phaseStart = node_process_1.default.hrtime.bigint();
2443
- if (_plugin.async) {
2444
- content = await _plugin.func(content, tree.entry);
2445
- }
2446
- else {
2447
- content = _plugin.func(content, tree.entry);
2448
- }
2449
- logBundlerPhase(entry, `preProcessPlugin:${_plugin.name ?? "anonymous"}`, phaseStart);
2450
- }
2451
- }
2452
- }
2453
- logBundlerPhase(entry, "total", bundlerStart);
2454
- // Returns
2455
- return content;
2456
- }
2457
- async function bundle(entry) {
2458
- return await bundler(entry);
2459
- }
2460
- //package.json
2461
- const __jsonModule__package = { "name": "susee", "version": "1.6.2", "description": "TypeScript-first bundler for library packages", "type": "module", "main": "dist/index.cjs", "types": "dist/index.d.cts", "module": "dist/index.mjs", "exports": { ".": { "import": { "types": "./dist/index.d.mts", "default": "./dist/index.mjs" }, "require": { "types": "./dist/index.d.cts", "default": "./dist/index.cjs" } } }, "bin": { "susee": "bin/susee" }, "scripts": { "build": "tsx build.ts", "lint": "biome lint ./src ./__tests__ --write", "fmt": "biome format --write", "test": "tsx --test", "hooks:install": "bash scripts/install-hooks.sh", "commit": "bash scripts/commit.sh", "v:patch": "npm version patch --no-git-tag-version", "v:minor": "npm version minor --no-git-tag-version", "v:major": "npm version major --no-git-tag-version" }, "keywords": ["bundler", "susee", "suseejs"], "author": "Pho Thin Mg <phothinmg@disroot.org> (https://phothinmg.github.io/)", "license": "Apache-2.0", "files": ["package.json", "README.md", "LICENSE", "dist/**/*", "bin/**/*"], "publishConfig": { "provenance": true, "access": "public" }, "repository": { "url": "git+https://github.com/phothinmg/susee.git", "type": "git" }, "homepage": "https://susee.js.org/", "bugs": { "url": "https://github.com/phothinmg/susee/issues" }, "dependencies": { "@suseejs/color": "^0.0.9", "@suseejs/ts6": "^1.0.0" }, "devDependencies": { "@biomejs/biome": "^2.4.12", "@suseejs/banner-text-plugin": "^0.0.9", "@suseejs/type": "^0.0.9", "@types/node": "^25.6.0", "tsx": "^4.23.1", "typescript": "^7.0.2" }, "allowScripts": { "esbuild@0.28.1": true }, "workspaces": ["susee-docs"] };
2462
- /**
2463
- * Finds the path of the susee.config file if it exists.
2464
- * It checks for the existence of "susee.config.ts", "susee.config.js", and "susee.config.mjs" in the current working directory.
2465
- * The first file found is returned.
2466
- * @returns {string | undefined} - path to the susee.config file or undefined if it does not exist.
2467
- */
2468
- const getSuseeConfigPath = () => {
2469
- const fileNames = ["susee.config.ts", "susee.config.js", "susee.config.mjs"];
2470
- let configFile;
2471
- for (const file of fileNames) {
2472
- const _file = ts6_1.default.sys.resolvePath(file);
2473
- if (ts6_1.default.sys.fileExists(_file)) {
2474
- configFile = _file;
2475
- break;
2476
- }
2477
- }
2478
- return configFile;
2479
- };
2480
- /**
2481
- * Checks if the given entries have at least one entry and if there are any duplicate export paths.
2482
- * If there are no entries, it will exit with code 1 and print an error message.
2483
- * If there are any duplicate export paths, it will exit with code 1 and print an error message.
2484
- * It will also check if each entry file exists, if not, it will exit with code 1 and print an error message.
2485
- * @param {EntryPoint[]} entries - array of entry points
2486
- */
2487
- function checkEntries(entries) {
2488
- if (entries.length < 1) {
2489
- console.error(color_1.default.magenta(`No entry found in susee.config file or build options, at least one entry required`));
2490
- ts6_1.default.sys.exit(1);
2491
- }
2492
- const objectStore = {};
2493
- const duplicateExportPaths = [];
2494
- for (const obj of entries) {
2495
- const value = obj.exportPath;
2496
- if (objectStore[value]) {
2497
- duplicateExportPaths.push(`"${value}"`);
2498
- }
2499
- else {
2500
- objectStore[value] = true;
2501
- }
2502
- }
2503
- if (duplicateExportPaths.length > 0) {
2504
- console.error(color_1.default.magenta(`Duplicate export paths/path (${duplicateExportPaths.join(",")}) found in your susee.config file or build options , that will error for bundled output`));
2505
- ts6_1.default.sys.exit(1);
2506
- }
2507
- for (const obj of entries) {
2508
- if (!ts6_1.default.sys.fileExists(ts6_1.default.sys.resolvePath(obj.entry))) {
2509
- console.error(color_1.default.magenta(`Entry file ${obj.entry} dose not exists.`));
2510
- ts6_1.default.sys.exit(1);
2511
- }
2512
- }
2513
- }
2514
- /**
2515
- * Generates normalized build options from the user config.
2516
- * It validates entry points, applies default values, removes duplicate formats,
2517
- * resolves the output directory for each export path, and keeps duplicate declaration handling fail-fast.
2518
- * @param {SuSeeConfig} config - raw susee configuration object.
2519
- * @returns {BuildOptions} normalized build options for the compiler.
2520
- */
2521
- function generateBuildOptions(config) {
2522
- const outDir = config.outDir ?? "dist";
2523
- const points = [];
2524
- checkEntries(config.entryPoints);
2525
- for (const ent of config.entryPoints) {
2526
- const entry = ent.entry;
2527
- const exportPath = ent.exportPath;
2528
- const format = ent.format
2529
- ? [...new Set(ent.format)]
2530
- : ["esm"];
2531
- const warning = ent.warning ?? false;
2532
- const plugins = ent.plugins ?? [];
2533
- const tsconfigFilePath = ent.tsconfigFilePath ?? undefined;
2534
- const outputDirectoryPath = ent.exportPath === "." ? outDir : `${outDir}${ent.exportPath.slice(1)}`;
2535
- points.push({
2536
- entry,
2537
- exportPath,
2538
- format,
2539
- plugins,
2540
- warning,
2541
- outputDirectoryPath,
2542
- tsconfigFilePath,
2543
- });
2544
- }
2545
- return {
2546
- buildEntryPoints: points,
2547
- updatePackage: config.allowUpdatePackageJson ?? false,
2548
- outDir,
2549
- };
2550
- }
2551
- /**
2552
- * Loads the susee config file from the current working directory and converts it into build options.
2553
- * If no supported config file is found, it returns `undefined`.
2554
- * @returns {Promise<BuildOptions | undefined>} normalized build options or undefined when no config file exists.
2555
- */
2556
- async function finalSuseeConfig() {
2557
- const configPath = getSuseeConfigPath();
2558
- if (configPath) {
2559
- const _default = await Promise.resolve(`${configPath}`).then(s => __importStar(require(s)));
2560
- const config = _default.default;
2561
- return generateBuildOptions(config);
2562
- }
2563
- }
2564
- /**
2565
- * Normalizes TypeScript compiler options when JSX compilation is requested.
2566
- *
2567
- * For JSX input, this validates that the source imports either React runtime
2568
- * modules or the configured `jsxImportSource` runtime package. When validation
2569
- * passes, it enables DOM libs and defaults `jsx` to `ReactJSX` if unset.
2570
- *
2571
- * @param {string} sourceCode - Source text to inspect for JSX runtime imports.
2572
- * @param {ts6.CompilerOptions} compilerOptions - User-provided compiler options.
2573
- * @param {boolean} isJsx - Whether JSX mode is enabled for this compilation.
2574
- * @returns {ts6.CompilerOptions} Compiler options to pass into program creation.
2575
- */
2576
- function jsxCompilerOptions(sourceCode, compilerOptions, isJsx) {
2577
- if (!isJsx) {
2578
- return compilerOptions;
2579
- }
2580
- const reactRegexp = /import\s+(?:.*?)\s+from\s+(?:"react"|"react\/.*"|"react-dom\/.*"|"react-dom")/gm;
2581
- if (!reactRegexp.test(sourceCode)) {
2582
- if (!compilerOptions.jsxImportSource) {
2583
- console.error("[jsx-runtime-error]:\nJSX syntax found in bundled code,but its not react runtime,you need to be set jsxImportSource in tsconfig.");
2584
- node_process_1.default.exit(1);
2585
- }
2586
- const txt = compilerOptions.jsxImportSource;
2587
- const pattern = `import\\s+(?:.*?)\\s+from\\s+("${txt}"|"${txt}\\/.*")`;
2588
- const re = new RegExp(pattern, "gm");
2589
- if (!re.test(sourceCode)) {
2590
- console.error("[jsx-runtime-mismatch-error]:\nJSX syntax found in bundled code,but its not react runtime and jsx-runtime from bundled code and jsxImportSource from tsconfig are mismatched.`");
2591
- node_process_1.default.exit(1);
2592
- }
2593
- }
2594
- const { jsx, lib, ...rest } = compilerOptions;
2595
- const _jsx = jsx ?? ts6_1.default.JsxEmit.ReactJSX;
2596
- return {
2597
- lib: ["dom", "dom.iterable", "esnext"],
2598
- jsx: _jsx,
2599
- ...rest,
2600
- };
2601
- }
2602
- /**
2603
- * Creates a ts.CompilerHost that can be used with the typescript compiler.
2604
- * This host is designed to be used with in-memory compilation and will
2605
- * return the source file for the given fileName and will write all output
2606
- * files to the createdFiles object.
2607
- * @param {string} sourceCode - the source code to compile
2608
- * @param {string} fileName - the name of the file to compile
2609
- * @returns {{createdFiles: Record<string, string>, host: ts.CompilerHost}}
2610
- */
2611
- function createHost(sourceCode, fileName) {
2612
- const createdFiles = {};
2613
- const host = {
2614
- getSourceFile: (file, languageVersion) => {
2615
- if (file === fileName) {
2616
- return ts6_1.default.createSourceFile(file, sourceCode, languageVersion);
2617
- }
2618
- return undefined;
2619
- },
2620
- writeFile: (fileName, contents) => {
2621
- createdFiles[fileName] = contents;
2622
- },
2623
- getDefaultLibFileName: (options) => ts6_1.default.getDefaultLibFilePath(options),
2624
- getCurrentDirectory: () => "",
2625
- getDirectories: () => [],
2626
- fileExists: (file) => file === fileName,
2627
- readFile: (file) => (file === fileName ? sourceCode : undefined),
2628
- getCanonicalFileName: (file) => file,
2629
- useCaseSensitiveFileNames: () => true,
2630
- getNewLine: () => "\n",
2631
- };
2632
- return { createdFiles, host };
2633
- }
2634
- function suseeCompiler({ sourceCode, fileName, compilerOptions, isJsx = false, }) {
2635
- compilerOptions = jsxCompilerOptions(sourceCode, compilerOptions, isJsx);
2636
- // create host
2637
- const _host = createHost(sourceCode, fileName);
2638
- const createdFiles = _host.createdFiles;
2639
- const host = _host.host;
2640
- const program = ts6_1.default.createProgram([fileName], compilerOptions, host);
2641
- program.emit();
2642
- let dts;
2643
- let map;
2644
- let code = "";
2645
- let file_name = "";
2646
- let out_dir = "";
2647
- for (const key of Object.keys(createdFiles)) {
2648
- if (key.endsWith(".js"))
2649
- code = createdFiles[key];
2650
- if (key.endsWith(".d.ts"))
2651
- dts = createdFiles[key];
2652
- if (key.endsWith(".js.map"))
2653
- map = createdFiles[key];
2654
- file_name = node_path_1.default.basename(key).split(".")[0];
2655
- out_dir = node_path_1.default.dirname(key);
2656
- }
2657
- return { code, file_name, out_dir, dts, map };
2658
- }
2659
- //src/compiler/tsoptions.ts
2660
- /**
2661
- * Get the path of the configuration file.
2662
- * If customConfigPath is provided and exists, use it.
2663
- * If customConfigPath is not provided or does not exist, use the default configuration file.
2664
- * @param {string | undefined} customConfigPath path of the custom configuration file.
2665
- * @returns {string | undefined} path of the configuration file or undefined if customConfigPath does not exist.
2666
- */
2667
- function getTsConfigPath(customConfigPath) {
2668
- let config_path;
2669
- if (customConfigPath) {
2670
- if (!ts6_1.default.sys.fileExists(ts6_1.default.sys.resolvePath(customConfigPath))) {
2671
- console.error(`> ${color_1.default.magenta(`Given custom file ${customConfigPath} does not exists`)}`);
2672
- ts6_1.default.sys.exit(1);
2673
- }
2674
- config_path = customConfigPath;
2675
- return config_path;
2676
- }
2677
- else {
2678
- config_path = ts6_1.default.findConfigFile(ts6_1.default.sys.getCurrentDirectory(), ts6_1.default.sys.fileExists);
2679
- return config_path;
2680
- }
2681
- }
2682
- /**
2683
- * Get the TypeScript compiler options for susee bundler.
2684
- * @param {string | undefined} customConfigPath path of the custom configuration file.
2685
- */
2686
- function getCompilerOptions(customConfigPath) {
2687
- let tsconfig_opts;
2688
- const config_path = getTsConfigPath(customConfigPath);
2689
- if (config_path) {
2690
- const config = ts6_1.default.readConfigFile(config_path, ts6_1.default.sys.readFile);
2691
- const basePath = node_path_1.default.dirname(config_path);
2692
- const parsed = ts6_1.default.parseJsonConfigFileContent(config.config, ts6_1.default.sys, basePath);
2693
- tsconfig_opts = { ...parsed.options };
2694
- }
2695
- const commonjs = (out_dir) => {
2696
- const _out = out_dir ? out_dir : "dist";
2697
- if (tsconfig_opts !== undefined) {
2698
- const { rootDir, outDir, module, allowJs, declarationDir, ...rest } = tsconfig_opts;
2699
- return {
2700
- outDir: _out,
2701
- module: ts6_1.default.ModuleKind.CommonJS,
2702
- allowJs: true,
2703
- ...rest,
2704
- };
2705
- }
2706
- else {
2707
- return {
2708
- outDir: _out,
2709
- module: ts6_1.default.ModuleKind.CommonJS,
2710
- target: ts6_1.default.ScriptTarget.Latest,
2711
- };
2712
- }
2713
- };
2714
- const esm = (out_dir) => {
2715
- const _out = out_dir ? out_dir : "dist";
2716
- if (tsconfig_opts !== undefined) {
2717
- const { rootDir, outDir, module, allowJs, declarationDir, ...rest } = tsconfig_opts;
2718
- return {
2719
- outDir: _out,
2720
- module: ts6_1.default.ModuleKind.ES2020,
2721
- allowJs: true,
2722
- ...rest,
2723
- };
2724
- }
2725
- else {
2726
- return {
2727
- outDir: _out,
2728
- module: ts6_1.default.ModuleKind.ES2020,
2729
- target: ts6_1.default.ScriptTarget.Latest,
2730
- };
2731
- }
2732
- };
2733
- const defaultOptions = ts6_1.default.getDefaultCompilerOptions;
2734
- return { commonjs, esm, defaultOptions };
2735
- }
2736
- //src/compiler/index.ts
2737
- const logCompilerPhase = (entry, format, phase, start) => {
2738
- logProfilePhase(`compiler:${format}:${entry}`, phase, start);
2739
- };
2740
- /**
2741
- * Compiler for the JavaScript API.
2742
- * It bundles each configured entry point, emits CommonJS and ESM outputs,
2743
- * and optionally updates package export metadata.
2744
- */
2745
- class Compiler {
2746
- _files;
2747
- _object;
2748
- _bundledCodeCache;
2749
- /**
2750
- * Creates a compiler instance with normalized build options.
2751
- * @param {BuildOptions} object - build options generated from the susee config.
2752
- */
2753
- constructor(object) {
2754
- this._object = object;
2755
- this._bundledCodeCache = new WeakMap();
2756
- this._files = {
2757
- commonjs: undefined,
2758
- commonjsTypes: undefined,
2759
- esm: undefined,
2760
- esmTypes: undefined,
2761
- main: undefined,
2762
- module: undefined,
2763
- types: undefined,
2764
- };
2765
- }
2766
- _update() {
2767
- return this._object.updatePackage;
2768
- }
2769
- async _bundle(point) {
2770
- let bundledCode = this._bundledCodeCache.get(point);
2771
- if (!bundledCode) {
2772
- bundledCode = bundler(point.entry, point.plugins, point.warning);
2773
- this._bundledCodeCache.set(point, bundledCode);
2774
- }
2775
- return bundledCode;
2776
- }
2777
- async _commonjs(point) {
2778
- const isMain = point.exportPath === ".";
2779
- const opts = getCompilerOptions(point.tsconfigFilePath);
2780
- const compilerOptions = opts.commonjs(point.outputDirectoryPath);
2781
- let phaseStart = node_process_1.default.hrtime.bigint();
2782
- const bundledCode = await this._bundle(point);
2783
- logCompilerPhase(point.entry, "commonjs", "bundle", phaseStart);
2784
- const is_jsx = utils.checks.isJsxContent(bundledCode);
2785
- phaseStart = node_process_1.default.hrtime.bigint();
2786
- const compiled = suseeCompiler({
2787
- sourceCode: bundledCode,
2788
- fileName: point.entry,
2789
- compilerOptions,
2790
- isJsx: is_jsx,
2791
- });
2792
- logCompilerPhase(point.entry, "commonjs", "typescriptEmit", phaseStart);
2793
- let compiledCode = compiled.code;
2794
- const mainFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.cjs`);
2795
- const dtsFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.d.cts`);
2796
- const mapFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.cjs.map`);
2797
- // replace source mapping url
2798
- compiledCode = compiledCode.replace(new RegExp(`${compiled.file_name}.js.map`, "gm"), `${compiled.file_name}.cjs.map`);
2799
- // call post-process plugin
2800
- if (point.plugins.length > 0) {
2801
- for (const plugin of point.plugins) {
2802
- const _plugin = typeof plugin === "function" ? plugin() : plugin;
2803
- if (_plugin.type === "post-process") {
2804
- phaseStart = node_process_1.default.hrtime.bigint();
2805
- if (_plugin.async) {
2806
- compiledCode = await _plugin.func(compiledCode, point.entry);
2807
- }
2808
- else {
2809
- compiledCode = _plugin.func(compiledCode, point.entry);
2810
- }
2811
- logCompilerPhase(point.entry, "commonjs", `postProcessPlugin:${_plugin.name ?? "anonymous"}`, phaseStart);
2812
- }
2813
- }
2814
- }
2815
- // if allow update create file object
2816
- if (this._update()) {
2817
- this._files.commonjs = mainFilePath;
2818
- if (compiled.dts) {
2819
- this._files.commonjsTypes = dtsFilePath;
2820
- }
2821
- if (isMain && point.format.includes("commonjs")) {
2822
- if (this._files.commonjs)
2823
- this._files.main = this._files.commonjs;
2824
- if (this._files.commonjsTypes)
2825
- this._files.types = this._files.commonjsTypes;
2826
- }
2827
- } //update
2828
- phaseStart = node_process_1.default.hrtime.bigint();
2829
- await files.writeFile(mainFilePath, compiledCode);
2830
- if (compiled.dts)
2831
- await files.writeFile(dtsFilePath, compiled.dts);
2832
- if (compiled.map)
2833
- await files.writeFile(mapFilePath, compiled.map);
2834
- logCompilerPhase(point.entry, "commonjs", "writeFiles", phaseStart);
2835
- }
2836
- async _esm(point) {
2837
- const isMain = point.exportPath === ".";
2838
- const opts = getCompilerOptions(point.tsconfigFilePath);
2839
- const compilerOptions = opts.esm(point.outputDirectoryPath);
2840
- let phaseStart = node_process_1.default.hrtime.bigint();
2841
- const bundledCode = await this._bundle(point);
2842
- logCompilerPhase(point.entry, "esm", "bundle", phaseStart);
2843
- const is_jsx = utils.checks.isJsxContent(bundledCode);
2844
- phaseStart = node_process_1.default.hrtime.bigint();
2845
- const compiled = suseeCompiler({
2846
- sourceCode: bundledCode,
2847
- fileName: point.entry,
2848
- compilerOptions,
2849
- isJsx: is_jsx,
2850
- });
2851
- logCompilerPhase(point.entry, "esm", "typescriptEmit", phaseStart);
2852
- let compiledCode = compiled.code;
2853
- const mainFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.mjs`);
2854
- const dtsFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.d.mts`);
2855
- const mapFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.mjs.map`);
2856
- // replace source mapping url
2857
- compiledCode = compiledCode.replace(new RegExp(`${compiled.file_name}.js.map`, "gm"), `${compiled.file_name}.mjs.map`);
2858
- // call post-process plugin
2859
- if (point.plugins.length > 0) {
2860
- for (const plugin of point.plugins) {
2861
- const _plugin = typeof plugin === "function" ? plugin() : plugin;
2862
- if (_plugin.type === "post-process") {
2863
- phaseStart = node_process_1.default.hrtime.bigint();
2864
- if (_plugin.async) {
2865
- compiledCode = await _plugin.func(compiledCode, point.entry);
2866
- }
2867
- else {
2868
- compiledCode = _plugin.func(compiledCode, point.entry);
2869
- }
2870
- logCompilerPhase(point.entry, "esm", `postProcessPlugin:${_plugin.name ?? "anonymous"}`, phaseStart);
2871
- }
2872
- }
2873
- }
2874
- if (this._update()) {
2875
- this._files.esm = mainFilePath;
2876
- if (compiled.dts) {
2877
- this._files.esmTypes = dtsFilePath;
2878
- }
2879
- if (isMain && this._files.esm) {
2880
- this._files.module = this._files.esm;
2881
- }
2882
- } //update
2883
- phaseStart = node_process_1.default.hrtime.bigint();
2884
- await files.writeFile(mainFilePath, compiledCode);
2885
- if (compiled.dts)
2886
- await files.writeFile(dtsFilePath, compiled.dts);
2887
- if (compiled.map)
2888
- await files.writeFile(mapFilePath, compiled.map);
2889
- logCompilerPhase(point.entry, "esm", "writeFiles", phaseStart);
2890
- }
2891
- /**
2892
- * Clears the output directory and compiles all configured entry points.
2893
- * It also updates package.json export fields when package updates are enabled.
2894
- * @returns {Promise<void>}
2895
- */
2896
- async compile() {
2897
- await files.clearFolder(this._object.outDir);
2898
- for (const point of this._object.buildEntryPoints) {
2899
- for (const format of point.format) {
2900
- switch (format) {
2901
- case "commonjs":
2902
- await this._commonjs(point);
2903
- if (this._update()) {
2904
- await files.writePackageJson(this._files, point.exportPath);
2905
- }
2906
- break;
2907
- case "esm":
2908
- await this._esm(point);
2909
- if (this._update()) {
2910
- await files.writePackageJson(this._files, point.exportPath);
2911
- }
2912
- break;
2913
- }
2914
- }
2915
- }
2916
- }
2917
- }
2918
- //src/cli/build.ts
2919
- async function cliBuild() {
2920
- console.time(color_1.default.cyan("[Build] "));
2921
- const buildOptions = await finalSuseeConfig();
2922
- if (!buildOptions) {
2923
- console.error(color_1.default.magenta(`No susee.config file ("susee.config.ts", "susee.config.js", "susee.config.mjs") found`));
2924
- ts6_1.default.sys.exit(1);
2925
- }
2926
- const compiler = new Compiler(buildOptions);
2927
- await compiler.compile();
2928
- console.timeEnd(color_1.default.cyan("[Build] "));
2929
- }
2930
- //src/cli/lib/fail.ts
2931
- function fail(message) {
2932
- console.error(`${color_1.default.magenta("[Error]")} : ${color_1.default.gray(message)}`);
2933
- node_process_1.default.exit(1);
2934
- }
2935
- function isFile(entry) {
2936
- const exts = [".js", ".ts", ".mts", ".mjs", ".cjs", ".cts"];
2937
- return exts.includes(node_path_1.default.extname(entry));
2938
- }
2939
- // biome-ignore lint/suspicious/noExplicitAny: unknown
2940
- function isEmptyObject(entry) {
2941
- return (typeof entry === "object" &&
2942
- !Array.isArray(entry) &&
2943
- Object.keys(entry).length === 0);
2944
- }
2945
- function parseBooleanFlag(flag, value) {
2946
- if (value === "true")
2947
- return true;
2948
- if (value === "false")
2949
- return false;
2950
- fail(`Type of ${flag} must be boolean.`);
2951
- }
2952
- // biome-ignore lint/suspicious/noExplicitAny: unknown
2953
- function parseArgs(argv) {
2954
- const opts = {
2955
- entry: "",
2956
- };
2957
- for (let index = 0; index < argv.length; index += 1) {
2958
- const argument = argv[index];
2959
- if (index === 0 && !argument.startsWith("--") && isFile(argument)) {
2960
- opts.entry = argument;
2961
- continue;
2962
- }
2963
- const [flag, inlineValue] = argument.split("=", 2);
2964
- const nextValue = argv[index + 1];
2965
- const value = inlineValue ?? nextValue;
2966
- switch (flag) {
2967
- case "--entry":
2968
- if (!value || value.startsWith("--"))
2969
- fail("Entry point required.");
2970
- if (opts.entry !== "" && isFile(opts.entry))
2971
- fail("Entry point already exists.");
2972
- opts.entry = value;
2973
- if (inlineValue === undefined) {
2974
- index += 1;
2975
- }
2976
- break;
2977
- case "--outdir":
2978
- if (!value || value.startsWith("--"))
2979
- fail("Output directory required.");
2980
- opts.outDir = value;
2981
- if (inlineValue === undefined) {
2982
- index += 1;
2983
- }
2984
- break;
2985
- case "--format":
2986
- if (value !== "cjs" && value !== "commonjs" && value !== "esm") {
2987
- fail("Format must be cjs, commonjs, or esm.");
2988
- }
2989
- opts.format =
2990
- value === "cjs"
2991
- ? "commonjs"
2992
- : value;
2993
- if (inlineValue === undefined) {
2994
- index += 1;
2995
- }
2996
- break;
2997
- case "--tsconfig":
2998
- if (!value || value.startsWith("--"))
2999
- fail("Tsconfig path required.");
3000
- opts.tsconfig = value;
3001
- if (inlineValue === undefined) {
3002
- index += 1;
3003
- }
3004
- break;
3005
- case "--allow-update":
3006
- if (inlineValue !== undefined) {
3007
- opts.allowUpdate = parseBooleanFlag("allow update", inlineValue);
3008
- }
3009
- else if (nextValue === "true" || nextValue === "false") {
3010
- opts.allowUpdate = parseBooleanFlag("allow update", nextValue);
3011
- index += 1;
3012
- }
3013
- else {
3014
- opts.allowUpdate = true;
3015
- }
3016
- break;
3017
- case "--warning":
3018
- if (inlineValue !== undefined) {
3019
- opts.warning = parseBooleanFlag("warning", inlineValue);
3020
- }
3021
- else if (nextValue === "true" || nextValue === "false") {
3022
- opts.warning = parseBooleanFlag("warning", nextValue);
3023
- index += 1;
3024
- }
3025
- else {
3026
- opts.warning = true;
3027
- }
3028
- break;
3029
- case "--profile":
3030
- if (inlineValue !== undefined) {
3031
- opts.profile = parseBooleanFlag("profile", inlineValue);
3032
- }
3033
- else if (nextValue === "true" || nextValue === "false") {
3034
- opts.profile = parseBooleanFlag("profile", nextValue);
3035
- index += 1;
3036
- }
3037
- else {
3038
- opts.profile = true;
3039
- }
3040
- break;
3041
- }
3042
- }
3043
- if (isEmptyObject(opts) || opts.entry === "") {
3044
- fail("Entry point required");
3045
- }
3046
- return opts;
3047
- }
3048
- function getDefaultOptions(args) {
3049
- const entry = args.entry;
3050
- const outDir = args.outDir ?? "dist";
3051
- const format = args.format ?? "esm";
3052
- const tsconfig = args.tsconfig ?? undefined;
3053
- const allowUpdate = args.allowUpdate ?? false;
3054
- const warning = args.warning ?? false;
3055
- const profile = args.profile ?? false;
3056
- return {
3057
- entry,
3058
- outDir,
3059
- format,
3060
- tsconfig,
3061
- allowUpdate,
3062
- warning,
3063
- profile,
3064
- plugins: [],
3065
- };
3066
- }
3067
- //src/cli/cli.ts
3068
- const logCliCompilerPhase = (entry, format, phase, start) => {
3069
- logProfilePhase(`compiler:${format}:${entry}`, phase, start);
3070
- };
3071
- class CliCompiler {
3072
- _files;
3073
- _update;
3074
- constructor() {
3075
- this._files = {
3076
- commonjs: undefined,
3077
- commonjsTypes: undefined,
3078
- esm: undefined,
3079
- esmTypes: undefined,
3080
- main: undefined,
3081
- module: undefined,
3082
- types: undefined,
3083
- };
3084
- this._update = false;
3085
- }
3086
- async _commonjs(opts) {
3087
- this._update = opts.allowUpdate;
3088
- const _opts = getCompilerOptions(opts.tsconfig);
3089
- const compilerOptions = _opts.commonjs(opts.outDir);
3090
- let phaseStart = node_process_1.default.hrtime.bigint();
3091
- const bundledCode = await bundler(opts.entry, opts.plugins, opts.warning);
3092
- logCliCompilerPhase(opts.entry, "commonjs", "bundle", phaseStart);
3093
- const is_jsx = utils.checks.isJsxContent(bundledCode);
3094
- phaseStart = node_process_1.default.hrtime.bigint();
3095
- const compiled = suseeCompiler({
3096
- sourceCode: bundledCode,
3097
- fileName: opts.entry,
3098
- compilerOptions,
3099
- isJsx: is_jsx,
3100
- });
3101
- logCliCompilerPhase(opts.entry, "commonjs", "typescriptEmit", phaseStart);
3102
- let compiledCode = compiled.code;
3103
- const mainFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.cjs`);
3104
- const dtsFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.d.cts`);
3105
- const mapFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.cjs.map`);
3106
- compiledCode = compiledCode.replace(new RegExp(`${compiled.file_name}.js.map`, "gm"), `${compiled.file_name}.cjs.map`);
3107
- // --
3108
- // call post-process plugin
3109
- if (opts.plugins.length > 0) {
3110
- for (const plugin of opts.plugins) {
3111
- const _plugin = typeof plugin === "function" ? plugin() : plugin;
3112
- if (_plugin.type === "post-process") {
3113
- phaseStart = node_process_1.default.hrtime.bigint();
3114
- if (_plugin.async) {
3115
- compiledCode = await _plugin.func(compiledCode, opts.entry);
3116
- }
3117
- else {
3118
- compiledCode = _plugin.func(compiledCode, opts.entry);
3119
- }
3120
- logCliCompilerPhase(opts.entry, "commonjs", `postProcessPlugin:${_plugin.name ?? "anonymous"}`, phaseStart);
3121
- }
3122
- }
3123
- } //-----------
3124
- if (this._update) {
3125
- this._files.commonjs = mainFilePath;
3126
- if (compiled.dts) {
3127
- this._files.commonjsTypes = dtsFilePath;
3128
- }
3129
- if (opts.format.includes("commonjs")) {
3130
- if (this._files.commonjs)
3131
- this._files.main = this._files.commonjs;
3132
- if (this._files.commonjsTypes)
3133
- this._files.types = this._files.commonjsTypes;
3134
- }
3135
- } //update
3136
- phaseStart = node_process_1.default.hrtime.bigint();
3137
- await files.writeFile(mainFilePath, compiledCode);
3138
- if (compiled.dts)
3139
- await files.writeFile(dtsFilePath, compiled.dts);
3140
- if (compiled.map)
3141
- await files.writeFile(mapFilePath, compiled.map);
3142
- logCliCompilerPhase(opts.entry, "commonjs", "writeFiles", phaseStart);
3143
- }
3144
- //-----------------------------------------------------------------//
3145
- async _esm(opts) {
3146
- this._update = opts.allowUpdate;
3147
- const _opts = getCompilerOptions(opts.tsconfig);
3148
- const compilerOptions = _opts.esm(opts.outDir);
3149
- let phaseStart = node_process_1.default.hrtime.bigint();
3150
- const bundledCode = await bundler(opts.entry, opts.plugins, opts.warning);
3151
- logCliCompilerPhase(opts.entry, "esm", "bundle", phaseStart);
3152
- const is_jsx = utils.checks.isJsxContent(bundledCode);
3153
- phaseStart = node_process_1.default.hrtime.bigint();
3154
- const compiled = suseeCompiler({
3155
- sourceCode: bundledCode,
3156
- fileName: opts.entry,
3157
- compilerOptions,
3158
- isJsx: is_jsx,
3159
- });
3160
- logCliCompilerPhase(opts.entry, "esm", "typescriptEmit", phaseStart);
3161
- let compiledCode = compiled.code;
3162
- const mainFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.mjs`);
3163
- const dtsFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.d.mts`);
3164
- const mapFilePath = files.joinPath(compiled.out_dir, `${compiled.file_name}.mjs.map`);
3165
- compiledCode = compiledCode.replace(new RegExp(`${compiled.file_name}.js.map`, "gm"), `${compiled.file_name}.mjs.map`);
3166
- // call post-process plugin
3167
- if (opts.plugins.length > 0) {
3168
- for (const plugin of opts.plugins) {
3169
- const _plugin = typeof plugin === "function" ? plugin() : plugin;
3170
- if (_plugin.type === "post-process") {
3171
- phaseStart = node_process_1.default.hrtime.bigint();
3172
- if (_plugin.async) {
3173
- compiledCode = await _plugin.func(compiledCode, opts.entry);
3174
- }
3175
- else {
3176
- compiledCode = _plugin.func(compiledCode, opts.entry);
3177
- }
3178
- logCliCompilerPhase(opts.entry, "esm", `postProcessPlugin:${_plugin.name ?? "anonymous"}`, phaseStart);
3179
- }
3180
- }
3181
- } //-----------
3182
- if (this._update) {
3183
- this._files.esm = mainFilePath;
3184
- if (compiled.dts) {
3185
- this._files.esmTypes = dtsFilePath;
3186
- }
3187
- if (this._files.esm) {
3188
- this._files.module = this._files.esm;
3189
- }
3190
- } //update
3191
- phaseStart = node_process_1.default.hrtime.bigint();
3192
- await files.writeFile(mainFilePath, compiledCode);
3193
- if (compiled.dts)
3194
- await files.writeFile(dtsFilePath, compiled.dts);
3195
- if (compiled.map)
3196
- await files.writeFile(mapFilePath, compiled.map);
3197
- logCliCompilerPhase(opts.entry, "esm", "writeFiles", phaseStart);
3198
- }
3199
- //--
3200
- async compile(opts) {
3201
- await files.clearFolder(opts.outDir);
3202
- switch (opts.format) {
3203
- case "commonjs":
3204
- await this._commonjs(opts);
3205
- if (this._update) {
3206
- await files.writePackageJson(this._files, ".");
3207
- }
3208
- break;
3209
- case "esm":
3210
- await this._esm(opts);
3211
- if (this._update) {
3212
- await files.writePackageJson(this._files, ".");
3213
- }
3214
- break;
3215
- }
3216
- }
3217
- }
3218
- const cliCompiler = new CliCompiler();
3219
- //src/cli/lib/print_help.ts
3220
- function printHelp() {
3221
- console.log(`Susee CLI.
3222
-
3223
- Usage:
3224
- susee Build using susee.config.{ts,js,mjs}
3225
- susee init Generate susee.config.{ts,js,mjs}
3226
- susee --help Show this message
3227
- susee build <entry> [options] Build from a single entry file
3228
-
3229
- Options:
3230
- --entry <path> Entry file (optional if provided as positional <entry>)
3231
- --outdir <path> Output directory
3232
- --format <cjs|commonjs|esm> Output module format
3233
- --tsconfig <path> Custom tsconfig path
3234
- --allow-update[=true|false] Enable/disable dependency update
3235
- --warning[=true|false] Treat dependency graph warnings as fatal
3236
- --profile[=true|false] Print bundler/compiler phase timings
3237
-
3238
- Notes:
3239
- Duplicate top-level declarations fail the build with file and location output.
3240
- Rename conflicting declarations in source files before bundling.
3241
-
3242
- Examples:
3243
- susee build src/index.ts --outdir dist
3244
- susee build src/index.ts --format commonjs
3245
- susee build --entry src/index.ts --format esm --tsconfig tsconfig.build.json
3246
- susee build src/index.ts --profile
3247
- susee --profile
3248
-
3249
- `);
3250
- }
3251
- //src/cli/index.ts
3252
- const tsFileText = `
3253
- import type { SuSeeConfig } from "susee";
3254
-
3255
- const config: SuSeeConfig = {
3256
- // Array of entry point objects.
3257
- // ----------------------------
3258
- entryPoints: [
3259
- // You can add more entry points for different export paths.
3260
- // NOTE: duplicate export paths are not allowed.
3261
- // --------------------------------------------
3262
- {
3263
- // (required) Entry file path.
3264
- entry: "src/index.ts", // replace with your entry file
3265
- // (required) Export path for this entry.
3266
- exportPath: ".", // "." stands for the main export path and can be set to "./foo", "./bar", etc.
3267
- // (optional) Output module formats ["commonjs"] or ["esm", "commonjs"], default: ["esm"].
3268
- // Uncomment the following line to edit.
3269
- //format: ["esm"],
3270
- // Duplicate top-level declarations are checked during bundling.
3271
- // Rename conflicting declarations in source files before building.
3272
- // (optional) Custom tsconfig.json path, default: undefined.
3273
- // Uncomment the following line to edit.
3274
- //tsconfigFilePath: undefined,
3275
- // (optional) Array of susee plugins, default: [].
3276
- // Uncomment the following line to edit.
3277
- //plugins: [],
3278
- // (optional) Warning messages, if it true and warning message exist(1), default: false.
3279
- // Uncomment the following line to edit.
3280
- //warning: false,
3281
- },
3282
- ],
3283
- // NOTE: the following options apply to all entry points.
3284
- // ----------------------------------------------------------
3285
- // (optional) Output directory, default: dist.
3286
- // Uncomment the following line to edit.
3287
- //outDir: "dist",
3288
- // (optional) Allow susee to update your package.json, default: false.
3289
- // Uncomment the following line to edit.
3290
- //allowUpdatePackageJson: false,
3291
- };
3292
-
3293
- export default config;
3294
- `.trim();
3295
- const jsFileText = `
3296
- /**
3297
- * @type {import("susee").SuSeeConfig}
3298
- */
3299
- const config = {
3300
- // Array of entry point objects.
3301
- // ----------------------------
3302
- entryPoints: [
3303
- // You can add more entry points for different export paths.
3304
- // NOTE: duplicate export paths are not allowed.
3305
- // --------------------------------------------
3306
- {
3307
- // (required) Entry file path.
3308
- entry: "src/index.ts", // replace with your entry file
3309
- // (required) Export path for this entry.
3310
- exportPath: ".", // "." stands for the main export path and can be set to "./foo", "./bar", etc.
3311
- // (optional) Output module formats ["commonjs"] or ["esm", "commonjs"], default: ["esm"].
3312
- // Uncomment the following line to edit.
3313
- //format: ["esm"],
3314
- // Duplicate top-level declarations are checked during bundling.
3315
- // Rename conflicting declarations in source files before building.
3316
- // (optional) Custom tsconfig.json path, default: undefined.
3317
- // Uncomment the following line to edit.
3318
- //tsconfigFilePath: undefined,
3319
- // (optional) Array of susee plugins, default: [].
3320
- // Uncomment the following line to edit.
3321
- //plugins: [],
3322
- // (optional) Warning messages, if it true and warning message exist(1), default: false.
3323
- // Uncomment the following line to edit.
3324
- //warning: false,
3325
- },
3326
- ],
3327
- // NOTE: the following options apply to all entry points.
3328
- // ----------------------------------------------------------
3329
- // (optional) Output directory, default: dist.
3330
- // Uncomment the following line to edit.
3331
- //outDir: "dist",
3332
- // (optional) Allow susee to update your package.json, default: false.
3333
- // Uncomment the following line to edit.
3334
- //allowUpdatePackageJson: false,
3335
- };
3336
-
3337
- export default config;
3338
- `.trim();
3339
- async function getPackageType() {
3340
- const pkgPath = node_path_1.default.resolve(node_process_1.default.cwd(), "package.json");
3341
- const _pkg = await node_fs_1.default.promises.readFile(pkgPath, "utf8");
3342
- const pkg = JSON.parse(_pkg);
3343
- return __jsonModule__package.type === "module" ? "esm" : "commonjs";
3344
- }
3345
- async function cliInit() {
3346
- const rl = promises_1.default.createInterface({
3347
- input: node_process_1.default.stdin,
3348
- output: node_process_1.default.stdout,
3349
- });
3350
- console.log(`${color_1.default.gray("┌")} ${color_1.default.green("Welcome to Susee!")}`);
3351
- console.log("");
3352
- console.log(`${color_1.default.gray("│")}`);
3353
- const is_ts = await rl.question(`${color_1.default.cyan("◇")} Is TypeScript Project(y/n) : `);
3354
- const isTs = !!(is_ts === "y" || is_ts === "Y" || is_ts === "");
3355
- rl.close();
3356
- let configFile = "";
3357
- let str = "";
3358
- if (isTs) {
3359
- configFile = "susee.config.ts";
3360
- str = tsFileText;
3361
- }
3362
- else {
3363
- str = jsFileText;
3364
- const pkgType = await getPackageType();
3365
- switch (pkgType) {
3366
- case "commonjs":
3367
- configFile = "susee.config.mjs";
3368
- break;
3369
- case "esm":
3370
- configFile = "susee.config.js";
3371
- break;
3372
- }
3373
- }
3374
- const configFilePath = node_path_1.default.resolve(node_process_1.default.cwd(), configFile);
3375
- if (node_fs_1.default.existsSync(configFilePath))
3376
- await node_fs_1.default.promises.unlink(configFilePath);
3377
- await node_fs_1.default.promises.writeFile(configFilePath, str);
3378
- console.log("");
3379
- console.log(`${color_1.default.gray("│")}`);
3380
- console.log("");
3381
- console.info(`${color_1.default.gray("└")} Done! Susee config file ${color_1.default.cyan(configFile)} is created at project root`);
3382
- }
3383
- function extractProfileFlag(args) {
3384
- const nextArgs = [];
3385
- let profile = false;
3386
- for (let index = 0; index < args.length; index += 1) {
3387
- const argument = args[index];
3388
- const [flag, inlineValue] = argument.split("=", 2);
3389
- if (flag !== "--profile") {
3390
- nextArgs.push(argument);
3391
- continue;
3392
- }
3393
- const nextValue = args[index + 1];
3394
- if (inlineValue !== undefined) {
3395
- profile = parseBooleanFlag("profile", inlineValue);
3396
- continue;
3397
- }
3398
- if (nextValue === "true" || nextValue === "false") {
3399
- profile = parseBooleanFlag("profile", nextValue);
3400
- index += 1;
3401
- continue;
3402
- }
3403
- profile = true;
3404
- }
3405
- return { args: nextArgs, profile };
3406
- }
3407
- async function suseeCliBuild() {
3408
- const rawArgs = node_process_1.default.argv.slice(2);
3409
- const { args, profile } = extractProfileFlag(rawArgs);
3410
- if (profile) {
3411
- setProfileEnabled(true);
3412
- }
3413
- if (args.length === 0) {
3414
- await cliBuild();
3415
- }
3416
- else if (args.length === 1) {
3417
- if (args[0] === "--version" || args[0] === "-v") {
3418
- console.log(color_1.default.cyan(`susee v${__jsonModule__package.version}`));
3419
- }
3420
- if (args[0] === "--help" || args[0] === "-h") {
3421
- printHelp();
3422
- }
3423
- if (args[0] === "init") {
3424
- await cliInit();
3425
- }
3426
- if (args[0] === "build") {
3427
- printHelp();
3428
- }
3429
- }
3430
- else if (args.length > 1 &&
3431
- args[0] === "build" &&
3432
- (args[1] === "--help" || args[1] === "-h")) {
3433
- printHelp();
3434
- }
3435
- else if (args.length > 1 && args[0] === "build") {
3436
- const _r = parseArgs(args.slice(1));
3437
- const options = getDefaultOptions(_r);
3438
- await cliCompiler.compile(options);
3439
- }
3440
- else {
3441
- console.error("Unknown CLI usage");
3442
- node_process_1.default.exit(1);
3443
- }
3444
- }
3445
- if (import.meta.main) {
3446
- await suseeCliBuild();
3447
- }
3448
- //src/index.ts
3449
- /**
3450
- * Run a Susee build.
3451
- *
3452
- * Resolution order:
3453
- * 1. Use `options` when provided.
3454
- * 2. Otherwise try loading root config via `finalSuseeConfig()`.
3455
- *
3456
- * If neither source is available, this logs an error and exits with code 1.
3457
- */
3458
- async function build(options) {
3459
- console.time(color_1.default.cyan("[Build] "));
3460
- let buildOptions = {};
3461
- const _buildOptions = await finalSuseeConfig();
3462
- if (!options && !_buildOptions) {
3463
- console.error(`${color_1.default.magenta("[Error]")} : Required build options or susee config file at root.\n Use ${color_1.default.bold("npx susee init")} to create config file.`);
3464
- node_process_1.default.exit(1);
3465
- }
3466
- if (options) {
3467
- buildOptions = generateBuildOptions(options);
3468
- }
3469
- else if (_buildOptions) {
3470
- buildOptions = _buildOptions;
3471
- }
3472
- const compiler = new Compiler(buildOptions);
3473
- await compiler.compile();
3474
- console.timeEnd(color_1.default.cyan("[Build] "));
3475
- }
3476
- //# sourceMappingURL=index.cjs.map