@pikku/cli 0.12.34 → 0.12.35
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/console-app/assets/index-BOM3RFeu.js +233 -0
- package/console-app/index.html +1 -1
- package/dist/.pikku/agent/pikku-agent-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.d.ts +1 -1
- package/dist/.pikku/channel/pikku-channel-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-channel.js +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-types.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings-meta.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli-wirings.gen.js +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.d.ts +1 -1
- package/dist/.pikku/cli/pikku-cli.gen.js +1 -1
- package/dist/.pikku/console/pikku-node-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.d.ts +1 -1
- package/dist/.pikku/function/pikku-function-types.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.js +1 -1
- package/dist/.pikku/function/pikku-functions-meta.gen.json +180 -180
- package/dist/.pikku/function/pikku-functions.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-types.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings-meta.gen.js +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.d.ts +1 -1
- package/dist/.pikku/http/pikku-http-wirings.gen.js +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.d.ts +1 -1
- package/dist/.pikku/mcp/pikku-mcp-types.gen.js +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.d.ts +1 -1
- package/dist/.pikku/pikku-bootstrap.gen.js +1 -1
- package/dist/.pikku/pikku-meta-service.gen.d.ts +1 -1
- package/dist/.pikku/pikku-meta-service.gen.js +1 -1
- package/dist/.pikku/pikku-services.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.d.ts +1 -1
- package/dist/.pikku/pikku-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-types.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings-meta.gen.js +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.d.ts +1 -1
- package/dist/.pikku/queue/pikku-queue-workers-wirings.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.js +1 -1
- package/dist/.pikku/rpc/pikku-rpc-wirings-meta.internal.gen.json +4 -4
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.d.ts +1 -1
- package/dist/.pikku/scheduler/pikku-scheduler-types.gen.js +1 -1
- package/dist/.pikku/schemas/register.gen.js +13 -13
- package/dist/.pikku/secrets/pikku-secret-types.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secret-types.gen.js +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.d.ts +1 -1
- package/dist/.pikku/secrets/pikku-secrets.gen.js +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.d.ts +1 -1
- package/dist/.pikku/trigger/pikku-trigger-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variable-types.gen.js +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.d.ts +1 -1
- package/dist/.pikku/variables/pikku-variables.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.d.ts +1 -1
- package/dist/.pikku/workflow/pikku-workflow-types.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings-meta.gen.js +1 -1
- package/dist/.pikku/workflow/pikku-workflow-wirings.gen.js +1 -1
- package/dist/bin/pikku-bin.mjs +2 -2
- package/dist/src/functions/db/annotation-parser.d.ts +27 -16
- package/dist/src/functions/db/annotation-parser.js +50 -110
- package/dist/src/functions/db/coercion-plugin.d.ts +1 -1
- package/dist/src/functions/db/coercion-plugin.js +4 -0
- package/dist/src/functions/db/db-codegen.d.ts +13 -1
- package/dist/src/functions/db/db-codegen.js +142 -31
- package/dist/src/functions/db/db-introspector.d.ts +6 -0
- package/dist/src/functions/db/local-db.js +96 -78
- package/dist/src/functions/db/postgres/postgres-introspector.js +2 -0
- package/dist/src/functions/db/zod-codegen.d.ts +38 -0
- package/dist/src/functions/db/zod-codegen.js +144 -32
- package/dist/src/scaffold/rpc-remote.gen.js +1 -1
- package/package.json +1 -1
- package/console-app/assets/index-DsW0T00Z.js +0 -233
|
@@ -1,11 +1,40 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Canonical map of `format` tokens (authored in `db/annotations.ts`) to the zod
|
|
5
|
+
* expression they emit. These are all *string* refinements — they do not change
|
|
6
|
+
* the column's TypeScript type (it stays `string`), only the runtime validator.
|
|
7
|
+
* This is the single source of truth: `annotation-parser` imports it to validate
|
|
8
|
+
* authored values and `db-codegen` imports the key list to emit the `format`
|
|
9
|
+
* union in `ColumnEntry`. All confirmed present in zod 4.
|
|
10
|
+
*/
|
|
11
|
+
export const ZOD_FORMATS = {
|
|
12
|
+
email: 'z.email()',
|
|
13
|
+
url: 'z.url()',
|
|
14
|
+
emoji: 'z.emoji()',
|
|
15
|
+
e164: 'z.e164()',
|
|
16
|
+
jwt: 'z.jwt()',
|
|
17
|
+
cuid: 'z.cuid()',
|
|
18
|
+
cuid2: 'z.cuid2()',
|
|
19
|
+
ulid: 'z.ulid()',
|
|
20
|
+
nanoid: 'z.nanoid()',
|
|
21
|
+
base64: 'z.base64()',
|
|
22
|
+
base64url: 'z.base64url()',
|
|
23
|
+
ipv4: 'z.ipv4()',
|
|
24
|
+
ipv6: 'z.ipv6()',
|
|
25
|
+
cidrv4: 'z.cidrv4()',
|
|
26
|
+
cidrv6: 'z.cidrv6()',
|
|
27
|
+
isoDate: 'z.iso.date()',
|
|
28
|
+
isoTime: 'z.iso.time()',
|
|
29
|
+
isoDatetime: 'z.iso.datetime()',
|
|
30
|
+
isoDuration: 'z.iso.duration()',
|
|
31
|
+
};
|
|
3
32
|
const INTERFACE_RE = /export\s+interface\s+(\w+)\s*\{([^}]*)\}/g;
|
|
4
33
|
const FIELD_RE = /^\s*(\w+)\s*:\s*(.+?)\s*$/gm;
|
|
5
34
|
export function generateZodTypes(options) {
|
|
6
35
|
const src = readFileSync(options.schemaFile, 'utf8');
|
|
7
36
|
const tables = parseTables(src);
|
|
8
|
-
const body = emitZodModule(tables);
|
|
37
|
+
const body = emitZodModule(tables, options.formats ?? {});
|
|
9
38
|
let existing = null;
|
|
10
39
|
try {
|
|
11
40
|
existing = readFileSync(options.outFile, 'utf8');
|
|
@@ -39,7 +68,7 @@ function parseTables(src) {
|
|
|
39
68
|
}
|
|
40
69
|
return tables;
|
|
41
70
|
}
|
|
42
|
-
function emitZodModule(tables) {
|
|
71
|
+
function emitZodModule(tables, formats) {
|
|
43
72
|
const lines = [];
|
|
44
73
|
lines.push('// Generated by @pikku/cli — do not edit by hand.');
|
|
45
74
|
lines.push('// Run `pikku db migrate` to refresh.');
|
|
@@ -49,8 +78,9 @@ function emitZodModule(tables) {
|
|
|
49
78
|
for (const table of tables) {
|
|
50
79
|
const rowFields = [];
|
|
51
80
|
const insertFields = [];
|
|
81
|
+
const tableFormats = formats[table.name] ?? {};
|
|
52
82
|
for (const field of table.fields) {
|
|
53
|
-
const { schema, generated } = zodForType(field.type);
|
|
83
|
+
const { schema, generated } = zodForType(field.type, tableFormats[field.name]);
|
|
54
84
|
rowFields.push(` ${field.name}: ${schema},`);
|
|
55
85
|
insertFields.push(` ${field.name}: ${schema}${generated ? '.optional()' : ''},`);
|
|
56
86
|
}
|
|
@@ -83,7 +113,7 @@ function emitZodModule(tables) {
|
|
|
83
113
|
* and the column is insert-optional when `Insert` admits `undefined` (Kysely's
|
|
84
114
|
* encoding for default/auto/generated columns).
|
|
85
115
|
*/
|
|
86
|
-
function zodForType(tsType) {
|
|
116
|
+
function zodForType(tsType, format) {
|
|
87
117
|
let inner = tsType.trim();
|
|
88
118
|
let generated = false;
|
|
89
119
|
// Peel a single `Generated<…>` wrapper. For public bool/date columns this
|
|
@@ -102,9 +132,9 @@ function zodForType(tsType) {
|
|
|
102
132
|
if (unionIncludesUndefined(insertT)) {
|
|
103
133
|
generated = true;
|
|
104
134
|
}
|
|
105
|
-
return { schema: scalarSchema(selectT), generated };
|
|
135
|
+
return { schema: scalarSchema(selectT, format), generated };
|
|
106
136
|
}
|
|
107
|
-
return { schema: scalarSchema(inner), generated };
|
|
137
|
+
return { schema: scalarSchema(inner, format), generated };
|
|
108
138
|
}
|
|
109
139
|
/**
|
|
110
140
|
* Resolve a scalar/select type expression to a zod expression. Handles a
|
|
@@ -112,7 +142,7 @@ function zodForType(tsType) {
|
|
|
112
142
|
* and the known scalar bases. Unknown bases fall back to `z.unknown()` so
|
|
113
143
|
* generation stays total.
|
|
114
144
|
*/
|
|
115
|
-
function scalarSchema(tsType) {
|
|
145
|
+
function scalarSchema(tsType, format) {
|
|
116
146
|
let inner = tsType.trim();
|
|
117
147
|
// Defensive: a Select arg may itself be `Generated<…>` in older schemas.
|
|
118
148
|
const generatedMatch = inner.match(/^Generated<(.+)>$/);
|
|
@@ -129,44 +159,126 @@ function scalarSchema(tsType) {
|
|
|
129
159
|
inner = brandMatch[1].trim();
|
|
130
160
|
}
|
|
131
161
|
let schema;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
162
|
+
// A `format` override (e.g. `email`, `url`) replaces the string base with a
|
|
163
|
+
// refined string validator. `db-codegen` only emits a format hint for columns
|
|
164
|
+
// whose select type is plain `string`, so this never collides with Date/enum.
|
|
165
|
+
if (format) {
|
|
166
|
+
schema = ZOD_FORMATS[format];
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
// An enum column is emitted as a union of string literals, e.g.
|
|
170
|
+
// `'admin' | 'user'`. Detect it (after brand-unwrap + null-peel) and map to
|
|
171
|
+
// `z.enum([...])` (or `z.literal(...)` for a single value).
|
|
172
|
+
const literals = stringLiteralUnion(inner);
|
|
173
|
+
if (literals) {
|
|
174
|
+
schema =
|
|
175
|
+
literals.length === 1
|
|
176
|
+
? `z.literal('${literals[0]}')`
|
|
177
|
+
: `z.enum([${literals.map((l) => `'${l}'`).join(', ')}])`;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
switch (inner) {
|
|
181
|
+
case 'string':
|
|
182
|
+
schema = 'z.string()';
|
|
183
|
+
break;
|
|
184
|
+
case 'number':
|
|
185
|
+
schema = 'z.number()';
|
|
186
|
+
break;
|
|
187
|
+
case 'boolean':
|
|
188
|
+
schema = 'z.boolean()';
|
|
189
|
+
break;
|
|
190
|
+
case 'Date':
|
|
191
|
+
schema = 'z.date()';
|
|
192
|
+
break;
|
|
193
|
+
case 'Uuid':
|
|
194
|
+
schema = 'z.uuid()';
|
|
195
|
+
break;
|
|
196
|
+
case 'unknown':
|
|
197
|
+
schema = 'z.unknown()';
|
|
198
|
+
break;
|
|
199
|
+
default:
|
|
200
|
+
if (inner.endsWith('[]')) {
|
|
201
|
+
schema = `z.array(${scalarSchema(inner.slice(0, -2).trim())})`;
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
schema = 'z.unknown()';
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
154
207
|
}
|
|
155
|
-
|
|
208
|
+
}
|
|
156
209
|
}
|
|
157
210
|
if (nullable) {
|
|
158
211
|
schema += '.nullable()';
|
|
159
212
|
}
|
|
160
213
|
return schema;
|
|
161
214
|
}
|
|
162
|
-
/**
|
|
215
|
+
/**
|
|
216
|
+
* If `s` is a union of single-quoted string literals (`'a' | 'b' | 'c'`),
|
|
217
|
+
* return the unescaped-as-written label list; otherwise null. Quote-aware so a
|
|
218
|
+
* label containing `|` does not split the union. Re-emitting wraps each captured
|
|
219
|
+
* group back in quotes, so escaping is preserved verbatim.
|
|
220
|
+
*/
|
|
221
|
+
function stringLiteralUnion(s) {
|
|
222
|
+
const parts = splitUnion(s);
|
|
223
|
+
const labels = [];
|
|
224
|
+
for (const part of parts) {
|
|
225
|
+
const match = part.trim().match(/^'((?:[^'\\]|\\.)*)'$/);
|
|
226
|
+
if (!match)
|
|
227
|
+
return null;
|
|
228
|
+
labels.push(match[1]);
|
|
229
|
+
}
|
|
230
|
+
return labels.length > 0 ? labels : null;
|
|
231
|
+
}
|
|
232
|
+
/** Split a union on top-level `|`, skipping `|` inside `'…'` strings or `<>`/`()`. */
|
|
233
|
+
function splitUnion(s) {
|
|
234
|
+
const parts = [];
|
|
235
|
+
let depth = 0;
|
|
236
|
+
let inStr = false;
|
|
237
|
+
let start = 0;
|
|
238
|
+
for (let i = 0; i < s.length; i++) {
|
|
239
|
+
const char = s[i];
|
|
240
|
+
if (inStr) {
|
|
241
|
+
if (char === '\\')
|
|
242
|
+
i++;
|
|
243
|
+
else if (char === "'")
|
|
244
|
+
inStr = false;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
if (char === "'")
|
|
248
|
+
inStr = true;
|
|
249
|
+
else if (char === '<' || char === '(')
|
|
250
|
+
depth++;
|
|
251
|
+
else if (char === '>' || char === ')')
|
|
252
|
+
depth--;
|
|
253
|
+
else if (char === '|' && depth === 0) {
|
|
254
|
+
parts.push(s.slice(start, i));
|
|
255
|
+
start = i + 1;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
parts.push(s.slice(start));
|
|
259
|
+
return parts;
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Split the generic argument list of `Foo<a, b, c>` on top-level commas.
|
|
263
|
+
* Quote-aware so a comma inside an enum label literal (`'a,b'`) does not split.
|
|
264
|
+
*/
|
|
163
265
|
function splitGenericArgs(args) {
|
|
164
266
|
const parts = [];
|
|
165
267
|
let depth = 0;
|
|
268
|
+
let inStr = false;
|
|
166
269
|
let start = 0;
|
|
167
270
|
for (let i = 0; i < args.length; i++) {
|
|
168
271
|
const char = args[i];
|
|
169
|
-
if (
|
|
272
|
+
if (inStr) {
|
|
273
|
+
if (char === '\\')
|
|
274
|
+
i++;
|
|
275
|
+
else if (char === "'")
|
|
276
|
+
inStr = false;
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (char === "'")
|
|
280
|
+
inStr = true;
|
|
281
|
+
else if (char === '<')
|
|
170
282
|
depth++;
|
|
171
283
|
else if (char === '>')
|
|
172
284
|
depth--;
|