zshy 0.4.4 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -5,8 +5,9 @@ import glob from "fast-glob";
5
5
  import { table } from "table";
6
6
  import * as ts from "typescript";
7
7
  import { compileProject } from "./compile.js";
8
- import { emojiLog, formatForLog, isSourceFile, readTsconfig, relativePosix, removeExtension, toPosix, } from "./utils.js";
8
+ import { formatForLog, isSourceFile, isTestFile, log, readTsconfig, relativePosix, removeExtension, setSilent, toPosix, } from "./utils.js";
9
9
  export async function main() {
10
+ log.prefix = "» ";
10
11
  ///////////////////////////////////
11
12
  /// parse command line args ///
12
13
  ///////////////////////////////////
@@ -16,6 +17,7 @@ export async function main() {
16
17
  args = parseArgs({
17
18
  "--help": Boolean,
18
19
  "--verbose": Boolean,
20
+ "--silent": Boolean,
19
21
  "--project": String,
20
22
  "--dry-run": Boolean,
21
23
  "--fail-threshold": String,
@@ -27,7 +29,7 @@ export async function main() {
27
29
  }
28
30
  catch (error) {
29
31
  if (error instanceof Error) {
30
- emojiLog("❌", error.message, "error");
32
+ log.error(`❌ ${error.message}`);
31
33
  }
32
34
  console.error(`Use --help for usage information`);
33
35
  process.exit(1);
@@ -41,6 +43,7 @@ Options:
41
43
  -h, --help Show this help message
42
44
  -p, --project <path> Path to tsconfig.json file
43
45
  --verbose Enable verbose output
46
+ --silent Suppress all output
44
47
  --dry-run Don't write any files, just log what would be done
45
48
  --fail-threshold <threshold> When to exit with non-zero error code
46
49
  "error" (default)
@@ -51,6 +54,7 @@ Examples:
51
54
  zshy # Run build
52
55
  zshy --project ./tsconfig.build.json # Use specific tsconfig file (defaults to tsconfig.json)
53
56
  zshy --verbose # Enable verbose logging
57
+ zshy --silent # Suppress all output
54
58
  zshy --dry-run # Preview changes without writing files
55
59
  `);
56
60
  process.exit(0);
@@ -66,37 +70,50 @@ Examples:
66
70
  else {
67
71
  pmExec = "npx";
68
72
  }
69
- console.log(` ╔═══════════════════════════════════════════════╗`);
70
- console.log(` ║ zshy » the bundler-free TypeScript build tool ║`);
71
- console.log(` ╚═══════════════════════════════════════════════╝`);
72
- emojiLog("💎", "Starting build...");
73
+ // Validate that --verbose and --silent are not both passed
74
+ if (args["--verbose"] && args["--silent"]) {
75
+ log.error("❌ Cannot use both --verbose and --silent flags together");
76
+ process.exit(1);
77
+ }
78
+ // Set silent mode if --silent flag is passed
79
+ const isSilent = !!args["--silent"];
73
80
  const isVerbose = !!args["--verbose"];
81
+ setSilent(isSilent);
82
+ if (!isSilent) {
83
+ const originalPrefix = log.prefix;
84
+ log.prefix = undefined;
85
+ log.info(` ╔═══════════════════════════════════════════════╗`);
86
+ log.info(` ║ zshy » the bundler-free TypeScript build tool ║`);
87
+ log.info(` ╚═══════════════════════════════════════════════╝`);
88
+ log.prefix = originalPrefix;
89
+ log.info("Starting build...");
90
+ }
74
91
  const isDryRun = !!args["--dry-run"];
75
92
  const failThreshold = args["--fail-threshold"] || "error"; // Default to 'error'
76
93
  const isCjsInterop = true; // Enable CJS interop for testing
77
94
  // Validate that the threshold value is one of the allowed values
78
95
  if (failThreshold !== "never" && failThreshold !== "warn" && failThreshold !== "error") {
79
- emojiLog("❌", `Invalid value for --fail-threshold: "${failThreshold}". Valid values are "never", "warn", or "error"`, "error");
96
+ log.error(`❌ Invalid value for --fail-threshold: "${failThreshold}". Valid values are "never", "warn", or "error"`);
80
97
  process.exit(1);
81
98
  }
82
99
  const isAttw = false; // args["--attw"];
83
100
  if (isVerbose) {
84
- emojiLog("ℹ️", "Verbose mode enabled");
85
- emojiLog("📦", `Detected package manager: ${pmExec}`);
101
+ log.info("Verbose mode enabled");
102
+ log.info(`Detected package manager: ${pmExec}`);
86
103
  }
87
104
  if (isDryRun) {
88
- emojiLog("🔍", "Dry run mode enabled. No files will be written or modified.");
105
+ log.info("Dry run mode enabled. No files will be written or modified.");
89
106
  }
90
107
  // Display message about fail threshold setting
91
108
  if (isVerbose) {
92
109
  if (failThreshold === "never") {
93
- emojiLog("ℹ️", "Build will always succeed regardless of errors or warnings");
110
+ log.info("Build will always succeed regardless of errors or warnings");
94
111
  }
95
112
  else if (failThreshold === "warn") {
96
- emojiLog("⚠️", "Build will fail on warnings or errors");
113
+ log.warn("Build will fail on warnings or errors");
97
114
  }
98
115
  else {
99
- emojiLog("ℹ️", "Build will fail only on errors (default)");
116
+ log.info("Build will fail only on errors (default)");
100
117
  }
101
118
  }
102
119
  ///////////////////////////////////
@@ -114,7 +131,7 @@ Examples:
114
131
  currentDir = path.dirname(currentDir);
115
132
  }
116
133
  if (!fs.existsSync(packageJsonPath)) {
117
- emojiLog("❌", "package.json not found in current directory or any parent directories", "error");
134
+ log.error("❌ package.json not found in current directory or any parent directories");
118
135
  process.exit(1);
119
136
  }
120
137
  // read package.json and extract the "zshy" exports config
@@ -133,8 +150,10 @@ Examples:
133
150
  const pkgJsonDir = path.dirname(packageJsonPath);
134
151
  const pkgJsonRelPath = relativePosix(pkgJsonDir, packageJsonPath);
135
152
  // print project root
136
- emojiLog("⚙️", `Detected project root: ${pkgJsonDir}`);
137
- emojiLog("📦", `Reading package.json from ./${pkgJsonRelPath}`);
153
+ if (!isSilent) {
154
+ log.info(`Detected project root: ${pkgJsonDir}`);
155
+ log.info(`Reading package.json from ./${pkgJsonRelPath}`);
156
+ }
138
157
  /////////////////////////////////
139
158
  /// parse zshy config ///
140
159
  /////////////////////////////////
@@ -142,7 +161,7 @@ Examples:
142
161
  const CONFIG_KEY = "zshy";
143
162
  let rawConfig;
144
163
  if (!pkgJson[CONFIG_KEY]) {
145
- emojiLog("❌", `No "${CONFIG_KEY}" key found in package.json`, "error");
164
+ log.error(`❌ No "${CONFIG_KEY}" key found in package.json`);
146
165
  process.exit(1);
147
166
  }
148
167
  if (typeof pkgJson[CONFIG_KEY] === "string") {
@@ -156,11 +175,11 @@ Examples:
156
175
  rawConfig.exports = { ".": rawConfig.exports };
157
176
  }
158
177
  else if (typeof rawConfig.exports === "undefined") {
159
- emojiLog("❌", `Missing "exports" key in package.json#/${CONFIG_KEY}`, "error");
178
+ log.error(`❌ Missing "exports" key in package.json#/${CONFIG_KEY}`);
160
179
  process.exit(1);
161
180
  }
162
181
  else if (typeof rawConfig.exports !== "object") {
163
- emojiLog("❌", `Invalid "exports" key in package.json#/${CONFIG_KEY}`, "error");
182
+ log.error(`❌ Invalid "exports" key in package.json#/${CONFIG_KEY}`);
164
183
  process.exit(1);
165
184
  }
166
185
  // Validate bin field if present
@@ -172,7 +191,7 @@ Examples:
172
191
  // Object format is valid
173
192
  }
174
193
  else {
175
- emojiLog("❌", `Invalid "bin" key in package.json#/${CONFIG_KEY}, expected string or object`, "error");
194
+ log.error(`❌ Invalid "bin" key in package.json#/${CONFIG_KEY}, expected string or object`);
176
195
  process.exit(1);
177
196
  }
178
197
  }
@@ -182,31 +201,31 @@ Examples:
182
201
  // const { import: importCondition, require: requireCondition, ...rest } = config.conditions;
183
202
  for (const [condition, value] of Object.entries(rawConfig.conditions)) {
184
203
  if (value !== "esm" && value !== "cjs" && value !== "src") {
185
- emojiLog("❌", `Invalid condition value "${value}" for "${condition}" in package.json#/${CONFIG_KEY}/conditions. Valid values are "esm", "cjs", "src", or null`, "error");
204
+ log.error(`❌ Invalid condition value "${value}" for "${condition}" in package.json#/${CONFIG_KEY}/conditions. Valid values are "esm", "cjs", "src", or null`);
186
205
  process.exit(1);
187
206
  }
188
207
  }
189
208
  }
190
209
  else {
191
- emojiLog("❌", `Invalid "conditions" key in package.json#/${CONFIG_KEY}, expected object`, "error");
210
+ log.error(`❌ Invalid "conditions" key in package.json#/${CONFIG_KEY}, expected object`);
192
211
  process.exit(1);
193
212
  }
194
213
  }
