@oclif/core 3.0.5-dev.0 → 3.0.6
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 +14 -15
- package/lib/config/ts-node.js +70 -44
- package/lib/execute.d.ts +1 -1
- package/lib/execute.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
@oclif/core
|
|
2
|
-
===========
|
|
1
|
+
# @oclif/core
|
|
3
2
|
|
|
4
3
|
base library for oclif CLIs
|
|
5
4
|
|
|
@@ -7,9 +6,7 @@ base library for oclif CLIs
|
|
|
7
6
|
[](https://npmjs.org/package/@oclif/core)
|
|
8
7
|
[](https://github.com/oclif/core/blob/main/package.json)
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
Migrating
|
|
12
|
-
=====
|
|
9
|
+
# Migrating
|
|
13
10
|
|
|
14
11
|
See the [v3 migration guide](./guides/V3_MIGRATION.md) for an overview of breaking changes that occurred between v2 and v3.
|
|
15
12
|
|
|
@@ -17,19 +14,18 @@ See the [v2 migration guide](./guides/V2_MIGRATION.md) for an overview of breaki
|
|
|
17
14
|
|
|
18
15
|
Migrating from `@oclif/config` and `@oclif/command`? See the [v1 migration guide](./guides/PRE_CORE_MIGRATION.md).
|
|
19
16
|
|
|
20
|
-
CLI UX
|
|
21
|
-
=====
|
|
17
|
+
# CLI UX
|
|
22
18
|
|
|
23
19
|
The [ux README](./src/cli-ux/README.md) contains detailed usage examples of using the `ux` export.
|
|
24
20
|
|
|
25
|
-
Usage
|
|
26
|
-
=====
|
|
21
|
+
# Usage
|
|
27
22
|
|
|
28
23
|
We strongly encourage you generate an oclif CLI using the [oclif cli](https://github.com/oclif/oclif). The generator will generate an npm package with `@oclif/core` as a dependency.
|
|
29
24
|
|
|
30
25
|
You can, however, use `@oclif/core` in a standalone script like this:
|
|
26
|
+
|
|
31
27
|
```typescript
|
|
32
|
-
#!/usr/bin/env ts-node
|
|
28
|
+
#!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning
|
|
33
29
|
|
|
34
30
|
import * as fs from 'fs'
|
|
35
31
|
import {Command, Flags, flush, handle} from '@oclif/core'
|
|
@@ -54,11 +50,14 @@ class LS extends Command {
|
|
|
54
50
|
}
|
|
55
51
|
}
|
|
56
52
|
|
|
57
|
-
LS.run().then(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
LS.run().then(
|
|
54
|
+
async () => {
|
|
55
|
+
await flush()
|
|
56
|
+
},
|
|
57
|
+
async (err) => {
|
|
58
|
+
await handle(err)
|
|
59
|
+
},
|
|
60
|
+
)
|
|
62
61
|
```
|
|
63
62
|
|
|
64
63
|
Then run it like this:
|
package/lib/config/ts-node.js
CHANGED
|
@@ -86,6 +86,10 @@ function registerTSNode(root) {
|
|
|
86
86
|
sourceMap: tsconfig.compilerOptions.sourceMap ?? true,
|
|
87
87
|
target: tsconfig.compilerOptions.target ?? 'es2019',
|
|
88
88
|
typeRoots,
|
|
89
|
+
...(tsconfig.compilerOptions.moduleResolution
|
|
90
|
+
? { moduleResolution: tsconfig.compilerOptions.moduleResolution }
|
|
91
|
+
: {}),
|
|
92
|
+
...(tsconfig.compilerOptions.jsx ? { jsx: tsconfig.compilerOptions.jsx } : {}),
|
|
89
93
|
},
|
|
90
94
|
cwd: root,
|
|
91
95
|
esm: tsconfig['ts-node']?.esm ?? true,
|
|
@@ -95,18 +99,67 @@ function registerTSNode(root) {
|
|
|
95
99
|
skipProject: true,
|
|
96
100
|
transpileOnly: true,
|
|
97
101
|
};
|
|
98
|
-
if (tsconfig.compilerOptions.moduleResolution) {
|
|
99
|
-
// @ts-expect-error TSNode.RegisterOptions.compilerOptions is typed as a plain object
|
|
100
|
-
conf.compilerOptions.moduleResolution = tsconfig.compilerOptions.moduleResolution;
|
|
101
|
-
}
|
|
102
|
-
if (tsconfig.compilerOptions.jsx) {
|
|
103
|
-
// @ts-expect-error TSNode.RegisterOptions.compilerOptions is typed as a plain object
|
|
104
|
-
conf.compilerOptions.jsx = tsconfig.compilerOptions.jsx;
|
|
105
|
-
}
|
|
106
102
|
tsNode.register(conf);
|
|
107
103
|
REGISTERED.add(root);
|
|
108
104
|
return tsconfig;
|
|
109
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Skip ts-node registration for ESM plugins in production.
|
|
108
|
+
* The node ecosystem is not mature enough to support auto-transpiling ESM modules at this time.
|
|
109
|
+
* See the following:
|
|
110
|
+
* - https://github.com/TypeStrong/ts-node/issues/1791#issuecomment-1149754228
|
|
111
|
+
* - https://github.com/nodejs/node/issues/49432
|
|
112
|
+
* - https://github.com/nodejs/node/pull/49407
|
|
113
|
+
* - https://github.com/nodejs/node/issues/34049
|
|
114
|
+
*
|
|
115
|
+
* We still register ts-node for ESM plugins when NODE_ENV is "test" or "development" and root plugin is also ESM
|
|
116
|
+
* since that allows plugins to be auto-transpiled when developing locally using `bin/dev.js`.
|
|
117
|
+
*/
|
|
118
|
+
function cannotTranspileEsm(root, plugin, isProduction) {
|
|
119
|
+
return (isProduction || ROOT_PLUGIN?.moduleType === 'commonjs') && plugin?.moduleType === 'module';
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* If the dev script is run with ts-node for an ESM plugin, skip ts-node registration
|
|
123
|
+
* and fall back on compiled source since ts-node executable cannot transpile ESM in Node 20+
|
|
124
|
+
*
|
|
125
|
+
* See the following:
|
|
126
|
+
* https://nodejs.org/en/blog/announcements/v20-release-announce#custom-esm-loader-hooks-nearing-stable
|
|
127
|
+
* https://github.com/oclif/core/issues/817
|
|
128
|
+
* https://github.com/TypeStrong/ts-node/issues/1997
|
|
129
|
+
*/
|
|
130
|
+
function cannotUseTsNode(root, plugin, isProduction) {
|
|
131
|
+
if (plugin?.moduleType !== 'module' || isProduction)
|
|
132
|
+
return false;
|
|
133
|
+
const nodeMajor = Number.parseInt(process.version.replace('v', '').split('.')[0], 10);
|
|
134
|
+
const tsNodeExecIsUsed = process.execArgv[0] === '--require' && process.execArgv[1].split(node_path_1.sep).includes(`ts-node`);
|
|
135
|
+
return tsNodeExecIsUsed && nodeMajor >= 20;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Determine the path to the source file from the compiled ./lib files
|
|
139
|
+
*/
|
|
140
|
+
function determinePath(root, orig) {
|
|
141
|
+
const tsconfig = registerTSNode(root);
|
|
142
|
+
if (!tsconfig)
|
|
143
|
+
return orig;
|
|
144
|
+
const { outDir, rootDir, rootDirs } = tsconfig.compilerOptions;
|
|
145
|
+
const rootDirPath = rootDir || (rootDirs || [])[0];
|
|
146
|
+
if (!rootDirPath || !outDir)
|
|
147
|
+
return orig;
|
|
148
|
+
// rewrite path from ./lib/foo to ./src/foo
|
|
149
|
+
const lib = (0, node_path_1.join)(root, outDir); // ./lib
|
|
150
|
+
const src = (0, node_path_1.join)(root, rootDirPath); // ./src
|
|
151
|
+
const relative = (0, node_path_1.relative)(lib, orig); // ./commands
|
|
152
|
+
// For hooks, it might point to a js file, not a module. Something like "./hooks/myhook.js" which doesn't need the js.
|
|
153
|
+
const out = (0, node_path_1.join)(src, relative).replace(/\.js$/, ''); // ./src/commands
|
|
154
|
+
// this can be a directory of commands or point to a hook file
|
|
155
|
+
// if it's a directory, we check if the path exists. If so, return the path to the directory.
|
|
156
|
+
// For hooks, it might point to a module, not a file. Something like "./hooks/myhook"
|
|
157
|
+
// That file doesn't exist, and the real file is "./hooks/myhook.ts"
|
|
158
|
+
// In that case we attempt to resolve to the filename. If it fails it will revert back to the lib path
|
|
159
|
+
if ((0, node_fs_1.existsSync)(out) || (0, node_fs_1.existsSync)(out + '.ts'))
|
|
160
|
+
return out;
|
|
161
|
+
return orig;
|
|
162
|
+
}
|
|
110
163
|
function tsPath(root, orig, plugin) {
|
|
111
164
|
if (plugin?.isRoot)
|
|
112
165
|
ROOT_PLUGIN = plugin;
|
|
@@ -119,51 +172,24 @@ function tsPath(root, orig, plugin) {
|
|
|
119
172
|
return orig;
|
|
120
173
|
}
|
|
121
174
|
const isProduction = (0, util_1.isProd)();
|
|
122
|
-
|
|
123
|
-
* Skip ts-node registration for ESM plugins.
|
|
124
|
-
* The node ecosystem is not mature enough to support auto-transpiling ESM modules at this time.
|
|
125
|
-
* See the following:
|
|
126
|
-
* - https://github.com/TypeStrong/ts-node/issues/1791#issuecomment-1149754228
|
|
127
|
-
* - https://github.com/nodejs/node/issues/49432
|
|
128
|
-
* - https://github.com/nodejs/node/pull/49407
|
|
129
|
-
* - https://github.com/nodejs/node/issues/34049
|
|
130
|
-
*
|
|
131
|
-
* We still register ts-node for ESM plugins when NODE_ENV is "test" or "development" and root plugin is also ESM.
|
|
132
|
-
* In other words, this allows plugins to be auto-transpiled when developing locally using `bin/dev.js`.
|
|
133
|
-
*/
|
|
134
|
-
if ((isProduction || ROOT_PLUGIN?.moduleType === 'commonjs') && plugin?.moduleType === 'module') {
|
|
175
|
+
if (cannotTranspileEsm(root, plugin, isProduction)) {
|
|
135
176
|
debug(`Skipping ts-node registration for ${root} because it's an ESM module (NODE_ENV: ${process.env.NODE_ENV}, root plugin module type: ${ROOT_PLUGIN?.moduleType})))`);
|
|
136
|
-
if (plugin
|
|
137
|
-
(0, errors_1.memoizedWarn)(`${plugin
|
|
177
|
+
if (plugin?.type === 'link')
|
|
178
|
+
(0, errors_1.memoizedWarn)(`${plugin?.name} is a linked ESM module and cannot be auto-transpiled. Existing compiled source will be used instead.`);
|
|
138
179
|
return orig;
|
|
139
180
|
}
|
|
140
181
|
if (settings_1.settings.tsnodeEnabled === undefined && isProduction && plugin?.type !== 'link') {
|
|
141
182
|
debug(`Skipping ts-node registration for ${root} because NODE_ENV is NOT "test" or "development"`);
|
|
142
183
|
return orig;
|
|
143
184
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
return orig;
|
|
148
|
-
const { outDir, rootDir, rootDirs } = tsconfig.compilerOptions;
|
|
149
|
-
const rootDirPath = rootDir || (rootDirs || [])[0];
|
|
150
|
-
if (!rootDirPath || !outDir)
|
|
151
|
-
return orig;
|
|
152
|
-
// rewrite path from ./lib/foo to ./src/foo
|
|
153
|
-
const lib = (0, node_path_1.join)(root, outDir); // ./lib
|
|
154
|
-
const src = (0, node_path_1.join)(root, rootDirPath); // ./src
|
|
155
|
-
const relative = (0, node_path_1.relative)(lib, orig); // ./commands
|
|
156
|
-
// For hooks, it might point to a js file, not a module. Something like "./hooks/myhook.js" which doesn't need the js.
|
|
157
|
-
const out = (0, node_path_1.join)(src, relative).replace(/\.js$/, ''); // ./src/commands
|
|
158
|
-
// this can be a directory of commands or point to a hook file
|
|
159
|
-
// if it's a directory, we check if the path exists. If so, return the path to the directory.
|
|
160
|
-
// For hooks, it might point to a module, not a file. Something like "./hooks/myhook"
|
|
161
|
-
// That file doesn't exist, and the real file is "./hooks/myhook.ts"
|
|
162
|
-
// In that case we attempt to resolve to the filename. If it fails it will revert back to the lib path
|
|
163
|
-
if ((0, node_fs_1.existsSync)(out) || (0, node_fs_1.existsSync)(out + '.ts'))
|
|
164
|
-
return out;
|
|
185
|
+
if (cannotUseTsNode(root, plugin, isProduction)) {
|
|
186
|
+
debug(`Skipping ts-node registration for ${root} because ts-node is run in node version ${process.version}"`);
|
|
187
|
+
(0, errors_1.memoizedWarn)(`ts-node executable cannot transpile ESM in Node 20. Existing compiled source will be used instead. See https://github.com/oclif/core/issues/817.`);
|
|
165
188
|
return orig;
|
|
166
189
|
}
|
|
190
|
+
try {
|
|
191
|
+
return determinePath(root, orig);
|
|
192
|
+
}
|
|
167
193
|
catch (error) {
|
|
168
194
|
debug(error);
|
|
169
195
|
return orig;
|
package/lib/execute.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { LoadOptions } from './interfaces';
|
|
|
7
7
|
*
|
|
8
8
|
* @example For ESM dev.js
|
|
9
9
|
* ```
|
|
10
|
-
* #!/usr/bin/env ts-node
|
|
10
|
+
* #!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning
|
|
11
11
|
* async function main() {
|
|
12
12
|
* const oclif = await import('@oclif/core')
|
|
13
13
|
* await oclif.execute({development: true, dir: import.meta.url})
|
package/lib/execute.js
CHANGED
|
@@ -13,7 +13,7 @@ const settings_1 = require("./settings");
|
|
|
13
13
|
*
|
|
14
14
|
* @example For ESM dev.js
|
|
15
15
|
* ```
|
|
16
|
-
* #!/usr/bin/env ts-node
|
|
16
|
+
* #!/usr/bin/env -S node --loader ts-node/esm --no-warnings=ExperimentalWarning
|
|
17
17
|
* async function main() {
|
|
18
18
|
* const oclif = await import('@oclif/core')
|
|
19
19
|
* await oclif.execute({development: true, dir: import.meta.url})
|