@backstage/cli-node 0.3.2 → 0.3.3
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/CHANGELOG.md +6 -0
- package/README.md +19 -0
- package/dist/cli-module/CommandGraph.cjs.js +95 -0
- package/dist/cli-module/CommandGraph.cjs.js.map +1 -0
- package/dist/cli-module/runCli.cjs.js +247 -0
- package/dist/cli-module/runCli.cjs.js.map +1 -0
- package/dist/cli-module/runCliModule.cjs.js +5 -128
- package/dist/cli-module/runCliModule.cjs.js.map +1 -1
- package/dist/index.cjs.js +2 -0
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +29 -15
- package/package.json +8 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @backstage/cli-node
|
|
2
2
|
|
|
3
|
+
## 0.3.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- b521571: Added `runCli` for creating executable CLI packages from a fixed collection of directly imported CLI modules, with validation for conflicting command paths. The single-module `runCliModule` helper is now deprecated.
|
|
8
|
+
|
|
3
9
|
## 0.3.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -4,6 +4,25 @@ This library provides utilities for building CLI tools for Backstage.
|
|
|
4
4
|
|
|
5
5
|
The difference between this library and `@backstage/cli-common` is that this library is more feature rich with a larger dependency tree, with less concern for bundle size and installation speed. The `@backstage/cli-common` package on the other hand is intended to be extremely slim and only provide minimal features for use in tools like `@backstage/create-app`.
|
|
6
6
|
|
|
7
|
+
## Custom CLIs
|
|
8
|
+
|
|
9
|
+
Use `runCli` to create an executable CLI from a fixed set of directly imported modules:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { runCli } from '@backstage/cli-node';
|
|
13
|
+
import buildModule from '@backstage/cli-module-build';
|
|
14
|
+
import testModule from '@backstage/cli-module-test-jest';
|
|
15
|
+
import packageJson from '../package.json';
|
|
16
|
+
|
|
17
|
+
runCli({
|
|
18
|
+
modules: [buildModule, testModule],
|
|
19
|
+
name: packageJson.name,
|
|
20
|
+
version: packageJson.version,
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The caller owns module selection. The runner does not discover modules or apply module overrides.
|
|
25
|
+
|
|
7
26
|
## Documentation
|
|
8
27
|
|
|
9
28
|
- [Backstage Readme](https://github.com/backstage/backstage/blob/master/README.md)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var InternalCliModule = require('../cli-internal/src/InternalCliModule.cjs.js');
|
|
4
|
+
var InternalCommandNode = require('../cli-internal/src/InternalCommandNode.cjs.js');
|
|
5
|
+
require('node:fs');
|
|
6
|
+
require('node:os');
|
|
7
|
+
require('node:path');
|
|
8
|
+
require('../cli-internal/src/knownPluginPackages.cjs.js');
|
|
9
|
+
|
|
10
|
+
class CommandGraph {
|
|
11
|
+
#roots = [];
|
|
12
|
+
get roots() {
|
|
13
|
+
return this.#roots;
|
|
14
|
+
}
|
|
15
|
+
add(command, module) {
|
|
16
|
+
const { path } = command;
|
|
17
|
+
let current = this.#roots;
|
|
18
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
19
|
+
const name2 = path[i];
|
|
20
|
+
let next = current.find((node) => getNodeName(node) === name2);
|
|
21
|
+
if (!next) {
|
|
22
|
+
next = InternalCommandNode.OpaqueCommandTreeNode.createInstance("v1", {
|
|
23
|
+
name: name2,
|
|
24
|
+
children: []
|
|
25
|
+
});
|
|
26
|
+
current.push(next);
|
|
27
|
+
} else if (InternalCommandNode.OpaqueCommandLeafNode.isType(next)) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
formatConflictError(
|
|
30
|
+
path,
|
|
31
|
+
module,
|
|
32
|
+
InternalCommandNode.OpaqueCommandLeafNode.toInternal(next).module
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
current = InternalCommandNode.OpaqueCommandTreeNode.toInternal(next).children;
|
|
37
|
+
}
|
|
38
|
+
const name = path[path.length - 1];
|
|
39
|
+
const existing = current.find((node) => getNodeName(node) === name);
|
|
40
|
+
if (existing) {
|
|
41
|
+
throw new Error(
|
|
42
|
+
formatConflictError(path, module, findNodeModule(existing))
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
current.push(
|
|
46
|
+
InternalCommandNode.OpaqueCommandLeafNode.createInstance("v1", {
|
|
47
|
+
name,
|
|
48
|
+
command,
|
|
49
|
+
module
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function getNodeName(node) {
|
|
55
|
+
if (InternalCommandNode.OpaqueCommandTreeNode.isType(node)) {
|
|
56
|
+
return InternalCommandNode.OpaqueCommandTreeNode.toInternal(node).name;
|
|
57
|
+
}
|
|
58
|
+
return InternalCommandNode.OpaqueCommandLeafNode.toInternal(node).name;
|
|
59
|
+
}
|
|
60
|
+
function findNodeModule(node) {
|
|
61
|
+
if (InternalCommandNode.OpaqueCommandLeafNode.isType(node)) {
|
|
62
|
+
return InternalCommandNode.OpaqueCommandLeafNode.toInternal(node).module;
|
|
63
|
+
}
|
|
64
|
+
for (const child of InternalCommandNode.OpaqueCommandTreeNode.toInternal(node).children) {
|
|
65
|
+
const module = findNodeModule(child);
|
|
66
|
+
if (module) {
|
|
67
|
+
return module;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return void 0;
|
|
71
|
+
}
|
|
72
|
+
function getModuleName(module) {
|
|
73
|
+
if (module && InternalCliModule.OpaqueCliModule.isType(module)) {
|
|
74
|
+
return InternalCliModule.OpaqueCliModule.toInternal(module).packageName;
|
|
75
|
+
}
|
|
76
|
+
return void 0;
|
|
77
|
+
}
|
|
78
|
+
function formatConflictError(path, newModule, existingModule) {
|
|
79
|
+
const command = path.join(" ");
|
|
80
|
+
const newPackage = getModuleName(newModule);
|
|
81
|
+
const existingPackage = getModuleName(existingModule);
|
|
82
|
+
if (newPackage && existingPackage) {
|
|
83
|
+
return `Command "${command}" from "${newPackage}" conflicts with an existing command from "${existingPackage}"`;
|
|
84
|
+
}
|
|
85
|
+
if (newPackage) {
|
|
86
|
+
return `Command "${command}" from "${newPackage}" conflicts with an existing command`;
|
|
87
|
+
}
|
|
88
|
+
if (existingPackage) {
|
|
89
|
+
return `Command "${command}" conflicts with an existing command from "${existingPackage}"`;
|
|
90
|
+
}
|
|
91
|
+
return `Command "${command}" conflicts with an existing command`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
exports.CommandGraph = CommandGraph;
|
|
95
|
+
//# sourceMappingURL=CommandGraph.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CommandGraph.cjs.js","sources":["../../src/cli-module/CommandGraph.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OpaqueCliModule,\n OpaqueCommandLeafNode,\n OpaqueCommandTreeNode,\n} from '@internal/cli';\nimport type { CommandNode } from '@internal/cli';\nimport type { CliCommand, CliModule } from './types';\n\nexport class CommandGraph {\n readonly #roots: CommandNode[] = [];\n\n get roots(): ReadonlyArray<CommandNode> {\n return this.#roots;\n }\n\n add(command: CliCommand, module: CliModule): void {\n const { path } = command;\n let current = this.#roots;\n\n for (let i = 0; i < path.length - 1; i++) {\n const name = path[i];\n let next = current.find(node => getNodeName(node) === name);\n\n if (!next) {\n next = OpaqueCommandTreeNode.createInstance('v1', {\n name,\n children: [],\n });\n current.push(next);\n } else if (OpaqueCommandLeafNode.isType(next)) {\n throw new Error(\n formatConflictError(\n path,\n module,\n OpaqueCommandLeafNode.toInternal(next).module,\n ),\n );\n }\n\n current = OpaqueCommandTreeNode.toInternal(next).children;\n }\n\n const name = path[path.length - 1];\n const existing = current.find(node => getNodeName(node) === name);\n if (existing) {\n throw new Error(\n formatConflictError(path, module, findNodeModule(existing)),\n );\n }\n\n current.push(\n OpaqueCommandLeafNode.createInstance('v1', {\n name,\n command,\n module,\n }),\n );\n }\n}\n\nfunction getNodeName(node: CommandNode): string {\n if (OpaqueCommandTreeNode.isType(node)) {\n return OpaqueCommandTreeNode.toInternal(node).name;\n }\n return OpaqueCommandLeafNode.toInternal(node).name;\n}\n\nfunction findNodeModule(node: CommandNode): CliModule | undefined {\n if (OpaqueCommandLeafNode.isType(node)) {\n return OpaqueCommandLeafNode.toInternal(node).module;\n }\n\n for (const child of OpaqueCommandTreeNode.toInternal(node).children) {\n const module = findNodeModule(child);\n if (module) {\n return module;\n }\n }\n\n return undefined;\n}\n\nfunction getModuleName(module?: CliModule): string | undefined {\n if (module && OpaqueCliModule.isType(module)) {\n return OpaqueCliModule.toInternal(module).packageName;\n }\n return undefined;\n}\n\nfunction formatConflictError(\n path: string[],\n newModule: CliModule,\n existingModule?: CliModule,\n): string {\n const command = path.join(' ');\n const newPackage = getModuleName(newModule);\n const existingPackage = getModuleName(existingModule);\n\n if (newPackage && existingPackage) {\n return `Command \"${command}\" from \"${newPackage}\" conflicts with an existing command from \"${existingPackage}\"`;\n }\n if (newPackage) {\n return `Command \"${command}\" from \"${newPackage}\" conflicts with an existing command`;\n }\n if (existingPackage) {\n return `Command \"${command}\" conflicts with an existing command from \"${existingPackage}\"`;\n }\n return `Command \"${command}\" conflicts with an existing command`;\n}\n"],"names":["name","OpaqueCommandTreeNode","OpaqueCommandLeafNode","OpaqueCliModule"],"mappings":"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"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var InternalCliModule = require('../cli-internal/src/InternalCliModule.cjs.js');
|
|
4
|
+
var InternalCommandNode = require('../cli-internal/src/InternalCommandNode.cjs.js');
|
|
5
|
+
require('node:fs');
|
|
6
|
+
require('node:os');
|
|
7
|
+
require('node:path');
|
|
8
|
+
require('../cli-internal/src/knownPluginPackages.cjs.js');
|
|
9
|
+
var errors = require('@backstage/errors');
|
|
10
|
+
var chalk = require('chalk');
|
|
11
|
+
var cleye = require('cleye');
|
|
12
|
+
var CommandGraph = require('./CommandGraph.cjs.js');
|
|
13
|
+
|
|
14
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
15
|
+
|
|
16
|
+
var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
|
|
17
|
+
|
|
18
|
+
function exit(message, code = 1) {
|
|
19
|
+
process.stderr.write(`
|
|
20
|
+
${chalk__default.default.red(message)}
|
|
21
|
+
|
|
22
|
+
`);
|
|
23
|
+
process.exit(code);
|
|
24
|
+
}
|
|
25
|
+
function exitWithError(error) {
|
|
26
|
+
if (!errors.isError(error)) {
|
|
27
|
+
return exit(errors.stringifyError(error));
|
|
28
|
+
}
|
|
29
|
+
switch (error.name) {
|
|
30
|
+
case "InputError":
|
|
31
|
+
return exit(
|
|
32
|
+
error.message,
|
|
33
|
+
74
|
|
34
|
+
/* input/output error */
|
|
35
|
+
);
|
|
36
|
+
case "NotFoundError":
|
|
37
|
+
return exit(
|
|
38
|
+
error.message,
|
|
39
|
+
127
|
|
40
|
+
/* command not found */
|
|
41
|
+
);
|
|
42
|
+
case "NotImplementedError":
|
|
43
|
+
return exit(
|
|
44
|
+
error.message,
|
|
45
|
+
64
|
|
46
|
+
/* command line usage error */
|
|
47
|
+
);
|
|
48
|
+
case "AuthenticationError":
|
|
49
|
+
case "NotAllowedError":
|
|
50
|
+
return exit(
|
|
51
|
+
error.message,
|
|
52
|
+
77
|
|
53
|
+
/* permission denied */
|
|
54
|
+
);
|
|
55
|
+
case "ExitCodeError":
|
|
56
|
+
return exit(
|
|
57
|
+
error.message,
|
|
58
|
+
"code" in error && typeof error.code === "number" ? error.code : 1
|
|
59
|
+
);
|
|
60
|
+
default:
|
|
61
|
+
return exit(
|
|
62
|
+
errors.stringifyError(error),
|
|
63
|
+
"code" in error && typeof error.code === "number" ? error.code : 1
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function getNodeName(node) {
|
|
68
|
+
if (InternalCommandNode.OpaqueCommandTreeNode.isType(node)) {
|
|
69
|
+
return InternalCommandNode.OpaqueCommandTreeNode.toInternal(node).name;
|
|
70
|
+
}
|
|
71
|
+
return InternalCommandNode.OpaqueCommandLeafNode.toInternal(node).name;
|
|
72
|
+
}
|
|
73
|
+
function getNodeDescription(node) {
|
|
74
|
+
if (InternalCommandNode.OpaqueCommandTreeNode.isType(node)) {
|
|
75
|
+
return InternalCommandNode.OpaqueCommandTreeNode.toInternal(node).name;
|
|
76
|
+
}
|
|
77
|
+
return InternalCommandNode.OpaqueCommandLeafNode.toInternal(node).command.description;
|
|
78
|
+
}
|
|
79
|
+
function createHelpOptions(options) {
|
|
80
|
+
const { nodes, includeHelpCommand, version } = options;
|
|
81
|
+
const visibleNodes = nodes.filter((node) => !InternalCommandNode.isCommandNodeHidden(node));
|
|
82
|
+
return {
|
|
83
|
+
version,
|
|
84
|
+
render(nodesToRender, renderers) {
|
|
85
|
+
const commandsNode = nodesToRender.find((node) => node.id === "commands");
|
|
86
|
+
if (commandsNode) {
|
|
87
|
+
const commandRows = visibleNodes.map((node) => [
|
|
88
|
+
getNodeName(node),
|
|
89
|
+
getNodeDescription(node)
|
|
90
|
+
]);
|
|
91
|
+
if (includeHelpCommand) {
|
|
92
|
+
commandRows.push(["help", "Display help for command"]);
|
|
93
|
+
}
|
|
94
|
+
commandsNode.data.body.data.tableData = commandRows;
|
|
95
|
+
}
|
|
96
|
+
return renderers.render(nodesToRender);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
async function executeCommand(commandToExecute, args, programName) {
|
|
101
|
+
const context = {
|
|
102
|
+
args,
|
|
103
|
+
info: {
|
|
104
|
+
usage: [programName, ...commandToExecute.path].join(" "),
|
|
105
|
+
name: commandToExecute.path.join(" ")
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
if (typeof commandToExecute.execute === "function") {
|
|
109
|
+
await commandToExecute.execute(context);
|
|
110
|
+
} else {
|
|
111
|
+
const mod = await commandToExecute.execute.loader();
|
|
112
|
+
const fn = typeof mod.default === "function" ? mod.default : mod.default.default;
|
|
113
|
+
await fn(context);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
async function runCommandLevel(options) {
|
|
117
|
+
const { nodes, argv, programName, commandPath = [], version } = options;
|
|
118
|
+
const name = [programName, ...commandPath].join(" ");
|
|
119
|
+
const commandArgs = argv.slice(1);
|
|
120
|
+
const commands = nodes.map(
|
|
121
|
+
(node) => cleye.command(
|
|
122
|
+
{
|
|
123
|
+
name: getNodeName(node),
|
|
124
|
+
help: false
|
|
125
|
+
},
|
|
126
|
+
async () => {
|
|
127
|
+
try {
|
|
128
|
+
if (InternalCommandNode.OpaqueCommandTreeNode.isType(node)) {
|
|
129
|
+
await runCommandLevel({
|
|
130
|
+
nodes: InternalCommandNode.OpaqueCommandTreeNode.toInternal(node).children,
|
|
131
|
+
argv: commandArgs,
|
|
132
|
+
programName,
|
|
133
|
+
commandPath: [...commandPath, getNodeName(node)],
|
|
134
|
+
version
|
|
135
|
+
});
|
|
136
|
+
} else {
|
|
137
|
+
await executeCommand(
|
|
138
|
+
InternalCommandNode.OpaqueCommandLeafNode.toInternal(node).command,
|
|
139
|
+
commandArgs,
|
|
140
|
+
programName
|
|
141
|
+
);
|
|
142
|
+
process.exit(0);
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
exitWithError(error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
)
|
|
149
|
+
);
|
|
150
|
+
const includeHelpCommand = !nodes.some((node) => getNodeName(node) === "help");
|
|
151
|
+
if (includeHelpCommand && nodes.length > 0) {
|
|
152
|
+
commands.push(
|
|
153
|
+
cleye.command(
|
|
154
|
+
{
|
|
155
|
+
name: "help",
|
|
156
|
+
parameters: ["[command...]"],
|
|
157
|
+
help: false
|
|
158
|
+
},
|
|
159
|
+
async () => {
|
|
160
|
+
await runCommandLevel({
|
|
161
|
+
nodes,
|
|
162
|
+
argv: [...commandArgs, "--help"],
|
|
163
|
+
programName,
|
|
164
|
+
commandPath,
|
|
165
|
+
version
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
)
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
await cleye.cli(
|
|
172
|
+
{
|
|
173
|
+
name,
|
|
174
|
+
flags: version ? {
|
|
175
|
+
version: {
|
|
176
|
+
type: Boolean,
|
|
177
|
+
alias: "V",
|
|
178
|
+
description: "Show version"
|
|
179
|
+
}
|
|
180
|
+
} : void 0,
|
|
181
|
+
commands,
|
|
182
|
+
help: createHelpOptions({
|
|
183
|
+
nodes,
|
|
184
|
+
includeHelpCommand: includeHelpCommand && nodes.length > 0,
|
|
185
|
+
version
|
|
186
|
+
})
|
|
187
|
+
},
|
|
188
|
+
(parsed) => {
|
|
189
|
+
if (version && parsed.flags.version) {
|
|
190
|
+
console.log(version);
|
|
191
|
+
process.exit(0);
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (argv.length === 0) {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
console.log();
|
|
198
|
+
console.log(
|
|
199
|
+
chalk__default.default.red(`Invalid command: ${[...commandPath, ...argv].join(" ")}`)
|
|
200
|
+
);
|
|
201
|
+
console.log();
|
|
202
|
+
parsed.showHelp();
|
|
203
|
+
process.exit(1);
|
|
204
|
+
},
|
|
205
|
+
[...argv]
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
function handleUnhandledRejection(rejection) {
|
|
209
|
+
exitWithError(new errors.ForwardedError("Unhandled rejection", rejection));
|
|
210
|
+
}
|
|
211
|
+
function hasVersionFlag(args) {
|
|
212
|
+
const separatorIndex = args.indexOf("--");
|
|
213
|
+
const options = separatorIndex === -1 ? args : args.slice(0, separatorIndex);
|
|
214
|
+
return options.includes("-V") || options.includes("--version");
|
|
215
|
+
}
|
|
216
|
+
async function runCli(options) {
|
|
217
|
+
const { modules, name, version } = options;
|
|
218
|
+
const graph = new CommandGraph.CommandGraph();
|
|
219
|
+
for (const module of modules) {
|
|
220
|
+
if (!InternalCliModule.OpaqueCliModule.isType(module)) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
`Invalid CLI module: expected a module created with createCliModule`
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
for (const commandToAdd of await InternalCliModule.OpaqueCliModule.toInternal(module).commands) {
|
|
226
|
+
graph.add(commandToAdd, module);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
if (!process.listeners("unhandledRejection").includes(handleUnhandledRejection)) {
|
|
230
|
+
process.on("unhandledRejection", handleUnhandledRejection);
|
|
231
|
+
}
|
|
232
|
+
const args = process.argv.slice(2);
|
|
233
|
+
if (version && hasVersionFlag(args)) {
|
|
234
|
+
console.log(version);
|
|
235
|
+
process.exit(0);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
await runCommandLevel({
|
|
239
|
+
nodes: graph.roots,
|
|
240
|
+
argv: args,
|
|
241
|
+
programName: name,
|
|
242
|
+
version
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
exports.runCli = runCli;
|
|
247
|
+
//# sourceMappingURL=runCli.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runCli.cjs.js","sources":["../../src/cli-module/runCli.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OpaqueCliModule,\n OpaqueCommandLeafNode,\n OpaqueCommandTreeNode,\n isCommandNodeHidden,\n} from '@internal/cli';\nimport type { CommandNode } from '@internal/cli';\nimport { ForwardedError, isError, stringifyError } from '@backstage/errors';\nimport chalk from 'chalk';\nimport { cli, command } from 'cleye';\nimport type { Renderers } from 'cleye';\nimport { CommandGraph } from './CommandGraph';\nimport type { CliCommand, CliModule } from './types';\n\ninterface HelpNode {\n id?: string;\n type: keyof Renderers;\n data: unknown;\n}\n\ninterface CommandsHelpData {\n body: {\n data: {\n tableData: string[][];\n };\n };\n}\n\nfunction exit(message: string, code: number = 1): never {\n process.stderr.write(`\\n${chalk.red(message)}\\n\\n`);\n process.exit(code);\n}\n\nfunction exitWithError(error: unknown): never {\n if (!isError(error)) {\n return exit(stringifyError(error));\n }\n\n switch (error.name) {\n case 'InputError':\n return exit(error.message, 74 /* input/output error */);\n case 'NotFoundError':\n return exit(error.message, 127 /* command not found */);\n case 'NotImplementedError':\n return exit(error.message, 64 /* command line usage error */);\n case 'AuthenticationError':\n case 'NotAllowedError':\n return exit(error.message, 77 /* permission denied */);\n case 'ExitCodeError':\n return exit(\n error.message,\n 'code' in error && typeof error.code === 'number' ? error.code : 1,\n );\n default:\n return exit(\n stringifyError(error),\n 'code' in error && typeof error.code === 'number' ? error.code : 1,\n );\n }\n}\n\nfunction getNodeName(node: CommandNode): string {\n if (OpaqueCommandTreeNode.isType(node)) {\n return OpaqueCommandTreeNode.toInternal(node).name;\n }\n return OpaqueCommandLeafNode.toInternal(node).name;\n}\n\nfunction getNodeDescription(node: CommandNode): string {\n if (OpaqueCommandTreeNode.isType(node)) {\n return OpaqueCommandTreeNode.toInternal(node).name;\n }\n return OpaqueCommandLeafNode.toInternal(node).command.description;\n}\n\nfunction createHelpOptions(options: {\n nodes: ReadonlyArray<CommandNode>;\n includeHelpCommand: boolean;\n version?: string;\n}) {\n const { nodes, includeHelpCommand, version } = options;\n const visibleNodes = nodes.filter(node => !isCommandNodeHidden(node));\n\n return {\n version,\n render(nodesToRender: HelpNode[], renderers: Renderers) {\n const commandsNode = nodesToRender.find(node => node.id === 'commands');\n if (commandsNode) {\n const commandRows = visibleNodes.map(node => [\n getNodeName(node),\n getNodeDescription(node),\n ]);\n if (includeHelpCommand) {\n commandRows.push(['help', 'Display help for command']);\n }\n (commandsNode.data as CommandsHelpData).body.data.tableData =\n commandRows;\n }\n return renderers.render(nodesToRender);\n },\n };\n}\n\nasync function executeCommand(\n commandToExecute: CliCommand,\n args: string[],\n programName: string,\n): Promise<void> {\n const context = {\n args,\n info: {\n usage: [programName, ...commandToExecute.path].join(' '),\n name: commandToExecute.path.join(' '),\n },\n };\n\n if (typeof commandToExecute.execute === 'function') {\n await commandToExecute.execute(context);\n } else {\n const mod = await commandToExecute.execute.loader();\n const fn =\n typeof mod.default === 'function'\n ? mod.default\n : (mod.default as any).default;\n await fn(context);\n }\n}\n\nasync function runCommandLevel(options: {\n nodes: ReadonlyArray<CommandNode>;\n argv: string[];\n programName: string;\n commandPath?: string[];\n version?: string;\n}): Promise<void> {\n const { nodes, argv, programName, commandPath = [], version } = options;\n const name = [programName, ...commandPath].join(' ');\n const commandArgs = argv.slice(1);\n const commands = nodes.map(node =>\n command(\n {\n name: getNodeName(node),\n help: false,\n },\n async () => {\n try {\n if (OpaqueCommandTreeNode.isType(node)) {\n await runCommandLevel({\n nodes: OpaqueCommandTreeNode.toInternal(node).children,\n argv: commandArgs,\n programName,\n commandPath: [...commandPath, getNodeName(node)],\n version,\n });\n } else {\n await executeCommand(\n OpaqueCommandLeafNode.toInternal(node).command,\n commandArgs,\n programName,\n );\n process.exit(0);\n }\n } catch (error: unknown) {\n exitWithError(error);\n }\n },\n ),\n );\n const includeHelpCommand = !nodes.some(node => getNodeName(node) === 'help');\n if (includeHelpCommand && nodes.length > 0) {\n commands.push(\n command(\n {\n name: 'help',\n parameters: ['[command...]'],\n help: false,\n },\n async () => {\n await runCommandLevel({\n nodes,\n argv: [...commandArgs, '--help'],\n programName,\n commandPath,\n version,\n });\n },\n ),\n );\n }\n\n await cli(\n {\n name,\n flags: version\n ? {\n version: {\n type: Boolean,\n alias: 'V',\n description: 'Show version',\n },\n }\n : undefined,\n commands,\n help: createHelpOptions({\n nodes,\n includeHelpCommand: includeHelpCommand && nodes.length > 0,\n version,\n }),\n },\n parsed => {\n if (version && parsed.flags.version) {\n console.log(version);\n process.exit(0);\n return;\n }\n\n if (argv.length === 0) {\n return;\n }\n\n console.log();\n console.log(\n chalk.red(`Invalid command: ${[...commandPath, ...argv].join(' ')}`),\n );\n console.log();\n parsed.showHelp();\n process.exit(1);\n },\n [...argv],\n );\n}\n\nfunction handleUnhandledRejection(rejection: unknown): void {\n exitWithError(new ForwardedError('Unhandled rejection', rejection));\n}\n\nfunction hasVersionFlag(args: string[]): boolean {\n const separatorIndex = args.indexOf('--');\n const options = separatorIndex === -1 ? args : args.slice(0, separatorIndex);\n return options.includes('-V') || options.includes('--version');\n}\n\n/**\n * Runs a collection of CLI modules as an executable program.\n *\n * This is intended for creating custom CLI packages from a fixed set of\n * directly imported modules. Module discovery and override behavior are left\n * to the caller.\n *\n * @example\n * ```ts\n * import { runCli } from '@backstage/cli-node';\n * import buildModule from '@backstage/cli-module-build';\n * import testModule from '@backstage/cli-module-test-jest';\n * import packageJson from '../package.json';\n *\n * runCli({\n * modules: [buildModule, testModule],\n * name: packageJson.name,\n * version: packageJson.version,\n * });\n * ```\n *\n * @public\n */\nexport async function runCli(options: {\n /** The CLI modules whose commands are included in the program. */\n modules: ReadonlyArray<CliModule>;\n /** The program name shown in help output and usage strings. */\n name: string;\n /** The version string shown when `--version` is passed. */\n version?: string;\n}): Promise<void> {\n const { modules, name, version } = options;\n const graph = new CommandGraph();\n\n for (const module of modules) {\n if (!OpaqueCliModule.isType(module)) {\n throw new Error(\n `Invalid CLI module: expected a module created with createCliModule`,\n );\n }\n\n for (const commandToAdd of await OpaqueCliModule.toInternal(module)\n .commands) {\n graph.add(commandToAdd, module);\n }\n }\n\n if (\n !process.listeners('unhandledRejection').includes(handleUnhandledRejection)\n ) {\n process.on('unhandledRejection', handleUnhandledRejection);\n }\n\n const args = process.argv.slice(2);\n if (version && hasVersionFlag(args)) {\n console.log(version);\n process.exit(0);\n return;\n }\n\n await runCommandLevel({\n nodes: graph.roots,\n argv: args,\n programName: name,\n version,\n });\n}\n"],"names":["chalk","isError","stringifyError","OpaqueCommandTreeNode","OpaqueCommandLeafNode","isCommandNodeHidden","command","cli","ForwardedError","CommandGraph","OpaqueCliModule"],"mappings":"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"}
|
|
@@ -1,137 +1,14 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var InternalCommandNode = require('../cli-internal/src/InternalCommandNode.cjs.js');
|
|
5
|
-
require('node:fs');
|
|
6
|
-
require('node:os');
|
|
7
|
-
require('node:path');
|
|
8
|
-
require('../cli-internal/src/knownPluginPackages.cjs.js');
|
|
9
|
-
var commander = require('commander');
|
|
10
|
-
var chalk = require('chalk');
|
|
11
|
-
var errors = require('@backstage/errors');
|
|
3
|
+
var runCli = require('./runCli.cjs.js');
|
|
12
4
|
|
|
13
|
-
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
14
|
-
|
|
15
|
-
var chalk__default = /*#__PURE__*/_interopDefaultCompat(chalk);
|
|
16
|
-
|
|
17
|
-
function buildCommandGraph(commands) {
|
|
18
|
-
const graph = [];
|
|
19
|
-
for (const command of commands) {
|
|
20
|
-
const { path } = command;
|
|
21
|
-
let current = graph;
|
|
22
|
-
for (let i = 0; i < path.length - 1; i++) {
|
|
23
|
-
const name = path[i];
|
|
24
|
-
let next = current.find(
|
|
25
|
-
(n) => InternalCommandNode.OpaqueCommandTreeNode.isType(n) && InternalCommandNode.OpaqueCommandTreeNode.toInternal(n).name === name
|
|
26
|
-
);
|
|
27
|
-
if (!next) {
|
|
28
|
-
next = InternalCommandNode.OpaqueCommandTreeNode.createInstance("v1", {
|
|
29
|
-
name,
|
|
30
|
-
children: []
|
|
31
|
-
});
|
|
32
|
-
current.push(next);
|
|
33
|
-
}
|
|
34
|
-
current = InternalCommandNode.OpaqueCommandTreeNode.toInternal(next).children;
|
|
35
|
-
}
|
|
36
|
-
current.push(
|
|
37
|
-
InternalCommandNode.OpaqueCommandLeafNode.createInstance("v1", {
|
|
38
|
-
name: path[path.length - 1],
|
|
39
|
-
command
|
|
40
|
-
})
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
return graph;
|
|
44
|
-
}
|
|
45
|
-
function exitWithError(error) {
|
|
46
|
-
process.stderr.write(`
|
|
47
|
-
${chalk__default.default.red(errors.stringifyError(error))}
|
|
48
|
-
|
|
49
|
-
`);
|
|
50
|
-
process.exit(
|
|
51
|
-
errors.isError(error) && "code" in error && typeof error.code === "number" ? error.code : 1
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
function registerCommands(graph, program, programName) {
|
|
55
|
-
const queue = graph.map((node) => ({ node, argParser: program }));
|
|
56
|
-
while (queue.length) {
|
|
57
|
-
const { node, argParser } = queue.shift();
|
|
58
|
-
if (InternalCommandNode.OpaqueCommandTreeNode.isType(node)) {
|
|
59
|
-
const internal = InternalCommandNode.OpaqueCommandTreeNode.toInternal(node);
|
|
60
|
-
const treeParser = argParser.command(`${internal.name} [command]`, {
|
|
61
|
-
hidden: InternalCommandNode.isCommandNodeHidden(node)
|
|
62
|
-
}).description(internal.name);
|
|
63
|
-
queue.push(
|
|
64
|
-
...internal.children.map((child) => ({
|
|
65
|
-
node: child,
|
|
66
|
-
argParser: treeParser
|
|
67
|
-
}))
|
|
68
|
-
);
|
|
69
|
-
} else {
|
|
70
|
-
const internal = InternalCommandNode.OpaqueCommandLeafNode.toInternal(node);
|
|
71
|
-
argParser.command(internal.name, {
|
|
72
|
-
hidden: !!internal.command.deprecated || !!internal.command.experimental
|
|
73
|
-
}).description(internal.command.description).helpOption(false).allowUnknownOption(true).allowExcessArguments(true).action(async () => {
|
|
74
|
-
try {
|
|
75
|
-
const args = program.parseOptions(process.argv);
|
|
76
|
-
const nonProcessArgs = args.operands.slice(2);
|
|
77
|
-
const positionalArgs = [];
|
|
78
|
-
let index = 0;
|
|
79
|
-
for (let argIndex = 0; argIndex < nonProcessArgs.length; argIndex++) {
|
|
80
|
-
if (argIndex === index && internal.command.path[argIndex] === nonProcessArgs[argIndex]) {
|
|
81
|
-
index += 1;
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
positionalArgs.push(nonProcessArgs[argIndex]);
|
|
85
|
-
}
|
|
86
|
-
const context = {
|
|
87
|
-
args: [...positionalArgs, ...args.unknown],
|
|
88
|
-
info: {
|
|
89
|
-
usage: [programName, ...internal.command.path].join(" "),
|
|
90
|
-
name: internal.command.path.join(" ")
|
|
91
|
-
}
|
|
92
|
-
};
|
|
93
|
-
if (typeof internal.command.execute === "function") {
|
|
94
|
-
await internal.command.execute(context);
|
|
95
|
-
} else {
|
|
96
|
-
const mod = await internal.command.execute.loader();
|
|
97
|
-
const fn = typeof mod.default === "function" ? mod.default : mod.default.default;
|
|
98
|
-
await fn(context);
|
|
99
|
-
}
|
|
100
|
-
process.exit(0);
|
|
101
|
-
} catch (error) {
|
|
102
|
-
exitWithError(error);
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
5
|
async function runCliModule(options) {
|
|
109
6
|
const { module: cliModule, name, version } = options;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
const internal = InternalCliModule.OpaqueCliModule.toInternal(cliModule);
|
|
116
|
-
const commands = await internal.commands;
|
|
117
|
-
const graph = buildCommandGraph(commands);
|
|
118
|
-
const program = new commander.Command();
|
|
119
|
-
program.name(name).allowUnknownOption(true).allowExcessArguments(true);
|
|
120
|
-
if (version) {
|
|
121
|
-
program.version(version);
|
|
122
|
-
}
|
|
123
|
-
registerCommands(graph, program, name);
|
|
124
|
-
program.on("command:*", () => {
|
|
125
|
-
console.log();
|
|
126
|
-
console.log(chalk__default.default.red(`Invalid command: ${program.args.join(" ")}`));
|
|
127
|
-
console.log();
|
|
128
|
-
program.outputHelp();
|
|
129
|
-
process.exit(1);
|
|
130
|
-
});
|
|
131
|
-
process.on("unhandledRejection", (rejection) => {
|
|
132
|
-
exitWithError(rejection);
|
|
7
|
+
return runCli.runCli({
|
|
8
|
+
modules: [cliModule],
|
|
9
|
+
name,
|
|
10
|
+
version
|
|
133
11
|
});
|
|
134
|
-
await program.parseAsync(process.argv);
|
|
135
12
|
}
|
|
136
13
|
|
|
137
14
|
exports.runCliModule = runCliModule;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runCliModule.cjs.js","sources":["../../src/cli-module/runCliModule.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OpaqueCliModule,\n OpaqueCommandTreeNode,\n OpaqueCommandLeafNode,\n isCommandNodeHidden,\n} from '@internal/cli';\nimport type { CommandNode } from '@internal/cli';\nimport { Command } from 'commander';\nimport chalk from 'chalk';\nimport { isError, stringifyError } from '@backstage/errors';\nimport type { CliModule, CliCommand } from './types';\n\nfunction buildCommandGraph(commands: ReadonlyArray<CliCommand>): CommandNode[] {\n const graph: CommandNode[] = [];\n\n for (const command of commands) {\n const { path } = command;\n let current = graph;\n\n for (let i = 0; i < path.length - 1; i++) {\n const name = path[i];\n let next = current.find(\n n =>\n OpaqueCommandTreeNode.isType(n) &&\n OpaqueCommandTreeNode.toInternal(n).name === name,\n );\n if (!next) {\n next = OpaqueCommandTreeNode.createInstance('v1', {\n name,\n children: [],\n });\n current.push(next);\n }\n current = OpaqueCommandTreeNode.toInternal(next).children;\n }\n\n current.push(\n OpaqueCommandLeafNode.createInstance('v1', {\n name: path[path.length - 1],\n command,\n }),\n );\n }\n\n return graph;\n}\n\nfunction exitWithError(error: unknown): never {\n process.stderr.write(`\\n${chalk.red(stringifyError(error))}\\n\\n`);\n process.exit(\n isError(error) && 'code' in error && typeof error.code === 'number'\n ? error.code\n : 1,\n );\n}\n\nfunction registerCommands(\n graph: CommandNode[],\n program: Command,\n programName: string,\n): void {\n const queue = graph.map(node => ({ node, argParser: program }));\n\n while (queue.length) {\n const { node, argParser } = queue.shift()!;\n\n if (OpaqueCommandTreeNode.isType(node)) {\n const internal = OpaqueCommandTreeNode.toInternal(node);\n const treeParser = argParser\n .command(`${internal.name} [command]`, {\n hidden: isCommandNodeHidden(node),\n })\n .description(internal.name);\n\n queue.push(\n ...internal.children.map(child => ({\n node: child,\n argParser: treeParser,\n })),\n );\n } else {\n const internal = OpaqueCommandLeafNode.toInternal(node);\n argParser\n .command(internal.name, {\n hidden:\n !!internal.command.deprecated || !!internal.command.experimental,\n })\n .description(internal.command.description)\n .helpOption(false)\n .allowUnknownOption(true)\n .allowExcessArguments(true)\n .action(async () => {\n try {\n const args = program.parseOptions(process.argv);\n\n const nonProcessArgs = args.operands.slice(2);\n const positionalArgs = [];\n let index = 0;\n for (\n let argIndex = 0;\n argIndex < nonProcessArgs.length;\n argIndex++\n ) {\n if (\n argIndex === index &&\n internal.command.path[argIndex] === nonProcessArgs[argIndex]\n ) {\n index += 1;\n continue;\n }\n positionalArgs.push(nonProcessArgs[argIndex]);\n }\n const context = {\n args: [...positionalArgs, ...args.unknown],\n info: {\n usage: [programName, ...internal.command.path].join(' '),\n name: internal.command.path.join(' '),\n },\n };\n\n if (typeof internal.command.execute === 'function') {\n await internal.command.execute(context);\n } else {\n const mod = await internal.command.execute.loader();\n const fn =\n typeof mod.default === 'function'\n ? mod.default\n : (mod.default as any).default;\n await fn(context);\n }\n process.exit(0);\n } catch (error: unknown) {\n exitWithError(error);\n }\n });\n }\n }\n}\n\n/**\n * Runs a CLI module as a standalone program.\n *\n * This helper extracts the commands from a {@link CliModule} and exposes\n * them as a fully functional CLI with help output and argument parsing.\n * It is intended to be called from a module package's `bin` entry point\n * so that the module can be executed directly without being wired into\n * a larger CLI host.\n *\n * @example\n * ```ts\n * #!/usr/bin/env node\n * import { runCliModule } from '@backstage/cli-node';\n * import cliModule from './index';\n *\n * runCliModule({\n * module: cliModule,\n * name: 'backstage-auth',\n * version: require('../package.json').version,\n * });\n * ```\n *\n * @public\n */\nexport async function runCliModule(options: {\n /** The CLI module to run. */\n module: CliModule;\n /** The program name shown in help output and usage strings. */\n name: string;\n /** The version string shown when `--version` is passed. */\n version?: string;\n}): Promise<void> {\n const { module: cliModule, name, version } = options;\n\n if (!OpaqueCliModule.isType(cliModule)) {\n throw new Error(\n `Invalid CLI module: expected a module created with createCliModule`,\n );\n }\n\n const internal = OpaqueCliModule.toInternal(cliModule);\n const commands = await internal.commands;\n const graph = buildCommandGraph(commands);\n\n const program = new Command();\n program.name(name).allowUnknownOption(true).allowExcessArguments(true);\n\n if (version) {\n program.version(version);\n }\n\n registerCommands(graph, program, name);\n\n program.on('command:*', () => {\n console.log();\n console.log(chalk.red(`Invalid command: ${program.args.join(' ')}`));\n console.log();\n program.outputHelp();\n process.exit(1);\n });\n\n process.on('unhandledRejection', rejection => {\n exitWithError(rejection);\n });\n\n await program.parseAsync(process.argv);\n}\n"],"names":["OpaqueCommandTreeNode","OpaqueCommandLeafNode","chalk","stringifyError","isError","isCommandNodeHidden","OpaqueCliModule","Command"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runCliModule.cjs.js","sources":["../../src/cli-module/runCliModule.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { CliModule } from './types';\nimport { runCli } from './runCli';\n\n/**\n * Runs a CLI module as a standalone program.\n *\n * @deprecated Use {@link runCli} with a single entry in the `modules` array instead.\n * @public\n */\nexport async function runCliModule(options: {\n /** The CLI module to run. */\n module: CliModule;\n /** The program name shown in help output and usage strings. */\n name: string;\n /** The version string shown when `--version` is passed. */\n version?: string;\n}): Promise<void> {\n const { module: cliModule, name, version } = options;\n\n return runCli({\n modules: [cliModule],\n name,\n version,\n });\n}\n"],"names":["runCli"],"mappings":";;;;AAyBA,eAAsB,aAAa,OAAA,EAOjB;AAChB,EAAA,MAAM,EAAE,MAAA,EAAQ,SAAA,EAAW,IAAA,EAAM,SAAQ,GAAI,OAAA;AAE7C,EAAA,OAAOA,aAAA,CAAO;AAAA,IACZ,OAAA,EAAS,CAAC,SAAS,CAAA;AAAA,IACnB,IAAA;AAAA,IACA;AAAA,GACD,CAAA;AACH;;;;"}
|
package/dist/index.cjs.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var CliAuth = require('./auth/CliAuth.cjs.js');
|
|
4
4
|
var SuccessCache = require('./cache/SuccessCache.cjs.js');
|
|
5
5
|
var createCliModule = require('./cli-module/createCliModule.cjs.js');
|
|
6
|
+
var runCli = require('./cli-module/runCli.cjs.js');
|
|
6
7
|
var runCliModule = require('./cli-module/runCliModule.cjs.js');
|
|
7
8
|
var runConcurrentTasks = require('./concurrency/runConcurrentTasks.cjs.js');
|
|
8
9
|
var runWorkerQueueThreads = require('./concurrency/runWorkerQueueThreads.cjs.js');
|
|
@@ -18,6 +19,7 @@ var yarnPlugin = require('./yarn/yarnPlugin.cjs.js');
|
|
|
18
19
|
exports.CliAuth = CliAuth.CliAuth;
|
|
19
20
|
exports.SuccessCache = SuccessCache.SuccessCache;
|
|
20
21
|
exports.createCliModule = createCliModule.createCliModule;
|
|
22
|
+
exports.runCli = runCli.runCli;
|
|
21
23
|
exports.runCliModule = runCliModule.runCliModule;
|
|
22
24
|
exports.runConcurrentTasks = runConcurrentTasks.runConcurrentTasks;
|
|
23
25
|
exports.runWorkerQueueThreads = runWorkerQueueThreads.runWorkerQueueThreads;
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -215,29 +215,43 @@ declare function createCliModule(options: {
|
|
|
215
215
|
}): CliModule;
|
|
216
216
|
|
|
217
217
|
/**
|
|
218
|
-
* Runs a CLI
|
|
218
|
+
* Runs a collection of CLI modules as an executable program.
|
|
219
219
|
*
|
|
220
|
-
* This
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
* so that the module can be executed directly without being wired into
|
|
224
|
-
* a larger CLI host.
|
|
220
|
+
* This is intended for creating custom CLI packages from a fixed set of
|
|
221
|
+
* directly imported modules. Module discovery and override behavior are left
|
|
222
|
+
* to the caller.
|
|
225
223
|
*
|
|
226
224
|
* @example
|
|
227
225
|
* ```ts
|
|
228
|
-
*
|
|
229
|
-
* import
|
|
230
|
-
* import
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
226
|
+
* import { runCli } from '@backstage/cli-node';
|
|
227
|
+
* import buildModule from '@backstage/cli-module-build';
|
|
228
|
+
* import testModule from '@backstage/cli-module-test-jest';
|
|
229
|
+
* import packageJson from '../package.json';
|
|
230
|
+
*
|
|
231
|
+
* runCli({
|
|
232
|
+
* modules: [buildModule, testModule],
|
|
233
|
+
* name: packageJson.name,
|
|
234
|
+
* version: packageJson.version,
|
|
236
235
|
* });
|
|
237
236
|
* ```
|
|
238
237
|
*
|
|
239
238
|
* @public
|
|
240
239
|
*/
|
|
240
|
+
declare function runCli(options: {
|
|
241
|
+
/** The CLI modules whose commands are included in the program. */
|
|
242
|
+
modules: ReadonlyArray<CliModule>;
|
|
243
|
+
/** The program name shown in help output and usage strings. */
|
|
244
|
+
name: string;
|
|
245
|
+
/** The version string shown when `--version` is passed. */
|
|
246
|
+
version?: string;
|
|
247
|
+
}): Promise<void>;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Runs a CLI module as a standalone program.
|
|
251
|
+
*
|
|
252
|
+
* @deprecated Use {@link runCli} with a single entry in the `modules` array instead.
|
|
253
|
+
* @public
|
|
254
|
+
*/
|
|
241
255
|
declare function runCliModule(options: {
|
|
242
256
|
/** The CLI module to run. */
|
|
243
257
|
module: CliModule;
|
|
@@ -629,5 +643,5 @@ declare class Lockfile {
|
|
|
629
643
|
*/
|
|
630
644
|
declare function hasBackstageYarnPlugin(workspaceDir?: string): Promise<boolean>;
|
|
631
645
|
|
|
632
|
-
export { CliAuth, GitUtils, Lockfile, PackageGraph, PackageRoles, SuccessCache, createCliModule, hasBackstageYarnPlugin, isMonoRepo, packageFeatureType, runCliModule, runConcurrentTasks, runWorkerQueueThreads };
|
|
646
|
+
export { CliAuth, GitUtils, Lockfile, PackageGraph, PackageRoles, SuccessCache, createCliModule, hasBackstageYarnPlugin, isMonoRepo, packageFeatureType, runCli, runCliModule, runConcurrentTasks, runWorkerQueueThreads };
|
|
633
647
|
export type { BackstagePackage, BackstagePackageFeatureType, BackstagePackageJson, CliAuthCreateOptions, CliCommand, CliCommandContext, CliModule, ConcurrentTasksOptions, LockfileDiff, LockfileDiffEntry, LockfileQueryEntry, PackageGraphNode, PackageOutputType, PackagePlatform, PackageRole, PackageRoleInfo, WorkerQueueThreadsOptions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/cli-node",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Node.js library for Backstage CLIs",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"@yarnpkg/lockfile": "^1.1.0",
|
|
40
40
|
"@yarnpkg/parsers": "^3.0.0",
|
|
41
41
|
"chalk": "^4.0.0",
|
|
42
|
-
"
|
|
42
|
+
"cleye": "^2.6.0",
|
|
43
43
|
"fs-extra": "^11.2.0",
|
|
44
44
|
"pirates": "^4.0.6",
|
|
45
45
|
"proper-lockfile": "^4.1.2",
|
|
@@ -48,15 +48,12 @@
|
|
|
48
48
|
"zod": "^3.25.76 || ^4.0.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@backstage/backend-test-utils": "^1.11.
|
|
52
|
-
"@backstage/cli": "^0.36.
|
|
53
|
-
"@backstage/test-utils": "^1.7.
|
|
51
|
+
"@backstage/backend-test-utils": "^1.11.4",
|
|
52
|
+
"@backstage/cli": "^0.36.3",
|
|
53
|
+
"@backstage/test-utils": "^1.7.19",
|
|
54
54
|
"@types/proper-lockfile": "^4",
|
|
55
55
|
"@types/yarnpkg__lockfile": "^1.1.4"
|
|
56
56
|
},
|
|
57
|
-
"optionalDependencies": {
|
|
58
|
-
"keytar": "^7.9.0"
|
|
59
|
-
},
|
|
60
57
|
"peerDependencies": {
|
|
61
58
|
"@swc/core": "^1.15.6"
|
|
62
59
|
},
|
|
@@ -65,6 +62,9 @@
|
|
|
65
62
|
"optional": true
|
|
66
63
|
}
|
|
67
64
|
},
|
|
65
|
+
"optionalDependencies": {
|
|
66
|
+
"keytar": "^7.9.0"
|
|
67
|
+
},
|
|
68
68
|
"typesVersions": {
|
|
69
69
|
"*": {
|
|
70
70
|
"package.json": [
|