@reliverse/rempts-core 1.6.1 → 2.3.1
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 +398 -102
- package/dist/cli.d.ts +32 -0
- package/dist/cli.js +731 -0
- package/dist/config-loader.d.ts +42 -0
- package/dist/config-loader.js +20 -0
- package/dist/config.d.ts +99 -0
- package/dist/config.js +188 -0
- package/dist/file-loader.d.ts +43 -0
- package/dist/file-loader.js +199 -0
- package/dist/global-flags.d.ts +36 -0
- package/dist/global-flags.js +36 -0
- package/dist/mod.d.ts +13 -0
- package/dist/mod.js +19 -0
- package/dist/parser.d.ts +6 -0
- package/dist/parser.js +137 -0
- package/dist/plugin/context.d.ts +13 -0
- package/dist/plugin/context.js +53 -0
- package/dist/plugin/create.d.ts +92 -0
- package/dist/plugin/create.js +61 -0
- package/dist/plugin/loader.d.ts +12 -0
- package/dist/plugin/loader.js +65 -0
- package/dist/plugin/manager.d.ts +53 -0
- package/dist/plugin/manager.js +135 -0
- package/dist/plugin/mod.d.ts +10 -0
- package/dist/plugin/mod.js +27 -0
- package/dist/plugin/store.d.ts +45 -0
- package/dist/plugin/store.js +60 -0
- package/dist/plugin/testing.d.ts +38 -0
- package/dist/plugin/testing.js +175 -0
- package/dist/plugin/types.d.ts +146 -0
- package/dist/tui/registry.d.ts +8 -0
- package/dist/tui/registry.js +10 -0
- package/dist/tui/types.d.ts +58 -0
- package/dist/tui/types.js +10 -0
- package/dist/types.d.ts +178 -0
- package/dist/types.js +25 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.js +27 -0
- package/dist/utils/merge.d.ts +13 -0
- package/dist/utils/merge.js +25 -0
- package/dist/utils/mod.d.ts +6 -0
- package/dist/utils/mod.js +2 -0
- package/dist/utils/type-helpers.d.ts +41 -0
- package/dist/utils/type-helpers.js +0 -0
- package/dist/validation.d.ts +30 -0
- package/dist/validation.js +121 -0
- package/package.json +47 -44
- package/src/cli.ts +1049 -0
- package/src/config-loader.ts +71 -0
- package/src/config.ts +270 -0
- package/src/file-loader.ts +346 -0
- package/src/global-flags.ts +50 -0
- package/src/mod.ts +74 -0
- package/src/parser.ts +212 -0
- package/src/plugin/context.ts +88 -0
- package/src/plugin/create.ts +174 -0
- package/src/plugin/loader.ts +111 -0
- package/src/plugin/manager.ts +244 -0
- package/src/plugin/mod.ts +51 -0
- package/src/plugin/store.ts +124 -0
- package/src/plugin/testing.ts +236 -0
- package/src/plugin/types.ts +206 -0
- package/src/tui/registry.ts +22 -0
- package/src/tui/types.ts +79 -0
- package/src/types.ts +285 -0
- package/src/utils/logger.ts +43 -0
- package/src/utils/merge.ts +54 -0
- package/src/utils/mod.ts +7 -0
- package/src/utils/type-helpers.ts +151 -0
- package/src/validation.ts +177 -0
- package/LICENSE +0 -21
- package/bin/core-impl/anykey/anykey-mod.d.ts +0 -12
- package/bin/core-impl/anykey/anykey-mod.js +0 -125
- package/bin/core-impl/date/date.d.ts +0 -2
- package/bin/core-impl/date/date.js +0 -236
- package/bin/core-impl/editor/editor-mod.d.ts +0 -25
- package/bin/core-impl/editor/editor-mod.js +0 -896
- package/bin/core-impl/figures/figures-mod.d.ts +0 -233
- package/bin/core-impl/figures/figures-mod.js +0 -286
- package/bin/core-impl/figures/figures.test.d.ts +0 -1
- package/bin/core-impl/figures/figures.test.js +0 -474
- package/bin/core-impl/input/confirm-prompt.d.ts +0 -5
- package/bin/core-impl/input/confirm-prompt.js +0 -173
- package/bin/core-impl/input/input-prompt.d.ts +0 -16
- package/bin/core-impl/input/input-prompt.js +0 -370
- package/bin/core-impl/launcher/_parser.d.ts +0 -2
- package/bin/core-impl/launcher/_parser.js +0 -122
- package/bin/core-impl/launcher/_utils.d.ts +0 -8
- package/bin/core-impl/launcher/_utils.js +0 -29
- package/bin/core-impl/launcher/args.d.ts +0 -3
- package/bin/core-impl/launcher/args.js +0 -89
- package/bin/core-impl/launcher/command.d.ts +0 -8
- package/bin/core-impl/launcher/command.js +0 -68
- package/bin/core-impl/launcher/launcher-mod.d.ts +0 -8
- package/bin/core-impl/launcher/launcher-mod.js +0 -34
- package/bin/core-impl/launcher/usage.d.ts +0 -3
- package/bin/core-impl/launcher/usage.js +0 -104
- package/bin/core-impl/msg-fmt/colors.d.ts +0 -30
- package/bin/core-impl/msg-fmt/colors.js +0 -42
- package/bin/core-impl/msg-fmt/logger.d.ts +0 -17
- package/bin/core-impl/msg-fmt/logger.js +0 -106
- package/bin/core-impl/msg-fmt/mapping.d.ts +0 -3
- package/bin/core-impl/msg-fmt/mapping.js +0 -49
- package/bin/core-impl/msg-fmt/messages.d.ts +0 -35
- package/bin/core-impl/msg-fmt/messages.js +0 -314
- package/bin/core-impl/msg-fmt/terminal.d.ts +0 -15
- package/bin/core-impl/msg-fmt/terminal.js +0 -59
- package/bin/core-impl/msg-fmt/variants.d.ts +0 -11
- package/bin/core-impl/msg-fmt/variants.js +0 -52
- package/bin/core-impl/next-steps/next-steps.d.ts +0 -14
- package/bin/core-impl/next-steps/next-steps.js +0 -24
- package/bin/core-impl/number/number-mod.d.ts +0 -28
- package/bin/core-impl/number/number-mod.js +0 -197
- package/bin/core-impl/results/results.d.ts +0 -7
- package/bin/core-impl/results/results.js +0 -27
- package/bin/core-impl/select/multiselect-prompt.d.ts +0 -2
- package/bin/core-impl/select/multiselect-prompt.js +0 -341
- package/bin/core-impl/select/nummultiselect-prompt.d.ts +0 -6
- package/bin/core-impl/select/nummultiselect-prompt.js +0 -105
- package/bin/core-impl/select/numselect-prompt.d.ts +0 -7
- package/bin/core-impl/select/numselect-prompt.js +0 -115
- package/bin/core-impl/select/select-prompt.d.ts +0 -33
- package/bin/core-impl/select/select-prompt.js +0 -302
- package/bin/core-impl/select/toggle-prompt.d.ts +0 -5
- package/bin/core-impl/select/toggle-prompt.js +0 -208
- package/bin/core-impl/st-end/end.d.ts +0 -2
- package/bin/core-impl/st-end/end.js +0 -42
- package/bin/core-impl/st-end/start.d.ts +0 -17
- package/bin/core-impl/st-end/start.js +0 -66
- package/bin/core-impl/task/progress.d.ts +0 -2
- package/bin/core-impl/task/progress.js +0 -57
- package/bin/core-impl/task/spinner.d.ts +0 -15
- package/bin/core-impl/task/spinner.js +0 -110
- package/bin/core-impl/utils/colorize.d.ts +0 -2
- package/bin/core-impl/utils/colorize.js +0 -134
- package/bin/core-impl/utils/errors.d.ts +0 -1
- package/bin/core-impl/utils/errors.js +0 -15
- package/bin/core-impl/utils/prevent.d.ts +0 -10
- package/bin/core-impl/utils/prevent.js +0 -69
- package/bin/core-impl/utils/prompt-end.d.ts +0 -8
- package/bin/core-impl/utils/prompt-end.js +0 -33
- package/bin/core-impl/utils/stream-text.d.ts +0 -18
- package/bin/core-impl/utils/stream-text.js +0 -136
- package/bin/core-impl/utils/system.d.ts +0 -6
- package/bin/core-impl/utils/system.js +0 -7
- package/bin/core-impl/utils/validate.d.ts +0 -22
- package/bin/core-impl/utils/validate.js +0 -17
- package/bin/core-impl/visual/animate/animate.d.ts +0 -14
- package/bin/core-impl/visual/animate/animate.js +0 -64
- package/bin/core-impl/visual/ascii-art/ascii-art.d.ts +0 -6
- package/bin/core-impl/visual/ascii-art/ascii-art.js +0 -12
- package/bin/core-types.d.ts +0 -434
- package/bin/main.d.ts +0 -41
- package/bin/main.js +0 -96
- /package/{bin/core-types.js → dist/plugin/types.js} +0 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
2
|
+
import type { GLOBAL_FLAGS } from "./global-flags.js";
|
|
3
|
+
export type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
4
|
+
export type RenderResult = unknown;
|
|
5
|
+
export interface TuiRenderOptions {
|
|
6
|
+
exitOnCtrlC?: boolean;
|
|
7
|
+
targetFps?: number;
|
|
8
|
+
enableMouseMovement?: boolean;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
export interface RenderArgs<TFlags = Record<string, unknown>, TStore = {}> extends HandlerArgs<TFlags, TStore> {
|
|
12
|
+
command: Command<any, TStore>;
|
|
13
|
+
rendererOptions?: TuiRenderOptions;
|
|
14
|
+
}
|
|
15
|
+
export type RenderFunction<TFlags = Record<string, unknown>, TStore = {}> = (args: RenderArgs<TFlags, TStore>) => RenderResult;
|
|
16
|
+
/**
|
|
17
|
+
* CLI instance with plugin type information
|
|
18
|
+
*/
|
|
19
|
+
export interface CLI<TStore = {}> {
|
|
20
|
+
/**
|
|
21
|
+
* Initialize the CLI (load config, etc)
|
|
22
|
+
*/
|
|
23
|
+
init(): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Run the CLI with given arguments
|
|
26
|
+
*/
|
|
27
|
+
run(argv?: string[]): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Execute a command programmatically
|
|
30
|
+
*/
|
|
31
|
+
execute(commandName: string, args?: string[]): Promise<void>;
|
|
32
|
+
execute<T extends keyof RegisteredCommands>(commandName: T, options: CommandOptions<T>): Promise<void>;
|
|
33
|
+
execute<T extends keyof RegisteredCommands>(commandName: T, args: string[], options: CommandOptions<T>): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Add a global before hook that runs before command execution
|
|
36
|
+
* This provides a simple API for setup/initialization tasks
|
|
37
|
+
*/
|
|
38
|
+
before(hook: BeforeHook<TStore>): void;
|
|
39
|
+
/**
|
|
40
|
+
* Add a global after hook that runs after command execution
|
|
41
|
+
*/
|
|
42
|
+
after(hook: AfterHook<TStore>): void;
|
|
43
|
+
}
|
|
44
|
+
interface BaseCommand<TOptions extends Options = Options, TStore = {}, TName extends string = string> {
|
|
45
|
+
description: string;
|
|
46
|
+
options?: TOptions;
|
|
47
|
+
alias?: string | string[];
|
|
48
|
+
handler?: Handler<InferOptions<TOptions>, TStore, TName>;
|
|
49
|
+
render?: RenderFunction<InferOptions<TOptions>, TStore>;
|
|
50
|
+
}
|
|
51
|
+
export type Command<TOptions extends Options = Options, TStore = {}, TName extends string = string> = (BaseCommand<TOptions, TStore, TName> & {
|
|
52
|
+
handler: Handler<InferOptions<TOptions>, TStore, TName>;
|
|
53
|
+
}) | (BaseCommand<TOptions, TStore, TName> & {
|
|
54
|
+
render: RenderFunction<InferOptions<TOptions>, TStore>;
|
|
55
|
+
}) | (BaseCommand<TOptions, TStore, TName> & {
|
|
56
|
+
handler: Handler<InferOptions<TOptions>, TStore, TName>;
|
|
57
|
+
render: RenderFunction<InferOptions<TOptions>, TStore>;
|
|
58
|
+
}) | (BaseCommand<TOptions, TStore, TName> & {
|
|
59
|
+
handler?: never;
|
|
60
|
+
render?: never;
|
|
61
|
+
});
|
|
62
|
+
type InferSchema<T> = T extends StandardSchemaV1<any, infer Out> ? Out : never;
|
|
63
|
+
export type InferOptions<T extends Options> = {
|
|
64
|
+
[K in keyof T]: T[K] extends CLIOption<infer S> ? InferSchema<S> : never;
|
|
65
|
+
};
|
|
66
|
+
export type MergedOptions<TOptions extends Options> = typeof GLOBAL_FLAGS & TOptions;
|
|
67
|
+
export type InferMergedOptions<TOptions extends Options> = InferOptions<MergedOptions<TOptions>>;
|
|
68
|
+
export type Handler<TFlags = Record<string, unknown>, TStore = {}, TCommandName extends string = string> = (args: HandlerArgs<TFlags, TStore, TCommandName>) => void | Promise<void>;
|
|
69
|
+
export interface HandlerArgs<TFlags = Record<string, unknown>, TStore = {}, TCommandName extends string = string> {
|
|
70
|
+
flags: TFlags;
|
|
71
|
+
positional: string[];
|
|
72
|
+
shell: typeof Bun.$;
|
|
73
|
+
env: typeof process.env;
|
|
74
|
+
cwd: string;
|
|
75
|
+
prompt: typeof import("@reliverse/rempts-utils").prompt;
|
|
76
|
+
spinner: typeof import("@reliverse/rempts-utils").spinner;
|
|
77
|
+
colors: typeof import("@reliverse/relico").relico;
|
|
78
|
+
context?: import("./plugin/types.js.js").CommandContext<any>;
|
|
79
|
+
hooks?: Record<string, any>;
|
|
80
|
+
terminal: TerminalInfo;
|
|
81
|
+
runtime: RuntimeInfo;
|
|
82
|
+
}
|
|
83
|
+
export interface TerminalInfo {
|
|
84
|
+
width: number;
|
|
85
|
+
height: number;
|
|
86
|
+
isInteractive: boolean;
|
|
87
|
+
isCI: boolean;
|
|
88
|
+
supportsColor: boolean;
|
|
89
|
+
supportsMouse: boolean;
|
|
90
|
+
}
|
|
91
|
+
export interface RuntimeInfo {
|
|
92
|
+
startTime: number;
|
|
93
|
+
args: string[];
|
|
94
|
+
command: string;
|
|
95
|
+
}
|
|
96
|
+
export interface CLIOption<S extends StandardSchemaV1 = StandardSchemaV1> {
|
|
97
|
+
schema: S;
|
|
98
|
+
short?: string;
|
|
99
|
+
description?: string;
|
|
100
|
+
default?: unknown;
|
|
101
|
+
}
|
|
102
|
+
export type Options = Record<string, CLIOption<any>>;
|
|
103
|
+
export declare function defineCommand<TOptions extends Options = Options, TStore = {}>(command: Command<TOptions, TStore>): Command<TOptions, TStore>;
|
|
104
|
+
import type { RemptsConfig } from "./config.js";
|
|
105
|
+
export type { RemptsConfig } from "./config.js";
|
|
106
|
+
export { remptsConfigSchema } from "./config.js";
|
|
107
|
+
export type PluginConfig = import("./plugin/types.js.js").PluginConfig;
|
|
108
|
+
export type RegisteredCommands = Record<string, Command<any, any, any>>;
|
|
109
|
+
/**
|
|
110
|
+
* Get command options type from registered commands
|
|
111
|
+
* Uses Standard Schema's InferOutput to extract types from schemas
|
|
112
|
+
*/
|
|
113
|
+
export type CommandOptions<T extends keyof RegisteredCommands> = RegisteredCommands[T] extends Command<infer TOptions, any, any> ? InferOptions<TOptions> : never;
|
|
114
|
+
export type CommandFlags<TCommand extends Command<any, any, any>> = TCommand extends Command<infer TOptions, any, any> ? InferOptions<TOptions> : never;
|
|
115
|
+
/**
|
|
116
|
+
* Get all registered command names
|
|
117
|
+
*/
|
|
118
|
+
export type RegisteredCommandNames = keyof RegisteredCommands;
|
|
119
|
+
export type ResolvedConfig = Required<Omit<RemptsConfig, "build" | "dev" | "test" | "workspace" | "release">> & {
|
|
120
|
+
build: NonNullable<RemptsConfig["build"]>;
|
|
121
|
+
dev: NonNullable<RemptsConfig["dev"]>;
|
|
122
|
+
test: NonNullable<RemptsConfig["test"]>;
|
|
123
|
+
workspace: NonNullable<RemptsConfig["workspace"]>;
|
|
124
|
+
release: NonNullable<RemptsConfig["release"]>;
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Hook context passed to before/after hooks
|
|
128
|
+
*/
|
|
129
|
+
export interface HookContext<TStore = {}> {
|
|
130
|
+
/** Global flags parsed from command line */
|
|
131
|
+
flags: Record<string, unknown>;
|
|
132
|
+
/** Store from plugins (if any) */
|
|
133
|
+
store: TStore;
|
|
134
|
+
/** Environment variables */
|
|
135
|
+
env: typeof process.env;
|
|
136
|
+
/** Current working directory */
|
|
137
|
+
cwd: string;
|
|
138
|
+
/** Set data that will be available to command handlers */
|
|
139
|
+
set(key: string, value: any): void;
|
|
140
|
+
/** Get data that was set by hooks */
|
|
141
|
+
get(key: string): any;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Before hook function type
|
|
145
|
+
*/
|
|
146
|
+
export type BeforeHook<TStore = {}> = (context: HookContext<TStore>) => void | Promise<void>;
|
|
147
|
+
/**
|
|
148
|
+
* After hook function type
|
|
149
|
+
*/
|
|
150
|
+
export type AfterHook<TStore = {}> = (context: HookContext<TStore> & {
|
|
151
|
+
exitCode: number;
|
|
152
|
+
error?: Error;
|
|
153
|
+
}) => void | Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Rich validation error with context information
|
|
156
|
+
*/
|
|
157
|
+
export declare class RemptsValidationError extends Error {
|
|
158
|
+
readonly context: {
|
|
159
|
+
option: string;
|
|
160
|
+
value: unknown;
|
|
161
|
+
command: string;
|
|
162
|
+
expectedType: string;
|
|
163
|
+
hint?: string;
|
|
164
|
+
};
|
|
165
|
+
constructor(message: string, context: {
|
|
166
|
+
option: string;
|
|
167
|
+
value: unknown;
|
|
168
|
+
command: string;
|
|
169
|
+
expectedType: string;
|
|
170
|
+
hint?: string;
|
|
171
|
+
});
|
|
172
|
+
toString(): string;
|
|
173
|
+
}
|
|
174
|
+
export declare function option<S extends StandardSchemaV1>(schema: S, metadata?: {
|
|
175
|
+
short?: string;
|
|
176
|
+
description?: string;
|
|
177
|
+
default?: unknown;
|
|
178
|
+
}): CLIOption<S>;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export function defineCommand(command) {
|
|
2
|
+
return command;
|
|
3
|
+
}
|
|
4
|
+
export { remptsConfigSchema } from "./config.js";
|
|
5
|
+
export class RemptsValidationError extends Error {
|
|
6
|
+
constructor(message, context) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.context = context;
|
|
9
|
+
this.name = "RemptsValidationError";
|
|
10
|
+
}
|
|
11
|
+
toString() {
|
|
12
|
+
return `${this.name}: Invalid option '${this.context.option}' for command '${this.context.command}'
|
|
13
|
+
|
|
14
|
+
Expected: ${this.context.expectedType}
|
|
15
|
+
Received: ${typeof this.context.value} (${JSON.stringify(this.context.value)})
|
|
16
|
+
${this.context.hint ? `
|
|
17
|
+
Hint: ${this.context.hint}` : ""}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function option(schema, metadata) {
|
|
21
|
+
return {
|
|
22
|
+
schema,
|
|
23
|
+
...metadata
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple logger implementation
|
|
3
|
+
*/
|
|
4
|
+
export interface Logger {
|
|
5
|
+
info(message: string, ...args: any[]): void;
|
|
6
|
+
warn(message: string, ...args: any[]): void;
|
|
7
|
+
error(message: string, ...args: any[]): void;
|
|
8
|
+
debug(message: string, ...args: any[]): void;
|
|
9
|
+
}
|
|
10
|
+
export declare function createLogger(namespace: string): Logger;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export function createLogger(namespace) {
|
|
2
|
+
const prefix = `[${namespace}]`;
|
|
3
|
+
const debugEnabled = process.env.dler_DEBUG === "true" || process.env.dler_DEBUG?.includes(namespace);
|
|
4
|
+
const silent = process.env.dler_SILENT === "true" || process.env.NODE_ENV === "test";
|
|
5
|
+
return {
|
|
6
|
+
info(message, ...args) {
|
|
7
|
+
if (!silent) {
|
|
8
|
+
console.log(prefix, message, ...args);
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
warn(message, ...args) {
|
|
12
|
+
if (!silent) {
|
|
13
|
+
console.warn(prefix, message, ...args);
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
error(message, ...args) {
|
|
17
|
+
if (!silent) {
|
|
18
|
+
console.error(prefix, message, ...args);
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
debug(message, ...args) {
|
|
22
|
+
if (debugEnabled && !silent) {
|
|
23
|
+
console.log(`${prefix} [DEBUG]`, message, ...args);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep merge utility for configuration objects
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Deep merge multiple objects
|
|
6
|
+
* Arrays are concatenated, objects are recursively merged
|
|
7
|
+
*/
|
|
8
|
+
export declare function deepMerge<T = any>(...objects: Partial<T>[]): T;
|
|
9
|
+
/**
|
|
10
|
+
* Shallow merge multiple objects
|
|
11
|
+
* Last value wins for all properties
|
|
12
|
+
*/
|
|
13
|
+
export declare function shallowMerge<T = any>(...objects: Partial<T>[]): T;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function isPlainObject(value) {
|
|
2
|
+
return value !== null && typeof value === "object" && value.constructor === Object && Object.prototype.toString.call(value) === "[object Object]";
|
|
3
|
+
}
|
|
4
|
+
export function deepMerge(...objects) {
|
|
5
|
+
const result = {};
|
|
6
|
+
for (const obj of objects) {
|
|
7
|
+
if (!obj) {
|
|
8
|
+
continue;
|
|
9
|
+
}
|
|
10
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
11
|
+
const existing = result[key];
|
|
12
|
+
if (Array.isArray(value)) {
|
|
13
|
+
result[key] = Array.isArray(existing) ? [...existing, ...value] : [...value];
|
|
14
|
+
} else if (isPlainObject(value)) {
|
|
15
|
+
result[key] = isPlainObject(existing) ? deepMerge(existing, value) : { ...value };
|
|
16
|
+
} else {
|
|
17
|
+
result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
export function shallowMerge(...objects) {
|
|
24
|
+
return Object.assign({}, ...objects);
|
|
25
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type utilities inspired by TanStack Router for advanced type manipulation
|
|
3
|
+
*/
|
|
4
|
+
export type UnionToIntersection<T> = (T extends any ? (arg: T) => any : never) extends (arg: infer T) => any ? T : never;
|
|
5
|
+
export type Constrain<T, TConstraint, TDefault = TConstraint> = (T extends TConstraint ? T : never) | TDefault;
|
|
6
|
+
export type PickRequired<T> = {
|
|
7
|
+
[K in keyof T as undefined extends T[K] ? never : K]: T[K];
|
|
8
|
+
};
|
|
9
|
+
export type PickOptional<T> = {
|
|
10
|
+
[K in keyof T as undefined extends T[K] ? K : never]: T[K];
|
|
11
|
+
};
|
|
12
|
+
export type ExtractPrimitives<TUnion> = TUnion extends MergeAllPrimitive ? TUnion : TUnion extends object ? never : TUnion;
|
|
13
|
+
export type MergeAllPrimitive = readonly any[] | number | string | bigint | boolean | symbol | undefined | null;
|
|
14
|
+
export type ExtractObjects<TUnion> = TUnion extends MergeAllPrimitive ? never : TUnion;
|
|
15
|
+
export type PartialMergeAllObject<TUnion> = ExtractObjects<TUnion> extends infer TObj ? [TObj] extends [never] ? never : {
|
|
16
|
+
[TKey in TObj extends any ? keyof TObj : never]?: TObj extends any ? TKey extends keyof TObj ? TObj[TKey] : never : never;
|
|
17
|
+
} : never;
|
|
18
|
+
export type PartialMergeAll<TUnion> = ExtractPrimitives<TUnion> | PartialMergeAllObject<TUnion>;
|
|
19
|
+
export type MergeAllObjects<TUnion, TIntersected = UnionToIntersection<ExtractObjects<TUnion>>> = [
|
|
20
|
+
keyof TIntersected
|
|
21
|
+
] extends [never] ? never : {
|
|
22
|
+
[TKey in keyof TIntersected]: TUnion extends any ? TUnion[TKey & keyof TUnion] : never;
|
|
23
|
+
};
|
|
24
|
+
export type MergeAll<TUnion> = MergeAllObjects<TUnion> | ExtractPrimitives<TUnion>;
|
|
25
|
+
export type NoInfer<T> = [T][T extends any ? 0 : never];
|
|
26
|
+
export type IsAny<TValue, TYesResult, TNoResult = TValue> = 1 extends 0 & TValue ? TYesResult : TNoResult;
|
|
27
|
+
export type PickAsRequired<TValue, TKey extends keyof TValue> = Omit<TValue, TKey> & Required<Pick<TValue, TKey>>;
|
|
28
|
+
export type WithoutEmpty<T> = T extends any ? ({} extends T ? never : T) : never;
|
|
29
|
+
export type Expand<T> = T extends object ? T extends infer O ? O extends Function ? O : {
|
|
30
|
+
[K in keyof O]: O[K];
|
|
31
|
+
} : never : T;
|
|
32
|
+
export type DeepPartial<T> = T extends object ? {
|
|
33
|
+
[P in keyof T]?: DeepPartial<T[P]>;
|
|
34
|
+
} : T;
|
|
35
|
+
export type MakeDifferenceOptional<TLeft, TRight> = keyof TLeft & keyof TRight extends never ? TRight : Omit<TRight, keyof TLeft & keyof TRight> & {
|
|
36
|
+
[K in keyof TLeft & keyof TRight]?: TRight[K];
|
|
37
|
+
};
|
|
38
|
+
export type IsUnion<T, U extends T = T> = (T extends any ? U extends T ? false : true : never) extends false ? false : true;
|
|
39
|
+
export type IsNonEmptyObject<T> = T extends object ? (keyof T extends never ? false : true) : false;
|
|
40
|
+
export type Assign<TLeft, TRight> = TLeft extends any ? TRight extends any ? IsNonEmptyObject<TLeft> extends false ? TRight : IsNonEmptyObject<TRight> extends false ? TLeft : keyof TLeft & keyof TRight extends never ? TLeft & TRight : Omit<TLeft, keyof TRight> & TRight : never : never;
|
|
41
|
+
export type IntersectAssign<TLeft, TRight> = TLeft extends any ? TRight extends any ? IsNonEmptyObject<TLeft> extends false ? TRight : IsNonEmptyObject<TRight> extends false ? TLeft : TRight & TLeft : never : never;
|
|
File without changes
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime validation utilities for Rempts
|
|
3
|
+
*/
|
|
4
|
+
import type { StandardSchemaV1 } from "@standard-schema/spec";
|
|
5
|
+
/**
|
|
6
|
+
* Validate a value against a schema at runtime
|
|
7
|
+
*/
|
|
8
|
+
export declare function validateValue(value: unknown, schema: StandardSchemaV1, context: {
|
|
9
|
+
option: string;
|
|
10
|
+
command: string;
|
|
11
|
+
}): Promise<unknown>;
|
|
12
|
+
/**
|
|
13
|
+
* Validate multiple values against their schemas
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateValues(values: Record<string, unknown>, schemas: Record<string, StandardSchemaV1>, command: string): Promise<Record<string, unknown>>;
|
|
16
|
+
/**
|
|
17
|
+
* Check if a value matches a schema type
|
|
18
|
+
*/
|
|
19
|
+
export declare function isValueOfType(value: unknown, expectedType: string): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Create a validator function from a schema
|
|
22
|
+
*/
|
|
23
|
+
export declare function createValidator(schema: StandardSchemaV1): (value: unknown, context: {
|
|
24
|
+
option: string;
|
|
25
|
+
command: string;
|
|
26
|
+
}) => Promise<unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Batch validate multiple values
|
|
29
|
+
*/
|
|
30
|
+
export declare function createBatchValidator(schemas: Record<string, StandardSchemaV1>): (values: Record<string, unknown>, command: string) => Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { RemptsValidationError } from "./types.js";
|
|
2
|
+
export async function validateValue(value, schema, context) {
|
|
3
|
+
try {
|
|
4
|
+
const result = await schema["~standard"].validate(value);
|
|
5
|
+
if (result.issues && result.issues.length > 0) {
|
|
6
|
+
const issue = result.issues[0];
|
|
7
|
+
if (!issue) {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
const expectedType = extractSchemaType(schema);
|
|
11
|
+
const hint = generateHint(schema, value);
|
|
12
|
+
throw new RemptsValidationError(`Invalid option '${context.option}': ${issue.message}`, {
|
|
13
|
+
option: context.option,
|
|
14
|
+
value,
|
|
15
|
+
command: context.command,
|
|
16
|
+
expectedType,
|
|
17
|
+
hint
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
return "value" in result ? result.value : value;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
if (error instanceof RemptsValidationError) {
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
throw new RemptsValidationError(`Validation failed for option '${context.option}': ${error}`, {
|
|
26
|
+
option: context.option,
|
|
27
|
+
value,
|
|
28
|
+
command: context.command,
|
|
29
|
+
expectedType: "unknown",
|
|
30
|
+
hint: "Check the value format and try again"
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function validateValues(values, schemas, command) {
|
|
35
|
+
const results = {};
|
|
36
|
+
const errors = [];
|
|
37
|
+
for (const [key, value] of Object.entries(values)) {
|
|
38
|
+
const schema = schemas[key];
|
|
39
|
+
if (!schema) {
|
|
40
|
+
results[key] = value;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
results[key] = await validateValue(value, schema, {
|
|
45
|
+
option: key,
|
|
46
|
+
command
|
|
47
|
+
});
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (error instanceof RemptsValidationError) {
|
|
50
|
+
errors.push(error.toString());
|
|
51
|
+
} else {
|
|
52
|
+
errors.push(`Validation error for ${key}: ${error}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (errors.length > 0) {
|
|
57
|
+
throw new Error(`Validation failed:
|
|
58
|
+
${errors.join("\n")}`);
|
|
59
|
+
}
|
|
60
|
+
return results;
|
|
61
|
+
}
|
|
62
|
+
export function isValueOfType(value, expectedType) {
|
|
63
|
+
switch (expectedType) {
|
|
64
|
+
case "string":
|
|
65
|
+
return typeof value === "string";
|
|
66
|
+
case "number":
|
|
67
|
+
return typeof value === "number";
|
|
68
|
+
case "boolean":
|
|
69
|
+
return typeof value === "boolean";
|
|
70
|
+
case "array":
|
|
71
|
+
return Array.isArray(value);
|
|
72
|
+
case "object":
|
|
73
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
74
|
+
default:
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function extractSchemaType(schema) {
|
|
79
|
+
if ("type" in schema && typeof schema.type === "string") {
|
|
80
|
+
return schema.type;
|
|
81
|
+
}
|
|
82
|
+
if ("enum" in schema) {
|
|
83
|
+
return "enum";
|
|
84
|
+
}
|
|
85
|
+
if ("items" in schema) {
|
|
86
|
+
return "array";
|
|
87
|
+
}
|
|
88
|
+
if ("properties" in schema) {
|
|
89
|
+
return "object";
|
|
90
|
+
}
|
|
91
|
+
if ("format" in schema) {
|
|
92
|
+
return "string";
|
|
93
|
+
}
|
|
94
|
+
return "unknown";
|
|
95
|
+
}
|
|
96
|
+
function generateHint(schema, value) {
|
|
97
|
+
const type = extractSchemaType(schema);
|
|
98
|
+
if (type === "boolean" && typeof value === "string") {
|
|
99
|
+
return "Use --flag or --no-flag for boolean options";
|
|
100
|
+
}
|
|
101
|
+
if (type === "number" && typeof value === "string") {
|
|
102
|
+
return "Provide a numeric value";
|
|
103
|
+
}
|
|
104
|
+
if (type === "array" && !Array.isArray(value)) {
|
|
105
|
+
return "Provide a comma-separated list of values";
|
|
106
|
+
}
|
|
107
|
+
if (type === "enum" && typeof value === "string") {
|
|
108
|
+
return "Choose from the available options";
|
|
109
|
+
}
|
|
110
|
+
return "";
|
|
111
|
+
}
|
|
112
|
+
export function createValidator(schema) {
|
|
113
|
+
return async (value, context) => {
|
|
114
|
+
return validateValue(value, schema, context);
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export function createBatchValidator(schemas) {
|
|
118
|
+
return async (values, command) => {
|
|
119
|
+
return validateValues(values, schemas, command);
|
|
120
|
+
};
|
|
121
|
+
}
|
package/package.json
CHANGED
|
@@ -1,58 +1,61 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "@reliverse/prompts is your modern, type-safe toolkit for building delightful CLI experiences. It's fast, flexible, and built with developer joy in mind. Forget the clutter — this is how CLI should feel.",
|
|
3
|
-
"license": "MIT",
|
|
4
2
|
"name": "@reliverse/rempts-core",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"author": "reliverse",
|
|
8
|
-
"bugs": {
|
|
9
|
-
"email": "blefnk@gmail.com",
|
|
10
|
-
"url": "https://github.com/reliverse/prompts/issues"
|
|
11
|
-
},
|
|
3
|
+
"version": "2.3.1",
|
|
4
|
+
"description": "Minimal, type-safe CLI framework for Bun",
|
|
12
5
|
"keywords": [
|
|
13
|
-
"
|
|
14
|
-
"
|
|
6
|
+
"bun",
|
|
7
|
+
"cli",
|
|
8
|
+
"command-line",
|
|
9
|
+
"framework",
|
|
10
|
+
"rempts",
|
|
11
|
+
"type-safe",
|
|
12
|
+
"typescript"
|
|
15
13
|
],
|
|
14
|
+
"homepage": "https://github.com/reliverse/dler#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/reliverse/dler/issues"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": "blefnk",
|
|
16
20
|
"repository": {
|
|
17
21
|
"type": "git",
|
|
18
|
-
"url": "
|
|
19
|
-
|
|
20
|
-
"dependencies": {
|
|
21
|
-
"@figliolia/chalk-animation": "^1.0.4",
|
|
22
|
-
"@reliverse/relico": "^1.1.0",
|
|
23
|
-
"@reliverse/relinka": "^1.3.7",
|
|
24
|
-
"@reliverse/runtime": "^1.0.3",
|
|
25
|
-
"ansi-escapes": "^7.0.0",
|
|
26
|
-
"c12": "^3.0.2",
|
|
27
|
-
"cli-spinners": "^3.2.0",
|
|
28
|
-
"detect-package-manager": "^3.0.2",
|
|
29
|
-
"figlet": "^1.8.0",
|
|
30
|
-
"fs-extra": "^11.3.0",
|
|
31
|
-
"gradient-string": "^3.0.0",
|
|
32
|
-
"log-update": "^6.1.0",
|
|
33
|
-
"node-emoji": "^2.2.0",
|
|
34
|
-
"ora": "^8.2.0",
|
|
35
|
-
"pathe": "^2.0.3",
|
|
36
|
-
"scule": "^1.3.0",
|
|
37
|
-
"sisteransi": "^1.0.5",
|
|
38
|
-
"terminal-kit": "^3.1.2",
|
|
39
|
-
"terminal-size": "^4.0.0",
|
|
40
|
-
"ts-regex-builder": "^1.8.2",
|
|
41
|
-
"wrap-ansi": "^9.0.0"
|
|
42
|
-
},
|
|
43
|
-
"devDependencies": {},
|
|
44
|
-
"exports": {
|
|
45
|
-
".": "./bin/main.js"
|
|
22
|
+
"url": "https://github.com/reliverse/dler.git",
|
|
23
|
+
"directory": "packages/core"
|
|
46
24
|
},
|
|
47
25
|
"files": [
|
|
48
|
-
"
|
|
49
|
-
"package.json",
|
|
26
|
+
"dist",
|
|
50
27
|
"README.md",
|
|
51
|
-
"
|
|
28
|
+
"src"
|
|
52
29
|
],
|
|
53
|
-
"
|
|
54
|
-
"module": "./
|
|
30
|
+
"type": "module",
|
|
31
|
+
"module": "./src/mod.ts",
|
|
32
|
+
"types": "./src/mod.ts",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"types": "./dist/mod.d.ts",
|
|
36
|
+
"import": "./dist/mod.js"
|
|
37
|
+
},
|
|
38
|
+
"./plugin": {
|
|
39
|
+
"types": "./dist/plugin/mod.d.ts",
|
|
40
|
+
"import": "./dist/plugin/mod.js"
|
|
41
|
+
},
|
|
42
|
+
"./utils": {
|
|
43
|
+
"types": "./dist/utils/mod.d.ts",
|
|
44
|
+
"import": "./dist/utils/mod.js"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
55
47
|
"publishConfig": {
|
|
56
48
|
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@reliverse/relico": "2.3.1",
|
|
52
|
+
"@reliverse/rempts-utils": "2.3.1",
|
|
53
|
+
"@standard-schema/spec": "^1.1.0",
|
|
54
|
+
"@standard-schema/utils": "^0.3.0",
|
|
55
|
+
"arktype": "^2.1.29",
|
|
56
|
+
"zustand": "^5.0.9"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"bun": ">=1.3.5"
|
|
57
60
|
}
|
|
58
61
|
}
|