rhombic
Version:
SQL parsing, lineage extraction and manipulation
147 lines • 6.56 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateDefinitionTypes = exports.generateContextTypes = void 0;
const fs_1 = require("fs");
const chalk_1 = __importDefault(require("chalk"));
const path_1 = require("path");
const case_1 = require("case");
const isEmpty_1 = __importDefault(require("lodash/isEmpty"));
const alternationLink = `}) & {`;
/**
* Script to generate context types from the grammar.
*
* Result:
* `src/Context.ts`
*/
function generateContextTypes(grammar) {
let types = `// Auto-generated by generateContextTypes.ts
import { IToken } from "chevrotain";
`;
const IContext = [];
// Improve the type safety with our own types, `RuleNode[]` is a better version of `ISerializedGast[]`
grammar.forEach(rule => {
const def = generateDefinitionTypes(rule.definition);
IContext.push(`${case_1.pascal(rule.name)}Context`);
types += def.includes("|")
? `\nexport type ${case_1.pascal(rule.name)}Context = \n ${def.includes(alternationLink) ? "(" : ""} | {\n`
: `\nexport interface ${case_1.pascal(rule.name)}Context {`;
types += def;
types += "\n}\n\n";
});
types += `export type IContext = ${IContext.join(" | ")}\n`;
fs_1.writeFileSync(path_1.join(__dirname, "../Context.ts"), types);
console.log(chalk_1.default.green("✔") + " context types generated!");
}
exports.generateContextTypes = generateContextTypes;
function generateDefinitionTypes(definition, options) {
const { indent, optional, keys } = Object.assign({ keys: [], indent: 2, optional: false }, options);
return definition.reduce(({ output, isAfterAlternation }, node) => {
// Avoid the next node to be inside the Alternation union
if (isAfterAlternation && output.includes("} | {")) {
output += alternationLink;
}
switch (node.type) {
case "Terminal":
if (keys.includes(node.name)) {
if (!optional) {
// Remove optional from definition
return {
output: output.replace(`${node.name}?: IToken[];`, `${node.name}: IToken[];`),
isAfterAlternation: false
};
}
return { output, isAfterAlternation: false };
}
keys.push(node.name);
return {
output: `${output}\n${" ".repeat(indent)}${node.name}${optional ? "?" : ""}: IToken[];`,
isAfterAlternation: false
};
case "NonTerminal":
if (keys.includes(node.name))
return { output, isAfterAlternation: false };
keys.push(node.name);
return {
output: `${output}\n${" ".repeat(indent)}${node.name}${optional ? "?" : ""}: Array<{\n${" ".repeat(indent + 2)}name: "${node.name}";\n${" ".repeat(indent + 2)}children: ${case_1.pascal(node.name)}Context;\n${" ".repeat(indent)}}>;`,
isAfterAlternation: false
};
case "Option":
return {
output: output +
generateDefinitionTypes(node.definition, {
indent,
optional: true,
keys
}),
isAfterAlternation: false
};
case "RepetitionMandatoryWithSeparator":
return {
output: output +
generateDefinitionTypes(node.definition, {
indent: indent + 2,
keys
}) +
generateDefinitionTypes([node.separator], {
indent: indent + 2,
optional: true,
keys
}),
isAfterAlternation: false
};
case "Repetition":
return {
output: output +
generateDefinitionTypes(node.definition, {
indent: indent + 2,
optional: true,
keys
}),
isAfterAlternation: false
};
case "Alternation": {
const isTerminalOnly = !JSON.stringify(node.definition).includes("NonTerminal");
const entries = new Set();
return {
output: output +
"\n" +
(isTerminalOnly
? node.definition
.map(i => generateDefinitionTypes(i.definition, {
indent: 0,
optional: true,
keys
}))
.join("")
.split("\n")
.filter((j) => {
const isAlreadyDefined = entries.has(j);
if (!j.includes("}>;")) {
entries.add(j);
}
return !isEmpty_1.default(j) && !isAlreadyDefined;
})
.join("\n")
: node.definition
.map(i => generateDefinitionTypes(i.definition, {
indent: 0
}).replace("\n", ""))
.join("} | {")),
isAfterAlternation: true
};
}
case "Flat":
return {
output: output + generateDefinitionTypes(node.definition).replace(/[\n;]/g, ""),
isAfterAlternation: false
};
default:
return { output, isAfterAlternation: false };
}
}, { output: "", isAfterAlternation: false }).output;
}
exports.generateDefinitionTypes = generateDefinitionTypes;
//# sourceMappingURL=generateContextTypes.js.map