@knighted/duel 3.0.0 → 3.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 +6 -0
- package/dist/cjs/duel.cjs +179 -1
- package/dist/cjs/init.cjs +11 -1
- package/dist/cjs/init.d.cts +1 -0
- package/dist/esm/duel.js +180 -2
- package/dist/esm/init.d.ts +1 -0
- package/dist/esm/init.js +11 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,6 +98,10 @@ The available options are limited, because you should define most of them inside
|
|
|
98
98
|
- `--pkg-dir, -k` The directory to start looking for a package.json file. Defaults to `--project` dir.
|
|
99
99
|
- `--modules, -m` Transform module globals for dual build target. Defaults to false.
|
|
100
100
|
- `--dirs, -d` Outputs both builds to directories inside of `outDir`. Defaults to `false`.
|
|
101
|
+
- `--exports, -e` Generate `package.json` `exports` from build output. Values: `wildcard` | `dir` | `name`.
|
|
102
|
+
|
|
103
|
+
> [!NOTE]
|
|
104
|
+
> Exports keys are extensionless by design; the target `import`/`require`/`types` entries keep explicit file extensions so Node resolution remains deterministic.
|
|
101
105
|
|
|
102
106
|
You can run `duel --help` to get the same info. Below is the output of that:
|
|
103
107
|
|
|
@@ -131,3 +135,5 @@ Fortunately, Node.js has added `--experimental-require-module` so that you can [
|
|
|
131
135
|
## Documentation
|
|
132
136
|
|
|
133
137
|
- [docs/faq.md](docs/faq.md)
|
|
138
|
+
- [docs/exports.md](docs/exports.md)
|
|
139
|
+
- [docs/migrate-v2-v3.md](docs/migrate-v2-v3.md)
|
package/dist/cjs/duel.cjs
CHANGED
|
@@ -13,15 +13,178 @@ const find_up_1 = require("find-up");
|
|
|
13
13
|
const module_1 = require("@knighted/module");
|
|
14
14
|
const init_js_1 = require("./init.cjs");
|
|
15
15
|
const util_js_1 = require("./util.cjs");
|
|
16
|
+
const stripKnownExt = path => {
|
|
17
|
+
return path.replace(/(\.d\.(?:ts|mts|cts)|\.(?:mjs|cjs|js))$/, '');
|
|
18
|
+
};
|
|
19
|
+
const ensureDotSlash = path => {
|
|
20
|
+
return path.startsWith('./') ? path : `./${path}`;
|
|
21
|
+
};
|
|
22
|
+
const getSubpath = (mode, relFromRoot) => {
|
|
23
|
+
const parsed = (0, node_path_1.parse)(relFromRoot);
|
|
24
|
+
const segments = parsed.dir.split('/').filter(Boolean);
|
|
25
|
+
if (mode === 'name') {
|
|
26
|
+
return parsed.name ? `./${parsed.name}` : null;
|
|
27
|
+
}
|
|
28
|
+
if (mode === 'dir') {
|
|
29
|
+
const last = segments.at(-1);
|
|
30
|
+
return last ? `./${last}` : null;
|
|
31
|
+
}
|
|
32
|
+
if (mode === 'wildcard') {
|
|
33
|
+
const first = segments[0];
|
|
34
|
+
return first ? `./${first}/*` : null;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
};
|
|
16
38
|
const handleErrorAndExit = message => {
|
|
17
39
|
const exitCode = Number(message);
|
|
18
40
|
(0, util_js_1.logError)('Compilation errors found.');
|
|
19
41
|
process.exit(exitCode);
|
|
20
42
|
};
|
|
43
|
+
const generateExports = async (options) => {
|
|
44
|
+
const { mode, pkg, pkgDir, esmRoot, cjsRoot, mainDefaultKind, mainPath } = options;
|
|
45
|
+
const toPosix = path => path.replace(/\\/g, '/');
|
|
46
|
+
const esmRootPosix = toPosix(esmRoot);
|
|
47
|
+
const cjsRootPosix = toPosix(cjsRoot);
|
|
48
|
+
const esmIgnore = ['node_modules/**'];
|
|
49
|
+
const cjsIgnore = ['node_modules/**'];
|
|
50
|
+
const baseMap = new Map();
|
|
51
|
+
const subpathMap = new Map();
|
|
52
|
+
const baseToSubpath = new Map();
|
|
53
|
+
if (cjsRootPosix.startsWith(`${esmRootPosix}/`)) {
|
|
54
|
+
esmIgnore.push(`${cjsRootPosix}/**`);
|
|
55
|
+
}
|
|
56
|
+
if (esmRootPosix.startsWith(`${cjsRootPosix}/`)) {
|
|
57
|
+
cjsIgnore.push(`${esmRootPosix}/**`);
|
|
58
|
+
}
|
|
59
|
+
const recordPath = (kind, filePath, root) => {
|
|
60
|
+
const relPkg = toPosix((0, node_path_1.relative)(pkgDir, filePath));
|
|
61
|
+
const relFromRoot = toPosix((0, node_path_1.relative)(root, filePath));
|
|
62
|
+
const withDot = ensureDotSlash(relPkg);
|
|
63
|
+
const baseKey = stripKnownExt(relPkg);
|
|
64
|
+
const baseEntry = baseMap.get(baseKey) ?? {};
|
|
65
|
+
baseEntry[kind] = withDot;
|
|
66
|
+
baseMap.set(baseKey, baseEntry);
|
|
67
|
+
const subpath = getSubpath(mode, relFromRoot);
|
|
68
|
+
if (kind === 'types') {
|
|
69
|
+
const mappedSubpath = baseToSubpath.get(baseKey);
|
|
70
|
+
if (mappedSubpath) {
|
|
71
|
+
const subEntry = subpathMap.get(mappedSubpath) ?? {};
|
|
72
|
+
subEntry.types = withDot;
|
|
73
|
+
subpathMap.set(mappedSubpath, subEntry);
|
|
74
|
+
}
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (subpath && subpath !== '.') {
|
|
78
|
+
const subEntry = subpathMap.get(subpath) ?? {};
|
|
79
|
+
subEntry[kind] = withDot;
|
|
80
|
+
subpathMap.set(subpath, subEntry);
|
|
81
|
+
baseToSubpath.set(baseKey, subpath);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const esmFiles = await (0, glob_1.glob)(`${esmRootPosix}/**/*.{js,mjs,d.ts,d.mts}`, {
|
|
85
|
+
ignore: esmIgnore,
|
|
86
|
+
});
|
|
87
|
+
for (const file of esmFiles) {
|
|
88
|
+
if (/\.d\.(ts|mts)$/.test(file)) {
|
|
89
|
+
recordPath('types', file, esmRoot);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
recordPath('import', file, esmRoot);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const cjsFiles = await (0, glob_1.glob)(`${cjsRootPosix}/**/*.{js,cjs,d.ts,d.cts}`, {
|
|
96
|
+
ignore: cjsIgnore,
|
|
97
|
+
});
|
|
98
|
+
for (const file of cjsFiles) {
|
|
99
|
+
if (/\.d\.(ts|cts)$/.test(file)) {
|
|
100
|
+
recordPath('types', file, cjsRoot);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
recordPath('require', file, cjsRoot);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const exportsMap = {};
|
|
107
|
+
const mainBase = mainPath ? stripKnownExt(mainPath.replace(/^\.\//, '')) : null;
|
|
108
|
+
const mainEntry = mainBase ? (baseMap.get(mainBase) ?? {}) : {};
|
|
109
|
+
if (mainPath) {
|
|
110
|
+
const rootEntry = {};
|
|
111
|
+
if (mainEntry.types) {
|
|
112
|
+
rootEntry.types = mainEntry.types;
|
|
113
|
+
}
|
|
114
|
+
if (mainDefaultKind === 'import') {
|
|
115
|
+
rootEntry.import = mainEntry.import ?? ensureDotSlash(mainPath);
|
|
116
|
+
if (mainEntry.require) {
|
|
117
|
+
rootEntry.require = mainEntry.require;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
rootEntry.require = mainEntry.require ?? ensureDotSlash(mainPath);
|
|
122
|
+
if (mainEntry.import) {
|
|
123
|
+
rootEntry.import = mainEntry.import;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
rootEntry.default = ensureDotSlash(mainPath);
|
|
127
|
+
exportsMap['.'] = rootEntry;
|
|
128
|
+
}
|
|
129
|
+
const defaultKind = mainDefaultKind ?? 'import';
|
|
130
|
+
for (const [subpath, entry] of subpathMap.entries()) {
|
|
131
|
+
const out = {};
|
|
132
|
+
if (entry.types) {
|
|
133
|
+
out.types = entry.types;
|
|
134
|
+
}
|
|
135
|
+
if (entry.import) {
|
|
136
|
+
out.import = entry.import;
|
|
137
|
+
}
|
|
138
|
+
if (entry.require) {
|
|
139
|
+
out.require = entry.require;
|
|
140
|
+
}
|
|
141
|
+
const def = defaultKind === 'import'
|
|
142
|
+
? (entry.import ?? entry.require)
|
|
143
|
+
: (entry.require ?? entry.import);
|
|
144
|
+
if (def) {
|
|
145
|
+
out.default = def;
|
|
146
|
+
}
|
|
147
|
+
if (Object.keys(out).length) {
|
|
148
|
+
exportsMap[subpath] = out;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (!exportsMap['.'] && baseMap.size) {
|
|
152
|
+
const [subpath, entry] = subpathMap.entries().next().value ?? [];
|
|
153
|
+
if (entry) {
|
|
154
|
+
const out = {};
|
|
155
|
+
if (entry.types) {
|
|
156
|
+
out.types = entry.types;
|
|
157
|
+
}
|
|
158
|
+
if (entry.import) {
|
|
159
|
+
out.import = entry.import;
|
|
160
|
+
}
|
|
161
|
+
if (entry.require) {
|
|
162
|
+
out.require = entry.require;
|
|
163
|
+
}
|
|
164
|
+
const def = defaultKind === 'import'
|
|
165
|
+
? (entry.import ?? entry.require)
|
|
166
|
+
: (entry.require ?? entry.import);
|
|
167
|
+
if (def) {
|
|
168
|
+
out.default = def;
|
|
169
|
+
}
|
|
170
|
+
if (Object.keys(out).length) {
|
|
171
|
+
exportsMap['.'] = out;
|
|
172
|
+
exportsMap[subpath] ??= out;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (Object.keys(exportsMap).length) {
|
|
177
|
+
const pkgJson = {
|
|
178
|
+
...pkg.packageJson,
|
|
179
|
+
exports: exportsMap,
|
|
180
|
+
};
|
|
181
|
+
await (0, promises_1.writeFile)(pkg.path, `${JSON.stringify(pkgJson, null, 2)}\n`);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
21
184
|
const duel = async (args) => {
|
|
22
185
|
const ctx = await (0, init_js_1.init)(args);
|
|
23
186
|
if (ctx) {
|
|
24
|
-
const { projectDir, tsconfig, configPath, modules, dirs, pkg } = ctx;
|
|
187
|
+
const { projectDir, tsconfig, configPath, modules, dirs, pkg, exports: exportsOpt, } = ctx;
|
|
25
188
|
const tsc = await (0, find_up_1.findUp)(async (dir) => {
|
|
26
189
|
const tscBin = (0, node_path_1.join)(dir, 'node_modules', '.bin', 'tsc');
|
|
27
190
|
try {
|
|
@@ -45,6 +208,8 @@ const duel = async (args) => {
|
|
|
45
208
|
});
|
|
46
209
|
};
|
|
47
210
|
const pkgDir = (0, node_path_1.dirname)(pkg.path);
|
|
211
|
+
const mainPath = pkg.packageJson.main;
|
|
212
|
+
const mainDefaultKind = mainPath?.endsWith('.cjs') ? 'require' : 'import';
|
|
48
213
|
const outDir = tsconfig.compilerOptions?.outDir ?? 'dist';
|
|
49
214
|
const absoluteOutDir = (0, node_path_1.resolve)(projectDir, outDir);
|
|
50
215
|
const originalType = pkg.packageJson.type ?? 'commonjs';
|
|
@@ -192,6 +357,19 @@ const duel = async (args) => {
|
|
|
192
357
|
const primaryFiles = await (0, glob_1.glob)(`${primaryOutDir.replace(/\\/g, '/')}/**/*{.js,.d.ts}`, { ignore: 'node_modules/**' });
|
|
193
358
|
await updateSpecifiersAndFileExtensions(primaryFiles, 'commonjs', '.cjs');
|
|
194
359
|
}
|
|
360
|
+
if (exportsOpt) {
|
|
361
|
+
const esmRoot = isCjsBuild ? primaryOutDir : absoluteDualOutDir;
|
|
362
|
+
const cjsRoot = isCjsBuild ? absoluteDualOutDir : primaryOutDir;
|
|
363
|
+
await generateExports({
|
|
364
|
+
mode: exportsOpt,
|
|
365
|
+
pkg,
|
|
366
|
+
pkgDir,
|
|
367
|
+
esmRoot,
|
|
368
|
+
cjsRoot,
|
|
369
|
+
mainDefaultKind,
|
|
370
|
+
mainPath,
|
|
371
|
+
});
|
|
372
|
+
}
|
|
195
373
|
logSuccess(startTime);
|
|
196
374
|
}
|
|
197
375
|
}
|
package/dist/cjs/init.cjs
CHANGED
|
@@ -37,6 +37,10 @@ const init = async (args) => {
|
|
|
37
37
|
short: 'd',
|
|
38
38
|
default: false,
|
|
39
39
|
},
|
|
40
|
+
exports: {
|
|
41
|
+
type: 'string',
|
|
42
|
+
short: 'e',
|
|
43
|
+
},
|
|
40
44
|
help: {
|
|
41
45
|
type: 'boolean',
|
|
42
46
|
short: 'h',
|
|
@@ -57,10 +61,11 @@ const init = async (args) => {
|
|
|
57
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.');
|
|
58
62
|
(0, util_js_1.log)('--modules, -m \t\t Transform module globals for dual build target. Defaults to false.');
|
|
59
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.');
|
|
60
65
|
(0, util_js_1.log)('--help, -h \t\t Print this message.');
|
|
61
66
|
}
|
|
62
67
|
else {
|
|
63
|
-
const { project, 'target-extension': targetExt, 'pkg-dir': pkgDir, modules, dirs, } = parsed;
|
|
68
|
+
const { project, 'target-extension': targetExt, 'pkg-dir': pkgDir, modules, dirs, exports: exportsOpt, } = parsed;
|
|
64
69
|
let configPath = (0, node_path_1.resolve)(project);
|
|
65
70
|
let stats = null;
|
|
66
71
|
let pkg = null;
|
|
@@ -96,10 +101,15 @@ const init = async (args) => {
|
|
|
96
101
|
if (!tsconfig.compilerOptions?.outDir) {
|
|
97
102
|
(0, util_js_1.log)('No outDir defined in tsconfig.json. Build output will be in "dist".');
|
|
98
103
|
}
|
|
104
|
+
if (exportsOpt && !['wildcard', 'dir', 'name'].includes(exportsOpt)) {
|
|
105
|
+
(0, util_js_1.logError)('--exports expects one of: wildcard | dir | name');
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
99
108
|
return {
|
|
100
109
|
pkg,
|
|
101
110
|
dirs,
|
|
102
111
|
modules,
|
|
112
|
+
exports: exportsOpt,
|
|
103
113
|
tsconfig,
|
|
104
114
|
projectDir,
|
|
105
115
|
configPath,
|
package/dist/cjs/init.d.cts
CHANGED
|
@@ -2,6 +2,7 @@ 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
|
+
exports: string | undefined;
|
|
5
6
|
tsconfig: {
|
|
6
7
|
compilerOptions?: import("get-tsconfig").TsConfigJson.CompilerOptions | undefined;
|
|
7
8
|
watchOptions?: import("get-tsconfig").TsConfigJson.WatchOptions | undefined;
|
package/dist/esm/duel.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { argv, platform } from 'node:process';
|
|
3
|
-
import { join, dirname, resolve, relative } from 'node:path';
|
|
3
|
+
import { join, dirname, resolve, relative, parse as parsePath } 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';
|
|
@@ -10,15 +10,178 @@ import { findUp } from 'find-up';
|
|
|
10
10
|
import { transform } from '@knighted/module';
|
|
11
11
|
import { init } from './init.js';
|
|
12
12
|
import { getRealPathAsFileUrl, getCompileFiles, logError, log } from './util.js';
|
|
13
|
+
const stripKnownExt = path => {
|
|
14
|
+
return path.replace(/(\.d\.(?:ts|mts|cts)|\.(?:mjs|cjs|js))$/, '');
|
|
15
|
+
};
|
|
16
|
+
const ensureDotSlash = path => {
|
|
17
|
+
return path.startsWith('./') ? path : `./${path}`;
|
|
18
|
+
};
|
|
19
|
+
const getSubpath = (mode, relFromRoot) => {
|
|
20
|
+
const parsed = parsePath(relFromRoot);
|
|
21
|
+
const segments = parsed.dir.split('/').filter(Boolean);
|
|
22
|
+
if (mode === 'name') {
|
|
23
|
+
return parsed.name ? `./${parsed.name}` : null;
|
|
24
|
+
}
|
|
25
|
+
if (mode === 'dir') {
|
|
26
|
+
const last = segments.at(-1);
|
|
27
|
+
return last ? `./${last}` : null;
|
|
28
|
+
}
|
|
29
|
+
if (mode === 'wildcard') {
|
|
30
|
+
const first = segments[0];
|
|
31
|
+
return first ? `./${first}/*` : null;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
};
|
|
13
35
|
const handleErrorAndExit = message => {
|
|
14
36
|
const exitCode = Number(message);
|
|
15
37
|
logError('Compilation errors found.');
|
|
16
38
|
process.exit(exitCode);
|
|
17
39
|
};
|
|
40
|
+
const generateExports = async (options) => {
|
|
41
|
+
const { mode, pkg, pkgDir, esmRoot, cjsRoot, mainDefaultKind, mainPath } = options;
|
|
42
|
+
const toPosix = path => path.replace(/\\/g, '/');
|
|
43
|
+
const esmRootPosix = toPosix(esmRoot);
|
|
44
|
+
const cjsRootPosix = toPosix(cjsRoot);
|
|
45
|
+
const esmIgnore = ['node_modules/**'];
|
|
46
|
+
const cjsIgnore = ['node_modules/**'];
|
|
47
|
+
const baseMap = new Map();
|
|
48
|
+
const subpathMap = new Map();
|
|
49
|
+
const baseToSubpath = new Map();
|
|
50
|
+
if (cjsRootPosix.startsWith(`${esmRootPosix}/`)) {
|
|
51
|
+
esmIgnore.push(`${cjsRootPosix}/**`);
|
|
52
|
+
}
|
|
53
|
+
if (esmRootPosix.startsWith(`${cjsRootPosix}/`)) {
|
|
54
|
+
cjsIgnore.push(`${esmRootPosix}/**`);
|
|
55
|
+
}
|
|
56
|
+
const recordPath = (kind, filePath, root) => {
|
|
57
|
+
const relPkg = toPosix(relative(pkgDir, filePath));
|
|
58
|
+
const relFromRoot = toPosix(relative(root, filePath));
|
|
59
|
+
const withDot = ensureDotSlash(relPkg);
|
|
60
|
+
const baseKey = stripKnownExt(relPkg);
|
|
61
|
+
const baseEntry = baseMap.get(baseKey) ?? {};
|
|
62
|
+
baseEntry[kind] = withDot;
|
|
63
|
+
baseMap.set(baseKey, baseEntry);
|
|
64
|
+
const subpath = getSubpath(mode, relFromRoot);
|
|
65
|
+
if (kind === 'types') {
|
|
66
|
+
const mappedSubpath = baseToSubpath.get(baseKey);
|
|
67
|
+
if (mappedSubpath) {
|
|
68
|
+
const subEntry = subpathMap.get(mappedSubpath) ?? {};
|
|
69
|
+
subEntry.types = withDot;
|
|
70
|
+
subpathMap.set(mappedSubpath, subEntry);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (subpath && subpath !== '.') {
|
|
75
|
+
const subEntry = subpathMap.get(subpath) ?? {};
|
|
76
|
+
subEntry[kind] = withDot;
|
|
77
|
+
subpathMap.set(subpath, subEntry);
|
|
78
|
+
baseToSubpath.set(baseKey, subpath);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const esmFiles = await glob(`${esmRootPosix}/**/*.{js,mjs,d.ts,d.mts}`, {
|
|
82
|
+
ignore: esmIgnore,
|
|
83
|
+
});
|
|
84
|
+
for (const file of esmFiles) {
|
|
85
|
+
if (/\.d\.(ts|mts)$/.test(file)) {
|
|
86
|
+
recordPath('types', file, esmRoot);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
recordPath('import', file, esmRoot);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const cjsFiles = await glob(`${cjsRootPosix}/**/*.{js,cjs,d.ts,d.cts}`, {
|
|
93
|
+
ignore: cjsIgnore,
|
|
94
|
+
});
|
|
95
|
+
for (const file of cjsFiles) {
|
|
96
|
+
if (/\.d\.(ts|cts)$/.test(file)) {
|
|
97
|
+
recordPath('types', file, cjsRoot);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
recordPath('require', file, cjsRoot);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const exportsMap = {};
|
|
104
|
+
const mainBase = mainPath ? stripKnownExt(mainPath.replace(/^\.\//, '')) : null;
|
|
105
|
+
const mainEntry = mainBase ? (baseMap.get(mainBase) ?? {}) : {};
|
|
106
|
+
if (mainPath) {
|
|
107
|
+
const rootEntry = {};
|
|
108
|
+
if (mainEntry.types) {
|
|
109
|
+
rootEntry.types = mainEntry.types;
|
|
110
|
+
}
|
|
111
|
+
if (mainDefaultKind === 'import') {
|
|
112
|
+
rootEntry.import = mainEntry.import ?? ensureDotSlash(mainPath);
|
|
113
|
+
if (mainEntry.require) {
|
|
114
|
+
rootEntry.require = mainEntry.require;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
rootEntry.require = mainEntry.require ?? ensureDotSlash(mainPath);
|
|
119
|
+
if (mainEntry.import) {
|
|
120
|
+
rootEntry.import = mainEntry.import;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
rootEntry.default = ensureDotSlash(mainPath);
|
|
124
|
+
exportsMap['.'] = rootEntry;
|
|
125
|
+
}
|
|
126
|
+
const defaultKind = mainDefaultKind ?? 'import';
|
|
127
|
+
for (const [subpath, entry] of subpathMap.entries()) {
|
|
128
|
+
const out = {};
|
|
129
|
+
if (entry.types) {
|
|
130
|
+
out.types = entry.types;
|
|
131
|
+
}
|
|
132
|
+
if (entry.import) {
|
|
133
|
+
out.import = entry.import;
|
|
134
|
+
}
|
|
135
|
+
if (entry.require) {
|
|
136
|
+
out.require = entry.require;
|
|
137
|
+
}
|
|
138
|
+
const def = defaultKind === 'import'
|
|
139
|
+
? (entry.import ?? entry.require)
|
|
140
|
+
: (entry.require ?? entry.import);
|
|
141
|
+
if (def) {
|
|
142
|
+
out.default = def;
|
|
143
|
+
}
|
|
144
|
+
if (Object.keys(out).length) {
|
|
145
|
+
exportsMap[subpath] = out;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
if (!exportsMap['.'] && baseMap.size) {
|
|
149
|
+
const [subpath, entry] = subpathMap.entries().next().value ?? [];
|
|
150
|
+
if (entry) {
|
|
151
|
+
const out = {};
|
|
152
|
+
if (entry.types) {
|
|
153
|
+
out.types = entry.types;
|
|
154
|
+
}
|
|
155
|
+
if (entry.import) {
|
|
156
|
+
out.import = entry.import;
|
|
157
|
+
}
|
|
158
|
+
if (entry.require) {
|
|
159
|
+
out.require = entry.require;
|
|
160
|
+
}
|
|
161
|
+
const def = defaultKind === 'import'
|
|
162
|
+
? (entry.import ?? entry.require)
|
|
163
|
+
: (entry.require ?? entry.import);
|
|
164
|
+
if (def) {
|
|
165
|
+
out.default = def;
|
|
166
|
+
}
|
|
167
|
+
if (Object.keys(out).length) {
|
|
168
|
+
exportsMap['.'] = out;
|
|
169
|
+
exportsMap[subpath] ??= out;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (Object.keys(exportsMap).length) {
|
|
174
|
+
const pkgJson = {
|
|
175
|
+
...pkg.packageJson,
|
|
176
|
+
exports: exportsMap,
|
|
177
|
+
};
|
|
178
|
+
await writeFile(pkg.path, `${JSON.stringify(pkgJson, null, 2)}\n`);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
18
181
|
const duel = async (args) => {
|
|
19
182
|
const ctx = await init(args);
|
|
20
183
|
if (ctx) {
|
|
21
|
-
const { projectDir, tsconfig, configPath, modules, dirs, pkg } = ctx;
|
|
184
|
+
const { projectDir, tsconfig, configPath, modules, dirs, pkg, exports: exportsOpt, } = ctx;
|
|
22
185
|
const tsc = await findUp(async (dir) => {
|
|
23
186
|
const tscBin = join(dir, 'node_modules', '.bin', 'tsc');
|
|
24
187
|
try {
|
|
@@ -42,6 +205,8 @@ const duel = async (args) => {
|
|
|
42
205
|
});
|
|
43
206
|
};
|
|
44
207
|
const pkgDir = dirname(pkg.path);
|
|
208
|
+
const mainPath = pkg.packageJson.main;
|
|
209
|
+
const mainDefaultKind = mainPath?.endsWith('.cjs') ? 'require' : 'import';
|
|
45
210
|
const outDir = tsconfig.compilerOptions?.outDir ?? 'dist';
|
|
46
211
|
const absoluteOutDir = resolve(projectDir, outDir);
|
|
47
212
|
const originalType = pkg.packageJson.type ?? 'commonjs';
|
|
@@ -189,6 +354,19 @@ const duel = async (args) => {
|
|
|
189
354
|
const primaryFiles = await glob(`${primaryOutDir.replace(/\\/g, '/')}/**/*{.js,.d.ts}`, { ignore: 'node_modules/**' });
|
|
190
355
|
await updateSpecifiersAndFileExtensions(primaryFiles, 'commonjs', '.cjs');
|
|
191
356
|
}
|
|
357
|
+
if (exportsOpt) {
|
|
358
|
+
const esmRoot = isCjsBuild ? primaryOutDir : absoluteDualOutDir;
|
|
359
|
+
const cjsRoot = isCjsBuild ? absoluteDualOutDir : primaryOutDir;
|
|
360
|
+
await generateExports({
|
|
361
|
+
mode: exportsOpt,
|
|
362
|
+
pkg,
|
|
363
|
+
pkgDir,
|
|
364
|
+
esmRoot,
|
|
365
|
+
cjsRoot,
|
|
366
|
+
mainDefaultKind,
|
|
367
|
+
mainPath,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
192
370
|
logSuccess(startTime);
|
|
193
371
|
}
|
|
194
372
|
}
|
package/dist/esm/init.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export function init(args: any): Promise<false | {
|
|
|
2
2
|
pkg: import("read-package-up").NormalizedReadResult;
|
|
3
3
|
dirs: boolean;
|
|
4
4
|
modules: boolean;
|
|
5
|
+
exports: string | undefined;
|
|
5
6
|
tsconfig: {
|
|
6
7
|
compilerOptions?: import("get-tsconfig").TsConfigJson.CompilerOptions | undefined;
|
|
7
8
|
watchOptions?: import("get-tsconfig").TsConfigJson.WatchOptions | undefined;
|
package/dist/esm/init.js
CHANGED
|
@@ -34,6 +34,10 @@ const init = async (args) => {
|
|
|
34
34
|
short: 'd',
|
|
35
35
|
default: false,
|
|
36
36
|
},
|
|
37
|
+
exports: {
|
|
38
|
+
type: 'string',
|
|
39
|
+
short: 'e',
|
|
40
|
+
},
|
|
37
41
|
help: {
|
|
38
42
|
type: 'boolean',
|
|
39
43
|
short: 'h',
|
|
@@ -54,10 +58,11 @@ const init = async (args) => {
|
|
|
54
58
|
log('--pkg-dir, -k [path] \t The directory to start looking for a package.json file. Defaults to --project directory.');
|
|
55
59
|
log('--modules, -m \t\t Transform module globals for dual build target. Defaults to false.');
|
|
56
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.');
|
|
57
62
|
log('--help, -h \t\t Print this message.');
|
|
58
63
|
}
|
|
59
64
|
else {
|
|
60
|
-
const { project, 'target-extension': targetExt, 'pkg-dir': pkgDir, modules, dirs, } = parsed;
|
|
65
|
+
const { project, 'target-extension': targetExt, 'pkg-dir': pkgDir, modules, dirs, exports: exportsOpt, } = parsed;
|
|
61
66
|
let configPath = resolve(project);
|
|
62
67
|
let stats = null;
|
|
63
68
|
let pkg = null;
|
|
@@ -93,10 +98,15 @@ const init = async (args) => {
|
|
|
93
98
|
if (!tsconfig.compilerOptions?.outDir) {
|
|
94
99
|
log('No outDir defined in tsconfig.json. Build output will be in "dist".');
|
|
95
100
|
}
|
|
101
|
+
if (exportsOpt && !['wildcard', 'dir', 'name'].includes(exportsOpt)) {
|
|
102
|
+
logError('--exports expects one of: wildcard | dir | name');
|
|
103
|
+
return false;
|
|
104
|
+
}
|
|
96
105
|
return {
|
|
97
106
|
pkg,
|
|
98
107
|
dirs,
|
|
99
108
|
modules,
|
|
109
|
+
exports: exportsOpt,
|
|
100
110
|
tsconfig,
|
|
101
111
|
projectDir,
|
|
102
112
|
configPath,
|