@knighted/duel 3.2.3 → 3.2.5

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
@@ -53,7 +53,7 @@ And then running it:
53
53
  npm run build
54
54
  ```
55
55
 
56
- If everything worked, you should have an ESM build inside of `dist` and a CJS build inside of `dist/cjs`. Now you can update your [`exports`](https://nodejs.org/api/packages.html#exports) to match the build output.
56
+ If everything worked, you should have an ESM build inside of `dist` and a CJS build inside of `dist/cjs`. You can manually update your [`exports`](https://nodejs.org/api/packages.html#exports) to match the build output, or run `duel --exports <mode>` to generate them automatically (see [docs/exports.md](docs/exports.md)).
57
57
 
58
58
  It should work similarly for a CJS-first project. Except, your package.json file would use `"type": "commonjs"` and the dual build directory is in `dist/esm`.
59
59
 
package/dist/cjs/duel.cjs CHANGED
@@ -27,7 +27,7 @@ const getSubpath = (mode, relFromRoot) => {
27
27
  }
28
28
  if (mode === 'dir') {
29
29
  const last = segments.at(-1);
30
- return last ? `./${last}` : null;
30
+ return last ? `./${last}/*` : null;
31
31
  }
32
32
  if (mode === 'wildcard') {
33
33
  const first = segments[0];
@@ -36,7 +36,8 @@ const getSubpath = (mode, relFromRoot) => {
36
36
  return null;
37
37
  };
38
38
  const handleErrorAndExit = message => {
39
- const exitCode = Number(message);
39
+ const parsed = parseInt(message, 10);
40
+ const exitCode = Number.isNaN(parsed) ? 1 : parsed;
40
41
  (0, util_js_1.logError)('Compilation errors found.');
41
42
  process.exit(exitCode);
42
43
  };
@@ -56,6 +57,17 @@ const generateExports = async (options) => {
56
57
  if (esmRootPosix.startsWith(`${cjsRootPosix}/`)) {
57
58
  cjsIgnore.push(`${esmRootPosix}/**`);
58
59
  }
60
+ const toWildcardValue = value => {
61
+ const dir = node_path_1.posix.dirname(value);
62
+ const file = node_path_1.posix.basename(value);
63
+ const dtsMatch = file.match(/(\.d\.(?:ts|mts|cts))$/i);
64
+ if (dtsMatch) {
65
+ const ext = dtsMatch[1];
66
+ return dir === '.' ? `./*${ext}` : `${dir}/*${ext}`;
67
+ }
68
+ const ext = node_path_1.posix.extname(file);
69
+ return dir === '.' ? `./*${ext}` : `${dir}/*${ext}`;
70
+ };
59
71
  const recordPath = (kind, filePath, root) => {
60
72
  const relPkg = toPosix((0, node_path_1.relative)(pkgDir, filePath));
61
73
  const relFromRoot = toPosix((0, node_path_1.relative)(root, filePath));
@@ -65,18 +77,19 @@ const generateExports = async (options) => {
65
77
  baseEntry[kind] = withDot;
66
78
  baseMap.set(baseKey, baseEntry);
67
79
  const subpath = getSubpath(mode, relFromRoot);
80
+ const useWildcard = subpath?.includes('*');
68
81
  if (kind === 'types') {
69
82
  const mappedSubpath = baseToSubpath.get(baseKey);
70
83
  if (mappedSubpath) {
71
84
  const subEntry = subpathMap.get(mappedSubpath) ?? {};
72
- subEntry.types = withDot;
85
+ subEntry.types = useWildcard ? toWildcardValue(withDot) : withDot;
73
86
  subpathMap.set(mappedSubpath, subEntry);
74
87
  }
75
88
  return;
76
89
  }
77
90
  if (subpath && subpath !== '.') {
78
91
  const subEntry = subpathMap.get(subpath) ?? {};
79
- subEntry[kind] = withDot;
92
+ subEntry[kind] = useWildcard ? toWildcardValue(withDot) : withDot;
80
93
  subpathMap.set(subpath, subEntry);
81
94
  baseToSubpath.set(baseKey, subpath);
82
95
  }
@@ -148,9 +161,10 @@ const generateExports = async (options) => {
148
161
  exportsMap[subpath] = out;
149
162
  }
150
163
  }
151
- if (!exportsMap['.'] && baseMap.size) {
152
- const [subpath, entry] = subpathMap.entries().next().value ?? [];
153
- if (entry) {
164
+ if (!exportsMap['.']) {
165
+ const firstNonWildcard = [...subpathMap.entries()].find(([key]) => !key.includes('*'));
166
+ if (firstNonWildcard) {
167
+ const [subpath, entry] = firstNonWildcard;
154
168
  const out = {};
155
169
  if (entry.types) {
156
170
  out.types = entry.types;
@@ -169,7 +183,9 @@ const generateExports = async (options) => {
169
183
  }
170
184
  if (Object.keys(out).length) {
171
185
  exportsMap['.'] = out;
172
- exportsMap[subpath] ??= out;
186
+ if (!exportsMap[subpath]) {
187
+ exportsMap[subpath] = out;
188
+ }
173
189
  }
174
190
  }
175
191
  }
@@ -186,10 +202,10 @@ const duel = async (args) => {
186
202
  if (ctx) {
187
203
  const { projectDir, tsconfig, configPath, modules, dirs, transformSyntax, pkg, exports: exportsOpt, } = ctx;
188
204
  const tsc = await (0, find_up_1.findUp)(async (dir) => {
189
- const tscBin = (0, node_path_1.join)(dir, 'node_modules', '.bin', 'tsc');
205
+ const candidate = (0, node_path_1.join)(dir, 'node_modules', 'typescript', 'bin', 'tsc');
190
206
  try {
191
- await (0, promises_1.access)(tscBin);
192
- return tscBin;
207
+ await (0, promises_1.access)(candidate);
208
+ return (0, node_path_1.resolve)(candidate);
193
209
  }
194
210
  catch {
195
211
  /* continue */