195
214
  }
196
215
  else if (typeof pkgJson[CONFIG_KEY] === "undefined") {
197
- emojiLog("❌", `Missing "${CONFIG_KEY}" key in package.json`, "error");
216
+ log.error(`❌ Missing "${CONFIG_KEY}" key in package.json`);
198
217
  process.exit(1);
199
218
  }
200
219
  else {
201
- emojiLog("❌", `Invalid "${CONFIG_KEY}" key in package.json, expected string or object`, "error");
220
+ log.error(`❌ Invalid "${CONFIG_KEY}" key in package.json, expected string or object`);
202
221
  process.exit(1);
203
222
  }
204
223
  if (isVerbose) {
205
- emojiLog("🔧", `Parsed zshy config: ${formatForLog(rawConfig)}`);
224
+ log.info(`Parsed zshy config: ${formatForLog(rawConfig)}`);
206
225
  }
207
226
  // Check for deprecated sourceDialects
208
227
  if ("sourceDialects" in rawConfig) {
209
- emojiLog("❌", 'The "sourceDialects" option is no longer supported. Use "conditions" instead to configure custom export conditions.', "error");
228
+ log.error('❌ The "sourceDialects" option is no longer supported. Use "conditions" instead to configure custom export conditions.');
210
229
  process.exit(1);
211
230
  }
