rhombic
Version:
SQL parsing, lineage extraction and manipulation
139 lines • 4.95 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.formatCst = exports.prettifyCst = void 0;
const chevrotain_1 = require("chevrotain");
const isCstNode_1 = require("./isCstNode");
/**
* Pretty output for cst for easy specifications
*
* @param cst
*/
function prettifyCst(cst) {
let output = "";
Object.entries(cst).forEach(([_, elements]) => {
elements.forEach((node, i, nodes) => {
if (isCstNode_1.isCstNode(node)) {
output += node.name + "(" + prettifyCst(node.children) + ")";
}
else {
if (i === 0 && node.tokenType)
output += node.tokenType.tokenName;
if (i === 0)
output += "(";
output += `"${node.image}"`;
if (i === nodes.length - 1)
output += ")";
else
output += ",";
}
});
});
return output;
}
exports.prettifyCst = prettifyCst;
/**
* Indent the prettify version of the cst for more visibility
*
* @param cst output of `prettifyCst()`
*/
function formatCst(prettifiedCst) {
const lexResult = PrettyCstLexer.tokenize(prettifiedCst);
parser.input = lexResult.tokens;
const cst = parser.node();
if (parser.errors.length + lexResult.errors.length > 0) {
throw new Error(`PrettifyCst Error: \n - ${[...parser.errors.map(i => i.message), ...lexResult.errors.map(i => i.message)].join("\n - ")}`);
}
const visitor = new PrettyCstVisitor();
visitor.visit(cst);
return visitor.output
.split("\n")
.filter(i => i)
.join("\n");
}
exports.formatCst = formatCst;
// Lexer/Parser/Visitor to support `formatCst()`
const Identifier = chevrotain_1.createToken({
name: "Identifier",
pattern: /[a-zA-Z_]+/
});
const Value = chevrotain_1.createToken({
name: "Value",
pattern: /((""[^"\\]*(?:\\.[^"\\]*)*(""))+)|(("[^"\\]*(?:\\.[^"\\]*)*("))+)/
});
const LParen = chevrotain_1.createToken({ name: "LParen", pattern: /\(/ });
const RParen = chevrotain_1.createToken({ name: "RParen", pattern: /\)/ });
const Comma = chevrotain_1.createToken({ name: "Comma", pattern: /,/ });
const WhiteSpace = chevrotain_1.createToken({
name: "WhiteSpace",
pattern: /\s+/,
group: chevrotain_1.Lexer.SKIPPED
});
const allTokens = [WhiteSpace, Identifier, Value, LParen, RParen, Comma];
const PrettyCstLexer = new chevrotain_1.Lexer(allTokens, {
lineTerminatorCharacters: ["\n"]
});
class PrettyCstParser extends chevrotain_1.CstParser {
constructor() {
super(allTokens);
this.node = this.RULE("node", () => {
this.CONSUME(Identifier);
this.CONSUME(LParen);
this.OR([
{
ALT: () => {
// Should be `AT_LEAST_ONE_SEP` but strange error with chevrotain…
// this.AT_LEAST_ONE_SEP({
// DEF: () => this.CONSUME(Value),
// SEP: Comma
// });
this.CONSUME(Value);
this.OPTION(() => {
this.CONSUME(Comma);
this.CONSUME1(Value);
});
this.OPTION1(() => {
this.CONSUME1(Comma);
this.CONSUME2(Value);
});
this.OPTION2(() => {
this.CONSUME2(Comma);
this.CONSUME3(Value);
});
this.OPTION3(() => {
this.CONSUME3(Comma);
this.CONSUME4(Value);
});
}
},
{ ALT: () => this.AT_LEAST_ONE(() => this.SUBRULE(this.node)) }
]);
this.CONSUME(RParen);
});
this.performSelfAnalysis();
}
}
const parser = new PrettyCstParser();
const Visitor = parser.getBaseCstVisitorConstructorWithDefaults();
class PrettyCstVisitor extends Visitor {
constructor() {
super();
this.output = "";
this.indent = "";
this.validateVisitor();
}
node(ctx) {
this.output += this.indent + ctx.Identifier[0].image + ctx.LParen[0].image;
if (ctx.Value) {
this.output += ctx.Value.map(v => v.image).join(", ") + ctx.RParen[0].image + "\n";
}
else if (ctx.node) {
this.output += "\n";
this.indent += " ";
ctx.node.forEach(i => this.node(i.children));
this.output += "\n";
this.indent = this.indent.slice(0, -2);
this.output += this.indent + ctx.RParen[0].image + "\n";
}
}
}
//# sourceMappingURL=prettifyCst.js.map