@drzl/cli 4.18.0 → 4.19.0
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/dist/{chunk-I4KMDCQR.js → chunk-V2IXXAC2.js} +13 -2
- package/dist/chunk-V2IXXAC2.js.map +1 -0
- package/dist/cli.cjs +593 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +41 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.cjs +12 -1
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.cts +4 -2
- package/dist/config.d.ts +4 -2
- package/dist/config.js +1 -1
- package/dist/dist-CZDVFYFW.js +559 -0
- package/dist/dist-CZDVFYFW.js.map +1 -0
- package/package.json +4 -3
- package/dist/chunk-I4KMDCQR.js.map +0 -1
package/dist/cli.cjs
CHANGED
|
@@ -1140,6 +1140,547 @@ var init_dist2 = __esm({
|
|
|
1140
1140
|
}
|
|
1141
1141
|
});
|
|
1142
1142
|
|
|
1143
|
+
// ../generator-effect/dist/index.js
|
|
1144
|
+
var dist_exports3 = {};
|
|
1145
|
+
__export(dist_exports3, {
|
|
1146
|
+
EffectGenerator: () => EffectGenerator,
|
|
1147
|
+
default: () => index_default3
|
|
1148
|
+
});
|
|
1149
|
+
function filter(expr, description) {
|
|
1150
|
+
return `${NS}.filter((v) => ${expr}, { description: ${JSON.stringify(description)} })`;
|
|
1151
|
+
}
|
|
1152
|
+
function piped(base, steps) {
|
|
1153
|
+
return steps.length ? `${base}.pipe(${steps.join(", ")})` : base;
|
|
1154
|
+
}
|
|
1155
|
+
function isUnknownExpr(expr) {
|
|
1156
|
+
return expr === UNKNOWN_EXPR;
|
|
1157
|
+
}
|
|
1158
|
+
function withNarrowedType(expr, ref2) {
|
|
1159
|
+
return `${expr} as unknown as ${NS}.Schema<${ref2}>`;
|
|
1160
|
+
}
|
|
1161
|
+
function numericBounds(c, checks) {
|
|
1162
|
+
let lo = c.min !== void 0 ? { fn: "greaterThanOrEqualTo", value: c.min } : void 0;
|
|
1163
|
+
let hi = c.max !== void 0 ? { fn: "lessThanOrEqualTo", value: c.max } : void 0;
|
|
1164
|
+
for (const k of checks.filter((x) => x.column === c.name && x.kind === "number")) {
|
|
1165
|
+
if (k.operator === ">=") lo = { fn: "greaterThanOrEqualTo", value: k.value };
|
|
1166
|
+
else if (k.operator === ">") lo = { fn: "greaterThan", value: k.value };
|
|
1167
|
+
else if (k.operator === "<=") hi = { fn: "lessThanOrEqualTo", value: k.value };
|
|
1168
|
+
else if (k.operator === "<") hi = { fn: "lessThan", value: k.value };
|
|
1169
|
+
}
|
|
1170
|
+
return [lo, hi].filter(Boolean).map((x) => `${NS}.${x.fn}(${x.value})`);
|
|
1171
|
+
}
|
|
1172
|
+
function foldedIntoBounds(c, checks) {
|
|
1173
|
+
if (c.arrayDimensions || c.shape) return /* @__PURE__ */ new Set();
|
|
1174
|
+
if (c.tsType !== "number" && c.tsType !== "bigint") return /* @__PURE__ */ new Set();
|
|
1175
|
+
return new Set(
|
|
1176
|
+
checks.filter(
|
|
1177
|
+
(k) => k.column === c.name && k.kind === "number" && k.operator !== "=" && k.operator !== "<>"
|
|
1178
|
+
)
|
|
1179
|
+
);
|
|
1180
|
+
}
|
|
1181
|
+
function nonFiniteBranches(c) {
|
|
1182
|
+
const { nan, infinity } = (0, import_validation_core6.nonFiniteAccepted)(c);
|
|
1183
|
+
return [
|
|
1184
|
+
...nan ? [`${NS}.Number.pipe(${filter("Number.isNaN(v)", "NaN, which this column stores")})`] : [],
|
|
1185
|
+
...infinity ? [`${NS}.Literal(Infinity, -Infinity)`] : []
|
|
1186
|
+
];
|
|
1187
|
+
}
|
|
1188
|
+
function withNonFinite(c, base) {
|
|
1189
|
+
const branches = nonFiniteBranches(c);
|
|
1190
|
+
return branches.length ? `${NS}.Union(${base}, ${branches.join(", ")})` : base;
|
|
1191
|
+
}
|
|
1192
|
+
function dateExpr(mode, coerceDates) {
|
|
1193
|
+
const plain = `${NS}.ValidDateFromSelf`;
|
|
1194
|
+
if (coerceDates === "none") return plain;
|
|
1195
|
+
const fromString = piped(`${NS}.String`, [
|
|
1196
|
+
`${NS}.pattern(new RegExp(${JSON.stringify(import_validation_core6.COERCIBLE_DATE_STRING)}))`,
|
|
1197
|
+
filter((0, import_validation_core6.parsesToADate)("new Date(v)"), "a date the runtime can parse")
|
|
1198
|
+
]);
|
|
1199
|
+
const fromNumber = piped(`${NS}.Number`, [
|
|
1200
|
+
filter((0, import_validation_core6.parsesToADate)("new Date(v)"), "a date the runtime can parse")
|
|
1201
|
+
]);
|
|
1202
|
+
const union = `${NS}.Union(${plain}, ${fromString}, ${fromNumber})`;
|
|
1203
|
+
if (coerceDates === "all") return union;
|
|
1204
|
+
return mode === "select" ? plain : union;
|
|
1205
|
+
}
|
|
1206
|
+
function capSteps(c, mode) {
|
|
1207
|
+
const steps = [];
|
|
1208
|
+
if (c.shape?.kind === "byteString") {
|
|
1209
|
+
const n = c.shape.length;
|
|
1210
|
+
if (!n) return steps;
|
|
1211
|
+
return mode === "select" ? [filter(`${import_validation_core6.CODEPOINT_LENGTH} <= ${n}`, `at most ${n} characters`)] : [filter(`new TextEncoder().encode(v).length <= ${n}`, `at most ${n} bytes`)];
|
|
1212
|
+
}
|
|
1213
|
+
if (c.maxLength) {
|
|
1214
|
+
steps.push(
|
|
1215
|
+
filter(`${import_validation_core6.CODEPOINT_LENGTH} <= ${c.maxLength}`, `at most ${c.maxLength} characters`)
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
if (c.maxBytes) {
|
|
1219
|
+
steps.push(
|
|
1220
|
+
filter(`new TextEncoder().encode(v).length <= ${c.maxBytes}`, `at most ${c.maxBytes} bytes`)
|
|
1221
|
+
);
|
|
1222
|
+
}
|
|
1223
|
+
return steps;
|
|
1224
|
+
}
|
|
1225
|
+
function lengthSteps(c, lengths) {
|
|
1226
|
+
if (c.arrayDimensions || c.shape) return [];
|
|
1227
|
+
return lengths.filter((k) => k.column === c.name).map(
|
|
1228
|
+
(k) => filter(
|
|
1229
|
+
`${import_validation_core6.CODEPOINT_LENGTH} ${OPS[k.operator]} ${k.value}`,
|
|
1230
|
+
`${k.name ? `${k.name}: ` : ""}length(${c.name}) ${k.operator} ${k.value}`
|
|
1231
|
+
)
|
|
1232
|
+
);
|
|
1233
|
+
}
|
|
1234
|
+
function cardinalitySteps(c, cardinalities) {
|
|
1235
|
+
if (!c.arrayDimensions) return [];
|
|
1236
|
+
return cardinalities.filter((k) => k.column === c.name).map(
|
|
1237
|
+
(k) => filter(
|
|
1238
|
+
`v.length ${OPS[k.operator]} ${k.value}`,
|
|
1239
|
+
`${k.name ? `${k.name}: ` : ""}cardinality(${c.name}) ${k.operator} ${k.value}`
|
|
1240
|
+
)
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
function checkSteps(c, checks) {
|
|
1244
|
+
if (c.arrayDimensions || c.shape) return [];
|
|
1245
|
+
const folded = foldedIntoBounds(c, checks);
|
|
1246
|
+
return checks.filter((k) => k.column === c.name && !folded.has(k)).map((k) => {
|
|
1247
|
+
const literal = k.kind === "string" ? JSON.stringify(k.value) : k.value;
|
|
1248
|
+
return filter(
|
|
1249
|
+
`v ${OPS[k.operator]} ${literal}`,
|
|
1250
|
+
`${k.name ? `${k.name}: ` : ""}${c.name} ${k.operator} ${k.value}`
|
|
1251
|
+
);
|
|
1252
|
+
});
|
|
1253
|
+
}
|
|
1254
|
+
function hasNoRuntimeType(c) {
|
|
1255
|
+
return c.tsType === "any" || c.shape?.kind === "custom" || c.shape?.kind === "json";
|
|
1256
|
+
}
|
|
1257
|
+
function shapeExpr(c, mode, replaced = false) {
|
|
1258
|
+
const s = c.shape;
|
|
1259
|
+
if (!s) return void 0;
|
|
1260
|
+
switch (s.kind) {
|
|
1261
|
+
case "json":
|
|
1262
|
+
return replaced ? UNKNOWN_EXPR : JSON_CONST;
|
|
1263
|
+
case "custom":
|
|
1264
|
+
return UNKNOWN_EXPR;
|
|
1265
|
+
case "buffer":
|
|
1266
|
+
return `${NS}.Uint8ArrayFromSelf`;
|
|
1267
|
+
case "tuple":
|
|
1268
|
+
return `${NS}.Tuple(${Array.from({ length: s.length }, () => `${NS}.Number`).join(", ")})`;
|
|
1269
|
+
case "numberObject":
|
|
1270
|
+
return `${NS}.Struct({ ${s.fields.map((f) => `${f}: ${NS}.Number`).join(", ")} })`;
|
|
1271
|
+
case "numberVector":
|
|
1272
|
+
return piped(
|
|
1273
|
+
`${NS}.Array(${NS}.Number)`,
|
|
1274
|
+
s.length ? [filter(`v.length === ${s.length}`, `exactly ${s.length} elements`)] : []
|
|
1275
|
+
);
|
|
1276
|
+
case "bitstring":
|
|
1277
|
+
return piped(`${NS}.String`, [
|
|
1278
|
+
`${NS}.pattern(/^[01]*$/)`,
|
|
1279
|
+
...s.length ? [
|
|
1280
|
+
s.exact ? filter(`v.length === ${s.length}`, `exactly ${s.length} binary digits`) : filter(`v.length <= ${s.length}`, `at most ${s.length} binary digits`)
|
|
1281
|
+
] : []
|
|
1282
|
+
]);
|
|
1283
|
+
case "byteString":
|
|
1284
|
+
return piped(`${NS}.String`, capSteps(c, mode));
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
function exprForColumn(c, mode, coerceDates, checks, sets, lengths, replaced) {
|
|
1288
|
+
const shaped = shapeExpr(c, mode, replaced);
|
|
1289
|
+
if (shaped) return shaped;
|
|
1290
|
+
const set = sets.find((x) => x.column === c.name);
|
|
1291
|
+
if (set) {
|
|
1292
|
+
const values = set.values.map((v) => set.kind === "string" ? JSON.stringify(v) : v);
|
|
1293
|
+
return `${NS}.Literal(${values.join(", ")})`;
|
|
1294
|
+
}
|
|
1295
|
+
if (c.arrayDimensions) checks = [];
|
|
1296
|
+
if (c.enumValues && c.enumValues.length) {
|
|
1297
|
+
return `${NS}.Literal(${c.enumValues.map((v) => JSON.stringify(v)).join(", ")})`;
|
|
1298
|
+
}
|
|
1299
|
+
const eq = checks.find((k) => k.column === c.name && k.operator === "=");
|
|
1300
|
+
if (eq && !c.shape) {
|
|
1301
|
+
return `${NS}.Literal(${eq.kind === "string" ? JSON.stringify(eq.value) : eq.value})`;
|
|
1302
|
+
}
|
|
1303
|
+
const rest = [...checkSteps(c, checks), ...lengthSteps(c, lengths)];
|
|
1304
|
+
switch (c.tsType) {
|
|
1305
|
+
case "string": {
|
|
1306
|
+
const base = c.format === "uuid" ? `${NS}.UUID` : `${NS}.String`;
|
|
1307
|
+
const pattern = c.format && c.format !== "uuid" && import_validation_core6.COLUMN_FORMATS[c.format] ? [`${NS}.pattern(new RegExp(${JSON.stringify(import_validation_core6.COLUMN_FORMATS[c.format])}))`] : [];
|
|
1308
|
+
return piped(base, [...pattern, ...capSteps(c, mode), ...rest]);
|
|
1309
|
+
}
|
|
1310
|
+
case "number": {
|
|
1311
|
+
const base = (0, import_validation_core6.isIntegerColumn)(c) ? `${NS}.Int` : `${NS}.Finite`;
|
|
1312
|
+
return withNonFinite(c, piped(base, [...numericBounds(c, checks), ...rest]));
|
|
1313
|
+
}
|
|
1314
|
+
case "bigint":
|
|
1315
|
+
return piped(`${NS}.BigIntFromSelf`, [
|
|
1316
|
+
...c.min !== void 0 ? [`${NS}.greaterThanOrEqualToBigInt(${c.min}n)`] : [],
|
|
1317
|
+
...c.max !== void 0 ? [`${NS}.lessThanOrEqualToBigInt(${c.max}n)`] : [],
|
|
1318
|
+
...rest
|
|
1319
|
+
]);
|
|
1320
|
+
case "boolean":
|
|
1321
|
+
return `${NS}.Boolean`;
|
|
1322
|
+
case "Date":
|
|
1323
|
+
return dateExpr(mode, coerceDates);
|
|
1324
|
+
case "Uint8Array":
|
|
1325
|
+
return `${NS}.Uint8ArrayFromSelf`;
|
|
1326
|
+
case "any":
|
|
1327
|
+
return UNKNOWN_EXPR;
|
|
1328
|
+
default:
|
|
1329
|
+
return UNKNOWN_EXPR;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
function renderField(c, mode, coerceDates, checks, sets, lengths, cardinalities, applyDefault, narrowRef) {
|
|
1333
|
+
let expr = exprForColumn(
|
|
1334
|
+
c,
|
|
1335
|
+
mode,
|
|
1336
|
+
coerceDates,
|
|
1337
|
+
checks,
|
|
1338
|
+
sets,
|
|
1339
|
+
lengths,
|
|
1340
|
+
!!narrowRef && hasNoRuntimeType(c)
|
|
1341
|
+
);
|
|
1342
|
+
const dims = c.arrayDimensions ?? 0;
|
|
1343
|
+
for (let i = 0; i < dims; i++) {
|
|
1344
|
+
expr = `${NS}.Array(${expr})`;
|
|
1345
|
+
if (i === dims - 1) expr = piped(expr, cardinalitySteps(c, cardinalities));
|
|
1346
|
+
}
|
|
1347
|
+
if (c.nullable && !isUnknownExpr(expr)) expr = `${NS}.NullOr(${expr})`;
|
|
1348
|
+
if (narrowRef) expr = withNarrowedType(expr, narrowRef);
|
|
1349
|
+
if (mode === "select") return expr;
|
|
1350
|
+
const wantsDefault = mode === "insert" && applyDefault && c.defaultValue !== void 0;
|
|
1351
|
+
if (wantsDefault) {
|
|
1352
|
+
return `${NS}.optionalWith(${expr}, { default: () => ${JSON.stringify(c.defaultValue)} })`;
|
|
1353
|
+
}
|
|
1354
|
+
if (mode === "update" || c.nullable || c.hasDefault) return `${NS}.optional(${expr})`;
|
|
1355
|
+
return expr;
|
|
1356
|
+
}
|
|
1357
|
+
function wantsRef(c, allColumns) {
|
|
1358
|
+
return allColumns || hasNoRuntimeType(c);
|
|
1359
|
+
}
|
|
1360
|
+
function renderObjectShape(cols, mode, coerceDates, checks, sets, lengths, cardinalities, typedJson, applyDefaults) {
|
|
1361
|
+
return cols.map((c) => {
|
|
1362
|
+
const ref2 = typedJson && wantsRef(c, !!typedJson.allColumns) ? `(typeof ${typedJson.table}.$infer${typedJson.mode === "insert" ? "Insert" : "Select"})[${JSON.stringify(c.name)}]` : void 0;
|
|
1363
|
+
const field2 = renderField(
|
|
1364
|
+
c,
|
|
1365
|
+
mode,
|
|
1366
|
+
coerceDates,
|
|
1367
|
+
checks,
|
|
1368
|
+
sets,
|
|
1369
|
+
lengths,
|
|
1370
|
+
cardinalities,
|
|
1371
|
+
applyDefaults,
|
|
1372
|
+
ref2
|
|
1373
|
+
);
|
|
1374
|
+
return ` ${JSON.stringify(c.name)}: ${field2},`;
|
|
1375
|
+
}).join("\n");
|
|
1376
|
+
}
|
|
1377
|
+
function rowSteps(rows, cols) {
|
|
1378
|
+
const present = new Set(cols.map((c) => c.name));
|
|
1379
|
+
return rows.filter((r) => present.has(r.left) && present.has(r.right)).map((r) => {
|
|
1380
|
+
const l = `o[${JSON.stringify(r.left)}]`;
|
|
1381
|
+
const rt = `o[${JSON.stringify(r.right)}]`;
|
|
1382
|
+
const msg = `${r.name ? `${r.name}: ` : ""}${r.left} ${r.operator} ${r.right}`;
|
|
1383
|
+
return `${NS}.filter((o) => ${l} == null || ${rt} == null || ${l} ${OPS[r.operator]} ${rt}, { description: ${JSON.stringify(msg)} })`;
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
function indentBlock(code, by = " ") {
|
|
1387
|
+
return code.split("\n").map((line) => line ? by + line : line).join("\n");
|
|
1388
|
+
}
|
|
1389
|
+
function parsedChecksFor(table) {
|
|
1390
|
+
const parsed = (table.checks ?? []).map((k) => (0, import_validation_core6.parseCheck)(k.expression, k.name));
|
|
1391
|
+
return {
|
|
1392
|
+
checks: parsed.flatMap((p) => p.ok ? p.checks : []),
|
|
1393
|
+
sets: parsed.flatMap((p) => p.ok ? p.sets ?? [] : []),
|
|
1394
|
+
rows: parsed.flatMap((p) => p.ok ? p.rows ?? [] : []),
|
|
1395
|
+
lengths: parsed.flatMap((p) => p.ok ? p.lengths ?? [] : []),
|
|
1396
|
+
cardinalities: parsed.flatMap((p) => p.ok ? p.cardinalities ?? [] : [])
|
|
1397
|
+
};
|
|
1398
|
+
}
|
|
1399
|
+
function nestedNodeCols(node, mode) {
|
|
1400
|
+
const all = mode === "insert" ? (0, import_validation_core6.insertColumns)(node.table) : (0, import_validation_core6.selectColumns)(node.table);
|
|
1401
|
+
return (0, import_validation_core6.nestedNodeColumns)(all, node);
|
|
1402
|
+
}
|
|
1403
|
+
function nestedNodes(node, into = []) {
|
|
1404
|
+
into.push(node);
|
|
1405
|
+
for (const arm of node.arms) nestedNodes(arm.child, into);
|
|
1406
|
+
return into;
|
|
1407
|
+
}
|
|
1408
|
+
function renderNestedObject(node, mode, coerceDates, typedJson, applyDefaults) {
|
|
1409
|
+
const cols = nestedNodeCols(node, mode);
|
|
1410
|
+
const { checks, sets, rows, lengths, cardinalities } = parsedChecksFor(node.table);
|
|
1411
|
+
const tj = typedJson ? { table: node.table.tsName, mode, allColumns: typedJson.allColumns } : void 0;
|
|
1412
|
+
const fields = renderObjectShape(
|
|
1413
|
+
cols,
|
|
1414
|
+
mode,
|
|
1415
|
+
coerceDates,
|
|
1416
|
+
checks,
|
|
1417
|
+
sets,
|
|
1418
|
+
lengths,
|
|
1419
|
+
cardinalities,
|
|
1420
|
+
tj,
|
|
1421
|
+
applyDefaults
|
|
1422
|
+
);
|
|
1423
|
+
const arms = node.arms.map((arm) => {
|
|
1424
|
+
const notes = (0, import_validation_core6.nestedArmNotes)(arm).map((n) => ` // ${n}
|
|
1425
|
+
`).join("");
|
|
1426
|
+
const child = renderNestedObject(arm.child, mode, coerceDates, typedJson, applyDefaults);
|
|
1427
|
+
const inner = arm.single ? `${NS}.NullOr(
|
|
1428
|
+
${indentBlock(indentBlock(child))}
|
|
1429
|
+
)` : `${NS}.Array(
|
|
1430
|
+
${indentBlock(indentBlock(child))}
|
|
1431
|
+
)`;
|
|
1432
|
+
return `${notes} ${JSON.stringify(arm.key)}: ${NS}.optional(${inner}),`;
|
|
1433
|
+
});
|
|
1434
|
+
const body = [fields, ...arms].filter(Boolean).join("\n");
|
|
1435
|
+
return piped(`${NS}.Struct({
|
|
1436
|
+
${body}
|
|
1437
|
+
})`, rowSteps(rows, cols));
|
|
1438
|
+
}
|
|
1439
|
+
function renderNestedSchemas(table, affix, coerceDates, typedJson, applyDefaults, plans) {
|
|
1440
|
+
const out = [];
|
|
1441
|
+
for (const mode of ["insert", "select"]) {
|
|
1442
|
+
const plan = plans[mode];
|
|
1443
|
+
if (!plan) continue;
|
|
1444
|
+
const name = (0, import_validation_core6.nestedSchemaName)(mode, table.tsName, affix);
|
|
1445
|
+
const tname = (0, import_validation_core6.nestedTypeName)(mode, table.tsName, affix);
|
|
1446
|
+
const expr = renderNestedObject(plan, mode, coerceDates, typedJson, applyDefaults);
|
|
1447
|
+
out.push(
|
|
1448
|
+
`export const ${name} = ${expr};
|
|
1449
|
+
|
|
1450
|
+
export type ${tname} = ${NS}.Schema.Type<typeof ${name}>;
|
|
1451
|
+
|
|
1452
|
+
export const ${STANDARD_PREFIX}${name} = ${NS}.standardSchemaV1(${name});`
|
|
1453
|
+
);
|
|
1454
|
+
}
|
|
1455
|
+
return out.length ? `
|
|
1456
|
+
${out.join("\n\n")}
|
|
1457
|
+
` : "";
|
|
1458
|
+
}
|
|
1459
|
+
function nestedPlansFor(table, analysis, depth) {
|
|
1460
|
+
const out = {};
|
|
1461
|
+
for (const mode of ["insert", "select"]) {
|
|
1462
|
+
if (mode === "insert" && table.readOnly) continue;
|
|
1463
|
+
const plan = (0, import_validation_core6.buildNestedPlan)(table, analysis.tables, analysis.relations ?? [], mode, depth);
|
|
1464
|
+
if (plan) out[mode] = plan;
|
|
1465
|
+
}
|
|
1466
|
+
return out;
|
|
1467
|
+
}
|
|
1468
|
+
function renderTableSchemas(table, affix, coerceDates, typedJson, applyDefaults = false, wantsDuplicateFinder = false, nested = {}) {
|
|
1469
|
+
const T = table.tsName;
|
|
1470
|
+
const insertCols = (0, import_validation_core6.insertColumns)(table);
|
|
1471
|
+
const updateCols = (0, import_validation_core6.updateColumns)(table);
|
|
1472
|
+
const selectCols = (0, import_validation_core6.selectColumns)(table);
|
|
1473
|
+
const { checks, sets, rows, lengths, cardinalities } = parsedChecksFor(table);
|
|
1474
|
+
const tj = typedJson ? { table: T, allColumns: typedJson.allColumns } : void 0;
|
|
1475
|
+
const modes = [
|
|
1476
|
+
["insert", insertCols],
|
|
1477
|
+
["update", updateCols],
|
|
1478
|
+
["select", selectCols]
|
|
1479
|
+
];
|
|
1480
|
+
const blocks = modes.map(([mode, cols]) => {
|
|
1481
|
+
const name = (0, import_validation_core6.schemaName)(mode, T, affix);
|
|
1482
|
+
const tname = (0, import_validation_core6.typeName)(mode, T, affix);
|
|
1483
|
+
const body = renderObjectShape(
|
|
1484
|
+
cols,
|
|
1485
|
+
mode,
|
|
1486
|
+
coerceDates,
|
|
1487
|
+
checks,
|
|
1488
|
+
sets,
|
|
1489
|
+
lengths,
|
|
1490
|
+
cardinalities,
|
|
1491
|
+
// The update schema references the insert-side inferred types: both describe a value going
|
|
1492
|
+
// in, and `$inferSelect` would name the post-default type for a column a write may omit.
|
|
1493
|
+
tj ? { ...tj, mode: mode === "select" ? "select" : "insert" } : void 0,
|
|
1494
|
+
applyDefaults
|
|
1495
|
+
);
|
|
1496
|
+
const expr = piped(`${NS}.Struct({
|
|
1497
|
+
${body}
|
|
1498
|
+
})`, rowSteps(rows, cols));
|
|
1499
|
+
return `export const ${name} = ${expr};
|
|
1500
|
+
|
|
1501
|
+
export type ${tname} = ${NS}.Schema.Type<typeof ${name}>;
|
|
1502
|
+
|
|
1503
|
+
export const ${STANDARD_PREFIX}${name} = ${NS}.standardSchemaV1(${name});`;
|
|
1504
|
+
});
|
|
1505
|
+
const nestedByTable = ["insert", "select"].flatMap((m) => {
|
|
1506
|
+
const plan = nested[m];
|
|
1507
|
+
return plan ? nestedNodes(plan).map((n) => [n.table.tsName, nestedNodeCols(n, m)]) : [];
|
|
1508
|
+
});
|
|
1509
|
+
const nestedCols = nestedByTable.flatMap(([, cs]) => cs);
|
|
1510
|
+
const referenced = /* @__PURE__ */ new Set();
|
|
1511
|
+
if (typedJson) {
|
|
1512
|
+
const all = !!typedJson.allColumns;
|
|
1513
|
+
if ([...insertCols, ...updateCols, ...selectCols].some((c) => wantsRef(c, all))) {
|
|
1514
|
+
referenced.add(T);
|
|
1515
|
+
}
|
|
1516
|
+
for (const [name, cs] of nestedByTable) {
|
|
1517
|
+
if (cs.some((c) => wantsRef(c, all))) referenced.add(name);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
const schemaImport = referenced.size ? `import type { ${[...referenced].join(", ")} } from '${typedJson.schemaSpecifier}';
|
|
1521
|
+
` : "";
|
|
1522
|
+
const needsJson = !typedJson && [...insertCols, ...updateCols, ...selectCols, ...nestedCols].some(
|
|
1523
|
+
(c) => c.shape?.kind === "json"
|
|
1524
|
+
);
|
|
1525
|
+
const finder = wantsDuplicateFinder ? (0, import_validation_core6.renderDuplicateFinder)(table, `findDuplicate${T}`, (0, import_validation_core6.typeName)("insert", T, affix)) : void 0;
|
|
1526
|
+
const duplicates = finder ? `
|
|
1527
|
+
${finder}
|
|
1528
|
+
` : "";
|
|
1529
|
+
const nestedCode = renderNestedSchemas(
|
|
1530
|
+
table,
|
|
1531
|
+
affix,
|
|
1532
|
+
coerceDates,
|
|
1533
|
+
typedJson,
|
|
1534
|
+
applyDefaults,
|
|
1535
|
+
nested
|
|
1536
|
+
);
|
|
1537
|
+
return `import * as ${NS} from 'effect/Schema';
|
|
1538
|
+
${schemaImport}${needsJson ? `
|
|
1539
|
+
${JSON_PREAMBLE}` : ""}
|
|
1540
|
+
${blocks.join("\n\n")}
|
|
1541
|
+
${nestedCode}${duplicates}`;
|
|
1542
|
+
}
|
|
1543
|
+
function buildHeader3(h) {
|
|
1544
|
+
if (h && h.enabled === false) return "";
|
|
1545
|
+
const text = h?.text?.trim();
|
|
1546
|
+
const lines = text ? text.split(/\r?\n/).map((l) => `// ${l}`) : [
|
|
1547
|
+
"// Generated by DRZL (@drzl/*)",
|
|
1548
|
+
"// Generated output is granted to you under your project's license.",
|
|
1549
|
+
"// You may use, copy, modify, and distribute without attribution."
|
|
1550
|
+
];
|
|
1551
|
+
return lines.join("\n") + "\n\n";
|
|
1552
|
+
}
|
|
1553
|
+
var import_validation_core6, DEFAULT_FILE_SUFFIX2, STANDARD_PREFIX, NS, OPS, JSON_CONST, JSON_PREAMBLE, UNKNOWN_EXPR, EffectGenerator, index_default3;
|
|
1554
|
+
var init_dist3 = __esm({
|
|
1555
|
+
"../generator-effect/dist/index.js"() {
|
|
1556
|
+
"use strict";
|
|
1557
|
+
import_validation_core6 = require("@drzl/validation-core");
|
|
1558
|
+
DEFAULT_FILE_SUFFIX2 = ".effect.ts";
|
|
1559
|
+
STANDARD_PREFIX = "Standard";
|
|
1560
|
+
NS = "Schema";
|
|
1561
|
+
OPS = {
|
|
1562
|
+
">=": ">=",
|
|
1563
|
+
">": ">",
|
|
1564
|
+
"<=": "<=",
|
|
1565
|
+
"<": "<",
|
|
1566
|
+
"=": "===",
|
|
1567
|
+
"<>": "!=="
|
|
1568
|
+
};
|
|
1569
|
+
JSON_CONST = "DrzlJsonValue";
|
|
1570
|
+
JSON_PREAMBLE = `type ${JSON_CONST}Type =
|
|
1571
|
+
| string
|
|
1572
|
+
| number
|
|
1573
|
+
| boolean
|
|
1574
|
+
| null
|
|
1575
|
+
| readonly ${JSON_CONST}Type[]
|
|
1576
|
+
| { readonly [key: string]: ${JSON_CONST}Type };
|
|
1577
|
+
|
|
1578
|
+
const ${JSON_CONST}: ${NS}.Schema<${JSON_CONST}Type, unknown> = ${NS}.suspend(() =>
|
|
1579
|
+
${NS}.Union(
|
|
1580
|
+
${NS}.String,
|
|
1581
|
+
${NS}.Finite,
|
|
1582
|
+
${NS}.Boolean,
|
|
1583
|
+
${NS}.Null,
|
|
1584
|
+
${NS}.Array(${JSON_CONST}),
|
|
1585
|
+
// The plain-object test comes before the record, not after it. \`Schema.Record\` rebuilds its
|
|
1586
|
+
// output, so a check placed after it inspects that new object and reports every input as
|
|
1587
|
+
// plain. A Date sailed through: it has no own enumerable keys, so the record accepted it and
|
|
1588
|
+
// rebuilt it as \`{}\`.
|
|
1589
|
+
${NS}.Unknown.pipe(
|
|
1590
|
+
${NS}.filter(
|
|
1591
|
+
(o) => {
|
|
1592
|
+
if (typeof o !== 'object' || o === null || Array.isArray(o)) return false;
|
|
1593
|
+
const p = Object.getPrototypeOf(o);
|
|
1594
|
+
return p === Object.prototype || p === null;
|
|
1595
|
+
},
|
|
1596
|
+
{ description: 'a plain object' }
|
|
1597
|
+
),
|
|
1598
|
+
${NS}.compose(${NS}.Record({ key: ${NS}.String, value: ${JSON_CONST} }), { strict: false })
|
|
1599
|
+
)
|
|
1600
|
+
)
|
|
1601
|
+
);
|
|
1602
|
+
`;
|
|
1603
|
+
UNKNOWN_EXPR = `${NS}.Unknown`;
|
|
1604
|
+
EffectGenerator = class {
|
|
1605
|
+
constructor(analysis) {
|
|
1606
|
+
this.analysis = analysis;
|
|
1607
|
+
this.library = "effect";
|
|
1608
|
+
}
|
|
1609
|
+
async generate(opts) {
|
|
1610
|
+
const fs3 = await import("fs/promises");
|
|
1611
|
+
const path6 = await import("path");
|
|
1612
|
+
const out = path6.resolve(process.cwd(), opts.outDir);
|
|
1613
|
+
const files = [];
|
|
1614
|
+
await fs3.mkdir(out, { recursive: true });
|
|
1615
|
+
const affix = (0, import_validation_core6.resolveAffix)(opts);
|
|
1616
|
+
const coerceDates = opts.coerceDates ?? "input";
|
|
1617
|
+
const fileSuffix = opts.fileSuffix ?? DEFAULT_FILE_SUFFIX2;
|
|
1618
|
+
const wantsTypes = opts.typedJson || opts.typedColumns;
|
|
1619
|
+
const typedJson = wantsTypes && opts.schemaPath ? {
|
|
1620
|
+
schemaSpecifier: (0, import_validation_core6.resolveConfiguredImport)(
|
|
1621
|
+
opts.schemaPath,
|
|
1622
|
+
out,
|
|
1623
|
+
process.cwd(),
|
|
1624
|
+
opts.importExtension
|
|
1625
|
+
),
|
|
1626
|
+
allColumns: !!opts.typedColumns
|
|
1627
|
+
} : void 0;
|
|
1628
|
+
if (wantsTypes && !opts.schemaPath) {
|
|
1629
|
+
console.warn(
|
|
1630
|
+
"[drzl] typedJson was requested but the schema path is unknown, so json columns keep their wide type."
|
|
1631
|
+
);
|
|
1632
|
+
}
|
|
1633
|
+
const nestedDepth = opts.nestedSchemas ? (0, import_validation_core6.resolveNestedDepth)(opts.nestedDepth, (m) => console.warn(m)) : 0;
|
|
1634
|
+
for (const table of this.analysis.tables) {
|
|
1635
|
+
const filePath = path6.join(out, (0, import_validation_core6.moduleFileName)(table.tsName, fileSuffix));
|
|
1636
|
+
const code = renderTableSchemas(
|
|
1637
|
+
table,
|
|
1638
|
+
affix,
|
|
1639
|
+
coerceDates,
|
|
1640
|
+
typedJson,
|
|
1641
|
+
!!opts.applyDefaults,
|
|
1642
|
+
!!opts?.duplicateFinder,
|
|
1643
|
+
opts.nestedSchemas ? nestedPlansFor(table, this.analysis, nestedDepth) : {}
|
|
1644
|
+
);
|
|
1645
|
+
const formatted = await (0, import_validation_core6.formatCode)(
|
|
1646
|
+
buildHeader3(opts.outputHeader) + code,
|
|
1647
|
+
filePath,
|
|
1648
|
+
opts.format
|
|
1649
|
+
);
|
|
1650
|
+
await fs3.writeFile(filePath, formatted, "utf8");
|
|
1651
|
+
files.push(filePath);
|
|
1652
|
+
}
|
|
1653
|
+
const indexPath = path6.join(out, "index.ts");
|
|
1654
|
+
const indexFormatted = await (0, import_validation_core6.formatCode)(
|
|
1655
|
+
buildHeader3(opts.outputHeader) + this.defaultIndex(this.analysis, opts),
|
|
1656
|
+
indexPath,
|
|
1657
|
+
opts.format
|
|
1658
|
+
);
|
|
1659
|
+
await fs3.writeFile(indexPath, indexFormatted, "utf8");
|
|
1660
|
+
files.push(indexPath);
|
|
1661
|
+
return files;
|
|
1662
|
+
}
|
|
1663
|
+
renderTable(table, opts) {
|
|
1664
|
+
return renderTableSchemas(
|
|
1665
|
+
table,
|
|
1666
|
+
(0, import_validation_core6.resolveAffix)(opts),
|
|
1667
|
+
opts?.coerceDates ?? "input",
|
|
1668
|
+
void 0,
|
|
1669
|
+
!!opts?.applyDefaults,
|
|
1670
|
+
!!opts?.duplicateFinder
|
|
1671
|
+
);
|
|
1672
|
+
}
|
|
1673
|
+
defaultIndex(analysis, opts) {
|
|
1674
|
+
const fileSuffix = opts.fileSuffix ?? DEFAULT_FILE_SUFFIX2;
|
|
1675
|
+
return analysis.tables.map(
|
|
1676
|
+
(t) => `export * from '${(0, import_validation_core6.moduleSpecifier)(t.tsName, fileSuffix, opts.importExtension)}';`
|
|
1677
|
+
).join("\n") + "\n";
|
|
1678
|
+
}
|
|
1679
|
+
};
|
|
1680
|
+
index_default3 = EffectGenerator;
|
|
1681
|
+
}
|
|
1682
|
+
});
|
|
1683
|
+
|
|
1143
1684
|
// src/cli.ts
|
|
1144
1685
|
var import_analyzer = require("@drzl/analyzer");
|
|
1145
1686
|
var import_generator_orpc = require("@drzl/generator-orpc");
|
|
@@ -1229,7 +1770,17 @@ var AffixSchema = import_zod.z.object({
|
|
|
1229
1770
|
}).strict();
|
|
1230
1771
|
var ImportExtensionSchema = import_zod.z.enum(import_validation_core.IMPORT_EXTENSIONS);
|
|
1231
1772
|
var GeneratorSchema = import_zod.z.object({
|
|
1232
|
-
kind: import_zod.z.enum([
|
|
1773
|
+
kind: import_zod.z.enum([
|
|
1774
|
+
"orpc",
|
|
1775
|
+
"trpc",
|
|
1776
|
+
"service",
|
|
1777
|
+
"zod",
|
|
1778
|
+
"valibot",
|
|
1779
|
+
"arktype",
|
|
1780
|
+
"typebox",
|
|
1781
|
+
"effect",
|
|
1782
|
+
"json-schema"
|
|
1783
|
+
]),
|
|
1233
1784
|
/**
|
|
1234
1785
|
* Overrides the top-level `importExtension` for this generator alone, for a project whose
|
|
1235
1786
|
* generated directories are compiled by different tsconfigs.
|
|
@@ -1563,6 +2114,7 @@ function computeGeneratorOutputDirs(cfg, cwd = process.cwd()) {
|
|
|
1563
2114
|
if (g.kind === "valibot") dirs.add(abs(g.path ?? "src/validators/valibot"));
|
|
1564
2115
|
if (g.kind === "arktype") dirs.add(abs(g.path ?? "src/validators/arktype"));
|
|
1565
2116
|
if (g.kind === "typebox") dirs.add(abs(g.path ?? "src/validators/typebox"));
|
|
2117
|
+
if (g.kind === "effect") dirs.add(abs(g.path ?? "src/validators/effect"));
|
|
1566
2118
|
if (g.kind === "json-schema") dirs.add(abs(g.path ?? "src/validators/json-schema"));
|
|
1567
2119
|
}
|
|
1568
2120
|
return [...dirs];
|
|
@@ -1979,7 +2531,7 @@ var shownThisProcess = false;
|
|
|
1979
2531
|
var tips = [
|
|
1980
2532
|
"Pair DRZL watch mode with drizzle-kit to keep schema & API synced.",
|
|
1981
2533
|
"Templatize your ORPC routers to roll out new endpoints safely.",
|
|
1982
|
-
"Need typed validators? Enable the zod, valibot, arktype, or
|
|
2534
|
+
"Need typed validators? Enable the zod, valibot, arktype, typebox, or effect generators.",
|
|
1983
2535
|
"Need JSON Schema or OpenAPI? The json-schema generator emits both, with no runtime dependency.",
|
|
1984
2536
|
"Use output headers to track generated files and trim noisy diffs."
|
|
1985
2537
|
];
|
|
@@ -2364,6 +2916,25 @@ program.command("generate").description("Run configured generators (drzl.config.
|
|
|
2364
2916
|
reportGeneratorFailure(g.kind, e);
|
|
2365
2917
|
process.exit(1);
|
|
2366
2918
|
}
|
|
2919
|
+
} else if (g.kind === "effect") {
|
|
2920
|
+
try {
|
|
2921
|
+
const { EffectGenerator: EffectGenerator2 } = await loadGenerator(
|
|
2922
|
+
"@drzl/generator-effect",
|
|
2923
|
+
() => Promise.resolve().then(() => (init_dist3(), dist_exports3))
|
|
2924
|
+
);
|
|
2925
|
+
const gen = new EffectGenerator2(analysis);
|
|
2926
|
+
const target = g.path ?? "src/validators/effect";
|
|
2927
|
+
const files = await gen.generate(
|
|
2928
|
+
validationOptions(g, cfg, target, { schemaTypes: true })
|
|
2929
|
+
);
|
|
2930
|
+
progress.stop();
|
|
2931
|
+
(0, import_ora.default)().succeed(import_chalk3.default.green(`Generated (effect): ${files.length} files`));
|
|
2932
|
+
files.forEach((f) => console.log(" -", import_chalk3.default.cyan(f)));
|
|
2933
|
+
} catch (e) {
|
|
2934
|
+
progress.stop();
|
|
2935
|
+
reportGeneratorFailure(g.kind, e);
|
|
2936
|
+
process.exit(1);
|
|
2937
|
+
}
|
|
2367
2938
|
}
|
|
2368
2939
|
}
|
|
2369
2940
|
if (driftBefore) {
|
|
@@ -2701,6 +3272,26 @@ program.command("watch").description("Watch schema and regenerate on changes").o
|
|
|
2701
3272
|
reportGeneratorFailure(g.kind, e);
|
|
2702
3273
|
return;
|
|
2703
3274
|
}
|
|
3275
|
+
} else if (g.kind === "effect") {
|
|
3276
|
+
try {
|
|
3277
|
+
const { EffectGenerator: EffectGenerator2 } = await loadGenerator(
|
|
3278
|
+
"@drzl/generator-effect",
|
|
3279
|
+
() => Promise.resolve().then(() => (init_dist3(), dist_exports3))
|
|
3280
|
+
);
|
|
3281
|
+
const gen = new EffectGenerator2(analysis);
|
|
3282
|
+
const target = g.path ?? "src/validators/effect";
|
|
3283
|
+
const files = await gen.generate(
|
|
3284
|
+
validationOptions(g, cfg, target, { schemaTypes: true })
|
|
3285
|
+
);
|
|
3286
|
+
opts.json ? console.log(JSON.stringify({ event: "generate_complete", kind: g.kind, files })) : console.log(
|
|
3287
|
+
import_chalk3.default.green(`Generated (effect): ${files.length} files`),
|
|
3288
|
+
files.map((f) => import_chalk3.default.cyan(f)).join(", ")
|
|
3289
|
+
);
|
|
3290
|
+
newFiles.push(...files);
|
|
3291
|
+
} catch (e) {
|
|
3292
|
+
reportGeneratorFailure(g.kind, e);
|
|
3293
|
+
return;
|
|
3294
|
+
}
|
|
2704
3295
|
} else if (g.kind === "json-schema") {
|
|
2705
3296
|
try {
|
|
2706
3297
|
const { JsonSchemaGenerator: JsonSchemaGenerator2 } = await loadGenerator(
|