wp-typia 0.16.9 → 0.16.11
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/package.json +2 -2
- package/src/cli.ts +17 -4
- package/src/command-contract.ts +4 -0
- package/src/commands/add.ts +15 -0
- package/src/commands/create.ts +20 -1
- package/src/commands/doctor.ts +11 -3
- package/src/commands/migrate.ts +1 -0
- package/src/config.ts +4 -0
- package/src/runtime-bridge.ts +290 -173
- package/src/ui/add-flow-model.ts +14 -0
- package/src/ui/add-flow.tsx +1 -0
- package/src/ui/create-flow-model.ts +32 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wp-typia",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.11",
|
|
4
4
|
"description": "Canonical CLI package for wp-typia scaffolding and project workflows",
|
|
5
5
|
"packageManager": "bun@1.3.11",
|
|
6
6
|
"type": "module",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"@bunli/tui": "0.6.0",
|
|
66
66
|
"@bunli/utils": "0.6.0",
|
|
67
67
|
"@wp-typia/api-client": "^0.4.4",
|
|
68
|
-
"@wp-typia/project-tools": "0.16.
|
|
68
|
+
"@wp-typia/project-tools": "0.16.10",
|
|
69
69
|
"better-result": "^2.7.0",
|
|
70
70
|
"react": "^19.2.5",
|
|
71
71
|
"react-dom": "^19.2.5",
|
package/src/cli.ts
CHANGED
|
@@ -73,6 +73,15 @@ function resolveGeneratedMetadataPath(moduleUrl: string): string {
|
|
|
73
73
|
return fileURLToPath(new URL("../.bunli/commands.gen.ts", moduleUrl));
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
async function formatCliError(error: unknown): Promise<string> {
|
|
77
|
+
try {
|
|
78
|
+
const { formatCliDiagnosticError } = await import("@wp-typia/project-tools/cli-diagnostics");
|
|
79
|
+
return formatCliDiagnosticError(error);
|
|
80
|
+
} catch {
|
|
81
|
+
return error instanceof Error ? error.message : String(error);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
76
85
|
export async function createWpTypiaCli(options: {
|
|
77
86
|
configOverridePath?: string;
|
|
78
87
|
} = {}): Promise<CLI> {
|
|
@@ -117,10 +126,14 @@ export async function main(argv = process.argv.slice(2)): Promise<void> {
|
|
|
117
126
|
}
|
|
118
127
|
|
|
119
128
|
if (import.meta.main) {
|
|
120
|
-
void
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
129
|
+
void (async () => {
|
|
130
|
+
try {
|
|
131
|
+
await main();
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error(await formatCliError(error));
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
})();
|
|
124
137
|
}
|
|
125
138
|
|
|
126
139
|
export default createWpTypiaCli;
|
package/src/command-contract.ts
CHANGED
|
@@ -32,12 +32,16 @@ const STRING_OPTION_NAMES_BY_COMMAND = {
|
|
|
32
32
|
"anchor",
|
|
33
33
|
"block",
|
|
34
34
|
"data-storage",
|
|
35
|
+
"external-layer-id",
|
|
36
|
+
"external-layer-source",
|
|
35
37
|
"persistence-policy",
|
|
36
38
|
"position",
|
|
37
39
|
"template",
|
|
38
40
|
]),
|
|
39
41
|
create: new Set([
|
|
40
42
|
"data-storage",
|
|
43
|
+
"external-layer-id",
|
|
44
|
+
"external-layer-source",
|
|
41
45
|
"namespace",
|
|
42
46
|
"package-manager",
|
|
43
47
|
"persistence-policy",
|
package/src/commands/add.ts
CHANGED
|
@@ -34,6 +34,14 @@ const addOptions = {
|
|
|
34
34
|
description: "Persistence storage mode for persistence-capable templates.",
|
|
35
35
|
schema: z.string().optional(),
|
|
36
36
|
},
|
|
37
|
+
"external-layer-id": {
|
|
38
|
+
description: "Explicit layer id when an external layer package exposes multiple selectable layers.",
|
|
39
|
+
schema: z.string().optional(),
|
|
40
|
+
},
|
|
41
|
+
"external-layer-source": {
|
|
42
|
+
description: "Local path, GitHub locator, or npm package that exposes wp-typia.layers.json for built-in block templates.",
|
|
43
|
+
schema: z.string().optional(),
|
|
44
|
+
},
|
|
37
45
|
"persistence-policy": {
|
|
38
46
|
description: "Persistence write policy for persistence-capable templates.",
|
|
39
47
|
schema: z.string().optional(),
|
|
@@ -49,6 +57,7 @@ const addOptions = {
|
|
|
49
57
|
};
|
|
50
58
|
|
|
51
59
|
export const addCommand = defineCommand({
|
|
60
|
+
defaultFormat: "toon",
|
|
52
61
|
description: "Extend an official wp-typia workspace with blocks, variations, patterns, binding sources, or hooked blocks.",
|
|
53
62
|
handler: async (args) => {
|
|
54
63
|
await executeAddCommand({
|
|
@@ -76,6 +85,12 @@ export const addCommand = defineCommand({
|
|
|
76
85
|
"data-storage":
|
|
77
86
|
(args.flags["data-storage"] as string | undefined) ??
|
|
78
87
|
config["data-storage"],
|
|
88
|
+
"external-layer-id":
|
|
89
|
+
(args.flags["external-layer-id"] as string | undefined) ??
|
|
90
|
+
config["external-layer-id"],
|
|
91
|
+
"external-layer-source":
|
|
92
|
+
(args.flags["external-layer-source"] as string | undefined) ??
|
|
93
|
+
config["external-layer-source"],
|
|
79
94
|
anchor: (args.flags.anchor as string | undefined) ?? "",
|
|
80
95
|
block: (args.flags.block as string | undefined) ?? "",
|
|
81
96
|
kind:
|
package/src/commands/create.ts
CHANGED
|
@@ -26,6 +26,14 @@ const createOptions = {
|
|
|
26
26
|
description: "Persistence storage mode for persistence-capable templates.",
|
|
27
27
|
schema: z.string().optional(),
|
|
28
28
|
},
|
|
29
|
+
"external-layer-id": {
|
|
30
|
+
description: "Explicit layer id when an external layer package exposes multiple selectable layers.",
|
|
31
|
+
schema: z.string().optional(),
|
|
32
|
+
},
|
|
33
|
+
"external-layer-source": {
|
|
34
|
+
description: "Local path, GitHub locator, or npm package that exposes wp-typia.layers.json for built-in templates.",
|
|
35
|
+
schema: z.string().optional(),
|
|
36
|
+
},
|
|
29
37
|
namespace: {
|
|
30
38
|
description: "Override the default block namespace.",
|
|
31
39
|
schema: z.string().optional(),
|
|
@@ -85,11 +93,16 @@ const createOptions = {
|
|
|
85
93
|
};
|
|
86
94
|
|
|
87
95
|
export const createCommand = defineCommand({
|
|
96
|
+
defaultFormat: "toon",
|
|
88
97
|
description: "Scaffold a new wp-typia project.",
|
|
89
98
|
handler: async (args) => {
|
|
90
99
|
const projectDir = args.positional[0];
|
|
91
100
|
if (!projectDir) {
|
|
92
|
-
|
|
101
|
+
const { createCliCommandError } = await import("@wp-typia/project-tools/cli-diagnostics");
|
|
102
|
+
throw createCliCommandError({
|
|
103
|
+
command: "create",
|
|
104
|
+
detailLines: ["`wp-typia create` requires <project-dir>."],
|
|
105
|
+
});
|
|
93
106
|
}
|
|
94
107
|
await executeCreateCommand({
|
|
95
108
|
cwd: args.cwd,
|
|
@@ -115,6 +128,12 @@ export const createCommand = defineCommand({
|
|
|
115
128
|
"data-storage":
|
|
116
129
|
(args.flags["data-storage"] as string | undefined) ??
|
|
117
130
|
config["data-storage"],
|
|
131
|
+
"external-layer-id":
|
|
132
|
+
(args.flags["external-layer-id"] as string | undefined) ??
|
|
133
|
+
config["external-layer-id"],
|
|
134
|
+
"external-layer-source":
|
|
135
|
+
(args.flags["external-layer-source"] as string | undefined) ??
|
|
136
|
+
config["external-layer-source"],
|
|
118
137
|
namespace:
|
|
119
138
|
(args.flags.namespace as string | undefined) ?? config.namespace,
|
|
120
139
|
"no-install": Boolean(
|
package/src/commands/doctor.ts
CHANGED
|
@@ -2,18 +2,26 @@ import { defineCommand } from "@bunli/core";
|
|
|
2
2
|
import { executeDoctorCommand } from "../runtime-bridge";
|
|
3
3
|
|
|
4
4
|
export const doctorCommand = defineCommand({
|
|
5
|
+
defaultFormat: "toon",
|
|
5
6
|
description: "Run repository and project diagnostics.",
|
|
6
7
|
handler: async (args) => {
|
|
7
8
|
const prefersStructuredOutput =
|
|
8
9
|
(args.formatExplicit && args.format !== "toon") ||
|
|
9
|
-
args.agent ||
|
|
10
10
|
Boolean(args.context?.store?.isAIAgent);
|
|
11
11
|
if (prefersStructuredOutput) {
|
|
12
|
-
const { getDoctorChecks }
|
|
12
|
+
const [{ getDoctorChecks }, { createCliCommandError, getDoctorFailureDetailLines }] =
|
|
13
|
+
await Promise.all([
|
|
14
|
+
import("@wp-typia/project-tools/cli-doctor"),
|
|
15
|
+
import("@wp-typia/project-tools/cli-diagnostics"),
|
|
16
|
+
]);
|
|
13
17
|
const checks = await getDoctorChecks(args.cwd);
|
|
14
18
|
args.output({ checks });
|
|
15
19
|
if (checks.some((check) => check.status === "fail")) {
|
|
16
|
-
throw
|
|
20
|
+
throw createCliCommandError({
|
|
21
|
+
command: "doctor",
|
|
22
|
+
detailLines: getDoctorFailureDetailLines(checks),
|
|
23
|
+
summary: "One or more doctor checks failed.",
|
|
24
|
+
});
|
|
17
25
|
}
|
|
18
26
|
return;
|
|
19
27
|
}
|
package/src/commands/migrate.ts
CHANGED
package/src/config.ts
CHANGED
|
@@ -12,6 +12,8 @@ export type WpTypiaSchemaSource = {
|
|
|
12
12
|
export type WpTypiaUserConfig = {
|
|
13
13
|
create?: {
|
|
14
14
|
"data-storage"?: string;
|
|
15
|
+
"external-layer-id"?: string;
|
|
16
|
+
"external-layer-source"?: string;
|
|
15
17
|
namespace?: string;
|
|
16
18
|
"no-install"?: boolean;
|
|
17
19
|
"package-manager"?: string;
|
|
@@ -28,6 +30,8 @@ export type WpTypiaUserConfig = {
|
|
|
28
30
|
add?: {
|
|
29
31
|
block?: {
|
|
30
32
|
"data-storage"?: string;
|
|
33
|
+
"external-layer-id"?: string;
|
|
34
|
+
"external-layer-source"?: string;
|
|
31
35
|
"persistence-policy"?: string;
|
|
32
36
|
template?: string;
|
|
33
37
|
};
|
package/src/runtime-bridge.ts
CHANGED
|
@@ -29,9 +29,12 @@ type AddExecutionInput = {
|
|
|
29
29
|
cwd: string;
|
|
30
30
|
emitOutput?: boolean;
|
|
31
31
|
flags: Record<string, unknown>;
|
|
32
|
+
interactive?: boolean;
|
|
32
33
|
kind?: string;
|
|
33
34
|
name?: string;
|
|
34
35
|
printLine?: PrintLine;
|
|
36
|
+
prompt?: ReadlinePrompt;
|
|
37
|
+
warnLine?: PrintLine;
|
|
35
38
|
};
|
|
36
39
|
|
|
37
40
|
type TemplatesExecutionInput = {
|
|
@@ -56,6 +59,12 @@ type MigrateExecutionInput = {
|
|
|
56
59
|
|
|
57
60
|
type PrintLine = (line: string) => void;
|
|
58
61
|
type PackageManagerId = "bun" | "npm" | "pnpm" | "yarn";
|
|
62
|
+
type CliCommandId = "add" | "create" | "doctor" | "migrate";
|
|
63
|
+
type ExternalLayerSelectOption = {
|
|
64
|
+
description?: string;
|
|
65
|
+
extends: string[];
|
|
66
|
+
id: string;
|
|
67
|
+
};
|
|
59
68
|
|
|
60
69
|
type SyncProjectContext = {
|
|
61
70
|
cwd: string;
|
|
@@ -65,18 +74,56 @@ type SyncProjectContext = {
|
|
|
65
74
|
};
|
|
66
75
|
|
|
67
76
|
const loadCliAddRuntime = () => import("@wp-typia/project-tools/cli-add");
|
|
77
|
+
const loadCliDiagnosticsRuntime = () => import("@wp-typia/project-tools/cli-diagnostics");
|
|
68
78
|
const loadCliDoctorRuntime = () => import("@wp-typia/project-tools/cli-doctor");
|
|
69
79
|
const loadCliPromptRuntime = () => import("@wp-typia/project-tools/cli-prompt");
|
|
70
80
|
const loadCliScaffoldRuntime = () => import("@wp-typia/project-tools/cli-scaffold");
|
|
71
81
|
const loadCliTemplatesRuntime = () => import("@wp-typia/project-tools/cli-templates");
|
|
72
82
|
const loadMigrationsRuntime = () => import("@wp-typia/project-tools/migrations");
|
|
73
83
|
|
|
84
|
+
async function wrapCliCommandError(command: CliCommandId, error: unknown) {
|
|
85
|
+
const { createCliCommandError } = await loadCliDiagnosticsRuntime();
|
|
86
|
+
return createCliCommandError({ command, error });
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function shouldWrapCliCommandError(options: {
|
|
90
|
+
emitOutput?: boolean;
|
|
91
|
+
renderLine?: ((line: string) => void) | undefined;
|
|
92
|
+
}): boolean {
|
|
93
|
+
if (options.emitOutput === false) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (options.renderLine) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
|
|
74
104
|
function printBlock(lines: string[], printLine: PrintLine): void {
|
|
75
105
|
for (const line of lines) {
|
|
76
106
|
printLine(line);
|
|
77
107
|
}
|
|
78
108
|
}
|
|
79
109
|
|
|
110
|
+
function formatExternalLayerSelectHint(option: ExternalLayerSelectOption): string | undefined {
|
|
111
|
+
const details = [
|
|
112
|
+
option.description,
|
|
113
|
+
option.extends.length > 0 ? `extends ${option.extends.join(", ")}` : undefined,
|
|
114
|
+
].filter((value): value is string => typeof value === "string" && value.length > 0);
|
|
115
|
+
|
|
116
|
+
return details.length > 0 ? details.join(" · ") : undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function toExternalLayerPromptOptions(options: ExternalLayerSelectOption[]) {
|
|
120
|
+
return options.map((option) => ({
|
|
121
|
+
hint: formatExternalLayerSelectHint(option),
|
|
122
|
+
label: option.id,
|
|
123
|
+
value: option.id,
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
|
|
80
127
|
export function printCompletionPayload(
|
|
81
128
|
payload: AlternateBufferCompletionPayload,
|
|
82
129
|
options: {
|
|
@@ -172,6 +219,7 @@ function buildAddCompletionPayload(options: {
|
|
|
172
219
|
kind: "binding-source" | "block" | "hooked-block" | "pattern" | "variation";
|
|
173
220
|
projectDir: string;
|
|
174
221
|
values: Record<string, string>;
|
|
222
|
+
warnings?: string[];
|
|
175
223
|
}): AlternateBufferCompletionPayload {
|
|
176
224
|
switch (options.kind) {
|
|
177
225
|
case "variation":
|
|
@@ -218,6 +266,7 @@ function buildAddCompletionPayload(options: {
|
|
|
218
266
|
`Project directory: ${options.projectDir}`,
|
|
219
267
|
],
|
|
220
268
|
title: "✅ Added workspace block",
|
|
269
|
+
warningLines: options.warnings,
|
|
221
270
|
};
|
|
222
271
|
}
|
|
223
272
|
}
|
|
@@ -431,11 +480,15 @@ export async function executeCreateCommand({
|
|
|
431
480
|
const shouldPrompt =
|
|
432
481
|
interactive ?? (!Boolean(flags.yes) && Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY));
|
|
433
482
|
const activePrompt = shouldPrompt ? (prompt ?? createReadlinePrompt()) : undefined;
|
|
483
|
+
const shouldPromptForExternalLayerSelection =
|
|
484
|
+
Boolean(activePrompt) && activePrompt !== prompt;
|
|
434
485
|
|
|
435
486
|
try {
|
|
436
487
|
const flow = await runScaffoldFlow({
|
|
437
488
|
cwd,
|
|
438
489
|
dataStorageMode: readOptionalLooseStringFlag(flags, "data-storage"),
|
|
490
|
+
externalLayerId: readOptionalLooseStringFlag(flags, "external-layer-id"),
|
|
491
|
+
externalLayerSource: readOptionalLooseStringFlag(flags, "external-layer-source"),
|
|
439
492
|
isInteractive: Boolean(activePrompt),
|
|
440
493
|
namespace: readOptionalLooseStringFlag(flags, "namespace"),
|
|
441
494
|
noInstall: Boolean(flags["no-install"]),
|
|
@@ -449,6 +502,14 @@ export async function executeCreateCommand({
|
|
|
449
502
|
selectDataStorage: activePrompt
|
|
450
503
|
? () => activePrompt.select("Select a data storage mode", [...DATA_STORAGE_PROMPT_OPTIONS], 1)
|
|
451
504
|
: undefined,
|
|
505
|
+
selectExternalLayerId: shouldPromptForExternalLayerSelection && activePrompt
|
|
506
|
+
? (options) =>
|
|
507
|
+
activePrompt.select(
|
|
508
|
+
"Select an external layer",
|
|
509
|
+
toExternalLayerPromptOptions(options),
|
|
510
|
+
1,
|
|
511
|
+
)
|
|
512
|
+
: undefined,
|
|
452
513
|
selectPackageManager: activePrompt
|
|
453
514
|
? () => activePrompt.select("Select a package manager", [...PACKAGE_MANAGER_PROMPT_OPTIONS], 1)
|
|
454
515
|
: undefined,
|
|
@@ -495,6 +556,11 @@ export async function executeCreateCommand({
|
|
|
495
556
|
});
|
|
496
557
|
}
|
|
497
558
|
return payload;
|
|
559
|
+
} catch (error) {
|
|
560
|
+
if (!shouldWrapCliCommandError({ emitOutput })) {
|
|
561
|
+
throw error;
|
|
562
|
+
}
|
|
563
|
+
throw await wrapCliCommandError("create", error);
|
|
498
564
|
} finally {
|
|
499
565
|
if (activePrompt && activePrompt !== prompt) {
|
|
500
566
|
activePrompt.close();
|
|
@@ -506,9 +572,12 @@ export async function executeAddCommand({
|
|
|
506
572
|
cwd,
|
|
507
573
|
emitOutput = true,
|
|
508
574
|
flags,
|
|
575
|
+
interactive,
|
|
509
576
|
kind,
|
|
510
577
|
name,
|
|
511
578
|
printLine = console.log as PrintLine,
|
|
579
|
+
prompt,
|
|
580
|
+
warnLine = console.warn as PrintLine,
|
|
512
581
|
}: AddExecutionInput): Promise<AlternateBufferCompletionPayload | void> {
|
|
513
582
|
if (!kind) {
|
|
514
583
|
const { formatAddHelpText } = await loadCliAddRuntime();
|
|
@@ -517,168 +586,205 @@ export async function executeAddCommand({
|
|
|
517
586
|
}
|
|
518
587
|
|
|
519
588
|
const addRuntime = await loadCliAddRuntime();
|
|
589
|
+
let activePrompt: ReadlinePrompt | undefined;
|
|
520
590
|
|
|
521
|
-
|
|
522
|
-
if (
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
591
|
+
try {
|
|
592
|
+
if (kind === "variation") {
|
|
593
|
+
if (!name) {
|
|
594
|
+
throw new Error(
|
|
595
|
+
"`wp-typia add variation` requires <name>. Usage: wp-typia add variation <name> --block <block-slug>",
|
|
596
|
+
);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
const blockSlug = readOptionalStringFlag(flags, "block");
|
|
600
|
+
if (!blockSlug) {
|
|
601
|
+
throw new Error("`wp-typia add variation` requires --block <block-slug>.");
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
const result = await addRuntime.runAddVariationCommand({
|
|
605
|
+
blockName: blockSlug,
|
|
606
|
+
cwd,
|
|
607
|
+
variationName: name,
|
|
608
|
+
});
|
|
609
|
+
const payload = buildAddCompletionPayload({
|
|
610
|
+
kind: "variation",
|
|
611
|
+
projectDir: result.projectDir,
|
|
612
|
+
values: {
|
|
613
|
+
blockSlug: result.blockSlug,
|
|
614
|
+
variationSlug: result.variationSlug,
|
|
615
|
+
},
|
|
616
|
+
});
|
|
617
|
+
if (emitOutput) {
|
|
618
|
+
printCompletionPayload(payload, { printLine });
|
|
619
|
+
}
|
|
620
|
+
return payload;
|
|
526
621
|
}
|
|
527
622
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
623
|
+
if (kind === "pattern") {
|
|
624
|
+
if (!name) {
|
|
625
|
+
throw new Error(
|
|
626
|
+
"`wp-typia add pattern` requires <name>. Usage: wp-typia add pattern <name>.",
|
|
627
|
+
);
|
|
628
|
+
}
|
|
532
629
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
630
|
+
const result = await addRuntime.runAddPatternCommand({
|
|
631
|
+
cwd,
|
|
632
|
+
patternName: name,
|
|
633
|
+
});
|
|
634
|
+
const payload = buildAddCompletionPayload({
|
|
635
|
+
kind: "pattern",
|
|
636
|
+
projectDir: result.projectDir,
|
|
637
|
+
values: {
|
|
638
|
+
patternSlug: result.patternSlug,
|
|
639
|
+
},
|
|
640
|
+
});
|
|
641
|
+
if (emitOutput) {
|
|
642
|
+
printCompletionPayload(payload, { printLine });
|
|
643
|
+
}
|
|
644
|
+
return payload;
|
|
548
645
|
}
|
|
549
|
-
return payload;
|
|
550
|
-
}
|
|
551
646
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
647
|
+
if (kind === "binding-source") {
|
|
648
|
+
if (!name) {
|
|
649
|
+
throw new Error(
|
|
650
|
+
"`wp-typia add binding-source` requires <name>. Usage: wp-typia add binding-source <name>.",
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
const result = await addRuntime.runAddBindingSourceCommand({
|
|
655
|
+
bindingSourceName: name,
|
|
656
|
+
cwd,
|
|
657
|
+
});
|
|
658
|
+
const payload = buildAddCompletionPayload({
|
|
659
|
+
kind: "binding-source",
|
|
660
|
+
projectDir: result.projectDir,
|
|
661
|
+
values: {
|
|
662
|
+
bindingSourceSlug: result.bindingSourceSlug,
|
|
663
|
+
},
|
|
664
|
+
});
|
|
665
|
+
if (emitOutput) {
|
|
666
|
+
printCompletionPayload(payload, { printLine });
|
|
667
|
+
}
|
|
668
|
+
return payload;
|
|
557
669
|
}
|
|
558
670
|
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
671
|
+
if (kind === "hooked-block") {
|
|
672
|
+
if (!name) {
|
|
673
|
+
throw new Error(
|
|
674
|
+
"`wp-typia add hooked-block` requires <block-slug>. Usage: wp-typia add hooked-block <block-slug> --anchor <anchor-block-name> --position <before|after|firstChild|lastChild>.",
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const anchorBlockName = readOptionalStringFlag(flags, "anchor");
|
|
679
|
+
if (!anchorBlockName) {
|
|
680
|
+
throw new Error("`wp-typia add hooked-block` requires --anchor <anchor-block-name>.");
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
const position = readOptionalStringFlag(flags, "position");
|
|
684
|
+
if (!position) {
|
|
685
|
+
throw new Error(
|
|
686
|
+
"`wp-typia add hooked-block` requires --position <before|after|firstChild|lastChild>.",
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const result = await addRuntime.runAddHookedBlockCommand({
|
|
691
|
+
anchorBlockName,
|
|
692
|
+
blockName: name,
|
|
693
|
+
cwd,
|
|
694
|
+
position,
|
|
695
|
+
});
|
|
696
|
+
const payload = buildAddCompletionPayload({
|
|
697
|
+
kind: "hooked-block",
|
|
698
|
+
projectDir: result.projectDir,
|
|
699
|
+
values: {
|
|
700
|
+
anchorBlockName: result.anchorBlockName,
|
|
701
|
+
blockSlug: result.blockSlug,
|
|
702
|
+
position: result.position,
|
|
703
|
+
},
|
|
704
|
+
});
|
|
705
|
+
if (emitOutput) {
|
|
706
|
+
printCompletionPayload(payload, { printLine });
|
|
707
|
+
}
|
|
708
|
+
return payload;
|
|
572
709
|
}
|
|
573
|
-
return payload;
|
|
574
|
-
}
|
|
575
710
|
|
|
576
|
-
|
|
577
|
-
if (!name) {
|
|
711
|
+
if (kind !== "block") {
|
|
578
712
|
throw new Error(
|
|
579
|
-
|
|
713
|
+
`Unknown add kind "${kind}". Expected one of: block, variation, pattern, binding-source, hooked-block.`,
|
|
580
714
|
);
|
|
581
715
|
}
|
|
582
716
|
|
|
583
|
-
const result = await addRuntime.runAddBindingSourceCommand({
|
|
584
|
-
bindingSourceName: name,
|
|
585
|
-
cwd,
|
|
586
|
-
});
|
|
587
|
-
const payload = buildAddCompletionPayload({
|
|
588
|
-
kind: "binding-source",
|
|
589
|
-
projectDir: result.projectDir,
|
|
590
|
-
values: {
|
|
591
|
-
bindingSourceSlug: result.bindingSourceSlug,
|
|
592
|
-
},
|
|
593
|
-
});
|
|
594
|
-
if (emitOutput) {
|
|
595
|
-
printCompletionPayload(payload, { printLine });
|
|
596
|
-
}
|
|
597
|
-
return payload;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
if (kind === "hooked-block") {
|
|
601
717
|
if (!name) {
|
|
602
718
|
throw new Error(
|
|
603
|
-
"`wp-typia add
|
|
719
|
+
"`wp-typia add block` requires <name>. Usage: wp-typia add block <name> --template <basic|interactivity|persistence|compound>",
|
|
604
720
|
);
|
|
605
721
|
}
|
|
606
722
|
|
|
607
|
-
|
|
608
|
-
if (!anchorBlockName) {
|
|
609
|
-
throw new Error("`wp-typia add hooked-block` requires --anchor <anchor-block-name>.");
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
const position = readOptionalStringFlag(flags, "position");
|
|
613
|
-
if (!position) {
|
|
723
|
+
if (!flags.template) {
|
|
614
724
|
throw new Error(
|
|
615
|
-
"`wp-typia add
|
|
725
|
+
"`wp-typia add block` requires --template <basic|interactivity|persistence|compound>.",
|
|
616
726
|
);
|
|
617
727
|
}
|
|
618
728
|
|
|
619
|
-
const
|
|
620
|
-
|
|
729
|
+
const externalLayerId = readOptionalStringFlag(flags, "external-layer-id");
|
|
730
|
+
const externalLayerSource = readOptionalStringFlag(flags, "external-layer-source");
|
|
731
|
+
const shouldPromptForLayerSelection =
|
|
732
|
+
Boolean(externalLayerSource) &&
|
|
733
|
+
!Boolean(externalLayerId) &&
|
|
734
|
+
(interactive ?? (Boolean(process.stdin.isTTY) && Boolean(process.stdout.isTTY)));
|
|
735
|
+
const promptRuntime = shouldPromptForLayerSelection
|
|
736
|
+
? await loadCliPromptRuntime()
|
|
737
|
+
: undefined;
|
|
738
|
+
activePrompt = shouldPromptForLayerSelection
|
|
739
|
+
? (prompt ?? promptRuntime?.createReadlinePrompt())
|
|
740
|
+
: undefined;
|
|
741
|
+
const selectPrompt = activePrompt;
|
|
742
|
+
|
|
743
|
+
const result = await addRuntime.runAddBlockCommand({
|
|
621
744
|
blockName: name,
|
|
622
745
|
cwd,
|
|
623
|
-
|
|
746
|
+
dataStorageMode: readOptionalStringFlag(flags, "data-storage"),
|
|
747
|
+
externalLayerId,
|
|
748
|
+
externalLayerSource,
|
|
749
|
+
persistencePolicy: readOptionalStringFlag(flags, "persistence-policy"),
|
|
750
|
+
selectExternalLayerId: selectPrompt
|
|
751
|
+
? (options) =>
|
|
752
|
+
selectPrompt.select(
|
|
753
|
+
"Select an external layer",
|
|
754
|
+
toExternalLayerPromptOptions(options),
|
|
755
|
+
1,
|
|
756
|
+
)
|
|
757
|
+
: undefined,
|
|
758
|
+
templateId: readOptionalStringFlag(flags, "template") as
|
|
759
|
+
| "basic"
|
|
760
|
+
| "interactivity"
|
|
761
|
+
| "persistence"
|
|
762
|
+
| "compound",
|
|
624
763
|
});
|
|
764
|
+
|
|
625
765
|
const payload = buildAddCompletionPayload({
|
|
626
|
-
kind: "
|
|
766
|
+
kind: "block",
|
|
627
767
|
projectDir: result.projectDir,
|
|
628
768
|
values: {
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
position: result.position,
|
|
769
|
+
blockSlugs: result.blockSlugs.join(", "),
|
|
770
|
+
templateId: result.templateId,
|
|
632
771
|
},
|
|
772
|
+
warnings: result.warnings,
|
|
633
773
|
});
|
|
634
774
|
if (emitOutput) {
|
|
635
|
-
printCompletionPayload(payload, { printLine });
|
|
775
|
+
printCompletionPayload(payload, { printLine, warnLine });
|
|
636
776
|
}
|
|
637
777
|
return payload;
|
|
778
|
+
} catch (error) {
|
|
779
|
+
if (!shouldWrapCliCommandError({ emitOutput })) {
|
|
780
|
+
throw error;
|
|
781
|
+
}
|
|
782
|
+
throw await wrapCliCommandError("add", error);
|
|
783
|
+
} finally {
|
|
784
|
+
if (activePrompt && activePrompt !== prompt) {
|
|
785
|
+
activePrompt.close();
|
|
786
|
+
}
|
|
638
787
|
}
|
|
639
|
-
|
|
640
|
-
if (kind !== "block") {
|
|
641
|
-
throw new Error(
|
|
642
|
-
`Unknown add kind "${kind}". Expected one of: block, variation, pattern, binding-source, hooked-block.`,
|
|
643
|
-
);
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
if (!name) {
|
|
647
|
-
throw new Error(
|
|
648
|
-
"`wp-typia add block` requires <name>. Usage: wp-typia add block <name> --template <basic|interactivity|persistence|compound>",
|
|
649
|
-
);
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
if (!flags.template) {
|
|
653
|
-
throw new Error(
|
|
654
|
-
"`wp-typia add block` requires --template <basic|interactivity|persistence|compound>.",
|
|
655
|
-
);
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
const result = await addRuntime.runAddBlockCommand({
|
|
659
|
-
blockName: name,
|
|
660
|
-
cwd,
|
|
661
|
-
dataStorageMode: readOptionalStringFlag(flags, "data-storage"),
|
|
662
|
-
persistencePolicy: readOptionalStringFlag(flags, "persistence-policy"),
|
|
663
|
-
templateId: readOptionalStringFlag(flags, "template") as
|
|
664
|
-
| "basic"
|
|
665
|
-
| "interactivity"
|
|
666
|
-
| "persistence"
|
|
667
|
-
| "compound",
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
const payload = buildAddCompletionPayload({
|
|
671
|
-
kind: "block",
|
|
672
|
-
projectDir: result.projectDir,
|
|
673
|
-
values: {
|
|
674
|
-
blockSlugs: result.blockSlugs.join(", "),
|
|
675
|
-
templateId: result.templateId,
|
|
676
|
-
},
|
|
677
|
-
});
|
|
678
|
-
if (emitOutput) {
|
|
679
|
-
printCompletionPayload(payload, { printLine });
|
|
680
|
-
}
|
|
681
|
-
return payload;
|
|
682
788
|
}
|
|
683
789
|
|
|
684
790
|
export async function executeTemplatesCommand(
|
|
@@ -720,8 +826,12 @@ export async function executeTemplatesCommand(
|
|
|
720
826
|
}
|
|
721
827
|
|
|
722
828
|
export async function executeDoctorCommand(cwd: string): Promise<void> {
|
|
723
|
-
|
|
724
|
-
|
|
829
|
+
try {
|
|
830
|
+
const { runDoctor } = await loadCliDoctorRuntime();
|
|
831
|
+
await runDoctor(cwd);
|
|
832
|
+
} catch (error) {
|
|
833
|
+
throw await wrapCliCommandError("doctor", error);
|
|
834
|
+
}
|
|
725
835
|
}
|
|
726
836
|
|
|
727
837
|
export async function loadAddWorkspaceBlockOptions(cwd: string) {
|
|
@@ -767,53 +877,60 @@ export async function executeMigrateCommand({
|
|
|
767
877
|
return;
|
|
768
878
|
}
|
|
769
879
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
880
|
+
try {
|
|
881
|
+
const argv = [command];
|
|
882
|
+
pushFlag(argv, "all", flags.all);
|
|
883
|
+
pushFlag(argv, "force", flags.force);
|
|
884
|
+
pushFlag(
|
|
885
|
+
argv,
|
|
886
|
+
"current-migration-version",
|
|
887
|
+
readOptionalLooseStringFlag(flags, "current-migration-version"),
|
|
888
|
+
);
|
|
889
|
+
pushFlag(argv, "migration-version", readOptionalLooseStringFlag(flags, "migration-version"));
|
|
890
|
+
pushFlag(
|
|
891
|
+
argv,
|
|
892
|
+
"from-migration-version",
|
|
893
|
+
readOptionalLooseStringFlag(flags, "from-migration-version"),
|
|
894
|
+
);
|
|
895
|
+
pushFlag(
|
|
896
|
+
argv,
|
|
897
|
+
"to-migration-version",
|
|
898
|
+
readOptionalLooseStringFlag(flags, "to-migration-version"),
|
|
899
|
+
);
|
|
900
|
+
pushFlag(argv, "iterations", readOptionalLooseStringFlag(flags, "iterations"));
|
|
901
|
+
pushFlag(argv, "seed", readOptionalLooseStringFlag(flags, "seed"));
|
|
902
|
+
|
|
903
|
+
const parsed = parseMigrationArgs(argv);
|
|
904
|
+
const lines: string[] | null = renderLine ? [] : null;
|
|
905
|
+
const captureLine = (line: string) => {
|
|
906
|
+
lines?.push(line);
|
|
907
|
+
if (renderLine) {
|
|
908
|
+
renderLine(line);
|
|
909
|
+
return;
|
|
910
|
+
}
|
|
911
|
+
console.log(line);
|
|
912
|
+
};
|
|
913
|
+
const result = await runMigrationCommand(parsed, cwd, {
|
|
914
|
+
prompt,
|
|
915
|
+
renderLine: captureLine,
|
|
916
|
+
});
|
|
796
917
|
if (renderLine) {
|
|
797
|
-
|
|
798
|
-
|
|
918
|
+
return result && typeof result === "object" && "cancelled" in result && result.cancelled === true
|
|
919
|
+
? undefined
|
|
920
|
+
: buildMigrationCompletionPayload({
|
|
921
|
+
command: parsed.command ?? "plan",
|
|
922
|
+
lines: lines ?? [],
|
|
923
|
+
});
|
|
799
924
|
}
|
|
800
|
-
console.log(line);
|
|
801
|
-
};
|
|
802
|
-
const result = await runMigrationCommand(parsed, cwd, {
|
|
803
|
-
prompt,
|
|
804
|
-
renderLine: captureLine,
|
|
805
|
-
});
|
|
806
|
-
if (renderLine) {
|
|
807
|
-
return result && typeof result === "object" && "cancelled" in result && result.cancelled === true
|
|
808
|
-
? undefined
|
|
809
|
-
: buildMigrationCompletionPayload({
|
|
810
|
-
command: parsed.command ?? "plan",
|
|
811
|
-
lines: lines ?? [],
|
|
812
|
-
});
|
|
813
|
-
}
|
|
814
925
|
|
|
815
|
-
|
|
816
|
-
|
|
926
|
+
if (result && typeof result === "object" && "cancelled" in result && result.cancelled === true) {
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
} catch (error) {
|
|
930
|
+
if (!shouldWrapCliCommandError({ renderLine })) {
|
|
931
|
+
throw error;
|
|
932
|
+
}
|
|
933
|
+
throw await wrapCliCommandError("migrate", error);
|
|
817
934
|
}
|
|
818
935
|
}
|
|
819
936
|
|
package/src/ui/add-flow-model.ts
CHANGED
|
@@ -11,6 +11,8 @@ export const addFlowSchema = z.object({
|
|
|
11
11
|
anchor: z.string().optional(),
|
|
12
12
|
block: z.string().optional(),
|
|
13
13
|
"data-storage": z.string().optional(),
|
|
14
|
+
"external-layer-id": z.string().optional(),
|
|
15
|
+
"external-layer-source": z.string().optional(),
|
|
14
16
|
kind: z
|
|
15
17
|
.enum(["block", "variation", "pattern", "binding-source", "hooked-block"])
|
|
16
18
|
.default("block"),
|
|
@@ -116,5 +118,17 @@ export function sanitizeAddSubmitValues(values: AddFlowValues): Record<string, u
|
|
|
116
118
|
}
|
|
117
119
|
}
|
|
118
120
|
|
|
121
|
+
if ((values.kind ?? "block") === "block") {
|
|
122
|
+
for (const hiddenFieldName of ["external-layer-source", "external-layer-id"] as const) {
|
|
123
|
+
const value = values[hiddenFieldName];
|
|
124
|
+
if (typeof value === "string") {
|
|
125
|
+
const trimmed = value.trim();
|
|
126
|
+
if (trimmed.length > 0) {
|
|
127
|
+
sanitized[hiddenFieldName] = trimmed;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
119
133
|
return sanitized;
|
|
120
134
|
}
|
package/src/ui/add-flow.tsx
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
|
|
11
11
|
export const createFlowSchema = z.object({
|
|
12
12
|
"data-storage": z.string().optional(),
|
|
13
|
+
"external-layer-id": z.string().optional(),
|
|
14
|
+
"external-layer-source": z.string().optional(),
|
|
13
15
|
namespace: z.string().optional(),
|
|
14
16
|
"no-install": z.boolean().default(false),
|
|
15
17
|
"package-manager": z.string().optional(),
|
|
@@ -82,6 +84,24 @@ export function isCreatePersistenceTemplate(template?: string): boolean {
|
|
|
82
84
|
return template === "persistence" || template === "compound";
|
|
83
85
|
}
|
|
84
86
|
|
|
87
|
+
function supportsCreateExternalLayers(template?: string): boolean {
|
|
88
|
+
return (
|
|
89
|
+
template === "basic" ||
|
|
90
|
+
template === "interactivity" ||
|
|
91
|
+
template === "persistence" ||
|
|
92
|
+
template === "compound"
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function normalizeOptionalHiddenString(value?: string): string | undefined {
|
|
97
|
+
if (typeof value !== "string") {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const trimmed = value.trim();
|
|
102
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
103
|
+
}
|
|
104
|
+
|
|
85
105
|
export function getVisibleCreateFieldNames(
|
|
86
106
|
values: Partial<CreateFlowValues>,
|
|
87
107
|
): Array<CreateFieldName> {
|
|
@@ -113,12 +133,22 @@ export function getCreateScrollTop(options: {
|
|
|
113
133
|
}
|
|
114
134
|
|
|
115
135
|
export function sanitizeCreateSubmitValues(values: CreateFlowValues): CreateFlowValues {
|
|
136
|
+
const normalizedValues: CreateFlowValues = {
|
|
137
|
+
...values,
|
|
138
|
+
"external-layer-id": supportsCreateExternalLayers(values.template)
|
|
139
|
+
? normalizeOptionalHiddenString(values["external-layer-id"])
|
|
140
|
+
: undefined,
|
|
141
|
+
"external-layer-source": supportsCreateExternalLayers(values.template)
|
|
142
|
+
? normalizeOptionalHiddenString(values["external-layer-source"])
|
|
143
|
+
: undefined,
|
|
144
|
+
};
|
|
145
|
+
|
|
116
146
|
if (isCreatePersistenceTemplate(values.template)) {
|
|
117
|
-
return
|
|
147
|
+
return normalizedValues;
|
|
118
148
|
}
|
|
119
149
|
|
|
120
150
|
return {
|
|
121
|
-
...
|
|
151
|
+
...normalizedValues,
|
|
122
152
|
"data-storage": undefined,
|
|
123
153
|
"persistence-policy": undefined,
|
|
124
154
|
};
|