@proofkit/typegen
Version:
`@proofkit/typegen` is a tool for generating TypeScript types from FileMaker database schemas, making it easier to work with FileMaker data in modern TypeScript projects.
334 lines (333 loc) • 9.54 kB
JavaScript
import { VariableDeclarationKind } from "ts-morph";
import { varname } from "./constants.js";
function buildSchema(schemaFile, { type, ...args }) {
args.schema.reduce(
(acc, el) => acc.find((o) => o.name === el.name) ? acc : [...acc, el],
[]
);
const {
schema,
schemaName,
portalSchema = [],
valueLists = [],
strictNumbers = false
} = args;
const hasPortals = portalSchema.length > 0;
if (type === "zod" || type === "zod/v4" || type === "zod/v3") {
schemaFile.addImportDeclaration({
moduleSpecifier: type,
namedImports: ["z"]
});
if (hasPortals) {
schemaFile.addImportDeclaration({
moduleSpecifier: "@proofkit/fmdapi",
namedImports: ["InferZodPortals"]
});
}
}
for (const p of portalSchema) {
if (type === "ts") {
buildTypeTS(schemaFile, {
schemaName: p.schemaName,
schema: p.schema,
strictNumbers
});
} else {
buildTypeZod(schemaFile, {
schemaName: p.schemaName,
schema: p.schema,
strictNumbers
});
}
}
for (const vls of valueLists) {
if (vls.values.length > 0) {
if (type === "ts") {
buildValueListTS(schemaFile, {
name: vls.name,
values: vls.values
});
} else {
buildValueListZod(schemaFile, {
name: vls.name,
values: vls.values
});
}
}
}
if (type === "ts") {
buildTypeTS(schemaFile, {
schemaName,
schema,
strictNumbers
});
} else {
buildTypeZod(schemaFile, {
schemaName,
schema,
strictNumbers
});
}
if (portalSchema.length > 0) {
if (type === "ts") {
schemaFile.addTypeAlias({
name: `T${varname(schemaName)}Portals`,
type: (writer) => {
writer.block(() => {
portalSchema.forEach((p) => {
writer.write(`${p.schemaName}: T${varname(p.schemaName)}`);
});
});
},
isExported: true
});
} else {
schemaFile.addVariableStatement({
isExported: true,
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: `Z${varname(schemaName)}Portals`,
initializer: (writer) => {
writer.write(`{`).newLine().indent(() => {
portalSchema.forEach((p, i) => {
writer.quote(p.schemaName).write(": ").write(`Z${varname(p.schemaName)}`);
writer.conditionalWrite(i !== portalSchema.length - 1, ",");
writer.newLine();
});
}).write(`}`);
}
}
]
});
schemaFile.addTypeAlias({
name: `T${varname(schemaName)}Portals`,
type: `InferZodPortals<typeof Z${varname(schemaName)}Portals>`,
isExported: true
});
}
}
}
function buildTypeTS(schemaFile, {
schemaName,
schema,
strictNumbers = false
}) {
schemaFile.addTypeAlias({
name: `T${varname(schemaName)}`,
type: (writer) => {
writer.inlineBlock(() => {
schema.forEach((field) => {
var _a;
writer.quote(field.name).write(": ");
if (field.type === "string") {
writer.write("string");
} else if (field.type === "fmnumber") {
if (strictNumbers) {
writer.write("number | null");
} else {
writer.write("string | number");
}
} else if (field.type === "valueList") {
writer.write(`"${(_a = field.values) == null ? void 0 : _a.join('" | "')}"`);
} else {
writer.write("any");
}
writer.write(",").newLine();
});
});
},
isExported: true
});
}
function buildValueListTS(schemaFile, {
name,
values
}) {
schemaFile.addTypeAlias({
name: `TVL${varname(name)}`,
type: `"${values.join('" | "')}"`,
isExported: true
});
}
function buildTypeZod(schemaFile, {
schemaName,
schema,
strictNumbers = false
}) {
schemaFile.addVariableStatement({
isExported: true,
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: `Z${varname(schemaName)}`,
initializer: (writer) => {
writer.write(`z.object(`).inlineBlock(() => {
schema.forEach((field) => {
var _a, _b;
writer.quote(field.name).write(": ");
if (field.type === "string") {
writer.write("z.string()");
} else if (field.type === "fmnumber") {
if (strictNumbers) {
writer.write("z.coerce.number().nullable().catch(null)");
} else {
writer.write("z.union([z.string(), z.number()])");
}
} else if (field.type === "valueList") {
writer.write(`z.enum([`);
(_a = field.values) == null ? void 0 : _a.map(
(v, i) => writer.quote(v).conditionalWrite(
i !== (field.values ?? []).length - 1,
", "
)
);
writer.write("])");
writer.conditionalWrite(
(_b = field.values) == null ? void 0 : _b.includes(""),
`.catch("")`
);
} else {
writer.write("z.any()");
}
writer.write(",").newLine();
});
}).write(")");
}
}
]
});
schemaFile.addTypeAlias({
name: `T${varname(schemaName)}`,
type: `z.infer<typeof Z${varname(schemaName)}>`,
isExported: true
});
}
function buildValueListZod(schemaFile, {
name,
values
}) {
schemaFile.addVariableStatement({
isExported: true,
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: `ZVL${varname(name)}`,
initializer: (writer) => {
writer.write(`z.enum([`);
values.map(
(v, i) => writer.quote(v).conditionalWrite(i !== values.length - 1, ", ")
);
writer.write("])");
}
}
]
});
schemaFile.addTypeAlias({
name: `TVL${varname(name)}`,
type: `z.infer<typeof ZVL${varname(name)}>`,
isExported: true
});
}
function buildOverrideFile(overrideFile, schemaFile, { type, ...args }) {
if (type === "zod" || type === "zod/v4" || type === "zod/v3") {
overrideFile.addImportDeclaration({
moduleSpecifier: type,
namedImports: ["z"]
});
}
const { schemaName, portalSchema = [] } = args;
const namedExportNames = schemaFile.getExportSymbols().map((symbol) => symbol.getName()).filter((name) => {
if (type === "zod" || type === "zod/v4" || type === "zod/v3") {
return name.startsWith("Z");
} else {
return name.startsWith("T");
}
}).filter((name) => !name.endsWith("Portals"));
overrideFile.addImportDeclaration({
moduleSpecifier: `./generated/${args.schemaName}`,
namedImports: namedExportNames.map((name) => ({
name,
alias: `${name}_generated`,
isTypeOnly: type === "ts"
}))
});
const hasPortals = portalSchema.length > 0;
if (hasPortals && (type === "zod" || type === "zod/v4" || type === "zod/v3")) {
overrideFile.addImportDeclaration({
moduleSpecifier: "@proofkit/fmdapi",
namedImports: ["InferZodPortals"]
});
}
namedExportNames.forEach((name) => {
if (type === "zod" || type === "zod/v4" || type === "zod/v3") {
overrideFile.addVariableStatement({
isExported: true,
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name,
initializer: (writer) => {
writer.write(`${name}_generated`);
}
}
]
});
overrideFile.addTypeAlias({
name: name.replace(/^Z/, "T"),
type: `z.infer<typeof ${name}>`,
isExported: true
});
} else if (type === "ts") {
overrideFile.addTypeAlias({
name,
type: `${name}_generated`,
isExported: true
});
}
});
if (hasPortals) {
if (type === "ts") {
overrideFile.addTypeAlias({
name: `T${varname(schemaName)}Portals`,
type: (writer) => {
writer.block(() => {
portalSchema.forEach((p) => {
writer.write(`${p.schemaName}: T${varname(p.schemaName)}`);
});
});
},
isExported: true
});
} else {
overrideFile.addVariableStatement({
isExported: true,
declarationKind: VariableDeclarationKind.Const,
declarations: [
{
name: `Z${varname(schemaName)}Portals`,
initializer: (writer) => {
writer.write(`{`).newLine().indent(() => {
portalSchema.forEach((p, i) => {
writer.quote(p.schemaName).write(": ").write(`Z${varname(p.schemaName)}`);
writer.conditionalWrite(i !== portalSchema.length - 1, ",");
writer.newLine();
});
}).write(`}`);
}
}
]
});
overrideFile.addTypeAlias({
name: `T${varname(schemaName)}Portals`,
type: `InferZodPortals<typeof Z${varname(schemaName)}Portals>`,
isExported: true
});
}
}
}
export {
buildOverrideFile,
buildSchema
};
//# sourceMappingURL=buildSchema.js.map