@rune-cli/rune 0.0.7 → 0.0.8
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.mjs +3 -3
- package/dist/{dist-FWLEc-op.mjs → dist-uz53Uv1e.mjs} +43 -2
- package/dist/{index-B6XsJ6ON.d.mts → index-BWxfSwrT.d.mts} +21 -7
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{run-manifest-command-BmeVwPA5.mjs → run-manifest-command-Dq_lBv-H.mjs} +1 -1
- package/dist/runtime.d.mts +1 -1
- package/dist/runtime.mjs +2 -2
- package/dist/test.d.mts +1 -1
- package/dist/test.mjs +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./dist-
|
|
3
|
-
import { n as isHelpFlag, r as isVersionFlag, t as runManifestCommand } from "./run-manifest-command-
|
|
2
|
+
import "./dist-uz53Uv1e.mjs";
|
|
3
|
+
import { n as isHelpFlag, r as isVersionFlag, t as runManifestCommand } from "./run-manifest-command-Dq_lBv-H.mjs";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { build } from "esbuild";
|
|
6
6
|
import { cp, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import ts from "typescript";
|
|
9
9
|
//#region package.json
|
|
10
|
-
var version = "0.0.
|
|
10
|
+
var version = "0.0.8";
|
|
11
11
|
//#endregion
|
|
12
12
|
//#region src/manifest/generate-manifest.ts
|
|
13
13
|
const COMMAND_ENTRY_FILE = "index.ts";
|
|
@@ -4,6 +4,34 @@ function isSchemaField(field) {
|
|
|
4
4
|
return "schema" in field && field.schema !== void 0;
|
|
5
5
|
}
|
|
6
6
|
const DEFINED_COMMAND_BRAND = Symbol.for("@rune-cli/defined-command");
|
|
7
|
+
const OPTION_NAME_RE = /^[A-Za-z][A-Za-z0-9]*(?:-[A-Za-z0-9]+)*$/;
|
|
8
|
+
const ALIAS_RE = /^[a-zA-Z]$/;
|
|
9
|
+
function validateFieldShape(fields, kind) {
|
|
10
|
+
for (const field of fields) {
|
|
11
|
+
const raw = field;
|
|
12
|
+
if (raw.schema === void 0 && raw.type === void 0) throw new Error(`${kind === "argument" ? "Argument" : "Option"} "${raw.name}" must have either a "type" or "schema" property.`);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function validateUniqueFieldNames(fields, kind) {
|
|
16
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17
|
+
for (const field of fields) {
|
|
18
|
+
if (field.name.length === 0) throw new Error(`Invalid ${kind} name "${field.name}". Names must be non-empty.`);
|
|
19
|
+
if (seen.has(field.name)) throw new Error(`Duplicate ${kind} name "${field.name}".`);
|
|
20
|
+
seen.add(field.name);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function validateOptionNames(options) {
|
|
24
|
+
for (const field of options) if (!OPTION_NAME_RE.test(field.name)) throw new Error(`Invalid option name "${field.name}". Option names must start with a letter and contain only letters, numbers, and internal hyphens.`);
|
|
25
|
+
}
|
|
26
|
+
function validateOptionAliases(options) {
|
|
27
|
+
const seen = /* @__PURE__ */ new Set();
|
|
28
|
+
for (const field of options) {
|
|
29
|
+
if (field.alias === void 0) continue;
|
|
30
|
+
if (!ALIAS_RE.test(field.alias)) throw new Error(`Invalid alias "${field.alias}" for option "${field.name}". Alias must be a single letter.`);
|
|
31
|
+
if (seen.has(field.alias)) throw new Error(`Duplicate alias "${field.alias}" for option "${field.name}".`);
|
|
32
|
+
seen.add(field.alias);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
7
35
|
function isOptionalArg(field) {
|
|
8
36
|
if (isSchemaField(field)) return;
|
|
9
37
|
return field.required !== true || field.default !== void 0;
|
|
@@ -69,7 +97,17 @@ function validateArgOrdering(args) {
|
|
|
69
97
|
* the ordering check is skipped for that field.
|
|
70
98
|
*/
|
|
71
99
|
function defineCommand(input) {
|
|
72
|
-
if (input.args)
|
|
100
|
+
if (input.args) {
|
|
101
|
+
validateFieldShape(input.args, "argument");
|
|
102
|
+
validateUniqueFieldNames(input.args, "argument");
|
|
103
|
+
validateArgOrdering(input.args);
|
|
104
|
+
}
|
|
105
|
+
if (input.options) {
|
|
106
|
+
validateFieldShape(input.options, "option");
|
|
107
|
+
validateUniqueFieldNames(input.options, "option");
|
|
108
|
+
validateOptionNames(input.options);
|
|
109
|
+
validateOptionAliases(input.options);
|
|
110
|
+
}
|
|
73
111
|
const command = {
|
|
74
112
|
description: input.description,
|
|
75
113
|
args: input.args ?? [],
|
|
@@ -92,8 +130,10 @@ function formatExecutionError(error) {
|
|
|
92
130
|
}
|
|
93
131
|
async function executeCommand(command, input = {}) {
|
|
94
132
|
try {
|
|
133
|
+
const options = { ...input.options };
|
|
134
|
+
for (const field of command.options) if (options[field.name] === void 0 && !isSchemaField(field) && field.type === "boolean") options[field.name] = false;
|
|
95
135
|
await command.run({
|
|
96
|
-
options
|
|
136
|
+
options,
|
|
97
137
|
args: input.args ?? {},
|
|
98
138
|
cwd: input.cwd ?? process.cwd(),
|
|
99
139
|
rawArgs: input.rawArgs ?? []
|
|
@@ -389,6 +429,7 @@ async function parseCommand(command, rawArgs) {
|
|
|
389
429
|
const result = await resolveMissingField(field, () => missingRequiredOption(field));
|
|
390
430
|
if (!result.ok) return result;
|
|
391
431
|
if (result.present) parsedOptions[field.name] = result.value;
|
|
432
|
+
else if (!isSchemaField(field) && field.type === "boolean") parsedOptions[field.name] = false;
|
|
392
433
|
}
|
|
393
434
|
return {
|
|
394
435
|
ok: true,
|
|
@@ -81,7 +81,13 @@ declare namespace StandardSchemaV1 {
|
|
|
81
81
|
type PrimitiveFieldType = "string" | "number" | "boolean";
|
|
82
82
|
type PrimitiveFieldValue<TType extends PrimitiveFieldType> = TType extends "string" ? string : TType extends "number" ? number : boolean;
|
|
83
83
|
interface NamedField<TName extends string = string> {
|
|
84
|
-
/**
|
|
84
|
+
/**
|
|
85
|
+
* Identifier used as the key in `ctx.args` / `ctx.options`.
|
|
86
|
+
*
|
|
87
|
+
* For args, any non-empty name is allowed.
|
|
88
|
+
* For options, names must start with a letter and may contain only letters,
|
|
89
|
+
* numbers, and internal hyphens (for example: `dry-run`, `dryRun`, `v2`).
|
|
90
|
+
*/
|
|
85
91
|
readonly name: TName;
|
|
86
92
|
/** One-line help text shown in `--help` output. */
|
|
87
93
|
readonly description?: string | undefined;
|
|
@@ -91,7 +97,8 @@ interface PrimitiveFieldBase<TName extends string, TType extends PrimitiveFieldT
|
|
|
91
97
|
readonly type: TType;
|
|
92
98
|
/**
|
|
93
99
|
* When `true`, the field must be provided by the user.
|
|
94
|
-
* Omitted or `false` makes the field optional
|
|
100
|
+
* Omitted or `false` makes the field optional. Absent fields are `undefined`
|
|
101
|
+
* in `ctx`, except primitive boolean options, which default to `false`.
|
|
95
102
|
*/
|
|
96
103
|
readonly required?: boolean | undefined;
|
|
97
104
|
/** Value used when the user does not provide this field. Makes the field always present in `ctx`. */
|
|
@@ -153,9 +160,13 @@ type FieldInputValue<TField> = TField extends {
|
|
|
153
160
|
type HasDefaultValue<TField> = TField extends {
|
|
154
161
|
readonly default: infer TDefault;
|
|
155
162
|
} ? [TDefault] extends [undefined] ? false : true : false;
|
|
156
|
-
type IsRequiredField<TField> = TField extends {
|
|
163
|
+
type IsRequiredField<TField, TBooleanAlwaysPresent extends boolean = false> = TField extends {
|
|
157
164
|
readonly schema: infer TSchema;
|
|
158
|
-
} ? IsOptionalSchemaOutput<InferSchemaOutput<TSchema>> extends true ? false : true : HasDefaultValue<TField> extends true ? true : TField extends {
|
|
165
|
+
} ? IsOptionalSchemaOutput<InferSchemaOutput<TSchema>> extends true ? false : true : HasDefaultValue<TField> extends true ? true : TBooleanAlwaysPresent extends true ? TField extends {
|
|
166
|
+
readonly type: "boolean";
|
|
167
|
+
} ? true : TField extends {
|
|
168
|
+
readonly required: true;
|
|
169
|
+
} ? true : false : TField extends {
|
|
159
170
|
readonly required: true;
|
|
160
171
|
} ? true : false;
|
|
161
172
|
type IsArgOptional<TField> = TField extends {
|
|
@@ -170,7 +181,7 @@ type ValidateArgOrder<TArgs> = TArgs extends readonly CommandArgField[] ? IsVali
|
|
|
170
181
|
readonly args: never;
|
|
171
182
|
} : unknown : unknown;
|
|
172
183
|
type Simplify<TValue> = { [TKey in keyof TValue]: TValue[TKey] };
|
|
173
|
-
type InferNamedFields<TFields extends readonly NamedField[]> = Simplify<{ [TField in TFields[number] as IsRequiredField<TField> extends true ? FieldName<TField> : never]: FieldValue<TField> } & { [TField in TFields[number] as IsRequiredField<TField> extends true ? never : FieldName<TField>]?: FieldValue<TField> }>;
|
|
184
|
+
type InferNamedFields<TFields extends readonly NamedField[], TBooleanAlwaysPresent extends boolean = false> = Simplify<{ [TField in TFields[number] as IsRequiredField<TField, TBooleanAlwaysPresent> extends true ? FieldName<TField> : never]: FieldValue<TField> } & { [TField in TFields[number] as IsRequiredField<TField, TBooleanAlwaysPresent> extends true ? never : FieldName<TField>]?: FieldValue<TField> }>;
|
|
174
185
|
type InferExecutionFields<TFields extends readonly NamedField[]> = Simplify<{ [TField in TFields[number] as FieldName<TField>]?: FieldInputValue<TField> }>;
|
|
175
186
|
/** Runtime data passed into a command's `run` function. */
|
|
176
187
|
interface CommandContext<TOptions, TArgs> {
|
|
@@ -193,6 +204,7 @@ interface DefineCommandInput<TArgsFields extends readonly CommandArgField[] | un
|
|
|
193
204
|
/**
|
|
194
205
|
* Positional arguments declared in the order they appear on the command line.
|
|
195
206
|
* Required arguments must come before optional ones.
|
|
207
|
+
* Argument names must be non-empty and unique within the command.
|
|
196
208
|
*
|
|
197
209
|
* Each entry is either a primitive field (`{ name, type }`) or a schema
|
|
198
210
|
* field (`{ name, schema }`).
|
|
@@ -200,6 +212,8 @@ interface DefineCommandInput<TArgsFields extends readonly CommandArgField[] | un
|
|
|
200
212
|
readonly args?: TArgsFields;
|
|
201
213
|
/**
|
|
202
214
|
* Options declared as `--name` flags, with optional single-character aliases.
|
|
215
|
+
* Option names must be unique within the command, start with a letter, and
|
|
216
|
+
* contain only letters, numbers, and internal hyphens.
|
|
203
217
|
*
|
|
204
218
|
* Each entry is either a primitive field (`{ name, type }`) or a schema
|
|
205
219
|
* field (`{ name, schema }`).
|
|
@@ -209,13 +223,13 @@ interface DefineCommandInput<TArgsFields extends readonly CommandArgField[] | un
|
|
|
209
223
|
* The function executed when this command is invoked.
|
|
210
224
|
* Receives a {@link CommandContext} with fully parsed `args` and `options`.
|
|
211
225
|
*/
|
|
212
|
-
readonly run: (ctx: CommandContext<InferNamedFields<NormalizeFields<TOptionsFields, CommandOptionField
|
|
226
|
+
readonly run: (ctx: CommandContext<InferNamedFields<NormalizeFields<TOptionsFields, CommandOptionField>, true>, InferNamedFields<NormalizeFields<TArgsFields, CommandArgField>>>) => void | Promise<void>;
|
|
213
227
|
}
|
|
214
228
|
interface DefinedCommand<TArgsFields extends readonly CommandArgField[] = readonly [], TOptionsFields extends readonly CommandOptionField[] = readonly []> {
|
|
215
229
|
readonly description?: string | undefined;
|
|
216
230
|
readonly args: TArgsFields;
|
|
217
231
|
readonly options: TOptionsFields;
|
|
218
|
-
readonly run: (ctx: CommandContext<InferNamedFields<TOptionsFields>, InferNamedFields<TArgsFields>>) => void | Promise<void>;
|
|
232
|
+
readonly run: (ctx: CommandContext<InferNamedFields<TOptionsFields, true>, InferNamedFields<TArgsFields>>) => void | Promise<void>;
|
|
219
233
|
} //#endregion
|
|
220
234
|
//#region src/define-command.d.ts
|
|
221
235
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as ExecuteCommandInput, c as PrimitiveFieldType, d as SchemaOptionField, f as defineCommand, i as DefinedCommand, l as PrimitiveOptionField, n as CommandContext, o as InferExecutionFields, r as CommandOptionField, s as PrimitiveArgField, t as CommandArgField, u as SchemaArgField } from "./index-
|
|
1
|
+
import { a as ExecuteCommandInput, c as PrimitiveFieldType, d as SchemaOptionField, f as defineCommand, i as DefinedCommand, l as PrimitiveOptionField, n as CommandContext, o as InferExecutionFields, r as CommandOptionField, s as PrimitiveArgField, t as CommandArgField, u as SchemaArgField } from "./index-BWxfSwrT.mjs";
|
|
2
2
|
export { type CommandArgField, type CommandContext, type CommandOptionField, type DefinedCommand, type ExecuteCommandInput, type InferExecutionFields, type PrimitiveArgField, type PrimitiveFieldType, type PrimitiveOptionField, type SchemaArgField, type SchemaOptionField, defineCommand };
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as defineCommand } from "./dist-
|
|
1
|
+
import { n as defineCommand } from "./dist-uz53Uv1e.mjs";
|
|
2
2
|
export { defineCommand };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as isSchemaField, i as isDefinedCommand, o as parseCommand, r as executeCommand } from "./dist-
|
|
1
|
+
import { a as isSchemaField, i as isDefinedCommand, o as parseCommand, r as executeCommand } from "./dist-uz53Uv1e.mjs";
|
|
2
2
|
import { pathToFileURL } from "node:url";
|
|
3
3
|
//#region src/cli/flags.ts
|
|
4
4
|
function isHelpFlag(token) {
|
package/dist/runtime.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as DefinedCommand, r as CommandOptionField, t as CommandArgField } from "./index-
|
|
1
|
+
import { i as DefinedCommand, r as CommandOptionField, t as CommandArgField } from "./index-BWxfSwrT.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/manifest/manifest-types.d.ts
|
|
4
4
|
type CommandManifestPath = readonly string[];
|
package/dist/runtime.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import "./dist-
|
|
2
|
-
import { t as runManifestCommand } from "./run-manifest-command-
|
|
1
|
+
import "./dist-uz53Uv1e.mjs";
|
|
2
|
+
import { t as runManifestCommand } from "./run-manifest-command-Dq_lBv-H.mjs";
|
|
3
3
|
export { runManifestCommand };
|
package/dist/test.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as ExecuteCommandInput, i as DefinedCommand, o as InferExecutionFields, r as CommandOptionField, t as CommandArgField } from "./index-
|
|
1
|
+
import { a as ExecuteCommandInput, i as DefinedCommand, o as InferExecutionFields, r as CommandOptionField, t as CommandArgField } from "./index-BWxfSwrT.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/test.d.ts
|
|
4
4
|
type RunCommandOptions<TOptions, TArgs> = ExecuteCommandInput<TOptions, TArgs>;
|
package/dist/test.mjs
CHANGED
package/package.json
CHANGED