Skip to content

Commit

Permalink
Add configuration validation and refactor unknown identifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
mikabytes committed Jan 29, 2024
1 parent c1e6611 commit b186968
Show file tree
Hide file tree
Showing 7 changed files with 566 additions and 128 deletions.
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,6 @@ Available plugins are over at [Babel: Plugins List](https://babeljs.io/docs/plug

#### Example: Remove all preconfigured defaults

```javascript
parserPlugins: []
```
Expand Down Expand Up @@ -571,7 +570,7 @@ parserPlugins: [
proposal: 'hack',
},
],
]
];
```

### `sortImports`
Expand Down
112 changes: 6 additions & 106 deletions lib/Configuration.js
Original file line number Diff line number Diff line change
@@ -1,119 +1,23 @@
// @flow

import crypto from 'crypto';
import os from 'os';
import path from 'path';
import has from 'lodash/has';

import globals from 'globals';
import semver from 'semver';

import FileUtils from './FileUtils';
import JsModule from './JsModule';
import findPackageDependencies from './findPackageDependencies';
import meteorEnvironment from './environments/meteorEnvironment';
import nodeEnvironment from './environments/nodeEnvironment';
import normalizePath from './normalizePath';
import version from './version';
import { DEFAULT_PARSER_PLUGINS } from './parse.js';
import { validate, getDefaultConfig } from './configurationSchema.js';

const JSON_CONFIG_FILE = '.importjs.json';
const JS_CONFIG_FILES = ['.importjs.js', '.importjs.cjs', '.importjs.mjs'];

function findGlobalsFromEnvironments(
environments: Array<string>,
): Array<string> {
const result = Object.keys(globals.builtin);

environments.forEach((environment: string) => {
const envGlobals = globals[environment];
if (!envGlobals) {
return;
}
result.push(...Object.keys(envGlobals));
});
return result;
}

const DEFAULT_CONFIG = {
aliases: {},
declarationKeyword: 'import',
cacheLocation: ({ config }: Object): string => {
const hash = crypto
.createHash('md5')
.update(`${config.workingDirectory}-v4`)
.digest('hex');
return path.join(os.tmpdir(), `import-js-${hash}.db`);
},
coreModules: [],
namedExports: {},
environments: [],
excludes: [],
globals: ({ config }: Object): Array<string> =>
findGlobalsFromEnvironments(config.get('environments')),
groupImports: true,
ignorePackagePrefixes: [],
importDevDependencies: false,
importFunction: 'require',
importStatementFormatter: ({ importStatement }: Object): string =>
importStatement,
logLevel: 'info',
maxLineLength: 80,
minimumVersion: '0.0.0',
moduleNameFormatter: ({ moduleName }: Object): string => moduleName,
moduleSideEffectImports: (): Array<string> => [],
sortImports: true,
emptyLineBetweenGroups: true,
stripFileExtensions: ['.js', '.jsx', '.ts', '.tsx'],
danglingCommas: true,
tab: ' ',
useRelativePaths: true,
packageDependencies: ({ config }: Object): Set<string> =>
findPackageDependencies(
config.workingDirectory,
config.get('importDevDependencies'),
),
// Default configuration options, and options inherited from environment
// configuration are overridden if they appear in user config. Some options,
// however, get merged with the parent configuration. This list specifies which
// ones are merged.
mergableOptions: {
aliases: true,
coreModules: true,
namedExports: true,
globals: true,
},
parserPlugins: DEFAULT_PARSER_PLUGINS,
};

const KNOWN_CONFIGURATION_OPTIONS = [
'aliases',
'cacheLocation',
'coreModules',
'declarationKeyword',
'environments',
'excludes',
'globals',
'groupImports',
'ignorePackagePrefixes',
'importDevDependencies',
'importFunction',
'importStatementFormatter',
'logLevel',
'maxLineLength',
'minimumVersion',
'moduleNameFormatter',
'moduleSideEffectImports',
'namedExports',
'sortImports',
'stripFileExtensions',
'tab',
'useRelativePaths',
'mergableOptions',
'danglingCommas',
'emptyLineBetweenGroups',
'parserPlugins',
];
const DEFAULT_CONFIG = getDefaultConfig();

const DEPRECATED_CONFIGURATION_OPTIONS = [];

Expand All @@ -122,16 +26,12 @@ const ENVIRONMENTS = {
meteor: meteorEnvironment,
};

function checkForUnknownConfiguration(config: Object): Array<string> {
function checkConfiguration(config: Object): Array<string> {
const messages = [];

Object.keys(config).forEach((option: string) => {
if (KNOWN_CONFIGURATION_OPTIONS.indexOf(option) === -1) {
messages.push(`Unknown configuration: \`${option}\``);
}
});
const result = validate(config);

return messages;
return result.messages;
}

function checkForDeprecatedConfiguration(config: Object): Array<string> {
Expand Down Expand Up @@ -242,7 +142,7 @@ export default class Configuration {

if (userConfig) {
this.configs.push(userConfig);
this.messages.push(...checkForUnknownConfiguration(userConfig));
this.messages.push(...checkConfiguration(userConfig));
this.messages.push(...checkForDeprecatedConfiguration(userConfig));

// Add configurations for the environments specified in the user config
Expand Down
2 changes: 1 addition & 1 deletion lib/__tests__/ImportStatements-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ describe('ImportStatements', () => {
beforeEach(() => {
FileUtils.__setFile(path.join(process.cwd(), '.importjs.js'), {
environments: ['meteor'],
packageDependencies: new Set(['meteor/bar']),
packageDependencies: ['meteor/bar'],
});
});

Expand Down
45 changes: 45 additions & 0 deletions lib/__tests__/configurationSchema-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { validate, getDefaultConfig } from '../configurationSchema.js';

it('should export defaults as an object', () => {
const config = getDefaultConfig();

expect(config.aliases).toEqual({});
});

it('should validate successfully', () => {
const result = validate({
aliases: {
_: 'third-party-libs/underscore',
},
});
expect(result.error).toEqual(false);
expect(result.messages).toEqual([]);
});

it('should notify about unknown identifiers, and remove them', () => {
const data = {
thisAintRight: 'better fail',
};
const result = validate(data);
expect(result.error).toEqual(true);
expect(result.messages[0]).toEqual('Unknown configuration: `thisAintRight`');
expect(data.hasOwnProperty('thisAintRight')).toBe(false);
});

it('should handle functions', () => {
const result = validate({
aliases: () => ({ _: 'third-party-libs/underscore' }),
});
expect(result.error).toEqual(false);
});

it('should notify about invalid identifiers, and remove them', () => {
const data = {
aliases: 123,
};
const result = validate(data);
expect(result.error).toEqual(true);
expect(result.messages.length).toEqual(1);
expect(result.messages[0]).toEqual('Invalid configuration: `aliases`');
expect(data.hasOwnProperty('aliases')).toBe(false);
});
Loading

0 comments on commit b186968

Please sign in to comment.