sizuku 0.6.2 → 0.6.5
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/index.mjs +89 -18
- package/package.json +1 -2
package/dist/index.mjs
CHANGED
|
@@ -432,6 +432,66 @@ function extractRelationsFromSchema(code) {
|
|
|
432
432
|
});
|
|
433
433
|
}
|
|
434
434
|
//#endregion
|
|
435
|
+
//#region src/helper/parse-relation.ts
|
|
436
|
+
const RELATIONSHIPS = {
|
|
437
|
+
"zero-one": "|o",
|
|
438
|
+
one: "||",
|
|
439
|
+
"zero-many": "}o",
|
|
440
|
+
many: "}|"
|
|
441
|
+
};
|
|
442
|
+
function isRelationshipType(type) {
|
|
443
|
+
return type === "zero-one" || type === "one" || type === "zero-many" || type === "many";
|
|
444
|
+
}
|
|
445
|
+
const CARDINALITY = "(?:zero-one|one|zero-many|many)";
|
|
446
|
+
const RELATION_TYPE = `${CARDINALITY}-to-${CARDINALITY}(?:-optional)?`;
|
|
447
|
+
const RELATION_RE = new RegExp(String.raw`^@relation\s+(\w+)\.(\w+)\s+(\w+)\.(\w+)\s+(${RELATION_TYPE})$`);
|
|
448
|
+
function parseRelation(line) {
|
|
449
|
+
const match = line.trim().replace(/^\/\/\/\s*/, "").match(RELATION_RE);
|
|
450
|
+
if (!match) return null;
|
|
451
|
+
const [, fromModel, fromField, toModel, toField, type] = match;
|
|
452
|
+
return {
|
|
453
|
+
fromModel,
|
|
454
|
+
fromField,
|
|
455
|
+
toModel,
|
|
456
|
+
toField,
|
|
457
|
+
type
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function makeRelationLine(input) {
|
|
461
|
+
const parts = input.split("-to-");
|
|
462
|
+
if (parts.length !== 2) return {
|
|
463
|
+
ok: false,
|
|
464
|
+
error: `Invalid input format: ${input}`
|
|
465
|
+
};
|
|
466
|
+
const [to, optionalFlag] = parts[1].includes("-optional") ? [parts[1].replace("-optional", ""), "optional"] : [parts[1], ""];
|
|
467
|
+
const from = parts[0];
|
|
468
|
+
if (!isRelationshipType(from)) return {
|
|
469
|
+
ok: false,
|
|
470
|
+
error: `Invalid relationship: ${from}`
|
|
471
|
+
};
|
|
472
|
+
if (!isRelationshipType(to)) return {
|
|
473
|
+
ok: false,
|
|
474
|
+
error: `Invalid relationship: ${to}`
|
|
475
|
+
};
|
|
476
|
+
return {
|
|
477
|
+
ok: true,
|
|
478
|
+
value: `${RELATIONSHIPS[from]}${optionalFlag === "optional" ? ".." : "--"}${RELATIONSHIPS[to]}`
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
function extractRelationsFromAnnotations(code) {
|
|
482
|
+
return code.map(parseRelation).filter((r) => r !== null).flatMap((r) => {
|
|
483
|
+
const result = makeRelationLine(r.type);
|
|
484
|
+
if (!result.ok) return [];
|
|
485
|
+
return [{
|
|
486
|
+
fromModel: r.fromModel,
|
|
487
|
+
fromField: r.fromField,
|
|
488
|
+
toModel: r.toModel,
|
|
489
|
+
toField: r.toField,
|
|
490
|
+
symbol: result.value
|
|
491
|
+
}];
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
//#endregion
|
|
435
495
|
//#region src/generator/arktype.ts
|
|
436
496
|
function undeclared(objectType) {
|
|
437
497
|
if (objectType === "strict") return "\"+\":\"reject\",";
|
|
@@ -642,8 +702,19 @@ async function emit(code, dir, output) {
|
|
|
642
702
|
//#region src/generator/mermaid-er.ts
|
|
643
703
|
function mermaidER(code) {
|
|
644
704
|
const tables = parseTableInfo(code);
|
|
645
|
-
const
|
|
646
|
-
const
|
|
705
|
+
const inferred = extractRelationsFromSchema(code);
|
|
706
|
+
const annotated = extractRelationsFromAnnotations(code);
|
|
707
|
+
const key = (r) => `${r.fromModel}.${r.fromField}->${r.toModel}.${r.toField}`;
|
|
708
|
+
const merged = /* @__PURE__ */ new Map();
|
|
709
|
+
for (const r of inferred) merged.set(key(r), {
|
|
710
|
+
fromModel: r.fromModel,
|
|
711
|
+
fromField: r.fromField,
|
|
712
|
+
toModel: r.toModel,
|
|
713
|
+
toField: r.toField,
|
|
714
|
+
symbol: r.isRequired ? "||--}|" : "||--}o"
|
|
715
|
+
});
|
|
716
|
+
for (const r of annotated) merged.set(key(r), r);
|
|
717
|
+
const relationLines = [...merged.values()].map((r) => ` ${r.fromModel} ${r.symbol} ${r.toModel} : "(${r.fromField}) - (${r.toField})"`);
|
|
647
718
|
const tableDefinitions = tables.flatMap((table) => [
|
|
648
719
|
` ${table.name} {`,
|
|
649
720
|
...table.fields.map((field) => {
|
|
@@ -799,42 +870,42 @@ Options:
|
|
|
799
870
|
--no-with-comment Do not add JSDoc comments
|
|
800
871
|
--no-with-relation Do not generate relation schemas
|
|
801
872
|
-h, --help Display this help message`;
|
|
802
|
-
function parseFlags(
|
|
873
|
+
function parseFlags(args) {
|
|
803
874
|
const ZOD_VERSIONS = [
|
|
804
875
|
"v4",
|
|
805
876
|
"mini",
|
|
806
877
|
"@hono/zod-openapi"
|
|
807
878
|
];
|
|
808
|
-
const zodVersionIndex =
|
|
809
|
-
const zodVersionValue = zodVersionIndex === -1 ? void 0 :
|
|
879
|
+
const zodVersionIndex = args.findIndex((a) => a === "--zod-version" || a.startsWith("--zod-version="));
|
|
880
|
+
const zodVersionValue = zodVersionIndex === -1 ? void 0 : args[zodVersionIndex].includes("=") ? args[zodVersionIndex].split("=")[1] : args[zodVersionIndex + 1];
|
|
810
881
|
return {
|
|
811
|
-
zod:
|
|
812
|
-
valibot:
|
|
813
|
-
arktype:
|
|
814
|
-
effect:
|
|
882
|
+
zod: args.includes("--zod"),
|
|
883
|
+
valibot: args.includes("--valibot"),
|
|
884
|
+
arktype: args.includes("--arktype"),
|
|
885
|
+
effect: args.includes("--effect"),
|
|
815
886
|
zodVersion: ZOD_VERSIONS.find((v) => v === zodVersionValue),
|
|
816
|
-
exportTypes: !
|
|
817
|
-
withComment: !
|
|
818
|
-
withRelation: !
|
|
887
|
+
exportTypes: !args.includes("--no-export-types"),
|
|
888
|
+
withComment: !args.includes("--no-with-comment"),
|
|
889
|
+
withRelation: !args.includes("--no-with-relation")
|
|
819
890
|
};
|
|
820
891
|
}
|
|
821
892
|
async function sizuku() {
|
|
822
|
-
const
|
|
823
|
-
if (
|
|
893
|
+
const args = process.argv.slice(2);
|
|
894
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) return {
|
|
824
895
|
ok: true,
|
|
825
896
|
value: HELP_TEXT
|
|
826
897
|
};
|
|
827
|
-
const input =
|
|
898
|
+
const input = args[0];
|
|
828
899
|
if (!input || input.startsWith("-")) return {
|
|
829
900
|
ok: false,
|
|
830
901
|
error: HELP_TEXT
|
|
831
902
|
};
|
|
832
|
-
const oIndex =
|
|
903
|
+
const oIndex = args.indexOf("-o");
|
|
833
904
|
if (oIndex === -1) return {
|
|
834
905
|
ok: false,
|
|
835
906
|
error: "Missing -o flag. Usage: sizuku <input> -o <output>"
|
|
836
907
|
};
|
|
837
|
-
const output =
|
|
908
|
+
const output = args[oIndex + 1];
|
|
838
909
|
if (!output) return {
|
|
839
910
|
ok: false,
|
|
840
911
|
error: "Missing output file path after -o"
|
|
@@ -844,7 +915,7 @@ async function sizuku() {
|
|
|
844
915
|
ok: false,
|
|
845
916
|
error: `Unsupported output format: ${output}. Supported: .dbml, .png, .md, .ts`
|
|
846
917
|
};
|
|
847
|
-
const flags = outputType === "typescript" ? parseFlags(
|
|
918
|
+
const flags = outputType === "typescript" ? parseFlags(args) : null;
|
|
848
919
|
const lib = flags === null ? null : flags.zod ? {
|
|
849
920
|
name: "zod",
|
|
850
921
|
label: "Zod"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sizuku",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "Sizuku is a tool that generates validation schemas for Zod and Valibot, as well as ER diagrams and DBML, from Drizzle schemas annotated with comments.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dbml",
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"type": "module",
|
|
28
28
|
"main": "dist/index.mjs",
|
|
29
29
|
"types": "dist/index.d.mts",
|
|
30
|
-
"exports": {},
|
|
31
30
|
"publishConfig": {
|
|
32
31
|
"access": "public"
|
|
33
32
|
},
|