Implement package linter (#148496)

This PR implements a linter like the TS Project linter, except for
packages in the repo. It does this by extracting the reusable bits from
the TS Project linter and reusing them for the project linter. The only
rule that exists for packages right now is that the "name" in the
package.json file matches the "id" in Kibana.jsonc. The goal is to use a
rule to migrate kibana.json files on the future.

Additionally, a new rule for validating the indentation of tsconfig.json
files was added.

Validating and fixing violations is what has triggered review by so many
teams, but we plan to treat those review requests as notifications of
the changes and not as blockers for merging.

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Spencer 2023-01-09 17:49:29 -06:00 committed by GitHub
parent 039ed991d8
commit d6be4a4b06
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
218 changed files with 3917 additions and 1650 deletions

View file

@ -0,0 +1,3 @@
# @kbn/picomatcher
A simple wrapper around picomatch for making fast match functions from a list of globs with negative matching and tests.

View file

@ -0,0 +1,13 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
module.exports = {
preset: '@kbn/test/jest_node',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-picomatcher'],
};

View file

@ -0,0 +1,6 @@
{
"type": "shared-common",
"id": "@kbn/picomatcher",
"owner": "@elastic/kibana-operations",
"devOnly": true
}

View file

@ -0,0 +1,51 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import { makeMatcher } from './make_matcher';
describe('@kbn/picomatcher makeMatcher()', () => {
it('does positive matching', () => {
const matcher = makeMatcher(['foo/**', 'bar/**']);
expect(matcher('foo')).toBe(true);
expect(matcher('foo/bar')).toBe(true);
expect(matcher('foo/baz')).toBe(true);
expect(matcher('bar')).toBe(true);
expect(matcher('bar/foo')).toBe(true);
expect(matcher('bar/baz')).toBe(true);
expect(matcher('baz')).toBe(false);
expect(matcher('baz/box')).toBe(false);
});
it('does negative matching', () => {
const matcher = makeMatcher(['foo/**', '!foo/bar/**'], {
ignore: ['foo/yar?/**'],
});
expect(matcher('foo')).toBe(true);
expect(matcher('foo/bar')).toBe(false);
expect(matcher('foo/bar/baz')).toBe(false);
expect(matcher('foo/box')).toBe(true);
expect(matcher('foo/box/baz')).toBe(true);
expect(matcher('foo/yar')).toBe(true);
expect(matcher('foo/yar/tya')).toBe(true);
expect(matcher('foo/yarn/tya')).toBe(false);
});
it('does case-insensitive matching', () => {
const matcher = makeMatcher(['foo/**', '!foo/bar/**'], { caseInsensitive: true });
expect(matcher('FOO')).toBe(true);
expect(matcher('FOO/BAR')).toBe(false);
expect(matcher('FOO/BAR/BAZ')).toBe(false);
expect(matcher('FOO/BOX')).toBe(true);
expect(matcher('FOO/BOX/BAZ')).toBe(true);
expect(matcher('FOO/YAR')).toBe(true);
expect(matcher('FOO/YAR/TYA')).toBe(true);
});
});

View file

@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
import pm from 'picomatch';
export type Matcher = (path: string) => boolean;
/**
* Simplified version of picomatch options, focusing on options useful to Kibana
* that we have actually tested.
*/
export interface MatchOptions {
/**
* One or more glob patterns for excluding strings that should not be matched from the result.
*/
ignore?: string[];
/**
* Make matching case-insensitive. Equivalent to the regex `i` flag.
*/
caseInsensitive?: boolean;
}
/**
* Create a matcher function which will can test if a string matches any
* of the positive patterns and none of the negative patterns
*/
export function makeMatcher(patterns: string[], options?: MatchOptions) {
const negative: string[] = [];
const positive: string[] = [];
for (const e of patterns) {
if (e.startsWith('!')) {
negative.push(e.slice(1));
} else {
positive.push(e);
}
}
const matcher = pm(positive, {
nocase: options?.caseInsensitive,
nonegate: true,
ignore: [...(options?.ignore ?? []), ...negative],
});
return (val: string) => matcher(val);
}

View file

@ -0,0 +1,7 @@
{
"name": "@kbn/picomatcher",
"private": true,
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0",
"main": "./make_matcher"
}

View file

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "target/types",
"types": [
"jest",
"node"
]
},
"include": [
"**/*.ts",
],
"exclude": [
"target/**/*"
],
"kbn_references": []
}