tree-sitter-yaml/scripts/update-snapshot.js
2019-08-31 19:14:13 +08:00

136 lines
3.1 KiB
JavaScript

const child_process = require("child_process");
const { loadTests, writeTests } = require("./utils");
updateTestOutputs("./corpus");
function updateTestOutputs(dirname) {
const tests = loadTests(dirname);
for (const [, testCases] of Object.entries(tests)) {
for (const [, testCase] of Object.entries(testCases)) {
testCase.output = "(x y: (z))";
}
}
writeTests(dirname, tests);
let stdout;
try {
child_process.execFileSync(
"./tree-sitter/target/release/tree-sitter",
["test"],
);
} catch (error) {
stdout = error.stdout.toString();
}
const sexps = parseTestStdout(stdout);
for (const [basename, testCases] of Object.entries(sexps)) {
for (const [title, sexp] of Object.entries(testCases)) {
tests[basename][title].output = printSExpression(parseSExpression(sexp));
}
}
writeTests(dirname, tests);
}
function parseTestStdout(stdout) {
const [tocText, detailText] = stdout
.replace(/\u001b\[\d+m/g, "") // ansi color
.split(/\n\n\d+ failures?:\n\nexpected \/ actual\n\n/);
const indices = [];
const sexps = {};
let basename;
for (const lineText of tocText.trim().split("\n")) {
if (lineText.startsWith(" ")) {
const title = lineText.slice(" ✗ ".length);
indices.push([basename, title]);
} else {
basename = lineText.slice(0, -1) + ".txt";
}
}
let counter = 0;
detailText.split("\n").forEach((lineText, i) => {
if (i % 3 === 1) {
const sexp = lineText.replace(/\(x y: \(z\)\)\s*$/, "").trim();
const [basename, title] = indices[counter++];
sexps[basename] = sexps[basename] || {};
sexps[basename][title] = sexp;
}
});
return sexps;
}
function parseSExpression(text) {
let node;
let key = null;
const stack = [];
const pushNode = () => {
if (key) {
node.key = key;
key = null;
}
if (stack.length) {
stack[stack.length - 1].children.push(node);
}
stack.push(node);
};
for (let i = 0; i < text.length; i++) {
switch (text[i]) {
case "(":
node = {
type: /^MISSING/.test(text.slice(i + 1))
? text.slice(i + 1).match(/^[^) ]+( \w+)?/)[0]
: text.slice(i + 1).match(/^[^) ]+/)[0],
children: [],
};
i += node.type.length;
pushNode();
break;
case ")":
node = stack.pop();
case " ":
break;
default:
key = text.slice(i).match(/^[^:]+/)[0];
i += key.length;
break;
}
}
return node;
}
function printSExpression(node, indent = " ") {
if (node.children.length === 0) {
return `${printNodeHead(node)})`;
}
if (node.children.every(child => child.children.length === 0)) {
return `${printNodeHead(node)}\n ${node.children
.map(child => `${printNodeHead(child)})`)
.join(" ")})`;
}
return `${printNodeHead(node)}\n${node.children
.map(x =>
printSExpression(x, indent + " ")
.split("\n")
.map(x => ` ${x}`)
.join("\n"),
)
.join(`\n`)})`;
}
function printNodeHead(node) {
return node.key ? `${node.key}: (${node.type}` : `(${node.type}`;
}