212
231
  const config = { ...rawConfig };
@@ -220,13 +239,13 @@ Examples:
220
239
  const cjsConditions = Object.entries(config.conditions).filter(([_, value]) => value === "cjs");
221
240
  if (cjsConditions.length > 0) {
222
241
  const conditionNames = cjsConditions.map(([name]) => name).join(", ");
223
- emojiLog("❌", `CJS is disabled (cjs: false) but the following conditions are set to "cjs": ${conditionNames}. Either enable CJS or change these conditions.`, "error");
242
+ log.error(`❌ CJS is disabled (cjs: false) but the following conditions are set to "cjs": ${conditionNames}. Either enable CJS or change these conditions.`);
224
243
  process.exit(1);
225
244
  }
226
245
  }
227
246
  // Validate that if cjs is disabled, package.json type must be "module"
228
247
  if (config.cjs === false && pkgJson.type !== "module") {
229
- emojiLog("❌", `CJS is disabled (cjs: false) but package.json#/type is not set to "module". When disabling CommonJS builds, you must set "type": "module" in your package.json.`, "error");
248
+ log.error(`❌ CJS is disabled (cjs: false) but package.json#/type is not set to "module". When disabling CommonJS builds, you must set "type": "module" in your package.json.`);
230
249
  process.exit(1);
231
250
  }
232
251
  ///////////////////////////
@@ -239,7 +258,7 @@ Examples:
239
258
  const resolvedProjectPath = path.resolve(process.cwd(), args["--project"]);
240
259
  if (fs.existsSync(resolvedProjectPath)) {
241
260
  if (fs.statSync(resolvedProjectPath).isDirectory()) {
242
- emojiLog("❌", `--project must point to a tsconfig.json file, not a directory: ${resolvedProjectPath}`, "error");
261
+ log.error(`--project must point to a tsconfig.json file, not a directory: ${resolvedProjectPath}`);
243
262
  process.exit(1);
244
263
  }
245
264
  else {
@@ -248,7 +267,7 @@ Examples:
248
267
  }
249
268
  }
250
269
  else {
251
- emojiLog("❌", `tsconfig.json file not found: ${resolvedProjectPath}`, "error");
270
+ log.error(`tsconfig.json file not found: ${resolvedProjectPath}`);
252
271
  process.exit(1);
253
272
  }
254
273
  }
@@ -257,7 +276,7 @@ Examples:
257
276
  const resolvedProjectPath = path.resolve(pkgJsonDir, config.tsconfig);
258
277
  if (fs.existsSync(resolvedProjectPath)) {
259
278
  if (fs.statSync(resolvedProjectPath).isDirectory()) {
260
- emojiLog("❌", `zshy.tsconfig must point to a tsconfig.json file, not a directory: ${resolvedProjectPath}`, "error");
279
+ log.error(`zshy.tsconfig must point to a tsconfig.json file, not a directory: ${resolvedProjectPath}`);
261
280
  process.exit(1);
262
281
  }
263
282
  else {
@@ -266,7 +285,7 @@ Examples:
266
285
  }
267
286
  }
268
287
  else {
269
- emojiLog("❌", `Tsconfig file not found: ${resolvedProjectPath}`, "error");
288
+ log.error(`Tsconfig file not found: ${resolvedProjectPath}`);
270
289
  process.exit(1);
271
290
  }
272
291
  }
@@ -277,10 +296,12 @@ Examples:
277
296
  const _parsedConfig = readTsconfig(tsconfigPath);
278
297
  if (!fs.existsSync(tsconfigPath)) {
279
298
  // Check if tsconfig.json exists
280
- emojiLog("❌", `tsconfig.json not found at ${toPosix(path.resolve(tsconfigPath))}`, "error");
299
+ log.error(`❌ tsconfig.json not found at ${toPosix(path.resolve(tsconfigPath))}`);
281
300
  process.exit(1);
282
301
  }
283
- emojiLog("📁", `Reading tsconfig from ./${relativePosix(pkgJsonDir, tsconfigPath)}`);
302
+ if (!isSilent) {
303
+ log.info(`Reading tsconfig from ./${relativePosix(pkgJsonDir, tsconfigPath)}`);
304
+ }
284
305
  // if (_parsedConfig.rootDir) {
285
306
  // console.error(
286
307
  // `❌ rootDir is determined from your set of entrypoints; you can remove it from your tsconfig.json.`,
@@ -314,17 +335,17 @@ Examples:
314
335
  };
