renovate
Version:
Automated dependency updates. Flexible so you don't need to be.
262 lines • 8.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.parse = parse;
const tslib_1 = require("tslib");
const good_enough_parser_1 = require("good-enough-parser");
const logger_1 = require("../../../logger");
const memCache = tslib_1.__importStar(require("../../../util/cache/memory"));
const hash_1 = require("../../../util/hash");
const rules_1 = require("./rules");
function emptyCtx(source) {
return {
source,
results: [],
stack: [],
};
}
function currentFragment(ctx) {
const deepestFragment = ctx.stack[ctx.stack.length - 1];
return deepestFragment;
}
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 = good_enough_parser_1.query
.sym((ctx, { value: recordKey }) => {
return { ...ctx, recordKey };
})
.op('=')
.alt(
// string
good_enough_parser_1.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;
}),
// array of strings or calls
good_enough_parser_1.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: good_enough_parser_1.query.alt(good_enough_parser_1.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;
}), good_enough_parser_1.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(good_enough_parser_1.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: good_enough_parser_1.query
.opt(good_enough_parser_1.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 good_enough_parser_1.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 = good_enough_parser_1.query
.sym(rules_1.supportedRulesRegex, (ctx, token) => ruleNameHandler(recordStartHandler(ctx, token), token))
.join(ruleCall(kwParams));
/**
* Matches "maybe"-form rules:
* - `maybe(git_repository, ...)`
* - `maybe(_go_repository, ...)`
*/
const maybeRule = good_enough_parser_1.query
.sym('maybe', recordStartHandler)
.join(ruleCall(good_enough_parser_1.query.alt(good_enough_parser_1.query.begin().sym(rules_1.supportedRulesRegex, ruleNameHandler).op(','), kwParams)));
const rule = good_enough_parser_1.query.alt(maybeRule, regularRule);
const query = good_enough_parser_1.query.tree({
type: 'root-tree',
maxDepth: 16,
search: rule,
});
function getCacheKey(input) {
const hashedInput = (0, hash_1.hash)(input);
return `bazel-parser-${hashedInput}`;
}
const starlark = good_enough_parser_1.lang.createLang('starlark');
function parse(input, packageFile) {
const cacheKey = getCacheKey(input);
const cachedResult = memCache.get(cacheKey);
// istanbul ignore if
if (cachedResult === null || cachedResult) {
return cachedResult;
}
let result = null;
try {
const parsedResult = starlark.query(input, query, emptyCtx(input));
if (parsedResult) {
result = parsedResult.results;
}
}
catch (err) /* istanbul ignore next */ {
logger_1.logger.debug({ err, packageFile }, 'Bazel parsing error');
}
memCache.set(cacheKey, result);
return result;
}
//# sourceMappingURL=parser.js.map