| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- import fs from "fs";
- import Handlebars from "handlebars";
- import type * as M from "./lua-api.models.js";
- import { FULL_API_TEMPLATE } from "./template.ts";
- import path from "path";
- interface Data {
- app: string;
- appVersion: string;
- apiVersion: number;
- stage: string;
- interfaces: Interface[];
- types: DataType[];
- }
- interface Interface {
- name: string;
- description: string;
- export: boolean;
- extends?: string;
- typeName?: string;
- props: Property[];
- isTypeFunction?: string;
- }
- interface Property {
- name: string;
- description: string;
- optional: boolean;
- type: string;
- }
- interface DataType {
- name: string;
- description: string;
- value: string;
- }
- function parseType(type: M.DataType, structName?: string): string {
- if (typeof type === "string") {
- // Handle known built-in types
- switch (type) {
- case "bool":
- return "boolean";
- case "double":
- case "float":
- case "int8":
- case "int16":
- case "int32":
- case "uint8":
- case "uint16":
- case "uint32":
- case "uint64":
- return "number";
- case "string":
- return "string";
- case "DataExtendMethod":
- return "() => void";
- default:
- return type;
- }
- }
- switch (type.complex_type) {
- case "array":
- return `${parseType(type.value, structName)}[]`;
- case "dictionary":
- return `Record<${parseType(type.key, structName)}, ${parseType(type.value, structName)}>`;
- case "literal": {
- if (typeof type.value === "string") {
- return `'${type.value}'`;
- } else {
- return type.value.toString();
- }
- }
- case "struct":
- if (structName == null)
- throw new Error("Unexpected struct: use properties on parent or pass a struct name to use");
- return structName;
- case "tuple":
- return `[${type.values.map((v) => parseType(v, structName)).join(", ")}]`;
- case "type":
- return parseType(type.value, structName);
- case "union":
- return `(${type.options.map((o) => parseType(o, structName)).join(" | ")})`;
- }
- }
- function parseProperty(prop: M.Property): Property {
- return {
- name: prop.name,
- description: prop.description,
- optional: prop.optional,
- type: parseType(prop.type),
- };
- }
- function getTypePropertyValue(props: M.Property[]): string | undefined {
- const typeProp = props.find((p) => p.name === "type");
- if (
- typeProp &&
- typeof typeProp.type !== "string" &&
- typeProp.type.complex_type === "literal" &&
- typeof typeProp.type.value === "string"
- ) {
- return typeProp.type.value;
- }
- return undefined;
- }
- export function parsePrototypeApi(api: M.PrototypeApi): Data {
- const data: Data = {
- app: api.application,
- appVersion: api.application_version,
- apiVersion: api.api_version,
- stage: api.stage,
- interfaces: [],
- types: [],
- };
- api.prototypes.forEach((p) => {
- const int: Interface = {
- name: p.name,
- description: p.description,
- export: p.parent == null,
- extends: p.parent,
- props: p.properties.map((p) => parseProperty(p)),
- };
- const typePropValue = getTypePropertyValue(p.properties);
- if (typePropValue != null) {
- int.isTypeFunction = typePropValue;
- } else if (p.typename) {
- int.typeName = p.typename;
- int.isTypeFunction = p.typename;
- }
- data.interfaces.push(int);
- });
- api.types.forEach((t) => {
- if (typeof t.type === "string") {
- if (t.type !== "builtin") {
- const dataType: DataType = {
- name: t.name,
- description: t.description,
- value: parseType(t.type),
- };
- data.types.push(dataType);
- }
- } else if (t.type.complex_type === "struct") {
- const int: Interface = {
- name: t.name,
- description: t.description,
- export: t.parent == null,
- extends: t.parent,
- props: [],
- };
- if (t.properties) {
- int.props = t.properties.map((p) => parseProperty(p));
- int.isTypeFunction = getTypePropertyValue(t.properties);
- }
- data.interfaces.push(int);
- } else {
- let structName: string | undefined;
- if (t.properties) {
- structName = `_${t.name}`;
- const int: Interface = {
- name: structName,
- description: t.description,
- export: false,
- extends: t.parent,
- props: t.properties.map((p) => parseProperty(p)),
- };
- data.interfaces.push(int);
- }
- const dataType: DataType = {
- name: t.name,
- description: t.description,
- value: parseType(t.type, structName),
- };
- data.types.push(dataType);
- }
- });
- return data;
- }
- export const generateDataModel = async function (outputFolder: string, api: M.PrototypeApi): Promise<void> {
- const data = parsePrototypeApi(api);
- const modelsTemplate = Handlebars.compile(FULL_API_TEMPLATE);
- const result = modelsTemplate(data);
- fs.writeFileSync(path.join(outputFolder, "models.ts"), result);
- console.log(`Generated ${api.prototypes.length.toString()} models`);
- };
|