@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 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,
@@ -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
  }
@@ -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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knighted/duel",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "TypeScript dual packages.",
5
5
  "type": "module",
6
6
  "main": "dist/esm/duel.js",