zshy 0.0.5 → 0.0.7

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 ADDED
@@ -0,0 +1,697 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const fs = __importStar(require("node:fs"));
41
+ const path = __importStar(require("node:path/posix"));
42
+ const arg_1 = __importDefault(require("arg"));
43
+ const globby_1 = require("globby");
44
+ const table_1 = require("table");
45
+ const ts = __importStar(require("typescript"));
46
+ const utils_1 = require("./utils.cjs");
47
+ function isSourceFile(filePath) {
48
+ return (filePath.endsWith(".ts") || filePath.endsWith(".mts") || filePath.endsWith(".cts") || filePath.endsWith(".tsx"));
49
+ }
50
+ function removeExtension(filePath) {
51
+ return filePath.split(".").slice(0, -1).join(".") || filePath;
52
+ }
53
+ async function main() {
54
+ ///////////////////////////////////
55
+ /// parse command line args ///
56
+ ///////////////////////////////////
57
+ // Parse command line arguments using arg library
58
+ let args;
59
+ try {
60
+ args = (0, arg_1.default)({
61
+ "--help": Boolean,
62
+ "--verbose": Boolean,
63
+ "--project": String,
64
+ "--dry-run": Boolean,
65
+ // "--attw": Boolean,
66
+ // Aliases
67
+ "-h": "--help",
68
+ "-p": "--project",
69
+ });
70
+ }
71
+ catch (error) {
72
+ if (error instanceof Error) {
73
+ (0, utils_1.emojiLog)("❌", error.message, "error");
74
+ }
75
+ console.error(`Use --help for usage information`);
76
+ process.exit(1);
77
+ }
78
+ // Handle help flag
79
+ if (args["--help"]) {
80
+ console.log(`
81
+ Usage: zshy [options]
82
+
83
+ Options:
84
+ -h, --help Show this help message
85
+ -p, --project <path> Path to tsconfig.json file
86
+ --verbose Enable verbose output
87
+ --dry-run Don't write any files, just log what would be done
88
+
89
+ Examples:
90
+ zshy # Run build
91
+ zshy --project ./tsconfig.build.json # Use specific tsconfig file (defaults to tsconfig.json)
92
+ zshy --verbose # Enable verbose logging
93
+ zshy --dry-run # Preview changes without writing files
94
+ `);
95
+ process.exit(0);
96
+ }
97
+ const userAgent = process.env.npm_config_user_agent;
98
+ let pmExec;
99
+ if (userAgent?.startsWith("pnpm")) {
100
+ pmExec = "pnpm exec";
101
+ }
102
+ else if (userAgent?.startsWith("yarn")) {
103
+ pmExec = "yarn exec";
104
+ }
105
+ else {
106
+ pmExec = "npx";
107
+ }
108
+ (0, utils_1.emojiLog)("💎", "Starting build... 🐒");
109
+ const isVerbose = args["--verbose"];
110
+ const isDryRun = args["--dry-run"];
111
+ const isAttw = false; // args["--attw"];
112
+ if (isVerbose) {
113
+ (0, utils_1.emojiLog)("ℹ️", "Verbose mode enabled");
114
+ (0, utils_1.emojiLog)("📦", `Detected package manager: ${pmExec}`);
115
+ }
116
+ if (isDryRun) {
117
+ (0, utils_1.emojiLog)("🔍", "Dry run mode enabled - no files will be written");
118
+ }
119
+ ///////////////////////////////////
120
+ /// find and read pkg json ///
121
+ ///////////////////////////////////
122
+ // Find package.json by scanning up the file system
123
+ let packageJsonPath = "./package.json";
124
+ let currentDir = process.cwd();
125
+ while (currentDir !== path.dirname(currentDir)) {
126
+ const candidatePath = path.join(currentDir, "package.json");
127
+ if (fs.existsSync(candidatePath)) {
128
+ packageJsonPath = candidatePath;
129
+ break;
130
+ }
131
+ currentDir = path.dirname(currentDir);
132
+ }
133
+ if (!fs.existsSync(packageJsonPath)) {
134
+ (0, utils_1.emojiLog)("❌", "package.json not found in current directory or any parent directories", "error");
135
+ process.exit(1);
136
+ }
137
+ // read package.json and extract the "zshy" exports config
138
+ // console.log("📦 Extracting entry points from package.json exports...");
139
+ const pkgJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
140
+ const pkgJsonDir = path.dirname(packageJsonPath);
141
+ // print project root
142
+ (0, utils_1.emojiLog)("⚙️", `Detected project root: ${pkgJsonDir}`);
143
+ (0, utils_1.emojiLog)("📦", `Reading package.json from ./${path.relative(pkgJsonDir, packageJsonPath)}`);
144
+ /////////////////////////////////
145
+ /// parse zshy config ///
146
+ /////////////////////////////////
147
+ // const pkgJson = JSON.parse(fs.readFileSync("./package.json", "utf-8"));
148
+ const CONFIG_KEY = "zshy";
149
+ let config;
150
+ if (!pkgJson[CONFIG_KEY]) {
151
+ (0, utils_1.emojiLog)("❌", `No "${CONFIG_KEY}" key found in package.json`, "error");
152
+ process.exit(1);
153
+ }
154
+ if (typeof pkgJson[CONFIG_KEY] === "string") {
155
+ config = {
156
+ exports: { ".": pkgJson[CONFIG_KEY] },
157
+ };
158
+ }
159
+ else if (typeof pkgJson[CONFIG_KEY] === "object") {
160
+ config = { ...pkgJson[CONFIG_KEY] };
161
+ if (typeof config.exports === "string") {
162
+ config.exports = { ".": config.exports };
163
+ }
164
+ else if (typeof config.exports === "undefined") {
165
+ (0, utils_1.emojiLog)("❌", `Missing "exports" key in package.json#/${CONFIG_KEY}`, "error");
166
+ process.exit(1);
167
+ }
168
+ else if (typeof config.exports !== "object") {
169
+ (0, utils_1.emojiLog)("❌", `Invalid "exports" key in package.json#/${CONFIG_KEY}`, "error");
170
+ process.exit(1);
171
+ }
172
+ // Validate bin field if present
173
+ if (config.bin !== undefined) {
174
+ if (typeof config.bin === "string") {
175
+ // Keep string format - we'll handle this in entry point extraction
176
+ }
177
+ else if (typeof config.bin === "object" && config.bin !== null) {
178
+ // Object format is valid
179
+ }
180
+ else {
181
+ (0, utils_1.emojiLog)("❌", `Invalid "bin" key in package.json#/${CONFIG_KEY}, expected string or object`, "error");
182
+ process.exit(1);
183
+ }
184
+ }
185
+ // {
186
+ // exports: { ".": pkgJson[CONFIG_KEY].exports },
187
+ // };
188
+ }
189
+ else if (typeof pkgJson[CONFIG_KEY] === "undefined") {
190
+ (0, utils_1.emojiLog)("❌", `Missing "${CONFIG_KEY}" key in package.json`, "error");
191
+ process.exit(1);
192
+ }
193
+ else {
194
+ (0, utils_1.emojiLog)("❌", `Invalid "${CONFIG_KEY}" key in package.json, expected string or object`, "error");
195
+ process.exit(1);
196
+ }
197
+ if (isVerbose) {
198
+ (0, utils_1.emojiLog)("🔧", `Parsed zshy config: ${(0, utils_1.formatForLog)(config)}`);
199
+ }
200
+ ///////////////////////////
201
+ /// read tsconfig ///
202
+ ///////////////////////////
203
+ // Determine tsconfig.json path
204
+ let tsconfigPath;
205
+ if (args["--project"]) {
206
+ // CLI flag takes priority
207
+ const resolvedProjectPath = path.resolve(process.cwd(), args["--project"]);
208
+ if (fs.existsSync(resolvedProjectPath)) {
209
+ if (fs.statSync(resolvedProjectPath).isDirectory()) {
210
+ (0, utils_1.emojiLog)("❌", `--project must point to a tsconfig.json file, not a directory: ${resolvedProjectPath}`, "error");
211
+ process.exit(1);
212
+ }
213
+ else {
214
+ // Use the file directly
215
+ tsconfigPath = resolvedProjectPath;
216
+ }
217
+ }
218
+ else {
219
+ (0, utils_1.emojiLog)("❌", `tsconfig.json file not found: ${resolvedProjectPath}`, "error");
220
+ process.exit(1);
221
+ }
222
+ }
223
+ else if (config.tsconfig) {
224
+ // Fallback to package.json config
225
+ const resolvedProjectPath = path.resolve(pkgJsonDir, config.tsconfig);
226
+ if (fs.existsSync(resolvedProjectPath)) {
227
+ if (fs.statSync(resolvedProjectPath).isDirectory()) {
228
+ (0, utils_1.emojiLog)("❌", `zshy.tsconfig must point to a tsconfig.json file, not a directory: ${resolvedProjectPath}`, "error");
229
+ process.exit(1);
230
+ }
231
+ else {
232
+ // Use the file directly
233
+ tsconfigPath = resolvedProjectPath;
234
+ }
235
+ }
236
+ else {
237
+ (0, utils_1.emojiLog)("❌", `Tsconfig file not found: ${resolvedProjectPath}`, "error");
238
+ process.exit(1);
239
+ }
240
+ }
241
+ else {
242
+ // Default to tsconfig.json in the package.json directory
243
+ tsconfigPath = path.join(pkgJsonDir, "tsconfig.json");
244
+ }
245
+ const _parsedConfig = (0, utils_1.readTsconfig)(tsconfigPath);
246
+ if (!fs.existsSync(tsconfigPath)) {
247
+ // Check if tsconfig.json exists
248
+ (0, utils_1.emojiLog)("❌", `tsconfig.json not found at ${path.resolve(tsconfigPath)}`, "error");
249
+ process.exit(1);
250
+ }
251
+ (0, utils_1.emojiLog)("📁", `Reading tsconfig from ./${path.relative(pkgJsonDir, tsconfigPath)}`);
252
+ // if (_parsedConfig.rootDir) {
253
+ // console.error(
254
+ // `❌ rootDir is determined from your set of entrypoints; you can remove it from your tsconfig.json.`,
255
+ // );
256
+ // process.exit(1);
257
+ // }
258
+ // if (_parsedConfig.declarationDir) {
259
+ // console.error(
260
+ // `❌ declarationDir is not supported in zshy; you should remove it from your tsconfig.json.`,
261
+ // );
262
+ // process.exit(1);
263
+ // }
264
+ // set/override compiler options
265
+ delete _parsedConfig.customConditions; // can't be set for CommonJS builds
266
+ const outDir = path.resolve(pkgJsonDir, _parsedConfig?.outDir || "./dist");
267
+ const relOutDir = path.relative(pkgJsonDir, outDir);
268
+ const declarationDir = path.resolve(pkgJsonDir, _parsedConfig?.declarationDir || relOutDir);
269
+ const relDeclarationDir = path.relative(pkgJsonDir, declarationDir);
270
+ // clean up outDir and declarationDir
271
+ if (relOutDir !== "") {
272
+ (0, utils_1.emojiLog)("🗑️", `Cleaning up outDir...`);
273
+ fs.rmSync(outDir, { recursive: true, force: true });
274
+ // // print success mesage in verbose mode
275
+ if (isVerbose) {
276
+ if (fs.existsSync(outDir)) {
277
+ (0, utils_1.emojiLog)("❌", `Failed to clean up outDir: ${relOutDir}. Directory still exists.`, "error");
278
+ }
279
+ }
280
+ }
281
+ else {
282
+ (0, utils_1.emojiLog)("🗑️", `Skipping cleanup of outDir as it contains source files`);
283
+ }
284
+ if (relDeclarationDir !== relOutDir && relDeclarationDir !== "") {
285
+ (0, utils_1.emojiLog)("🗑️", `Cleaning up declarationDir...`);
286
+ fs.rmSync(declarationDir, { recursive: true, force: true });
287
+ // // print success mesage in verbose mode
288
+ if (isVerbose) {
289
+ if (fs.existsSync(declarationDir)) {
290
+ (0, utils_1.emojiLog)("❌", `Failed to clean up declarationDir: ${relDeclarationDir}. Directory still exists.`, "error");
291
+ }
292
+ }
293
+ }
294
+ else {
295
+ if (isVerbose)
296
+ (0, utils_1.emojiLog)("🗑️", `Skipping cleanup of declarationDir as it contains source files`);
297
+ }
298
+ const tsconfigJson = {
299
+ ..._parsedConfig,
300
+ outDir,
301
+ target: _parsedConfig.target ?? ts.ScriptTarget.ES2020, // ensure compatible target for CommonJS
302
+ skipLibCheck: true, // skip library checks to reduce errors
303
+ declaration: true,
304
+ noEmit: false,
305
+ emitDeclarationOnly: false,
306
+ rewriteRelativeImportExtensions: true,
307
+ verbatimModuleSyntax: false,
308
+ };
309
+ if (relOutDir === "") {
310
+ if (!pkgJson.files) {
311
+ (0, utils_1.emojiLog)("⚠️", 'You\'re building your code to the project root. This means your compiled files will be generated alongside your source files.\n ➜ Setting "files" in package.json to exclude TypeScript source from the published package.');
312
+ pkgJson.files = ["**/*.js", "**/*.mjs", "**/*.cjs", "**/*.d.ts", "**/*.d.mts", "**/*.d.cts"];
313
+ }
314
+ else {
315
+ console.warn(`⚠️ You\'re building your code to the project root. This means your compiled files will be generated alongside your source files.
316
+ ➜ Ensure that your "files" in package.json excludes TypeScript source files, or your users may experience .d.ts resolution issues in some environments:
317
+
318
+ "files": ["**/*.js", "**/*.mjs", "**/*.cjs", "**/*.d.ts", "**/*.d.mts", "**/*.d.cts"],
319
+ `);
320
+ }
321
+ }
322
+ else {
323
+ if (!pkgJson.files) {
324
+ (0, utils_1.emojiLog)("⚠️", `The "files" key is missing in package.json. Setting to "${relOutDir}".`);
325
+ pkgJson.files = [relOutDir];
326
+ if (relOutDir !== relDeclarationDir) {
327
+ pkgJson.files.push(relDeclarationDir);
328
+ }
329
+ }
330
+ }
331
+ /////////////////////////////////
332
+ /// extract entry points ///
333
+ /////////////////////////////////
334
+ // Extract entry points from zshy exports config
335
+ (0, utils_1.emojiLog)("➡️", "Determining entrypoints...");
336
+ const entryPatterns = [];
337
+ const rows = [["Subpath", "Entrypoint"]];
338
+ for (const [exportPath, sourcePath] of Object.entries(config.exports)) {
339
+ if (exportPath.includes("package.json"))
340
+ continue;
341
+ let cleanExportPath;
342
+ if (exportPath === ".") {
343
+ cleanExportPath = pkgJson.name;
344
+ }
345
+ else if (exportPath.startsWith("./")) {
346
+ cleanExportPath = pkgJson.name + "/" + exportPath.slice(2);
347
+ }
348
+ else {
349
+ (0, utils_1.emojiLog)("⚠️", `Invalid subpath export "${exportPath}" — should start with "./"`, "warn");
350
+ process.exit(1);
351
+ }
352
+ if (typeof sourcePath === "string") {
353
+ if (sourcePath.includes("*")) {
354
+ if (!sourcePath.endsWith("/*")) {
355
+ (0, utils_1.emojiLog)("❌", `Wildcard paths should not contain file extensions: ${sourcePath}`, "error");
356
+ process.exit(1);
357
+ }
358
+ const pattern = sourcePath.slice(0, -2) + "/*.{ts,tsx,mts,cts}";
359
+ const wildcardFiles = await (0, globby_1.globby)([pattern], {
360
+ ignore: ["**/*.d.ts"],
361
+ cwd: pkgJsonDir,
362
+ deep: 1,
363
+ });
364
+ entryPatterns.push(...wildcardFiles);
365
+ rows.push([`"${cleanExportPath}"`, `${sourcePath} (${wildcardFiles.length} matches)`]);
366
+ }
367
+ else if (isSourceFile(sourcePath)) {
368
+ entryPatterns.push(sourcePath);
369
+ rows.push([`"${cleanExportPath}"`, sourcePath]);
370
+ }
371
+ }
372
+ }
373
+ // Extract bin entry points from zshy bin config
374
+ if (config.bin) {
375
+ if (typeof config.bin === "string") {
376
+ // Single bin entry
377
+ if (isSourceFile(config.bin)) {
378
+ entryPatterns.push(config.bin);
379
+ rows.push([`bin:${pkgJson.name}`, config.bin]);
380
+ }
381
+ }
382
+ else {
383
+ // Multiple bin entries
384
+ for (const [binName, sourcePath] of Object.entries(config.bin)) {
385
+ if (typeof sourcePath === "string" && isSourceFile(sourcePath)) {
386
+ entryPatterns.push(sourcePath);
387
+ rows.push([`bin:${binName}`, sourcePath]);
388
+ }
389
+ }
390
+ }
391
+ }
392
+ console.log(" " +
393
+ (0, table_1.table)(rows, {
394
+ drawHorizontalLine: (lineIndex, rowCount) => {
395
+ return (lineIndex === 0 ||
396
+ lineIndex === 1 ||
397
+ // lineIndex === rowCount - 1 ||
398
+ lineIndex === rowCount);
399
+ },
400
+ })
401
+ .split("\n")
402
+ .join("\n ")
403
+ .trim());
404
+ ///////////////////////////////
405
+ /// compute entry points ///
406
+ ///////////////////////////////
407
+ // compute entry points
408
+ const entryPoints = await (0, utils_1.getEntryPoints)(entryPatterns);
409
+ // disallow .mts and .cts files
410
+ if (entryPoints.some((ep) => ep.endsWith(".mts") || ep.endsWith(".cts"))) {
411
+ (0, utils_1.emojiLog)("❌", "Source files with .mts or .cts extensions are not supported. Please use regular .ts files.", "error");
412
+ process.exit(1);
413
+ }
414
+ if (entryPoints.length === 0) {
415
+ (0, utils_1.emojiLog)("❌", "No entry points found matching the specified patterns in package.json#/zshy exports", "error");
416
+ process.exit(1);
417
+ }
418
+ ///////////////////////////////
419
+ /// compute root dir ///
420
+ ///////////////////////////////
421
+ // Compute common ancestor directory for all entry points
422
+ let rootDir;
423
+ if (tsconfigJson.rootDir) {
424
+ rootDir = path.resolve(tsconfigPath, tsconfigJson.rootDir);
425
+ }
426
+ else {
427
+ // compute rootDir from entrypoints
428
+ rootDir =
429
+ entryPoints.length > 0
430
+ ? entryPoints.reduce((common, entryPoint) => {
431
+ const entryDir = path.dirname(path.resolve(entryPoint));
432
+ const commonDir = path.resolve(common);
433
+ // Find the longest common path
434
+ const entryParts = entryDir.split(path.sep);
435
+ const commonParts = commonDir.split(path.sep);
436
+ let i = 0;
437
+ while (i < entryParts.length && i < commonParts.length && entryParts[i] === commonParts[i]) {
438
+ i++;
439
+ }
440
+ return commonParts.slice(0, i).join(path.sep) || path.sep;
441
+ }, path.dirname(path.resolve(entryPoints[0])))
442
+ : process.cwd();
443
+ }
444
+ const relRootDir = path.relative(pkgJsonDir, rootDir);
445
+ // Display resolved paths table
446
+ (0, utils_1.emojiLog)("🔧", "Resolved build paths:");
447
+ const pathRows = [["Location", "Resolved path"]];
448
+ // pathRows.push([
449
+ // "package.json",
450
+ // `./${path.relative(pkgJsonDir, packageJsonPath)}`,
451
+ // ]);
452
+ // pathRows.push(["tsconfig", `./${path.relative(pkgJsonDir, tsconfigPath)}`]);
453
+ pathRows.push(["rootDir", relRootDir ? `./${relRootDir}` : "."]);
454
+ pathRows.push(["outDir", relOutDir ? `./${relOutDir}` : "."]);
455
+ if (relDeclarationDir !== relOutDir) {
456
+ pathRows.push(["declarationDir", relDeclarationDir ? `./${relDeclarationDir}` : "."]);
457
+ }
458
+ console.log(" " +
459
+ (0, table_1.table)(pathRows, {
460
+ drawHorizontalLine: (lineIndex, rowCount) => {
461
+ return (lineIndex === 0 ||
462
+ lineIndex === 1 ||
463
+ // lineIndex === rowCount - 1 ||
464
+ lineIndex === rowCount);
465
+ },
466
+ })
467
+ .split("\n")
468
+ .join("\n ")
469
+ .trim());
470
+ const isTypeModule = pkgJson.type === "module";
471
+ if (isTypeModule) {
472
+ (0, utils_1.emojiLog)("🟨", `Package is an ES module (package.json#/type is "module")`);
473
+ }
474
+ else {
475
+ (0, utils_1.emojiLog)("🐢", `Package is a CommonJS module (${pkgJson.type === "commonjs" ? 'package.json#/type is "commonjs"' : 'package.json#/type not set to "module"'})`);
476
+ }
477
+ ///////////////////////////////
478
+ /// compile tsc ///
479
+ ///////////////////////////////
480
+ const uniqueEntryPoints = [...new Set(entryPoints)];
481
+ try {
482
+ if (isVerbose) {
483
+ (0, utils_1.emojiLog)("→", `Resolved entrypoints: ${(0, utils_1.formatForLog)(uniqueEntryPoints)}`);
484
+ (0, utils_1.emojiLog)("→", `Resolved compilerOptions: ${(0, utils_1.formatForLog)({
485
+ ...tsconfigJson,
486
+ module: ts.ModuleKind[tsconfigJson.module],
487
+ moduleResolution: ts.ModuleResolutionKind[tsconfigJson.moduleResolution],
488
+ target: ts.ScriptTarget[tsconfigJson.target],
489
+ })}`);
490
+ }
491
+ // Track all written files
492
+ const allWrittenFiles = [];
493
+ // CJS
494
+ (0, utils_1.emojiLog)("🧱", `Building CJS...${isTypeModule ? ` (rewriting .ts -> .cjs/.d.cts)` : ``}`);
495
+ const cjsFiles = await (0, utils_1.compileProject)({
496
+ configPath: tsconfigPath,
497
+ mode: isTypeModule ? "cts" : "ts",
498
+ verbose: isVerbose,
499
+ dryRun: isDryRun,
500
+ packageRoot: pkgJsonDir,
501
+ compilerOptions: {
502
+ ...tsconfigJson,
503
+ module: ts.ModuleKind.CommonJS,
504
+ moduleResolution: ts.ModuleResolutionKind.Node10,
505
+ outDir,
506
+ },
507
+ }, uniqueEntryPoints);
508
+ allWrittenFiles.push(...cjsFiles);
509
+ // ESM
510
+ (0, utils_1.emojiLog)("🧱", `Building ESM...${isTypeModule ? `` : ` (rewriting .ts -> .mjs/.d.mts)`}`);
511
+ const esmFiles = await (0, utils_1.compileProject)({
512
+ configPath: tsconfigPath,
513
+ mode: isTypeModule ? "ts" : "mts",
514
+ verbose: isVerbose,
515
+ dryRun: isDryRun,
516
+ packageRoot: pkgJsonDir,
517
+ compilerOptions: {
518
+ ...tsconfigJson,
519
+ module: ts.ModuleKind.ESNext,
520
+ moduleResolution: ts.ModuleResolutionKind.Bundler,
521
+ outDir,
522
+ },
523
+ }, uniqueEntryPoints);
524
+ allWrittenFiles.push(...esmFiles);
525
+ ///////////////////////////////////
526
+ /// display written files ///
527
+ ///////////////////////////////////
528
+ // Display files that were written or would be written (only in verbose mode)
529
+ if (isVerbose && allWrittenFiles.length > 0) {
530
+ (0, utils_1.emojiLog)("📜", `${isDryRun ? "[dryrun] " : ""}Writing files (${allWrittenFiles.length} total)...`);
531
+ // Sort files by relative path for consistent display
532
+ const sortedFiles = [...allWrittenFiles]
533
+ .map((file) => path.relative(pkgJsonDir, file))
534
+ .sort()
535
+ .map((relPath) => (relPath.startsWith(".") ? relPath : `./${relPath}`));
536
+ sortedFiles.forEach((file) => {
537
+ console.log(` ${file}`);
538
+ });
539
+ }
540
+ ///////////////////////////////
541
+ /// generate exports ///
542
+ ///////////////////////////////
543
+ // generate package.json exports
544
+ (0, utils_1.emojiLog)("📦", `${isDryRun ? "[dryrun] " : ""}Updating package.json#/exports...`);
545
+ // Generate exports based on zshy config
546
+ const newExports = {};
547
+ const sourceDialects = config.sourceDialects || [];
548
+ for (const [exportPath, sourcePath] of Object.entries(config.exports)) {
549
+ if (exportPath.includes("package.json")) {
550
+ newExports[exportPath] = sourcePath;
551
+ continue;
552
+ }
553
+ const absSourcePath = path.resolve(pkgJsonDir, sourcePath);
554
+ const relSourcePath = path.relative(rootDir, absSourcePath);
555
+ const absJsPath = path.resolve(outDir, relSourcePath);
556
+ const absDtsPath = path.resolve(declarationDir, relSourcePath);
557
+ const relJsPath = "./" + path.relative(pkgJsonDir, absJsPath);
558
+ const relDtsPath = "./" + path.relative(pkgJsonDir, absDtsPath);
559
+ if (typeof sourcePath === "string") {
560
+ if (sourcePath.endsWith("/*")) {
561
+ // Handle wildcard exports
562
+ newExports[exportPath] = {
563
+ types: relDtsPath,
564
+ import: relJsPath,
565
+ require: relJsPath,
566
+ };
567
+ for (const sd of sourceDialects) {
568
+ newExports[exportPath] = {
569
+ [sd]: sourcePath,
570
+ ...newExports[exportPath],
571
+ };
572
+ }
573
+ }
574
+ else if (isSourceFile(sourcePath)) {
575
+ const esmPath = removeExtension(relJsPath) + (isTypeModule ? `.js` : `.mjs`);
576
+ const cjsPath = removeExtension(relJsPath) + (isTypeModule ? `.cjs` : `.js`);
577
+ const dtsPath = removeExtension(relDtsPath) + (isTypeModule ? `.d.cts` : `.d.ts`); // ./
578
+ newExports[exportPath] = {
579
+ types: dtsPath,
580
+ import: esmPath,
581
+ require: cjsPath,
582
+ };
583
+ if (exportPath === ".") {
584
+ pkgJson.main = cjsPath;
585
+ pkgJson.module = esmPath;
586
+ pkgJson.types = dtsPath;
587
+ }
588
+ for (const sd of sourceDialects) {
589
+ newExports[exportPath] = {
590
+ [sd]: sourcePath,
591
+ ...newExports[exportPath],
592
+ };
593
+ }
594
+ }
595
+ else {
596
+ (0, utils_1.emojiLog)("❌", `Invalid entrypoint: ${sourcePath}`, "error");
597
+ process.exit();
598
+ }
599
+ }
600
+ }
601
+ if (isVerbose) {
602
+ (0, utils_1.emojiLog)("🔧", `Generated "exports": ${(0, utils_1.formatForLog)(newExports)}`);
603
+ }
604
+ ///////////////////////////////
605
+ /// generate bin ///
606
+ ///////////////////////////////
607
+ // Generate bin field based on zshy bin config
608
+ if (config.bin) {
609
+ (0, utils_1.emojiLog)("📦", `${isDryRun ? "[dryrun] " : ""}Updating package.json#/bin...`);
610
+ const newBin = {};
611
+ // Convert config.bin to object format for processing
612
+ const binEntries = typeof config.bin === "string" ? [[pkgJson.name, config.bin]] : Object.entries(config.bin);
613
+ for (const [binName, sourcePath] of binEntries) {
614
+ if (typeof sourcePath === "string" && isSourceFile(sourcePath)) {
615
+ const absSourcePath = path.resolve(pkgJsonDir, sourcePath);
616
+ const relSourcePath = path.relative(rootDir, absSourcePath);
617
+ const absJsPath = path.resolve(outDir, relSourcePath);
618
+ const relJsPath = "./" + path.relative(pkgJsonDir, absJsPath);
619
+ // Use CommonJS entrypoint for bin
620
+ const binPath = removeExtension(relJsPath) + (isTypeModule ? `.cjs` : `.js`);
621
+ newBin[binName] = binPath;
622
+ }
623
+ }
624
+ // If original config.bin was a string, output as string
625
+ if (typeof config.bin === "string") {
626
+ pkgJson.bin = Object.values(newBin)[0];
627
+ }
628
+ else {
629
+ // Output as object
630
+ pkgJson.bin = newBin;
631
+ }
632
+ }
633
+ if (isVerbose) {
634
+ (0, utils_1.emojiLog)("🔧", `Generated "bin": ${(0, utils_1.formatForLog)(pkgJson.bin)}`);
635
+ }
636
+ ///////////////////////////////
637
+ /// write pkg json ///
638
+ ///////////////////////////////
639
+ // Update package.json with new exports
640
+ pkgJson.exports = newExports;
641
+ if (isDryRun) {
642
+ (0, utils_1.emojiLog)("📦", "[dryrun] Skipping package.json modification");
643
+ }
644
+ else {
645
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkgJson, null, 2) + "\n");
646
+ }
647
+ if (isAttw) {
648
+ // run `@arethetypeswrong/cli --pack .` to check types
649
+ (0, utils_1.emojiLog)("🔍", "Checking types with @arethetypeswrong/cli...");
650
+ const { execFile } = await Promise.resolve().then(() => __importStar(require("node:child_process")));
651
+ const { promisify } = await Promise.resolve().then(() => __importStar(require("node:util")));
652
+ const execFileAsync = promisify(execFile);
653
+ const [cmd, ...args] = `${pmExec} @arethetypeswrong/cli --pack ${pkgJsonDir}`.split(" ");
654
+ console.dir([cmd, ...args], { depth: null });
655
+ let stdout = "";
656
+ let stderr = "";
657
+ let exitCode = 0;
658
+ try {
659
+ const result = await execFileAsync(cmd, args, {
660
+ cwd: pkgJsonDir,
661
+ encoding: "utf-8",
662
+ });
663
+ stdout = result.stdout;
664
+ stderr = result.stderr;
665
+ }
666
+ catch (error) {
667
+ stdout = error.stdout || "";
668
+ stderr = error.stderr || "";
669
+ exitCode = error.code || 1;
670
+ }
671
+ const output = stdout || stderr;
672
+ if (output) {
673
+ const indentedOutput = output
674
+ .split("\n")
675
+ .map((line) => ` ${line}`)
676
+ .join("\n");
677
+ if (exitCode === 0) {
678
+ console.log(indentedOutput);
679
+ }
680
+ else {
681
+ console.error(indentedOutput);
682
+ (0, utils_1.emojiLog)("⚠️", "ATTW found issues, but the build was not affected.", "warn");
683
+ }
684
+ }
685
+ }
686
+ (0, utils_1.emojiLog)("🎉", "Build complete! ✅");
687
+ }
688
+ catch (error) {
689
+ (0, utils_1.emojiLog)("❌", `Build failed: ${error}`, "error");
690
+ process.exit(1);
691
+ }
692
+ }
693
+ // Run the script
694
+ main().catch((error) => {
695
+ (0, utils_1.emojiLog)("❌", `Script failed: ${error}`, "error");
696
+ process.exit(1);
697
+ });