refactor(bazel): Simplify parser output structure (#18270)

This commit is contained in:
Sergei Zharinov 2022-10-12 07:55:13 +03:00 committed by GitHub
parent 8b9259b0e9
commit f2d85c16cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 135 additions and 161 deletions

View file

@ -1,8 +1,7 @@
import { logger } from '../../../logger';
import type { PackageDependency, PackageFile } from '../types';
import { parse } from './parser';
import { extractDepFromFragment } from './rules';
import type { ArrayFragment } from './types';
import type { RecordFragment } from './types';
export function extractPackageFile(
content: string,
@ -10,19 +9,13 @@ export function extractPackageFile(
): PackageFile | null {
const deps: PackageDependency[] = [];
let parsed: ArrayFragment | null = null;
try {
parsed = parse(content);
} catch (err) /* istanbul ignore next */ {
logger.debug({ err, packageFile }, 'Bazel parsing error');
}
if (!parsed) {
const fragments: RecordFragment[] | null = parse(content, packageFile);
if (!fragments) {
return null;
}
for (let idx = 0; idx < parsed.children.length; idx += 1) {
const fragment = parsed.children[idx];
for (let idx = 0; idx < fragments.length; idx += 1) {
const fragment = fragments[idx];
const dep = extractDepFromFragment(fragment);
if (!dep) {

View file

@ -9,12 +9,7 @@ describe('modules/manager/bazel/parser', () => {
const res = parse(input);
expect(res).toEqual({
type: 'array',
value:
'go_repository(name = "foo")\nmaybe(go_repository, name = "bar", deps = ["baz", "qux"])',
offset: 0,
children: [
expect(res).toEqual([
{
type: 'record',
value: 'go_repository(name = "foo")',
@ -42,9 +37,8 @@ describe('modules/manager/bazel/parser', () => {
},
},
},
],
});
expect(extract(res!)).toMatchObject([
]);
expect(res?.map(extract)).toMatchObject([
{ rule: 'go_repository', name: 'foo' },
{ rule: 'go_repository', name: 'bar', deps: ['baz', 'qux'] },
]);
@ -66,8 +60,7 @@ describe('modules/manager/bazel/parser', () => {
const res = parse(input);
expect(res).toMatchObject({
children: [
expect(res).toMatchObject([
{
children: {
rule: { value: 'http_archive' },
@ -102,9 +95,9 @@ describe('modules/manager/bazel/parser', () => {
},
},
},
],
});
expect(extract(res!)).toMatchObject([
]);
expect(res?.map(extract)).toMatchObject([
{
rule: 'http_archive',
name: 'aspect_rules_js',
@ -134,8 +127,7 @@ describe('modules/manager/bazel/parser', () => {
const res = parse(input);
expect(res).toMatchObject({
children: [
expect(res).toMatchObject([
{
children: {
name: { value: 'rules_nodejs' },
@ -150,9 +142,9 @@ describe('modules/manager/bazel/parser', () => {
},
},
},
],
});
expect(extract(res!)).toMatchObject([
]);
expect(res?.map(extract)).toMatchObject([
{
rule: 'http_archive',
name: 'rules_nodejs',
@ -176,8 +168,7 @@ describe('modules/manager/bazel/parser', () => {
const res = parse(input);
expect(res).toMatchObject({
children: [
expect(res).toMatchObject([
{
children: {
name: { value: 'bazel_toolchains' },
@ -187,8 +178,7 @@ describe('modules/manager/bazel/parser', () => {
'4b1468b254a572dbe134cc1fd7c6eab1618a72acd339749ea343bd8f55c3b7eb',
},
strip_prefix: {
value:
'bazel-toolchains-d665ccfa3e9c90fa789671bf4ef5f7c19c5715c4',
value: 'bazel-toolchains-d665ccfa3e9c90fa789671bf4ef5f7c19c5715c4',
},
urls: {
children: [
@ -204,9 +194,9 @@ describe('modules/manager/bazel/parser', () => {
},
},
},
],
});
expect(extract(res!)).toMatchObject([
]);
expect(res?.map(extract)).toMatchObject([
{
name: 'bazel_toolchains',
rule: 'http_archive',

View file

@ -1,9 +1,9 @@
import { lang, lexer, parser, query as q } from 'good-enough-parser';
import hasha from 'hasha';
import { logger } from '../../../logger';
import * as memCache from '../../../util/cache/memory';
import { supportedRulesRegex } from './rules/index';
import type {
ArrayFragment,
Fragment,
FragmentData,
NestedFragment,
@ -12,6 +12,7 @@ import type {
interface Ctx {
readonly source: string;
results: RecordFragment[];
stack: NestedFragment[];
recordKey?: string;
}
@ -19,14 +20,8 @@ interface Ctx {
function emptyCtx(source: string): Ctx {
return {
source,
stack: [
{
type: 'array',
value: source,
offset: 0,
children: [],
},
],
results: [],
stack: [],
};
}
@ -139,12 +134,8 @@ function ruleCall(search: q.QueryBuilder<Ctx>): q.QueryBuilder<Ctx> {
const frag = currentFragment(ctx);
if (frag.type === 'record' && tree.type === 'wrapped-tree') {
frag.value = extractTreeValue(ctx.source, tree, frag.offset);
}
ctx.stack.pop();
const parentFrag = currentFragment(ctx);
if (parentFrag.type === 'array') {
parentFrag.children.push(frag);
ctx.results.push(frag);
}
return ctx;
@ -152,17 +143,13 @@ function ruleCall(search: q.QueryBuilder<Ctx>): q.QueryBuilder<Ctx> {
});
}
function ruleStartHandler(ctx: Ctx, { value, offset }: lexer.Token): Ctx {
const parentFragment = currentFragment(ctx);
if (parentFragment.type === 'array') {
function ruleStartHandler(ctx: Ctx, { offset }: lexer.Token): Ctx {
ctx.stack.push({
type: 'record',
value: '',
offset,
children: {},
});
}
return ctx;
}
@ -217,22 +204,26 @@ function getCacheKey(input: string): string {
const starlark = lang.createLang('starlark');
export function parse(input: string): ArrayFragment | null {
export function parse(
input: string,
packageFile?: string
): RecordFragment[] | null {
const cacheKey = getCacheKey(input);
const cachedResult = memCache.get<ArrayFragment | null>(cacheKey);
const cachedResult = memCache.get<RecordFragment[] | null>(cacheKey);
// istanbul ignore if
if (cachedResult === null || cachedResult) {
return cachedResult;
}
let result: ArrayFragment | null = null;
let result: RecordFragment[] | null = null;
try {
const parsedResult = starlark.query(input, query, emptyCtx(input));
if (parsedResult) {
const rootFragment = parsedResult.stack[0];
if (rootFragment.type === 'array') {
result = rootFragment;
result = parsedResult.results;
}
} catch (err) /* istanbul ignore next */ {
logger.debug({ err, packageFile }, 'Bazel parsing error');
}
memCache.set(cacheKey, result);