@@ -197,8 +213,10 @@ const duel = async (args) => {
197
213
  }, { cwd: projectDir });
198
214
  const runBuild = (project, outDir) => {
199
215
  return new Promise((resolve, reject) => {
200
- const args = outDir ? ['-p', project, '--outDir', outDir] : ['-p', project];
201
- const build = (0, node_child_process_1.spawn)(tsc, args, { stdio: 'inherit', shell: node_process_1.platform === 'win32' });
216
+ const args = outDir
217
+ ? [tsc, '-p', project, '--outDir', outDir]
218
+ : [tsc, '-p', project];
219
+ const build = (0, node_child_process_1.spawn)(process.execPath, args, { stdio: 'inherit' });
202
220
  build.on('exit', code => {
203
221
  if (code > 0) {
204
222
  return reject(new Error(code));
package/dist/cjs/util.cjs CHANGED
@@ -45,10 +45,9 @@ const getRealPathAsFileUrl = async (path) => {
45
45
  return asFileUrl;
46
46
  };
47
47
  exports.getRealPathAsFileUrl = getRealPathAsFileUrl;
48
- const getCompileFiles = (tscBinPath, wd = (0, node_process_1.cwd)()) => {
49
- const { stdout } = (0, node_child_process_1.spawnSync)(tscBinPath, ['--listFilesOnly'], {
48
+ const getCompileFiles = (tscPath, wd = (0, node_process_1.cwd)()) => {
49
+ const { stdout } = (0, node_child_process_1.spawnSync)(process.execPath, [tscPath, '--listFilesOnly'], {
50
50
  cwd: wd,
51
- shell: node_process_1.platform === 'win32',
52
51
  });
53
52
  // Exclude node_modules and empty strings.
54
53
  return stdout
@@ -3,4 +3,4 @@ export function logError(msg: any): void;
3
3
  export function logSuccess(msg: any): void;
4
4
  export function logWarn(msg: any): void;
5
5
  export function getRealPathAsFileUrl(path: any): Promise<string>;
6
- export function getCompileFiles(tscBinPath: any, wd?: string): string[];
6
+ export function getCompileFiles(tscPath: any, wd?: string): string[];
package/dist/esm/duel.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { argv, platform } from 'node:process';
3
- import { join, dirname, resolve, relative, parse as parsePath } from 'node:path';
2
+ import { argv } from 'node:process';
3
+ import { join, dirname, resolve, relative, parse as parsePath, posix } from 'node:path';
4
4
  import { spawn } from 'node:child_process';
5
5
  import { writeFile, rm, rename, mkdir, cp, access, readFile } from 'node:fs/promises';
6
6
  import { randomBytes } from 'node:crypto';
@@ -24,7 +24,7 @@ const getSubpath = (mode, relFromRoot) => {
24
24
  }
25
25
  if (mode === 'dir') {
26
26
  const last = segments.at(-1);
27
- return last ? `./${last}` : null;
27
+ return last ? `./${last}/*` : null;
28
28
  }
29
29
  if (mode === 'wildcard') {
30
30
  const first = segments[0];
@@ -33,7 +33,8 @@ const getSubpath = (mode, relFromRoot) => {
33
33
  return null;
34
34
  };
35
35
  const handleErrorAndExit = message => {
36
- const exitCode = Number(message);
36
+ const parsed = parseInt(message, 10);
37
+ const exitCode = Number.isNaN(parsed) ? 1 : parsed;
37
38
  logError('Compilation errors found.');
38
39
  process.exit(exitCode);
39
40
  };
@@ -53,6 +54,17 @@ const generateExports = async (options) => {
53
54
  if (esmRootPosix.startsWith(`${cjsRootPosix}/`)) {
54
55
  cjsIgnore.push(`${esmRootPosix}/**`);
55
56
  }
57
+ const toWildcardValue = value => {
58
+ const dir = posix.dirname(value);
59
+ const file = posix.basename(value);
60
+ const dtsMatch = file.match(/(\.d\.(?:ts|mts|cts))$/i);
61
+ if (dtsMatch) {
62
+ const ext = dtsMatch[1];
63
+ return dir === '.' ? `./*${ext}` : `${dir}/*${ext}`;
64
+ }
65
+ const ext = posix.extname(file);
66
+ return dir === '.' ? `./*${ext}` : `${dir}/*${ext}`;
67
+ };
56
68
  const recordPath = (kind, filePath, root) => {
57
69
  const relPkg = toPosix(relative(pkgDir, filePath));
58
70
  const relFromRoot = toPosix(relative(root, filePath));
@@ -62,18 +74,19 @@ const generateExports = async (options) => {
62
74
  baseEntry[kind] = withDot;
63
75
  baseMap.set(baseKey, baseEntry);
64
76
  const subpath = getSubpath(mode, relFromRoot);
77
+ const useWildcard = subpath?.includes('*');
65
78
  if (kind === 'types') {
66
79
  const mappedSubpath = baseToSubpath.get(baseKey);
67
80
  if (mappedSubpath) {
68
81
  const subEntry = subpathMap.get(mappedSubpath) ?? {};
69
- subEntry.types = withDot;
82
+ subEntry.types = useWildcard ? toWildcardValue(withDot) : withDot;
70
83
  subpathMap.set(mappedSubpath, subEntry);
71
84
  }
72
85
  return;
73
86
  }
74
87
  if (subpath && subpath !== '.') {
75
88
  const subEntry = subpathMap.get(subpath) ?? {};
76
- subEntry[kind] = withDot;
89
+ subEntry[kind] = useWildcard ? toWildcardValue(withDot) : withDot;
77
90
  subpathMap.set(subpath, subEntry);
78
91
  baseToSubpath.set(baseKey, subpath);
79
92
  }
@@ -145,9 +158,10 @@ const generateExports = async (options) => {
145
158
  exportsMap[subpath] = out;
146
159
  }
147
160
  }
148
- if (!exportsMap['.'] && baseMap.size) {
149
- const [subpath, entry] = subpathMap.entries().next().value ?? [];
150
- if (entry) {
161
+ if (!exportsMap['.']) {
162
+ const firstNonWildcard = [...subpathMap.entries()].find(([key]) => !key.includes('*'));
163
+ if (firstNonWildcard) {
164
+ const [subpath, entry] = firstNonWildcard;
151
165
  const out = {};
152
166
  if (entry.types) {
153
167
  out.types = entry.types;
@@ -166,7 +180,9 @@ const generateExports = async (options) => {
166
180
  }
167
181
  if (Object.keys(out).length) {
168
182
  exportsMap['.'] = out;
169
- exportsMap[subpath] ??= out;
183
+ if (!exportsMap[subpath]) {
184
+ exportsMap[subpath] = out;
185
+ }
170
186
  }
171
187
  }
172
188
  }
@@ -183,10 +199,10 @@ const duel = async (args) => {
183
199
  if (ctx) {
184
200
  const { projectDir, tsconfig, configPath, modules, dirs, transformSyntax, pkg, exports: exportsOpt, } = ctx;
185
201
  const tsc = await findUp(async (dir) => {
186
- const tscBin = join(dir, 'node_modules', '.bin', 'tsc');
202
+ const candidate = join(dir, 'node_modules', 'typescript', 'bin', 'tsc');
187
203
  try {
188
- await access(tscBin);
189
- return tscBin;
204
+ await access(candidate);
205
+ return resolve(candidate);
190
206
  }
191
207
  catch {
192
208
  /* continue */
@@ -194,8 +210,10 @@ const duel = async (args) => {
194
210
  }, { cwd: projectDir });
195
211
  const runBuild = (project, outDir) => {
196
212
  return new Promise((resolve, reject) => {
197
- const args = outDir ? ['-p', project, '--outDir', outDir] : ['-p', project];
198
- const build = spawn(tsc, args, { stdio: 'inherit', shell: platform === 'win32' });
213
+ const args = outDir
214
+ ? [tsc, '-p', project, '--outDir', outDir]
215
+ : [tsc, '-p', project];
216
+ const build = spawn(process.execPath, args, { stdio: 'inherit' });
199
217
  build.on('exit', code => {
200
218
  if (code > 0) {
201
219
  return reject(new Error(code));
@@ -3,4 +3,4 @@ export function logError(msg: any): void;
3
3
  export function logSuccess(msg: any): void;
4
4
  export function logWarn(msg: any): void;
5
5
  export function getRealPathAsFileUrl(path: any): Promise<string>;
6
- export function getCompileFiles(tscBinPath: any, wd?: string): string[];
6
+ export function getCompileFiles(tscPath: any, wd?: string): string[];
package/dist/esm/util.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { pathToFileURL } from 'node:url';
2
2
  import { realpath } from 'node:fs/promises';
3
3
  import { spawnSync } from 'node:child_process';
4
- import { cwd, platform } from 'node:process';
4
+ import { cwd } from 'node:process';
5
5
  import { EOL } from 'node:os';
6
6
  const COLORS = {
7
7
  reset: '\x1b[0m',
@@ -37,10 +37,9 @@ const getRealPathAsFileUrl = async (path) => {
37
37
  const asFileUrl = pathToFileURL(realPath).href;
38
38
  return asFileUrl;
39
39
  };
40
- const getCompileFiles = (tscBinPath, wd = cwd()) => {
41
- const { stdout } = spawnSync(tscBinPath, ['--listFilesOnly'], {
40
+ const getCompileFiles = (tscPath, wd = cwd()) => {
41
+ const { stdout } = spawnSync(process.execPath, [tscPath, '--listFilesOnly'], {
42
42
  cwd: wd,
43
- shell: platform === 'win32',
44
43
  });
45
44
  // Exclude node_modules and empty strings.
46
45
  return stdout
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knighted/duel",
3
- "version": "3.2.3",
3
+ "version": "3.2.5",
4
4
  "description": "TypeScript dual packages.",
5
5
  "type": "module",
6
6
  "main": "dist/esm/duel.js",
@@ -25,7 +25,7 @@
25
25
  "lint": "eslint src/*.js test/*.js",
26
26
  "test:integration": "node --test --test-reporter=spec test/integration.js",
27
27
  "test:monorepos": "node --test --test-reporter=spec test/monorepos.js",
28
- "test": "c8 --reporter=text --reporter=text-summary --reporter=lcov node --test --test-reporter=spec test/integration.js test/monorepos.js",
28
+ "test": "c8 --reporter=text --reporter=text-summary --reporter=lcov node --trace-deprecation --test --test-reporter=spec test/integration.js test/monorepos.js",
29
29
  "build": "node src/duel.js --dirs --mode globals",
30
30
  "prepack": "npm run build",
31
31
  "prepare": "husky"
@@ -70,6 +70,7 @@
70
70
  "@tsconfig/recommended": "^1.0.10",
71
71
  "@types/node": "^24.10.1",
72
72
  "c8": "^10.1.3",
73
+ "cross-spawn": "^7.0.6",
73
74
  "eslint": "^9.39.1",
74
75
  "eslint-plugin-n": "^17.23.1",
75
76
  "globals": "^16.3.0",