diff --git a/README.md b/README.md index 658c4a60..39963185 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,7 @@ eslint --init ``` Alternatively you can create the `.eslintrc` file by yourself. It is a good -idea to have a look at the [Get Started With ESLint](http://devnull.guru/get-started-with-eslint/) -blog post by [IanVS](https://github.com/IanVS) and [the ESLint documentation](http://eslint.org/docs/user-guide/configuring), +idea to have a look at the [ESLint documentation](http://eslint.org/docs/user-guide/configuring), including the [list of rules](http://eslint.org/docs/rules/). ## A Note About Settings diff --git a/docs/images/fork.png b/docs/images/fork.png deleted file mode 100644 index 9aeffc86..00000000 Binary files a/docs/images/fork.png and /dev/null differ diff --git a/docs/images/pr-button.png b/docs/images/pr-button.png deleted file mode 100644 index 9dfc9466..00000000 Binary files a/docs/images/pr-button.png and /dev/null differ diff --git a/docs/images/pr.png b/docs/images/pr.png deleted file mode 100644 index a398facd..00000000 Binary files a/docs/images/pr.png and /dev/null differ diff --git a/docs/images/rule-link.png b/docs/images/rule-link.png deleted file mode 100644 index 58b58406..00000000 Binary files a/docs/images/rule-link.png and /dev/null differ diff --git a/package.json b/package.json index d1bbe902..9020a540 100644 --- a/package.json +++ b/package.json @@ -9,72 +9,6 @@ "atom": ">=1.13.0 <2.0.0" }, "configSchema": { - "lintHtmlFiles": { - "title": "Lint HTML Files", - "description": "You should also add `eslint-plugin-html` to your .eslintrc plugins", - "type": "boolean", - "default": false - }, - "useGlobalEslint": { - "title": "Use global ESLint installation", - "description": "Make sure you have it in your $PATH", - "type": "boolean", - "default": false - }, - "showRuleIdInMessage": { - "title": "Show Rule ID in Messages", - "type": "boolean", - "default": true - }, - "disableWhenNoEslintConfig": { - "title": "Disable when no ESLint config is found (in package.json or .eslintrc)", - "type": "boolean", - "default": true - }, - "eslintrcPath": { - "title": ".eslintrc Path", - "description": "It will only be used when there's no config file in project", - "type": "string", - "default": "" - }, - "globalNodePath": { - "title": "Global Node Installation Path", - "description": "Write the value of `npm get prefix` here", - "type": "string", - "default": "" - }, - "advancedLocalNodeModules": { - "title": "Path to the local node_modules folder", - "description": "Optionally specify the path to the local node_modules folder", - "type": "string", - "default": "" - }, - "eslintRulesDirs": { - "title": "ESLint Rules Directories", - "description": "Specify a comma separated list of directories for ESLint to load rules from.", - "type": "array", - "default": [], - "items": { - "type": "string" - } - }, - "disableEslintIgnore": { - "title": "Don't use .eslintignore files", - "type": "boolean", - "default": false - }, - "disableFSCache": { - "title": "Disable FileSystem Cache", - "description": "Paths of node_modules, .eslintignore and others are cached", - "type": "boolean", - "default": false - }, - "fixOnSave": { - "title": "Fix errors on save", - "description": "Have eslint attempt to fix some errors automatically when saving the file.", - "type": "boolean", - "default": false - }, "scopes": { "title": "List of scopes to run ESLint on, run `Editor: Log Cursor Scope` to determine the scopes for a file.", "type": "array", @@ -87,31 +21,140 @@ ], "items": { "type": "string" + }, + "order": 1 + }, + "lintHtmlFiles": { + "title": "Lint HTML Files", + "description": "You should also add `eslint-plugin-html` to your .eslintrc plugins", + "type": "boolean", + "default": false, + "order": 2 + }, + "autofix": { + "type": "object", + "order": 3, + "title": "Automatic Fixes", + "properties": { + "fixOnSave": { + "title": "Fix errors on save", + "description": "Have eslint attempt to fix some errors automatically when saving the file.", + "type": "boolean", + "default": false, + "order": 1 + }, + "ignoreFixableRulesWhileTyping": { + "title": "Ignore fixable rules while typing", + "description": "Have the linter ignore all fixable rules during linting when editing a document. The list is automatically updated on each lint job, and requires at least one run to be populated. Only supported when using ESLint v4+.", + "type": "boolean", + "default": false, + "order": 2 + }, + "rulesToDisableWhileFixing": { + "title": "Disable specific rules from fixes", + "description": "Prevent rules from being auto-fixed by ESLint. Applies to fixes made during saves as well as when running the `Linter Eslint: Fix File` command.", + "type": "array", + "default": [], + "items": { + "type": "string" + }, + "order": 3 + } } }, - "rulesToSilenceWhileTyping": { - "title": "Silence specific rules while typing", - "description": "Useful when Atom fixes errors on save like `no-trailing-spaces` or `eol-last`.", - "type": "array", - "default": [], - "items": { - "type": "string" + "global": { + "type": "object", + "order": 4, + "title": "Global ESLint", + "properties": { + "useGlobalEslint": { + "title": "Use global ESLint installation", + "description": "Make sure you have it in your $PATH", + "type": "boolean", + "default": false, + "order": 1 + }, + "eslintrcPath": { + "title": ".eslintrc Path", + "description": "It will only be used when there's no config file in project", + "type": "string", + "default": "", + "order": 4 + }, + "globalNodePath": { + "title": "Global Node Installation Path", + "description": "Write the value of `npm get prefix` here", + "type": "string", + "default": "", + "order": 2 + } } }, - "rulesToDisableWhileFixing": { - "title": "Disable specific rules from fixes", - "description": "Prevent rules from being auto-fixed by ESLint. Applies to fixes made during saves as well as when running the `Linter Eslint: Fix File` command.", - "type": "array", - "default": [], - "items": { - "type": "string" + "disabling": { + "type": "object", + "order": 5, + "properties": { + "disableWhenNoEslintConfig": { + "title": "Disable when no ESLint config is found (in package.json or .eslintrc)", + "type": "boolean", + "default": true, + "order": 1 + }, + "rulesToSilenceWhileTyping": { + "title": "Silence specific rules while typing", + "description": "Useful when Atom fixes errors on save like `no-trailing-spaces` or `eol-last`.", + "type": "array", + "default": [], + "items": { + "type": "string" + }, + "order": 2 + } } }, - "ignoreFixableRulesWhileTyping": { - "title": "Ignore fixable rules while typing", - "description": "Have the linter ignore all fixable rules during linting when editing a document. The list is automatically updated on each lint job, and requires at least one run to be populated. Only supported when using ESLint v4+.", - "type": "boolean", - "default": false + "advanced": { + "type": "object", + "collapsed": true, + "title": "Uncommon", + "order": 6, + "properties": { + "disableEslintIgnore": { + "title": "Don't use .eslintignore files", + "type": "boolean", + "default": false, + "order": 1 + }, + "disableFSCache": { + "title": "Disable FileSystem Cache", + "description": "Paths of node_modules, .eslintignore and others are normally cached", + "type": "boolean", + "default": false, + "order": 2 + }, + "showRuleIdInMessage": { + "title": "Show Rule ID in Messages", + "type": "boolean", + "default": true, + "order": 3 + }, + "eslintRulesDirs": { + "title": "ESLint Rules Directories", + "description": "Specify a comma separated list of directories for ESLint to load rules from.", + "type": "array", + "default": [], + "items": { + "type": "string" + }, + "order": 4 + }, + "localNodeModules": { + "title": "Path to the local node_modules folder", + "description": "Optionally specify the path to the local node_modules folder", + "type": "string", + "default": "", + "order": 5 + } + } } }, "scripts": { diff --git a/spec/linter-eslint-spec.js b/spec/linter-eslint-spec.js index 9a1ecf5d..cecd3ae2 100644 --- a/spec/linter-eslint-spec.js +++ b/spec/linter-eslint-spec.js @@ -113,8 +113,8 @@ describe('The eslint provider for Linter', () => { const { lint } = linterProvider beforeEach(async () => { - atom.config.set('linter-eslint.disableFSCache', false) - atom.config.set('linter-eslint.disableEslintIgnore', true) + atom.config.set('linter-eslint.advanced.disableFSCache', false) + atom.config.set('linter-eslint.advanced.disableEslintIgnore', true) // Activate the JavaScript language so Atom knows what the files are await atom.packages.activatePackage('language-javascript') @@ -206,7 +206,7 @@ describe('The eslint provider for Linter', () => { describe('when a file is specified in an .eslintignore file', () => { beforeEach(() => { - atom.config.set('linter-eslint.disableEslintIgnore', false) + atom.config.set('linter-eslint.advanced.disableEslintIgnore', false) }) it('will not give warnings when linting the file', async () => { @@ -233,7 +233,7 @@ describe('The eslint provider for Linter', () => { const tempDir = path.dirname(tempPath) const editor = await atom.workspace.open(tempPath) - atom.config.set('linter-eslint.disableEslintIgnore', false) + atom.config.set('linter-eslint.advanced.disableEslintIgnore', false) await copyFileToDir(path.join(paths.eslintignoreDir, '.eslintrc.yaml'), tempDir) const messages = await lint(editor) @@ -244,7 +244,7 @@ describe('The eslint provider for Linter', () => { describe('when a file is specified in an eslintIgnore key in package.json', () => { it('will still lint the file if an .eslintignore file is present', async () => { - atom.config.set('linter-eslint.disableEslintIgnore', false) + atom.config.set('linter-eslint.advanced.disableEslintIgnore', false) const editor = await atom.workspace.open(path.join(paths.eslintIgnoreKeyDir, 'ignored.js')) const messages = await lint(editor) @@ -256,7 +256,7 @@ describe('The eslint provider for Linter', () => { const tempDir = path.dirname(tempPath) const editor = await atom.workspace.open(tempPath) - atom.config.set('linter-eslint.disableEslintIgnore', false) + atom.config.set('linter-eslint.advanced.disableEslintIgnore', false) await copyFileToDir(path.join(paths.eslintIgnoreKeyDir, 'package.json'), tempDir) const messages = await lint(editor) @@ -298,7 +298,7 @@ describe('The eslint provider for Linter', () => { }) it('should not fix linting errors for rules that are disabled with rulesToDisableWhileFixing', async () => { - atom.config.set('linter-eslint.rulesToDisableWhileFixing', ['semi']) + atom.config.set('linter-eslint.autofix.rulesToDisableWhileFixing', ['semi']) await firstLint(editor) await makeFixes(editor) @@ -382,8 +382,8 @@ describe('The eslint provider for Linter', () => { } it('does nothing on saved files', async () => { - atom.config.set('linter-eslint.rulesToSilenceWhileTyping', ['no-trailing-spaces']) - atom.config.set('linter-eslint.ignoreFixableRulesWhileTyping', true) + atom.config.set('linter-eslint.disabling.rulesToSilenceWhileTyping', ['no-trailing-spaces']) + atom.config.set('linter-eslint.autofix.ignoreFixableRulesWhileTyping', true) expectedPath = paths.modifiedIgnoreSpace const editor = await atom.workspace.open(expectedPath) // Run once to populate the fixable rules list @@ -409,7 +409,7 @@ describe('The eslint provider for Linter', () => { checkNew(messages) // Enable the option under test - atom.config.set('linter-eslint.rulesToSilenceWhileTyping', ['no-trailing-spaces']) + atom.config.set('linter-eslint.disabling.rulesToSilenceWhileTyping', ['no-trailing-spaces']) // Check the lint results const newMessages = await lint(editor) @@ -433,7 +433,7 @@ describe('The eslint provider for Linter', () => { // Enable the option under test // NOTE: Depends on no-trailing-spaces being marked as fixable by ESLint - atom.config.set('linter-eslint.ignoreFixableRulesWhileTyping', true) + atom.config.set('linter-eslint.autofix.ignoreFixableRulesWhileTyping', true) // Check the lint results const newMessages = await lint(editor) @@ -459,7 +459,7 @@ describe('The eslint provider for Linter', () => { // Enable the option under test // NOTE: Depends on mport/newline-after-import rule being marked as fixable - atom.config.set('linter-eslint.ignoreFixableRulesWhileTyping', true) + atom.config.set('linter-eslint.autofix.ignoreFixableRulesWhileTyping', true) // Check the lint results const newMessages = await lint(editor) @@ -516,7 +516,7 @@ describe('The eslint provider for Linter', () => { let tempFixtureDir beforeEach(async () => { - atom.config.set('linter-eslint.disableWhenNoEslintConfig', false) + atom.config.set('linter-eslint.disabling.disableWhenNoEslintConfig', false) tempFilePath = await copyFileToTempDir(paths.badInline) editor = await atom.workspace.open(tempFilePath) @@ -549,7 +549,7 @@ describe('The eslint provider for Linter', () => { let tempFixtureDir beforeEach(async () => { - atom.config.set('linter-eslint.disableWhenNoEslintConfig', true) + atom.config.set('linter-eslint.disabling.disableWhenNoEslintConfig', true) const tempFilePath = await copyFileToTempDir(paths.badInline) editor = await atom.workspace.open(tempFilePath) @@ -571,7 +571,7 @@ describe('The eslint provider for Linter', () => { it('works when the cache fails', async () => { // Ensure the cache is enabled, since we will be taking advantage of // a failing in it's operation - atom.config.set('linter-eslint.disableFSCache', false) + atom.config.set('linter-eslint.advanced.disableFSCache', false) const fooPath = path.join(paths.badCache, 'temp', 'foo.js') const newConfigPath = path.join(paths.badCache, 'temp', '.eslintrc.js') const editor = await atom.workspace.open(fooPath) @@ -658,7 +658,7 @@ describe('The eslint provider for Linter', () => { const expectedUrl = 'https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-unresolved.md' it('shows the rule ID when enabled', async () => { - atom.config.set('linter-eslint.showRuleIdInMessage', true) + atom.config.set('linter-eslint.advanced.showRuleIdInMessage', true) const editor = await atom.workspace.open(paths.badImport) const messages = await lint(editor) const expected = "Unable to resolve path to module '../nonexistent'. (import/no-unresolved)" @@ -673,7 +673,7 @@ describe('The eslint provider for Linter', () => { }) it("doesn't show the rule ID when disabled", async () => { - atom.config.set('linter-eslint.showRuleIdInMessage', false) + atom.config.set('linter-eslint.advanced.showRuleIdInMessage', false) const editor = await atom.workspace.open(paths.badImport) const messages = await lint(editor) const expected = "Unable to resolve path to module '../nonexistent'." diff --git a/spec/make-spy.js b/spec/make-spy.js index d195cfc0..fd2fb41a 100644 --- a/spec/make-spy.js +++ b/spec/make-spy.js @@ -17,6 +17,6 @@ export default (returnValue) => { return { call, calledWith, - called: () => calledWith.length + called: () => Boolean(calledWith.length) } } diff --git a/spec/migrate-config-options-spec.js b/spec/migrate-config-options-spec.js new file mode 100644 index 00000000..12fed26f --- /dev/null +++ b/spec/migrate-config-options-spec.js @@ -0,0 +1,37 @@ +'use babel' + +import migrateConfigOptions from '../src/migrate-config-options' +import makeSpy from './make-spy' + +describe('migrateConfigOptions()', () => { + it('calls the migrate functions of objects in a proided migrations array', () => { + const migrateSpy = makeSpy() + const migrations = [{ migrate: migrateSpy.call }] + migrateConfigOptions(migrations) + expect(migrateSpy.called()).toEqual(true) + }) + + it('provides the linter-eslint config to migrate functions', () => { + atom.config.set('linter-eslint.oldSetting', true) + const migrateSpy = makeSpy() + const migrations = [{ migrate: migrateSpy.call }] + migrateConfigOptions(migrations) + expect(migrateSpy.calledWith[0][0]).toEqual(atom.config.get('linter-eslint')) + }) + + it('moves configs using `moves` array in a provided migrations array', () => { + atom.config.set('linter-eslint.oldSetting', true) + const migrations = [{ + moves: [{ + old: 'oldSetting', + new: 'newSetting', + }], + }] + migrateConfigOptions(migrations) + const oldSetting = atom.config.get('linter-eslint.oldSetting') + const newSetting = atom.config.get('linter-eslint.newSetting') + console.log({ oldSetting, newSetting }) + expect(oldSetting).toEqual(undefined) + expect(newSetting).toEqual(true) + }) +}) diff --git a/spec/worker-helpers-spec.js b/spec/worker-helpers-spec.js index fb40d493..84943d3a 100644 --- a/spec/worker-helpers-spec.js +++ b/spec/worker-helpers-spec.js @@ -12,11 +12,22 @@ const globalNodePath = process.platform === 'win32' ? Path.join(getFixturesPath('global-eslint'), 'lib') : getFixturesPath('global-eslint') +function createConfig(overrides = {}) { + return Object.assign( + {}, + overrides, + { global: Object.assign({}, overrides.global) }, + { autofix: Object.assign({}, overrides.autofix) }, + { disabling: Object.assign({}, overrides.disabling) }, + { advanced: Object.assign({}, overrides.advanced) }, + ) +} + describe('Worker Helpers', () => { describe('findESLintDirectory', () => { it('returns an object with path and type keys', () => { const modulesDir = Path.join(getFixturesPath('local-eslint'), 'node_modules') - const foundEslint = Helpers.findESLintDirectory(modulesDir, {}) + const foundEslint = Helpers.findESLintDirectory(modulesDir, createConfig()) expect(typeof foundEslint === 'object').toBe(true) expect(foundEslint.path).toBeDefined() expect(foundEslint.type).toBeDefined() @@ -24,7 +35,8 @@ describe('Worker Helpers', () => { it('finds a local eslint when useGlobalEslint is false', () => { const modulesDir = Path.join(getFixturesPath('local-eslint'), 'node_modules') - const foundEslint = Helpers.findESLintDirectory(modulesDir, { useGlobalEslint: false }) + const config = createConfig({ global: { useGlobalEslint: false } }) + const foundEslint = Helpers.findESLintDirectory(modulesDir, config) const expectedEslintPath = Path.join(getFixturesPath('local-eslint'), 'node_modules', 'eslint') expect(foundEslint.path).toEqual(expectedEslintPath) expect(foundEslint.type).toEqual('local project') @@ -32,7 +44,7 @@ describe('Worker Helpers', () => { it('does not find a local eslint when useGlobalEslint is true', () => { const modulesDir = Path.join(getFixturesPath('local-eslint'), 'node_modules') - const config = { useGlobalEslint: true, globalNodePath } + const config = createConfig({ global: { useGlobalEslint: true, globalNodePath } }) const foundEslint = Helpers.findESLintDirectory(modulesDir, config) const expectedEslintPath = Path.join(getFixturesPath('local-eslint'), 'node_modules', 'eslint') expect(foundEslint.path).not.toEqual(expectedEslintPath) @@ -41,7 +53,7 @@ describe('Worker Helpers', () => { it('finds a global eslint when useGlobalEslint is true and a valid globalNodePath is provided', () => { const modulesDir = Path.join(getFixturesPath('local-eslint'), 'node_modules') - const config = { useGlobalEslint: true, globalNodePath } + const config = createConfig({ global: { useGlobalEslint: true, globalNodePath } }) const foundEslint = Helpers.findESLintDirectory(modulesDir, config) const expectedEslintPath = process.platform === 'win32' ? Path.join(globalNodePath, 'node_modules', 'eslint') @@ -52,7 +64,7 @@ describe('Worker Helpers', () => { it('falls back to the packaged eslint when no local eslint is found', () => { const modulesDir = 'not/a/real/path' - const config = { useGlobalEslint: false } + const config = createConfig({ global: { useGlobalEslint: false } }) const foundEslint = Helpers.findESLintDirectory(modulesDir, config) const expectedBundledPath = Path.join(__dirname, '..', 'node_modules', 'eslint') expect(foundEslint.path).toEqual(expectedBundledPath) @@ -65,56 +77,61 @@ describe('Worker Helpers', () => { it('tries to find an indirect local eslint using an absolute path', () => { const path = Path.join(getFixturesPath('indirect-local-eslint'), pathPart) - const eslint = Helpers.getESLintInstance('', { - useGlobalEslint: false, - advancedLocalNodeModules: path + const config = createConfig({ + global: { useGlobalEslint: false }, + advanced: { localNodeModules: path } }) + const eslint = Helpers.getESLintInstance('', config) expect(eslint).toBe('located') }) it('tries to find an indirect local eslint using a relative path', () => { const path = Path.join(getFixturesPath('indirect-local-eslint'), pathPart) const [projectPath, relativePath] = atom.project.relativizePath(path) - - const eslint = Helpers.getESLintInstance('', { - useGlobalEslint: false, - advancedLocalNodeModules: relativePath - }, projectPath) + const config = createConfig({ + global: { useGlobalEslint: false }, + advanced: { localNodeModules: relativePath } + }) + const eslint = Helpers.getESLintInstance('', config, projectPath) expect(eslint).toBe('located') }) it('tries to find a local eslint', () => { - const eslint = Helpers.getESLintInstance(getFixturesPath('local-eslint'), {}) + const config = createConfig() + const eslint = Helpers.getESLintInstance(getFixturesPath('local-eslint'), config) expect(eslint).toBe('located') }) it('cries if local eslint is not found', () => { expect(() => { - Helpers.getESLintInstance(getFixturesPath('files', {})) + const config = createConfig() + Helpers.getESLintInstance(getFixturesPath('files', config)) }).toThrow() }) it('tries to find a global eslint if config is specified', () => { - const eslint = Helpers.getESLintInstance(getFixturesPath('local-eslint'), { - useGlobalEslint: true, - globalNodePath + const config = createConfig({ + global: { useGlobalEslint: true, globalNodePath } }) + console.log({ config }) + const eslint = Helpers.getESLintInstance(getFixturesPath('local-eslint'), config) expect(eslint).toBe('located') }) it('cries if global eslint is not found', () => { expect(() => { - Helpers.getESLintInstance(getFixturesPath('local-eslint'), { - useGlobalEslint: true, - globalNodePath: getFixturesPath('files') + const config = createConfig({ + global: { useGlobalEslint: true, globalNodePath: getFixturesPath('files') } }) + Helpers.getESLintInstance(getFixturesPath('local-eslint'), config) }).toThrow() }) it('tries to find a local eslint with nested node_modules', () => { const fileDir = Path.join(getFixturesPath('local-eslint'), 'lib', 'foo.js') - const eslint = Helpers.getESLintInstance(fileDir, {}) + const config = createConfig() + const eslint = Helpers.getESLintInstance(fileDir, config) expect(eslint).toBe('located') }) }) @@ -167,7 +184,8 @@ describe('Worker Helpers', () => { it('return path relative of ignore file if found', () => { const fixtureDir = getFixturesPath('eslintignore') const fixtureFile = Path.join(fixtureDir, 'ignored.js') - const relativePath = Helpers.getRelativePath(fixtureDir, fixtureFile, {}) + const config = createConfig() + const relativePath = Helpers.getRelativePath(fixtureDir, fixtureFile, config) const expectedPath = Path.relative(Path.join(__dirname, '..'), fixtureFile) expect(relativePath).toBe(expectedPath) }) @@ -175,8 +193,11 @@ describe('Worker Helpers', () => { it('does not return path relative to ignore file if config overrides it', () => { const fixtureDir = getFixturesPath('eslintignore') const fixtureFile = Path.join(fixtureDir, 'ignored.js') + const config = createConfig({ + advanced: { disableEslintIgnore: true } + }) const relativePath = - Helpers.getRelativePath(fixtureDir, fixtureFile, { disableEslintIgnore: true }) + Helpers.getRelativePath(fixtureDir, fixtureFile, config) expect(relativePath).toBe('ignored.js') }) @@ -187,8 +208,9 @@ describe('Worker Helpers', () => { const tempDir = Path.dirname(tempFixturePath) const filepath = Path.join(tempDir, 'good.js') const tempDirParent = Path.dirname(tempDir) + const config = createConfig() - const relativePath = Helpers.getRelativePath(tempDir, filepath, {}, tempDirParent) + const relativePath = Helpers.getRelativePath(tempDir, filepath, config, tempDirParent) // Since the project is the parent of the temp dir, the relative path should be // the dir containing the file, plus the file. (e.g. asgln3/good.js) const expectedPath = Path.join(Path.basename(tempDir), 'good.js') @@ -203,8 +225,9 @@ describe('Worker Helpers', () => { const tempFixturePath = await copyFileToTempDir(fixtureFile) const tempDir = Path.dirname(tempFixturePath) const filepath = Path.join(tempDir, 'good.js') + const config = createConfig() - const relativePath = Helpers.getRelativePath(tempDir, filepath, {}, null) + const relativePath = Helpers.getRelativePath(tempDir, filepath, config, null) expect(relativePath).toBe('good.js') // Remove the temporary directory diff --git a/src/main.js b/src/main.js index b3ebd46d..faf9e79d 100644 --- a/src/main.js +++ b/src/main.js @@ -14,6 +14,7 @@ let path let helpers let workerHelpers let isConfigAtHomeRoot +let migrateConfigOptions const loadDeps = () => { if (!path) { @@ -85,19 +86,10 @@ module.exports = { activate() { this.subscriptions = new CompositeDisposable() - /** - * FIXME: Deprecated eslintRulesDir{String} option in favor of - * eslintRulesDirs{Array}. Remove in the next major release, - * in v8.5.0, or after 2018-04. - */ - const oldRulesdir = atom.config.get('linter-eslint.eslintRulesDir') - if (oldRulesdir) { - const rulesDirs = atom.config.get('linter-eslint.eslintRulesDirs') - if (rulesDirs.length === 0) { - atom.config.set('linter-eslint.eslintRulesDirs', [oldRulesdir]) - } - atom.config.unset('linter-eslint.eslintRulesDir') + if (!migrateConfigOptions) { + migrateConfigOptions = require('./migrate-config-options') } + migrateConfigOptions() const embeddedScope = 'source.js.embedded.html' this.subscriptions.add(atom.config.observe( @@ -129,7 +121,7 @@ module.exports = { this.subscriptions.add(atom.workspace.observeTextEditors((editor) => { editor.onDidSave(async () => { if (hasValidScope(editor, scopes) - && atom.config.get('linter-eslint.fixOnSave') + && atom.config.get('linter-eslint.autofix.fixOnSave') ) { await this.fixJob(true) } @@ -152,27 +144,27 @@ module.exports = { })) this.subscriptions.add(atom.config.observe( - 'linter-eslint.showRuleIdInMessage', + 'linter-eslint.advanced.showRuleIdInMessage', (value) => { showRule = value } )) this.subscriptions.add(atom.config.observe( - 'linter-eslint.disableWhenNoEslintConfig', + 'linter-eslint.disabling.disableWhenNoEslintConfig', (value) => { disableWhenNoEslintConfig = value } )) this.subscriptions.add(atom.config.observe( - 'linter-eslint.rulesToSilenceWhileTyping', + 'linter-eslint.disabling.rulesToSilenceWhileTyping', (ids) => { ignoredRulesWhenModified = ids } )) this.subscriptions.add(atom.config.observe( - 'linter-eslint.rulesToDisableWhileFixing', + 'linter-eslint.autofix.rulesToDisableWhileFixing', (ids) => { ignoredRulesWhenFixing = idsToIgnoredRules(ids) } )) this.subscriptions.add(atom.config.observe( - 'linter-eslint.ignoreFixableRulesWhileTyping', + 'linter-eslint.autofix.ignoreFixableRulesWhileTyping', (value) => { ignoreFixableRulesWhileTyping = value } )) diff --git a/src/migrate-config-options.js b/src/migrate-config-options.js new file mode 100644 index 00000000..b2591ad0 --- /dev/null +++ b/src/migrate-config-options.js @@ -0,0 +1,106 @@ +'use babel' + +/* + * These migrations can take one of two forms, a direct move or a general function. + * + * Direct move: + * These objects have an array of `moves`, which + * are objects containing an `old` setting name and a `new` setting name. + * Any existing config found in the `old` name will be moved over to (and overwrite) + * the `new` key. + * + * Functions: + * These have a `migrate` function, which takes the + * current linter-eslint atom config as an argument, and can act on it however + * it needs to. + */ +const activeMigrations = [ + { + added: 'January, 2018', + description: 'Organized config settings into sections', + moves: [ + { + old: 'disableWhenNoEslintConfig', + new: 'disabling.disableWhenNoEslintConfig', + }, { + old: 'fixOnSave', + new: 'autofix.fixOnSave' + }, { + old: 'ignoreFixableRulesWhileTyping', + new: 'autofix.ignoreFixableRulesWhileTyping' + }, { + old: 'rulesToDisableWhileFixing', + new: 'autofix.rulesToDisableWhileFixing' + }, { + old: 'rulesToSilenceWhileTyping', + new: 'disabling.rulesToSilenceWhileTyping' + }, { + old: 'disableEslintIgnore', + new: 'advanced.disableEslintIgnore' + }, { + old: 'disableFSCache', + new: 'advanced.disableFSCache' + }, { + old: 'showRuleIdInMessage', + new: 'advanced.showRuleIdInMessage' + }, { + old: 'eslintrcPath', + new: 'global.eslintrcPath' + }, { + old: 'advancedLocalNodeModules', + new: 'advanced.localNodeModules' + }, { + old: 'eslintRulesDirs', + new: 'advanced.eslintRulesDirs' + }, { + old: 'useGlobalEslint', + new: 'global.useGlobalEslint' + }, { + old: 'globalNodePath', + new: 'global.globalNodePath' + } + ] + }, + { + added: 'September, 2017', + description: 'Deprecated eslintRulesDir{String} option in favor of eslintRulesDirs{Array}', + migrate(config) { + const oldRulesdir = config.eslintRulesDir + if (oldRulesdir) { + const newRulesDirs = config.eslintRulesDirs + if (newRulesDirs.length === 0) { + atom.config.set('linter-eslint.eslintRulesDirs', [oldRulesdir]) + } + atom.config.unset('linter-eslint.eslintRulesDir') + } + } + } +] + +/* + * This function can be called when linter-eslint first activates in order to + * ensure that the user's settings are up-to-date with the current version of + * linter-eslint. Ideally, we would call this only when upgrading to a new + * version. + */ +function migrateConfigOptions(migrations = activeMigrations) { + if (migrations.length) { + const linterEslintConfig = atom.config.get('linter-eslint') + migrations.forEach((migration) => { + if (migration.moves && Array.isArray(migration.moves)) { + // Copy old settings over to the new ones, then unset the old setting keys + migration.moves.forEach((move) => { + const oldSetting = linterEslintConfig[move.old] + if (oldSetting !== undefined) { + atom.config.set(`linter-eslint.${move.new}`, oldSetting) + atom.config.unset(`linter-eslint.${move.old}`) + } + }) + } else if (typeof migration.migrate === 'function') { + migration.migrate(linterEslintConfig) + } + }) + } +} + +module.exports = migrateConfigOptions diff --git a/src/worker-helpers.js b/src/worker-helpers.js index bdcfd47e..ba6492f2 100644 --- a/src/worker-helpers.js +++ b/src/worker-helpers.js @@ -51,9 +51,9 @@ function isDirectory(dirPath) { export function findESLintDirectory(modulesDir, config, projectPath) { let eslintDir = null let locationType = null - if (config.useGlobalEslint) { + if (config.global.useGlobalEslint) { locationType = 'global' - const configGlobal = cleanPath(config.globalNodePath) + const configGlobal = cleanPath(config.global.globalNodePath) const prefixPath = configGlobal || getNodePrefixPath() // NPM on Windows and Yarn on all platforms eslintDir = Path.join(prefixPath, 'node_modules', 'eslint') @@ -61,22 +61,22 @@ export function findESLintDirectory(modulesDir, config, projectPath) { // NPM on platforms other than Windows eslintDir = Path.join(prefixPath, 'lib', 'node_modules', 'eslint') } - } else if (!config.advancedLocalNodeModules) { + } else if (!config.advanced.localNodeModules) { locationType = 'local project' eslintDir = Path.join(modulesDir || '', 'eslint') - } else if (Path.isAbsolute(cleanPath(config.advancedLocalNodeModules))) { + } else if (Path.isAbsolute(cleanPath(config.advanced.localNodeModules))) { locationType = 'advanced specified' - eslintDir = Path.join(cleanPath(config.advancedLocalNodeModules), 'eslint') + eslintDir = Path.join(cleanPath(config.advanced.localNodeModules), 'eslint') } else { locationType = 'advanced specified' - eslintDir = Path.join(projectPath || '', cleanPath(config.advancedLocalNodeModules), 'eslint') + eslintDir = Path.join(projectPath || '', cleanPath(config.advanced.localNodeModules), 'eslint') } if (isDirectory(eslintDir)) { return { path: eslintDir, type: locationType, } - } else if (config.useGlobalEslint) { + } else if (config.global.useGlobalEslint) { throw new Error('ESLint not found, please ensure the global Node path is set correctly.') } return { @@ -91,7 +91,7 @@ export function getESLintFromDirectory(modulesDir, config, projectPath) { // eslint-disable-next-line import/no-dynamic-require return require(ESLintDirectory) } catch (e) { - if (config.useGlobalEslint && e.code === 'MODULE_NOT_FOUND') { + if (config.global.useGlobalEslint && e.code === 'MODULE_NOT_FOUND') { throw new Error('ESLint not found, try restarting Atom to clear caches.') } // eslint-disable-next-line import/no-dynamic-require @@ -137,7 +137,7 @@ export function getConfigPath(fileDir) { } export function getRelativePath(fileDir, filePath, config, projectPath) { - const ignoreFile = config.disableEslintIgnore ? null : findCached(fileDir, '.eslintignore') + const ignoreFile = config.advanced.disableEslintIgnore ? null : findCached(fileDir, '.eslintignore') // If we can find an .eslintignore file, we can set cwd there // (because they are expected to be at the project root) @@ -159,16 +159,16 @@ export function getRelativePath(fileDir, filePath, config, projectPath) { export function getCLIEngineOptions(type, config, rules, filePath, fileDir, givenConfigPath) { const cliEngineConfig = { rules, - ignore: !config.disableEslintIgnore, + ignore: !config.advanced.disableEslintIgnore, fix: type === 'fix' } - const ignoreFile = config.disableEslintIgnore ? null : findCached(fileDir, '.eslintignore') + const ignoreFile = config.advanced.disableEslintIgnore ? null : findCached(fileDir, '.eslintignore') if (ignoreFile) { cliEngineConfig.ignorePath = ignoreFile } - cliEngineConfig.rulePaths = config.eslintRulesDirs.map((path) => { + cliEngineConfig.rulePaths = config.advanced.eslintRulesDirs.map((path) => { const rulesDir = cleanPath(path) if (!Path.isAbsolute(rulesDir)) { return findCached(fileDir, rulesDir) @@ -176,9 +176,9 @@ export function getCLIEngineOptions(type, config, rules, filePath, fileDir, give return rulesDir }).filter(path => path) - if (givenConfigPath === null && config.eslintrcPath) { + if (givenConfigPath === null && config.global.eslintrcPath) { // If we didn't find a configuration use the fallback from the settings - cliEngineConfig.configFile = cleanPath(config.eslintrcPath) + cliEngineConfig.configFile = cleanPath(config.global.eslintrcPath) } return cliEngineConfig diff --git a/src/worker.js b/src/worker.js index 845ee7c7..2e0af61e 100644 --- a/src/worker.js +++ b/src/worker.js @@ -44,7 +44,7 @@ module.exports = async () => { contents, type, config, filePath, projectPath, rules, emitKey } = jobConfig try { - if (config.disableFSCache) { + if (config.advanced.disableFSCache) { FindCache.clear() } @@ -52,7 +52,7 @@ module.exports = async () => { const eslint = Helpers.getESLintInstance(fileDir, config, projectPath) const configPath = Helpers.getConfigPath(fileDir) const noProjectConfig = (configPath === null || isConfigAtHomeRoot(configPath)) - if (noProjectConfig && config.disableWhenNoEslintConfig) { + if (noProjectConfig && config.disabling.disableWhenNoEslintConfig) { emit(emitKey, { messages: [] }) return }