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,42 +9,36 @@ 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: [
{
type: 'record',
value: 'go_repository(name = "foo")',
offset: 0,
children: {
rule: { type: 'string', value: 'go_repository', offset: 0 },
name: { type: 'string', value: 'foo', offset: 22 },
expect(res).toEqual([
{
type: 'record',
value: 'go_repository(name = "foo")',
offset: 0,
children: {
rule: { type: 'string', value: 'go_repository', offset: 0 },
name: { type: 'string', value: 'foo', offset: 22 },
},
},
{
type: 'record',
value: 'maybe(go_repository, name = "bar", deps = ["baz", "qux"])',
offset: 28,
children: {
rule: { type: 'string', value: 'go_repository', offset: 34 },
name: { type: 'string', value: 'bar', offset: 57 },
deps: {
type: 'array',
value: '["baz", "qux"]',
offset: 70,
children: [
{ type: 'string', value: 'baz', offset: 72 },
{ type: 'string', value: 'qux', offset: 79 },
],
},
},
{
type: 'record',
value: 'maybe(go_repository, name = "bar", deps = ["baz", "qux"])',
offset: 28,
children: {
rule: { type: 'string', value: 'go_repository', offset: 34 },
name: { type: 'string', value: 'bar', offset: 57 },
deps: {
type: 'array',
value: '["baz", "qux"]',
offset: 70,
children: [
{ type: 'string', value: 'baz', offset: 72 },
{ type: 'string', value: 'qux', offset: 79 },
],
},
},
},
],
});
expect(extract(res!)).toMatchObject([
},
]);
expect(res?.map(extract)).toMatchObject([
{ rule: 'go_repository', name: 'foo' },
{ rule: 'go_repository', name: 'bar', deps: ['baz', 'qux'] },
]);
@ -66,45 +60,44 @@ describe('modules/manager/bazel/parser', () => {
const res = parse(input);
expect(res).toMatchObject({
children: [
{
children: {
rule: { value: 'http_archive' },
name: { value: 'aspect_rules_js' },
sha256: {
value:
'db9f446752fe4100320cf8487e8fd476b9af0adf6b99b601bcfd70b289bb0598',
},
strip_prefix: { value: 'rules_js-1.1.2' },
url: {
value:
'https://github.com/aspect-build/rules_js/archive/refs/tags/v1.1.2.tar.gz',
},
expect(res).toMatchObject([
{
children: {
rule: { value: 'http_archive' },
name: { value: 'aspect_rules_js' },
sha256: {
value:
'db9f446752fe4100320cf8487e8fd476b9af0adf6b99b601bcfd70b289bb0598',
},
strip_prefix: { value: 'rules_js-1.1.2' },
url: {
value:
'https://github.com/aspect-build/rules_js/archive/refs/tags/v1.1.2.tar.gz',
},
},
{
children: {
rule: { value: 'http_archive' },
name: { value: 'rules_nodejs' },
sha256: {
value:
'5aef09ed3279aa01d5c928e3beb248f9ad32dde6aafe6373a8c994c3ce643064',
},
urls: {
type: 'array',
children: [
{
value:
'https://github.com/bazelbuild/rules_nodejs/releases/download/5.5.3/rules_nodejs-core-5.5.3.tar.gz',
},
],
},
},
{
children: {
rule: { value: 'http_archive' },
name: { value: 'rules_nodejs' },
sha256: {
value:
'5aef09ed3279aa01d5c928e3beb248f9ad32dde6aafe6373a8c994c3ce643064',
},
urls: {
type: 'array',
children: [
{
value:
'https://github.com/bazelbuild/rules_nodejs/releases/download/5.5.3/rules_nodejs-core-5.5.3.tar.gz',
},
],
},
},
],
});
expect(extract(res!)).toMatchObject([
},
]);
expect(res?.map(extract)).toMatchObject([
{
rule: 'http_archive',
name: 'aspect_rules_js',
@ -134,25 +127,24 @@ describe('modules/manager/bazel/parser', () => {
const res = parse(input);
expect(res).toMatchObject({
children: [
{
children: {
name: { value: 'rules_nodejs' },
rule: { value: 'http_archive' },
sha256: {
value:
'5aef09ed3279aa01d5c928e3beb248f9ad32dde6aafe6373a8c994c3ce643064',
},
url: {
value:
'https://github.com/bazelbuild/rules_nodejs/releases/download/5.5.3/rules_nodejs-core-5.5.3.tar.gz',
},
expect(res).toMatchObject([
{
children: {
name: { value: 'rules_nodejs' },
rule: { value: 'http_archive' },
sha256: {
value:
'5aef09ed3279aa01d5c928e3beb248f9ad32dde6aafe6373a8c994c3ce643064',
},
url: {
value:
'https://github.com/bazelbuild/rules_nodejs/releases/download/5.5.3/rules_nodejs-core-5.5.3.tar.gz',
},
},
],
});
expect(extract(res!)).toMatchObject([
},
]);
expect(res?.map(extract)).toMatchObject([
{
rule: 'http_archive',
name: 'rules_nodejs',
@ -176,37 +168,35 @@ describe('modules/manager/bazel/parser', () => {
const res = parse(input);
expect(res).toMatchObject({
children: [
{
children: {
name: { value: 'bazel_toolchains' },
rule: { value: 'http_archive' },
sha256: {
value:
'4b1468b254a572dbe134cc1fd7c6eab1618a72acd339749ea343bd8f55c3b7eb',
},
strip_prefix: {
value:
'bazel-toolchains-d665ccfa3e9c90fa789671bf4ef5f7c19c5715c4',
},
urls: {
children: [
{
value:
'https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/d665ccfa3e9c90fa789671bf4ef5f7c19c5715c4.tar.gz',
},
{
value:
'https://github.com/bazelbuild/bazel-toolchains/archive/d665ccfa3e9c90fa789671bf4ef5f7c19c5715c4.tar.gz',
},
],
},
expect(res).toMatchObject([
{
children: {
name: { value: 'bazel_toolchains' },
rule: { value: 'http_archive' },
sha256: {
value:
'4b1468b254a572dbe134cc1fd7c6eab1618a72acd339749ea343bd8f55c3b7eb',
},
strip_prefix: {
value: 'bazel-toolchains-d665ccfa3e9c90fa789671bf4ef5f7c19c5715c4',
},
urls: {
children: [
{
value:
'https://mirror.bazel.build/github.com/bazelbuild/bazel-toolchains/archive/d665ccfa3e9c90fa789671bf4ef5f7c19c5715c4.tar.gz',
},
{
value:
'https://github.com/bazelbuild/bazel-toolchains/archive/d665ccfa3e9c90fa789671bf4ef5f7c19c5715c4.tar.gz',
},
],
},
},
],
});
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.stack.pop();
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') {
ctx.stack.push({
type: 'record',
value: '',
offset,
children: {},
});
}
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;
const parsedResult = starlark.query(input, query, emptyCtx(input));
if (parsedResult) {
const rootFragment = parsedResult.stack[0];
if (rootFragment.type === 'array') {
result = rootFragment;
let result: RecordFragment[] | null = null;
try {
const parsedResult = starlark.query(input, query, emptyCtx(input));
if (parsedResult) {
result = parsedResult.results;
}
} catch (err) /* istanbul ignore next */ {
logger.debug({ err, packageFile }, 'Bazel parsing error');
}
memCache.set(cacheKey, result);