wp-typia 0.16.0 → 0.16.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.
@@ -1,187 +1,205 @@
1
- import { useState } from "react";
1
+ import { createElement, useMemo } from "react";
2
2
 
3
- import { useRuntime } from "@bunli/runtime/app";
4
- import { Alert, SchemaForm } from "@bunli/tui";
5
- import { z } from "zod";
3
+ import {
4
+ Form,
5
+ type SelectOption,
6
+ useFormContext,
7
+ useTerminalDimensions,
8
+ } from "@bunli/tui";
6
9
 
7
10
  import { executeMigrateCommand } from "../runtime-bridge";
11
+ import { useAlternateBufferLifecycle } from "./alternate-buffer-lifecycle";
12
+ import {
13
+ type MigrateFlowValues,
14
+ getMigrateScrollTop,
15
+ getMigrateViewportHeight,
16
+ getVisibleMigrateFieldNames,
17
+ migrateFlowSchema,
18
+ sanitizeMigrateSubmitValues,
19
+ } from "./migrate-flow-model";
20
+ import {
21
+ FirstPartyCheckboxField,
22
+ FirstPartyScrollBox,
23
+ FirstPartySelectField,
24
+ FirstPartyTextField,
25
+ } from "./first-party-form";
26
+ import { getWrappedFieldNeighbors } from "./first-party-form-model";
8
27
 
9
- const migrateFlowSchema = z.object({
10
- all: z.boolean().default(false),
11
- command: z.enum([
12
- "init",
13
- "snapshot",
14
- "plan",
15
- "wizard",
16
- "diff",
17
- "scaffold",
18
- "verify",
19
- "doctor",
20
- "fixtures",
21
- "fuzz",
22
- ]),
23
- "current-migration-version": z.string().optional(),
24
- force: z.boolean().default(false),
25
- "from-migration-version": z.string().optional(),
26
- iterations: z.string().optional(),
27
- "migration-version": z.string().optional(),
28
- seed: z.string().optional(),
29
- "to-migration-version": z.string().optional(),
30
- });
31
-
32
- type MigrateFlowValues = z.infer<typeof migrateFlowSchema>;
28
+ const migrateCommandOptions: SelectOption[] = [
29
+ { name: "init", description: "Initialize migration config", value: "init" },
30
+ {
31
+ name: "snapshot",
32
+ description: "Capture the current schema snapshot",
33
+ value: "snapshot",
34
+ },
35
+ { name: "plan", description: "Preview migration work", value: "plan" },
36
+ {
37
+ name: "wizard",
38
+ description: "Guided migration preview",
39
+ value: "wizard",
40
+ },
41
+ { name: "diff", description: "Diff migration snapshots", value: "diff" },
42
+ {
43
+ name: "scaffold",
44
+ description: "Generate migration rules and artifacts",
45
+ value: "scaffold",
46
+ },
47
+ {
48
+ name: "verify",
49
+ description: "Verify generated migration fixtures",
50
+ value: "verify",
51
+ },
52
+ {
53
+ name: "doctor",
54
+ description: "Diagnose migration workspace health",
55
+ value: "doctor",
56
+ },
57
+ {
58
+ name: "fixtures",
59
+ description: "Refresh migration fixtures",
60
+ value: "fixtures",
61
+ },
62
+ { name: "fuzz", description: "Run migration fuzzing", value: "fuzz" },
63
+ ];
33
64
 
34
65
  type MigrateFlowProps = {
35
66
  cwd: string;
36
67
  initialValues: Partial<MigrateFlowValues>;
37
68
  };
38
69
 
39
- function sanitizeMigrateValues(values: MigrateFlowValues): Record<string, unknown> {
40
- return Object.fromEntries(
41
- Object.entries(values).flatMap(([key, value]) => {
42
- if (typeof value === "string" && value.trim().length === 0) {
43
- return [];
44
- }
45
- return [[key, value]];
46
- }),
47
- );
48
- }
70
+ type MigrateSelectFieldName = {
71
+ [K in keyof MigrateFlowValues]-?: MigrateFlowValues[K] extends string | undefined ? K : never;
72
+ }[keyof MigrateFlowValues];
49
73
 