315
336
  if (relOutDir === "") {
316
337
  if (!pkgJson.files) {
317
- 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.');
338
+ log.info('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.');
318
339
  pkgJson.files = ["**/*.js", "**/*.mjs", "**/*.cjs", "**/*.d.ts", "**/*.d.mts", "**/*.d.cts"];
319
340
  }
320
341
  else {
321
- emojiLog(`⚠️`, `You\'re building your code to the project root. This means your compiled files will be generated alongside your source files.
322
- Ensure that your "files" in package.json excludes TypeScript source files, or your users may experience .d.ts resolution issues in some environments:
342
+ log.info(`You\'re building your code to the project root. This means your compiled files will be generated alongside your source files.
343
+ Ensure that your "files" in package.json does not include TypeScript source files, or your users may experience .d.ts resolution issues in some environments:
323
344
  "files": ["**/*.js", "**/*.mjs", "**/*.cjs", "**/*.d.ts", "**/*.d.mts", "**/*.d.cts"]`);
324
345
  }
325
346
  }
326
347
  else if (!pkgJson.files) {
327
- emojiLog("⚠️", `The "files" key is missing in package.json. Setting to "${relOutDir}".`);
348
+ log.warn(`The "files" key is missing in package.json. Setting to "${relOutDir}".`);
328
349
  pkgJson.files = [relOutDir];
329
350
  if (relOutDir !== relDeclarationDir) {
330
351
  pkgJson.files.push(relDeclarationDir);
@@ -334,7 +355,9 @@ Examples:
334
355
  /// extract entry points ///
335
356
  /////////////////////////////////
336
357
  // Extract entry points from zshy exports config
337
- emojiLog("➡️", "Determining entrypoints...");
358
+ if (!isSilent) {
359
+ log.info("Determining entrypoints...");
360
+ }
338
361
  const entryPoints = [];
339
362
  const assetEntrypoints = [];
340
363
  const rows = [["Subpath", "Entrypoint"]];
@@ -349,13 +372,13 @@ Examples:
349
372
  cleanExportPath = pkgJson.name + "/" + exportPath.slice(2);
350
373
  }
351
374
  else {
352
- emojiLog("⚠️", `Invalid subpath export "${exportPath}" — should start with "./"`, "warn");
375
+ log.warn(`Invalid subpath export "${exportPath}" — should start with "./"`);
353
376
  process.exit(1);
354
377
  }
355
378
  if (typeof sourcePath === "string") {
356
379
  if (sourcePath.includes("*")) {
357
380
  if (!sourcePath.endsWith("/*") && !sourcePath.endsWith("/**/*")) {
358
- emojiLog("❌", `Wildcard paths should end with /* or /**/* (for deep globs): ${sourcePath}`, "error");
381
+ log.error(`❌ Wildcard paths should end with /* or /**/* (for deep globs): ${sourcePath}`);
359
382
  process.exit(1);
360
383
  }
361
384
  let pattern;
@@ -368,16 +391,23 @@ Examples:
368
391
  pattern = sourcePath.slice(0, -2) + "/*.{ts,tsx,mts,cts}";
369
392
  }
370
393
  if (isVerbose) {
371
- emojiLog("🔍", `Matching glob: ${pattern}`);
394
+ log.info(`Matching glob: ${pattern}`);
372
395
  }
373
396
  const wildcardFiles = await glob(pattern, {
374
397
  ignore: ["**/*.d.ts", "**/*.d.mts", "**/*.d.cts"],
375
398
  cwd: pkgJsonDir,
376
399
  });
377
- entryPoints.push(...wildcardFiles);
378
- rows.push([`"${cleanExportPath}"`, `${sourcePath} (${wildcardFiles.length} matches)`]);
400
+ // Filter out test files (__tests__ directories, .test.*, .spec.*)
401
+ const filteredFiles = wildcardFiles.filter((file) => !isTestFile(file));
402
+ entryPoints.push(...filteredFiles);
403
+ rows.push([`"${cleanExportPath}"`, `${sourcePath} (${filteredFiles.length} matches)`]);
379
404
  }
380
405
  else if (isSourceFile(sourcePath)) {
406
+ // Skip test files even if explicitly specified
407
+ if (isTestFile(sourcePath)) {
408
+ log.warn(`Skipping test file: ${sourcePath}`);
409
+ continue;
410
+ }
381
411
  entryPoints.push(sourcePath);
382
412
  rows.push([`"${cleanExportPath}"`, sourcePath]);
383
413
  }
@@ -393,32 +423,47 @@ Examples:
393
423
  if (typeof config.bin === "string") {
394
424
  // Single bin entry
395
425
  if (isSourceFile(config.bin)) {
396
- entryPoints.push(config.bin);
397
- rows.push([`bin:${pkgJson.name}`, config.bin]);
426
+ if (isTestFile(config.bin)) {
427
+ log.warn(`Skipping test file in bin: ${config.bin}`);
428
+ }
429
+ else {
430
+ entryPoints.push(config.bin);
431
+ rows.push([`bin:${pkgJson.name}`, config.bin]);
432
+ }
398
433
  }
399
434
  }
400
435
  else {
401
436
  // Multiple bin entries
402
437
  for (const [binName, sourcePath] of Object.entries(config.bin)) {
403
438
  if (typeof sourcePath === "string" && isSourceFile(sourcePath)) {
404
- entryPoints.push(sourcePath);
405
- rows.push([`bin:${binName}`, sourcePath]);
439
+ if (isTestFile(sourcePath)) {
440
+ log.warn(`Skipping test file in bin: ${sourcePath}`);
441
+ }
442
+ else {
443
+ entryPoints.push(sourcePath);
444
+ rows.push([`bin:${binName}`, sourcePath]);
445
+ }
406
446
  }
407
447
  }
408
448
  }
409
449
  }
410
- console.log(" " +
411
- table(rows, {
412
- drawHorizontalLine: (lineIndex, rowCount) => {
413
- return (lineIndex === 0 ||
414
- lineIndex === 1 ||
415
- // lineIndex === rowCount - 1 ||
416
- lineIndex === rowCount);
417
- },
418
- })
419
- .split("\n")
420
- .join("\n ")
421
- .trim());
450
+ if (!isSilent) {
451
+ const originalPrefix = log.prefix;
452
+ log.prefix = undefined;
453
+ log.info(" " +
454
+ table(rows, {
455
+ drawHorizontalLine: (lineIndex, rowCount) => {
456
+ return (lineIndex === 0 ||
457
+ lineIndex === 1 ||
458
+ // lineIndex === rowCount - 1 ||
459
+ lineIndex === rowCount);
460
+ },
461
+ })
462
+ .split("\n")
463
+ .join("\n ")
464
+ .trim());
465
+ log.prefix = originalPrefix;
466
+ }
422
467
  // disallow .mts and .cts files
423
468
  // if (entryPoints.some((ep) => ep.endsWith(".mts") || ep.endsWith(".cts"))) {
424
469
  // emojiLog(
@@ -429,7 +474,7 @@ Examples:
429
474
  // process.exit(1);
430
475
  // }
431
476
  if (entryPoints.length === 0) {
432
- emojiLog("❌", "No entry points found matching the specified patterns in package.json#/zshy exports or bin", "error");
477
+ log.error("❌ No entry points found matching the specified patterns in package.json#/zshy exports or bin");
433
478
  process.exit(1);
434
479
  }
435
480
  ///////////////////////////////
@@ -462,49 +507,62 @@ Examples:
462
507
  //////////////////////////////////
463
508
  /// display resolved paths ///
464
509
  //////////////////////////////////
465
- emojiLog("🔧", "Resolved build paths:");
510
+ if (!isSilent) {
511
+ log.info("Resolved build paths:");
512
+ }
466
513
  const pathRows = [["Location", "Resolved path"]];
467
514
  pathRows.push(["rootDir", relRootDir ? `./${relRootDir}` : "."]);
468
515
  pathRows.push(["outDir", relOutDir ? `./${relOutDir}` : "."]);
469
516
  if (relDeclarationDir !== relOutDir) {
470
517
  pathRows.push(["declarationDir", relDeclarationDir ? `./${relDeclarationDir}` : "."]);
471
518
  }
472
- console.log(" " +
473
- table(pathRows, {
474
- drawHorizontalLine: (lineIndex, rowCount) => {
475
- return (lineIndex === 0 ||
476
- lineIndex === 1 ||
477
- // lineIndex === rowCount - 1 ||
478
- lineIndex === rowCount);
479
- },
480
- })
481
- .split("\n")
482
- .join("\n ")
483
- .trim());
484
- const isTypeModule = pkgJson.type === "module";
485
- if (isTypeModule) {
486
- emojiLog("🟨", `Package is an ES module (package.json#/type is "module")`);
519
+ if (!isSilent) {
520
+ const originalPrefix = log.prefix;
521
+ log.prefix = undefined;
522
+ log.info(" " +
523
+ table(pathRows, {
524
+ drawHorizontalLine: (lineIndex, rowCount) => {
525
+ return (lineIndex === 0 ||
526
+ lineIndex === 1 ||
527
+ // lineIndex === rowCount - 1 ||
528
+ lineIndex === rowCount);
529
+ },
530
+ })
531
+ .split("\n")
532
+ .join("\n ")
533
+ .trim());
534
+ log.prefix = originalPrefix;
487
535
  }
488
- else {
489
- emojiLog("🐢", `Package is a CommonJS module (${pkgJson.type === "commonjs" ? 'package.json#/type is "commonjs"' : 'package.json#/type not set to "module"'})`);
536
+ const isTypeModule = pkgJson.type === "module";
537
+ if (!isSilent) {
538
+ if (isTypeModule) {
539
+ log.info(`Package is an ES module (package.json#/type is "module")`);
540
+ }
541
+ else {
542
+ log.info(`Package is a CommonJS module (${pkgJson.type === "commonjs" ? 'package.json#/type is "commonjs"' : 'package.json#/type not set to "module"'})`);
543
+ }
490
544
  }
491
545
  //////////////////////////////////////////////
492
546
  /// clean up outDir and declarationDir ///
493
547
  //////////////////////////////////////////////
494
548
  const prefix = isDryRun ? "[dryrun] " : "";
495
549
  if (relRootDir.startsWith(relOutDir)) {
496
- emojiLog("🗑️", `${prefix}Skipping cleanup of outDir as it contains source files`);
550
+ if (!isSilent) {
551
+ log.info(`${prefix}Skipping cleanup of outDir as it contains source files`);
552
+ }
497
553
  }
498
554
  else {
499
555
  // source files are in the outDir, so skip cleanup
500
556
  // clean up outDir and declarationDir
501
- emojiLog("🗑️", `${prefix}Cleaning up outDir...`);
557
+ if (!isSilent) {
558
+ log.info(`${prefix}Cleaning up outDir...`);
559
+ }
502
560
  if (!isDryRun) {
503
561
  fs.rmSync(outDir, { recursive: true, force: true });
504
562
  // // print success message in verbose mode
505
563
  if (isVerbose) {
506
564
  if (fs.existsSync(outDir)) {
507
- emojiLog("❌", `Failed to clean up outDir: ${relOutDir}. Directory still exists.`, "error");
565
+ log.error(`❌ Failed to clean up outDir: ${relOutDir}. Directory still exists.`);
508
566
  }
509
567
  }
510
568
  }
@@ -513,16 +571,20 @@ Examples:
513
571
  // already done
514
572
  }
515
573
  else if (relRootDir.startsWith(relDeclarationDir)) {
516
- emojiLog("🗑️", `${prefix}Skipping cleanup of declarationDir as it contains source files`);
574
+ if (!isSilent) {
575
+ log.info(`${prefix}Skipping cleanup of declarationDir as it contains source files`);
576
+ }
517
577
  }
518
578
  else {
519
- emojiLog("🗑️", `${prefix}Cleaning up declarationDir...`);
579
+ if (!isSilent) {
580
+ log.info(`${prefix}Cleaning up declarationDir...`);
581
+ }
520
582
  if (!isDryRun) {
521
583
  fs.rmSync(declarationDir, { recursive: true, force: true });
522
584
  // // print success message in verbose mode
523
585
  if (isVerbose) {
524
586
  if (fs.existsSync(declarationDir)) {
525
- emojiLog("❌", `Failed to clean up declarationDir: ${relDeclarationDir}. Directory still exists.`, "error");
587
+ log.error(`❌ Failed to clean up declarationDir: ${relDeclarationDir}. Directory still exists.`);
526
588
  }
527
589
  }
528
590
  }
@@ -533,8 +595,8 @@ Examples:
533
595
  const uniqueEntryPoints = [...new Set(entryPoints)];
534
596
  // try {
535
597
  if (isVerbose) {
536
- emojiLog("→", `Resolved entrypoints: ${formatForLog(uniqueEntryPoints)}`);
537
- emojiLog("→", `Resolved compilerOptions: ${formatForLog({
598
+ log.info(`Resolved entrypoints: ${formatForLog(uniqueEntryPoints)}`);
599
+ log.info(`Resolved compilerOptions: ${formatForLog({
538
600
  ...tsconfigJson,
539
601
  module: ts.ModuleKind[tsconfigJson.module],
540
602
  moduleResolution: ts.ModuleResolutionKind[tsconfigJson.moduleResolution],
@@ -552,7 +614,9 @@ Examples:
552
614
  const skipCjs = config.cjs === false;
553
615
  // CJS
554
616
  if (!skipCjs) {
555
- emojiLog("🧱", `Building CJS...${isTypeModule ? ` (rewriting .ts -> .cjs/.d.cts)` : ``}`);
617
+ if (!isSilent) {
618
+ log.info(`Building CJS...${isTypeModule ? ` (rewriting .ts -> .cjs/.d.cts)` : ``}`);
619
+ }
556
620
  await compileProject({
557
621
  configPath: tsconfigPath,
558
622
  ext: isTypeModule ? "cjs" : "js",
@@ -571,10 +635,14 @@ Examples:
571
635
  }, uniqueEntryPoints, buildContext);
572
636
  }
573
637
  else {
574
- emojiLog("⏭️", "Skipping CJS build (cjs: false)");
638
+ if (!isSilent) {
639
+ log.info("Skipping CJS build (cjs: false)");
640
+ }
575
641
  }
576
642
  // ESM
577
- emojiLog("🧱", `Building ESM...${isTypeModule ? `` : ` (rewriting .ts -> .mjs/.d.mts)`}`);
643
+ if (!isSilent) {
644
+ log.info(`Building ESM...${isTypeModule ? `` : ` (rewriting .ts -> .mjs/.d.mts)`}`);
645
+ }
578
646
  await compileProject({
579
647
  configPath: tsconfigPath,
580
648
  ext: isTypeModule ? "js" : "mjs",
@@ -596,14 +664,16 @@ Examples:
596
664
  ///////////////////////////////////
597
665
  // Copy asset entrypoints to output directory
598
666
  if (assetEntrypoints.length > 0) {
599
- emojiLog("📄", `${prefix}Copying ${assetEntrypoints.length} asset${assetEntrypoints.length === 1 ? "" : "s"}...`);
667
+ if (!isSilent) {
668
+ log.info(`${prefix}Copying ${assetEntrypoints.length} asset${assetEntrypoints.length === 1 ? "" : "s"}...`);
669
+ }
600
670
  for (const { sourcePath } of assetEntrypoints) {
601
671
  const sourceFile = path.resolve(pkgJsonDir, sourcePath);
602
672
  const relativePath = path.relative(rootDir, path.resolve(pkgJsonDir, sourcePath));
603
673
  const destFile = path.resolve(outDir, relativePath);
604
674
  const destDir = path.dirname(destFile);
605
675
  if (!fs.existsSync(sourceFile)) {
606
- emojiLog("⚠️", `Asset not found: ${sourcePath}`, "warn");
676
+ log.warn(`Asset not found: ${sourcePath}`);
607
677
  continue;
608
678
  }
609
679
  if (!isDryRun) {
@@ -615,7 +685,7 @@ Examples:
615
685
  if (isVerbose) {
616
686
  const relativeSource = toPosix(path.relative(pkgJsonDir, sourceFile));
617
687
  const relativeDest = toPosix(path.relative(pkgJsonDir, destFile));
618
- emojiLog("📋", `${isDryRun ? "[dryrun] " : ""}Copied asset: ./${relativeSource} → ./${relativeDest}`);
688
+ log.info(`${isDryRun ? "[dryrun] " : ""}Copied asset: ./${relativeSource} → ./${relativeDest}`);
619
689
  }
620
690
  }
621
691
  }
@@ -624,26 +694,34 @@ Examples:
624
694
  ///////////////////////////////////
625
695
  // Display files that were written or would be written (only in verbose mode)
626
696
  if (isVerbose && buildContext.writtenFiles.size > 0) {
627
- emojiLog("📜", `${prefix}Writing files (${buildContext.writtenFiles.size} total)...`);
697
+ log.info(`${prefix}Writing files (${buildContext.writtenFiles.size} total)...`);
628
698
  // Sort files by relative path for consistent display
629
699
  const sortedFiles = [...buildContext.writtenFiles]
630
700
  .map((file) => relativePosix(pkgJsonDir, file))
631
701
  .sort()
632
702
  .map((relPath) => (relPath.startsWith(".") ? relPath : `./${relPath}`));
703
+ // Temporarily disable prefix for individual file listings
704
+ const originalPrefix = log.prefix;
705
+ log.prefix = undefined;
633
706
  sortedFiles.forEach((file) => {
634
- console.log(` ${file}`);
707
+ log.info(` ${file}`);
635
708
  });
709
+ log.prefix = originalPrefix;
636
710
  }
637
711
  ///////////////////////////////
638
712
  /// generate exports ///
639
713
  ///////////////////////////////
640
714
  // generate package.json exports
641
715
  if (config.noEdit) {
642
- emojiLog("📦", "[noedit] Skipping modification of package.json");
716
+ if (!isSilent) {
717
+ log.info("[noedit] Skipping modification of package.json");
718
+ }
643
719
  }
644
720
  else {
645
721
  // Generate exports based on zshy config
646
- emojiLog("📦", `${prefix}Updating package.json...`);
722
+ if (!isSilent) {
723
+ log.info(`${prefix}Updating package.json...`);
724
+ }
647
725
  const newExports = {};
648
726
  if (config.exports) {
649
727
  for (const [exportPath, sourcePath] of Object.entries(config.exports)) {
@@ -662,7 +740,7 @@ Examples:
662
740
  // Handle wildcard exports
663
741
  const finalExportPath = exportPath;
664
742
  if (finalExportPath.includes("**")) {
665
- emojiLog("❌", `Export keys cannot contain "**": ${finalExportPath}`, "error");
743
+ log.error(`❌ Export keys cannot contain "**": ${finalExportPath}`);
666
744
  process.exit(1);
667
745
  }
668
746
  // Convert deep glob patterns to simple wildcard patterns in the final export
@@ -693,8 +771,13 @@ Examples:
693
771
  }
694
772
  // Add standard conditions
695
773
  exportObj.types = relDtsPath;
696
- exportObj.import = relJsPath;
697
- if (!skipCjs) {
774
+ if (skipCjs) {
775
+ // ESM-only: use default condition instead of import
776
+ exportObj.default = relJsPath;
777
+ }
778
+ else {
779
+ // Dual CJS/ESM: use import and require
780
+ exportObj.import = relJsPath;
698
781
  exportObj.require = relJsPath;
699
782
  }
700
783
  newExports[finalExportPath] = exportObj;
@@ -723,8 +806,13 @@ Examples:
723
806
  }
724
807
  // Add standard conditions
725
808
  exportObj.types = dtsPath;
726
- exportObj.import = esmPath;
727
- if (!skipCjs) {
809
+ if (skipCjs) {
810
+ // ESM-only: use default condition instead of import
811
+ exportObj.default = esmPath;
812
+ }
813
+ else {
814
+ // Dual CJS/ESM: use import and require
815
+ exportObj.import = esmPath;
728
816
  exportObj.require = cjsPath;
729
817
  }
730
818
  newExports[exportPath] = exportObj;
@@ -740,9 +828,9 @@ Examples:
740
828
  pkgJson.types = dtsPath;
741
829
  }
742
830
  if (isVerbose) {
743
- emojiLog("🔧", `Setting "main": ${formatForLog(cjsPath)}`);
744
- emojiLog("🔧", `Setting "module": ${formatForLog(esmPath)}`);
745
- emojiLog("🔧", `Setting "types": ${formatForLog(dtsPath)}`);
831
+ log.info(`Setting "main": ${formatForLog(cjsPath)}`);
832
+ log.info(`Setting "module": ${formatForLog(esmPath)}`);
833
+ log.info(`Setting "types": ${formatForLog(dtsPath)}`);
746
834
  }
747
835
  }
748
836
  }
@@ -772,15 +860,15 @@ Examples:
772
860
  pkgJson.types = relAssetPath;
773
861
  }
774
862
  if (isVerbose) {
775
- emojiLog("🔧", `Setting "main": ${formatForLog(relAssetPath)}`);
776
- emojiLog("🔧", `Setting "module": ${formatForLog(relAssetPath)}`);
777
- emojiLog("🔧", `Setting "types": ${formatForLog(relAssetPath)}`);
863
+ log.info(`Setting "main": ${formatForLog(relAssetPath)}`);
864
+ log.info(`Setting "module": ${formatForLog(relAssetPath)}`);
865
+ log.info(`Setting "types": ${formatForLog(relAssetPath)}`);
778
866
  }
779
867
  }
780
868
  }
781
869
  pkgJson.exports = newExports;
782
870
  if (isVerbose) {
783
- emojiLog("🔧", `Setting "exports": ${formatForLog(newExports)}`);
871
+ log.info(`Setting "exports": ${formatForLog(newExports)}`);
784
872
  }
785
873
  }
786
874
  ///////////////////////////////
@@ -812,14 +900,14 @@ Examples:
812
900
  pkgJson.bin = newBin;
813
901
  }
814
902
  if (isVerbose) {
815
- emojiLog("🔧", `Setting "bin": ${formatForLog(pkgJson.bin)}`);
903
+ log.info(`Setting "bin": ${formatForLog(pkgJson.bin)}`);
816
904
  }
817
905
  }
818
906
  if (isDryRun) {
819
907
  ///////////////////////////////
820
908
  /// write pkg json ///
821
909
  ///////////////////////////////
822
- emojiLog("📦", "[dryrun] Skipping package.json modification");
910
+ log.info("[dryrun] Skipping package.json modification");
823
911
  }
824
912
  else {
825
913
  fs.writeFileSync(packageJsonPath, JSON.stringify(pkgJson, null, indent) + "\n");
@@ -827,7 +915,9 @@ Examples:
827
915
  }
828
916
  if (isAttw) {
829
917
  // run `@arethetypeswrong/cli --pack .` to check types
830
- emojiLog("🔍", "Checking types with @arethetypeswrong/cli...");
918
+ if (!isSilent) {
919
+ log.info("Checking types with @arethetypeswrong/cli...");
920
+ }
831
921
  const { execFile } = await import("node:child_process");
832
922
  const { promisify } = await import("node:util");
833
923
  const execFileAsync = promisify(execFile);
@@ -856,39 +946,41 @@ Examples:
856
946
  .map((line) => ` ${line}`)
857
947
  .join("\n");
858
948
  if (exitCode === 0) {
859
- console.log(indentedOutput);
949
+ log.info(indentedOutput);
860
950
  }
861
951
  else {
862
- console.error(indentedOutput);
863
- emojiLog("⚠️", "ATTW found issues, but the build was not affected.", "warn");
952
+ log.error(indentedOutput);
953
+ log.warn("ATTW found issues, but the build was not affected.");
864
954
  }
865
955
  }
866
956
  }
867
957
  // Report total compilation results
868
958
  if (buildContext.errorCount > 0 || buildContext.warningCount > 0) {
869
- emojiLog("📊", `Compilation finished with ${buildContext.errorCount} error${buildContext.errorCount === 1 ? "" : "s"} and ${buildContext.warningCount} warning${buildContext.warningCount === 1 ? "" : "s"}`);
959
+ log.info(`Compilation finished with ${buildContext.errorCount} error${buildContext.errorCount === 1 ? "" : "s"} and ${buildContext.warningCount} warning${buildContext.warningCount === 1 ? "" : "s"}`);
870
960
  // Apply threshold rules for exit code
871
961
  if (failThreshold !== "never" && buildContext.errorCount > 0) {
872
962
  // Both 'warn' and 'error' thresholds cause failure on errors
873
- emojiLog("❌", `Build completed with errors`, "error");
963
+ log.error("❌ Build completed with errors");
874
964
  process.exit(1);
875
965
  }
876
966
  else if (failThreshold === "warn" && buildContext.warningCount > 0) {
877
967
  // Only 'warn' threshold causes failure on warnings
878
- emojiLog("⚠️", `Build completed with warnings (exiting with error due to --fail-threshold=warn)`, "warn");
968
+ log.warn(`Build completed with warnings (exiting with error due to --fail-threshold=warn)`);
879
969
  process.exit(1);
880
970
  }
881
971
  else if (buildContext.errorCount > 0) {
882
972
  // If we got here with errors, we're in 'never' mode
883
- emojiLog("⚠️", `Build completed with errors (continuing due to --fail-threshold=never)`, "warn");
973
+ log.warn(`Build completed with errors (continuing due to --fail-threshold=never)`);
884
974
  }
885
975
  else {
886
976
  // Just warnings and not failing on them
887
- emojiLog("🎉", `Build complete with warnings`);
977
+ log.info(`Build complete with warnings`);
888
978
  }
889
979
  }
890
980
  else {
891
- emojiLog("🎉", "Build complete! ✅");
981
+ if (!isSilent) {
982
+ log.info("Build complete! ✅");
983
+ }
892
984
  }
893
985
  }
894
986
  //# sourceMappingURL=main.js.map