[eslint] ensure that all imports are resolvable (#129002)

This commit is contained in:
Spencer 2022-04-04 14:37:06 -05:00 committed by GitHub
parent 0caddf864e
commit 2ad2a4c271
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
137 changed files with 1995 additions and 1894 deletions

View file

@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line import/no-unresolved
const { TestFailures } = require('kibana-buildkite-library');
(async () => {

View file

@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line import/no-unresolved
const { BuildkiteClient } = require('kibana-buildkite-library');
(async () => {

View file

@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line import/no-unresolved
const { CiStats } = require('kibana-buildkite-library');
(async () => {

View file

@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line import/no-unresolved
const { CiStats } = require('kibana-buildkite-library');
(async () => {

View file

@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line import/no-unresolved
const { CiStats } = require('kibana-buildkite-library');
(async () => {

View file

@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line import/no-unresolved
const { BuildkiteClient } = require('kibana-buildkite-library');
(async () => {

View file

@ -8,7 +8,6 @@
const execSync = require('child_process').execSync;
const fs = require('fs');
// eslint-disable-next-line import/no-unresolved
const { areChangesSkippable, doAnyChangesMatch } = require('kibana-buildkite-library');
const SKIPPABLE_PATHS = [

View file

@ -579,30 +579,6 @@ module.exports = {
},
},
/**
* Files that are allowed to import webpack-specific stuff
*/
{
files: [
'**/public/**/*.js',
'src/fixtures/**/*.js', // TODO: this directory needs to be more obviously "public" (or go away)
],
settings: {
// instructs import/no-extraneous-dependencies to treat certain modules
// as core modules, even if they aren't listed in package.json
'import/core-modules': ['plugins'],
'import/resolver': {
'@kbn/eslint-import-resolver-kibana': {
forceNode: false,
rootPackageName: 'kibana',
kibanaPath: '.',
pluginMap: {},
},
},
},
},
/**
* Single package.json rules, it tells eslint to ignore the child package.json files
* and look for dependencies declarations in the single and root level package.json
@ -690,7 +666,6 @@ module.exports = {
{
files: [
'.eslintrc.js',
'packages/kbn-eslint-import-resolver-kibana/**/*.js',
'packages/kbn-eslint-plugin-eslint/**/*',
'x-pack/gulpfile.js',
'x-pack/scripts/*.js',
@ -1567,14 +1542,6 @@ module.exports = {
{
files: ['x-pack/plugins/canvas/canvas_plugin_src/**/*.js'],
globals: { canvas: true, $: true },
rules: {
'import/no-unresolved': [
'error',
{
ignore: ['!!raw-loader.+.svg$'],
},
],
},
},
{
files: ['x-pack/plugins/canvas/public/**/*.js'],

1
.github/CODEOWNERS vendored
View file

@ -221,6 +221,7 @@
/packages/*babel*/ @elastic/kibana-operations
/packages/kbn-dev-utils*/ @elastic/kibana-operations
/packages/kbn-es/ @elastic/kibana-operations
/packages/kbn-eslint-plugin-imports/ @elastic/kibana-operations
/packages/kbn-optimizer/ @elastic/kibana-operations
/packages/kbn-pm/ @elastic/kibana-operations
/packages/kbn-test/ @elastic/kibana-operations

View file

@ -68,7 +68,6 @@ yarn kbn watch
- @kbn/docs-utils
- @kbn/es
- @kbn/es-archiver
- @kbn/eslint-import-resolver-kibana
- @kbn/eslint-plugin-eslint
- @kbn/expect
- @kbn/i18n

View file

@ -25,7 +25,7 @@ import {
} from './book_embeddable';
import { CreateEditBookComponent } from './create_edit_book_component';
import { OnSaveProps } from '../../../../src/plugins/saved_objects/public';
import { SavedObjectsClientContract } from '../../../../src/core/target/types/public/saved_objects';
import { SavedObjectsClientContract } from '../../../../src/core/public';
interface StartServices {
openModal: OverlayStart['openModal'];

View file

@ -32,8 +32,10 @@ import example1SampleCode from '!!raw-loader!./examples/1_using_existing_format'
import example2SampleCodePart1 from '!!raw-loader!../common/example_currency_format';
// @ts-ignore
import example2SampleCodePart2 from '!!raw-loader!./examples/2_creating_custom_formatter';
/* eslint-disable @kbn/eslint/no-restricted-paths */
// @ts-ignore
import example2SampleCodePart3 from '!!raw-loader!../server/examples/2_creating_custom_formatter';
/* eslint-enable @kbn/eslint/no-restricted-paths */
// @ts-ignore
import example3SampleCode from '!!raw-loader!./examples/3_creating_custom_format_editor';

View file

@ -138,6 +138,7 @@
"@kbn/crypto": "link:bazel-bin/packages/kbn-crypto",
"@kbn/doc-links": "link:bazel-bin/packages/kbn-doc-links",
"@kbn/es-query": "link:bazel-bin/packages/kbn-es-query",
"@kbn/eslint-plugin-imports": "link:bazel-bin/packages/kbn-eslint-plugin-imports",
"@kbn/field-types": "link:bazel-bin/packages/kbn-field-types",
"@kbn/flot-charts": "link:bazel-bin/packages/kbn-flot-charts",
"@kbn/i18n": "link:bazel-bin/packages/kbn-i18n",
@ -473,7 +474,6 @@
"@kbn/docs-utils": "link:bazel-bin/packages/kbn-docs-utils",
"@kbn/es": "link:bazel-bin/packages/kbn-es",
"@kbn/es-archiver": "link:bazel-bin/packages/kbn-es-archiver",
"@kbn/eslint-import-resolver-kibana": "link:bazel-bin/packages/kbn-eslint-import-resolver-kibana",
"@kbn/eslint-plugin-eslint": "link:bazel-bin/packages/kbn-eslint-plugin-eslint",
"@kbn/expect": "link:bazel-bin/packages/kbn-expect",
"@kbn/generate": "link:bazel-bin/packages/kbn-generate",
@ -594,6 +594,7 @@
"@types/kbn__docs-utils": "link:bazel-bin/packages/kbn-docs-utils/npm_module_types",
"@types/kbn__es-archiver": "link:bazel-bin/packages/kbn-es-archiver/npm_module_types",
"@types/kbn__es-query": "link:bazel-bin/packages/kbn-es-query/npm_module_types",
"@types/kbn__eslint-plugin-imports": "link:bazel-bin/packages/kbn-eslint-plugin-imports/npm_module_types",
"@types/kbn__field-types": "link:bazel-bin/packages/kbn-field-types/npm_module_types",
"@types/kbn__generate": "link:bazel-bin/packages/kbn-generate/npm_module_types",
"@types/kbn__i18n": "link:bazel-bin/packages/kbn-i18n/npm_module_types",
@ -695,6 +696,7 @@
"@types/reduce-reducers": "^1.0.0",
"@types/redux-actions": "^2.6.1",
"@types/redux-logger": "^3.0.8",
"@types/resolve": "^1.20.1",
"@types/seedrandom": ">=2.0.0 <4.0.0",
"@types/selenium-webdriver": "^4.0.18",
"@types/semver": "^7",
@ -782,8 +784,6 @@
"enzyme-to-json": "^3.6.1",
"eslint": "^7.32.0",
"eslint-config-prettier": "^7.2.0",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-webpack": "^0.13.1",
"eslint-module-utils": "^2.6.2",
"eslint-plugin-ban": "^1.5.2",
"eslint-plugin-cypress": "^2.12.1",
@ -876,7 +876,7 @@
"react-test-renderer": "^16.12.0",
"read-pkg": "^5.2.0",
"regenerate": "^1.4.0",
"resolve": "^1.7.1",
"resolve": "^1.22.0",
"rxjs-marbles": "^5.0.6",
"sass-loader": "^10.2.0",
"sass-resources-loader": "^2.0.1",

View file

@ -32,8 +32,8 @@ filegroup(
"//packages/kbn-es-archiver:build",
"//packages/kbn-es-query:build",
"//packages/kbn-es:build",
"//packages/kbn-eslint-import-resolver-kibana:build",
"//packages/kbn-eslint-plugin-eslint:build",
"//packages/kbn-eslint-plugin-imports:build",
"//packages/kbn-expect:build",
"//packages/kbn-field-types:build",
"//packages/kbn-flot-charts:build",
@ -115,6 +115,7 @@ filegroup(
"//packages/kbn-docs-utils:build_types",
"//packages/kbn-es-archiver:build_types",
"//packages/kbn-es-query:build_types",
"//packages/kbn-eslint-plugin-imports:build_types",
"//packages/kbn-field-types:build_types",
"//packages/kbn-generate:build_types",
"//packages/kbn-i18n-react:build_types",

View file

@ -10,6 +10,7 @@ module.exports = {
plugins: [
'@kbn/eslint-plugin-eslint',
'@kbn/eslint-plugin-imports',
'prettier',
],
@ -109,5 +110,6 @@ module.exports = {
'@kbn/eslint/no_trailing_import_slash': 'error',
'@kbn/eslint/no_constructor_args_in_property_initializers': 'error',
'@kbn/eslint/no_this_in_property_initializers': 'error',
'@kbn/imports/no_unresolved_imports': 'error',
},
};

View file

@ -18,14 +18,6 @@ module.exports = {
'prefer-object-spread',
],
settings: {
'import/resolver': {
'@kbn/eslint-import-resolver-kibana': {
forceNode: true,
},
},
},
env: {
es6: true,
node: true,
@ -93,7 +85,6 @@ module.exports = {
'mocha/handle-done-callback': 'error',
'mocha/no-exclusive-tests': 'error',
'import/no-unresolved': [ 'error', { 'amd': true, 'commonjs': true } ],
'import/named': 'error',
'import/namespace': 'error',
'import/default': 'error',

View file

@ -27,17 +27,6 @@ module.exports = {
'eslint-comments'
],
settings: {
'import/resolver': {
node: {
extensions: ['.mjs', '.js', '.json', '.ts', '.tsx'],
},
},
react: {
version: semver.valid(semver.coerce(PKG.dependencies.react)),
},
},
env: {
es6: true,
node: true,

View file

@ -60,7 +60,7 @@ peggy(
"--allowed-start-rules",
"start,Literal",
"-o",
"$(@D)/index.js",
"$(@D)/built_grammar.js",
"./%s/grammar/grammar.peggy" % package_name()
],
)

View file

@ -6,4 +6,6 @@
* Side Public License, v 1.
*/
exports.debug = require('debug')('eslint-plugin-import:resolver:kibana');
declare module '*/grammar/built_grammar.js' {
export const parse: any;
}

View file

@ -6,5 +6,4 @@
* Side Public License, v 1.
*/
// @ts-expect-error
export { parse } from '../../../grammar';
export { parse } from '../../../grammar/built_grammar.js';

View file

@ -10,7 +10,8 @@
]
},
"include": [
"src/**/*"
"src/**/*",
"src/kuery/grammar/grammar.d.ts"
],
"exclude": [
"**/__fixtures__/**/*",

View file

@ -1,55 +0,0 @@
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//src/dev/bazel:index.bzl", "pkg_npm")
PKG_BASE_NAME = "kbn-eslint-import-resolver-kibana"
PKG_REQUIRE_NAME = "@kbn/eslint-import-resolver-kibana"
SOURCE_FILES = glob([
"lib/**/*.js",
"import_resolver_kibana.js",
])
SRCS = SOURCE_FILES
filegroup(
name = "srcs",
srcs = SRCS,
)
NPM_MODULE_EXTRA_FILES = [
"package.json",
"README.md",
]
DEPS = [
"@npm//debug",
"@npm//eslint-import-resolver-node",
"@npm//eslint-import-resolver-webpack",
"@npm//eslint-plugin-import",
"@npm//lru-cache",
]
js_library(
name = PKG_BASE_NAME,
srcs = NPM_MODULE_EXTRA_FILES + [
":srcs",
],
deps = DEPS,
package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
)
pkg_npm(
name = "npm_module",
deps = [
":%s" % PKG_BASE_NAME,
]
)
filegroup(
name = "build",
srcs = [
":npm_module",
],
visibility = ["//visibility:public"],
)

View file

@ -1,69 +0,0 @@
# @kbn/eslint-import-resolver-kibana
Resolver for Kibana imports, meant to be used with [eslint-plugin-import](https://github.com/benmosher/eslint-plugin-import).
## Installation
To install this utility use `yarn` to link to the package from the Kibana project:
```sh
yarn add --dev link:../../kibana/packages/kbn-eslint-import-resolver-kibana
```
## Usage
Specify this resolver with the `import/resolver` setting in your eslint config file:
```yml
# .eslintrc.yml
settings:
import/resolver: "@kbn/eslint-import-resolver-kibana"
```
## Settings
***NOTE:*** All relative paths are resolved as relative to the project root, which is determined by walking up from the first linted file and looking for a `package.json` file. If your project has multiple `package.json` files then make sure to specify the `rootPackageName` setting.
Property | Default | Description
-------- | ------- | -----------
rootPackageName | `null` | The `"name"` property of the root `package.json` file. If your project has multiple `package.json` files then specify this setting to tell the resolver which `package.json` file sits at the root of your project.
pluginPaths | `[]` if `rootPackageName` is set, otherwise `[.]` | Array of relative paths which contain a Kibana plugin. Plugins must contain a `package.json` file to be valid.
pluginDirs | `[]` | Array of relative paths pointing to directories which contain Kibana plugins. Plugins must contain a `package.json` file to be valid.
pluginMap | `{}` | A map of plugin ids to relative paths, explicitly pointing to the location where Kibana should map `plugin/{pluginId}` import statements. Directories do not need to contain a `package.json` file to work.
## Settings Usage
To specify additional config add a `:` after the resolver name and specify the argument as key-value pairs:
```yml
# .eslintrc.yml
settings:
import/resolver:
"@kbn/eslint-import-resolver-kibana":
# if your project has multiple package.json files
rootPackageName: my-project
# if your project stores plugin source in sub directories you can specify
# those directories via `pluginPaths`.
pluginPaths:
- ./plugin-one
- ./plugin-two
# if all of your plugins have the same parent directory you can specify
# that directory and we will look for plugins there
pluginDirs:
- ./kibana-plugins
# if you have some other special configuration supply a map of plugin
# ids to the directory containing their code
pluginMap:
plugin1: plugins/plugin1
plugin2: plugins/plugin2
```
See [the resolvers docs](https://github.com/benmosher/eslint-plugin-import#resolvers) or the [resolver spec](https://github.com/benmosher/eslint-plugin-import/blob/master/resolvers/README.md#resolvesource-file-config---found-boolean-path-string-) for more details.
## Debugging
For debugging output from this resolver, run your linter with `DEBUG=eslint-plugin-import:resolver:kibana`.
This resolver defers to [*eslint-import-resolver-node*](https://www.npmjs.com/package/eslint-import-resolver-node) and [*eslint-import-resolver-webpack*](https://www.npmjs.com/package/eslint-import-resolver-webpack) for all of it's actual resolution logic. To get debugging output from all resolvers use `DEBUG=eslint-plugin-import:resolver:*`.

View file

@ -1,103 +0,0 @@
/*
* 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.
*/
const { join, dirname, extname } = require('path');
const webpackResolver = require('eslint-import-resolver-webpack');
const nodeResolver = require('eslint-import-resolver-node');
const {
getKibanaPath,
getProjectRoot,
getWebpackConfig,
isFile,
getIsPathRequest,
resolveWebpackAlias,
} = require('./lib');
// cache context, it shouldn't change
let context;
function initContext(file, config) {
if (context) {
return context;
}
const projectRoot = getProjectRoot(file, config);
const kibanaPath = getKibanaPath(config, projectRoot);
const webpackConfig = getWebpackConfig(kibanaPath, projectRoot, config);
const aliasEntries = Object.entries(webpackConfig.resolve.alias || {});
context = {
webpackConfig,
aliasEntries,
};
return context;
}
function tryNodeResolver(importRequest, file, config) {
return nodeResolver.resolve(
importRequest,
file,
// we use Object.assign so that this file is compatible with slightly older
// versions of node.js used by IDEs (eg. resolvers are run in the Electron
// process in Atom)
Object.assign({}, config, {
extensions: ['.js', '.json', '.ts', '.tsx'],
isFile,
})
);
}
exports.resolve = function resolveKibanaPath(importRequest, file, config) {
config = config || {};
if (config.forceNode) {
return tryNodeResolver(importRequest, file, config);
}
const { webpackConfig, aliasEntries } = initContext(file, config);
let isPathRequest = getIsPathRequest(importRequest);
// if the importRequest is not a path we might be able to map it to a path
// by comparing it to the webpack aliases. If we can convert it to a path
// without actually invoking the webpack resolver we can save a lot of time
if (!isPathRequest) {
const resolvedAlias = resolveWebpackAlias(importRequest, aliasEntries);
if (resolvedAlias) {
importRequest = resolvedAlias;
isPathRequest = true;
}
}
// if the importRequest is a path, and it has a file extension, then
// we just resolve it. This is most helpful with relative imports for
// .css and .html files because those don't work with the node resolver
// and we can resolve them much quicker than webpack
if (isPathRequest && extname(importRequest)) {
const abs = join(dirname(file), importRequest);
if (isFile(abs)) {
return {
found: true,
path: abs,
};
}
}
const nodeResult = tryNodeResolver(importRequest, file, config);
if (nodeResult && nodeResult.found) {
return nodeResult;
}
return webpackResolver.resolve(importRequest, file, {
config: webpackConfig,
});
};
// use version 2 of the resolver interface, https://github.com/benmosher/eslint-plugin-import/blob/master/resolvers/README.md#interfaceversion--number
exports.interfaceVersion = 2;

View file

@ -1,25 +0,0 @@
/*
* 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.
*/
// "path" imports point to a specific location and don't require
// module directory resolution. This RegExp should capture import
// statements that:
//
// - start with `./`
// - start with `../`
// - equal `..`
// - equal `.`
// - start with `C:\`
// - start with `C:/`
// - start with `/`
//
const PATH_IMPORT_RE = /^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/;
exports.getIsPathRequest = function (source) {
return PATH_IMPORT_RE.test(source);
};

View file

@ -1,37 +0,0 @@
/*
* 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.
*/
const { resolve } = require('path');
const { debug } = require('./debug');
const DEFAULT_PLUGIN_PATH = '../..';
/*
* Resolves the path to Kibana, either from default setting or config
*/
exports.getKibanaPath = function (config, projectRoot) {
const inConfig = config != null && config.kibanaPath;
// We only allow `.` in the config as we need it for Kibana itself
if (inConfig && config.kibanaPath !== '.') {
throw new Error(
'The `kibanaPath` option has been removed from `eslint-import-resolver-kibana`. ' +
'During development your plugin must live in `./plugins/{pluginName}` ' +
'inside the Kibana folder or `../kibana-extra/{pluginName}` ' +
'relative to the Kibana folder to work with this package.'
);
}
const kibanaPath = inConfig
? resolve(projectRoot, config.kibanaPath)
: resolve(projectRoot, DEFAULT_PLUGIN_PATH);
debug(`Resolved Kibana path: ${kibanaPath}`);
return kibanaPath;
};

View file

@ -1,47 +0,0 @@
/*
* 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.
*/
const { statSync } = require('fs');
const LRU = require('lru-cache');
const DIR = Symbol('dir');
const FILE = Symbol('file');
const cache = process.env.KIBANA_RESOLVER_HARD_CACHE ? new Map() : new LRU({ maxAge: 1000 });
function getPathType(path) {
const cached = cache.get(path);
if (cached !== undefined) {
return cached;
}
let type = null;
try {
const stats = statSync(path);
if (stats.isDirectory()) {
type = DIR;
} else if (stats.isFile() || stats.isFIFO()) {
type = FILE;
}
} catch (error) {
if (!error || (error.code !== 'ENOENT' && error.code !== 'ENOTDIR')) {
throw error;
}
}
cache.set(path, type);
return type;
}
exports.isDirectory = function (path) {
return getPathType(path) === DIR;
};
exports.isFile = function (path) {
return getPathType(path) === FILE;
};

View file

@ -1,56 +0,0 @@
/*
* 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.
*/
const { dirname, resolve, parse } = require('path');
const { accessSync, readFileSync } = require('fs');
const { debug } = require('./debug');
function getConfig(config) {
const defaults = {
projectRoot: true,
};
if (!config || !config['@elastic/eslint-import-resolver-kibana']) return defaults;
return Object.assign(defaults, config['@elastic/eslint-import-resolver-kibana']);
}
function getRootPackageDir(dirRoot, dir, rootPackageName) {
if (dirRoot === dir) return null;
const pkgFile = resolve(dir, 'package.json');
try {
accessSync(pkgFile);
// if rootPackageName is not provided, stop when package.json is found
if (!rootPackageName) return dir;
// if rootPackageName is provided, check for match
const { name, config } = JSON.parse(readFileSync(pkgFile));
const { projectRoot } = getConfig(config);
if (projectRoot && name === rootPackageName) return dir;
// recurse until a matching package.json is found
return getRootPackageDir(dirRoot, dirname(dir), rootPackageName);
} catch (e) {
if (e.code === 'ENOENT') return getRootPackageDir(dirRoot, dirname(dir), rootPackageName);
throw e;
}
}
exports.getProjectRoot = function (file, config) {
const { root, dir } = parse(resolve(file));
const { rootPackageName } = config;
const projectRoot = getRootPackageDir(root, dir, rootPackageName);
if (projectRoot === null) throw new Error('Failed to find plugin root');
debug(`Resolved project root: ${projectRoot}`);
return projectRoot;
};

View file

@ -1,25 +0,0 @@
/*
* 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.
*/
const { resolve } = require('path');
exports.getWebpackConfig = function (kibanaPath) {
return {
context: kibanaPath,
resolve: {
extensions: ['.js', '.json', '.ts', '.tsx'],
mainFields: ['browser', 'main'],
modules: ['node_modules', resolve(kibanaPath, 'node_modules')],
alias: {
// Dev defaults for test bundle https://github.com/elastic/kibana/blob/6998f074542e8c7b32955db159d15661aca253d7/src/core_plugins/tests_bundle/index.js#L73-L78
fixtures: resolve(kibanaPath, 'src/fixtures'),
},
unsafeCache: true,
},
};
};

View file

@ -1,31 +0,0 @@
/*
* 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.
*/
/**
* Attempt to apply basic webpack alias transformations so we can
* avoid triggering the webpack resolver for many imports
*
* @param {string} source
* @param {Array<[alias,path]>} aliasEntries
* @return {string|undefined}
*/
exports.resolveWebpackAlias = function (source, aliasEntries) {
for (const [alias, path] of aliasEntries) {
if (source === alias) {
return path;
}
if (alias.endsWith('$')) {
if (source === alias.slice(0, -1)) {
return path;
}
} else if (source.startsWith(alias + '/')) {
return path + '/' + source.slice(alias.length + 1);
}
}
};

View file

@ -1,15 +0,0 @@
{
"name": "@kbn/eslint-import-resolver-kibana",
"description": "eslint-plugin-import resolver for Kibana",
"private": true,
"version": "2.0.0",
"main": "import_resolver_kibana.js",
"license": "SSPL-1.0 OR Elastic License 2.0",
"kibana": {
"devOnly": true
},
"repository": {
"type": "git",
"url": "https://github.com/elastic/kibana/tree/main/packages/kbn-eslint-import-resolver-kibana"
}
}

View file

@ -27,8 +27,8 @@
* THE SOFTWARE.
*/
const path = require('path');
const resolve = require('eslint-module-utils/resolve').default;
const mm = require('micromatch');
const { resolveKibanaImport } = require('@kbn/eslint-plugin-imports');
function isStaticRequire(node) {
return (
@ -90,6 +90,11 @@ module.exports = {
},
create(context) {
const sourcePath = context.getPhysicalFilename
? context.getPhysicalFilename()
: context.getFilename();
const sourceDirname = path.dirname(sourcePath);
const options = context.options[0] || {};
const zones = options.zones || [];
const basePath = options.basePath;
@ -98,16 +103,15 @@ module.exports = {
}
function checkForRestrictedImportPath(importPath, node) {
const absoluteImportPath = importPath[0] === '.' ? resolve(importPath, context) : undefined;
const resolveReport = resolveKibanaImport(importPath, sourceDirname);
if (resolveReport?.type !== 'file' || resolveReport.nodeModule) {
return;
}
const currentFilename = context.getFilename();
for (const { target, from, allowSameFolder, errorMessage = '' } of zones) {
const srcFilePath = resolve(currentFilename, context);
const relativeSrcFile = path.relative(basePath, srcFilePath);
const relativeImportFile = absoluteImportPath
? path.relative(basePath, absoluteImportPath)
: importPath;
const relativeSrcFile = path.relative(basePath, sourcePath);
const relativeImportFile = path.relative(basePath, resolveReport.absolute);
if (
!mm([relativeSrcFile], target).length ||

View file

@ -29,6 +29,7 @@
const path = require('path');
const { RuleTester } = require('eslint');
const { REPO_ROOT } = require('@kbn/utils');
const rule = require('./no_restricted_paths');
const ruleTester = new RuleTester({
@ -346,10 +347,10 @@ ruleTester.run('@kbn/eslint/no-restricted-paths', rule, {
{
// Does not allow to import deeply within Core, using "src/core/..." Webpack alias.
code: 'const d = require("src/core/server/saved_objects")',
filename: path.join(__dirname, './__fixtures__/no_restricted_paths/client/a.js'),
filename: path.join(REPO_ROOT, './__fixtures__/no_restricted_paths/client/a.js'),
options: [
{
basePath: __dirname,
basePath: REPO_ROOT,
zones: [
{
target: '__fixtures__/no_restricted_paths/**/*',
@ -367,56 +368,6 @@ ruleTester.run('@kbn/eslint/no-restricted-paths', rule, {
],
},
{
// Does not allow to import "ui/kfetch".
code: 'const d = require("ui/kfetch")',
filename: path.join(__dirname, './__fixtures__/no_restricted_paths/client/a.js'),
options: [
{
basePath: __dirname,
zones: [
{
from: ['src/legacy/ui/**/*', 'ui/**/*'],
target: '__fixtures__/no_restricted_paths/**/*',
allowSameFolder: true,
},
],
},
],
errors: [
{
message: 'Unexpected path "ui/kfetch" imported in restricted zone.',
line: 1,
column: 19,
},
],
},
{
// Does not allow to import deeply "ui/kfetch/public/index".
code: 'const d = require("ui/kfetch/public/index")',
filename: path.join(__dirname, './__fixtures__/no_restricted_paths/client/a.js'),
options: [
{
basePath: __dirname,
zones: [
{
from: ['src/legacy/ui/**/*', 'ui/**/*'],
target: '__fixtures__/no_restricted_paths/**/*',
allowSameFolder: true,
},
],
},
],
errors: [
{
message: 'Unexpected path "ui/kfetch/public/index" imported in restricted zone.',
line: 1,
column: 19,
},
],
},
{
// Don't use index*.
// It won't work with dirs that start with 'index'.

View file

@ -0,0 +1,125 @@
load("@npm//@bazel/typescript:index.bzl", "ts_config")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
PKG_DIRNAME = "kbn-eslint-plugin-imports"
PKG_REQUIRE_NAME = "@kbn/eslint-plugin-imports"
SOURCE_FILES = glob(
[
"src/**/*.ts",
],
exclude = [
"**/*.test.*",
],
)
SRCS = SOURCE_FILES
filegroup(
name = "srcs",
srcs = SRCS,
)
NPM_MODULE_EXTRA_FILES = [
"package.json",
]
# In this array place runtime dependencies, including other packages and NPM packages
# which must be available for this code to run.
#
# To reference other packages use:
# "//repo/relative/path/to/package"
# eg. "//packages/kbn-utils"
#
# To reference a NPM package use:
# "@npm//name-of-package"
# eg. "@npm//lodash"
RUNTIME_DEPS = [
"//packages/kbn-utils",
"@npm//resolve",
"@npm//@typescript-eslint/typescript-estree",
"@npm//eslint",
"@npm//normalize-path",
]
# In this array place dependencies necessary to build the types, which will include the
# :npm_module_types target of other packages and packages from NPM, including @types/*
# packages.
#
# To reference the types for another package use:
# "//repo/relative/path/to/package:npm_module_types"
# eg. "//packages/kbn-utils:npm_module_types"
#
# References to NPM packages work the same as RUNTIME_DEPS
TYPES_DEPS = [
"//packages/kbn-utils:npm_module_types",
"//packages/kbn-dev-utils:npm_module_types", # only required for the tests, which are excluded except on windows
"@npm//@types/eslint",
"@npm//@types/jest",
"@npm//@types/node",
"@npm//@types/normalize-path",
"@npm//@types/resolve",
"@npm//@typescript-eslint/typescript-estree",
]
jsts_transpiler(
name = "target_node",
srcs = SRCS,
build_pkg_name = package_name(),
)
ts_config(
name = "tsconfig",
src = "tsconfig.json",
deps = [
"//:tsconfig.base.json",
"//:tsconfig.bazel.json",
],
)
ts_project(
name = "tsc_types",
args = ['--pretty'],
srcs = SRCS,
deps = TYPES_DEPS,
declaration = True,
emit_declaration_only = True,
out_dir = "target_types",
root_dir = "src",
tsconfig = ":tsconfig",
)
js_library(
name = PKG_DIRNAME,
srcs = NPM_MODULE_EXTRA_FILES,
deps = RUNTIME_DEPS + [":target_node"],
package_name = PKG_REQUIRE_NAME,
visibility = ["//visibility:public"],
)
pkg_npm(
name = "npm_module",
deps = [":" + PKG_DIRNAME],
)
filegroup(
name = "build",
srcs = [":npm_module"],
visibility = ["//visibility:public"],
)
pkg_npm_types(
name = "npm_module_types",
srcs = SRCS,
deps = [":tsc_types"],
package_name = PKG_REQUIRE_NAME,
tsconfig = ":tsconfig",
visibility = ["//visibility:public"],
)
filegroup(
name = "build_types",
srcs = [":npm_module_types"],
visibility = ["//visibility:public"],
)

View file

@ -0,0 +1,9 @@
# @kbn/eslint-plugin-imports
ESLint plugin providing custom rules for validating imports in the Kibana repo with custom logic beyond what's possible with custom config to eslint-plugin-imports and even a custom resolver
## `resolveKibanaImport(request: string, dirname: string)`
Resolve an import request (the "from" string from an import statement, or any other relative/absolute import path) from a given directory. The `dirname` should be the same for all files in a given directory.
Result will be `null` when the import path does not resolve, but all valid/committed import paths *should* resolve. Other result values are documented in src/resolve_result.ts.

View file

@ -6,12 +6,8 @@
* Side Public License, v 1.
*/
module.exports = Object.assign(
{},
require('./get_kibana_path'),
require('./get_project_root'),
require('./get_webpack_config'),
require('./get_path_type'),
require('./get_is_path_request'),
require('./resolve_webpack_alias')
);
module.exports = {
preset: '@kbn/test/jest_integration_node',
rootDir: '../..',
roots: ['<rootDir>/packages/kbn-eslint-plugin-imports'],
};

View file

@ -0,0 +1,7 @@
{
"name": "@kbn/eslint-plugin-imports",
"private": true,
"version": "1.0.0",
"main": "./target_node/index.js",
"license": "SSPL-1.0 OR Elastic License 2.0"
}

View file

@ -0,0 +1,36 @@
/*
* 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 Fs from 'fs';
import { memoize } from './memoize';
const runningInEditor = !!process.env.VSCODE_CWD;
const safeStat = (path: string) => {
try {
return Fs.statSync(path);
} catch (error) {
if (error?.code === 'ENOENT') {
return undefined;
}
throw error;
}
};
function _isDirectory(path: string) {
return !!safeStat(path)?.isDirectory();
}
function _isFile(path: string) {
return !!safeStat(path)?.isFile();
}
export const isDirectory = runningInEditor ? _isDirectory : memoize(_isDirectory);
export const isFile = runningInEditor ? _isFile : memoize(_isFile);

View file

@ -0,0 +1,22 @@
/*
* 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.
*/
export function memoize<T, T2>(fn: (arg: T) => T2): (arg: T) => T2 {
const cache = new Map<T, T2>();
return (arg) => {
const cached = cache.get(arg);
if (cached !== undefined) {
return cached;
}
const result = fn(arg);
cache.set(arg, result);
return result;
};
}

View file

@ -0,0 +1,78 @@
/*
* 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 { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/typescript-estree';
// @ts-expect-error no types for this module
import moduleVisitor from 'eslint-module-utils/moduleVisitor';
type Importers =
| TSESTree.ImportDeclaration
| TSESTree.ExportNamedDeclaration
| TSESTree.ExportAllDeclaration
| TSESTree.CallExpression
| TSESTree.ImportExpression
| TSESTree.CallExpression;
type ImportVisitor = (req: string, node: Importers) => void;
/**
* Create an ESLint rule visitor that calls visitor() for every import string, including
* 'export from' statements, require() calls, jest.mock() calls, and more.
*/
export function visitAllImportStatements(visitor: ImportVisitor) {
const baseWrapper = moduleVisitor(
(reqNode: TSESTree.Literal, importer: Importers) => {
const req = reqNode.value;
if (typeof req !== 'string') {
throw new Error('unable to read value of import request');
}
visitor(req, importer);
},
{
esmodules: true,
commonjs: true,
}
);
const baseCallExpressionVisitor = baseWrapper.CallExpression;
/**
* wrapper around the base wrapper which also picks up calls to jest.<any>('../<any>' or '@kbn/<any>', ...) as "import statements"
* @param {CallExpression} node
*/
baseWrapper.CallExpression = (node: TSESTree.CallExpression) => {
const { callee } = node;
// is this call expression a represenation of an obj.method() call?
if (callee.type === AST_NODE_TYPES.MemberExpression) {
const { object } = callee;
// is the object being called named "jest"?
if (object.type === AST_NODE_TYPES.Identifier && object.name === 'jest') {
const [path] = node.arguments;
// is the first argument to the method a string which starts with '../' or '@kbn/'?
if (
path &&
path.type === AST_NODE_TYPES.Literal &&
typeof path.value === 'string' &&
(path.value.startsWith('../') || path.value.startsWith('@kbn/'))
) {
// call our visitor and assume this node represents a call to a jest mocking function and validate the relative path
visitor(path.value, node);
}
return;
}
}
return baseCallExpressionVisitor(node);
};
return baseWrapper;
}

View file

@ -0,0 +1,20 @@
/*
* 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.
*/
export * from './resolve_kibana_import';
export * from './resolve_result';
import { NoUnresolvedImportsRule } from './rules/no_unresolved_imports';
/**
* Custom ESLint rules, add `'@kbn/eslint-plugin-imports'` to your eslint config to use them
* @internal
*/
export const rules = {
no_unresolved_imports: NoUnresolvedImportsRule,
};

View file

@ -0,0 +1,158 @@
/*
* 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 Path from 'path';
import { REPO_ROOT } from '@kbn/utils';
import { createAbsolutePathSerializer } from '@kbn/dev-utils';
import { resolveKibanaImport } from '../resolve_kibana_import';
expect.addSnapshotSerializer(createAbsolutePathSerializer());
const plugin = (subPath: string) => Path.resolve(REPO_ROOT, 'src/plugins', subPath);
const xPlugin = (subPath: string) => Path.resolve(REPO_ROOT, 'x-pack/plugins', subPath);
const pkg = (subPath: string) => Path.resolve(REPO_ROOT, 'packages', subPath);
describe('standard import formats', () => {
it('resolves requests to src/', () => {
expect(resolveKibanaImport('src/core/public', plugin('discovery/public/components/foo')))
.toMatchInlineSnapshot(`
Object {
"absolute": <absolute path>/src/core/public/index.ts,
"type": "file",
}
`);
expect(resolveKibanaImport('src/core/server', xPlugin('spaces/server/routes')))
.toMatchInlineSnapshot(`
Object {
"absolute": <absolute path>/src/core/server/index.ts,
"type": "file",
}
`);
expect(resolveKibanaImport('src/core/utils', pkg('kbn-dev-utils/lib'))).toMatchInlineSnapshot(`
Object {
"absolute": <absolute path>/src/core/utils/index.ts,
"type": "file",
}
`);
});
it('resolves relative paths too', () => {
expect(resolveKibanaImport('../../../../core/public', plugin('foo/bar/baz')))
.toMatchInlineSnapshot(`
Object {
"absolute": <absolute path>/src/core/public/index.ts,
"type": "file",
}
`);
});
it('resolves @kbn/ imports', () => {
expect(resolveKibanaImport('@kbn/std', pkg('kbn-dev-utils/src'))).toMatchInlineSnapshot(`
Object {
"absolute": <absolute path>/node_modules/@kbn/std/target_node/index.js,
"nodeModule": "@kbn/std",
"type": "file",
}
`);
});
it('resolves @elastic/ imports', () => {
expect(resolveKibanaImport('@elastic/datemath', pkg('kbn-dev-utils/src')))
.toMatchInlineSnapshot(`
Object {
"absolute": <absolute path>/node_modules/@elastic/datemath/target_node/index.js,
"nodeModule": "@elastic/datemath",
"type": "file",
}
`);
expect(resolveKibanaImport('@elastic/eui', pkg('kbn-dev-utils/src'))).toMatchInlineSnapshot(`
Object {
"absolute": <absolute path>/node_modules/@elastic/eui/lib/index.js,
"nodeModule": "@elastic/eui",
"type": "file",
}
`);
});
it('resolves normal node module imports', () => {
expect(resolveKibanaImport('lodash', pkg('kbn-dev-utils/src'))).toMatchInlineSnapshot(`
Object {
"absolute": <absolute path>/node_modules/lodash/lodash.js,
"nodeModule": "lodash",
"type": "file",
}
`);
expect(resolveKibanaImport('globby', pkg('kbn-dev-utils/src'))).toMatchInlineSnapshot(`
Object {
"absolute": <absolute path>/node_modules/globby/index.js,
"nodeModule": "globby",
"type": "file",
}
`);
});
it('returns null when the import cannot be resolved', () => {
expect(resolveKibanaImport('../../../../invalid', plugin('foo/bar'))).toMatchInlineSnapshot(
`null`
);
expect(resolveKibanaImport('src/invalid', plugin('foo/bar'))).toMatchInlineSnapshot(`null`);
expect(resolveKibanaImport('kibana/invalid', plugin('foo/bar'))).toMatchInlineSnapshot(`null`);
expect(resolveKibanaImport('@kbn/invalid', plugin('foo/bar'))).toMatchInlineSnapshot(`null`);
});
it('returns ignore results for known unresolvable but okay import statements', () => {
expect(resolveKibanaImport('../../grammar/built_grammar.js', plugin('foo/bar')))
.toMatchInlineSnapshot(`
Object {
"type": "ignore",
}
`);
expect(resolveKibanaImport('kibana-buildkite-library', pkg('kbn-foo/src')))
.toMatchInlineSnapshot(`
Object {
"type": "ignore",
}
`);
expect(resolveKibanaImport('core_styles', pkg('kbn-foo/src'))).toMatchInlineSnapshot(`
Object {
"type": "ignore",
}
`);
expect(resolveKibanaImport('core_app_image_assets', pkg('kbn-foo/src'))).toMatchInlineSnapshot(`
Object {
"type": "ignore",
}
`);
expect(resolveKibanaImport('ace/lib/dom', pkg('kbn-foo/src'))).toMatchInlineSnapshot(`
Object {
"type": "ignore",
}
`);
expect(resolveKibanaImport('@elastic/eui/src/components/', pkg('kbn-foo/src')))
.toMatchInlineSnapshot(`
Object {
"type": "ignore",
}
`);
expect(resolveKibanaImport('@elastic/eui/src/services/', pkg('kbn-foo/src')))
.toMatchInlineSnapshot(`
Object {
"type": "ignore",
}
`);
});
});

View file

@ -0,0 +1,161 @@
/*
* 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 Fs from 'fs';
import Path from 'path';
import Resolve from 'resolve';
import { REPO_ROOT } from '@kbn/utils';
import { isDirectory, isFile } from './helpers/fs';
import { ResolveResult } from './resolve_result';
const NODE_MODULE_SEG = Path.sep + 'node_modules' + Path.sep;
function packageFilter(pkg: Record<string, unknown>) {
if (!pkg.main && pkg.types) {
// for the purpose of resolving files, a "types" file is adequate
return {
...pkg,
main: pkg.types,
};
}
return pkg;
}
function adaptReq(req: string, dirname: string): string | undefined {
// transform webpack loader requests and focus on the actual file selected
if (req.startsWith('!!')) {
return req.split('!').pop()?.split('?').shift();
}
// handle typescript aliases
if (req === 'kibana/public') {
return adaptReq('src/core/public', dirname);
}
if (req === 'kibana/server') {
return adaptReq('src/core/server', dirname);
}
// turn root-relative paths into relative paths
if (
req.startsWith('src/') ||
req.startsWith('x-pack/') ||
req.startsWith('examples/') ||
req.startsWith('test/')
) {
const absolute = Path.resolve(REPO_ROOT, req);
return `./${Path.relative(dirname, absolute)}`;
}
}
function shouldResolve(req: string) {
// this library is only installed on CI and never resolvable
if (req === 'kibana-buildkite-library') {
return;
}
// these are special webpack-aliases only used in storybooks, ignore them
if (req === 'core_styles' || req === 'core_app_image_assets') {
return;
}
// ignore amd require done by ace syntax plugin
if (req === 'ace/lib/dom') {
return;
}
// ignore requests to grammar/built_grammar.js files or built kbn-monaco workers, these are built by bazel and never resolvable
if (
req.endsWith('grammar/built_grammar.js') ||
(req.includes('/target_workers/') && req.endsWith('.editor.worker.js'))
) {
return;
}
// typescript validates these imports fine and they're purely virtual thanks to ambient type definitions in @elastic/eui so /shrug
if (
req.startsWith('@elastic/eui/src/components/') ||
req.startsWith('@elastic/eui/src/services/')
) {
return;
}
return true;
}
function tryNodeResolve(req: string, dirname: string): ResolveResult | null {
try {
const path = Resolve.sync(req, {
basedir: dirname,
extensions: ['.js', '.json', '.ts', '.tsx', '.d.ts'],
isDirectory,
isFile,
packageFilter,
});
if (path.includes(NODE_MODULE_SEG)) {
const modulePath = path.split(NODE_MODULE_SEG).pop()!.split(Path.sep);
const moduleId = modulePath[0].startsWith('@')
? `${modulePath[0]}/${modulePath[1]}`
: modulePath[0];
return {
type: 'file',
absolute: path,
nodeModule: moduleId,
};
}
return {
type: 'file',
absolute: path.includes('node_modules') ? Fs.readlinkSync(path) : path,
};
} catch (error) {
if (error && error.code === 'MODULE_NOT_FOUND') {
return null;
}
throw error;
}
}
function tryTypesResolve(req: string, dirname: string): ResolveResult | null {
const parts = req.split('/');
const nmParts = parts[0].startsWith('@') ? [parts[0].slice(1), parts[1]] : [parts[0]];
const typesReq = `@types/${nmParts.join('__')}`;
const result = tryNodeResolve(typesReq, dirname);
if (result) {
return {
type: '@types',
module: typesReq,
};
}
return null;
}
/**
* Resolve an import request. All import requests in the repository should return a result, if they don't it's a bug
* which should be caught by the `@kbn/import/no_unresolved` rule, which should never be disabled. If you need help
* adding support for an import style please reach out to operations.
*
* @param req Text from an import/require, like `../../src/core/public` or `@kbn/std`
* @param dirname The directory of the file where the req was found
*/
export function resolveKibanaImport(req: string, dirname: string): ResolveResult | null {
req = adaptReq(req, dirname) ?? req;
if (!shouldResolve(req)) {
return { type: 'ignore' };
}
return tryNodeResolve(req, dirname) ?? tryTypesResolve(req, dirname);
}

View file

@ -0,0 +1,43 @@
/*
* 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.
*/
/**
* Resolution result indicating that the import request can't be resolved, but it shouldn't need to be
* because the file that is imported can't be resolved from the source alone, usually because it is explicitly
* importing a build asset. Import requests which meet this criteria are manually added to the resolver and
* can be trusted to exist after the build it complete or in their used location.
*/
export interface IgnoreResult {
type: 'ignore';
}
/**
* Resolution result indicating that the import only resolves to an @types package, including the name of
* the @types package. We don't validate the sub-path of these import strings and assume that TS will validate
* them, we just need to know that they don't map to actual files on the filesystem or modules which will
* end up in the build or running code.
*/
export interface TypesResult {
type: '@types';
module: string;
}
/**
* Resolution result indicating that the import resolves to a specific file, possible in a nodeModule, with
* the path of that file and the name of the nodeModule if applicable
*/
export interface FileResult {
type: 'file';
absolute: string;
nodeModule?: string;
}
/**
* Possible resolve result types
*/
export type ResolveResult = IgnoreResult | TypesResult | FileResult;

View file

@ -0,0 +1,34 @@
/*
* 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 Path from 'path';
import { Rule } from 'eslint';
import { resolveKibanaImport } from '../resolve_kibana_import';
import { visitAllImportStatements } from '../helpers/visit_all_import_statements';
export const NoUnresolvedImportsRule: Rule.RuleModule = {
create(context) {
const sourceFilename = context.getPhysicalFilename
? context.getPhysicalFilename()
: context.getFilename();
if (!sourceFilename) {
throw new Error('unable to determine sourceFilename for file being linted');
}
return visitAllImportStatements((req, importer) => {
if (!resolveKibanaImport(req, Path.dirname(sourceFilename))) {
context.report({
node: importer as any,
message: `Unable to resolve import [${req}]`,
});
}
});
},
};

View file

@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.bazel.json",
"compilerOptions": {
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "target_types",
"rootDir": "src",
"stripInternal": false,
"types": [
"jest",
"node"
]
},
"include": [
"src/**/*"
]
}

View file

@ -52,7 +52,7 @@ peggy(
"--allowed-start-rules",
"expression,argument",
"-o",
"$(@D)/index.js",
"$(@D)/built_grammar.js",
"./%s/grammar/grammar.peggy" % package_name()
],
)

View file

@ -6,6 +6,6 @@
* Side Public License, v 1.
*/
declare module '*/grammar' {
declare module '*/grammar/built_grammar.js' {
export const parse: import('./parse').Parse;
}

View file

@ -7,7 +7,7 @@
*/
import type { Ast, AstWithMeta } from './ast';
import { parse } from '../../../grammar';
import { parse } from '../../../grammar/built_grammar.js';
interface Options {
startRule?: string;

View file

@ -24,7 +24,7 @@ import { VocabularyImpl } from "antlr4ts/VocabularyImpl";
import * as Utils from "antlr4ts/misc/Utils";
import { painless_parserListener } from "./painless_parserListener";
import { painless_parserListener } from "./painless_parser_listener";
export class painless_parser extends Parser {
public static readonly WS = 1;

File diff suppressed because one or more lines are too long

View file

@ -17,7 +17,7 @@ peggy(
output_dir = True,
args = [
"-o",
"$(@D)/chain.js",
"$(@D)/built_grammar.js",
"./%s/grammar/chain.peggy" % package_name()
],
)

View file

@ -3,5 +3,5 @@
"version": "1.0.0",
"license": "SSPL-1.0 OR Elastic License 2.0",
"private": true,
"main": "grammar/chain.js"
"main": "grammar/built_grammar.js"
}

View file

@ -39,7 +39,7 @@ peggy(
output_dir = True,
args = [
"-o",
"$(@D)/index.js",
"$(@D)/built_grammar.js",
"./%s/grammar/grammar.peggy" % package_name()
],
)

View file

@ -8,9 +8,8 @@
const { get } = require('lodash');
const memoizeOne = require('memoize-one');
// eslint-disable-next-line import/no-unresolved
const { parse: parseFn } = require('../grammar');
const { functions: includedFunctions } = require('./functions');
const { parse: parseFn } = require('../grammar/built_grammar.js');
function parse(input, options) {
if (input == null) {

View file

@ -7,12 +7,12 @@
*/
import Path from 'path';
import Fs from 'fs';
import loadJsonFile from 'load-json-file';
const readKibanaPkgJson = (dir: string) => {
const readKibanaPkgJson = (path: string) => {
try {
const path = Path.resolve(dir, 'package.json');
const json = loadJsonFile.sync(path);
if (json && typeof json === 'object' && 'name' in json && json.name === 'kibana') {
return json;
@ -34,10 +34,14 @@ const findKibanaPackageJson = () => {
const { root: rootDir } = Path.parse(startDir);
let cursor = startDir;
while (true) {
const kibanaPkgJson = readKibanaPkgJson(cursor);
const packageJsonPath = Path.resolve(cursor, 'package.json');
const kibanaPkgJson = readKibanaPkgJson(packageJsonPath);
if (kibanaPkgJson) {
return {
kibanaDir: cursor,
// when this script is run by ESLint in IDEs it doesn't use --preserve-symlinks, so we have to
// use `Fs.realpathSync()` to resolve the package.json path to the actual file in the repo rather
// than the sym-linked version in the bazel-out dir
kibanaDir: Path.dirname(Fs.realpathSync(packageJsonPath)),
kibanaPkgJson: kibanaPkgJson as {
name: string;
branch: string;

View file

@ -13,7 +13,6 @@ import cheerio from 'cheerio';
import fs from 'fs';
import fetch from 'node-fetch';
import path from 'path';
import { PackageJson } from 'type-fest';
type PuppeteerRelease = string;
type ChromiumRevision = string;
@ -27,7 +26,7 @@ const forkCompatibilityMap: Record<string, PuppeteerRelease> = {
async function getPuppeteerRelease(log: ToolingLog): Promise<PuppeteerRelease> {
// open node_modules/puppeteer/package.json
const puppeteerPackageJson: PackageJson = JSON.parse(
const puppeteerPackageJson = JSON.parse(
fs.readFileSync(path.resolve(REPO_ROOT, 'node_modules', 'puppeteer', 'package.json'), 'utf8')
);
const { version } = puppeteerPackageJson;

View file

@ -6,7 +6,6 @@
* Side Public License, v 1.
*/
/* eslint import/no-unresolved: 0 */
import ace from 'brace';
ace.define('ace/theme/sense-dark', ['require', 'exports', 'module'], function (require, exports) {

View file

@ -12,6 +12,7 @@ import { i18n } from '@kbn/i18n';
import type { SerializableRecord } from '@kbn/utility-types';
import { Assign, Ensure } from '@kbn/utility-types';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { ISearchOptions, ISearchSource } from 'src/plugins/data/public';
import { ExpressionAstExpression, ExpressionAstArgument } from 'src/plugins/expressions/common';
import type { SerializedFieldFormat } from 'src/plugins/field_formats/common';

View file

@ -18,6 +18,7 @@ import {
ISearchOptions,
ISearchSource,
RangeFilter,
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
} from 'src/plugins/data/public';
import { AggConfig, AggConfigSerialized, IAggConfig } from './agg_config';
import { IAggType } from './agg_type';

View file

@ -9,6 +9,7 @@
import { constant, noop, identity } from 'lodash';
import { i18n } from '@kbn/i18n';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { ISearchSource } from 'src/plugins/data/public';
import { DatatableColumnType } from 'src/plugins/expressions/common';
import type { RequestAdapter } from 'src/plugins/inspector/common';

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { ISearchOptions, ISearchSource } from 'src/plugins/data/public';
import { ExpressionAstExpression } from 'src/plugins/expressions/common';
import { IAggConfigs } from '../agg_configs';

View file

@ -15,6 +15,7 @@
import { i18n } from '@kbn/i18n';
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import type { ISearchSource } from 'src/plugins/data/public';
import type { RequestStatistics } from 'src/plugins/inspector/common';

View file

@ -7,6 +7,7 @@
*/
import type * as estypes from '@elastic/elasticsearch/lib/api/typesWithBodyKey';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { AggConfigSerialized, IAggConfigs } from 'src/plugins/data/public';
import { SerializableRecord } from '@kbn/utility-types';
import { Query } from '../..';

View file

@ -12,6 +12,7 @@ import type {
SavedObject,
SavedObjectsFindResponse,
SavedObjectsUpdateResponse,
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
} from 'kibana/server';
import type { SearchSessionSavedObjectAttributes } from '../../../common';
export type SearchSessionSavedObject = SavedObject<SearchSessionSavedObjectAttributes>;

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { PackageInfo } from 'kibana/server';
import { SearchUsageCollector } from './collectors';
import { AggsSetup, AggsSetupDependencies, AggsStartDependencies, AggsStart } from './aggs';

View file

@ -11,6 +11,7 @@ import { act } from 'react-dom/test-utils';
import { shallowWithIntl as shallow } from '@kbn/test-jest-helpers';
import { ShallowWrapper } from 'enzyme';
import { ChangeIndexPattern } from './change_indexpattern';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { SavedObject } from 'kibana/server';
import { DiscoverIndexPattern, DiscoverIndexPatternProps } from './discover_index_pattern';
import { EuiSelectable } from '@elastic/eui';

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { SavedObjectAttributes } from 'kibana/server';
import { IEmbeddable } from './i_embeddable';
import { EmbeddableFactory } from './embeddable_factory';

View file

@ -7,6 +7,7 @@
*/
import { errors } from '@elastic/elasticsearch';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { IKibanaResponse, KibanaResponseFactory } from 'kibana/server';
import { getEsCause } from './es_error_parser';

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { SavedObjectsFindOptionsReference } from 'kibana/server';
import { SavedObjectsTaggingApi } from '../../../saved_objects_tagging_oss/public';

View file

@ -8,6 +8,7 @@
import { LocatorDefinition } from './types';
import { Locator, LocatorDependencies } from './locator';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { KibanaLocation } from 'src/plugins/share/public';
import { LocatorGetUrlParams } from '.';
import { decompressFromBase64 } from 'lz-string';

View file

@ -7,6 +7,7 @@
*/
import type { SerializableRecord } from '@kbn/utility-types';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import type { SavedObjectReference } from 'kibana/server';
import { DependencyList } from 'react';
import type { PersistableState } from 'src/plugins/kibana_utils/common';

View file

@ -8,6 +8,7 @@
import type { SerializableRecord } from '@kbn/utility-types';
import { MigrateFunctionsObject } from 'src/plugins/kibana_utils/common';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { SavedObjectReference } from 'kibana/server';
import type { LocatorDependencies } from './locator';
import type { LocatorDefinition, LocatorPublic, ILocatorClient, LocatorData } from './types';

View file

@ -6,6 +6,4 @@
* Side Public License, v 1.
*/
// @ts-ignore
export { validateInterval } from './validate_interval';
export { getTimezone } from './get_timezone';

View file

@ -6,6 +6,7 @@
* Side Public License, v 1.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { SavedObjectAttributes } from 'kibana/server';
import type { SerializableRecord } from '@kbn/utility-types';
import { AggConfigSerialized, SerializedSearchSourceFields } from 'src/plugins/data/common';

View file

@ -9,6 +9,7 @@
import semverGte from 'semver/functions/gte';
import { makeVisualizeEmbeddableFactory } from './make_visualize_embeddable_factory';
import { getAllMigrations } from '../migrations/visualization_saved_object_migrations';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { SerializedSearchSourceFields } from 'src/plugins/data/public';
import { GetMigrationFunctionObjectFn } from 'src/plugins/kibana_utils/common';

View file

@ -9,6 +9,7 @@
import { flow, mapValues } from 'lodash';
import { EmbeddableRegistryDefinition } from 'src/plugins/embeddable/server';
import type { SerializableRecord } from '@kbn/utility-types';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { SerializedSearchSourceFields } from 'src/plugins/data/public';
import {
mergeMigrationFunctionMaps,

View file

@ -9,8 +9,6 @@
import { setTimeout as setTimeoutAsync } from 'timers/promises';
import { cloneDeepWith } from 'lodash';
import { Key, Origin, WebDriver } from 'selenium-webdriver';
// @ts-ignore internal modules are not typed
import { LegacyActionSequence } from 'selenium-webdriver/lib/actions';
import { modifyUrl } from '@kbn/std';
import Jimp from 'jimp';

View file

@ -1,14 +0,0 @@
{
"name": "embedded_lens_example",
"version": "1.0.0",
"main": "target/examples/embedded_lens_example",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"
},
"license": "Elastic License 2.0",
"scripts": {
"kbn": "node ../../../scripts/kbn.js",
"build": "rm -rf './target' && ../../../node_modules/.bin/tsc"
}
}

View file

@ -1,14 +0,0 @@
{
"name": "exploratory_view_example",
"version": "1.0.0",
"main": "target/examples/exploratory_view_example",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"
},
"license": "Elastic License 2.0",
"scripts": {
"kbn": "node ../../../scripts/kbn.js",
"build": "rm -rf './target' && ../../../node_modules/.bin/tsc"
}
}

View file

@ -1,14 +0,0 @@
{
"name": "testing_embedded_lens",
"version": "1.0.0",
"main": "target/examples/testing_embedded_lens",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"
},
"license": "Elastic License 2.0",
"scripts": {
"kbn": "node ../../../scripts/kbn.js",
"build": "rm -rf './target' && ../../../node_modules/.bin/tsc"
}
}

View file

@ -1,14 +0,0 @@
{
"name": "third_party_lens_navigation_prompt",
"version": "1.0.0",
"main": "target/examples/third_party_lens_navigation_prompt",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"
},
"license": "Elastic License 2.0",
"scripts": {
"kbn": "node ../../../scripts/kbn.js",
"build": "rm -rf './target' && ../../../node_modules/.bin/tsc"
}
}

View file

@ -1,14 +0,0 @@
{
"name": "third_party_vis_lens_example",
"version": "1.0.0",
"main": "target/examples/third_party_vis_lens_example",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"
},
"license": "Elastic License 2.0",
"scripts": {
"kbn": "node ../../../scripts/kbn.js",
"build": "rm -rf './target' && ../../../node_modules/.bin/tsc"
}
}

View file

@ -1,14 +0,0 @@
{
"name": "ui_actions_enhanced_examples",
"version": "1.0.0",
"main": "target/examples/ui_actions_enhanced_examples",
"kibana": {
"version": "kibana",
"templateVersion": "1.0.0"
},
"license": "Elastic License 2.0",
"scripts": {
"kbn": "node ../../../scripts/kbn.js",
"build": "rm -rf './target' && ../../../node_modules/.bin/tsc"
}
}

View file

@ -9,6 +9,7 @@ import {
SavedObjectAttribute,
SavedObjectAttributes,
SavedObjectsResolveResponse,
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
} from 'kibana/server';
import { RuleExecutionMetrics } from '.';
import { RuleNotifyWhenType } from './rule_notify_when_type';

View file

@ -294,14 +294,13 @@ function setupRawAlertMocks(
encryptedSavedObjects.getDecryptedAsInternalUser.mockReset();
// splitting this out as it's easier to set a breakpoint :-)
// eslint-disable-next-line prettier/prettier
unsecuredSavedObjectsClient.get.mockImplementation(async () =>
cloneDeep(rawAlert)
);
unsecuredSavedObjectsClient.get.mockImplementation(async () => {
return cloneDeep(rawAlert);
});
encryptedSavedObjects.getDecryptedAsInternalUser.mockImplementation(async () =>
cloneDeep(decryptedRawAlert)
);
encryptedSavedObjects.getDecryptedAsInternalUser.mockImplementation(async () => {
return cloneDeep(decryptedRawAlert);
});
}
// setup for each test

View file

@ -6,8 +6,6 @@
*/
import { Transaction } from '../../../../../typings/es_schemas/ui/transaction';
// @ts-expect-error
import configureStore from '../../../../../store/config/configureStore';
import { getDiscoverQuery } from './discover_transaction_link';
function getMockTransaction() {

View file

@ -14,6 +14,7 @@
import { merge, chunk, flatten, omit } from 'lodash';
import { argv } from 'yargs';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { Logger } from 'kibana/server';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { CollectTelemetryParams } from '../../server/lib/apm_telemetry/collect_data_telemetry';

View file

@ -10,7 +10,7 @@ import { APM_STATIC_INDEX_PATTERN_ID } from '../../../common/index_pattern_const
import { hasHistoricalAgentData } from '../../routes/historical_data/has_historical_agent_data';
import { Setup } from '../../lib/helpers/setup_request';
import { APMRouteHandlerResources } from '../../routes/typings';
import { InternalSavedObjectsClient } from '../../lib/helpers/get_internal_saved_objects_client.js';
import { InternalSavedObjectsClient } from '../../lib/helpers/get_internal_saved_objects_client';
import { withApmSpan } from '../../utils/with_apm_span';
import { getApmDataViewTitle } from './get_apm_data_view_title';
import { getApmDataViewAttributes } from './get_apm_data_view_attributes';

View file

@ -5,11 +5,7 @@
* 2.0.
*/
import '../../../typings/rison_node';
import '../../infra/types/eui';
// EUIBasicTable
import '../../reporting/public/components/report_listing';
import '../../reporting/server/lib/puid';
import './apm_rum_react';
// Allow unknown properties in an object

View file

@ -5,6 +5,7 @@
* 2.0.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { ExpressionFunctionDefinition } from 'src/plugins/expressions/public';
import { ExpressionValueFilter } from '../../types';
import { getFunctionHelp } from '../../i18n';

View file

@ -5,12 +5,11 @@
* 2.0.
*/
import React, { useCallback, FC } from 'react';
import CSS from 'csstype';
import React, { useCallback, FC, CSSProperties } from 'react';
interface Props {
render: (element: HTMLElement) => void;
style?: CSS.Properties;
style?: CSSProperties;
}
export const RenderToDom: FC<Props> = ({ render, style }) => {

View file

@ -4,6 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { ExpressionsServiceSetup } from 'src/plugins/expressions/public';
export interface CanvasSavedObjectTypeMigrationsDeps {

View file

@ -5,7 +5,6 @@
* 2.0.
*/
/* es-lint-disable import/no-extraneous-dependencies */
import { applyMiddleware, Dispatch, Store } from 'redux';
import thunkMiddleware from 'redux-thunk';
import addons from '@storybook/addons';
@ -14,8 +13,6 @@ import { isFunction } from 'lodash';
import { EVENTS } from './constants';
// @ts-expect-error untyped local
import { appReady } from '../../../public/state/middleware/app_ready';
// @ts-expect-error untyped local
import { resolvedArgs } from '../../../public/state/middleware/resolved_args';

View file

@ -5,8 +5,6 @@
* 2.0.
*/
/* es-lint-disable import/no-extraneous-dependencies */
import React from 'react';
import { createStore } from 'redux';
import { Provider as ReduxProvider } from 'react-redux';

View file

@ -5,7 +5,7 @@
* 2.0.
*/
import { canvasStorybookConfig } from './canvas.webpack';
import { canvasStorybookConfig } from './canvas_webpack';
module.exports = canvasStorybookConfig;

View file

@ -5,6 +5,7 @@
* 2.0.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { ElasticsearchClient } from 'kibana/server';
/**

View file

@ -5,6 +5,7 @@
* 2.0.
*/
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import { Privileges } from 'src/plugins/es_ui_shared/public';
import { RouteDependencies } from '../../../types';
import { addBasePath } from '../index';

View file

@ -9,6 +9,7 @@ import { fold } from 'fp-ts/lib/Either';
import { identity } from 'fp-ts/lib/function';
import { pipe } from 'fp-ts/lib/pipeable';
import { Context, Errors, IntersectionType, Type, UnionType, ValidationError } from 'io-ts';
// eslint-disable-next-line @kbn/eslint/no-restricted-paths
import type { RouteValidationFunction } from 'kibana/server';
type ErrorFactory = (message: string) => Error;

Some files were not shown because too many files have changed in this diff Show more