@knighted/duel 3.1.0 → 3.1.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/README.md CHANGED
@@ -90,6 +90,10 @@ Note, there is a slight performance penalty since your project needs to be copie
90
90
 
91
91
  This feature is still a work in progress regarding transforming `exports` when targeting an ES module build (relies on [`@knighted/module`](https://github.com/knightedcodemonkey/module)).
92
92
 
93
+ #### Pre-`tsc` transform (TypeScript 58658)
94
+
95
+ When you pass `--modules`, `duel` copies your sources and runs [`@knighted/module`](https://github.com/knightedcodemonkey/module) **before** `tsc` so the transformed files no longer trigger TypeScript’s asymmetrical module-global errors (see [TypeScript#58658](https://github.com/microsoft/TypeScript/issues/58658)). No extra setup is needed: `--modules` is the pre-`tsc` mitigation.
96
+
93
97
  ## Options
94
98
 
95
99
  The available options are limited, because you should define most of them inside your project's `tsconfig.json` file.
@@ -122,7 +126,7 @@ These are definitely edge cases, and would only really come up if your project m
122
126
 
123
127
  - This is going to work best if your CJS-first project uses file extensions in _relative_ specifiers. This is completely acceptable in CJS projects, and [required in ESM projects](https://nodejs.org/api/esm.html#import-specifiers). This package makes no attempt to rewrite bare specifiers, or remap any relative specifiers to a directory index.
124
128
 
125
- - Unfortunately, `tsc` doesn't support [dual packages](https://nodejs.org/api/packages.html#dual-commonjses-module-packages) completely. One instance of unexpected behavior is when the compiler throws errors for ES module globals when running a dual CJS build, but not for the inverse case, despite both causing runtime errors in Node.js. See the [open issue](https://github.com/microsoft/TypeScript/issues/58658). You can circumvent this with `duel` by using the `--modules` option if your project uses module globals such as `import.meta` properties or `__dirname`, `__filename`, etc. in a CommonJS project.
129
+ - Unfortunately, `tsc` doesn't support [dual packages](https://nodejs.org/api/packages.html#dual-commonjses-module-packages) completely. For mitigation details, see the pre-`tsc` transform note above (`--modules`).
126
130
 
127
131
  - If running `duel` with your project's package.json file open in your editor, you may temporarily see the content replaced. This is because `duel` dynamically creates a new package.json using the `type` necessary for the dual build. Your original package.json will be restored after the build completes.
128
132
 
package/dist/cjs/duel.cjs CHANGED
@@ -258,6 +258,7 @@ const duel = async (args) => {
258
258
  const writeOptions = {
259
259
  target,
260
260
  rewriteSpecifier,
261
+ transformSyntax: 'globals-only',
261
262
  ...(outFilename === filename ? { inPlace: true } : { out: outFilename }),
262
263
  };
263
264
  await (0, module_1.transform)(filename, writeOptions);
@@ -267,7 +268,7 @@ const duel = async (args) => {
267
268
  }
268
269
  };
269
270
  const logSuccess = start => {
270
- (0, util_js_1.log)(`Successfully created a dual ${isCjsBuild ? 'CJS' : 'ESM'} build in ${Math.round(node_perf_hooks_1.performance.now() - start)}ms.`);
271
+ (0, util_js_1.logSuccess)(`Successfully created a dual ${isCjsBuild ? 'CJS' : 'ESM'} build in ${Math.round(node_perf_hooks_1.performance.now() - start)}ms.`);
271
272
  };
272
273
  (0, util_js_1.log)('Starting primary build...');
273
274
  let success = false;
@@ -314,7 +315,7 @@ const duel = async (args) => {
314
315
  await (0, module_1.transform)(file, {
315
316
  out: file,
316
317
  target: isCjsBuild ? 'commonjs' : 'module',
317
- transformSyntax: false,
318
+ transformSyntax: 'globals-only',
318
319
  });
319
320
  }
320
321
  }
package/dist/cjs/init.cjs CHANGED
@@ -55,14 +55,15 @@ const init = async (args) => {
55
55
  return false;
56
56
  }
57
57
  if (parsed.help) {
58
- (0, util_js_1.log)('Usage: duel [options]\n');
59
- (0, util_js_1.log)('Options:');
60
- (0, util_js_1.log)("--project, -p [path] \t Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.");
61
- (0, util_js_1.log)('--pkg-dir, -k [path] \t The directory to start looking for a package.json file. Defaults to --project directory.');
62
- (0, util_js_1.log)('--modules, -m \t\t Transform module globals for dual build target. Defaults to false.');
63
- (0, util_js_1.log)('--dirs, -d \t\t Output both builds to directories inside of outDir. [esm, cjs].');
64
- (0, util_js_1.log)('--exports, -e \t Generate package.json exports. Values: wildcard | dir | name.');
65
- (0, util_js_1.log)('--help, -h \t\t Print this message.');
58
+ const bare = { bare: true };
59
+ (0, util_js_1.log)('Usage: duel [options]\n', 'info', bare);
60
+ (0, util_js_1.log)('Options:', 'info', bare);
61
+ (0, util_js_1.log)("--project, -p [path] \t Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.", 'info', bare);
62
+ (0, util_js_1.log)('--pkg-dir, -k [path] \t The directory to start looking for a package.json file. Defaults to --project directory.', 'info', bare);
63
+ (0, util_js_1.log)('--modules, -m \t\t Transform module globals for dual build target. Defaults to false.', 'info', bare);
64
+ (0, util_js_1.log)('--dirs, -d \t\t Output both builds to directories inside of outDir. [esm, cjs].', 'info', bare);
65
+ (0, util_js_1.log)('--exports, -e \t Generate package.json exports. Values: wildcard | dir | name.', 'info', bare);
66
+ (0, util_js_1.log)('--help, -h \t\t Print this message.', 'info', bare);
66
67
  }
67
68
  else {
68
69
  const { project, 'target-extension': targetExt, 'pkg-dir': pkgDir, modules, dirs, exports: exportsOpt, } = parsed;
package/dist/cjs/util.cjs CHANGED
@@ -1,17 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getCompileFiles = exports.getRealPathAsFileUrl = exports.logError = exports.log = void 0;
3
+ exports.getCompileFiles = exports.getRealPathAsFileUrl = exports.logWarn = exports.logSuccess = exports.logError = exports.log = void 0;
4
4
  const node_url_1 = require("node:url");
5
5
  const promises_1 = require("node:fs/promises");
6
6
  const node_child_process_1 = require("node:child_process");
7
7
  const node_process_1 = require("node:process");
8
8
  const node_os_1 = require("node:os");
9
- const log = (color = '\x1b[30m', msg = '') => {
9
+ const COLORS = {
10
+ reset: '\x1b[0m',
11
+ info: '\x1b[36m',
12
+ success: '\x1b[32m',
13
+ warn: '\x1b[33m',
14
+ error: '\x1b[31m',
15
+ };
16
+ const log = (msg = '', level = 'info', opts = {}) => {
17
+ const { bare = false } = opts;
18
+ const palette = {
19
+ info: COLORS.info,
20
+ success: COLORS.success,
21
+ warn: COLORS.warn,
22
+ error: COLORS.error,
23
+ };
24
+ const badge = {
25
+ success: '[✓]',
26
+ warn: '[!]',
27
+ error: '[x]',
28
+ info: '[i]',
29
+ }[level];
30
+ const color = palette[level] ?? COLORS.info;
31
+ const prefix = !bare && badge ? `${badge} ` : '';
10
32
  // eslint-disable-next-line no-console
11
- console.log(`${color}%s\x1b[0m`, msg);
33
+ console.log(`${color}${prefix}%s${COLORS.reset}`, msg);
12
34
  };
13
35
  exports.log = log;
14
- const logError = log.bind(null, '\x1b[31m');
36
+ const logSuccess = msg => log(msg, 'success');
37
+ exports.logSuccess = logSuccess;
38
+ const logWarn = msg => log(msg, 'warn');
39
+ exports.logWarn = logWarn;
40
+ const logError = msg => log(msg, 'error');
15
41
  exports.logError = logError;
16
42
  const getRealPathAsFileUrl = async (path) => {
17
43
  const realPath = await (0, promises_1.realpath)(path);
@@ -1,4 +1,6 @@
1
- export function log(color?: string, msg?: string): void;
2
- export const logError: (msg?: string | undefined) => void;
1
+ export function log(msg?: string, level?: string, opts?: {}): void;
2
+ export function logError(msg: any): void;
3
+ export function logSuccess(msg: any): void;
4
+ export function logWarn(msg: any): void;
3
5
  export function getRealPathAsFileUrl(path: any): Promise<string>;
4
6
  export function getCompileFiles(tscBinPath: any, wd?: string): string[];
package/dist/esm/duel.js CHANGED
@@ -9,7 +9,7 @@ import { glob } from 'glob';
9
9
  import { findUp } from 'find-up';
10
10
  import { transform } from '@knighted/module';
11
11
  import { init } from './init.js';
12
- import { getRealPathAsFileUrl, getCompileFiles, logError, log } from './util.js';
12
+ import { getRealPathAsFileUrl, getCompileFiles, log, logError, logSuccess as logSuccessBadge, } from './util.js';
13
13
  const stripKnownExt = path => {
14
14
  return path.replace(/(\.d\.(?:ts|mts|cts)|\.(?:mjs|cjs|js))$/, '');
15
15
  };
@@ -255,6 +255,7 @@ const duel = async (args) => {
255
255
  const writeOptions = {
256
256
  target,
257
257
  rewriteSpecifier,
258
+ transformSyntax: 'globals-only',
258
259
  ...(outFilename === filename ? { inPlace: true } : { out: outFilename }),
259
260
  };
260
261
  await transform(filename, writeOptions);
@@ -264,7 +265,7 @@ const duel = async (args) => {
264
265
  }
265
266
  };
266
267
  const logSuccess = start => {
267
- log(`Successfully created a dual ${isCjsBuild ? 'CJS' : 'ESM'} build in ${Math.round(performance.now() - start)}ms.`);
268
+ logSuccessBadge(`Successfully created a dual ${isCjsBuild ? 'CJS' : 'ESM'} build in ${Math.round(performance.now() - start)}ms.`);
268
269
  };
269
270
  log('Starting primary build...');
270
271
  let success = false;
@@ -311,7 +312,7 @@ const duel = async (args) => {
311
312
  await transform(file, {
312
313
  out: file,
313
314
  target: isCjsBuild ? 'commonjs' : 'module',
314
- transformSyntax: false,
315
+ transformSyntax: 'globals-only',
315
316
  });
316
317
  }
317
318
  }
package/dist/esm/init.js CHANGED
@@ -52,14 +52,15 @@ const init = async (args) => {
52
52
  return false;
53
53
  }
54
54
  if (parsed.help) {
55
- log('Usage: duel [options]\n');
56
- log('Options:');
57
- log("--project, -p [path] \t Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.");
58
- log('--pkg-dir, -k [path] \t The directory to start looking for a package.json file. Defaults to --project directory.');
59
- log('--modules, -m \t\t Transform module globals for dual build target. Defaults to false.');
60
- log('--dirs, -d \t\t Output both builds to directories inside of outDir. [esm, cjs].');
61
- log('--exports, -e \t Generate package.json exports. Values: wildcard | dir | name.');
62
- log('--help, -h \t\t Print this message.');
55
+ const bare = { bare: true };
56
+ log('Usage: duel [options]\n', 'info', bare);
57
+ log('Options:', 'info', bare);
58
+ log("--project, -p [path] \t Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.", 'info', bare);
59
+ log('--pkg-dir, -k [path] \t The directory to start looking for a package.json file. Defaults to --project directory.', 'info', bare);
60
+ log('--modules, -m \t\t Transform module globals for dual build target. Defaults to false.', 'info', bare);
61
+ log('--dirs, -d \t\t Output both builds to directories inside of outDir. [esm, cjs].', 'info', bare);
62
+ log('--exports, -e \t Generate package.json exports. Values: wildcard | dir | name.', 'info', bare);
63
+ log('--help, -h \t\t Print this message.', 'info', bare);
63
64
  }
64
65
  else {
65
66
  const { project, 'target-extension': targetExt, 'pkg-dir': pkgDir, modules, dirs, exports: exportsOpt, } = parsed;
@@ -1,4 +1,6 @@
1
- export function log(color?: string, msg?: string): void;
2
- export const logError: (msg?: string | undefined) => void;
1
+ export function log(msg?: string, level?: string, opts?: {}): void;
2
+ export function logError(msg: any): void;
3
+ export function logSuccess(msg: any): void;
4
+ export function logWarn(msg: any): void;
3
5
  export function getRealPathAsFileUrl(path: any): Promise<string>;
4
6
  export function getCompileFiles(tscBinPath: any, wd?: string): string[];
package/dist/esm/util.js CHANGED
@@ -3,11 +3,35 @@ import { realpath } from 'node:fs/promises';
3
3
  import { spawnSync } from 'node:child_process';
4
4
  import { cwd, platform } from 'node:process';
5
5
  import { EOL } from 'node:os';
6
- const log = (color = '\x1b[30m', msg = '') => {
6
+ const COLORS = {
7
+ reset: '\x1b[0m',
8
+ info: '\x1b[36m',
9
+ success: '\x1b[32m',
10
+ warn: '\x1b[33m',
11
+ error: '\x1b[31m',
12
+ };
13
+ const log = (msg = '', level = 'info', opts = {}) => {
14
+ const { bare = false } = opts;
15
+ const palette = {
16
+ info: COLORS.info,
17
+ success: COLORS.success,
18
+ warn: COLORS.warn,
19
+ error: COLORS.error,
20
+ };
21
+ const badge = {
22
+ success: '[✓]',
23
+ warn: '[!]',
24
+ error: '[x]',
25
+ info: '[i]',
26
+ }[level];
27
+ const color = palette[level] ?? COLORS.info;
28
+ const prefix = !bare && badge ? `${badge} ` : '';
7
29
  // eslint-disable-next-line no-console
8
- console.log(`${color}%s\x1b[0m`, msg);
30
+ console.log(`${color}${prefix}%s${COLORS.reset}`, msg);
9
31
  };
10
- const logError = log.bind(null, '\x1b[31m');
32
+ const logSuccess = msg => log(msg, 'success');
33
+ const logWarn = msg => log(msg, 'warn');
34
+ const logError = msg => log(msg, 'error');
11
35
  const getRealPathAsFileUrl = async (path) => {
12
36
  const realPath = await realpath(path);
13
37
  const asFileUrl = pathToFileURL(realPath).href;
@@ -24,4 +48,4 @@ const getCompileFiles = (tscBinPath, wd = cwd()) => {
24
48
  .split(EOL)
25
49
  .filter(path => !/node_modules|^$/.test(path));
26
50
  };
27
- export { log, logError, getRealPathAsFileUrl, getCompileFiles };
51
+ export { log, logError, logSuccess, logWarn, getRealPathAsFileUrl, getCompileFiles };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knighted/duel",
3
- "version": "3.1.0",
3
+ "version": "3.1.1",
4
4
  "description": "TypeScript dual packages.",
5
5
  "type": "module",
6
6
  "main": "dist/esm/duel.js",
@@ -67,7 +67,6 @@
67
67
  },
68
68
  "devDependencies": {
69
69
  "@eslint/js": "^9.39.1",
70
- "@knighted/module": "^1.0.0-rc.2",
71
70
  "@tsconfig/recommended": "^1.0.10",
72
71
  "@types/node": "^24.10.1",
73
72
  "c8": "^10.1.3",
@@ -83,6 +82,7 @@
83
82
  "vite": "^7.2.4"
84
83
  },
85
84
  "dependencies": {
85
+ "@knighted/module": "^1.0.0-rc.6",
86
86
  "find-up": "^8.0.0",
87
87
  "get-tsconfig": "^4.13.0",
88
88
  "glob": "^13.0.0",