Skip to content

Commit

Permalink
[eslint-import-resolver-kibana] bring in repo as package (elastic#17665)
Browse files Browse the repository at this point in the history
* [eslint-import-resolver-kibana] bring in repo as package

* [eslint-import-resolver] enable prettier
  • Loading branch information
spalger authored Apr 11, 2018
1 parent 7fed7b6 commit 4f2a19b
Show file tree
Hide file tree
Showing 12 changed files with 2,807 additions and 12 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module.exports = {

settings: {
'import/resolver': {
'@elastic/eslint-import-resolver-kibana': {
'@kbn/eslint-import-resolver-kibana': {
rootPackageName: 'kibana',
kibanaPath: '.',
},
Expand All @@ -22,6 +22,7 @@ module.exports = {
'packages/kbn-es/**/*',
'packages/kbn-datemath/**/*.js',
'packages/kbn-plugin-generator/**/*',
'packages/kbn-eslint-import-resolver-kibana/**/*',
],
plugins: ['prettier'],
rules: Object.assign(
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,9 +218,9 @@
},
"devDependencies": {
"@elastic/eslint-config-kibana": "link:packages/eslint-config-kibana",
"@elastic/eslint-import-resolver-kibana": "1.0.0",
"@elastic/eslint-plugin-kibana-custom": "link:packages/eslint-plugin-kibana-custom",
"@kbn/es": "link:packages/kbn-es",
"@kbn/eslint-import-resolver-kibana": "link:packages/kbn-eslint-import-resolver-kibana",
"@kbn/plugin-generator": "link:packages/kbn-plugin-generator",
"angular-mocks": "1.4.7",
"babel-eslint": "8.1.2",
Expand Down
54 changes: 54 additions & 0 deletions packages/kbn-eslint-import-resolver-kibana/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# @elastic/eslint-import-resolver-kibana

Resolver for Kibana imports, meant to be used with [eslint-plugin-import](https://github.com/benmosher/eslint-plugin-import).

## 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.

## 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
```
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:*`.
29 changes: 29 additions & 0 deletions packages/kbn-eslint-import-resolver-kibana/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
const webpackResolver = require('eslint-import-resolver-webpack');
const nodeResolver = require('eslint-import-resolver-node');
const getProjectRoot = require('./lib/get_project_root');
const getWebpackConfig = require('./lib/get_webpack_config');

// cache expensive resolution results
let projectRoot;
let webpackConfig;

exports.resolve = function resolveKibanaPath(source, file, config) {
const settings = config || {};

// try to resolve with the node resolver first
const resolvedWithNode = nodeResolver.resolve(source, file, config);
if (resolvedWithNode && resolvedWithNode.found) {
return resolvedWithNode;
}

// fall back to the webpack resolver
projectRoot = projectRoot || getProjectRoot(file, settings);
webpackConfig =
webpackConfig || getWebpackConfig(source, projectRoot, settings);
return webpackResolver.resolve(source, 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;
3 changes: 3 additions & 0 deletions packages/kbn-eslint-import-resolver-kibana/lib/debug.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const debug = require('debug')('eslint-plugin-import:resolver:kibana');

module.exports = debug;
27 changes: 27 additions & 0 deletions packages/kbn-eslint-import-resolver-kibana/lib/get_kibana_path.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const { resolve } = require('path');
const debug = require('./debug');

const DEFAULT_PLUGIN_PATH = '../../kibana';

/*
* Resolves the path to Kibana, either from default setting or config
*/
module.exports = function getKibanaPath(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 `../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;
};
35 changes: 35 additions & 0 deletions packages/kbn-eslint-import-resolver-kibana/lib/get_plugins.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const { dirname, resolve } = require('path');
const glob = require('glob-all');

module.exports = function getPlugins(config, kibanaPath, projectRoot) {
const resolveToRoot = path => resolve(projectRoot, path);

const pluginDirs = [
...(config.pluginDirs || []).map(resolveToRoot),
resolve(kibanaPath, 'plugins'),
resolve(kibanaPath, 'src/core_plugins'),
];

const pluginPaths = [
...(config.pluginPaths || []).map(resolveToRoot),

// when the rootPackageName is specified we assume that the root of the project
// is not a plugin, so don't include it automatically
...(config.rootPackageName ? [] : [projectRoot]),
];

const globPatterns = [
...pluginDirs.map(dir => resolve(dir, '*/package.json')),
...pluginPaths.map(path => resolve(path, 'package.json')),
];

return glob.sync(globPatterns).map(pkgJsonPath => {
const path = dirname(pkgJsonPath);
const pkg = require(pkgJsonPath);
return {
name: pkg.name,
directory: path,
publicDirectory: resolve(path, 'public'),
};
});
};
52 changes: 52 additions & 0 deletions packages/kbn-eslint-import-resolver-kibana/lib/get_project_root.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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;
}
}

module.exports = function getProjectRoot(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;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const { resolve } = require('path');
const debug = require('./debug');

const getKibanaPath = require('./get_kibana_path');
const getPlugins = require('./get_plugins');

module.exports = function getWebpackConfig(source, projectRoot, config) {
const kibanaPath = getKibanaPath(config, projectRoot);
const fromKibana = (...path) => resolve(kibanaPath, ...path);

const alias = {
// Kibana defaults https://github.com/elastic/kibana/blob/6998f074542e8c7b32955db159d15661aca253d7/src/ui/ui_bundler_env.js#L30-L36
ui: fromKibana('src/ui/public'),
ui_framework: fromKibana('ui_framework'),
test_harness: fromKibana('src/test_harness/public'),
querystring: 'querystring-browser',
moment$: fromKibana('webpackShims/moment'),
'moment-timezone$': fromKibana('webpackShims/moment-timezone'),

// Dev defaults for test bundle https://github.com/elastic/kibana/blob/6998f074542e8c7b32955db159d15661aca253d7/src/core_plugins/tests_bundle/index.js#L73-L78
ng_mock$: fromKibana('src/core_plugins/dev_mode/public/ng_mock'),
'angular-mocks$': fromKibana(
'src/core_plugins/tests_bundle/webpackShims/angular-mocks.js'
),
fixtures: fromKibana('src/fixtures'),
test_utils: fromKibana('src/test_utils/public'),
};

getPlugins(config, kibanaPath, projectRoot).forEach(plugin => {
alias[`plugins/${plugin.name}`] = plugin.publicDirectory;
});

debug('Webpack resolved aliases', alias);

return {
context: kibanaPath,
resolve: {
extensions: ['.js', '.json'],
mainFields: ['browser', 'main'],
modules: [
'webpackShims',
'node_modules',
fromKibana('webpackShims'),
fromKibana('node_modules'),
],
alias,
unsafeCache: true,
},
};
};
19 changes: 19 additions & 0 deletions packages/kbn-eslint-import-resolver-kibana/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@kbn/eslint-import-resolver-kibana",
"description": "eslint-plugin-import resolver for Kibana",
"private": true,
"version": "2.0.0",
"main": "index.js",
"license": "Apache-2.0",
"repository": {
"type": "git",
"url": "https://github.com/elastic/kibana/tree/master/packages/kbn-eslint-import-resolver-kibana"
},
"dependencies": {
"debug": "^2.6.6",
"eslint-import-resolver-node": "^0.3.0",
"eslint-import-resolver-webpack": "^0.8.1",
"glob-all": "^3.1.0",
"webpack": "3.6.0"
}
}
Loading

0 comments on commit 4f2a19b

Please sign in to comment.