123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358 |
- 'use strict';
- const os = require('os');
- const path = require('path');
- const arrify = require('arrify');
- const mergeWith = require('lodash.mergewith');
- const multimatch = require('multimatch');
- const pathExists = require('path-exists');
- const pkgConf = require('pkg-conf');
- const resolveFrom = require('resolve-from');
- const prettier = require('prettier');
- const semver = require('semver');
- const DEFAULT_IGNORE = [
- '**/node_modules/**',
- '**/bower_components/**',
- 'flow-typed/**',
- 'coverage/**',
- '{tmp,temp}/**',
- '**/*.min.js',
- '**/bundle.js',
- 'fixture{-*,}.{js,jsx}',
- 'fixture{s,}/**',
- '{test,tests,spec,__tests__}/fixture{s,}/**',
- 'vendor/**',
- 'dist/**'
- ];
- const DEFAULT_EXTENSION = [
- 'js',
- 'jsx'
- ];
- const DEFAULT_CONFIG = {
- useEslintrc: false,
- cache: true,
- cacheLocation: path.join(os.homedir() || os.tmpdir(), '.xo-cache/'),
- baseConfig: {
- extends: [
- 'xo',
- path.join(__dirname, '../config/overrides.js'),
- path.join(__dirname, '../config/plugins.js')
- ]
- }
- };
- const ENGINE_RULES = {
- 'promise/prefer-await-to-then': {
- '7.6.0': 'error'
- }
- };
- const mergeFn = (prev, val) => {
- if (Array.isArray(prev) && Array.isArray(val)) {
- return val;
- }
- };
- const normalizeOpts = opts => {
- opts = Object.assign({}, opts);
-
- const aliases = [
- 'env',
- 'global',
- 'ignore',
- 'plugin',
- 'rule',
- 'setting',
- 'extend',
- 'extension'
- ];
- for (const singular of aliases) {
- const plural = singular + 's';
- let value = opts[plural] || opts[singular];
- delete opts[singular];
- if (value === undefined) {
- continue;
- }
- if (singular !== 'rule' && singular !== 'setting') {
- value = arrify(value);
- }
- opts[plural] = value;
- }
- return opts;
- };
- const mergeWithPkgConf = opts => {
- opts = Object.assign({cwd: process.cwd()}, opts);
- opts.cwd = path.resolve(opts.cwd);
- const conf = pkgConf.sync('xo', {cwd: opts.cwd, skipOnFalse: true});
- const engines = pkgConf.sync('engines', {cwd: opts.cwd});
- return Object.assign({}, conf, {engines}, opts);
- };
- const normalizeSpaces = opts => typeof opts.space === 'number' ? opts.space : 2;
- const mergeWithPrettierConf = (opts, prettierOpts) => {
- if ((opts.semicolon === true && prettierOpts.semi === false) ||
- (opts.semicolon === false && prettierOpts.semi === true)) {
- throw new Error(`The Prettier config \`semi\` is ${prettierOpts.semi} while XO \`semicolon\` is ${opts.semicolon}`);
- }
- if (((opts.space === true || typeof opts.space === 'number') && prettierOpts.useTabs === true) ||
- ((opts.space === false) && prettierOpts.useTabs === false)) {
- throw new Error(`The Prettier config \`useTabs\` is ${prettierOpts.useTabs} while XO \`space\` is ${opts.space}`);
- }
- if (typeof opts.space === 'number' && typeof prettierOpts.tabWidth === 'number' && opts.space !== prettierOpts.tabWidth) {
- throw new Error(`The Prettier config \`tabWidth\` is ${prettierOpts.tabWidth} while XO \`space\` is ${opts.space}`);
- }
- return mergeWith(
- {},
- {
- singleQuote: true,
- bracketSpacing: false,
- jsxBracketSameLine: false,
- trailingComma: 'none',
- tabWidth: normalizeSpaces(opts),
- useTabs: !opts.space,
- semi: opts.semicolon !== false
- },
- prettierOpts,
- mergeFn
- );
- };
- const emptyOptions = () => ({
- rules: {},
- settings: {},
- globals: [],
- envs: [],
- plugins: [],
- extends: []
- });
- const buildConfig = opts => {
- const config = mergeWith(
- emptyOptions(),
- DEFAULT_CONFIG,
- opts,
- mergeFn
- );
- const spaces = normalizeSpaces(opts);
- if (opts.engines && opts.engines.node && semver.validRange(opts.engines.node)) {
- for (const rule of Object.keys(ENGINE_RULES)) {
-
- for (const minVersion of Object.keys(ENGINE_RULES[rule]).sort(semver.compare)) {
- if (!semver.intersects(opts.engines.node, `<${minVersion}`)) {
- config.rules[rule] = ENGINE_RULES[rule][minVersion];
- }
- }
- }
- }
- if (opts.space && !opts.prettier) {
- config.rules.indent = ['error', spaces, {SwitchCase: 1}];
-
- if (opts.cwd && resolveFrom.silent(opts.cwd, 'eslint-plugin-react')) {
- config.plugins = config.plugins.concat('react');
- config.rules['react/jsx-indent-props'] = ['error', spaces];
- config.rules['react/jsx-indent'] = ['error', spaces];
- }
- }
- if (opts.semicolon === false && !opts.prettier) {
- config.rules.semi = ['error', 'never'];
- config.rules['semi-spacing'] = ['error', {
- before: false,
- after: true
- }];
- }
- if (opts.esnext !== false) {
- config.baseConfig.extends = [
- 'xo/esnext',
- path.join(__dirname, '../config/plugins.js')
- ];
- }
- if (opts.rules) {
- Object.assign(config.rules, opts.rules);
- }
- if (opts.settings) {
- config.baseConfig.settings = opts.settings;
- }
- if (opts.parser) {
- config.baseConfig.parser = opts.parser;
- }
- if (opts.extends && opts.extends.length > 0) {
-
-
- const configs = opts.extends.map(name => {
-
- if (pathExists.sync(name)) {
- return name;
- }
-
- if (name.startsWith('plugin:')) {
- return name;
- }
- if (!name.includes('eslint-config-')) {
- name = `eslint-config-${name}`;
- }
- const ret = resolveFrom(opts.cwd, name);
- if (!ret) {
- throw new Error(`Couldn't find ESLint config: ${name}`);
- }
- return ret;
- });
- config.baseConfig.extends = config.baseConfig.extends.concat(configs);
- }
-
- if (opts.prettier) {
-
- config.rules['unicorn/number-literal-case'] = 'off';
-
- config.plugins = config.plugins.concat('prettier');
-
- config.baseConfig.extends = config.baseConfig.extends.concat('prettier');
-
- config.rules['prettier/prettier'] = [
- 'error', mergeWithPrettierConf(opts, prettier.resolveConfig.sync(opts.cwd || process.cwd()) || {})
- ];
-
-
- for (const override of ['react', 'flowtype', 'standard']) {
- if (opts.cwd && resolveFrom.silent(opts.cwd, `eslint-plugin-${override}`)) {
- config.baseConfig.extends = config.baseConfig.extends.concat(`prettier/${override}`);
- }
- }
- }
- return config;
- };
- const findApplicableOverrides = (path, overrides) => {
- let hash = 0;
- const applicable = [];
- for (const override of overrides) {
- hash <<= 1;
- if (multimatch(path, override.files).length > 0) {
- applicable.push(override);
- hash |= 1;
- }
- }
- return {
- hash,
- applicable
- };
- };
- const mergeApplicableOverrides = (baseOptions, applicableOverrides) => {
- applicableOverrides = applicableOverrides.map(override => normalizeOpts(override));
- const overrides = [emptyOptions(), baseOptions].concat(applicableOverrides, mergeFn);
- return mergeWith(...overrides);
- };
- const groupConfigs = (paths, baseOptions, overrides) => {
- const map = {};
- const arr = [];
- for (const x of paths) {
- const data = findApplicableOverrides(x, overrides);
- if (!map[data.hash]) {
- const mergedOpts = mergeApplicableOverrides(baseOptions, data.applicable);
- delete mergedOpts.files;
- arr.push(map[data.hash] = {
- opts: mergedOpts,
- paths: []
- });
- }
- map[data.hash].paths.push(x);
- }
- return arr;
- };
- const getIgnores = opts => {
- opts.ignores = DEFAULT_IGNORE.concat(opts.ignores || []);
- return opts;
- };
- const preprocess = opts => {
- opts = mergeWithPkgConf(opts);
- opts = normalizeOpts(opts);
- opts = getIgnores(opts);
- opts.extensions = DEFAULT_EXTENSION.concat(opts.extensions || []);
- return opts;
- };
- module.exports.DEFAULT_IGNORE = DEFAULT_IGNORE;
- module.exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
- module.exports.mergeWithPkgConf = mergeWithPkgConf;
- module.exports.mergeWithPrettierConf = mergeWithPrettierConf;
- module.exports.normalizeOpts = normalizeOpts;
- module.exports.buildConfig = buildConfig;
- module.exports.findApplicableOverrides = findApplicableOverrides;
- module.exports.mergeApplicableOverrides = mergeApplicableOverrides;
- module.exports.groupConfigs = groupConfigs;
- module.exports.preprocess = preprocess;
- module.exports.emptyOptions = emptyOptions;
- module.exports.getIgnores = getIgnores;
|