@knighted/duel 2.0.0 → 2.1.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/README.md +4 -6
- package/dist/cjs/init.cjs +9 -24
- package/dist/cjs/init.d.cts +10 -1
- package/dist/esm/init.d.ts +10 -1
- package/dist/esm/init.js +10 -22
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ This feature is still a work in progress regarding transforming `exports` when t
|
|
|
89
89
|
The available options are limited, because you should define most of them inside your project's `tsconfig.json` file.
|
|
90
90
|
|
|
91
91
|
- `--project, -p` The path to the project's configuration file. Defaults to `tsconfig.json`.
|
|
92
|
-
- `--pkg-dir, -k` The directory to start looking for a package.json file. Defaults to
|
|
92
|
+
- `--pkg-dir, -k` The directory to start looking for a package.json file. Defaults to `--project` dir.
|
|
93
93
|
- `--modules, -m` Transform module globals for dual build target. Defaults to false.
|
|
94
94
|
- `--dirs, -d` Outputs both builds to directories inside of `outDir`. Defaults to `false`.
|
|
95
95
|
|
|
@@ -100,7 +100,7 @@ Usage: duel [options]
|
|
|
100
100
|
|
|
101
101
|
Options:
|
|
102
102
|
--project, -p [path] Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.
|
|
103
|
-
--pkg-dir, -k [path] The directory to start looking for a package.json file. Defaults to
|
|
103
|
+
--pkg-dir, -k [path] The directory to start looking for a package.json file. Defaults to --project directory.
|
|
104
104
|
--modules, -m Transform module globals for dual build target. Defaults to false.
|
|
105
105
|
--dirs, -d Output both builds to directories inside of outDir. [esm, cjs].
|
|
106
106
|
--help, -h Print this message.
|
|
@@ -112,14 +112,12 @@ These are definitely edge cases, and would only really come up if your project m
|
|
|
112
112
|
|
|
113
113
|
- 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.
|
|
114
114
|
|
|
115
|
-
- Unfortunately,
|
|
116
|
-
|
|
117
|
-
- If doing an `import type` across module systems, i.e. from `.mts` into `.cts`, or vice versa, you might encounter the compilation error ``error TS1452: 'resolution-mode' assertions are only supported when `moduleResolution` is `node16` or `nodenext`.``. This is a [known issue](https://github.com/microsoft/TypeScript/issues/49055) and TypeScript currently suggests installing the nightly build, i.e. `npm i typescript@next`.
|
|
115
|
+
- 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.
|
|
118
116
|
|
|
119
117
|
- 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.
|
|
120
118
|
|
|
121
119
|
## Notes
|
|
122
120
|
|
|
123
|
-
As far as I can tell, `duel` is one (if not the only) way to get a correct dual package build using `tsc` without requiring multiple `tsconfig.json` files or extra configuration. The
|
|
121
|
+
As far as I can tell, `duel` is one (if not the only) way to get a correct dual package build using `tsc` without requiring multiple `tsconfig.json` files or extra configuration. The TypeScript team [keep](https://github.com/microsoft/TypeScript/pull/54546) [talking](https://github.com/microsoft/TypeScript/issues/54593) about dual build support, but they continue to [refuse to rewrite specifiers](https://github.com/microsoft/TypeScript/issues/16577).
|
|
124
122
|
|
|
125
123
|
Fortunately, Node.js has added `--experimental-require-module` so that you can [`require()` ES modules](https://nodejs.org/api/esm.html#require) if they don't use top level await, which sets the stage for possibly no longer requiring dual builds.
|
package/dist/cjs/init.cjs
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.init = void 0;
|
|
7
|
-
const node_process_1 = require("node:process");
|
|
8
4
|
const node_util_1 = require("node:util");
|
|
9
5
|
const node_path_1 = require("node:path");
|
|
10
6
|
const promises_1 = require("node:fs/promises");
|
|
7
|
+
const get_tsconfig_1 = require("get-tsconfig");
|
|
11
8
|
const read_package_up_1 = require("read-package-up");
|
|
12
|
-
const jsonc_parser_1 = __importDefault(require("jsonc-parser"));
|
|
13
9
|
const util_js_1 = require("./util.cjs");
|
|
14
10
|
const init = async (args) => {
|
|
15
11
|
let parsed = null;
|
|
@@ -30,7 +26,6 @@ const init = async (args) => {
|
|
|
30
26
|
'pkg-dir': {
|
|
31
27
|
type: 'string',
|
|
32
28
|
short: 'k',
|
|
33
|
-
default: (0, node_process_1.cwd)(),
|
|
34
29
|
},
|
|
35
30
|
modules: {
|
|
36
31
|
type: 'boolean',
|
|
@@ -59,7 +54,7 @@ const init = async (args) => {
|
|
|
59
54
|
(0, util_js_1.log)('Usage: duel [options]\n');
|
|
60
55
|
(0, util_js_1.log)('Options:');
|
|
61
56
|
(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'.");
|
|
62
|
-
(0, util_js_1.log)('--pkg-dir, -k [path] \t The directory to start looking for a package.json file. Defaults to
|
|
57
|
+
(0, util_js_1.log)('--pkg-dir, -k [path] \t The directory to start looking for a package.json file. Defaults to --project directory.');
|
|
63
58
|
(0, util_js_1.log)('--modules, -m \t\t Transform module globals for dual build target. Defaults to false.');
|
|
64
59
|
(0, util_js_1.log)('--dirs, -d \t\t Output both builds to directories inside of outDir. [esm, cjs].');
|
|
65
60
|
(0, util_js_1.log)('--help, -h \t\t Print this message.');
|
|
@@ -73,11 +68,6 @@ const init = async (args) => {
|
|
|
73
68
|
(0, util_js_1.logError)('--target-extension is deprecated. Define "type" in your package.json instead and the dual build will be inferred from that.');
|
|
74
69
|
return false;
|
|
75
70
|
}
|
|
76
|
-
pkg = await (0, read_package_up_1.readPackageUp)({ cwd: pkgDir });
|
|
77
|
-
if (!pkg) {
|
|
78
|
-
(0, util_js_1.logError)('No package.json file found.');
|
|
79
|
-
return false;
|
|
80
|
-
}
|
|
81
71
|
try {
|
|
82
72
|
stats = await (0, promises_1.stat)(configPath);
|
|
83
73
|
}
|
|
@@ -85,6 +75,11 @@ const init = async (args) => {
|
|
|
85
75
|
(0, util_js_1.logError)(`Provided --project '${project}' resolves to ${configPath} which is not a file or directory.`);
|
|
86
76
|
return false;
|
|
87
77
|
}
|
|
78
|
+
pkg = await (0, read_package_up_1.readPackageUp)({ cwd: pkgDir ?? configPath });
|
|
79
|
+
if (!pkg) {
|
|
80
|
+
(0, util_js_1.logError)('No package.json file found.');
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
88
83
|
if (stats.isDirectory()) {
|
|
89
84
|
configPath = (0, node_path_1.join)(configPath, 'tsconfig.json');
|
|
90
85
|
try {
|
|
@@ -96,21 +91,11 @@ const init = async (args) => {
|
|
|
96
91
|
}
|
|
97
92
|
}
|
|
98
93
|
if (stats.isFile()) {
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
const jsonText = (await (0, promises_1.readFile)(configPath)).toString();
|
|
102
|
-
tsconfig = jsonc_parser_1.default.parse(jsonText, errors, {
|
|
103
|
-
disallowComments: false,
|
|
104
|
-
allowTrailingComma: true,
|
|
105
|
-
});
|
|
106
|
-
if (errors.length) {
|
|
107
|
-
(0, util_js_1.logError)(`The config file found at ${configPath} is not parsable as JSONC.`);
|
|
108
|
-
return false;
|
|
109
|
-
}
|
|
94
|
+
const tsconfig = (0, get_tsconfig_1.parseTsconfig)(configPath);
|
|
95
|
+
const projectDir = (0, node_path_1.dirname)(configPath);
|
|
110
96
|
if (!tsconfig.compilerOptions?.outDir) {
|
|
111
97
|
(0, util_js_1.log)('No outDir defined in tsconfig.json. Build output will be in "dist".');
|
|
112
98
|
}
|
|
113
|
-
const projectDir = (0, node_path_1.dirname)(configPath);
|
|
114
99
|
return {
|
|
115
100
|
pkg,
|
|
116
101
|
dirs,
|
package/dist/cjs/init.d.cts
CHANGED
|
@@ -2,7 +2,16 @@ export function init(args: any): Promise<false | {
|
|
|
2
2
|
pkg: import("read-package-up", { with: { "resolution-mode": "import" } }).NormalizedReadResult;
|
|
3
3
|
dirs: boolean;
|
|
4
4
|
modules: boolean;
|
|
5
|
-
tsconfig:
|
|
5
|
+
tsconfig: {
|
|
6
|
+
compilerOptions?: import("get-tsconfig").TsConfigJson.CompilerOptions | undefined;
|
|
7
|
+
watchOptions?: import("get-tsconfig").TsConfigJson.WatchOptions | undefined;
|
|
8
|
+
typeAcquisition?: import("get-tsconfig").TsConfigJson.TypeAcquisition | undefined;
|
|
9
|
+
compileOnSave?: boolean | undefined;
|
|
10
|
+
files?: string[] | undefined;
|
|
11
|
+
exclude?: string[] | undefined;
|
|
12
|
+
include?: string[] | undefined;
|
|
13
|
+
references?: import("get-tsconfig").TsConfigJson.References[] | undefined;
|
|
14
|
+
};
|
|
6
15
|
projectDir: string;
|
|
7
16
|
configPath: string;
|
|
8
17
|
}>;
|
package/dist/esm/init.d.ts
CHANGED
|
@@ -2,7 +2,16 @@ export function init(args: any): Promise<false | {
|
|
|
2
2
|
pkg: import("read-package-up").NormalizedReadResult;
|
|
3
3
|
dirs: boolean;
|
|
4
4
|
modules: boolean;
|
|
5
|
-
tsconfig:
|
|
5
|
+
tsconfig: {
|
|
6
|
+
compilerOptions?: import("get-tsconfig").TsConfigJson.CompilerOptions | undefined;
|
|
7
|
+
watchOptions?: import("get-tsconfig").TsConfigJson.WatchOptions | undefined;
|
|
8
|
+
typeAcquisition?: import("get-tsconfig").TsConfigJson.TypeAcquisition | undefined;
|
|
9
|
+
compileOnSave?: boolean | undefined;
|
|
10
|
+
files?: string[] | undefined;
|
|
11
|
+
exclude?: string[] | undefined;
|
|
12
|
+
include?: string[] | undefined;
|
|
13
|
+
references?: import("get-tsconfig").TsConfigJson.References[] | undefined;
|
|
14
|
+
};
|
|
6
15
|
projectDir: string;
|
|
7
16
|
configPath: string;
|
|
8
17
|
}>;
|
package/dist/esm/init.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { cwd } from 'node:process';
|
|
2
1
|
import { parseArgs } from 'node:util';
|
|
3
2
|
import { resolve, join, dirname } from 'node:path';
|
|
4
|
-
import { stat
|
|
3
|
+
import { stat } from 'node:fs/promises';
|
|
4
|
+
import { parseTsconfig } from 'get-tsconfig';
|
|
5
5
|
import { readPackageUp } from 'read-package-up';
|
|
6
|
-
import JSONC from 'jsonc-parser';
|
|
7
6
|
import { logError, log } from './util.js';
|
|
8
7
|
const init = async (args) => {
|
|
9
8
|
let parsed = null;
|
|
@@ -24,7 +23,6 @@ const init = async (args) => {
|
|
|
24
23
|
'pkg-dir': {
|
|
25
24
|
type: 'string',
|
|
26
25
|
short: 'k',
|
|
27
|
-
default: cwd(),
|
|
28
26
|
},
|
|
29
27
|
modules: {
|
|
30
28
|
type: 'boolean',
|
|
@@ -53,7 +51,7 @@ const init = async (args) => {
|
|
|
53
51
|
log('Usage: duel [options]\n');
|
|
54
52
|
log('Options:');
|
|
55
53
|
log("--project, -p [path] \t Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'.");
|
|
56
|
-
log('--pkg-dir, -k [path] \t The directory to start looking for a package.json file. Defaults to
|
|
54
|
+
log('--pkg-dir, -k [path] \t The directory to start looking for a package.json file. Defaults to --project directory.');
|
|
57
55
|
log('--modules, -m \t\t Transform module globals for dual build target. Defaults to false.');
|
|
58
56
|
log('--dirs, -d \t\t Output both builds to directories inside of outDir. [esm, cjs].');
|
|
59
57
|
log('--help, -h \t\t Print this message.');
|
|
@@ -67,11 +65,6 @@ const init = async (args) => {
|
|
|
67
65
|
logError('--target-extension is deprecated. Define "type" in your package.json instead and the dual build will be inferred from that.');
|
|
68
66
|
return false;
|
|
69
67
|
}
|
|
70
|
-
pkg = await readPackageUp({ cwd: pkgDir });
|
|
71
|
-
if (!pkg) {
|
|
72
|
-
logError('No package.json file found.');
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
68
|
try {
|
|
76
69
|
stats = await stat(configPath);
|
|
77
70
|
}
|
|
@@ -79,6 +72,11 @@ const init = async (args) => {
|
|
|
79
72
|
logError(`Provided --project '${project}' resolves to ${configPath} which is not a file or directory.`);
|
|
80
73
|
return false;
|
|
81
74
|
}
|
|
75
|
+
pkg = await readPackageUp({ cwd: pkgDir ?? configPath });
|
|
76
|
+
if (!pkg) {
|
|
77
|
+
logError('No package.json file found.');
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
82
80
|
if (stats.isDirectory()) {
|
|
83
81
|
configPath = join(configPath, 'tsconfig.json');
|
|
84
82
|
try {
|
|
@@ -90,21 +88,11 @@ const init = async (args) => {
|
|
|
90
88
|
}
|
|
91
89
|
}
|
|
92
90
|
if (stats.isFile()) {
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
const jsonText = (await readFile(configPath)).toString();
|
|
96
|
-
tsconfig = JSONC.parse(jsonText, errors, {
|
|
97
|
-
disallowComments: false,
|
|
98
|
-
allowTrailingComma: true,
|
|
99
|
-
});
|
|
100
|
-
if (errors.length) {
|
|
101
|
-
logError(`The config file found at ${configPath} is not parsable as JSONC.`);
|
|
102
|
-
return false;
|
|
103
|
-
}
|
|
91
|
+
const tsconfig = parseTsconfig(configPath);
|
|
92
|
+
const projectDir = dirname(configPath);
|
|
104
93
|
if (!tsconfig.compilerOptions?.outDir) {
|
|
105
94
|
log('No outDir defined in tsconfig.json. Build output will be in "dist".');
|
|
106
95
|
}
|
|
107
|
-
const projectDir = dirname(configPath);
|
|
108
96
|
return {
|
|
109
97
|
pkg,
|
|
110
98
|
dirs,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knighted/duel",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "TypeScript dual packages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/esm/duel.js",
|
|
@@ -57,22 +57,23 @@
|
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@eslint/js": "^9.6.0",
|
|
60
|
+
"@tsconfig/recommended": "^1.0.8",
|
|
60
61
|
"@types/node": "^22.7.4",
|
|
61
62
|
"c8": "^10.1.3",
|
|
62
63
|
"eslint": "^9.16.0",
|
|
63
64
|
"eslint-plugin-n": "^17.15.0",
|
|
64
65
|
"globals": "^15.6.0",
|
|
65
66
|
"prettier": "^3.4.2",
|
|
66
|
-
"tsx": "^4.19.
|
|
67
|
-
"typescript": "^5.
|
|
68
|
-
"vite": "^6.
|
|
67
|
+
"tsx": "^4.19.3",
|
|
68
|
+
"typescript": "^5.8.2",
|
|
69
|
+
"vite": "^6.2.3"
|
|
69
70
|
},
|
|
70
71
|
"dependencies": {
|
|
71
72
|
"@knighted/module": "^1.0.0-alpha.4",
|
|
72
73
|
"@knighted/specifier": "^2.0.0-rc.1",
|
|
73
74
|
"find-up": "^6.3.0",
|
|
74
|
-
"
|
|
75
|
-
"
|
|
75
|
+
"get-tsconfig": "^4.10.0",
|
|
76
|
+
"glob": "^11.0.1",
|
|
76
77
|
"read-package-up": "^11.0.0"
|
|
77
78
|
},
|
|
78
79
|
"prettier": {
|