87 lines
2.4 KiB
TypeScript
87 lines
2.4 KiB
TypeScript
import * as FS from "fs";
|
|
import * as FSE from "fs-extra";
|
|
import * as Path from "path";
|
|
import {
|
|
EnumDefinition,
|
|
IR,
|
|
ServiceDefinition,
|
|
Step,
|
|
TypeDefinition,
|
|
} from "./ir";
|
|
|
|
export abstract class CompileTarget<T = any> {
|
|
abstract name: string;
|
|
constructor(
|
|
private outputFolder: string,
|
|
protected options: T & { allow_bytes: boolean }
|
|
) {
|
|
if (!FS.existsSync(outputFolder)) {
|
|
FS.mkdirSync(outputFolder, {
|
|
recursive: true,
|
|
});
|
|
}
|
|
}
|
|
|
|
abstract start(): void;
|
|
|
|
abstract generateType(definition: TypeDefinition): void;
|
|
|
|
abstract generateEnum(definition: EnumDefinition): void;
|
|
|
|
abstract generateService(definition: ServiceDefinition): void;
|
|
|
|
abstract finalize(steps: Step[]): void;
|
|
|
|
protected writeFile(name: string, content: string | Promise<string>) {
|
|
let resPath = Path.join(this.outputFolder, name);
|
|
let resDir = Path.dirname(resPath);
|
|
if (!FS.existsSync(resDir)) FS.mkdirSync(resDir, { recursive: true });
|
|
if (content instanceof Promise) {
|
|
content.then((res) => FS.writeFileSync(resPath, res));
|
|
} else {
|
|
FS.writeFileSync(resPath, content);
|
|
}
|
|
}
|
|
|
|
protected getTemplate(name: string): string {
|
|
let path = Path.join(__dirname, "../templates/" + name);
|
|
let file = FS.readFileSync(path, "utf-8");
|
|
|
|
const splitted = file.split("\n");
|
|
let res = [];
|
|
let ignore = false;
|
|
for (const line of splitted) {
|
|
if (ignore) {
|
|
ignore = false;
|
|
} else if (line.trim().startsWith("//@template-ignore")) {
|
|
ignore = true;
|
|
} else {
|
|
res.push(line);
|
|
}
|
|
}
|
|
|
|
return res.join("\n");
|
|
}
|
|
|
|
protected loadTemplateFolder(name: string) {
|
|
let root = Path.join(__dirname, "../templates/", name);
|
|
|
|
FSE.copySync(root, this.outputFolder, {});
|
|
}
|
|
}
|
|
|
|
export default function compile(ir: IR, target: CompileTarget) {
|
|
// Types are verified. They are now ready to be compiled to targets
|
|
|
|
// setState("Building for target: " + target.name);
|
|
target.start();
|
|
ir.steps.forEach((step) => {
|
|
const [type, def] = step;
|
|
if (type == "type") target.generateType(def as TypeDefinition);
|
|
else if (type == "enum") target.generateEnum(def as EnumDefinition);
|
|
else if (type == "service")
|
|
target.generateService(def as ServiceDefinition);
|
|
});
|
|
if (target.finalize) target.finalize(ir.steps);
|
|
}
|