@overlayed/cli 0.0.1 → 0.0.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/dist/cli.js +4 -1679
- package/package.json +8 -4
- package/.attest/assertions/typescript.json +0 -1
- package/__mocks__/fs/promises.cjs +0 -2
- package/__mocks__/fs.cjs +0 -2
- package/__tests__/bundler.test.ts +0 -457
- package/__tests__/temp.test.ts +0 -7
- package/__tests__/utils.ts +0 -2
- package/dist/chunk-RDQt0V5E.js +0 -31
- package/dist/lib-DalWKwNu.js +0 -1041
- package/moon.yml +0 -18
- package/setupVitest.ts +0 -5
- package/src/bundle/command.ts +0 -87
- package/src/bundle/internal/appBundler.ts +0 -35
- package/src/bundle/internal/bundler.ts +0 -77
- package/src/bundle/internal/isBundleConfig.ts +0 -6
- package/src/cli.ts +0 -4
- package/src/consts.ts +0 -3
- package/temp/myfile.txt +0 -0
- package/temp/overlayed.config.ts +0 -8
- package/temp/someotherfile.ts +0 -0
- package/tsconfig.build.json +0 -8
- package/tsconfig.json +0 -38
- package/tsdown.config.ts +0 -13
- package/vitest.config.ts +0 -17
package/dist/cli.js
CHANGED
|
@@ -1,1682 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import tty from "tty";
|
|
3
|
-
import chalk from "chalk";
|
|
4
|
-
import fs, { createReadStream } from "node:fs";
|
|
5
|
-
import { OVERLAYED_CONFIG_GLOB, getOverlayedConfigs } from "@overlayed/utils-node";
|
|
6
|
-
import { glob } from "glob";
|
|
7
|
-
import { fileURLToPath } from "node:url";
|
|
8
|
-
import path from "node:path";
|
|
9
|
-
import Zip from "jszip";
|
|
10
|
-
import { asArray } from "@overlayed/utils";
|
|
11
|
-
|
|
12
|
-
//#region ../../node_modules/.pnpm/clipanion@4.0.0-rc.4_typanion@3.14.0/node_modules/clipanion/lib/constants.mjs
|
|
13
|
-
var SpecialToken;
|
|
14
|
-
(function(SpecialToken$1) {
|
|
15
|
-
SpecialToken$1["StartOfInput"] = "\0";
|
|
16
|
-
SpecialToken$1["EndOfInput"] = "";
|
|
17
|
-
SpecialToken$1["EndOfPartialInput"] = "";
|
|
18
|
-
})(SpecialToken || (SpecialToken = {}));
|
|
19
|
-
var NodeType;
|
|
20
|
-
(function(NodeType$1) {
|
|
21
|
-
NodeType$1[NodeType$1["InitialNode"] = 0] = "InitialNode";
|
|
22
|
-
NodeType$1[NodeType$1["SuccessNode"] = 1] = "SuccessNode";
|
|
23
|
-
NodeType$1[NodeType$1["ErrorNode"] = 2] = "ErrorNode";
|
|
24
|
-
NodeType$1[NodeType$1["CustomNode"] = 3] = "CustomNode";
|
|
25
|
-
})(NodeType || (NodeType = {}));
|
|
26
|
-
const HELP_COMMAND_INDEX = -1;
|
|
27
|
-
const HELP_REGEX = /^(-h|--help)(?:=([0-9]+))?$/;
|
|
28
|
-
const OPTION_REGEX = /^(--[a-z]+(?:-[a-z]+)*|-[a-zA-Z]+)$/;
|
|
29
|
-
const BATCH_REGEX = /^-[a-zA-Z]{2,}$/;
|
|
30
|
-
const BINDING_REGEX = /^([^=]+)=([\s\S]*)$/;
|
|
31
|
-
const IS_DEBUG = process.env.DEBUG_CLI === `1`;
|
|
32
|
-
|
|
33
|
-
//#endregion
|
|
34
|
-
//#region ../../node_modules/.pnpm/clipanion@4.0.0-rc.4_typanion@3.14.0/node_modules/clipanion/lib/errors.mjs
|
|
35
|
-
/**
|
|
36
|
-
* A generic usage error with the name `UsageError`.
|
|
37
|
-
*
|
|
38
|
-
* It should be used over `Error` only when it's the user's fault.
|
|
39
|
-
*/
|
|
40
|
-
var UsageError = class extends Error {
|
|
41
|
-
constructor(message) {
|
|
42
|
-
super(message);
|
|
43
|
-
this.clipanion = { type: `usage` };
|
|
44
|
-
this.name = `UsageError`;
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
var UnknownSyntaxError = class extends Error {
|
|
48
|
-
constructor(input, candidates) {
|
|
49
|
-
super();
|
|
50
|
-
this.input = input;
|
|
51
|
-
this.candidates = candidates;
|
|
52
|
-
this.clipanion = { type: `none` };
|
|
53
|
-
this.name = `UnknownSyntaxError`;
|
|
54
|
-
if (this.candidates.length === 0) this.message = `Command not found, but we're not sure what's the alternative.`;
|
|
55
|
-
else if (this.candidates.every((candidate) => candidate.reason !== null && candidate.reason === candidates[0].reason)) {
|
|
56
|
-
const [{ reason }] = this.candidates;
|
|
57
|
-
this.message = `${reason}\n\n${this.candidates.map(({ usage }) => `$ ${usage}`).join(`\n`)}`;
|
|
58
|
-
} else if (this.candidates.length === 1) {
|
|
59
|
-
const [{ usage }] = this.candidates;
|
|
60
|
-
this.message = `Command not found; did you mean:\n\n$ ${usage}\n${whileRunning(input)}`;
|
|
61
|
-
} else this.message = `Command not found; did you mean one of:\n\n${this.candidates.map(({ usage }, index) => {
|
|
62
|
-
return `${`${index}.`.padStart(4)} ${usage}`;
|
|
63
|
-
}).join(`\n`)}\n\n${whileRunning(input)}`;
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
var AmbiguousSyntaxError = class extends Error {
|
|
67
|
-
constructor(input, usages) {
|
|
68
|
-
super();
|
|
69
|
-
this.input = input;
|
|
70
|
-
this.usages = usages;
|
|
71
|
-
this.clipanion = { type: `none` };
|
|
72
|
-
this.name = `AmbiguousSyntaxError`;
|
|
73
|
-
this.message = `Cannot find which to pick amongst the following alternatives:\n\n${this.usages.map((usage, index) => {
|
|
74
|
-
return `${`${index}.`.padStart(4)} ${usage}`;
|
|
75
|
-
}).join(`\n`)}\n\n${whileRunning(input)}`;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
const whileRunning = (input) => `While running ${input.filter((token) => {
|
|
79
|
-
return token !== SpecialToken.EndOfInput && token !== SpecialToken.EndOfPartialInput;
|
|
80
|
-
}).map((token) => {
|
|
81
|
-
const json = JSON.stringify(token);
|
|
82
|
-
if (token.match(/\s/) || token.length === 0 || json !== `"${token}"`) return json;
|
|
83
|
-
else return token;
|
|
84
|
-
}).join(` `)}`;
|
|
85
|
-
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region ../../node_modules/.pnpm/clipanion@4.0.0-rc.4_typanion@3.14.0/node_modules/clipanion/lib/advanced/options/utils.mjs
|
|
88
|
-
const isOptionSymbol = Symbol(`clipanion/isOption`);
|
|
89
|
-
function cleanValidationError(message, { mergeName = false } = {}) {
|
|
90
|
-
const match = message.match(/^([^:]+): (.*)$/m);
|
|
91
|
-
if (!match) return `validation failed`;
|
|
92
|
-
let [, path$1, line] = match;
|
|
93
|
-
if (mergeName) line = line[0].toLowerCase() + line.slice(1);
|
|
94
|
-
line = path$1 !== `.` || !mergeName ? `${path$1.replace(/^\.(\[|$)/, `$1`)}: ${line}` : `: ${line}`;
|
|
95
|
-
return line;
|
|
96
|
-
}
|
|
97
|
-
function formatError(message, errors) {
|
|
98
|
-
if (errors.length === 1) return new UsageError(`${message}${cleanValidationError(errors[0], { mergeName: true })}`);
|
|
99
|
-
else return new UsageError(`${message}:\n${errors.map((error) => `\n- ${cleanValidationError(error)}`).join(``)}`);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
//#endregion
|
|
103
|
-
//#region ../../node_modules/.pnpm/clipanion@4.0.0-rc.4_typanion@3.14.0/node_modules/clipanion/lib/advanced/Command.mjs
|
|
104
|
-
/**
|
|
105
|
-
* Base abstract class for CLI commands. The main thing to remember is to
|
|
106
|
-
* declare an async `execute` member function that will be called when the
|
|
107
|
-
* command is invoked from the CLI, and optionally a `paths` property to
|
|
108
|
-
* declare the set of paths under which the command should be exposed.
|
|
109
|
-
*/
|
|
110
|
-
var Command = class {
|
|
111
|
-
constructor() {
|
|
112
|
-
/**
|
|
113
|
-
* Predefined that will be set to true if `-h,--help` has been used, in
|
|
114
|
-
* which case `Command#execute` won't be called.
|
|
115
|
-
*/
|
|
116
|
-
this.help = false;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Defines the usage information for the given command.
|
|
120
|
-
*/
|
|
121
|
-
static Usage(usage) {
|
|
122
|
-
return usage;
|
|
123
|
-
}
|
|
124
|
-
/**
|
|
125
|
-
* Standard error handler which will simply rethrow the error. Can be used
|
|
126
|
-
* to add custom logic to handle errors from the command or simply return
|
|
127
|
-
* the parent class error handling.
|
|
128
|
-
*/
|
|
129
|
-
async catch(error) {
|
|
130
|
-
throw error;
|
|
131
|
-
}
|
|
132
|
-
async validateAndExecute() {
|
|
133
|
-
const commandClass = this.constructor;
|
|
134
|
-
const cascade = commandClass.schema;
|
|
135
|
-
if (Array.isArray(cascade)) {
|
|
136
|
-
const { isDict, isUnknown, applyCascade } = await import("./lib-DalWKwNu.js").then(__toDynamicImportESM(1));
|
|
137
|
-
const schema = applyCascade(isDict(isUnknown()), cascade);
|
|
138
|
-
const errors = [];
|
|
139
|
-
const coercions = [];
|
|
140
|
-
const check = schema(this, {
|
|
141
|
-
errors,
|
|
142
|
-
coercions
|
|
143
|
-
});
|
|
144
|
-
if (!check) throw formatError(`Invalid option schema`, errors);
|
|
145
|
-
for (const [, op] of coercions) op();
|
|
146
|
-
} else if (cascade != null) throw new Error(`Invalid command schema`);
|
|
147
|
-
const exitCode = await this.execute();
|
|
148
|
-
if (typeof exitCode !== `undefined`) return exitCode;
|
|
149
|
-
else return 0;
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
/**
|
|
153
|
-
* Used to detect option definitions.
|
|
154
|
-
*/
|
|
155
|
-
Command.isOption = isOptionSymbol;
|
|
156
|
-
/**
|
|
157
|
-
* Just an helper to use along with the `paths` fields, to make it
|
|
158
|
-
* clearer that a command is the default one.
|
|
159
|
-
*
|
|
160
|
-
* @example
|
|
161
|
-
* class MyCommand extends Command {
|
|
162
|
-
* static paths = [Command.Default];
|
|
163
|
-
* }
|
|
164
|
-
*/
|
|
165
|
-
Command.Default = [];
|
|
166
|
-
|
|
167
|
-
//#endregion
|
|
168
|
-
//#region ../../node_modules/.pnpm/clipanion@4.0.0-rc.4_typanion@3.14.0/node_modules/clipanion/lib/platform/node.mjs
|
|
169
|
-
function getDefaultColorDepth() {
|
|
170
|
-
if (tty && `getColorDepth` in tty.WriteStream.prototype) return tty.WriteStream.prototype.getColorDepth();
|
|
171
|
-
if (process.env.FORCE_COLOR === `0`) return 1;
|
|
172
|
-
if (process.env.FORCE_COLOR === `1`) return 8;
|
|
173
|
-
if (typeof process.stdout !== `undefined` && process.stdout.isTTY) return 8;
|
|
174
|
-
return 1;
|
|
175
|
-
}
|
|
176
|
-
let gContextStorage;
|
|
177
|
-
function getCaptureActivator(context) {
|
|
178
|
-
let contextStorage = gContextStorage;
|
|
179
|
-
if (typeof contextStorage === `undefined`) {
|
|
180
|
-
if (context.stdout === process.stdout && context.stderr === process.stderr) return null;
|
|
181
|
-
const { AsyncLocalStorage: LazyAsyncLocalStorage } = __require("async_hooks");
|
|
182
|
-
contextStorage = gContextStorage = new LazyAsyncLocalStorage();
|
|
183
|
-
const origStdoutWrite = process.stdout._write;
|
|
184
|
-
process.stdout._write = function(chunk, encoding, cb) {
|
|
185
|
-
const context$1 = contextStorage.getStore();
|
|
186
|
-
if (typeof context$1 === `undefined`) return origStdoutWrite.call(this, chunk, encoding, cb);
|
|
187
|
-
return context$1.stdout.write(chunk, encoding, cb);
|
|
188
|
-
};
|
|
189
|
-
const origStderrWrite = process.stderr._write;
|
|
190
|
-
process.stderr._write = function(chunk, encoding, cb) {
|
|
191
|
-
const context$1 = contextStorage.getStore();
|
|
192
|
-
if (typeof context$1 === `undefined`) return origStderrWrite.call(this, chunk, encoding, cb);
|
|
193
|
-
return context$1.stderr.write(chunk, encoding, cb);
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
return (fn) => {
|
|
197
|
-
return contextStorage.run(context, fn);
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
//#endregion
|
|
202
|
-
//#region ../../node_modules/.pnpm/clipanion@4.0.0-rc.4_typanion@3.14.0/node_modules/clipanion/lib/core.mjs
|
|
203
|
-
function debug(str) {
|
|
204
|
-
if (IS_DEBUG) console.log(str);
|
|
205
|
-
}
|
|
206
|
-
const basicHelpState = {
|
|
207
|
-
candidateUsage: null,
|
|
208
|
-
requiredOptions: [],
|
|
209
|
-
errorMessage: null,
|
|
210
|
-
ignoreOptions: false,
|
|
211
|
-
path: [],
|
|
212
|
-
positionals: [],
|
|
213
|
-
options: [],
|
|
214
|
-
remainder: null,
|
|
215
|
-
selectedIndex: HELP_COMMAND_INDEX,
|
|
216
|
-
tokens: []
|
|
217
|
-
};
|
|
218
|
-
function makeStateMachine() {
|
|
219
|
-
const stateMachine = { nodes: [] };
|
|
220
|
-
for (let t = 0; t < NodeType.CustomNode; ++t) stateMachine.nodes.push(makeNode());
|
|
221
|
-
return stateMachine;
|
|
222
|
-
}
|
|
223
|
-
function makeAnyOfMachine(inputs) {
|
|
224
|
-
const output = makeStateMachine();
|
|
225
|
-
const heads = [];
|
|
226
|
-
let offset = output.nodes.length;
|
|
227
|
-
for (const input of inputs) {
|
|
228
|
-
heads.push(offset);
|
|
229
|
-
for (let t = 0; t < input.nodes.length; ++t) if (!isTerminalNode(t)) output.nodes.push(cloneNode(input.nodes[t], offset));
|
|
230
|
-
offset += input.nodes.length - NodeType.CustomNode + 1;
|
|
231
|
-
}
|
|
232
|
-
for (const head of heads) registerShortcut(output, NodeType.InitialNode, head);
|
|
233
|
-
return output;
|
|
234
|
-
}
|
|
235
|
-
function injectNode(machine, node) {
|
|
236
|
-
machine.nodes.push(node);
|
|
237
|
-
return machine.nodes.length - 1;
|
|
238
|
-
}
|
|
239
|
-
function simplifyMachine(input) {
|
|
240
|
-
const visited = /* @__PURE__ */ new Set();
|
|
241
|
-
const process$1 = (node) => {
|
|
242
|
-
if (visited.has(node)) return;
|
|
243
|
-
visited.add(node);
|
|
244
|
-
const nodeDef = input.nodes[node];
|
|
245
|
-
for (const transitions of Object.values(nodeDef.statics)) for (const { to } of transitions) process$1(to);
|
|
246
|
-
for (const [, { to }] of nodeDef.dynamics) process$1(to);
|
|
247
|
-
for (const { to } of nodeDef.shortcuts) process$1(to);
|
|
248
|
-
const shortcuts = new Set(nodeDef.shortcuts.map(({ to }) => to));
|
|
249
|
-
while (nodeDef.shortcuts.length > 0) {
|
|
250
|
-
const { to } = nodeDef.shortcuts.shift();
|
|
251
|
-
const toDef = input.nodes[to];
|
|
252
|
-
for (const [segment, transitions] of Object.entries(toDef.statics)) {
|
|
253
|
-
const store = !Object.prototype.hasOwnProperty.call(nodeDef.statics, segment) ? nodeDef.statics[segment] = [] : nodeDef.statics[segment];
|
|
254
|
-
for (const transition of transitions) if (!store.some(({ to: to$1 }) => transition.to === to$1)) store.push(transition);
|
|
255
|
-
}
|
|
256
|
-
for (const [test, transition] of toDef.dynamics) if (!nodeDef.dynamics.some(([otherTest, { to: to$1 }]) => test === otherTest && transition.to === to$1)) nodeDef.dynamics.push([test, transition]);
|
|
257
|
-
for (const transition of toDef.shortcuts) if (!shortcuts.has(transition.to)) {
|
|
258
|
-
nodeDef.shortcuts.push(transition);
|
|
259
|
-
shortcuts.add(transition.to);
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
process$1(NodeType.InitialNode);
|
|
264
|
-
}
|
|
265
|
-
function debugMachine(machine, { prefix = `` } = {}) {
|
|
266
|
-
if (IS_DEBUG) {
|
|
267
|
-
debug(`${prefix}Nodes are:`);
|
|
268
|
-
for (let t = 0; t < machine.nodes.length; ++t) debug(`${prefix} ${t}: ${JSON.stringify(machine.nodes[t])}`);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
function runMachineInternal(machine, input, partial = false) {
|
|
272
|
-
debug(`Running a vm on ${JSON.stringify(input)}`);
|
|
273
|
-
let branches = [{
|
|
274
|
-
node: NodeType.InitialNode,
|
|
275
|
-
state: {
|
|
276
|
-
candidateUsage: null,
|
|
277
|
-
requiredOptions: [],
|
|
278
|
-
errorMessage: null,
|
|
279
|
-
ignoreOptions: false,
|
|
280
|
-
options: [],
|
|
281
|
-
path: [],
|
|
282
|
-
positionals: [],
|
|
283
|
-
remainder: null,
|
|
284
|
-
selectedIndex: null,
|
|
285
|
-
tokens: []
|
|
286
|
-
}
|
|
287
|
-
}];
|
|
288
|
-
debugMachine(machine, { prefix: ` ` });
|
|
289
|
-
const tokens = [SpecialToken.StartOfInput, ...input];
|
|
290
|
-
for (let t = 0; t < tokens.length; ++t) {
|
|
291
|
-
const segment = tokens[t];
|
|
292
|
-
const isEOI = segment === SpecialToken.EndOfInput || segment === SpecialToken.EndOfPartialInput;
|
|
293
|
-
const segmentIndex = t - 1;
|
|
294
|
-
debug(` Processing ${JSON.stringify(segment)}`);
|
|
295
|
-
const nextBranches = [];
|
|
296
|
-
for (const { node, state } of branches) {
|
|
297
|
-
debug(` Current node is ${node}`);
|
|
298
|
-
const nodeDef = machine.nodes[node];
|
|
299
|
-
if (node === NodeType.ErrorNode) {
|
|
300
|
-
nextBranches.push({
|
|
301
|
-
node,
|
|
302
|
-
state
|
|
303
|
-
});
|
|
304
|
-
continue;
|
|
305
|
-
}
|
|
306
|
-
console.assert(nodeDef.shortcuts.length === 0, `Shortcuts should have been eliminated by now`);
|
|
307
|
-
const hasExactMatch = Object.prototype.hasOwnProperty.call(nodeDef.statics, segment);
|
|
308
|
-
if (!partial || t < tokens.length - 1 || hasExactMatch) if (hasExactMatch) {
|
|
309
|
-
const transitions = nodeDef.statics[segment];
|
|
310
|
-
for (const { to, reducer } of transitions) {
|
|
311
|
-
nextBranches.push({
|
|
312
|
-
node: to,
|
|
313
|
-
state: typeof reducer !== `undefined` ? execute(reducers, reducer, state, segment, segmentIndex) : state
|
|
314
|
-
});
|
|
315
|
-
debug(` Static transition to ${to} found`);
|
|
316
|
-
}
|
|
317
|
-
} else debug(` No static transition found`);
|
|
318
|
-
else {
|
|
319
|
-
let hasMatches = false;
|
|
320
|
-
for (const candidate of Object.keys(nodeDef.statics)) {
|
|
321
|
-
if (!candidate.startsWith(segment)) continue;
|
|
322
|
-
if (segment === candidate) for (const { to, reducer } of nodeDef.statics[candidate]) {
|
|
323
|
-
nextBranches.push({
|
|
324
|
-
node: to,
|
|
325
|
-
state: typeof reducer !== `undefined` ? execute(reducers, reducer, state, segment, segmentIndex) : state
|
|
326
|
-
});
|
|
327
|
-
debug(` Static transition to ${to} found`);
|
|
328
|
-
}
|
|
329
|
-
else for (const { to } of nodeDef.statics[candidate]) {
|
|
330
|
-
nextBranches.push({
|
|
331
|
-
node: to,
|
|
332
|
-
state: {
|
|
333
|
-
...state,
|
|
334
|
-
remainder: candidate.slice(segment.length)
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
debug(` Static transition to ${to} found (partial match)`);
|
|
338
|
-
}
|
|
339
|
-
hasMatches = true;
|
|
340
|
-
}
|
|
341
|
-
if (!hasMatches) debug(` No partial static transition found`);
|
|
342
|
-
}
|
|
343
|
-
if (!isEOI) {
|
|
344
|
-
for (const [test, { to, reducer }] of nodeDef.dynamics) if (execute(tests, test, state, segment, segmentIndex)) {
|
|
345
|
-
nextBranches.push({
|
|
346
|
-
node: to,
|
|
347
|
-
state: typeof reducer !== `undefined` ? execute(reducers, reducer, state, segment, segmentIndex) : state
|
|
348
|
-
});
|
|
349
|
-
debug(` Dynamic transition to ${to} found (via ${test})`);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
if (nextBranches.length === 0 && isEOI && input.length === 1) return [{
|
|
354
|
-
node: NodeType.InitialNode,
|
|
355
|
-
state: basicHelpState
|
|
356
|
-
}];
|
|
357
|
-
if (nextBranches.length === 0) throw new UnknownSyntaxError(input, branches.filter(({ node }) => {
|
|
358
|
-
return node !== NodeType.ErrorNode;
|
|
359
|
-
}).map(({ state }) => {
|
|
360
|
-
return {
|
|
361
|
-
usage: state.candidateUsage,
|
|
362
|
-
reason: null
|
|
363
|
-
};
|
|
364
|
-
}));
|
|
365
|
-
if (nextBranches.every(({ node }) => node === NodeType.ErrorNode)) throw new UnknownSyntaxError(input, nextBranches.map(({ state }) => {
|
|
366
|
-
return {
|
|
367
|
-
usage: state.candidateUsage,
|
|
368
|
-
reason: state.errorMessage
|
|
369
|
-
};
|
|
370
|
-
}));
|
|
371
|
-
branches = trimSmallerBranches(nextBranches);
|
|
372
|
-
}
|
|
373
|
-
if (branches.length > 0) {
|
|
374
|
-
debug(` Results:`);
|
|
375
|
-
for (const branch of branches) debug(` - ${branch.node} -> ${JSON.stringify(branch.state)}`);
|
|
376
|
-
} else debug(` No results`);
|
|
377
|
-
return branches;
|
|
378
|
-
}
|
|
379
|
-
function runMachine(machine, input, { endToken = SpecialToken.EndOfInput } = {}) {
|
|
380
|
-
const branches = runMachineInternal(machine, [...input, endToken]);
|
|
381
|
-
return selectBestState(input, branches.map(({ state }) => {
|
|
382
|
-
return state;
|
|
383
|
-
}));
|
|
384
|
-
}
|
|
385
|
-
function trimSmallerBranches(branches) {
|
|
386
|
-
let maxPathSize = 0;
|
|
387
|
-
for (const { state } of branches) if (state.path.length > maxPathSize) maxPathSize = state.path.length;
|
|
388
|
-
return branches.filter(({ state }) => {
|
|
389
|
-
return state.path.length === maxPathSize;
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
function selectBestState(input, states) {
|
|
393
|
-
const terminalStates = states.filter((state) => {
|
|
394
|
-
return state.selectedIndex !== null;
|
|
395
|
-
});
|
|
396
|
-
if (terminalStates.length === 0) throw new Error();
|
|
397
|
-
const requiredOptionsSetStates = terminalStates.filter((state) => state.selectedIndex === HELP_COMMAND_INDEX || state.requiredOptions.every((names) => names.some((name) => state.options.find((opt) => opt.name === name))));
|
|
398
|
-
if (requiredOptionsSetStates.length === 0) throw new UnknownSyntaxError(input, terminalStates.map((state) => ({
|
|
399
|
-
usage: state.candidateUsage,
|
|
400
|
-
reason: null
|
|
401
|
-
})));
|
|
402
|
-
let maxPathSize = 0;
|
|
403
|
-
for (const state of requiredOptionsSetStates) if (state.path.length > maxPathSize) maxPathSize = state.path.length;
|
|
404
|
-
const bestPathBranches = requiredOptionsSetStates.filter((state) => {
|
|
405
|
-
return state.path.length === maxPathSize;
|
|
406
|
-
});
|
|
407
|
-
const getPositionalCount = (state) => state.positionals.filter(({ extra }) => {
|
|
408
|
-
return !extra;
|
|
409
|
-
}).length + state.options.length;
|
|
410
|
-
const statesWithPositionalCount = bestPathBranches.map((state) => {
|
|
411
|
-
return {
|
|
412
|
-
state,
|
|
413
|
-
positionalCount: getPositionalCount(state)
|
|
414
|
-
};
|
|
415
|
-
});
|
|
416
|
-
let maxPositionalCount = 0;
|
|
417
|
-
for (const { positionalCount } of statesWithPositionalCount) if (positionalCount > maxPositionalCount) maxPositionalCount = positionalCount;
|
|
418
|
-
const bestPositionalStates = statesWithPositionalCount.filter(({ positionalCount }) => {
|
|
419
|
-
return positionalCount === maxPositionalCount;
|
|
420
|
-
}).map(({ state }) => {
|
|
421
|
-
return state;
|
|
422
|
-
});
|
|
423
|
-
const fixedStates = aggregateHelpStates(bestPositionalStates);
|
|
424
|
-
if (fixedStates.length > 1) throw new AmbiguousSyntaxError(input, fixedStates.map((state) => state.candidateUsage));
|
|
425
|
-
return fixedStates[0];
|
|
426
|
-
}
|
|
427
|
-
function aggregateHelpStates(states) {
|
|
428
|
-
const notHelps = [];
|
|
429
|
-
const helps = [];
|
|
430
|
-
for (const state of states) if (state.selectedIndex === HELP_COMMAND_INDEX) helps.push(state);
|
|
431
|
-
else notHelps.push(state);
|
|
432
|
-
if (helps.length > 0) notHelps.push({
|
|
433
|
-
...basicHelpState,
|
|
434
|
-
path: findCommonPrefix(...helps.map((state) => state.path)),
|
|
435
|
-
options: helps.reduce((options, state) => options.concat(state.options), [])
|
|
436
|
-
});
|
|
437
|
-
return notHelps;
|
|
438
|
-
}
|
|
439
|
-
function findCommonPrefix(firstPath, secondPath, ...rest) {
|
|
440
|
-
if (secondPath === void 0) return Array.from(firstPath);
|
|
441
|
-
return findCommonPrefix(firstPath.filter((segment, i) => segment === secondPath[i]), ...rest);
|
|
442
|
-
}
|
|
443
|
-
function makeNode() {
|
|
444
|
-
return {
|
|
445
|
-
dynamics: [],
|
|
446
|
-
shortcuts: [],
|
|
447
|
-
statics: {}
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
function isTerminalNode(node) {
|
|
451
|
-
return node === NodeType.SuccessNode || node === NodeType.ErrorNode;
|
|
452
|
-
}
|
|
453
|
-
function cloneTransition(input, offset = 0) {
|
|
454
|
-
const to = !isTerminalNode(input.to) ? input.to >= NodeType.CustomNode ? input.to + offset - NodeType.CustomNode + 1 : input.to + offset : input.to;
|
|
455
|
-
return {
|
|
456
|
-
to,
|
|
457
|
-
reducer: input.reducer
|
|
458
|
-
};
|
|
459
|
-
}
|
|
460
|
-
function cloneNode(input, offset = 0) {
|
|
461
|
-
const output = makeNode();
|
|
462
|
-
for (const [test, transition] of input.dynamics) output.dynamics.push([test, cloneTransition(transition, offset)]);
|
|
463
|
-
for (const transition of input.shortcuts) output.shortcuts.push(cloneTransition(transition, offset));
|
|
464
|
-
for (const [segment, transitions] of Object.entries(input.statics)) output.statics[segment] = transitions.map((transition) => cloneTransition(transition, offset));
|
|
465
|
-
return output;
|
|
466
|
-
}
|
|
467
|
-
function registerDynamic(machine, from, test, to, reducer) {
|
|
468
|
-
machine.nodes[from].dynamics.push([test, {
|
|
469
|
-
to,
|
|
470
|
-
reducer
|
|
471
|
-
}]);
|
|
472
|
-
}
|
|
473
|
-
function registerShortcut(machine, from, to, reducer) {
|
|
474
|
-
machine.nodes[from].shortcuts.push({
|
|
475
|
-
to,
|
|
476
|
-
reducer
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
function registerStatic(machine, from, test, to, reducer) {
|
|
480
|
-
const store = !Object.prototype.hasOwnProperty.call(machine.nodes[from].statics, test) ? machine.nodes[from].statics[test] = [] : machine.nodes[from].statics[test];
|
|
481
|
-
store.push({
|
|
482
|
-
to,
|
|
483
|
-
reducer
|
|
484
|
-
});
|
|
485
|
-
}
|
|
486
|
-
function execute(store, callback, state, segment, segmentIndex) {
|
|
487
|
-
if (Array.isArray(callback)) {
|
|
488
|
-
const [name, ...args] = callback;
|
|
489
|
-
return store[name](state, segment, segmentIndex, ...args);
|
|
490
|
-
} else return store[callback](state, segment, segmentIndex);
|
|
491
|
-
}
|
|
492
|
-
const tests = {
|
|
493
|
-
always: () => {
|
|
494
|
-
return true;
|
|
495
|
-
},
|
|
496
|
-
isOptionLike: (state, segment) => {
|
|
497
|
-
return !state.ignoreOptions && segment !== `-` && segment.startsWith(`-`);
|
|
498
|
-
},
|
|
499
|
-
isNotOptionLike: (state, segment) => {
|
|
500
|
-
return state.ignoreOptions || segment === `-` || !segment.startsWith(`-`);
|
|
501
|
-
},
|
|
502
|
-
isOption: (state, segment, segmentIndex, name) => {
|
|
503
|
-
return !state.ignoreOptions && segment === name;
|
|
504
|
-
},
|
|
505
|
-
isBatchOption: (state, segment, segmentIndex, names) => {
|
|
506
|
-
return !state.ignoreOptions && BATCH_REGEX.test(segment) && [...segment.slice(1)].every((name) => names.has(`-${name}`));
|
|
507
|
-
},
|
|
508
|
-
isBoundOption: (state, segment, segmentIndex, names, options) => {
|
|
509
|
-
const optionParsing = segment.match(BINDING_REGEX);
|
|
510
|
-
return !state.ignoreOptions && !!optionParsing && OPTION_REGEX.test(optionParsing[1]) && names.has(optionParsing[1]) && options.filter((opt) => opt.nameSet.includes(optionParsing[1])).every((opt) => opt.allowBinding);
|
|
511
|
-
},
|
|
512
|
-
isNegatedOption: (state, segment, segmentIndex, name) => {
|
|
513
|
-
return !state.ignoreOptions && segment === `--no-${name.slice(2)}`;
|
|
514
|
-
},
|
|
515
|
-
isHelp: (state, segment) => {
|
|
516
|
-
return !state.ignoreOptions && HELP_REGEX.test(segment);
|
|
517
|
-
},
|
|
518
|
-
isUnsupportedOption: (state, segment, segmentIndex, names) => {
|
|
519
|
-
return !state.ignoreOptions && segment.startsWith(`-`) && OPTION_REGEX.test(segment) && !names.has(segment);
|
|
520
|
-
},
|
|
521
|
-
isInvalidOption: (state, segment) => {
|
|
522
|
-
return !state.ignoreOptions && segment.startsWith(`-`) && !OPTION_REGEX.test(segment);
|
|
523
|
-
}
|
|
524
|
-
};
|
|
525
|
-
const reducers = {
|
|
526
|
-
setCandidateState: (state, segment, segmentIndex, candidateState) => {
|
|
527
|
-
return {
|
|
528
|
-
...state,
|
|
529
|
-
...candidateState
|
|
530
|
-
};
|
|
531
|
-
},
|
|
532
|
-
setSelectedIndex: (state, segment, segmentIndex, index) => {
|
|
533
|
-
return {
|
|
534
|
-
...state,
|
|
535
|
-
selectedIndex: index
|
|
536
|
-
};
|
|
537
|
-
},
|
|
538
|
-
pushBatch: (state, segment, segmentIndex, names) => {
|
|
539
|
-
const options = state.options.slice();
|
|
540
|
-
const tokens = state.tokens.slice();
|
|
541
|
-
for (let t = 1; t < segment.length; ++t) {
|
|
542
|
-
const name = names.get(`-${segment[t]}`);
|
|
543
|
-
const slice = t === 1 ? [0, 2] : [t, t + 1];
|
|
544
|
-
options.push({
|
|
545
|
-
name,
|
|
546
|
-
value: true
|
|
547
|
-
});
|
|
548
|
-
tokens.push({
|
|
549
|
-
segmentIndex,
|
|
550
|
-
type: `option`,
|
|
551
|
-
option: name,
|
|
552
|
-
slice
|
|
553
|
-
});
|
|
554
|
-
}
|
|
555
|
-
return {
|
|
556
|
-
...state,
|
|
557
|
-
options,
|
|
558
|
-
tokens
|
|
559
|
-
};
|
|
560
|
-
},
|
|
561
|
-
pushBound: (state, segment, segmentIndex) => {
|
|
562
|
-
const [, name, value] = segment.match(BINDING_REGEX);
|
|
563
|
-
const options = state.options.concat({
|
|
564
|
-
name,
|
|
565
|
-
value
|
|
566
|
-
});
|
|
567
|
-
const tokens = state.tokens.concat([
|
|
568
|
-
{
|
|
569
|
-
segmentIndex,
|
|
570
|
-
type: `option`,
|
|
571
|
-
slice: [0, name.length],
|
|
572
|
-
option: name
|
|
573
|
-
},
|
|
574
|
-
{
|
|
575
|
-
segmentIndex,
|
|
576
|
-
type: `assign`,
|
|
577
|
-
slice: [name.length, name.length + 1]
|
|
578
|
-
},
|
|
579
|
-
{
|
|
580
|
-
segmentIndex,
|
|
581
|
-
type: `value`,
|
|
582
|
-
slice: [name.length + 1, name.length + value.length + 1]
|
|
583
|
-
}
|
|
584
|
-
]);
|
|
585
|
-
return {
|
|
586
|
-
...state,
|
|
587
|
-
options,
|
|
588
|
-
tokens
|
|
589
|
-
};
|
|
590
|
-
},
|
|
591
|
-
pushPath: (state, segment, segmentIndex) => {
|
|
592
|
-
const path$1 = state.path.concat(segment);
|
|
593
|
-
const tokens = state.tokens.concat({
|
|
594
|
-
segmentIndex,
|
|
595
|
-
type: `path`
|
|
596
|
-
});
|
|
597
|
-
return {
|
|
598
|
-
...state,
|
|
599
|
-
path: path$1,
|
|
600
|
-
tokens
|
|
601
|
-
};
|
|
602
|
-
},
|
|
603
|
-
pushPositional: (state, segment, segmentIndex) => {
|
|
604
|
-
const positionals = state.positionals.concat({
|
|
605
|
-
value: segment,
|
|
606
|
-
extra: false
|
|
607
|
-
});
|
|
608
|
-
const tokens = state.tokens.concat({
|
|
609
|
-
segmentIndex,
|
|
610
|
-
type: `positional`
|
|
611
|
-
});
|
|
612
|
-
return {
|
|
613
|
-
...state,
|
|
614
|
-
positionals,
|
|
615
|
-
tokens
|
|
616
|
-
};
|
|
617
|
-
},
|
|
618
|
-
pushExtra: (state, segment, segmentIndex) => {
|
|
619
|
-
const positionals = state.positionals.concat({
|
|
620
|
-
value: segment,
|
|
621
|
-
extra: true
|
|
622
|
-
});
|
|
623
|
-
const tokens = state.tokens.concat({
|
|
624
|
-
segmentIndex,
|
|
625
|
-
type: `positional`
|
|
626
|
-
});
|
|
627
|
-
return {
|
|
628
|
-
...state,
|
|
629
|
-
positionals,
|
|
630
|
-
tokens
|
|
631
|
-
};
|
|
632
|
-
},
|
|
633
|
-
pushExtraNoLimits: (state, segment, segmentIndex) => {
|
|
634
|
-
const positionals = state.positionals.concat({
|
|
635
|
-
value: segment,
|
|
636
|
-
extra: NoLimits
|
|
637
|
-
});
|
|
638
|
-
const tokens = state.tokens.concat({
|
|
639
|
-
segmentIndex,
|
|
640
|
-
type: `positional`
|
|
641
|
-
});
|
|
642
|
-
return {
|
|
643
|
-
...state,
|
|
644
|
-
positionals,
|
|
645
|
-
tokens
|
|
646
|
-
};
|
|
647
|
-
},
|
|
648
|
-
pushTrue: (state, segment, segmentIndex, name) => {
|
|
649
|
-
const options = state.options.concat({
|
|
650
|
-
name,
|
|
651
|
-
value: true
|
|
652
|
-
});
|
|
653
|
-
const tokens = state.tokens.concat({
|
|
654
|
-
segmentIndex,
|
|
655
|
-
type: `option`,
|
|
656
|
-
option: name
|
|
657
|
-
});
|
|
658
|
-
return {
|
|
659
|
-
...state,
|
|
660
|
-
options,
|
|
661
|
-
tokens
|
|
662
|
-
};
|
|
663
|
-
},
|
|
664
|
-
pushFalse: (state, segment, segmentIndex, name) => {
|
|
665
|
-
const options = state.options.concat({
|
|
666
|
-
name,
|
|
667
|
-
value: false
|
|
668
|
-
});
|
|
669
|
-
const tokens = state.tokens.concat({
|
|
670
|
-
segmentIndex,
|
|
671
|
-
type: `option`,
|
|
672
|
-
option: name
|
|
673
|
-
});
|
|
674
|
-
return {
|
|
675
|
-
...state,
|
|
676
|
-
options,
|
|
677
|
-
tokens
|
|
678
|
-
};
|
|
679
|
-
},
|
|
680
|
-
pushUndefined: (state, segment, segmentIndex, name) => {
|
|
681
|
-
const options = state.options.concat({
|
|
682
|
-
name: segment,
|
|
683
|
-
value: void 0
|
|
684
|
-
});
|
|
685
|
-
const tokens = state.tokens.concat({
|
|
686
|
-
segmentIndex,
|
|
687
|
-
type: `option`,
|
|
688
|
-
option: segment
|
|
689
|
-
});
|
|
690
|
-
return {
|
|
691
|
-
...state,
|
|
692
|
-
options,
|
|
693
|
-
tokens
|
|
694
|
-
};
|
|
695
|
-
},
|
|
696
|
-
pushStringValue: (state, segment, segmentIndex) => {
|
|
697
|
-
var _a;
|
|
698
|
-
const lastOption = state.options[state.options.length - 1];
|
|
699
|
-
const options = state.options.slice();
|
|
700
|
-
const tokens = state.tokens.concat({
|
|
701
|
-
segmentIndex,
|
|
702
|
-
type: `value`
|
|
703
|
-
});
|
|
704
|
-
lastOption.value = ((_a = lastOption.value) !== null && _a !== void 0 ? _a : []).concat([segment]);
|
|
705
|
-
return {
|
|
706
|
-
...state,
|
|
707
|
-
options,
|
|
708
|
-
tokens
|
|
709
|
-
};
|
|
710
|
-
},
|
|
711
|
-
setStringValue: (state, segment, segmentIndex) => {
|
|
712
|
-
const lastOption = state.options[state.options.length - 1];
|
|
713
|
-
const options = state.options.slice();
|
|
714
|
-
const tokens = state.tokens.concat({
|
|
715
|
-
segmentIndex,
|
|
716
|
-
type: `value`
|
|
717
|
-
});
|
|
718
|
-
lastOption.value = segment;
|
|
719
|
-
return {
|
|
720
|
-
...state,
|
|
721
|
-
options,
|
|
722
|
-
tokens
|
|
723
|
-
};
|
|
724
|
-
},
|
|
725
|
-
inhibateOptions: (state) => {
|
|
726
|
-
return {
|
|
727
|
-
...state,
|
|
728
|
-
ignoreOptions: true
|
|
729
|
-
};
|
|
730
|
-
},
|
|
731
|
-
useHelp: (state, segment, segmentIndex, command) => {
|
|
732
|
-
const [, , index] = segment.match(HELP_REGEX);
|
|
733
|
-
if (typeof index !== `undefined`) return {
|
|
734
|
-
...state,
|
|
735
|
-
options: [{
|
|
736
|
-
name: `-c`,
|
|
737
|
-
value: String(command)
|
|
738
|
-
}, {
|
|
739
|
-
name: `-i`,
|
|
740
|
-
value: index
|
|
741
|
-
}]
|
|
742
|
-
};
|
|
743
|
-
else return {
|
|
744
|
-
...state,
|
|
745
|
-
options: [{
|
|
746
|
-
name: `-c`,
|
|
747
|
-
value: String(command)
|
|
748
|
-
}]
|
|
749
|
-
};
|
|
750
|
-
},
|
|
751
|
-
setError: (state, segment, segmentIndex, errorMessage) => {
|
|
752
|
-
if (segment === SpecialToken.EndOfInput || segment === SpecialToken.EndOfPartialInput) return {
|
|
753
|
-
...state,
|
|
754
|
-
errorMessage: `${errorMessage}.`
|
|
755
|
-
};
|
|
756
|
-
else return {
|
|
757
|
-
...state,
|
|
758
|
-
errorMessage: `${errorMessage} ("${segment}").`
|
|
759
|
-
};
|
|
760
|
-
},
|
|
761
|
-
setOptionArityError: (state, segment) => {
|
|
762
|
-
const lastOption = state.options[state.options.length - 1];
|
|
763
|
-
return {
|
|
764
|
-
...state,
|
|
765
|
-
errorMessage: `Not enough arguments to option ${lastOption.name}.`
|
|
766
|
-
};
|
|
767
|
-
}
|
|
768
|
-
};
|
|
769
|
-
const NoLimits = Symbol();
|
|
770
|
-
var CommandBuilder = class {
|
|
771
|
-
constructor(cliIndex, cliOpts) {
|
|
772
|
-
this.allOptionNames = /* @__PURE__ */ new Map();
|
|
773
|
-
this.arity = {
|
|
774
|
-
leading: [],
|
|
775
|
-
trailing: [],
|
|
776
|
-
extra: [],
|
|
777
|
-
proxy: false
|
|
778
|
-
};
|
|
779
|
-
this.options = [];
|
|
780
|
-
this.paths = [];
|
|
781
|
-
this.cliIndex = cliIndex;
|
|
782
|
-
this.cliOpts = cliOpts;
|
|
783
|
-
}
|
|
784
|
-
addPath(path$1) {
|
|
785
|
-
this.paths.push(path$1);
|
|
786
|
-
}
|
|
787
|
-
setArity({ leading = this.arity.leading, trailing = this.arity.trailing, extra = this.arity.extra, proxy = this.arity.proxy }) {
|
|
788
|
-
Object.assign(this.arity, {
|
|
789
|
-
leading,
|
|
790
|
-
trailing,
|
|
791
|
-
extra,
|
|
792
|
-
proxy
|
|
793
|
-
});
|
|
794
|
-
}
|
|
795
|
-
addPositional({ name = `arg`, required = true } = {}) {
|
|
796
|
-
if (!required && this.arity.extra === NoLimits) throw new Error(`Optional parameters cannot be declared when using .rest() or .proxy()`);
|
|
797
|
-
if (!required && this.arity.trailing.length > 0) throw new Error(`Optional parameters cannot be declared after the required trailing positional arguments`);
|
|
798
|
-
if (!required && this.arity.extra !== NoLimits) this.arity.extra.push(name);
|
|
799
|
-
else if (this.arity.extra !== NoLimits && this.arity.extra.length === 0) this.arity.leading.push(name);
|
|
800
|
-
else this.arity.trailing.push(name);
|
|
801
|
-
}
|
|
802
|
-
addRest({ name = `arg`, required = 0 } = {}) {
|
|
803
|
-
if (this.arity.extra === NoLimits) throw new Error(`Infinite lists cannot be declared multiple times in the same command`);
|
|
804
|
-
if (this.arity.trailing.length > 0) throw new Error(`Infinite lists cannot be declared after the required trailing positional arguments`);
|
|
805
|
-
for (let t = 0; t < required; ++t) this.addPositional({ name });
|
|
806
|
-
this.arity.extra = NoLimits;
|
|
807
|
-
}
|
|
808
|
-
addProxy({ required = 0 } = {}) {
|
|
809
|
-
this.addRest({ required });
|
|
810
|
-
this.arity.proxy = true;
|
|
811
|
-
}
|
|
812
|
-
addOption({ names: nameSet, description, arity = 0, hidden = false, required = false, allowBinding = true }) {
|
|
813
|
-
if (!allowBinding && arity > 1) throw new Error(`The arity cannot be higher than 1 when the option only supports the --arg=value syntax`);
|
|
814
|
-
if (!Number.isInteger(arity)) throw new Error(`The arity must be an integer, got ${arity}`);
|
|
815
|
-
if (arity < 0) throw new Error(`The arity must be positive, got ${arity}`);
|
|
816
|
-
const preferredName = nameSet.reduce((longestName, name) => {
|
|
817
|
-
return name.length > longestName.length ? name : longestName;
|
|
818
|
-
}, ``);
|
|
819
|
-
for (const name of nameSet) this.allOptionNames.set(name, preferredName);
|
|
820
|
-
this.options.push({
|
|
821
|
-
preferredName,
|
|
822
|
-
nameSet,
|
|
823
|
-
description,
|
|
824
|
-
arity,
|
|
825
|
-
hidden,
|
|
826
|
-
required,
|
|
827
|
-
allowBinding
|
|
828
|
-
});
|
|
829
|
-
}
|
|
830
|
-
setContext(context) {
|
|
831
|
-
this.context = context;
|
|
832
|
-
}
|
|
833
|
-
usage({ detailed = true, inlineOptions = true } = {}) {
|
|
834
|
-
const segments = [this.cliOpts.binaryName];
|
|
835
|
-
const detailedOptionList = [];
|
|
836
|
-
if (this.paths.length > 0) segments.push(...this.paths[0]);
|
|
837
|
-
if (detailed) {
|
|
838
|
-
for (const { preferredName, nameSet, arity, hidden, description, required } of this.options) {
|
|
839
|
-
if (hidden) continue;
|
|
840
|
-
const args = [];
|
|
841
|
-
for (let t = 0; t < arity; ++t) args.push(` #${t}`);
|
|
842
|
-
const definition = `${nameSet.join(`,`)}${args.join(``)}`;
|
|
843
|
-
if (!inlineOptions && description) detailedOptionList.push({
|
|
844
|
-
preferredName,
|
|
845
|
-
nameSet,
|
|
846
|
-
definition,
|
|
847
|
-
description,
|
|
848
|
-
required
|
|
849
|
-
});
|
|
850
|
-
else segments.push(required ? `<${definition}>` : `[${definition}]`);
|
|
851
|
-
}
|
|
852
|
-
segments.push(...this.arity.leading.map((name) => `<${name}>`));
|
|
853
|
-
if (this.arity.extra === NoLimits) segments.push(`...`);
|
|
854
|
-
else segments.push(...this.arity.extra.map((name) => `[${name}]`));
|
|
855
|
-
segments.push(...this.arity.trailing.map((name) => `<${name}>`));
|
|
856
|
-
}
|
|
857
|
-
const usage = segments.join(` `);
|
|
858
|
-
return {
|
|
859
|
-
usage,
|
|
860
|
-
options: detailedOptionList
|
|
861
|
-
};
|
|
862
|
-
}
|
|
863
|
-
compile() {
|
|
864
|
-
if (typeof this.context === `undefined`) throw new Error(`Assertion failed: No context attached`);
|
|
865
|
-
const machine = makeStateMachine();
|
|
866
|
-
let firstNode = NodeType.InitialNode;
|
|
867
|
-
const candidateUsage = this.usage().usage;
|
|
868
|
-
const requiredOptions = this.options.filter((opt) => opt.required).map((opt) => opt.nameSet);
|
|
869
|
-
firstNode = injectNode(machine, makeNode());
|
|
870
|
-
registerStatic(machine, NodeType.InitialNode, SpecialToken.StartOfInput, firstNode, [`setCandidateState`, {
|
|
871
|
-
candidateUsage,
|
|
872
|
-
requiredOptions
|
|
873
|
-
}]);
|
|
874
|
-
const positionalArgument = this.arity.proxy ? `always` : `isNotOptionLike`;
|
|
875
|
-
const paths = this.paths.length > 0 ? this.paths : [[]];
|
|
876
|
-
for (const path$1 of paths) {
|
|
877
|
-
let lastPathNode = firstNode;
|
|
878
|
-
if (path$1.length > 0) {
|
|
879
|
-
const optionPathNode = injectNode(machine, makeNode());
|
|
880
|
-
registerShortcut(machine, lastPathNode, optionPathNode);
|
|
881
|
-
this.registerOptions(machine, optionPathNode);
|
|
882
|
-
lastPathNode = optionPathNode;
|
|
883
|
-
}
|
|
884
|
-
for (let t = 0; t < path$1.length; ++t) {
|
|
885
|
-
const nextPathNode = injectNode(machine, makeNode());
|
|
886
|
-
registerStatic(machine, lastPathNode, path$1[t], nextPathNode, `pushPath`);
|
|
887
|
-
lastPathNode = nextPathNode;
|
|
888
|
-
if (t + 1 < path$1.length) {
|
|
889
|
-
const helpNode = injectNode(machine, makeNode());
|
|
890
|
-
registerDynamic(machine, lastPathNode, `isHelp`, helpNode, [`useHelp`, this.cliIndex]);
|
|
891
|
-
registerStatic(machine, helpNode, SpecialToken.EndOfInput, NodeType.SuccessNode, [`setSelectedIndex`, HELP_COMMAND_INDEX]);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
if (this.arity.leading.length > 0 || !this.arity.proxy) {
|
|
895
|
-
const helpNode = injectNode(machine, makeNode());
|
|
896
|
-
registerDynamic(machine, lastPathNode, `isHelp`, helpNode, [`useHelp`, this.cliIndex]);
|
|
897
|
-
registerDynamic(machine, helpNode, `always`, helpNode, `pushExtra`);
|
|
898
|
-
registerStatic(machine, helpNode, SpecialToken.EndOfInput, NodeType.SuccessNode, [`setSelectedIndex`, HELP_COMMAND_INDEX]);
|
|
899
|
-
this.registerOptions(machine, lastPathNode);
|
|
900
|
-
}
|
|
901
|
-
if (this.arity.leading.length > 0) {
|
|
902
|
-
registerStatic(machine, lastPathNode, SpecialToken.EndOfInput, NodeType.ErrorNode, [`setError`, `Not enough positional arguments`]);
|
|
903
|
-
registerStatic(machine, lastPathNode, SpecialToken.EndOfPartialInput, NodeType.SuccessNode, [`setSelectedIndex`, this.cliIndex]);
|
|
904
|
-
}
|
|
905
|
-
let lastLeadingNode = lastPathNode;
|
|
906
|
-
for (let t = 0; t < this.arity.leading.length; ++t) {
|
|
907
|
-
const nextLeadingNode = injectNode(machine, makeNode());
|
|
908
|
-
if (!this.arity.proxy || t + 1 !== this.arity.leading.length) this.registerOptions(machine, nextLeadingNode);
|
|
909
|
-
if (this.arity.trailing.length > 0 || t + 1 !== this.arity.leading.length) {
|
|
910
|
-
registerStatic(machine, nextLeadingNode, SpecialToken.EndOfInput, NodeType.ErrorNode, [`setError`, `Not enough positional arguments`]);
|
|
911
|
-
registerStatic(machine, nextLeadingNode, SpecialToken.EndOfPartialInput, NodeType.SuccessNode, [`setSelectedIndex`, this.cliIndex]);
|
|
912
|
-
}
|
|
913
|
-
registerDynamic(machine, lastLeadingNode, `isNotOptionLike`, nextLeadingNode, `pushPositional`);
|
|
914
|
-
lastLeadingNode = nextLeadingNode;
|
|
915
|
-
}
|
|
916
|
-
let lastExtraNode = lastLeadingNode;
|
|
917
|
-
if (this.arity.extra === NoLimits || this.arity.extra.length > 0) {
|
|
918
|
-
const extraShortcutNode = injectNode(machine, makeNode());
|
|
919
|
-
registerShortcut(machine, lastLeadingNode, extraShortcutNode);
|
|
920
|
-
if (this.arity.extra === NoLimits) {
|
|
921
|
-
const extraNode = injectNode(machine, makeNode());
|
|
922
|
-
if (!this.arity.proxy) this.registerOptions(machine, extraNode);
|
|
923
|
-
registerDynamic(machine, lastLeadingNode, positionalArgument, extraNode, `pushExtraNoLimits`);
|
|
924
|
-
registerDynamic(machine, extraNode, positionalArgument, extraNode, `pushExtraNoLimits`);
|
|
925
|
-
registerShortcut(machine, extraNode, extraShortcutNode);
|
|
926
|
-
} else for (let t = 0; t < this.arity.extra.length; ++t) {
|
|
927
|
-
const nextExtraNode = injectNode(machine, makeNode());
|
|
928
|
-
if (!this.arity.proxy || t > 0) this.registerOptions(machine, nextExtraNode);
|
|
929
|
-
registerDynamic(machine, lastExtraNode, positionalArgument, nextExtraNode, `pushExtra`);
|
|
930
|
-
registerShortcut(machine, nextExtraNode, extraShortcutNode);
|
|
931
|
-
lastExtraNode = nextExtraNode;
|
|
932
|
-
}
|
|
933
|
-
lastExtraNode = extraShortcutNode;
|
|
934
|
-
}
|
|
935
|
-
if (this.arity.trailing.length > 0) {
|
|
936
|
-
registerStatic(machine, lastExtraNode, SpecialToken.EndOfInput, NodeType.ErrorNode, [`setError`, `Not enough positional arguments`]);
|
|
937
|
-
registerStatic(machine, lastExtraNode, SpecialToken.EndOfPartialInput, NodeType.SuccessNode, [`setSelectedIndex`, this.cliIndex]);
|
|
938
|
-
}
|
|
939
|
-
let lastTrailingNode = lastExtraNode;
|
|
940
|
-
for (let t = 0; t < this.arity.trailing.length; ++t) {
|
|
941
|
-
const nextTrailingNode = injectNode(machine, makeNode());
|
|
942
|
-
if (!this.arity.proxy) this.registerOptions(machine, nextTrailingNode);
|
|
943
|
-
if (t + 1 < this.arity.trailing.length) {
|
|
944
|
-
registerStatic(machine, nextTrailingNode, SpecialToken.EndOfInput, NodeType.ErrorNode, [`setError`, `Not enough positional arguments`]);
|
|
945
|
-
registerStatic(machine, nextTrailingNode, SpecialToken.EndOfPartialInput, NodeType.SuccessNode, [`setSelectedIndex`, this.cliIndex]);
|
|
946
|
-
}
|
|
947
|
-
registerDynamic(machine, lastTrailingNode, `isNotOptionLike`, nextTrailingNode, `pushPositional`);
|
|
948
|
-
lastTrailingNode = nextTrailingNode;
|
|
949
|
-
}
|
|
950
|
-
registerDynamic(machine, lastTrailingNode, positionalArgument, NodeType.ErrorNode, [`setError`, `Extraneous positional argument`]);
|
|
951
|
-
registerStatic(machine, lastTrailingNode, SpecialToken.EndOfInput, NodeType.SuccessNode, [`setSelectedIndex`, this.cliIndex]);
|
|
952
|
-
registerStatic(machine, lastTrailingNode, SpecialToken.EndOfPartialInput, NodeType.SuccessNode, [`setSelectedIndex`, this.cliIndex]);
|
|
953
|
-
}
|
|
954
|
-
return {
|
|
955
|
-
machine,
|
|
956
|
-
context: this.context
|
|
957
|
-
};
|
|
958
|
-
}
|
|
959
|
-
registerOptions(machine, node) {
|
|
960
|
-
registerDynamic(machine, node, [`isOption`, `--`], node, `inhibateOptions`);
|
|
961
|
-
registerDynamic(machine, node, [`isBatchOption`, this.allOptionNames], node, [`pushBatch`, this.allOptionNames]);
|
|
962
|
-
registerDynamic(machine, node, [
|
|
963
|
-
`isBoundOption`,
|
|
964
|
-
this.allOptionNames,
|
|
965
|
-
this.options
|
|
966
|
-
], node, `pushBound`);
|
|
967
|
-
registerDynamic(machine, node, [`isUnsupportedOption`, this.allOptionNames], NodeType.ErrorNode, [`setError`, `Unsupported option name`]);
|
|
968
|
-
registerDynamic(machine, node, [`isInvalidOption`], NodeType.ErrorNode, [`setError`, `Invalid option name`]);
|
|
969
|
-
for (const option of this.options) if (option.arity === 0) for (const name of option.nameSet) {
|
|
970
|
-
registerDynamic(machine, node, [`isOption`, name], node, [`pushTrue`, option.preferredName]);
|
|
971
|
-
if (name.startsWith(`--`) && !name.startsWith(`--no-`)) registerDynamic(machine, node, [`isNegatedOption`, name], node, [`pushFalse`, option.preferredName]);
|
|
972
|
-
}
|
|
973
|
-
else {
|
|
974
|
-
let lastNode = injectNode(machine, makeNode());
|
|
975
|
-
for (const name of option.nameSet) registerDynamic(machine, node, [`isOption`, name], lastNode, [`pushUndefined`, option.preferredName]);
|
|
976
|
-
for (let t = 0; t < option.arity; ++t) {
|
|
977
|
-
const nextNode = injectNode(machine, makeNode());
|
|
978
|
-
registerStatic(machine, lastNode, SpecialToken.EndOfInput, NodeType.ErrorNode, `setOptionArityError`);
|
|
979
|
-
registerStatic(machine, lastNode, SpecialToken.EndOfPartialInput, NodeType.ErrorNode, `setOptionArityError`);
|
|
980
|
-
registerDynamic(machine, lastNode, `isOptionLike`, NodeType.ErrorNode, `setOptionArityError`);
|
|
981
|
-
const action = option.arity === 1 ? `setStringValue` : `pushStringValue`;
|
|
982
|
-
registerDynamic(machine, lastNode, `isNotOptionLike`, nextNode, action);
|
|
983
|
-
lastNode = nextNode;
|
|
984
|
-
}
|
|
985
|
-
registerShortcut(machine, lastNode, node);
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
};
|
|
989
|
-
var CliBuilder = class CliBuilder {
|
|
990
|
-
static build(cbs, opts = {}) {
|
|
991
|
-
return new CliBuilder(opts).commands(cbs).compile();
|
|
992
|
-
}
|
|
993
|
-
constructor({ binaryName = `...` } = {}) {
|
|
994
|
-
this.builders = [];
|
|
995
|
-
this.opts = { binaryName };
|
|
996
|
-
}
|
|
997
|
-
getBuilderByIndex(n) {
|
|
998
|
-
if (!(n >= 0 && n < this.builders.length)) throw new Error(`Assertion failed: Out-of-bound command index (${n})`);
|
|
999
|
-
return this.builders[n];
|
|
1000
|
-
}
|
|
1001
|
-
commands(cbs) {
|
|
1002
|
-
for (const cb of cbs) cb(this.command());
|
|
1003
|
-
return this;
|
|
1004
|
-
}
|
|
1005
|
-
command() {
|
|
1006
|
-
const builder = new CommandBuilder(this.builders.length, this.opts);
|
|
1007
|
-
this.builders.push(builder);
|
|
1008
|
-
return builder;
|
|
1009
|
-
}
|
|
1010
|
-
compile() {
|
|
1011
|
-
const machines = [];
|
|
1012
|
-
const contexts = [];
|
|
1013
|
-
for (const builder of this.builders) {
|
|
1014
|
-
const { machine: machine$1, context } = builder.compile();
|
|
1015
|
-
machines.push(machine$1);
|
|
1016
|
-
contexts.push(context);
|
|
1017
|
-
}
|
|
1018
|
-
const machine = makeAnyOfMachine(machines);
|
|
1019
|
-
simplifyMachine(machine);
|
|
1020
|
-
return {
|
|
1021
|
-
machine,
|
|
1022
|
-
contexts,
|
|
1023
|
-
process: (input, { partial } = {}) => {
|
|
1024
|
-
const endToken = partial ? SpecialToken.EndOfPartialInput : SpecialToken.EndOfInput;
|
|
1025
|
-
return runMachine(machine, input, { endToken });
|
|
1026
|
-
}
|
|
1027
|
-
};
|
|
1028
|
-
}
|
|
1029
|
-
};
|
|
1030
|
-
|
|
1031
|
-
//#endregion
|
|
1032
|
-
//#region ../../node_modules/.pnpm/clipanion@4.0.0-rc.4_typanion@3.14.0/node_modules/clipanion/lib/format.mjs
|
|
1033
|
-
const MAX_LINE_LENGTH = 80;
|
|
1034
|
-
const richLine = Array(MAX_LINE_LENGTH).fill(`━`);
|
|
1035
|
-
for (let t = 0; t <= 24; ++t) richLine[richLine.length - t] = `\x1b[38;5;${232 + t}m━`;
|
|
1036
|
-
const richFormat = {
|
|
1037
|
-
header: (str) => `\x1b[1m━━━ ${str}${str.length < MAX_LINE_LENGTH - 5 ? ` ${richLine.slice(str.length + 5).join(``)}` : `:`}\x1b[0m`,
|
|
1038
|
-
bold: (str) => `\x1b[1m${str}\x1b[22m`,
|
|
1039
|
-
error: (str) => `\x1b[31m\x1b[1m${str}\x1b[22m\x1b[39m`,
|
|
1040
|
-
code: (str) => `\x1b[36m${str}\x1b[39m`
|
|
1041
|
-
};
|
|
1042
|
-
const textFormat = {
|
|
1043
|
-
header: (str) => str,
|
|
1044
|
-
bold: (str) => str,
|
|
1045
|
-
error: (str) => str,
|
|
1046
|
-
code: (str) => str
|
|
1047
|
-
};
|
|
1048
|
-
function dedent(text) {
|
|
1049
|
-
const lines = text.split(`\n`);
|
|
1050
|
-
const nonEmptyLines = lines.filter((line) => line.match(/\S/));
|
|
1051
|
-
const indent = nonEmptyLines.length > 0 ? nonEmptyLines.reduce((minLength, line) => Math.min(minLength, line.length - line.trimStart().length), Number.MAX_VALUE) : 0;
|
|
1052
|
-
return lines.map((line) => line.slice(indent).trimRight()).join(`\n`);
|
|
1053
|
-
}
|
|
1054
|
-
/**
|
|
1055
|
-
* Formats markdown text to be displayed to the console. Not all markdown features are supported.
|
|
1056
|
-
*
|
|
1057
|
-
* @param text The markdown text to format.
|
|
1058
|
-
* @param opts.format The format to use.
|
|
1059
|
-
* @param opts.paragraphs Whether to cut the text into paragraphs of 80 characters at most.
|
|
1060
|
-
*/
|
|
1061
|
-
function formatMarkdownish(text, { format, paragraphs }) {
|
|
1062
|
-
text = text.replace(/\r\n?/g, `\n`);
|
|
1063
|
-
text = dedent(text);
|
|
1064
|
-
text = text.replace(/^\n+|\n+$/g, ``);
|
|
1065
|
-
text = text.replace(/^(\s*)-([^\n]*?)\n+/gm, `$1-$2\n\n`);
|
|
1066
|
-
text = text.replace(/\n(\n)?\n*/g, ($0, $1) => $1 ? $1 : ` `);
|
|
1067
|
-
if (paragraphs) text = text.split(/\n/).map((paragraph) => {
|
|
1068
|
-
const bulletMatch = paragraph.match(/^\s*[*-][\t ]+(.*)/);
|
|
1069
|
-
if (!bulletMatch) return paragraph.match(/(.{1,80})(?: |$)/g).join(`\n`);
|
|
1070
|
-
const indent = paragraph.length - paragraph.trimStart().length;
|
|
1071
|
-
return bulletMatch[1].match(new RegExp(`(.{1,${78 - indent}})(?: |$)`, `g`)).map((line, index) => {
|
|
1072
|
-
return ` `.repeat(indent) + (index === 0 ? `- ` : ` `) + line;
|
|
1073
|
-
}).join(`\n`);
|
|
1074
|
-
}).join(`\n\n`);
|
|
1075
|
-
text = text.replace(/(`+)((?:.|[\n])*?)\1/g, ($0, $1, $2) => {
|
|
1076
|
-
return format.code($1 + $2 + $1);
|
|
1077
|
-
});
|
|
1078
|
-
text = text.replace(/(\*\*)((?:.|[\n])*?)\1/g, ($0, $1, $2) => {
|
|
1079
|
-
return format.bold($1 + $2 + $1);
|
|
1080
|
-
});
|
|
1081
|
-
return text ? `${text}\n` : ``;
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
//#endregion
|
|
1085
|
-
//#region ../../node_modules/.pnpm/clipanion@4.0.0-rc.4_typanion@3.14.0/node_modules/clipanion/lib/advanced/HelpCommand.mjs
|
|
1086
|
-
var HelpCommand = class HelpCommand extends Command {
|
|
1087
|
-
static from(state, contexts) {
|
|
1088
|
-
const command = new HelpCommand(contexts);
|
|
1089
|
-
command.path = state.path;
|
|
1090
|
-
for (const opt of state.options) switch (opt.name) {
|
|
1091
|
-
case `-c`:
|
|
1092
|
-
command.commands.push(Number(opt.value));
|
|
1093
|
-
break;
|
|
1094
|
-
case `-i`:
|
|
1095
|
-
command.index = Number(opt.value);
|
|
1096
|
-
break;
|
|
1097
|
-
}
|
|
1098
|
-
return command;
|
|
1099
|
-
}
|
|
1100
|
-
constructor(contexts) {
|
|
1101
|
-
super();
|
|
1102
|
-
this.contexts = contexts;
|
|
1103
|
-
this.commands = [];
|
|
1104
|
-
}
|
|
1105
|
-
async execute() {
|
|
1106
|
-
let commands = this.commands;
|
|
1107
|
-
if (typeof this.index !== `undefined` && this.index >= 0 && this.index < commands.length) commands = [commands[this.index]];
|
|
1108
|
-
if (commands.length === 0) this.context.stdout.write(this.cli.usage());
|
|
1109
|
-
else if (commands.length === 1) this.context.stdout.write(this.cli.usage(this.contexts[commands[0]].commandClass, { detailed: true }));
|
|
1110
|
-
else if (commands.length > 1) {
|
|
1111
|
-
this.context.stdout.write(`Multiple commands match your selection:\n`);
|
|
1112
|
-
this.context.stdout.write(`\n`);
|
|
1113
|
-
let index = 0;
|
|
1114
|
-
for (const command of this.commands) this.context.stdout.write(this.cli.usage(this.contexts[command].commandClass, { prefix: `${index++}. `.padStart(5) }));
|
|
1115
|
-
this.context.stdout.write(`\n`);
|
|
1116
|
-
this.context.stdout.write(`Run again with -h=<index> to see the longer details of any of those commands.\n`);
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
};
|
|
1120
|
-
|
|
1121
|
-
//#endregion
|
|
1122
|
-
//#region ../../node_modules/.pnpm/clipanion@4.0.0-rc.4_typanion@3.14.0/node_modules/clipanion/lib/advanced/Cli.mjs
|
|
1123
|
-
const errorCommandSymbol = Symbol(`clipanion/errorCommand`);
|
|
1124
|
-
async function runExit(...args) {
|
|
1125
|
-
const { resolvedOptions, resolvedCommandClasses, resolvedArgv, resolvedContext } = resolveRunParameters(args);
|
|
1126
|
-
const cli = Cli.from(resolvedCommandClasses, resolvedOptions);
|
|
1127
|
-
return cli.runExit(resolvedArgv, resolvedContext);
|
|
1128
|
-
}
|
|
1129
|
-
function resolveRunParameters(args) {
|
|
1130
|
-
let resolvedOptions;
|
|
1131
|
-
let resolvedCommandClasses;
|
|
1132
|
-
let resolvedArgv;
|
|
1133
|
-
let resolvedContext;
|
|
1134
|
-
if (typeof process !== `undefined` && typeof process.argv !== `undefined`) resolvedArgv = process.argv.slice(2);
|
|
1135
|
-
switch (args.length) {
|
|
1136
|
-
case 1:
|
|
1137
|
-
resolvedCommandClasses = args[0];
|
|
1138
|
-
break;
|
|
1139
|
-
case 2:
|
|
1140
|
-
if (args[0] && args[0].prototype instanceof Command || Array.isArray(args[0])) {
|
|
1141
|
-
resolvedCommandClasses = args[0];
|
|
1142
|
-
if (Array.isArray(args[1])) resolvedArgv = args[1];
|
|
1143
|
-
else resolvedContext = args[1];
|
|
1144
|
-
} else {
|
|
1145
|
-
resolvedOptions = args[0];
|
|
1146
|
-
resolvedCommandClasses = args[1];
|
|
1147
|
-
}
|
|
1148
|
-
break;
|
|
1149
|
-
case 3:
|
|
1150
|
-
if (Array.isArray(args[2])) {
|
|
1151
|
-
resolvedOptions = args[0];
|
|
1152
|
-
resolvedCommandClasses = args[1];
|
|
1153
|
-
resolvedArgv = args[2];
|
|
1154
|
-
} else if (args[0] && args[0].prototype instanceof Command || Array.isArray(args[0])) {
|
|
1155
|
-
resolvedCommandClasses = args[0];
|
|
1156
|
-
resolvedArgv = args[1];
|
|
1157
|
-
resolvedContext = args[2];
|
|
1158
|
-
} else {
|
|
1159
|
-
resolvedOptions = args[0];
|
|
1160
|
-
resolvedCommandClasses = args[1];
|
|
1161
|
-
resolvedContext = args[2];
|
|
1162
|
-
}
|
|
1163
|
-
break;
|
|
1164
|
-
default:
|
|
1165
|
-
{
|
|
1166
|
-
resolvedOptions = args[0];
|
|
1167
|
-
resolvedCommandClasses = args[1];
|
|
1168
|
-
resolvedArgv = args[2];
|
|
1169
|
-
resolvedContext = args[3];
|
|
1170
|
-
}
|
|
1171
|
-
break;
|
|
1172
|
-
}
|
|
1173
|
-
if (typeof resolvedArgv === `undefined`) throw new Error(`The argv parameter must be provided when running Clipanion outside of a Node context`);
|
|
1174
|
-
return {
|
|
1175
|
-
resolvedOptions,
|
|
1176
|
-
resolvedCommandClasses,
|
|
1177
|
-
resolvedArgv,
|
|
1178
|
-
resolvedContext
|
|
1179
|
-
};
|
|
1180
|
-
}
|
|
1181
|
-
/**
|
|
1182
|
-
* @template Context The context shared by all commands. Contexts are a set of values, defined when calling the `run`/`runExit` functions from the CLI instance, that will be made available to the commands via `this.context`.
|
|
1183
|
-
*/
|
|
1184
|
-
var Cli = class Cli {
|
|
1185
|
-
/**
|
|
1186
|
-
* Creates a new Cli and registers all commands passed as parameters.
|
|
1187
|
-
*
|
|
1188
|
-
* @param commandClasses The Commands to register
|
|
1189
|
-
* @returns The created `Cli` instance
|
|
1190
|
-
*/
|
|
1191
|
-
static from(commandClasses, options = {}) {
|
|
1192
|
-
const cli = new Cli(options);
|
|
1193
|
-
const resolvedCommandClasses = Array.isArray(commandClasses) ? commandClasses : [commandClasses];
|
|
1194
|
-
for (const commandClass of resolvedCommandClasses) cli.register(commandClass);
|
|
1195
|
-
return cli;
|
|
1196
|
-
}
|
|
1197
|
-
constructor({ binaryLabel, binaryName: binaryNameOpt = `...`, binaryVersion, enableCapture = false, enableColors } = {}) {
|
|
1198
|
-
this.registrations = /* @__PURE__ */ new Map();
|
|
1199
|
-
this.builder = new CliBuilder({ binaryName: binaryNameOpt });
|
|
1200
|
-
this.binaryLabel = binaryLabel;
|
|
1201
|
-
this.binaryName = binaryNameOpt;
|
|
1202
|
-
this.binaryVersion = binaryVersion;
|
|
1203
|
-
this.enableCapture = enableCapture;
|
|
1204
|
-
this.enableColors = enableColors;
|
|
1205
|
-
}
|
|
1206
|
-
/**
|
|
1207
|
-
* Registers a command inside the CLI.
|
|
1208
|
-
*/
|
|
1209
|
-
register(commandClass) {
|
|
1210
|
-
var _a;
|
|
1211
|
-
if (this.registrations.has(commandClass)) throw new RangeError(`${commandClass.name} has already been registered`);
|
|
1212
|
-
const specs = /* @__PURE__ */ new Map();
|
|
1213
|
-
const command = new commandClass();
|
|
1214
|
-
for (const key in command) {
|
|
1215
|
-
const value = command[key];
|
|
1216
|
-
if (typeof value === `object` && value !== null && value[Command.isOption]) specs.set(key, value);
|
|
1217
|
-
}
|
|
1218
|
-
const builder = this.builder.command();
|
|
1219
|
-
const index = builder.cliIndex;
|
|
1220
|
-
const paths = (_a = commandClass.paths) !== null && _a !== void 0 ? _a : command.paths;
|
|
1221
|
-
if (typeof paths !== `undefined`) for (const path$1 of paths) builder.addPath(path$1);
|
|
1222
|
-
this.registrations.set(commandClass, {
|
|
1223
|
-
specs,
|
|
1224
|
-
builder,
|
|
1225
|
-
index
|
|
1226
|
-
});
|
|
1227
|
-
for (const [key, { definition }] of specs.entries()) definition(builder, key);
|
|
1228
|
-
builder.setContext({ commandClass });
|
|
1229
|
-
}
|
|
1230
|
-
process(opts, contextArg) {
|
|
1231
|
-
const { input, context: userContext, partial } = typeof opts === `object` && Array.isArray(opts) ? {
|
|
1232
|
-
input: opts,
|
|
1233
|
-
context: contextArg
|
|
1234
|
-
} : opts;
|
|
1235
|
-
const { contexts, process: process$1 } = this.builder.compile();
|
|
1236
|
-
const state = process$1(input, { partial });
|
|
1237
|
-
const context = {
|
|
1238
|
-
...Cli.defaultContext,
|
|
1239
|
-
...userContext
|
|
1240
|
-
};
|
|
1241
|
-
switch (state.selectedIndex) {
|
|
1242
|
-
case HELP_COMMAND_INDEX: {
|
|
1243
|
-
const command = HelpCommand.from(state, contexts);
|
|
1244
|
-
command.context = context;
|
|
1245
|
-
command.tokens = state.tokens;
|
|
1246
|
-
return command;
|
|
1247
|
-
}
|
|
1248
|
-
default:
|
|
1249
|
-
{
|
|
1250
|
-
const { commandClass } = contexts[state.selectedIndex];
|
|
1251
|
-
const record = this.registrations.get(commandClass);
|
|
1252
|
-
if (typeof record === `undefined`) throw new Error(`Assertion failed: Expected the command class to have been registered.`);
|
|
1253
|
-
const command = new commandClass();
|
|
1254
|
-
command.context = context;
|
|
1255
|
-
command.tokens = state.tokens;
|
|
1256
|
-
command.path = state.path;
|
|
1257
|
-
try {
|
|
1258
|
-
for (const [key, { transformer }] of record.specs.entries()) command[key] = transformer(record.builder, key, state, context);
|
|
1259
|
-
return command;
|
|
1260
|
-
} catch (error) {
|
|
1261
|
-
error[errorCommandSymbol] = command;
|
|
1262
|
-
throw error;
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
break;
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
async run(input, userContext) {
|
|
1269
|
-
var _a, _b;
|
|
1270
|
-
let command;
|
|
1271
|
-
const context = {
|
|
1272
|
-
...Cli.defaultContext,
|
|
1273
|
-
...userContext
|
|
1274
|
-
};
|
|
1275
|
-
const colored = (_a = this.enableColors) !== null && _a !== void 0 ? _a : context.colorDepth > 1;
|
|
1276
|
-
if (!Array.isArray(input)) command = input;
|
|
1277
|
-
else try {
|
|
1278
|
-
command = this.process(input, context);
|
|
1279
|
-
} catch (error) {
|
|
1280
|
-
context.stdout.write(this.error(error, { colored }));
|
|
1281
|
-
return 1;
|
|
1282
|
-
}
|
|
1283
|
-
if (command.help) {
|
|
1284
|
-
context.stdout.write(this.usage(command, {
|
|
1285
|
-
colored,
|
|
1286
|
-
detailed: true
|
|
1287
|
-
}));
|
|
1288
|
-
return 0;
|
|
1289
|
-
}
|
|
1290
|
-
command.context = context;
|
|
1291
|
-
command.cli = {
|
|
1292
|
-
binaryLabel: this.binaryLabel,
|
|
1293
|
-
binaryName: this.binaryName,
|
|
1294
|
-
binaryVersion: this.binaryVersion,
|
|
1295
|
-
enableCapture: this.enableCapture,
|
|
1296
|
-
enableColors: this.enableColors,
|
|
1297
|
-
definitions: () => this.definitions(),
|
|
1298
|
-
definition: (command$1) => this.definition(command$1),
|
|
1299
|
-
error: (error, opts) => this.error(error, opts),
|
|
1300
|
-
format: (colored$1) => this.format(colored$1),
|
|
1301
|
-
process: (input$1, subContext) => this.process(input$1, {
|
|
1302
|
-
...context,
|
|
1303
|
-
...subContext
|
|
1304
|
-
}),
|
|
1305
|
-
run: (input$1, subContext) => this.run(input$1, {
|
|
1306
|
-
...context,
|
|
1307
|
-
...subContext
|
|
1308
|
-
}),
|
|
1309
|
-
usage: (command$1, opts) => this.usage(command$1, opts)
|
|
1310
|
-
};
|
|
1311
|
-
const activate = this.enableCapture ? (_b = getCaptureActivator(context)) !== null && _b !== void 0 ? _b : noopCaptureActivator : noopCaptureActivator;
|
|
1312
|
-
let exitCode;
|
|
1313
|
-
try {
|
|
1314
|
-
exitCode = await activate(() => command.validateAndExecute().catch((error) => command.catch(error).then(() => 0)));
|
|
1315
|
-
} catch (error) {
|
|
1316
|
-
context.stdout.write(this.error(error, {
|
|
1317
|
-
colored,
|
|
1318
|
-
command
|
|
1319
|
-
}));
|
|
1320
|
-
return 1;
|
|
1321
|
-
}
|
|
1322
|
-
return exitCode;
|
|
1323
|
-
}
|
|
1324
|
-
async runExit(input, context) {
|
|
1325
|
-
process.exitCode = await this.run(input, context);
|
|
1326
|
-
}
|
|
1327
|
-
definition(commandClass, { colored = false } = {}) {
|
|
1328
|
-
if (!commandClass.usage) return null;
|
|
1329
|
-
const { usage: path$1 } = this.getUsageByRegistration(commandClass, { detailed: false });
|
|
1330
|
-
const { usage, options } = this.getUsageByRegistration(commandClass, {
|
|
1331
|
-
detailed: true,
|
|
1332
|
-
inlineOptions: false
|
|
1333
|
-
});
|
|
1334
|
-
const category = typeof commandClass.usage.category !== `undefined` ? formatMarkdownish(commandClass.usage.category, {
|
|
1335
|
-
format: this.format(colored),
|
|
1336
|
-
paragraphs: false
|
|
1337
|
-
}) : void 0;
|
|
1338
|
-
const description = typeof commandClass.usage.description !== `undefined` ? formatMarkdownish(commandClass.usage.description, {
|
|
1339
|
-
format: this.format(colored),
|
|
1340
|
-
paragraphs: false
|
|
1341
|
-
}) : void 0;
|
|
1342
|
-
const details = typeof commandClass.usage.details !== `undefined` ? formatMarkdownish(commandClass.usage.details, {
|
|
1343
|
-
format: this.format(colored),
|
|
1344
|
-
paragraphs: true
|
|
1345
|
-
}) : void 0;
|
|
1346
|
-
const examples = typeof commandClass.usage.examples !== `undefined` ? commandClass.usage.examples.map(([label, cli]) => [formatMarkdownish(label, {
|
|
1347
|
-
format: this.format(colored),
|
|
1348
|
-
paragraphs: false
|
|
1349
|
-
}), cli.replace(/\$0/g, this.binaryName)]) : void 0;
|
|
1350
|
-
return {
|
|
1351
|
-
path: path$1,
|
|
1352
|
-
usage,
|
|
1353
|
-
category,
|
|
1354
|
-
description,
|
|
1355
|
-
details,
|
|
1356
|
-
examples,
|
|
1357
|
-
options
|
|
1358
|
-
};
|
|
1359
|
-
}
|
|
1360
|
-
definitions({ colored = false } = {}) {
|
|
1361
|
-
const data = [];
|
|
1362
|
-
for (const commandClass of this.registrations.keys()) {
|
|
1363
|
-
const usage = this.definition(commandClass, { colored });
|
|
1364
|
-
if (!usage) continue;
|
|
1365
|
-
data.push(usage);
|
|
1366
|
-
}
|
|
1367
|
-
return data;
|
|
1368
|
-
}
|
|
1369
|
-
usage(command = null, { colored, detailed = false, prefix = `$ ` } = {}) {
|
|
1370
|
-
var _a;
|
|
1371
|
-
if (command === null) {
|
|
1372
|
-
for (const commandClass$1 of this.registrations.keys()) {
|
|
1373
|
-
const paths = commandClass$1.paths;
|
|
1374
|
-
const isDocumented = typeof commandClass$1.usage !== `undefined`;
|
|
1375
|
-
const isExclusivelyDefault = !paths || paths.length === 0 || paths.length === 1 && paths[0].length === 0;
|
|
1376
|
-
const isDefault = isExclusivelyDefault || ((_a = paths === null || paths === void 0 ? void 0 : paths.some((path$1) => path$1.length === 0)) !== null && _a !== void 0 ? _a : false);
|
|
1377
|
-
if (isDefault) if (command) {
|
|
1378
|
-
command = null;
|
|
1379
|
-
break;
|
|
1380
|
-
} else command = commandClass$1;
|
|
1381
|
-
else if (isDocumented) {
|
|
1382
|
-
command = null;
|
|
1383
|
-
continue;
|
|
1384
|
-
}
|
|
1385
|
-
}
|
|
1386
|
-
if (command) detailed = true;
|
|
1387
|
-
}
|
|
1388
|
-
const commandClass = command !== null && command instanceof Command ? command.constructor : command;
|
|
1389
|
-
let result = ``;
|
|
1390
|
-
if (!commandClass) {
|
|
1391
|
-
const commandsByCategories = /* @__PURE__ */ new Map();
|
|
1392
|
-
for (const [commandClass$1, { index }] of this.registrations.entries()) {
|
|
1393
|
-
if (typeof commandClass$1.usage === `undefined`) continue;
|
|
1394
|
-
const category = typeof commandClass$1.usage.category !== `undefined` ? formatMarkdownish(commandClass$1.usage.category, {
|
|
1395
|
-
format: this.format(colored),
|
|
1396
|
-
paragraphs: false
|
|
1397
|
-
}) : null;
|
|
1398
|
-
let categoryCommands = commandsByCategories.get(category);
|
|
1399
|
-
if (typeof categoryCommands === `undefined`) commandsByCategories.set(category, categoryCommands = []);
|
|
1400
|
-
const { usage } = this.getUsageByIndex(index);
|
|
1401
|
-
categoryCommands.push({
|
|
1402
|
-
commandClass: commandClass$1,
|
|
1403
|
-
usage
|
|
1404
|
-
});
|
|
1405
|
-
}
|
|
1406
|
-
const categoryNames = Array.from(commandsByCategories.keys()).sort((a, b) => {
|
|
1407
|
-
if (a === null) return -1;
|
|
1408
|
-
if (b === null) return 1;
|
|
1409
|
-
return a.localeCompare(b, `en`, {
|
|
1410
|
-
usage: `sort`,
|
|
1411
|
-
caseFirst: `upper`
|
|
1412
|
-
});
|
|
1413
|
-
});
|
|
1414
|
-
const hasLabel = typeof this.binaryLabel !== `undefined`;
|
|
1415
|
-
const hasVersion = typeof this.binaryVersion !== `undefined`;
|
|
1416
|
-
if (hasLabel || hasVersion) {
|
|
1417
|
-
if (hasLabel && hasVersion) result += `${this.format(colored).header(`${this.binaryLabel} - ${this.binaryVersion}`)}\n\n`;
|
|
1418
|
-
else if (hasLabel) result += `${this.format(colored).header(`${this.binaryLabel}`)}\n`;
|
|
1419
|
-
else result += `${this.format(colored).header(`${this.binaryVersion}`)}\n`;
|
|
1420
|
-
result += ` ${this.format(colored).bold(prefix)}${this.binaryName} <command>\n`;
|
|
1421
|
-
} else result += `${this.format(colored).bold(prefix)}${this.binaryName} <command>\n`;
|
|
1422
|
-
for (const categoryName of categoryNames) {
|
|
1423
|
-
const commands = commandsByCategories.get(categoryName).slice().sort((a, b) => {
|
|
1424
|
-
return a.usage.localeCompare(b.usage, `en`, {
|
|
1425
|
-
usage: `sort`,
|
|
1426
|
-
caseFirst: `upper`
|
|
1427
|
-
});
|
|
1428
|
-
});
|
|
1429
|
-
const header = categoryName !== null ? categoryName.trim() : `General commands`;
|
|
1430
|
-
result += `\n`;
|
|
1431
|
-
result += `${this.format(colored).header(`${header}`)}\n`;
|
|
1432
|
-
for (const { commandClass: commandClass$1, usage } of commands) {
|
|
1433
|
-
const doc = commandClass$1.usage.description || `undocumented`;
|
|
1434
|
-
result += `\n`;
|
|
1435
|
-
result += ` ${this.format(colored).bold(usage)}\n`;
|
|
1436
|
-
result += ` ${formatMarkdownish(doc, {
|
|
1437
|
-
format: this.format(colored),
|
|
1438
|
-
paragraphs: false
|
|
1439
|
-
})}`;
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
result += `\n`;
|
|
1443
|
-
result += formatMarkdownish(`You can also print more details about any of these commands by calling them with the \`-h,--help\` flag right after the command name.`, {
|
|
1444
|
-
format: this.format(colored),
|
|
1445
|
-
paragraphs: true
|
|
1446
|
-
});
|
|
1447
|
-
} else if (!detailed) {
|
|
1448
|
-
const { usage } = this.getUsageByRegistration(commandClass);
|
|
1449
|
-
result += `${this.format(colored).bold(prefix)}${usage}\n`;
|
|
1450
|
-
} else {
|
|
1451
|
-
const { description = ``, details = ``, examples = [] } = commandClass.usage || {};
|
|
1452
|
-
if (description !== ``) {
|
|
1453
|
-
result += formatMarkdownish(description, {
|
|
1454
|
-
format: this.format(colored),
|
|
1455
|
-
paragraphs: false
|
|
1456
|
-
}).replace(/^./, ($0) => $0.toUpperCase());
|
|
1457
|
-
result += `\n`;
|
|
1458
|
-
}
|
|
1459
|
-
if (details !== `` || examples.length > 0) {
|
|
1460
|
-
result += `${this.format(colored).header(`Usage`)}\n`;
|
|
1461
|
-
result += `\n`;
|
|
1462
|
-
}
|
|
1463
|
-
const { usage, options } = this.getUsageByRegistration(commandClass, { inlineOptions: false });
|
|
1464
|
-
result += `${this.format(colored).bold(prefix)}${usage}\n`;
|
|
1465
|
-
if (options.length > 0) {
|
|
1466
|
-
result += `\n`;
|
|
1467
|
-
result += `${this.format(colored).header(`Options`)}\n`;
|
|
1468
|
-
const maxDefinitionLength = options.reduce((length, option) => {
|
|
1469
|
-
return Math.max(length, option.definition.length);
|
|
1470
|
-
}, 0);
|
|
1471
|
-
result += `\n`;
|
|
1472
|
-
for (const { definition, description: description$1 } of options) result += ` ${this.format(colored).bold(definition.padEnd(maxDefinitionLength))} ${formatMarkdownish(description$1, {
|
|
1473
|
-
format: this.format(colored),
|
|
1474
|
-
paragraphs: false
|
|
1475
|
-
})}`;
|
|
1476
|
-
}
|
|
1477
|
-
if (details !== ``) {
|
|
1478
|
-
result += `\n`;
|
|
1479
|
-
result += `${this.format(colored).header(`Details`)}\n`;
|
|
1480
|
-
result += `\n`;
|
|
1481
|
-
result += formatMarkdownish(details, {
|
|
1482
|
-
format: this.format(colored),
|
|
1483
|
-
paragraphs: true
|
|
1484
|
-
});
|
|
1485
|
-
}
|
|
1486
|
-
if (examples.length > 0) {
|
|
1487
|
-
result += `\n`;
|
|
1488
|
-
result += `${this.format(colored).header(`Examples`)}\n`;
|
|
1489
|
-
for (const [description$1, example] of examples) {
|
|
1490
|
-
result += `\n`;
|
|
1491
|
-
result += formatMarkdownish(description$1, {
|
|
1492
|
-
format: this.format(colored),
|
|
1493
|
-
paragraphs: false
|
|
1494
|
-
});
|
|
1495
|
-
result += `${example.replace(/^/m, ` ${this.format(colored).bold(prefix)}`).replace(/\$0/g, this.binaryName)}\n`;
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
}
|
|
1499
|
-
return result;
|
|
1500
|
-
}
|
|
1501
|
-
error(error, _a) {
|
|
1502
|
-
var _b;
|
|
1503
|
-
var { colored, command = (_b = error[errorCommandSymbol]) !== null && _b !== void 0 ? _b : null } = _a === void 0 ? {} : _a;
|
|
1504
|
-
if (!error || typeof error !== `object` || !(`stack` in error)) error = /* @__PURE__ */ new Error(`Execution failed with a non-error rejection (rejected value: ${JSON.stringify(error)})`);
|
|
1505
|
-
let result = ``;
|
|
1506
|
-
let name = error.name.replace(/([a-z])([A-Z])/g, `$1 $2`);
|
|
1507
|
-
if (name === `Error`) name = `Internal Error`;
|
|
1508
|
-
result += `${this.format(colored).error(name)}: ${error.message}\n`;
|
|
1509
|
-
const meta = error.clipanion;
|
|
1510
|
-
if (typeof meta !== `undefined`) {
|
|
1511
|
-
if (meta.type === `usage`) {
|
|
1512
|
-
result += `\n`;
|
|
1513
|
-
result += this.usage(command);
|
|
1514
|
-
}
|
|
1515
|
-
} else if (error.stack) result += `${error.stack.replace(/^.*\n/, ``)}\n`;
|
|
1516
|
-
return result;
|
|
1517
|
-
}
|
|
1518
|
-
format(colored) {
|
|
1519
|
-
var _a;
|
|
1520
|
-
return ((_a = colored !== null && colored !== void 0 ? colored : this.enableColors) !== null && _a !== void 0 ? _a : Cli.defaultContext.colorDepth > 1) ? richFormat : textFormat;
|
|
1521
|
-
}
|
|
1522
|
-
getUsageByRegistration(klass, opts) {
|
|
1523
|
-
const record = this.registrations.get(klass);
|
|
1524
|
-
if (typeof record === `undefined`) throw new Error(`Assertion failed: Unregistered command`);
|
|
1525
|
-
return this.getUsageByIndex(record.index, opts);
|
|
1526
|
-
}
|
|
1527
|
-
getUsageByIndex(n, opts) {
|
|
1528
|
-
return this.builder.getBuilderByIndex(n).usage(opts);
|
|
1529
|
-
}
|
|
1530
|
-
};
|
|
1531
|
-
/**
|
|
1532
|
-
* The default context of the CLI.
|
|
1533
|
-
*
|
|
1534
|
-
* Contains the stdio of the current `process`.
|
|
1535
|
-
*/
|
|
1536
|
-
Cli.defaultContext = {
|
|
1537
|
-
env: process.env,
|
|
1538
|
-
stdin: process.stdin,
|
|
1539
|
-
stdout: process.stdout,
|
|
1540
|
-
stderr: process.stderr,
|
|
1541
|
-
colorDepth: getDefaultColorDepth()
|
|
1542
|
-
};
|
|
1543
|
-
function noopCaptureActivator(fn) {
|
|
1544
|
-
return fn();
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1547
|
-
//#endregion
|
|
1548
|
-
//#region src/consts.ts
|
|
1549
|
-
const COMMAND_CATEGORIES = { deployment: "deployment" };
|
|
1550
|
-
|
|
1551
|
-
//#endregion
|
|
1552
|
-
//#region src/bundle/internal/bundler.ts
|
|
1553
|
-
var PatternSet = class {
|
|
1554
|
-
pattern;
|
|
1555
|
-
options;
|
|
1556
|
-
constructor(pattern, options) {
|
|
1557
|
-
this.pattern = pattern;
|
|
1558
|
-
this.options = options;
|
|
1559
|
-
}
|
|
1560
|
-
};
|
|
1561
|
-
/**
|
|
1562
|
-
|
|
1563
|
-
* Bundles files into a zip file based on a set of glob patterns.
|
|
1564
|
-
|
|
1565
|
-
*
|
|
1566
|
-
|
|
1567
|
-
* Always includes package.json in the bundle.
|
|
1568
|
-
|
|
1569
|
-
* Excludes installer folder.
|
|
1570
|
-
|
|
1571
|
-
*/
|
|
1572
|
-
var Bundler = class {
|
|
1573
|
-
patterns = [];
|
|
1574
|
-
addGlobPattern(pattern, options) {
|
|
1575
|
-
const resolvedOptions = this.resolveOptions(options);
|
|
1576
|
-
const patternArray = asArray(pattern);
|
|
1577
|
-
this.patterns.push(new PatternSet(patternArray, resolvedOptions));
|
|
1578
|
-
}
|
|
1579
|
-
async bundle() {
|
|
1580
|
-
const zip = new Zip();
|
|
1581
|
-
for (const pattern of this.patterns) {
|
|
1582
|
-
const options = pattern.options ?? {};
|
|
1583
|
-
let cwd;
|
|
1584
|
-
if (!options.cwd) cwd = process.cwd();
|
|
1585
|
-
else if (typeof options.cwd === "string") cwd = options.cwd;
|
|
1586
|
-
else cwd = fileURLToPath(options.cwd);
|
|
1587
|
-
if (!path.isAbsolute(cwd)) cwd = path.resolve(cwd);
|
|
1588
|
-
options.absolute = true;
|
|
1589
|
-
options.cwd = cwd;
|
|
1590
|
-
const files = await glob(pattern.pattern, options);
|
|
1591
|
-
await Promise.all(files.map(async (file) => {
|
|
1592
|
-
const zipPath = path.relative(cwd, file);
|
|
1593
|
-
const stream = createReadStream(file, "binary");
|
|
1594
|
-
zip.file(zipPath, stream, { compression: "DEFLATE" });
|
|
1595
|
-
}));
|
|
1596
|
-
}
|
|
1597
|
-
return zip;
|
|
1598
|
-
}
|
|
1599
|
-
resolveOptions(options) {
|
|
1600
|
-
return options;
|
|
1601
|
-
}
|
|
1602
|
-
};
|
|
1603
|
-
|
|
1604
|
-
//#endregion
|
|
1605
|
-
//#region src/bundle/internal/appBundler.ts
|
|
1606
|
-
var AppBundler = class extends Bundler {
|
|
1607
|
-
installerFolderGlob = "**/installer/**";
|
|
1608
|
-
constructor() {
|
|
1609
|
-
super();
|
|
1610
|
-
this.addGlobPattern("package.json");
|
|
1611
|
-
}
|
|
1612
|
-
async bundle() {
|
|
1613
|
-
const zip = await super.bundle();
|
|
1614
|
-
const packageJson = zip.file("package.json");
|
|
1615
|
-
if (!packageJson) throw new Error("package.json not found");
|
|
1616
|
-
return zip;
|
|
1617
|
-
}
|
|
1618
|
-
resolveOptions(options) {
|
|
1619
|
-
if (!options) return { ignore: this.installerFolderGlob };
|
|
1620
|
-
const ignore = typeof options.ignore === "string" ? [options.ignore] : options.ignore ?? [];
|
|
1621
|
-
ignore.push(this.installerFolderGlob);
|
|
1622
|
-
options.ignore = ignore;
|
|
1623
|
-
return options;
|
|
1624
|
-
}
|
|
1625
|
-
};
|
|
1626
|
-
|
|
1627
|
-
//#endregion
|
|
1628
|
-
//#region src/bundle/command.ts
|
|
1629
|
-
var BundleCommand = class extends Command {
|
|
1630
|
-
overlayedConfigGlob = "**/overlayed.config.{js,ts,mts}";
|
|
1631
|
-
static paths = [["bundle"]];
|
|
1632
|
-
static usage = Command.Usage({
|
|
1633
|
-
category: COMMAND_CATEGORIES.deployment,
|
|
1634
|
-
description: "Bundle the app and site for deployment.",
|
|
1635
|
-
details: `
|
|
1
|
+
import{Command as e,UsageError as t,runExit as n}from"clipanion";import r from"chalk";import i,{createReadStream as a}from"node:fs";import"arktype";import{createWriteStream as o,existsSync as s,mkdirSync as c,readdirSync as l,unlinkSync as u,writeFileSync as d}from"fs";import{join as f}from"path";import p from"node:path";import{glob as m}from"glob";import h,{fileURLToPath as g}from"node:url";import _ from"jszip";const v={deployment:`deployment`};function y(e){return{all:e=e||new Map,on:function(t,n){var r=e.get(t);r?r.push(n):e.set(t,[n])},off:function(t,n){var r=e.get(t);r&&(n?r.splice(r.indexOf(n)>>>0,1):e.set(t,[]))},emit:function(t,n){var r=e.get(t);r&&r.slice().map(function(e){e(n)}),(r=e.get(`*`))&&r.slice().map(function(e){e(t,n)})}}}function b(e){return Object.prototype.toString.call(e)===`[object Object]`}function x(e){return e?Array.isArray(e)?e:[e]:[]}var S=class{data=[];constructor(){}get size(){return this.data.length}add(e){this.data.push(e)}next(){return this.data.shift()}clear(){this.data.length=0}*flush(){for(;this.size>0;){let e=this.next();e&&(yield e)}}},C=class{emitter;constructor(){this.emitter=y()}on(e,t){this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}emit(e,t){this.emitter.emit(e,t)}removeAllListeners(){this.emitter.all.clear()}};function w(e,...t){let n=class extends e{static _instance;static getInstance(){return this._instance||(this._instance=new e(...t)),this._instance}static clearInstance(){this._instance=void 0}};return n}var T=class extends C{destroy(){this.removeAllListeners()}fatal(e,t,n){this.emit(`fatal`,{code:t,message:e,data:n,timestamp:Date.now()})}error(e,t,n){this.emit(`error`,{code:t,message:e,data:n,timestamp:Date.now()})}warn(e,t,n){this.emit(`warning`,{code:t,message:e,data:n,timestamp:Date.now()})}};w(T);var E=class e extends C{stream;logPath;baseFileName;currentDate;rotationCheckInterval;isRotating=!1;constructor(e,t){super(),this.logPath=e,this.baseFileName=t.replace(`.log`,``),this.currentDate=this.getDateString(new Date),this.ensureLogDirectory(),this.ensureLogFile(),this.stream=this.createStream(),this.rotationCheckInterval=this.startRotationCheck(),this.cleanupOldLogs()}static scope(t,n){return new e(t,n)}log(...e){this.write(`log`,...e)}error(...e){this.write(`error`,...e)}warn(...e){this.write(`warn`,...e)}info(...e){this.write(`info`,...e)}debug(...e){this.write(`debug`,...e)}async close(){clearInterval(this.rotationCheckInterval),await new Promise(e=>{this.stream.end(()=>e())})}getCurrentFileName(){return this.getFileName(this.currentDate)}getFileName(e){return`${this.baseFileName}-${e}.log`}ensureLogDirectory(){try{c(this.logPath,{recursive:!0})}catch(e){throw console.error(`Failed to create log directory ${this.logPath}:`,e),e}}ensureLogFile(){let e=f(this.logPath,this.getFileName(this.currentDate));if(!s(e))try{d(e,``,`utf8`)}catch(t){throw console.error(`Failed to create log file ${e}:`,t),t}}getDateString(e){return e.toISOString().split(`T`)[0]}createStream(){let e=f(this.logPath,this.getFileName(this.currentDate));return o(e,{flags:`a`,encoding:`utf8`})}async rotateLogs(){if(this.isRotating)return;this.isRotating=!0;let e=this.getDateString(new Date);e!==this.currentDate&&await new Promise(t=>{this.stream.end(()=>{this.currentDate=e,this.stream=this.createStream(),this.cleanupOldLogs(),t()})}),this.isRotating=!1}startRotationCheck(){return setInterval(()=>this.rotateLogs(),6e4)}cleanupOldLogs(){let e=l(this.logPath),t=new Date;t.setDate(t.getDate()-3),e.filter(e=>e.startsWith(this.baseFileName)&&e.endsWith(`.log`)).filter(e=>{let n=e.replace(`${this.baseFileName}-`,``).replace(`.log`,``),r=new Date(n);return r<t}).forEach(e=>{try{u(f(this.logPath,e))}catch(t){console.error(`Failed to delete old log file ${e}:`,t)}})}write(e,...t){let n=new Date,r=n.toISOString().replace(`T`,` `).replace(/\.\d+Z$/,``)+`.${n.getMilliseconds().toString().padStart(3,`0`)}`,i=t.map(e=>typeof e==`object`?JSON.stringify(e,void 0,2):String(e)).join(` `),a=`[${r}] [${e}] ${i}\n`;this.stream.write(a,e=>{e?this.emit(`error`,e):this.emit(`write`,a)})}};const D=()=>p.join(process.env.APPDATA??``,`overlayed`),O=e=>p.join(D(),`apps`,e),k=e=>p.join(O(e),`logs`);var A=class{fileLogger;path;appId;messageQueue=new S;fileName;constructor(e){this.fileName=e}init(e){this.appId=e,this.path=k(e),this.fileLogger=new E(this.path,this.fileName),this.messageQueue.flush().forEach(e=>{this.fileLogger?.[e.type](...e.args)})}scope(e){if(!this.appId||!this.path)throw Error(`Logger not initialized`);let t=`[${e}]`;return{scope:e=>this.scope(e),error:(...e)=>this.error(t,...e),warn:(...e)=>this.warn(t,...e),info:(...e)=>this.info(t,...e),log:(...e)=>this.log(t,...e)}}error(...e){this.handle(`error`,...e)}warn(...e){this.handle(`warn`,...e)}info(...e){this.handle(`log`,...e)}debug(...e){this.handle(`debug`,...e)}log(...e){this.handle(`log`,...e)}handle(e,...t){console[e](...t),this.fileLogger?this.fileLogger[e](...t):this.messageQueue.add({type:e,args:t})}};w(A,`main.log`);const j=`**/overlayed.config.{js,ts,mts}`;async function M(){let e=P(),t=await Promise.all(e.map(async e=>{let t=await import(h.pathToFileURL(e).toString());return t.default}));return t.filter(N)}function N(e){return b(e)&&`app`in e}function P(){let e=m.globSync(j,{absolute:!0,cwd:process.cwd()});return e}var F=class{pattern;options;constructor(e,t){this.pattern=e,this.options=t}},I=class{patterns=[];addGlobPattern(e,t){let n=this.resolveOptions(t),r=x(e);this.patterns.push(new F(r,n))}async bundle(){let e=new _;for(let t of this.patterns){let n=t.options??{},r;r=n.cwd?typeof n.cwd==`string`?n.cwd:g(n.cwd):process.cwd(),p.isAbsolute(r)||(r=p.resolve(r)),n.absolute=!0,n.cwd=r;let i=await m(t.pattern,n);await Promise.all(i.map(async t=>{let n=p.relative(r,t),i=a(t,`binary`);e.file(n,i,{compression:`DEFLATE`})}))}return e}resolveOptions(e){return e}},L=class extends I{installerFolderGlob=`**/installer/**`;constructor(){super(),this.addGlobPattern(`package.json`)}async bundle(){let e=await super.bundle(),t=e.file(`package.json`);if(!t)throw Error(`package.json not found`);return e}resolveOptions(e){if(!e)return{ignore:this.installerFolderGlob};let t=typeof e.ignore==`string`?[e.ignore]:e.ignore??[];return t.push(this.installerFolderGlob),e.ignore=t,e}},R=class extends e{overlayedConfigGlob=`**/overlayed.config.{js,ts,mts}`;static paths=[[`bundle`]];static usage=e.Usage({category:v.deployment,description:`Bundle the app and site for deployment.`,details:`
|
|
1636
2
|
Bundle the app and site for deployment.
|
|
1637
3
|
|
|
1638
4
|
[Docs](http://docs.overlayed.gg/cli/bundle)
|
|
1639
|
-
`,
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
async execute() {
|
|
1643
|
-
const config = await this.resolveConfig();
|
|
1644
|
-
const appWriteStream = fs.createWriteStream(process.cwd() + "/app.zip");
|
|
1645
|
-
const appZip = await config.app.bundle();
|
|
1646
|
-
appWriteStream.write(await appZip.generateAsync({ type: "nodebuffer" }));
|
|
1647
|
-
if (config.site) {
|
|
1648
|
-
const siteWriteStream = fs.createWriteStream(process.cwd() + "/site.zip");
|
|
1649
|
-
const siteZip = await config.site?.bundle();
|
|
1650
|
-
siteWriteStream.write(await siteZip?.generateAsync({ type: "nodebuffer" }));
|
|
1651
|
-
}
|
|
1652
|
-
this.context.stdout.write(chalk.green("Bundle created successfully."));
|
|
1653
|
-
}
|
|
1654
|
-
async resolveConfig() {
|
|
1655
|
-
const configs = await getOverlayedConfigs();
|
|
1656
|
-
if (configs.length === 0) throw new UsageError("No config file found matching " + this.overlayedConfigGlob);
|
|
1657
|
-
if (configs.length > 1) this.context.stdout.write(chalk.yellow(`
|
|
1658
|
-
Multiple config files found matching ${OVERLAYED_CONFIG_GLOB}, using the first one.
|
|
1659
|
-
`));
|
|
1660
|
-
const config = configs.at(0);
|
|
1661
|
-
return {
|
|
1662
|
-
app: this.getAppBundler(config.app),
|
|
1663
|
-
site: config.site ? this.getSiteBundler(config.site) : void 0
|
|
1664
|
-
};
|
|
1665
|
-
}
|
|
1666
|
-
getAppBundler(config) {
|
|
1667
|
-
const bundler = new AppBundler();
|
|
1668
|
-
bundler.addGlobPattern(config.include, { ignore: config.exclude });
|
|
1669
|
-
return bundler;
|
|
1670
|
-
}
|
|
1671
|
-
getSiteBundler(config) {
|
|
1672
|
-
const bundler = new Bundler();
|
|
1673
|
-
bundler.addGlobPattern(config.include, { ignore: config.exclude });
|
|
1674
|
-
return bundler;
|
|
1675
|
-
}
|
|
1676
|
-
};
|
|
1677
|
-
|
|
1678
|
-
//#endregion
|
|
1679
|
-
//#region src/cli.ts
|
|
1680
|
-
runExit([BundleCommand]);
|
|
1681
|
-
|
|
1682
|
-
//#endregion
|
|
5
|
+
`,examples:[[`Basic usage`,`$0 bundle`]]});async execute(){let e=await this.resolveConfig(),t=i.createWriteStream(process.cwd()+`/app.zip`),n=await e.app.bundle();if(t.write(await n.generateAsync({type:`nodebuffer`})),e.site){let t=i.createWriteStream(process.cwd()+`/site.zip`),n=await e.site?.bundle();t.write(await n?.generateAsync({type:`nodebuffer`}))}this.context.stdout.write(r.green(`Bundle created successfully.`))}async resolveConfig(){let e=await M();if(e.length===0)throw new t(`No config file found matching `+this.overlayedConfigGlob);e.length>1&&this.context.stdout.write(r.yellow(`
|
|
6
|
+
Multiple config files found matching ${j}, using the first one.
|
|
7
|
+
`));let n=e.at(0);return{app:this.getAppBundler(n.app),site:n.site?this.getSiteBundler(n.site):void 0}}getAppBundler(e){let t=new L;return t.addGlobPattern(e.include,{ignore:e.exclude}),t}getSiteBundler(e){let t=new I;return t.addGlobPattern(e.include,{ignore:e.exclude}),t}};n([R]);
|