@vercube/cli 0.0.47 ā 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/dist/Flag-qtOTYeqz.mjs +136 -0
- package/dist/index.mjs +519 -8
- package/dist/toolkit.d.mts +135 -0
- package/dist/toolkit.mjs +2 -0
- package/package.json +12 -7
- package/dist/build-BjzKMqLM.mjs +0 -19
- package/dist/dev-FNtcz-vW.mjs +0 -16
- package/dist/fetch-UyiACOy-.mjs +0 -60
- package/dist/init-BHbW8wC8.mjs +0 -181
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
&labelColor=%23000&color=%232f2f2f>)
|
|
13
13
|
&labelColor=%23000&color=%232f2f2f>)
|
|
14
14
|
|
|
15
|
-
**Dev server, production builds, all from the command line. `vercube dev` to start, `vercube build` when you're ready to ship.**
|
|
15
|
+
**Dev server, production builds, custom commands - all from the command line. `vercube dev` to start, `vercube build` when you're ready to ship.**
|
|
16
16
|
|
|
17
17
|
[Website](https://vercube.dev) ⢠[Documentation](https://vercube.dev/docs/getting-started)
|
|
18
18
|
|
|
@@ -22,6 +22,10 @@
|
|
|
22
22
|
|
|
23
23
|
- **Dev server** - hot-reload out of the box
|
|
24
24
|
- **Production build** - optimized bundles ready for deployment
|
|
25
|
+
- **Project scaffolding** - `vercube init` to create a new project from the starter template
|
|
26
|
+
- **Endpoint testing** - `vercube fetch /path` to test endpoints without a running server
|
|
27
|
+
- **Custom commands** - define your own commands with `@Command`, `@Arg`, `@Flag` decorators
|
|
28
|
+
- **Dependency injection** - commands integrate with `@vercube/di` for service injection
|
|
25
29
|
- **Config loading** - reads `vercube.config.ts` automatically
|
|
26
30
|
|
|
27
31
|
## š¦ Installation
|
|
@@ -30,6 +34,26 @@
|
|
|
30
34
|
pnpm add @vercube/cli
|
|
31
35
|
```
|
|
32
36
|
|
|
37
|
+
### Custom commands
|
|
38
|
+
|
|
39
|
+
Import from `@vercube/cli/toolkit` and register in `vercube.config.ts`:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { BaseCommand, Command, Flag } from '@vercube/cli/toolkit';
|
|
43
|
+
|
|
44
|
+
@Command({ name: 'deploy', description: 'Deploy to production' })
|
|
45
|
+
export class DeployCommand extends BaseCommand {
|
|
46
|
+
@Flag({ name: 'env', description: 'Target environment', default: 'staging' })
|
|
47
|
+
public env: string;
|
|
48
|
+
|
|
49
|
+
public override async run(): Promise<void> {
|
|
50
|
+
console.log(`Deploying to ${this.env}...`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
See the [Custom CLI Command](https://vercube.dev/docs/advanced/custom-cli-command) docs for the full API.
|
|
56
|
+
|
|
33
57
|
## š License
|
|
34
58
|
|
|
35
59
|
[MIT](https://github.com/vercube/vercube/blob/main/LICENSE)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
//#region src/BaseCommand.ts
|
|
2
|
+
/**
|
|
3
|
+
* Base class for all CLI commands.
|
|
4
|
+
*
|
|
5
|
+
* Extend this class and decorate with `@Command` to register a command.
|
|
6
|
+
* Dependencies can be injected via `@Inject` from `@vercube/di`.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* @Command({ name: 'deploy', description: 'Deploy application' })
|
|
11
|
+
* export class DeployCommand extends BaseCommand {
|
|
12
|
+
* @Inject(MyService)
|
|
13
|
+
* private readonly gMyService!: MyService;
|
|
14
|
+
*
|
|
15
|
+
* public override async run(): Promise<void> {
|
|
16
|
+
* await this.gMyService.deploy();
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
var BaseCommand = class {
|
|
22
|
+
/**
|
|
23
|
+
* CLI DI container, injected by CommandRegistry before `run()`.
|
|
24
|
+
* Prefer `@Inject` decorators over accessing this directly.
|
|
25
|
+
*/
|
|
26
|
+
container;
|
|
27
|
+
};
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region src/Decorators/Arg.ts
|
|
30
|
+
const COMMAND_ARGS_KEY = "__commandArgs";
|
|
31
|
+
/**
|
|
32
|
+
* Property decorator for positional CLI arguments.
|
|
33
|
+
* The value is injected from parsed CLI input before `run()` is called.
|
|
34
|
+
*
|
|
35
|
+
* @param options - argument configuration
|
|
36
|
+
* @returns property decorator
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* @Arg({ name: 'query', description: 'Phrase to search for' })
|
|
41
|
+
* public query: string;
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
function Arg(options) {
|
|
45
|
+
return (target, propertyKey) => {
|
|
46
|
+
if (!target["__commandArgs"]) target[COMMAND_ARGS_KEY] = [];
|
|
47
|
+
const def = {
|
|
48
|
+
kind: "positional",
|
|
49
|
+
property: propertyKey,
|
|
50
|
+
name: options.name,
|
|
51
|
+
description: options.description,
|
|
52
|
+
required: options.required
|
|
53
|
+
};
|
|
54
|
+
target[COMMAND_ARGS_KEY].push(def);
|
|
55
|
+
Object.defineProperty(target, propertyKey, {
|
|
56
|
+
configurable: true,
|
|
57
|
+
enumerable: true,
|
|
58
|
+
writable: true,
|
|
59
|
+
value: void 0
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/Decorators/Command.ts
|
|
65
|
+
const COMMAND_META_KEY = "__commandMeta";
|
|
66
|
+
/**
|
|
67
|
+
* Class decorator that marks a class as a CLI command.
|
|
68
|
+
* Stores command metadata on the prototype so `CommandRegistry` can discover it.
|
|
69
|
+
*
|
|
70
|
+
* @param meta - command configuration (name, description, optional subcommands)
|
|
71
|
+
* @returns class decorator
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* @Command({ name: 'build', description: 'Build the project' })
|
|
76
|
+
* export class BuildCommand extends BaseCommand { ... }
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
function Command(meta) {
|
|
80
|
+
return (target) => {
|
|
81
|
+
target.prototype[COMMAND_META_KEY] = meta;
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/Decorators/Flag.ts
|
|
86
|
+
/**
|
|
87
|
+
* Property decorator for named CLI flags (`--name value`).
|
|
88
|
+
* The value type is inferred from `default` when `type` is not set.
|
|
89
|
+
* The parsed value is injected before `run()` is called.
|
|
90
|
+
*
|
|
91
|
+
* @param options - flag configuration
|
|
92
|
+
* @returns property decorator
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* @Flag({ name: 'limit', description: 'Max results', default: 10 })
|
|
97
|
+
* public limit: number;
|
|
98
|
+
*
|
|
99
|
+
* @Flag({ name: 'json', description: 'Output as JSON', default: false })
|
|
100
|
+
* public json: boolean;
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
function Flag(options) {
|
|
104
|
+
return (target, propertyKey) => {
|
|
105
|
+
if (!target["__commandArgs"]) target[COMMAND_ARGS_KEY] = [];
|
|
106
|
+
const def = {
|
|
107
|
+
kind: "flag",
|
|
108
|
+
property: propertyKey,
|
|
109
|
+
name: options.name,
|
|
110
|
+
description: options.description,
|
|
111
|
+
default: options.default,
|
|
112
|
+
required: options.required,
|
|
113
|
+
valueType: options.type ?? inferType(options.default)
|
|
114
|
+
};
|
|
115
|
+
target[COMMAND_ARGS_KEY].push(def);
|
|
116
|
+
Object.defineProperty(target, propertyKey, {
|
|
117
|
+
configurable: true,
|
|
118
|
+
enumerable: true,
|
|
119
|
+
writable: true,
|
|
120
|
+
value: options.default
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Infers the citty arg type from a default value.
|
|
126
|
+
*
|
|
127
|
+
* @param value - default value to inspect
|
|
128
|
+
* @returns corresponding citty arg type string
|
|
129
|
+
*/
|
|
130
|
+
function inferType(value) {
|
|
131
|
+
if (typeof value === "boolean") return "boolean";
|
|
132
|
+
if (typeof value === "number") return "number";
|
|
133
|
+
return "string";
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { COMMAND_ARGS_KEY as a, Arg as i, COMMAND_META_KEY as n, BaseCommand as o, Command as r, Flag as t };
|
package/dist/index.mjs
CHANGED
|
@@ -1,19 +1,530 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { i as Arg, n as COMMAND_META_KEY, o as BaseCommand, r as Command, t as Flag } from "./Flag-qtOTYeqz.mjs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
2
4
|
import { defineCommand, runMain } from "citty";
|
|
5
|
+
import { Container } from "@vercube/di";
|
|
6
|
+
import { BaseLogger, Logger } from "@vercube/logger";
|
|
7
|
+
import { dirname, resolve } from "node:path";
|
|
8
|
+
import { loadVercubeConfig } from "@vercube/core";
|
|
9
|
+
import { createJiti } from "jiti";
|
|
10
|
+
import { build, createDevServer, createVercube, watch } from "@vercube/devkit";
|
|
11
|
+
import { cliFetch } from "srvx/cli";
|
|
12
|
+
import { existsSync } from "node:fs";
|
|
13
|
+
import { consola } from "consola";
|
|
14
|
+
import { colors } from "consola/utils";
|
|
15
|
+
import { downloadTemplate, startShell } from "giget";
|
|
16
|
+
import { installDependencies } from "nypm";
|
|
17
|
+
import { relative, resolve as resolve$1 } from "pathe";
|
|
18
|
+
import { hasTTY } from "std-env";
|
|
19
|
+
import { x } from "tinyexec";
|
|
20
|
+
//#region package.json
|
|
21
|
+
var version = "1.0.0-beta.2";
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/Utils/CommandUtils.ts
|
|
24
|
+
/**
|
|
25
|
+
* Reads `@Command` metadata from a class prototype.
|
|
26
|
+
*
|
|
27
|
+
* @param CommandClass - command class constructor to inspect
|
|
28
|
+
* @returns command metadata stored by the `@Command` decorator
|
|
29
|
+
* @throws if the class is not decorated with `@Command`
|
|
30
|
+
*/
|
|
31
|
+
function getCommandMeta(CommandClass) {
|
|
32
|
+
const meta = CommandClass.prototype[COMMAND_META_KEY];
|
|
33
|
+
if (!meta) throw new Error(`[CommandRegistry] Class "${CommandClass.name}" is missing the @Command decorator.`);
|
|
34
|
+
return meta;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Reads all `@Arg` / `@Flag` definitions from a class prototype.
|
|
38
|
+
*
|
|
39
|
+
* @param CommandClass - command class constructor to inspect
|
|
40
|
+
* @returns array of arg/flag definitions, or `[]` if none exist
|
|
41
|
+
*/
|
|
42
|
+
function getArgDefs(CommandClass) {
|
|
43
|
+
return CommandClass.prototype["__commandArgs"] ?? [];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Converts `ArgDef` entries into a citty-compatible args record.
|
|
47
|
+
*
|
|
48
|
+
* @param defs - arg/flag definitions to convert
|
|
49
|
+
* @returns record of citty argument descriptors keyed by name
|
|
50
|
+
*/
|
|
51
|
+
function buildCittyArgs(defs) {
|
|
52
|
+
const args = {};
|
|
53
|
+
for (const def of defs) if (def.kind === "positional") args[def.name] = {
|
|
54
|
+
type: "positional",
|
|
55
|
+
description: def.description,
|
|
56
|
+
required: def.required
|
|
57
|
+
};
|
|
58
|
+
else args[def.name] = {
|
|
59
|
+
type: def.valueType === "boolean" ? "boolean" : "string",
|
|
60
|
+
description: def.description,
|
|
61
|
+
default: def.valueType === "number" ? String(def.default ?? "") : def.default,
|
|
62
|
+
required: def.required
|
|
63
|
+
};
|
|
64
|
+
return args;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Injects parsed citty arg values into command instance properties
|
|
68
|
+
* using the mappings defined by `@Arg` / `@Flag` decorators.
|
|
69
|
+
* Handles `number` coercion for flags with `valueType: 'number'`.
|
|
70
|
+
*
|
|
71
|
+
* @param instance - command instance to inject into
|
|
72
|
+
* @param parsedArgs - parsed arg values from citty
|
|
73
|
+
* @param defs - arg/flag definitions describing the property mapping
|
|
74
|
+
*/
|
|
75
|
+
function injectArgs(instance, parsedArgs, defs) {
|
|
76
|
+
for (const def of defs) if (def.name in parsedArgs) {
|
|
77
|
+
const raw = parsedArgs[def.name];
|
|
78
|
+
instance[def.property] = def.valueType === "number" && typeof raw === "string" ? Number(raw) : raw;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/CommandRegistry.ts
|
|
83
|
+
/**
|
|
84
|
+
* Registry that stores command classes and transforms them into citty CommandDefs.
|
|
85
|
+
* Both built-in and user-defined commands are registered here before the CLI runs.
|
|
86
|
+
*/
|
|
87
|
+
var CommandRegistry = class {
|
|
88
|
+
fCommands = /* @__PURE__ */ new Map();
|
|
89
|
+
/**
|
|
90
|
+
* Registers a command class decorated with `@Command`.
|
|
91
|
+
*
|
|
92
|
+
* @param CommandClass - class to register
|
|
93
|
+
* @throws if the class is missing the `@Command` decorator
|
|
94
|
+
*/
|
|
95
|
+
register(CommandClass) {
|
|
96
|
+
const meta = getCommandMeta(CommandClass);
|
|
97
|
+
this.fCommands.set(meta.name, CommandClass);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Converts a single command class into a citty `CommandDef`.
|
|
101
|
+
* Recursively processes subcommands defined in `@Command({ subCommands })`.
|
|
102
|
+
*
|
|
103
|
+
* @param CommandClass - command class to convert
|
|
104
|
+
* @param container - CLI DI container used to resolve instances
|
|
105
|
+
* @returns citty CommandDef ready to pass to `defineCommand` / `runMain`
|
|
106
|
+
*/
|
|
107
|
+
toCommandDef(CommandClass, container) {
|
|
108
|
+
const meta = getCommandMeta(CommandClass);
|
|
109
|
+
const argDefs = getArgDefs(CommandClass);
|
|
110
|
+
const subCommands = {};
|
|
111
|
+
if (meta.subCommands) for (const SubCmd of meta.subCommands) {
|
|
112
|
+
const subMeta = getCommandMeta(SubCmd);
|
|
113
|
+
subCommands[subMeta.name] = () => this.toCommandDef(SubCmd, container);
|
|
114
|
+
}
|
|
115
|
+
return defineCommand({
|
|
116
|
+
meta: {
|
|
117
|
+
name: meta.name,
|
|
118
|
+
description: meta.description
|
|
119
|
+
},
|
|
120
|
+
args: buildCittyArgs(argDefs),
|
|
121
|
+
subCommands: Object.keys(subCommands).length > 0 ? subCommands : void 0,
|
|
122
|
+
run: async (ctx) => {
|
|
123
|
+
const instance = container.resolve(CommandClass);
|
|
124
|
+
instance.container = container;
|
|
125
|
+
injectArgs(instance, ctx.args, argDefs);
|
|
126
|
+
await instance.run();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Builds the full citty subcommands map from all registered commands.
|
|
132
|
+
*
|
|
133
|
+
* @param container - CLI DI container used when executing commands
|
|
134
|
+
* @returns record mapping command names to lazy `CommandDef` factories
|
|
135
|
+
*/
|
|
136
|
+
buildCittyTree(container) {
|
|
137
|
+
const tree = {};
|
|
138
|
+
for (const CommandClass of this.fCommands.values()) {
|
|
139
|
+
const meta = getCommandMeta(CommandClass);
|
|
140
|
+
tree[meta.name] = () => this.toCommandDef(CommandClass, container);
|
|
141
|
+
}
|
|
142
|
+
return tree;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
//#endregion
|
|
146
|
+
//#region src/CliContainer.ts
|
|
147
|
+
/**
|
|
148
|
+
* Creates and configures a dedicated DI container for the CLI.
|
|
149
|
+
* Separate from the application runtime container.
|
|
150
|
+
* Pre-configured with an evlog-backed Logger.
|
|
151
|
+
*
|
|
152
|
+
* @returns configured CLI container
|
|
153
|
+
*/
|
|
154
|
+
function createCliContainer() {
|
|
155
|
+
const container = new Container({ context: "cli" });
|
|
156
|
+
container.bind(Logger, BaseLogger);
|
|
157
|
+
container.get(Logger).configure({ logLevel: "info" });
|
|
158
|
+
container.bind(CommandRegistry);
|
|
159
|
+
container.flushQueue();
|
|
160
|
+
return container;
|
|
161
|
+
}
|
|
162
|
+
//#endregion
|
|
163
|
+
//#region src/CommandLoader.ts
|
|
164
|
+
/** @internal */
|
|
165
|
+
const _require = createRequire(import.meta.url);
|
|
166
|
+
/**
|
|
167
|
+
* Babel (used by jiti) emits `_initializerWarningHelper` for decorated properties
|
|
168
|
+
* without an explicit initializer - a function that always throws.
|
|
169
|
+
* Our decorators (`@Arg`, `@Flag`, `@Inject`) already define the property via
|
|
170
|
+
* `Object.defineProperty`, so the guard is unnecessary. We patch it out with a no-op.
|
|
171
|
+
*
|
|
172
|
+
* @see https://github.com/babel/babel/issues/12672
|
|
173
|
+
*/
|
|
174
|
+
const INIT_WARNING_HELPER_RE = /function _initializerWarningHelper\b[^{]*\{[^}]*\}/g;
|
|
175
|
+
/**
|
|
176
|
+
* jiti's bundled Babel transform, resolved via jiti's package.json because
|
|
177
|
+
* `jiti/dist/babel.cjs` is not listed in the package exports map.
|
|
178
|
+
*/
|
|
179
|
+
const babelTransform = _require(resolve(dirname(_require.resolve("jiti/package.json")), "dist/babel.cjs"));
|
|
180
|
+
/**
|
|
181
|
+
* Custom jiti instance with a patched Babel transform that replaces
|
|
182
|
+
* `_initializerWarningHelper` with a no-op so user command classes
|
|
183
|
+
* don't need `!` or explicit default values on decorated properties.
|
|
184
|
+
*/
|
|
185
|
+
const jiti = createJiti(import.meta.url, {
|
|
186
|
+
fsCache: false,
|
|
187
|
+
moduleCache: false,
|
|
188
|
+
transform(opts) {
|
|
189
|
+
return { code: babelTransform(opts).code.replace(INIT_WARNING_HELPER_RE, "function _initializerWarningHelper(){return void 0}") };
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
/**
|
|
193
|
+
* Loads user-defined command classes from `vercube.config.ts` in the given directory.
|
|
194
|
+
* Delegates file loading to the patched jiti instance so decorated properties
|
|
195
|
+
* work without `!` or explicit initializers.
|
|
196
|
+
*
|
|
197
|
+
* Returns an empty array when:
|
|
198
|
+
* - `vercube.config.ts` does not exist in `cwd`
|
|
199
|
+
* - the config file has no `cli.commands` and no plugin registered commands
|
|
200
|
+
*
|
|
201
|
+
* @param cwd - directory to look for `vercube.config.ts` in (typically `process.cwd()`)
|
|
202
|
+
* @returns array of command class constructors, or `[]` if none found
|
|
203
|
+
*/
|
|
204
|
+
async function loadUserCommands(cwd) {
|
|
205
|
+
try {
|
|
206
|
+
return (await loadVercubeConfig(void 0, {
|
|
207
|
+
cwd,
|
|
208
|
+
import: (id) => jiti.import(id)
|
|
209
|
+
})).cli?.commands ?? [];
|
|
210
|
+
} catch {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
//#endregion
|
|
215
|
+
//#region \0@oxc-project+runtime@0.134.0/helpers/esm/decorate.js
|
|
216
|
+
function __decorate(decorators, target, key, desc) {
|
|
217
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
218
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
219
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
220
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/Commands/Build.ts
|
|
224
|
+
let BuildCommand = class BuildCommand extends BaseCommand {
|
|
225
|
+
/** Custom entry file path. Uses default from vercube.config.ts when omitted. */
|
|
226
|
+
entry;
|
|
227
|
+
/**
|
|
228
|
+
* @returns resolves when the build is done
|
|
229
|
+
*/
|
|
230
|
+
async run() {
|
|
231
|
+
await build(await createVercube({ build: { entry: this.entry } }));
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
__decorate([Flag({
|
|
235
|
+
name: "entry",
|
|
236
|
+
description: "Entry file",
|
|
237
|
+
type: "string"
|
|
238
|
+
})], BuildCommand.prototype, "entry", void 0);
|
|
239
|
+
BuildCommand = __decorate([Command({
|
|
240
|
+
name: "build",
|
|
241
|
+
description: "Build the project"
|
|
242
|
+
})], BuildCommand);
|
|
243
|
+
//#endregion
|
|
244
|
+
//#region src/Commands/Dev.ts
|
|
245
|
+
let DevCommand = class DevCommand extends BaseCommand {
|
|
246
|
+
/**
|
|
247
|
+
* @returns resolves when the watcher is ready
|
|
248
|
+
*/
|
|
249
|
+
async run() {
|
|
250
|
+
const app = await createVercube();
|
|
251
|
+
createDevServer(app);
|
|
252
|
+
await watch(app);
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
DevCommand = __decorate([Command({
|
|
256
|
+
name: "dev",
|
|
257
|
+
description: "Start development server"
|
|
258
|
+
})], DevCommand);
|
|
259
|
+
//#endregion
|
|
260
|
+
//#region src/Commands/Fetch.ts
|
|
261
|
+
let FetchCommand = class FetchCommand extends BaseCommand {
|
|
262
|
+
/** Target URL path, e.g. `/api/users`. */
|
|
263
|
+
url;
|
|
264
|
+
/** Entry file relative to the output directory. */
|
|
265
|
+
entry;
|
|
266
|
+
/** HTTP method. */
|
|
267
|
+
method;
|
|
268
|
+
/** Request headers as `"Name: Value, Name: Value"`. */
|
|
269
|
+
headers;
|
|
270
|
+
/** Request body. `@-` reads from stdin, `@filename` reads from a file. */
|
|
271
|
+
data;
|
|
272
|
+
/** Print request and response headers alongside the body. */
|
|
273
|
+
verbose;
|
|
274
|
+
/**
|
|
275
|
+
* @returns resolves when the response has been printed
|
|
276
|
+
*/
|
|
277
|
+
async run() {
|
|
278
|
+
const app = await createVercube({ build: { dts: false } });
|
|
279
|
+
await build(app);
|
|
280
|
+
await cliFetch({
|
|
281
|
+
verbose: this.verbose,
|
|
282
|
+
dir: app.config.build?.output?.dir ?? "dist",
|
|
283
|
+
entry: this.entry,
|
|
284
|
+
url: this.url,
|
|
285
|
+
method: this.method,
|
|
286
|
+
header: this.headers?.split(",") ?? [],
|
|
287
|
+
data: this.data
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
__decorate([Arg({
|
|
292
|
+
name: "url",
|
|
293
|
+
description: "URL to fetch"
|
|
294
|
+
})], FetchCommand.prototype, "url", void 0);
|
|
295
|
+
__decorate([Flag({
|
|
296
|
+
name: "entry",
|
|
297
|
+
description: "Entry point for the application",
|
|
298
|
+
default: "index.mjs"
|
|
299
|
+
})], FetchCommand.prototype, "entry", void 0);
|
|
300
|
+
__decorate([Flag({
|
|
301
|
+
name: "method",
|
|
302
|
+
description: "HTTP method",
|
|
303
|
+
default: "GET"
|
|
304
|
+
})], FetchCommand.prototype, "method", void 0);
|
|
305
|
+
__decorate([Flag({
|
|
306
|
+
name: "headers",
|
|
307
|
+
description: "Add header (format: \"Name: Value, ...\")",
|
|
308
|
+
type: "string"
|
|
309
|
+
})], FetchCommand.prototype, "headers", void 0);
|
|
310
|
+
__decorate([Flag({
|
|
311
|
+
name: "data",
|
|
312
|
+
description: "Request body (use @- for stdin, @file for file)",
|
|
313
|
+
type: "string"
|
|
314
|
+
})], FetchCommand.prototype, "data", void 0);
|
|
315
|
+
__decorate([Flag({
|
|
316
|
+
name: "verbose",
|
|
317
|
+
description: "Show request and response headers",
|
|
318
|
+
default: false
|
|
319
|
+
})], FetchCommand.prototype, "verbose", void 0);
|
|
320
|
+
FetchCommand = __decorate([Command({
|
|
321
|
+
name: "fetch",
|
|
322
|
+
description: "Fetch a request from the application"
|
|
323
|
+
})], FetchCommand);
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region src/Utils/Logo.ts
|
|
326
|
+
const startColor = {
|
|
327
|
+
r: 149,
|
|
328
|
+
g: 100,
|
|
329
|
+
b: 245
|
|
330
|
+
};
|
|
331
|
+
const endColor = {
|
|
332
|
+
r: 111,
|
|
333
|
+
g: 114,
|
|
334
|
+
b: 245
|
|
335
|
+
};
|
|
336
|
+
const icon = [
|
|
337
|
+
" _ ",
|
|
338
|
+
" | | ",
|
|
339
|
+
" __ _____ _ __ ___ _ _| |__ ___ ",
|
|
340
|
+
" \\ \\ / / _ \\ '__/ __| | | | '_ \\ / _ \\",
|
|
341
|
+
String.raw` \ V / __/ | | (__| |_| | |_) | __/`,
|
|
342
|
+
String.raw` \_/ \___|_| \___|\__,_|_.__/ \___|`,
|
|
343
|
+
" ",
|
|
344
|
+
" "
|
|
345
|
+
];
|
|
346
|
+
function interpolateColor(startColor, endColor, factor) {
|
|
347
|
+
return `\u001B[38;2;${Math.round(startColor.r + factor * (endColor.r - startColor.r))};${Math.round(startColor.g + factor * (endColor.g - startColor.g))};${Math.round(startColor.b + factor * (endColor.b - startColor.b))}m`;
|
|
348
|
+
}
|
|
349
|
+
function applyGradient(icon, startColor, endColor) {
|
|
350
|
+
const totalLines = icon.length;
|
|
351
|
+
return icon.map((line, index) => {
|
|
352
|
+
return interpolateColor(startColor, endColor, index / (totalLines - 1)) + line;
|
|
353
|
+
}).join("\n");
|
|
354
|
+
}
|
|
355
|
+
const vercubeIcon = applyGradient(icon, startColor, endColor);
|
|
356
|
+
//#endregion
|
|
357
|
+
//#region src/Commands/Init.ts
|
|
358
|
+
const logger = consola.withTag(colors.whiteBright(colors.bold(colors.bgGreenBright(" vercube "))));
|
|
359
|
+
const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/vercube/starter/main/templates";
|
|
360
|
+
const DEFAULT_TEMPLATE_NAME = "vercube";
|
|
361
|
+
const packageManagerOptions = Object.keys({
|
|
362
|
+
npm: void 0,
|
|
363
|
+
pnpm: void 0,
|
|
364
|
+
yarn: void 0,
|
|
365
|
+
bun: void 0,
|
|
366
|
+
deno: void 0,
|
|
367
|
+
aube: void 0
|
|
368
|
+
});
|
|
369
|
+
let InitCommand = class InitCommand extends BaseCommand {
|
|
370
|
+
/** Target directory. Prompted interactively when omitted. */
|
|
371
|
+
dir;
|
|
372
|
+
/** Overwrite existing directory without prompting. */
|
|
373
|
+
force;
|
|
374
|
+
/** Set to `false` to skip dependency installation. */
|
|
375
|
+
install;
|
|
376
|
+
/** Run `git init` in the new project directory. */
|
|
377
|
+
gitInit;
|
|
378
|
+
/** Package manager for dependency installation. */
|
|
379
|
+
packageManager;
|
|
380
|
+
/** Open an interactive shell in the project directory after scaffolding. */
|
|
381
|
+
shell;
|
|
382
|
+
/**
|
|
383
|
+
* @returns resolves when scaffolding and setup are complete
|
|
384
|
+
*/
|
|
385
|
+
async run() {
|
|
386
|
+
if (hasTTY) process.stdout.write(`\n${vercubeIcon}\n\n`);
|
|
387
|
+
consola.info(`Welcome to ${colors.bold("Vercube")}!`);
|
|
388
|
+
let dir = this.dir ?? "";
|
|
389
|
+
if (!dir) dir = await logger.prompt("Where would you like to create your project?", {
|
|
390
|
+
placeholder: "./vercube-app",
|
|
391
|
+
type: "text",
|
|
392
|
+
default: "vercube-app",
|
|
393
|
+
cancel: "reject"
|
|
394
|
+
}).catch(() => process.exit(1));
|
|
395
|
+
const cwd = resolve$1(process.cwd());
|
|
396
|
+
let templateDownloadPath = resolve$1(cwd, dir);
|
|
397
|
+
logger.info(`Creating a new project in ${colors.cyan(relative(cwd, templateDownloadPath) || templateDownloadPath)}.`);
|
|
398
|
+
let shouldForce = Boolean(this.force);
|
|
399
|
+
if (!shouldForce && existsSync(templateDownloadPath)) switch (await logger.prompt(`The directory ${colors.cyan(templateDownloadPath)} already exists. What would you like to do?`, {
|
|
400
|
+
type: "select",
|
|
401
|
+
options: [
|
|
402
|
+
"Override its contents",
|
|
403
|
+
"Select different directory",
|
|
404
|
+
"Abort"
|
|
405
|
+
]
|
|
406
|
+
})) {
|
|
407
|
+
case "Override its contents":
|
|
408
|
+
shouldForce = true;
|
|
409
|
+
break;
|
|
410
|
+
case "Select different directory":
|
|
411
|
+
templateDownloadPath = resolve$1(cwd, await logger.prompt("Please specify a different directory:", {
|
|
412
|
+
type: "text",
|
|
413
|
+
cancel: "reject"
|
|
414
|
+
}).catch(() => process.exit(1)));
|
|
415
|
+
break;
|
|
416
|
+
default: process.exit(1);
|
|
417
|
+
}
|
|
418
|
+
let template;
|
|
419
|
+
try {
|
|
420
|
+
template = await downloadTemplate(DEFAULT_TEMPLATE_NAME, {
|
|
421
|
+
dir: templateDownloadPath,
|
|
422
|
+
force: shouldForce,
|
|
423
|
+
registry: DEFAULT_REGISTRY
|
|
424
|
+
});
|
|
425
|
+
} catch (error) {
|
|
426
|
+
if (process.env.DEBUG) throw error;
|
|
427
|
+
logger.error(error.toString());
|
|
428
|
+
process.exit(1);
|
|
429
|
+
}
|
|
430
|
+
const packageManagerArg = this.packageManager;
|
|
431
|
+
const selectedPackageManager = packageManagerOptions.includes(packageManagerArg) ? packageManagerArg : await logger.prompt("Which package manager would you like to use?", {
|
|
432
|
+
type: "select",
|
|
433
|
+
options: packageManagerOptions,
|
|
434
|
+
cancel: "reject"
|
|
435
|
+
}).catch(() => process.exit(1));
|
|
436
|
+
if (this.install === false) logger.info("Skipping install dependencies step.");
|
|
437
|
+
else {
|
|
438
|
+
logger.start("Installing dependencies...");
|
|
439
|
+
try {
|
|
440
|
+
await installDependencies({
|
|
441
|
+
cwd: template.dir,
|
|
442
|
+
packageManager: {
|
|
443
|
+
name: selectedPackageManager,
|
|
444
|
+
command: selectedPackageManager
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
} catch (error) {
|
|
448
|
+
if (process.env.DEBUG) throw error;
|
|
449
|
+
logger.error(error.toString());
|
|
450
|
+
process.exit(1);
|
|
451
|
+
}
|
|
452
|
+
logger.success("Installation completed.");
|
|
453
|
+
}
|
|
454
|
+
let gitInit = this.gitInit;
|
|
455
|
+
if (gitInit === void 0) gitInit = await logger.prompt("Initialize git repository?", {
|
|
456
|
+
type: "confirm",
|
|
457
|
+
cancel: "reject"
|
|
458
|
+
}).catch(() => process.exit(1));
|
|
459
|
+
if (gitInit) {
|
|
460
|
+
logger.info("Initializing git repository...\n");
|
|
461
|
+
try {
|
|
462
|
+
await x("git", ["init", template.dir], {
|
|
463
|
+
throwOnError: true,
|
|
464
|
+
nodeOptions: { stdio: "inherit" }
|
|
465
|
+
});
|
|
466
|
+
} catch (error) {
|
|
467
|
+
logger.warn(`Failed to initialize git repository: ${error}`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
logger.log("\n⨠Vercube project has been created! Next steps:");
|
|
471
|
+
const relativeTemplateDir = relative(process.cwd(), template.dir) || ".";
|
|
472
|
+
const runCmd = selectedPackageManager === "deno" ? "task" : "run";
|
|
473
|
+
const nextSteps = [!this.shell && relativeTemplateDir.length > 1 && `\`cd ${relativeTemplateDir}\``, `Start development server with \`${selectedPackageManager} ${runCmd} dev\``].filter(Boolean);
|
|
474
|
+
for (const step of nextSteps) logger.log(` āŗ ${step}`);
|
|
475
|
+
if (this.shell) startShell(template.dir);
|
|
476
|
+
}
|
|
477
|
+
};
|
|
478
|
+
__decorate([Arg({
|
|
479
|
+
name: "dir",
|
|
480
|
+
description: "Project directory"
|
|
481
|
+
})], InitCommand.prototype, "dir", void 0);
|
|
482
|
+
__decorate([Flag({
|
|
483
|
+
name: "force",
|
|
484
|
+
description: "Override existing directory",
|
|
485
|
+
default: false
|
|
486
|
+
})], InitCommand.prototype, "force", void 0);
|
|
487
|
+
__decorate([Flag({
|
|
488
|
+
name: "install",
|
|
489
|
+
description: "Install dependencies",
|
|
490
|
+
default: true
|
|
491
|
+
})], InitCommand.prototype, "install", void 0);
|
|
492
|
+
__decorate([Flag({
|
|
493
|
+
name: "gitInit",
|
|
494
|
+
description: "Initialize git repository",
|
|
495
|
+
default: true
|
|
496
|
+
})], InitCommand.prototype, "gitInit", void 0);
|
|
497
|
+
__decorate([Flag({
|
|
498
|
+
name: "packageManager",
|
|
499
|
+
description: "Package manager choice (npm, pnpm, yarn, bun)",
|
|
500
|
+
default: "pnpm"
|
|
501
|
+
})], InitCommand.prototype, "packageManager", void 0);
|
|
502
|
+
__decorate([Flag({
|
|
503
|
+
name: "shell",
|
|
504
|
+
description: "Open shell in project directory",
|
|
505
|
+
default: false
|
|
506
|
+
})], InitCommand.prototype, "shell", void 0);
|
|
507
|
+
InitCommand = __decorate([Command({
|
|
508
|
+
name: "init",
|
|
509
|
+
description: "Initialize a new Vercube app"
|
|
510
|
+
})], InitCommand);
|
|
3
511
|
//#endregion
|
|
4
512
|
//#region src/index.ts
|
|
513
|
+
const container = createCliContainer();
|
|
514
|
+
const registry = container.resolve(CommandRegistry);
|
|
515
|
+
registry.register(BuildCommand);
|
|
516
|
+
registry.register(DevCommand);
|
|
517
|
+
registry.register(InitCommand);
|
|
518
|
+
registry.register(FetchCommand);
|
|
519
|
+
const userCommands = await loadUserCommands(process.cwd());
|
|
520
|
+
for (const UserCommand of userCommands) registry.register(UserCommand);
|
|
5
521
|
runMain(defineCommand({
|
|
6
522
|
meta: {
|
|
7
|
-
name: "
|
|
8
|
-
version
|
|
523
|
+
name: "vercube",
|
|
524
|
+
version,
|
|
9
525
|
description: "Vercube CLI"
|
|
10
526
|
},
|
|
11
|
-
subCommands:
|
|
12
|
-
build: () => import("./build-BjzKMqLM.mjs").then(({ buildCommand }) => buildCommand),
|
|
13
|
-
dev: () => import("./dev-FNtcz-vW.mjs").then(({ devCommand }) => devCommand),
|
|
14
|
-
init: () => import("./init-BHbW8wC8.mjs").then(({ initCommand }) => initCommand),
|
|
15
|
-
fetch: () => import("./fetch-UyiACOy-.mjs").then(({ fetchCommand }) => fetchCommand)
|
|
16
|
-
}
|
|
527
|
+
subCommands: registry.buildCittyTree(container)
|
|
17
528
|
}));
|
|
18
529
|
//#endregion
|
|
19
530
|
export {};
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { Container } from "@vercube/di";
|
|
2
|
+
|
|
3
|
+
//#region src/BaseCommand.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Base class for all CLI commands.
|
|
6
|
+
*
|
|
7
|
+
* Extend this class and decorate with `@Command` to register a command.
|
|
8
|
+
* Dependencies can be injected via `@Inject` from `@vercube/di`.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* @Command({ name: 'deploy', description: 'Deploy application' })
|
|
13
|
+
* export class DeployCommand extends BaseCommand {
|
|
14
|
+
* @Inject(MyService)
|
|
15
|
+
* private readonly gMyService!: MyService;
|
|
16
|
+
*
|
|
17
|
+
* public override async run(): Promise<void> {
|
|
18
|
+
* await this.gMyService.deploy();
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
declare abstract class BaseCommand {
|
|
24
|
+
/**
|
|
25
|
+
* CLI DI container, injected by CommandRegistry before `run()`.
|
|
26
|
+
* Prefer `@Inject` decorators over accessing this directly.
|
|
27
|
+
*/
|
|
28
|
+
protected container: Container;
|
|
29
|
+
/**
|
|
30
|
+
* Execute the command logic. Called after arg/flag injection and DI resolution.
|
|
31
|
+
* @returns promise that resolves when the command is done
|
|
32
|
+
*/
|
|
33
|
+
abstract run(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/Types/CliTypes.d.ts
|
|
37
|
+
declare namespace CliTypes {
|
|
38
|
+
/**
|
|
39
|
+
* Metadata stored by the `@Command` decorator on a class prototype.
|
|
40
|
+
*/
|
|
41
|
+
interface CommandMeta {
|
|
42
|
+
/** Command name used on the CLI (`vercube <name>`). */
|
|
43
|
+
name: string;
|
|
44
|
+
/** Short description shown in `--help`. */
|
|
45
|
+
description: string;
|
|
46
|
+
/** Optional child command classes. */
|
|
47
|
+
subCommands?: (new () => unknown)[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Single arg/flag definition stored by `@Arg` / `@Flag` decorators.
|
|
51
|
+
*/
|
|
52
|
+
interface ArgDef {
|
|
53
|
+
/** Whether this is a positional arg or a named flag. */
|
|
54
|
+
kind: 'positional' | 'flag';
|
|
55
|
+
/** Property name on the command class instance. */
|
|
56
|
+
property: string;
|
|
57
|
+
/** Name used in the CLI (citty arg key). */
|
|
58
|
+
name: string;
|
|
59
|
+
/** Short description shown in `--help`. */
|
|
60
|
+
description?: string;
|
|
61
|
+
/** Default value. */
|
|
62
|
+
default?: unknown;
|
|
63
|
+
/** Whether the arg/flag is required. */
|
|
64
|
+
required?: boolean;
|
|
65
|
+
/** For flags: the value type used by citty. */
|
|
66
|
+
valueType?: 'string' | 'boolean' | 'number';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
//#endregion
|
|
70
|
+
//#region src/Decorators/Command.d.ts
|
|
71
|
+
/**
|
|
72
|
+
* Class decorator that marks a class as a CLI command.
|
|
73
|
+
* Stores command metadata on the prototype so `CommandRegistry` can discover it.
|
|
74
|
+
*
|
|
75
|
+
* @param meta - command configuration (name, description, optional subcommands)
|
|
76
|
+
* @returns class decorator
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```ts
|
|
80
|
+
* @Command({ name: 'build', description: 'Build the project' })
|
|
81
|
+
* export class BuildCommand extends BaseCommand { ... }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
declare function Command(meta: CliTypes.CommandMeta): Function;
|
|
85
|
+
//#endregion
|
|
86
|
+
//#region src/Decorators/Arg.d.ts
|
|
87
|
+
interface ArgOptions {
|
|
88
|
+
name: string;
|
|
89
|
+
description?: string;
|
|
90
|
+
required?: boolean;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Property decorator for positional CLI arguments.
|
|
94
|
+
* The value is injected from parsed CLI input before `run()` is called.
|
|
95
|
+
*
|
|
96
|
+
* @param options - argument configuration
|
|
97
|
+
* @returns property decorator
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* @Arg({ name: 'query', description: 'Phrase to search for' })
|
|
102
|
+
* public query: string;
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
declare function Arg(options: ArgOptions): Function;
|
|
106
|
+
//#endregion
|
|
107
|
+
//#region src/Decorators/Flag.d.ts
|
|
108
|
+
interface FlagOptions {
|
|
109
|
+
name: string;
|
|
110
|
+
description?: string;
|
|
111
|
+
default?: unknown;
|
|
112
|
+
required?: boolean;
|
|
113
|
+
/** Explicit citty value type. Inferred from `default` when omitted. */
|
|
114
|
+
type?: 'string' | 'boolean' | 'number';
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Property decorator for named CLI flags (`--name value`).
|
|
118
|
+
* The value type is inferred from `default` when `type` is not set.
|
|
119
|
+
* The parsed value is injected before `run()` is called.
|
|
120
|
+
*
|
|
121
|
+
* @param options - flag configuration
|
|
122
|
+
* @returns property decorator
|
|
123
|
+
*
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* @Flag({ name: 'limit', description: 'Max results', default: 10 })
|
|
127
|
+
* public limit: number;
|
|
128
|
+
*
|
|
129
|
+
* @Flag({ name: 'json', description: 'Output as JSON', default: false })
|
|
130
|
+
* public json: boolean;
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
declare function Flag(options: FlagOptions): Function;
|
|
134
|
+
//#endregion
|
|
135
|
+
export { Arg, BaseCommand, type CliTypes, Command, Flag };
|
package/dist/toolkit.mjs
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercube/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
4
|
"description": "CLI module for Vercube framework",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"module": "./dist/index.mjs",
|
|
15
15
|
"exports": {
|
|
16
16
|
".": "./dist/index.mjs",
|
|
17
|
+
"./toolkit": "./dist/toolkit.mjs",
|
|
17
18
|
"./package.json": "./package.json"
|
|
18
19
|
},
|
|
19
20
|
"types": "./dist/index.d.mts",
|
|
@@ -25,21 +26,25 @@
|
|
|
25
26
|
"vercube": "./dist/index.mjs"
|
|
26
27
|
},
|
|
27
28
|
"dependencies": {
|
|
29
|
+
"c12": "4.0.0-beta.5",
|
|
28
30
|
"citty": "0.2.2",
|
|
29
31
|
"consola": "3.4.2",
|
|
30
|
-
"giget": "3.
|
|
31
|
-
"
|
|
32
|
+
"giget": "3.3.0",
|
|
33
|
+
"jiti": "2.7.0",
|
|
34
|
+
"nypm": "0.6.7",
|
|
32
35
|
"pathe": "2.0.3",
|
|
33
36
|
"srvx": "0.11.16",
|
|
34
37
|
"std-env": "4.1.0",
|
|
35
|
-
"tinyexec": "1.2.
|
|
36
|
-
"@vercube/
|
|
37
|
-
"@vercube/
|
|
38
|
+
"tinyexec": "1.2.4",
|
|
39
|
+
"@vercube/core": "1.0.0-beta.2",
|
|
40
|
+
"@vercube/di": "1.0.0-beta.2",
|
|
41
|
+
"@vercube/logger": "1.0.0-beta.2",
|
|
42
|
+
"@vercube/devkit": "1.0.0-beta.2"
|
|
38
43
|
},
|
|
39
44
|
"publishConfig": {
|
|
40
45
|
"access": "public"
|
|
41
46
|
},
|
|
42
47
|
"scripts": {
|
|
43
|
-
"build": "tsdown --config
|
|
48
|
+
"build": "tsdown --config tsdown.config.ts --config-loader=unrun"
|
|
44
49
|
}
|
|
45
50
|
}
|
package/dist/build-BjzKMqLM.mjs
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { defineCommand } from "citty";
|
|
2
|
-
import { build, createVercube } from "@vercube/devkit";
|
|
3
|
-
//#region src/commands/build.ts
|
|
4
|
-
const buildCommand = defineCommand({
|
|
5
|
-
meta: {
|
|
6
|
-
name: "build",
|
|
7
|
-
description: "Build the project"
|
|
8
|
-
},
|
|
9
|
-
args: { entry: {
|
|
10
|
-
type: "string",
|
|
11
|
-
description: "Entry file",
|
|
12
|
-
default: void 0
|
|
13
|
-
} },
|
|
14
|
-
run: async (ctx) => {
|
|
15
|
-
await build(await createVercube({ build: { entry: ctx?.args?.entry ?? void 0 } }));
|
|
16
|
-
}
|
|
17
|
-
});
|
|
18
|
-
//#endregion
|
|
19
|
-
export { buildCommand };
|
package/dist/dev-FNtcz-vW.mjs
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { defineCommand } from "citty";
|
|
2
|
-
import { createDevServer, createVercube, watch } from "@vercube/devkit";
|
|
3
|
-
//#region src/commands/dev.ts
|
|
4
|
-
const devCommand = defineCommand({
|
|
5
|
-
meta: {
|
|
6
|
-
name: "dev",
|
|
7
|
-
description: "Start development server"
|
|
8
|
-
},
|
|
9
|
-
async run() {
|
|
10
|
-
const app = await createVercube();
|
|
11
|
-
createDevServer(app);
|
|
12
|
-
await watch(app);
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
//#endregion
|
|
16
|
-
export { devCommand };
|
package/dist/fetch-UyiACOy-.mjs
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { defineCommand } from "citty";
|
|
2
|
-
import { build, createVercube } from "@vercube/devkit";
|
|
3
|
-
import { cliFetch } from "srvx/cli";
|
|
4
|
-
//#region src/commands/fetch.ts
|
|
5
|
-
const fetchCommand = defineCommand({
|
|
6
|
-
meta: {
|
|
7
|
-
name: "fetch",
|
|
8
|
-
description: "Fetch a request from the application"
|
|
9
|
-
},
|
|
10
|
-
args: {
|
|
11
|
-
url: {
|
|
12
|
-
type: "positional",
|
|
13
|
-
description: "URL to fetch",
|
|
14
|
-
default: "/"
|
|
15
|
-
},
|
|
16
|
-
entry: {
|
|
17
|
-
type: "string",
|
|
18
|
-
description: "Entry point for the application",
|
|
19
|
-
default: "index.mjs"
|
|
20
|
-
},
|
|
21
|
-
method: {
|
|
22
|
-
type: "string",
|
|
23
|
-
description: "HTTP method (default: GET, or POST if body is provided)",
|
|
24
|
-
default: "GET",
|
|
25
|
-
alias: "X",
|
|
26
|
-
valueHint: "GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS"
|
|
27
|
-
},
|
|
28
|
-
headers: {
|
|
29
|
-
type: "string",
|
|
30
|
-
description: "Add header (format: \"Name: Value, Name: Value, ...\")",
|
|
31
|
-
alias: "H"
|
|
32
|
-
},
|
|
33
|
-
data: {
|
|
34
|
-
type: "string",
|
|
35
|
-
description: "Request body (use @- for stdin, @file for file)",
|
|
36
|
-
alias: "d"
|
|
37
|
-
},
|
|
38
|
-
verbose: {
|
|
39
|
-
type: "boolean",
|
|
40
|
-
description: "Show request and response headers",
|
|
41
|
-
alias: "v",
|
|
42
|
-
default: false
|
|
43
|
-
}
|
|
44
|
-
},
|
|
45
|
-
async run(ctx) {
|
|
46
|
-
const app = await createVercube({ build: { dts: false } });
|
|
47
|
-
await build(app);
|
|
48
|
-
await cliFetch({
|
|
49
|
-
verbose: ctx.args.verbose,
|
|
50
|
-
dir: app.config.build?.output?.dir ?? "dist",
|
|
51
|
-
entry: ctx.args.entry,
|
|
52
|
-
url: ctx.args.url,
|
|
53
|
-
method: ctx.args.method,
|
|
54
|
-
header: ctx.args.headers?.split(",") ?? [],
|
|
55
|
-
data: ctx.args.data
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
//#endregion
|
|
60
|
-
export { fetchCommand };
|
package/dist/init-BHbW8wC8.mjs
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
import { defineCommand } from "citty";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { consola } from "consola";
|
|
4
|
-
import { colors } from "consola/utils";
|
|
5
|
-
import { downloadTemplate, startShell } from "giget";
|
|
6
|
-
import { installDependencies } from "nypm";
|
|
7
|
-
import { relative, resolve } from "pathe";
|
|
8
|
-
import { hasTTY } from "std-env";
|
|
9
|
-
import { x } from "tinyexec";
|
|
10
|
-
//#region src/utils/logo.ts
|
|
11
|
-
const startColor = {
|
|
12
|
-
r: 149,
|
|
13
|
-
g: 100,
|
|
14
|
-
b: 245
|
|
15
|
-
};
|
|
16
|
-
const endColor = {
|
|
17
|
-
r: 111,
|
|
18
|
-
g: 114,
|
|
19
|
-
b: 245
|
|
20
|
-
};
|
|
21
|
-
const icon = [
|
|
22
|
-
" _ ",
|
|
23
|
-
" | | ",
|
|
24
|
-
" __ _____ _ __ ___ _ _| |__ ___ ",
|
|
25
|
-
" \\ \\ / / _ \\ '__/ __| | | | '_ \\ / _ \\",
|
|
26
|
-
String.raw` \ V / __/ | | (__| |_| | |_) | __/`,
|
|
27
|
-
String.raw` \_/ \___|_| \___|\__,_|_.__/ \___|`,
|
|
28
|
-
" ",
|
|
29
|
-
" "
|
|
30
|
-
];
|
|
31
|
-
function interpolateColor(startColor, endColor, factor) {
|
|
32
|
-
return `\u001B[38;2;${Math.round(startColor.r + factor * (endColor.r - startColor.r))};${Math.round(startColor.g + factor * (endColor.g - startColor.g))};${Math.round(startColor.b + factor * (endColor.b - startColor.b))}m`;
|
|
33
|
-
}
|
|
34
|
-
function applyGradient(icon, startColor, endColor) {
|
|
35
|
-
const totalLines = icon.length;
|
|
36
|
-
return icon.map((line, index) => {
|
|
37
|
-
return interpolateColor(startColor, endColor, index / (totalLines - 1)) + line;
|
|
38
|
-
}).join("\n");
|
|
39
|
-
}
|
|
40
|
-
const vercubeIcon = applyGradient(icon, startColor, endColor);
|
|
41
|
-
//#endregion
|
|
42
|
-
//#region src/commands/init.ts
|
|
43
|
-
const logger = consola.withTag(colors.whiteBright(colors.bold(colors.bgGreenBright(" vercube "))));
|
|
44
|
-
const DEFAULT_REGISTRY = "https://raw.githubusercontent.com/vercube/starter/main/templates";
|
|
45
|
-
const DEFAULT_TEMPLATE_NAME = "vercube";
|
|
46
|
-
const packageManagerOptions = Object.keys({
|
|
47
|
-
npm: void 0,
|
|
48
|
-
pnpm: void 0,
|
|
49
|
-
yarn: void 0,
|
|
50
|
-
bun: void 0,
|
|
51
|
-
deno: void 0
|
|
52
|
-
});
|
|
53
|
-
const initCommand = defineCommand({
|
|
54
|
-
meta: {
|
|
55
|
-
name: "init",
|
|
56
|
-
description: "Initialize a new Vercube app"
|
|
57
|
-
},
|
|
58
|
-
args: {
|
|
59
|
-
dir: {
|
|
60
|
-
type: "positional",
|
|
61
|
-
description: "Project directory",
|
|
62
|
-
default: ""
|
|
63
|
-
},
|
|
64
|
-
force: {
|
|
65
|
-
type: "boolean",
|
|
66
|
-
alias: "f",
|
|
67
|
-
description: "Override existing directory"
|
|
68
|
-
},
|
|
69
|
-
install: {
|
|
70
|
-
type: "boolean",
|
|
71
|
-
default: true,
|
|
72
|
-
description: "Skip installing dependencies"
|
|
73
|
-
},
|
|
74
|
-
gitInit: {
|
|
75
|
-
type: "boolean",
|
|
76
|
-
description: "Initialize git repository",
|
|
77
|
-
default: true
|
|
78
|
-
},
|
|
79
|
-
packageManager: {
|
|
80
|
-
type: "string",
|
|
81
|
-
description: "Package manager choice (npm, pnpm, yarn, bun)",
|
|
82
|
-
default: "pnpm"
|
|
83
|
-
}
|
|
84
|
-
},
|
|
85
|
-
async run(ctx) {
|
|
86
|
-
if (hasTTY) process.stdout.write(`\n${vercubeIcon}\n\n`);
|
|
87
|
-
consola.info(`Welcome to ${colors.bold("Vercube")}!`);
|
|
88
|
-
let dir = ctx.args.dir;
|
|
89
|
-
if (ctx.args.dir === "") dir = await logger.prompt("Where would you like to create your project?", {
|
|
90
|
-
placeholder: "./vercube-app",
|
|
91
|
-
type: "text",
|
|
92
|
-
default: "vercube-app",
|
|
93
|
-
cancel: "reject"
|
|
94
|
-
}).catch(() => process.exit(1));
|
|
95
|
-
const cwd = resolve(process.cwd());
|
|
96
|
-
let templateDownloadPath = resolve(cwd, dir);
|
|
97
|
-
logger.info(`Creating a new project in ${colors.cyan(relative(cwd, templateDownloadPath) || templateDownloadPath)}.`);
|
|
98
|
-
let shouldForce = Boolean(ctx.args.force);
|
|
99
|
-
if (!shouldForce && existsSync(templateDownloadPath)) switch (await logger.prompt(`The directory ${colors.cyan(templateDownloadPath)} already exists. What would you like to do?`, {
|
|
100
|
-
type: "select",
|
|
101
|
-
options: [
|
|
102
|
-
"Override its contents",
|
|
103
|
-
"Select different directory",
|
|
104
|
-
"Abort"
|
|
105
|
-
]
|
|
106
|
-
})) {
|
|
107
|
-
case "Override its contents":
|
|
108
|
-
shouldForce = true;
|
|
109
|
-
break;
|
|
110
|
-
case "Select different directory":
|
|
111
|
-
templateDownloadPath = resolve(cwd, await logger.prompt("Please specify a different directory:", {
|
|
112
|
-
type: "text",
|
|
113
|
-
cancel: "reject"
|
|
114
|
-
}).catch(() => process.exit(1)));
|
|
115
|
-
break;
|
|
116
|
-
default: process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
let template;
|
|
119
|
-
try {
|
|
120
|
-
template = await downloadTemplate(DEFAULT_TEMPLATE_NAME, {
|
|
121
|
-
dir: templateDownloadPath,
|
|
122
|
-
force: shouldForce,
|
|
123
|
-
offline: Boolean(ctx.args.offline),
|
|
124
|
-
preferOffline: Boolean(ctx.args.preferOffline),
|
|
125
|
-
registry: DEFAULT_REGISTRY
|
|
126
|
-
});
|
|
127
|
-
} catch (error) {
|
|
128
|
-
if (process.env.DEBUG) throw error;
|
|
129
|
-
logger.error(error.toString());
|
|
130
|
-
process.exit(1);
|
|
131
|
-
}
|
|
132
|
-
const packageManagerArg = ctx.args.packageManager;
|
|
133
|
-
const selectedPackageManager = packageManagerOptions.includes(packageManagerArg) ? packageManagerArg : await logger.prompt("Which package manager would you like to use?", {
|
|
134
|
-
type: "select",
|
|
135
|
-
options: packageManagerOptions,
|
|
136
|
-
cancel: "reject"
|
|
137
|
-
}).catch(() => process.exit(1));
|
|
138
|
-
if (ctx.args.install === false) logger.info("Skipping install dependencies step.");
|
|
139
|
-
else {
|
|
140
|
-
logger.start("Installing dependencies...");
|
|
141
|
-
try {
|
|
142
|
-
await installDependencies({
|
|
143
|
-
cwd: template.dir,
|
|
144
|
-
packageManager: {
|
|
145
|
-
name: selectedPackageManager,
|
|
146
|
-
command: selectedPackageManager
|
|
147
|
-
}
|
|
148
|
-
});
|
|
149
|
-
} catch (error) {
|
|
150
|
-
if (process.env.DEBUG) throw error;
|
|
151
|
-
logger.error(error.toString());
|
|
152
|
-
process.exit(1);
|
|
153
|
-
}
|
|
154
|
-
logger.success("Installation completed.");
|
|
155
|
-
}
|
|
156
|
-
let gitInit = ctx.args.gitInit;
|
|
157
|
-
if (gitInit === void 0) gitInit = await logger.prompt("Initialize git repository?", {
|
|
158
|
-
type: "confirm",
|
|
159
|
-
cancel: "reject"
|
|
160
|
-
}).catch(() => process.exit(1));
|
|
161
|
-
if (ctx.args.gitInit) {
|
|
162
|
-
logger.info("Initializing git repository...\n");
|
|
163
|
-
try {
|
|
164
|
-
await x("git", ["init", template.dir], {
|
|
165
|
-
throwOnError: true,
|
|
166
|
-
nodeOptions: { stdio: "inherit" }
|
|
167
|
-
});
|
|
168
|
-
} catch (error) {
|
|
169
|
-
logger.warn(`Failed to initialize git repository: ${error}`);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
logger.log("\n⨠Vercube project has been created! Next steps:");
|
|
173
|
-
const relativeTemplateDir = relative(process.cwd(), template.dir) || ".";
|
|
174
|
-
const runCmd = selectedPackageManager === "deno" ? "task" : "run";
|
|
175
|
-
const nextSteps = [!ctx.args.shell && relativeTemplateDir.length > 1 && `\`cd ${relativeTemplateDir}\``, `Start development server with \`${selectedPackageManager} ${runCmd} dev\``].filter(Boolean);
|
|
176
|
-
for (const step of nextSteps) logger.log(` āŗ ${step}`);
|
|
177
|
-
if (ctx.args.shell) startShell(template.dir);
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
//#endregion
|
|
181
|
-
export { initCommand };
|