123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447 |
- import path from 'path';
- import test from 'ava';
- import proxyquire from 'proxyquire';
- import parentConfig from './fixtures/nested/package';
- import childConfig from './fixtures/nested/child/package';
- import prettierConfig from './fixtures/prettier/package';
- import enginesConfig from './fixtures/engines/package';
- process.chdir(__dirname);
- const manager = proxyquire('../lib/options-manager', {
- 'resolve-from': (cwd, path) => `cwd/${path}`
- });
- test('normalizeOpts: makes all the opts plural and arrays', t => {
- const opts = manager.normalizeOpts({
- env: 'node',
- global: 'foo',
- ignore: 'test.js',
- plugin: 'my-plugin',
- rule: {'my-rule': 'foo'},
- setting: {'my-rule': 'bar'},
- extend: 'foo',
- extension: 'html'
- });
- t.deepEqual(opts, {
- envs: ['node'],
- globals: ['foo'],
- ignores: ['test.js'],
- plugins: ['my-plugin'],
- rules: {'my-rule': 'foo'},
- settings: {'my-rule': 'bar'},
- extends: ['foo'],
- extensions: ['html']
- });
- });
- test('normalizeOpts: falsie values stay falsie', t => {
- t.deepEqual(manager.normalizeOpts({}), {});
- });
- test('buildConfig: defaults', t => {
- const config = manager.buildConfig({});
- t.true(/[\\/]\.xo-cache[\\/]?$/.test(config.cacheLocation));
- t.is(config.useEslintrc, false);
- t.is(config.cache, true);
- t.is(config.baseConfig.extends[0], 'xo/esnext');
- });
- test('buildConfig: esnext', t => {
- const config = manager.buildConfig({esnext: false});
- t.is(config.baseConfig.extends[0], 'xo');
- });
- test('buildConfig: space: true', t => {
- const config = manager.buildConfig({space: true});
- t.deepEqual(config.rules.indent, ['error', 2, {SwitchCase: 1}]);
- });
- test('buildConfig: space: 4', t => {
- const config = manager.buildConfig({space: 4});
- t.deepEqual(config.rules.indent, ['error', 4, {SwitchCase: 1}]);
- });
- test('buildConfig: semicolon', t => {
- const config = manager.buildConfig({semicolon: false});
- t.deepEqual(config.rules, {
- semi: ['error', 'never'],
- 'semi-spacing': ['error', {
- before: false,
- after: true
- }]
- });
- });
- test('buildConfig: prettier: true', t => {
- const config = manager.buildConfig({prettier: true, extends: ['xo-react']});
- t.deepEqual(config.plugins, ['prettier']);
- // Sets the `semi`, `useTabs` and `tabWidth` options in `prettier/prettier` based on the XO `space` and `semicolon` options
- // Sets `singleQuote`, `trailingComma`, `bracketSpacing` and `jsxBracketSameLine` with XO defaults
- t.deepEqual(config.rules['prettier/prettier'], ['error', {
- useTabs: true,
- bracketSpacing: false,
- jsxBracketSameLine: false,
- semi: true,
- singleQuote: true,
- tabWidth: 2,
- trailingComma: 'none'
- }]);
- // eslint-prettier-config must always be last
- t.deepEqual(config.baseConfig.extends.slice(-1), ['prettier']);
- // Indent rule is not enabled
- t.is(config.rules.indent, undefined);
- // Semi rule is not enabled
- t.is(config.rules.semi, undefined);
- // Semi-spacing is not enabled
- t.is(config.rules['semi-spacing'], undefined);
- });
- test('buildConfig: prettier: true, semicolon: false', t => {
- const config = manager.buildConfig({prettier: true, semicolon: false});
- // Sets the `semi` options in `prettier/prettier` based on the XO `semicolon` option
- t.deepEqual(config.rules['prettier/prettier'], ['error', {
- useTabs: true,
- bracketSpacing: false,
- jsxBracketSameLine: false,
- semi: false,
- singleQuote: true,
- tabWidth: 2,
- trailingComma: 'none'
- }]);
- // Indent rule is not enabled
- t.is(config.rules.indent, undefined);
- // Semi rule is not enabled
- t.is(config.rules.semi, undefined);
- // Semi-spacing is not enabled
- t.is(config.rules['semi-spacing'], undefined);
- });
- test('buildConfig: prettier: true, space: 4', t => {
- const config = manager.buildConfig({prettier: true, space: 4});
- // Sets `useTabs` and `tabWidth` options in `prettier/prettier` rule based on the XO `space` options
- t.deepEqual(config.rules['prettier/prettier'], ['error', {
- useTabs: false,
- bracketSpacing: false,
- jsxBracketSameLine: false,
- semi: true,
- singleQuote: true,
- tabWidth: 4,
- trailingComma: 'none'
- }]);
- // Indent rule is not enabled
- t.is(config.rules.indent, undefined);
- // Semi rule is not enabled
- t.is(config.rules.semi, undefined);
- // Semi-spacing is not enabled
- t.is(config.rules['semi-spacing'], undefined);
- });
- test('buildConfig: prettier: true, esnext: false', t => {
- const config = manager.buildConfig({prettier: true, esnext: false});
- // Sets `useTabs` and `tabWidth` options in `prettier/prettier` rule based on the XO `space` options
- t.deepEqual(config.rules['prettier/prettier'], ['error', {
- useTabs: true,
- bracketSpacing: false,
- jsxBracketSameLine: false,
- semi: true,
- singleQuote: true,
- tabWidth: 2,
- trailingComma: 'none'
- }]);
- // Indent rule is not enabled
- t.is(config.rules.indent, undefined);
- // Semi rule is not enabled
- t.is(config.rules.semi, undefined);
- // Semi-spacing is not enabled
- t.is(config.rules['semi-spacing'], undefined);
- });
- test('buildConfig: prettier: true, space: true', t => {
- const config = manager.buildConfig({prettier: true, space: true});
- // Sets `useTabs` and `tabWidth` options in `prettier/prettier` rule based on the XO `space` options
- t.deepEqual(config.rules['prettier/prettier'], ['error', {
- useTabs: false,
- bracketSpacing: false,
- jsxBracketSameLine: false,
- semi: true,
- singleQuote: true,
- tabWidth: 2,
- trailingComma: 'none'
- }]);
- // Indent rule is not enabled
- t.is(config.rules.indent, undefined);
- // Semi rule is not enabled
- t.is(config.rules.semi, undefined);
- // Semi-spacing is not enabled
- t.is(config.rules['semi-spacing'], undefined);
- });
- test('buildConfig: merge with prettier config', t => {
- const cwd = path.resolve('fixtures', 'prettier');
- const config = manager.buildConfig({cwd, prettier: true});
- // Sets the `semi` options in `prettier/prettier` based on the XO `semicolon` option
- t.deepEqual(config.rules['prettier/prettier'], ['error', prettierConfig.prettier]);
- // Indent rule is not enabled
- t.is(config.rules.indent, undefined);
- // Semi rule is not enabled
- t.is(config.rules.semi, undefined);
- // Semi-spacing is not enabled
- t.is(config.rules['semi-spacing'], undefined);
- });
- test('buildConfig: engines: undefined', t => {
- const config = manager.buildConfig({});
- // Do not include any Node.js version specific rules
- t.is(config.rules['prefer-spread'], undefined);
- t.is(config.rules['prefer-rest-params'], undefined);
- t.is(config.rules['prefer-destructuring'], undefined);
- t.is(config.rules['promise/prefer-await-to-then'], undefined);
- });
- test('buildConfig: engines: false', t => {
- const config = manager.buildConfig({engines: false});
- // Do not include any Node.js version specific rules
- t.is(config.rules['prefer-spread'], undefined);
- t.is(config.rules['prefer-rest-params'], undefined);
- t.is(config.rules['prefer-destructuring'], undefined);
- t.is(config.rules['promise/prefer-await-to-then'], undefined);
- });
- test('buildConfig: engines: invalid range', t => {
- const config = manager.buildConfig({engines: {node: '4'}});
- // Do not include any Node.js version specific rules
- t.is(config.rules['prefer-spread'], undefined);
- t.is(config.rules['prefer-rest-params'], undefined);
- t.is(config.rules['prefer-destructuring'], undefined);
- t.is(config.rules['promise/prefer-await-to-then'], undefined);
- });
- test('buildConfig: engines: >=8', t => {
- const config = manager.buildConfig({engines: {node: '>=8'}});
- // Include rules for Node.js 8 and above
- t.is(config.rules['promise/prefer-await-to-then'], 'error');
- });
- test('mergeWithPrettierConf: use `singleQuote`, `trailingComma`, `bracketSpacing` and `jsxBracketSameLine` from `prettier` config if defined', t => {
- const prettierOpts = {singleQuote: false, trailingComma: 'all', bracketSpacing: false, jsxBracketSameLine: false};
- const result = manager.mergeWithPrettierConf({}, prettierOpts);
- const expected = Object.assign({}, prettierOpts, {tabWidth: 2, useTabs: true, semi: true});
- t.deepEqual(result, expected);
- });
- test('mergeWithPrettierConf: determine `tabWidth`, `useTabs`, `semi` from xo config', t => {
- const prettierOpts = {tabWidth: 4, useTabs: false, semi: false};
- const result = manager.mergeWithPrettierConf({space: 4, semicolon: false}, {});
- const expected = Object.assign(
- {bracketSpacing: false, jsxBracketSameLine: false, singleQuote: true, trailingComma: 'none'},
- prettierOpts
- );
- t.deepEqual(result, expected);
- });
- test('mergeWithPrettierConf: determine `tabWidth`, `useTabs`, `semi` from prettier config', t => {
- const prettierOpts = {useTabs: false, semi: false, tabWidth: 4};
- const result = manager.mergeWithPrettierConf({}, prettierOpts);
- const expected = Object.assign(
- {bracketSpacing: false, jsxBracketSameLine: false, singleQuote: true, trailingComma: 'none'},
- prettierOpts
- );
- t.deepEqual(result, expected);
- });
- test('mergeWithPrettierConf: throw error is `semi`/`semicolon` conflicts', t => {
- t.throws(() => manager.mergeWithPrettierConf(
- {semicolon: true},
- {semi: false}
- ));
- t.throws(() => manager.mergeWithPrettierConf(
- {semicolon: false},
- {semi: true}
- ));
- t.notThrows(() => manager.mergeWithPrettierConf(
- {semicolon: true},
- {semi: true}
- ));
- t.notThrows(() => manager.mergeWithPrettierConf({semicolon: false}, {semi: false}));
- });
- test('mergeWithPrettierConf: throw error is `space`/`useTabs` conflicts', t => {
- t.throws(() => manager.mergeWithPrettierConf({space: false}, {useTabs: false}));
- t.throws(() => manager.mergeWithPrettierConf({space: true}, {useTabs: true}));
- t.notThrows(() => manager.mergeWithPrettierConf({space: 4}, {useTabs: false}));
- t.notThrows(() => manager.mergeWithPrettierConf({space: true}, {useTabs: false}));
- t.notThrows(() => manager.mergeWithPrettierConf({space: false}, {useTabs: true}));
- });
- test('mergeWithPrettierConf: throw error is `space`/`tabWidth` conflicts', t => {
- t.throws(() => manager.mergeWithPrettierConf({space: 4}, {tabWidth: 2}));
- t.throws(() => manager.mergeWithPrettierConf({space: 0}, {tabWidth: 2}));
- t.throws(() => manager.mergeWithPrettierConf({space: 2}, {tabWidth: 0}));
- t.notThrows(() => manager.mergeWithPrettierConf({space: 4}, {tabWidth: 4}));
- t.notThrows(() => manager.mergeWithPrettierConf({space: false}, {tabWidth: 4}));
- t.notThrows(() => manager.mergeWithPrettierConf({space: true}, {tabWidth: 4}));
- });
- test('buildConfig: rules', t => {
- const rules = {'object-curly-spacing': ['error', 'always']};
- const config = manager.buildConfig({rules});
- t.deepEqual(config.rules, rules);
- });
- test('buildConfig: parser', t => {
- const parser = 'babel-eslint';
- const config = manager.buildConfig({parser});
- t.deepEqual(config.baseConfig.parser, parser);
- });
- test('buildConfig: settings', t => {
- const settings = {'import/resolver': 'webpack'};
- const config = manager.buildConfig({settings});
- t.deepEqual(config.baseConfig.settings, settings);
- });
- test('buildConfig: extends', t => {
- const config = manager.buildConfig({extends: [
- 'plugin:foo/bar',
- 'eslint-config-foo-bar',
- 'foo-bar-two'
- ]});
- t.deepEqual(config.baseConfig.extends.slice(-3), [
- 'plugin:foo/bar',
- 'cwd/eslint-config-foo-bar',
- 'cwd/eslint-config-foo-bar-two'
- ]);
- });
- test('findApplicableOverrides', t => {
- const result = manager.findApplicableOverrides('/user/dir/foo.js', [
- {files: '**/f*.js'},
- {files: '**/bar.js'},
- {files: '**/*oo.js'},
- {files: '**/*.txt'}
- ]);
- t.is(result.hash, 0b1010);
- t.deepEqual(result.applicable, [
- {files: '**/f*.js'},
- {files: '**/*oo.js'}
- ]);
- });
- test('groupConfigs', t => {
- const paths = [
- '/user/foo/hello.js',
- '/user/foo/goodbye.js',
- '/user/foo/howdy.js',
- '/user/bar/hello.js'
- ];
- const opts = {
- esnext: false
- };
- const overrides = [
- {
- files: '**/foo/*',
- esnext: true
- },
- {
- files: '**/foo/howdy.js',
- space: 3,
- env: 'mocha'
- }
- ];
- const result = manager.groupConfigs(paths, opts, overrides);
- t.deepEqual(result, [
- {
- opts: {
- esnext: true
- },
- paths: ['/user/foo/hello.js', '/user/foo/goodbye.js']
- },
- {
- opts: {
- esnext: true,
- space: 3,
- envs: ['mocha']
- },
- paths: ['/user/foo/howdy.js']
- },
- {
- opts: {
- esnext: false
- },
- paths: ['/user/bar/hello.js']
- }
- ].map(obj => {
- obj.opts = Object.assign(manager.emptyOptions(), obj.opts);
- return obj;
- }));
- });
- test('mergeWithPkgConf: use child if closest', t => {
- const cwd = path.resolve('fixtures', 'nested', 'child');
- const result = manager.mergeWithPkgConf({cwd});
- const expected = Object.assign({}, childConfig.xo, {cwd}, {engines: {}});
- t.deepEqual(result, expected);
- });
- test('mergeWithPkgConf: use parent if closest', t => {
- const cwd = path.resolve('fixtures', 'nested');
- const result = manager.mergeWithPkgConf({cwd});
- const expected = Object.assign({}, parentConfig.xo, {cwd}, {engines: {}});
- t.deepEqual(result, expected);
- });
- test('mergeWithPkgConf: use parent if child is ignored', t => {
- const cwd = path.resolve('fixtures', 'nested', 'child-ignore');
- const result = manager.mergeWithPkgConf({cwd});
- const expected = Object.assign({}, parentConfig.xo, {cwd}, {engines: {}});
- t.deepEqual(result, expected);
- });
- test('mergeWithPkgConf: use child if child is empty', t => {
- const cwd = path.resolve('fixtures', 'nested', 'child-empty');
- const result = manager.mergeWithPkgConf({cwd});
- t.deepEqual(result, {cwd, engines: {}});
- });
- test('mergeWithPkgConf: read engines from package.json', t => {
- const cwd = path.resolve('fixtures', 'engines');
- const result = manager.mergeWithPkgConf({cwd});
- const expected = Object.assign({}, {engines: enginesConfig.engines}, {cwd});
- t.deepEqual(result, expected);
- });
- test('mergeWithPkgConf: XO engine options supersede package.json\'s', t => {
- const cwd = path.resolve('fixtures', 'engines');
- const result = manager.mergeWithPkgConf({cwd, engines: {node: '>=8'}});
- const expected = Object.assign({}, {engines: {node: '>=8'}}, {cwd});
- t.deepEqual(result, expected);
- });
- test('mergeWithPkgConf: XO engine options false supersede package.json\'s', t => {
- const cwd = path.resolve('fixtures', 'engines');
- const result = manager.mergeWithPkgConf({cwd, engines: false});
- const expected = Object.assign({}, {engines: false}, {cwd});
- t.deepEqual(result, expected);
- });
|