diff --git a/README.md b/README.md index a346f930..3bc01f70 100644 --- a/README.md +++ b/README.md @@ -381,55 +381,6 @@ The logfile is written to "importjs.log" in your operating system's default directory for temporary files. You can get the path to the log file by running `importjsd logpath`. -## Local configuration (*deprecated*) - -_This way of configuring ImportJS is deprecated and will be removed in a future -release. See [Dynamic Configuration](#dynamic-configuration) for a better way -of accomplishing the same thing_. -_ -You can dynamically apply configuration to different directory trees within your -project by turning the `.importjs.js` file into an array of configuration -objects. Each configuration specifies what part of the tree it applies to -through the `appliesTo` and `appliesFrom` options. - -```javascript -[ - { - appliesTo: 'app/**', - declarationKeyword: 'import', - }, - { - appliesTo: 'app/**', - declarationKeyword: 'const', - }, - { - appliesFrom: 'tests/**', - appliesTo: 'app/**', - declarationKeyword: 'var', - importFunction: 'mockRequire', - }, -] -``` - -Use glob patterns supported by [minimatch][] for the `appliesTo` and -`appliesFrom` values. If any of the patterns are omitted, the default catch-all -"globstar" pattern (`**`) is used. The difference between the two patterns is -that `appliesTo` is matched with the file you are currently editing (relative -to the project root). The `appliesFrom` pattern is matched with the file you -are currently importing (also relative to the project root) will be used when -matching. - -[minimatch]: https://github.com/isaacs/minimatch - -Put more specific configuration at the bottom of the configuration file and the -default, catch-all configuration at the top. - -When using `appliesFrom` only a subset of configurations are supported: - -- `declarationKeyword` -- `importFunction` -- `stripFileExtensions` - ## Dynamic configuration Different sections of your application may have special importing needs. For diff --git a/lib/Configuration.js b/lib/Configuration.js index 0f068e45..50a6d73b 100644 --- a/lib/Configuration.js +++ b/lib/Configuration.js @@ -2,7 +2,6 @@ import path from 'path'; -import minimatch from 'minimatch'; import semver from 'semver'; import FileUtils from './FileUtils'; @@ -51,24 +50,8 @@ const MERGABLE_CONFIG_OPTIONS = [ 'namedExports', ]; -const RENAMED_CONFIGURATION_OPTIONS = { - applies_to: 'appliesTo', - applies_from: 'appliesFrom', - declaration_keyword: 'declarationKeyword', - named_exports: 'namedExports', - group_imports: 'groupImports', - ignore_package_prefixes: 'ignorePackagePrefixes', - import_dev_dependencies: 'importDevDependencies', - import_function: 'importFunction', - max_line_length: 'maxLineLength', - minimum_version: 'minimumVersion', - strip_file_extensions: 'stripFileExtensions', -}; - const KNOWN_CONFIGURATION_OPTIONS = [ 'aliases', - 'appliesFrom', - 'appliesTo', 'coreModules', 'declarationKeyword', 'environments', @@ -92,25 +75,6 @@ const ENVIRONMENTS = { meteor: meteorEnvironment, }; -function convertRenamedConfiguration(config: Object): Object { - const convertedConfig = Object.assign({}, config); - const messages = []; - - Object.keys(RENAMED_CONFIGURATION_OPTIONS).forEach((oldKey: string) => { - const newKey = RENAMED_CONFIGURATION_OPTIONS[oldKey]; - if (Object.prototype.hasOwnProperty.call(config, oldKey)) { - convertedConfig[newKey] = convertedConfig[oldKey]; - delete convertedConfig[oldKey]; - - messages.push( - `Deprecated configuration: \`${oldKey}\` has changed to \`${newKey}\`` - ); - } - }); - - return { config: convertedConfig, messages }; -} - function checkForUnknownConfiguration(config: Object): Array { const messages = []; @@ -192,27 +156,10 @@ export default class Configuration { this.messages.push( `Unable to parse configuration file. Reason:\n${error.stack}`); } - if (userConfig) { - if (Array.isArray(userConfig)) { - this.messages.push( - 'Deprecated configuration: Array style configuration detected. ' + - 'Local configuration using `appliesTo`/`appliesFrom` will be ' + - 'removed in a future version. Use a JavaScript configuration file ' + - 'and specify the configuration through functions (where needed) ' + - 'instead.' - ); - } else { - userConfig = [userConfig]; - } - // Check for deprecated configuration and add messages if we find any. - // Clone array to prevent mutating the original. - Array.from(userConfig).reverse().forEach((config: Object) => { - const convertedConfig = convertRenamedConfiguration(config); - this.configs.push(convertedConfig.config); - this.messages.push(...convertedConfig.messages); - this.messages.push(...checkForUnknownConfiguration(convertedConfig.config)); - }); + if (userConfig) { + this.configs.push(userConfig); + this.messages.push(...checkForUnknownConfiguration(userConfig)); // Add configurations for the environments specified in the user config // file. @@ -220,6 +167,7 @@ export default class Configuration { this.configs.push(ENVIRONMENTS[environment]); }); } + this.configs.push(DEFAULT_CONFIG); checkCurrentVersion(this.get('minimumVersion')); @@ -235,31 +183,10 @@ export default class Configuration { moduleName?: string, } = {} ): any { - const applyingConfigs = this.configs.filter((config: Object): boolean => { - const { - appliesTo = '**', - appliesFrom = '**', - } = config; - - if (!(key in config)) { - return false; - } - - if (!minimatch(this.pathToCurrentFile, - normalizePath(appliesTo, this.workingDirectory))) { - // This configuration does not apply to the current file being edited. - return false; - } - - if (!pathToImportedModule) { - return true; - } + const applyingConfigs = this.configs.filter((config: Object): boolean => ( + Object.prototype.hasOwnProperty.call(config, key) + )); - return minimatch( - normalizePath(pathToImportedModule, this.workingDirectory), - normalizePath(appliesFrom, this.workingDirectory) - ); - }); return mergedValue( applyingConfigs.map((config: Object): any => config[key]), key, diff --git a/lib/__tests__/Configuration-test.js b/lib/__tests__/Configuration-test.js index 918f8c44..fc44baf5 100644 --- a/lib/__tests__/Configuration-test.js +++ b/lib/__tests__/Configuration-test.js @@ -31,26 +31,6 @@ describe('Configuration', () => { }); }); - describe('with deprecated snake_cased configuration', () => { - beforeEach(() => { - FileUtils.__setFile(path.join(process.cwd(), '.importjs.js'), { - declaration_keyword: 'const', - }); - }); - - it('has a message about deprecated configuration', () => { - const configuration = new Configuration(); - expect(configuration.messages).toEqual([ - 'Deprecated configuration: `declaration_keyword` has changed to `declarationKeyword`', - ]); - }); - - it('can be retrieved via #get("camelCased")', () => { - const configuration = new Configuration(); - expect(configuration.get('declarationKeyword')).toEqual('const'); - }); - }); - describe('with unknown configuration', () => { beforeEach(() => { FileUtils.__setFile(path.join(process.cwd(), '.importjs.js'), { @@ -197,95 +177,6 @@ describe('Configuration', () => { }); }); }); - - describe('with multiple configurations', () => { - beforeEach(() => { - FileUtils.__setFile(path.join(process.cwd(), '.importjs.js'), [ - { - declarationKeyword: 'const', - importFunction: 'foobar', - }, - { - appliesTo: 'goo/**', - declarationKeyword: 'var', - }, - ]); - }); - - it('has a deprecation message', () => { - const configuration = new Configuration(); - expect(configuration.messages).toEqual([ - 'Deprecated configuration: Array style configuration detected. ' + - 'Local configuration using `appliesTo`/`appliesFrom` will be ' + - 'removed in a future version. Use a JavaScript configuration file ' + - 'and specify the configuration through functions (where needed) ' + - 'instead.', - ]); - }); - - describe('when the file being edited matches appliesTo', () => { - let configuration; - - beforeEach(() => { - configuration = new Configuration(`${process.cwd()}/goo/gar/gaz.js`); - }); - - it('uses local configuration', () => { - expect(configuration.get('declarationKeyword')).toEqual('var'); - }); - - it('falls back to global config if key missing from local config', () => { - expect(configuration.get('importFunction')).toEqual('foobar'); - }); - - it('falls back to default config if key is completely missing', () => { - expect(configuration.get('maxLineLength')).toEqual(80); - }); - }); - - it('works when the path to local file is not a full path', () => { - const configuration = new Configuration('goo/gar/gaz.js'); - expect(configuration.get('declarationKeyword')).toEqual('var'); - }); - - it('uses global config when the file does not match appliesTo', () => { - const configuration = new Configuration('foo/far/gaz.js'); - expect(configuration.get('declarationKeyword')).toEqual('const'); - }); - }); - - describe('with appliesFrom', () => { - beforeEach(() => { - FileUtils.__setFile(path.join(process.cwd(), '.importjs.js'), [ - { - declarationKeyword: 'const', - }, - { - appliesTo: 'goo/**', - appliesFrom: 'from/**', - declarationKeyword: 'var', - }, - ]); - }); - - it('uses local config when pathToImportedModule matches appliesFrom', () => { - const configuration = new Configuration('goo/gar/gaz.js'); - const opts = { pathToImportedModule: 'from/hello.js' }; - expect(configuration.get('declarationKeyword', opts)).toEqual('var'); - }); - - it('uses global config when pathToImportedModule does not match appliesFrom', () => { - const configuration = new Configuration('goo/gar/gaz.js'); - const opts = { pathToImportedModule: 'not_from/hello.js' }; - expect(configuration.get('declarationKeyword', opts)).toEqual('const'); - }); - - it('uses global config when current file does not match appliesTo', () => { - const configuration = new Configuration('foo/gar/gaz.js'); - const opts = { pathToImportedModule: 'from/hello.js' }; - expect(configuration.get('declarationKeyword', opts)).toEqual('const'); - }); - }); }); describe('#get coreModules', () => { @@ -383,40 +274,6 @@ describe('Configuration', () => { }); }); - describe('#get aliases', () => { - beforeEach(() => { - // TODO: replace the array-style configuration here when we have an - // environment that specify aliases. - FileUtils.__setFile( - path.join(process.cwd(), '.importjs.js'), - [ - { - aliases: { - foo: 'foosball', - }, - }, - { - aliases: { - bar: 'barsketball', - }, - }, - { - aliases: () => ({ - baz: 'bazeball', - }), - }, - ]); - }); - - it('merges all aliases into a single object', () => { - expect(new Configuration().get('aliases')).toEqual({ - foo: 'foosball', - bar: 'barsketball', - baz: 'bazeball', - }); - }); - }); - describe('#get moduleSideEffectImports', () => { describe('in meteor environment', () => { beforeEach(() => { @@ -468,34 +325,6 @@ describe('Configuration', () => { }); }); - describe('#get namedExports', () => { - beforeEach(() => { - // TODO: replace the array-style configuration here when we have an - // environment that specify namedExports. - FileUtils.__setFile( - path.join(process.cwd(), '.importjs.js'), - [ - { - namedExports: { - foo: ['foosball'], - }, - }, - { - namedExports: () => ({ - bar: ['barsketball'], - }), - }, - ]); - }); - - it('merges all namedExports into a single object', () => { - expect(new Configuration().get('namedExports')).toEqual({ - foo: ['foosball'], - bar: ['barsketball'], - }); - }); - }); - describe('#get namedExports from meteor environment', () => { beforeEach(() => { FileUtils.__setFile(path.join(process.cwd(), '.importjs.js'), { @@ -600,28 +429,6 @@ jane:bar@0.0.1 }); }); - - describe('#get lookupPaths', () => { - beforeEach(() => { - FileUtils.__setFile( - path.join(process.cwd(), '.importjs.js'), - [ - { - lookupPaths: ['foo'], - }, - { - lookupPaths: ['bar'], - }, - ]); - }); - - it('uses only one lookupPaths config (no merge)', () => { - expect(new Configuration().get('lookupPaths')).toEqual([ - 'bar', - ]); - }); - }); - describe("#get('packageDependencies')", () => { it('returns an empty array', () => { expect(new Configuration().get('packageDependencies')).toEqual([]); diff --git a/lib/__tests__/Importer-test.js b/lib/__tests__/Importer-test.js index 7fb70873..c51a58bd 100644 --- a/lib/__tests__/Importer-test.js +++ b/lib/__tests__/Importer-test.js @@ -72,12 +72,12 @@ describe('Importer', () => { requireResolve.__reset(); }); - it('has a message about the deprecated configuration', () => { - configuration = { declaration_keyword: 'const' }; + it('has a message about unknown configuration', () => { + configuration = { somethingStrange: 'foo' }; setup(); const importer = new Importer(text.split('\n'), pathToCurrentFile); expect(importer.messages).toEqual([ - 'Deprecated configuration: `declaration_keyword` has changed to `declarationKeyword`', + 'Unknown configuration: `somethingStrange`', ]); }); @@ -1947,105 +1947,6 @@ import foo from './foo'; foo `.trim()); }); - - describe('with local configuration defined in the main config file', () => { - beforeEach(() => { - existingFiles = ['bar/goo.jsx']; - pathToCurrentFile = 'foo/bar.js'; - configuration.appliesTo = 'foo/**/*'; - configuration.declarationKeyword = 'var'; - text = 'goo'; - word = 'goo'; - }); - - - it('uses local config when the pattern matches the file being edited', () => { - expect(subject()).toEqual(` -var goo = require('../bar/goo'); - -goo - `.trim()); - }); - - it('falls back to default when the pattern does not match file being edited', () => { - configuration.appliesTo = 'car/**'; - - expect(subject()).toEqual(` -import goo from '../bar/goo'; - -goo - `.trim()); - }); - - describe('with an appliesFrom pattern', () => { - beforeEach(() => { - configuration = Object.assign(configuration, { - appliesFrom: 'bar/**/*', - declarationKeyword: 'var', - importFunction: 'quack', - stripFileExtensions: [], - }); - }); - - describe('that matches the path of the file being imported', () => { - it('uses local config', () => { - expect(subject()).toEqual(` -var goo = quack('../bar/goo.jsx'); - -goo - `.trim()); - }); - }); - - describe('that does not match the file being imported', () => { - beforeEach(() => { - configuration.appliesFrom = 'foo/**'; - }); - - it('falls back to default config', () => { - expect(subject()).toEqual(` -import goo from '../bar/goo'; - -goo - `.trim()); - }); - }); - }); - - describe('with an appliesFrom pattern and alias', () => { - beforeEach(() => { - word = 'foobar'; - text = 'foobar'; - - configuration = Object.assign(configuration, { - aliases: { - foobar: 'jar/jar/binks', - }, - appliesFrom: 'bar/**/*', - declarationKeyword: 'const', - }); - }); - - it('uses default config when alias path does not match appliesFrom', () => { - expect(subject()).toEqual(` -import foobar from 'jar/jar/binks'; - -foobar - - `.trim()); - }); - - it('uses local config when alias path matches appliesFrom', () => { - configuration.appliesFrom = 'jar/**'; - expect(subject()).toEqual(` -const foobar = require('jar/jar/binks'); - -foobar - - `.trim()); - }); - }); - }); }); });