50
- export function MigrateFlow({ cwd, initialValues }: MigrateFlowProps) {
51
- const runtime = useRuntime();
52
- const [errorMessage, setErrorMessage] = useState<string | null>(null);
74
+ type MigrateCheckboxFieldName = {
75
+ [K in keyof MigrateFlowValues]-?: MigrateFlowValues[K] extends boolean | undefined ? K : never;
76
+ }[keyof MigrateFlowValues];
53
77
 
54
- return (
55
- <>
56
- {errorMessage ? (
57
- <Alert message={errorMessage} title="Migrate failed" tone="danger" />
58
- ) : null}
59
- <SchemaForm
60
- fields={[
61
- {
62
- kind: "select",
63
- label: "Migration command",
64
- name: "command",
65
- options: [
66
- { name: "init", description: "Initialize migration config", value: "init" },
67
- {
68
- name: "snapshot",
69
- description: "Capture the current schema snapshot",
70
- value: "snapshot",
71
- },
72
- { name: "plan", description: "Preview migration work", value: "plan" },
73
- {
74
- name: "wizard",
75
- description: "Guided migration preview",
76
- value: "wizard",
77
- },
78
- { name: "diff", description: "Diff migration snapshots", value: "diff" },
79
- {
80
- name: "scaffold",
81
- description: "Generate migration rules and artifacts",
82
- value: "scaffold",
83
- },
84
- {
85
- name: "verify",
86
- description: "Verify generated migration fixtures",
87
- value: "verify",
88
- },
89
- {
90
- name: "doctor",
91
- description: "Diagnose migration workspace health",
92
- value: "doctor",
93
- },
94
- {
95
- name: "fixtures",
96
- description: "Refresh migration fixtures",
97
- value: "fixtures",
98
- },
99
- { name: "fuzz", description: "Run migration fuzzing", value: "fuzz" },
100
- ],
101
- required: true,
102
- },
103
- {
104
- kind: "text",
78
+ function MigrateFlowFields() {
79
+ const { activeFieldName, values } = useFormContext();
80
+ const { height: terminalHeight = 24 } = useTerminalDimensions();
81
+ const migrateValues = values as Partial<MigrateFlowValues>;
82
+ const command = migrateValues.command ?? "plan";
83
+ const viewportHeight = getMigrateViewportHeight(terminalHeight);
84
+ const scrollValues = useMemo(() => ({ command }), [command]);
85
+ const scrollTop = useMemo(
86
+ () =>
87
+ getMigrateScrollTop({
88
+ activeFieldName,
89
+ values: scrollValues,
90
+ viewportHeight,
91
+ }),
92
+ [activeFieldName, scrollValues, viewportHeight],
93
+ );
94
+ const visibleFields = new Set(getVisibleMigrateFieldNames(migrateValues));
95
+ const orderedVisibleFields = useMemo(
96
+ () => getVisibleMigrateFieldNames(migrateValues),
97
+ [migrateValues],
98
+ );
99
+
100
+ return createElement(
101
+ FirstPartyScrollBox,
102
+ { scrollTop, viewportHeight },
103
+ [
104
+ createElement(FirstPartySelectField, {
105
+ ...getWrappedFieldNeighbors(orderedVisibleFields, "command"),
106
+ key: "command",
107
+ label: "Migration command",
108
+ name: "command" satisfies MigrateSelectFieldName,
109
+ options: migrateCommandOptions,
110
+ }),
111
+ visibleFields.has("current-migration-version")
112
+ ? createElement(FirstPartyTextField, {
113
+ ...getWrappedFieldNeighbors(
114
+ orderedVisibleFields,
115
+ "current-migration-version",
116
+ ),
117
+ key: "current-migration-version",
105
118
  label: "Current migration version",
106
119
  name: "current-migration-version",
107
- visibleWhen: (values) => values.command === "init",
108
- },
109
- {
110
- kind: "text",
120
+ })
121
+ : null,
122
+ visibleFields.has("migration-version")
123
+ ? createElement(FirstPartyTextField, {
124
+ ...getWrappedFieldNeighbors(orderedVisibleFields, "migration-version"),
125
+ key: "migration-version",
111
126
  label: "Migration version",
112
127
  name: "migration-version",
113
- visibleWhen: (values) => values.command === "snapshot",
114
- },
115
- {
116
- kind: "text",
128
+ })
129
+ : null,
130
+ visibleFields.has("from-migration-version")
131
+ ? createElement(FirstPartyTextField, {
132
+ ...getWrappedFieldNeighbors(orderedVisibleFields, "from-migration-version"),
133
+ key: "from-migration-version",
117
134
  label: "From migration version",
118
135
  name: "from-migration-version",
119
- visibleWhen: (values) =>
120
- values.command === "plan" ||
121
- values.command === "diff" ||
122
- values.command === "scaffold" ||
123
- values.command === "verify" ||
124
- values.command === "doctor" ||
125
- values.command === "fixtures" ||
126
- values.command === "fuzz",
127
- },
128
- {
129
- kind: "text",
136
+ })
137
+ : null,
138
+ visibleFields.has("to-migration-version")
139
+ ? createElement(FirstPartyTextField, {
140
+ ...getWrappedFieldNeighbors(orderedVisibleFields, "to-migration-version"),
141
+ key: "to-migration-version",
130
142
  label: "To migration version",
131
143
  name: "to-migration-version",
132
- visibleWhen: (values) =>
133
- values.command === "plan" ||
134
- values.command === "diff" ||
135
- values.command === "scaffold" ||
136
- values.command === "fixtures",
137
- },
138
- {
139
- kind: "checkbox",
144
+ })
145
+ : null,
146
+ visibleFields.has("all")
147
+ ? createElement(FirstPartyCheckboxField, {
148
+ ...getWrappedFieldNeighbors(orderedVisibleFields, "all"),
149
+ key: "all",
140
150
  label: "All configured migration versions",
141
- name: "all",
142
- visibleWhen: (values) =>
143
- values.command === "verify" ||
144
- values.command === "doctor" ||
145
- values.command === "fixtures" ||
146
- values.command === "fuzz",
147
- },
148
- {
149
- kind: "checkbox",
151
+ name: "all" satisfies MigrateCheckboxFieldName,
152
+ })
153
+ : null,
154
+ visibleFields.has("force")
155
+ ? createElement(FirstPartyCheckboxField, {
156
+ ...getWrappedFieldNeighbors(orderedVisibleFields, "force"),
157
+ key: "force",
150
158
  label: "Force overwrite",
151
- name: "force",
152
- visibleWhen: (values) => values.command === "fixtures",
153
- },
154
- {
155
- kind: "text",
159
+ name: "force" satisfies MigrateCheckboxFieldName,
160
+ })
161
+ : null,
162
+ visibleFields.has("iterations")
163
+ ? createElement(FirstPartyTextField, {
164
+ ...getWrappedFieldNeighbors(orderedVisibleFields, "iterations"),
165
+ key: "iterations",
156
166
  label: "Iterations",
157
167
  name: "iterations",
158
- visibleWhen: (values) => values.command === "fuzz",
159
- },
160
- {
161
- kind: "text",
168
+ })
169
+ : null,
170
+ visibleFields.has("seed")
171
+ ? createElement(FirstPartyTextField, {
172
+ ...getWrappedFieldNeighbors(orderedVisibleFields, "seed"),
173
+ key: "seed",
162
174
  label: "Seed",
163
175
  name: "seed",
164
- visibleWhen: (values) => values.command === "fuzz",
165
- },
166
- ]}
167
- initialValues={initialValues}
168
- onCancel={() => runtime.exit()}
169
- onSubmit={async (values) => {
170
- try {
171
- setErrorMessage(null);
172
- await executeMigrateCommand({
173
- command: values.command,
174
- cwd,
175
- flags: sanitizeMigrateValues(values),
176
- });
177
- runtime.exit();
178
- } catch (error) {
179
- setErrorMessage(error instanceof Error ? error.message : String(error));
180
- }
181
- }}
182
- schema={migrateFlowSchema}
183
- title="Run wp-typia migration workflows"
184
- />
185
- </>
176
+ })
177
+ : null,
178
+ ],
179
+ );
180
+ }
181
+
182
+ export function MigrateFlow({ cwd, initialValues }: MigrateFlowProps) {
183
+ const { handleCancel, handleSubmit } = useAlternateBufferLifecycle("wp-typia migrate failed");
184
+
185
+ return (
186
+ <Form
187
+ initialValues={initialValues}
188
+ onCancel={handleCancel}
189
+ onSubmit={async (values) =>
190
+ handleSubmit(async () => {
191
+ const flags = sanitizeMigrateSubmitValues(values);
192
+ await executeMigrateCommand({
193
+ command: values.command,
194
+ cwd,
195
+ flags,
196
+ });
197
+ })
198
+ }
199
+ schema={migrateFlowSchema}
200
+ title="Run wp-typia migration workflows"
201
+ >
202
+ <MigrateFlowFields />
203
+ </Form>
186
204
  );
187
205
  }