renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
233 lines (232 loc) • 6.36 kB
JavaScript
import { get, set } from "../../../util/cache/memory/index.js";
import { logger } from "../../../logger/index.js";
import { hash } from "../../../util/hash.js";
import { supportedRulesRegex } from "./rules/index.js";
import { lang, query } from "@renovatebot/good-enough-parser";
//#region lib/modules/manager/bazel/parser.ts
function emptyCtx(source) {
return {
source,
results: [],
stack: []
};
}
function currentFragment(ctx) {
return ctx.stack[ctx.stack.length - 1];
}
function extractTreeValue(source, tree, offset) {
if (tree.type === "wrapped-tree") {
const { endsWith } = tree;
const to = endsWith.offset + endsWith.value.length;
return source.slice(offset, to);
}
// istanbul ignore next
return "";
}
/**
* Matches key-value pairs:
* - `tag = "1.2.3"`
* - `name = "foobar"`
* - `deps = ["foo", "bar"]`
* - `
* artifacts = [
maven.artifact(
group = "com.example1",
artifact = "foobar",
version = "1.2.3",
)
]
`
**/
const kwParams = query.sym((ctx, { value: recordKey }) => {
return {
...ctx,
recordKey
};
}).op("=").alt(query.str((ctx, { offset, value }) => {
const frag = currentFragment(ctx);
if (frag.type === "record" && ctx.recordKey) {
const key = ctx.recordKey;
frag.children[key] = {
type: "string",
value,
offset
};
}
return ctx;
}), query.tree({
type: "wrapped-tree",
maxDepth: 1,
startsWith: "[",
endsWith: "]",
preHandler: (ctx, tree) => {
const parentRecord = currentFragment(ctx);
if (parentRecord.type === "record" && ctx.recordKey && tree.type === "wrapped-tree") {
const key = ctx.recordKey;
parentRecord.children[key] = {
type: "array",
value: "",
offset: tree.startsWith.offset,
children: []
};
}
return ctx;
},
search: query.alt(query.str((ctx, { value, offset }) => {
const parentRecord = currentFragment(ctx);
if (parentRecord.type === "record" && ctx.recordKey) {
const key = ctx.recordKey;
const array = parentRecord.children[key];
if (array.type === "array") array.children.push({
type: "string",
value,
offset
});
}
return ctx;
}), query.sym().handler(recordStartHandler).handler((ctx, { value, offset }) => {
const ruleFragment = currentFragment(ctx);
if (ruleFragment.type === "record") ruleFragment.children._function = {
type: "string",
value,
offset
};
return ctx;
}).many(query.op(".").sym((ctx, { value }) => {
const ruleFragment = currentFragment(ctx);
if (ruleFragment.type === "record" && ruleFragment.children._function) ruleFragment.children._function.value += `.${value}`;
return ctx;
}), 0, 3).tree({
type: "wrapped-tree",
maxDepth: 1,
startsWith: "(",
endsWith: ")",
search: query.opt(query.sym((ctx, { value: subRecordKey }) => ({
...ctx,
subRecordKey
})).op("=")).str((ctx, { value: subRecordValue, offset }) => {
const argIndex = ctx.argIndex ?? 0;
const subRecordKey = ctx.subRecordKey ?? argIndex.toString();
const ruleFragment = currentFragment(ctx);
if (ruleFragment.type === "record") ruleFragment.children[subRecordKey] = {
type: "string",
value: subRecordValue,
offset
};
delete ctx.subRecordKey;
ctx.argIndex = argIndex + 1;
return ctx;
}),
postHandler: (ctx, tree) => {
delete ctx.argIndex;
const callFrag = currentFragment(ctx);
ctx.stack.pop();
if (callFrag.type === "record" && tree.type === "wrapped-tree") {
callFrag.value = extractTreeValue(ctx.source, tree, callFrag.offset);
const parentRecord = currentFragment(ctx);
if (parentRecord.type === "record" && ctx.recordKey) {
const key = ctx.recordKey;
const array = parentRecord.children[key];
if (array.type === "array") array.children.push(callFrag);
}
}
return ctx;
}
})),
postHandler: (ctx, tree) => {
const parentRecord = currentFragment(ctx);
if (parentRecord.type === "record" && ctx.recordKey && tree.type === "wrapped-tree") {
const key = ctx.recordKey;
const array = parentRecord.children[key];
if (array.type === "array") array.value = extractTreeValue(ctx.source, tree, array.offset);
}
return ctx;
}
})).handler((ctx) => {
delete ctx.recordKey;
return ctx;
});
/**
* Matches rule signature:
* `git_repository(......)`
* ^^^^^^^^
*
* @param search something to match inside parens
*/
function ruleCall(search) {
return query.tree({
type: "wrapped-tree",
maxDepth: 1,
search,
postHandler: (ctx, tree) => {
const frag = currentFragment(ctx);
if (frag.type === "record" && tree.type === "wrapped-tree") {
frag.value = extractTreeValue(ctx.source, tree, frag.offset);
ctx.stack.pop();
ctx.results.push(frag);
}
return ctx;
}
});
}
function recordStartHandler(ctx, { offset }) {
ctx.stack.push({
type: "record",
value: "",
offset,
children: {}
});
return ctx;
}
function ruleNameHandler(ctx, { value, offset }) {
const ruleFragment = currentFragment(ctx);
if (ruleFragment.type === "record") ruleFragment.children.rule = {
type: "string",
value,
offset
};
return ctx;
}
/**
* Matches regular rules:
* - `git_repository(...)`
* - `_go_repository(...)`
*/
const regularRule = query.sym(supportedRulesRegex, (ctx, token) => ruleNameHandler(recordStartHandler(ctx, token), token)).join(ruleCall(kwParams));
/**
* Matches "maybe"-form rules:
* - `maybe(git_repository, ...)`
* - `maybe(_go_repository, ...)`
*/
const maybeRule = query.sym("maybe", recordStartHandler).join(ruleCall(query.alt(query.begin().sym(supportedRulesRegex, ruleNameHandler).op(","), kwParams)));
const rule = query.alt(maybeRule, regularRule);
const query$1 = query.tree({
type: "root-tree",
maxDepth: 16,
search: rule
});
function getCacheKey(input) {
return `bazel-parser-${hash(input)}`;
}
const starlark = lang.createLang("starlark");
function parse(input, packageFile) {
const cacheKey = getCacheKey(input);
const cachedResult = get(cacheKey);
// istanbul ignore if
if (cachedResult === null || cachedResult) return cachedResult;
let result = null;
try {
const parsedResult = starlark.query(input, query$1, emptyCtx(input));
if (parsedResult) result = parsedResult.results;
} catch (err) /* istanbul ignore next */ {
logger.debug({
err,
packageFile
}, "Bazel parsing error");
}
set(cacheKey, result);
return result;
}
//#endregion
export { parse };
//# sourceMappingURL=parser.js.map