diff --git a/.babelrc b/.babelrc index 2bbf404fc2..9d198317df 100644 --- a/.babelrc +++ b/.babelrc @@ -1,4 +1,11 @@ { - "optional": ["runtime"], + "presets": [ + "es2015", + "react", + "stage-1", + ], + plugins: [ + "transform-runtime", + ], "sourceMaps": "inline" } diff --git a/.eslintrc b/.eslintrc.yml similarity index 80% rename from .eslintrc rename to .eslintrc.yml index f27ff79e4a..b601df8b17 100644 --- a/.eslintrc +++ b/.eslintrc.yml @@ -3,12 +3,12 @@ extends: eslint:recommended env: node: true es6: true -ecmaFeatures: - modules: true +parserOptions: + sourceType: module + ecmaVersion: 6 rules: max-len: [1, 99, 2] semi: [2, "never"] - quotes: [2, "single"] curly: [2, "multi-line"] comma-dangle: [2, always-multiline] eqeqeq: [2, "allow-null"] diff --git a/.npmignore b/.npmignore index 3442f11564..8d019b34a7 100644 --- a/.npmignore +++ b/.npmignore @@ -3,11 +3,14 @@ reports/ resolvers/ # config -.eslintrc +.babelrc +.eslintrc.yml .travis.yml appveyor.yml +.coveralls.yml .editorconfig .gitignore +gulpfile.js # project stuff *.sublime-* diff --git a/.travis.yml b/.travis.yml index 6f2793d324..e71d76b16c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,5 @@ script: - "npm run-script ci-test" - "for resolver in ./resolvers/*; do cd $resolver && npm test && cd ../..; done" -# something broke remap-istanbul :-( -# after_success: -# - npm run coveralls +after_success: + - npm run coveralls diff --git a/README.md b/README.md index a7a8c471fe..a2eeaf12e4 100644 --- a/README.md +++ b/README.md @@ -54,15 +54,15 @@ or if you manage ESLint as a dev dependency: npm install eslint-plugin-import --save-dev ``` -As of v0.9, all rules are off by default. However, you may configure them manually -in your `.eslintrc`, or extend one of the canned base configs from the `eslint-config-import` -package: +All rules are off by default. However, you may configure them manually +in your `.eslintrc.(yml|json|js)`, or extend one of the canned configs: ```yaml --- extends: - - "eslint:recommended" - - import/warnings # after `npm i -D eslint-config-import`-ing + - eslint:recommended + - plugin:import/errors + - plugin:import/warnings # or configure manually: plugins: @@ -185,76 +185,6 @@ settings: See [resolver plugins](#resolver-plugins). -#### `import/parser` - -This setting allows you to provide a custom parser module, in the event your -project uses syntax not understood by Babel. - -This plugin defaults to using Babylon, Babel's internal parser, but is also -compatible with Espree's AST. As long as the import nodes follow [ESTree], -any parser should work. - -If you're using [babel-eslint] as ESLint's parser, and especially if you are using -any ES7+ features (object spread, decorators, etc.) you should specify it here, as -well: - -```yaml -settings: - import/parser: babel-eslint -``` - -If you're using the shared config `eslint-config-import`, you can also check out [`import/es7-jsx`], -which enables JSX and all current Babylon ES7 features. - -I am hoping to obviate this setting (and `import/parse-options`) entirely via -[a pull request](https://github.com/eslint/eslint/pull/4649) whereby I can just -use whatever parser is configured for ESLint proper. Coming to you whenever -ESLint 2.0 is released. 😎 - -[custom parser]: https://github.com/eslint/eslint/blob/master/docs/user-guide/configuring.md#specifying-parser -[babel-eslint]: https://github.com/babel/babel-eslint -[ESTree]: https://github.com/estree/estree - -#### `import/parse-options` - -This setting will be merged 1-level deep (think `Object.assign`) with the default -parse options and passed as the second parameter to the parser: `parse(file, options)`. -See the [`import/es7-jsx`] -config file for an example of explicit parse options for Babylon. - -Or, if you are using another parser, you may want to set these options as well. -(and maybe contribute another config file! i.e. `eslint-config-import/espree`) - -[`import/es7-jsx`]: https://github.com/benmosher/eslint-plugin-import/tree/master/config - -Here is an example `.eslintrc` for reference: - -```yaml - -extends: - - "eslint:recommended" - - import/warnings # optionally start from eslint-config-import - -# if not using the `extends` package, make sure to add the plugin here: -plugins: - - import - -rules: - import/default: 2 - import/no-unresolved: 1 - -settings: - - import/ignore: - # any imported module path matching one of these patterns will not be parsed - - 'node_modules' # this is the default, but must be included if overwritten - - '\\.es5$' - - import/resolver: webpack # will use 'node' if not specified - - import/parser: esprima-fb # default is 'babylon'. change if needed. -``` - ## SublimeLinter-eslint SublimeLinter-eslint introduced a change to support `.eslintignore` files diff --git a/config/README.md b/config/README.md deleted file mode 100644 index 2a4ded6037..0000000000 --- a/config/README.md +++ /dev/null @@ -1,11 +0,0 @@ -This package contains some pre-fabricated ESLint config files, intended for use -with [eslint-plugin-import](https://www.npmjs.com/package/eslint-plugin-import). - -The following stock configurations are provided: - -- `import` (index): just the bare-bones rules that catch misspelled/missing names. -- `import/warnings`: the above, plus warnings for common mistakes. -- `import/es7-jsx`: `import` + parser settings for stage 1 ES7 syntax and JSX. - -All configure the plugin for you. You may opt to combine the latter two for -maximum plugin goodness. diff --git a/config/index.js b/config/errors.js similarity index 100% rename from config/index.js rename to config/errors.js diff --git a/config/es7-jsx.js b/config/es7-jsx.js deleted file mode 100644 index 8e58deafcf..0000000000 --- a/config/es7-jsx.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Parser options to allow ES7 + JSX syntax in imported files. - */ -module.exports = { - extends: 'import', - // see https://github.com/babel/babel/tree/master/packages/babylon#options - // plugins array is not merged with defaults, so include all desired plugins. - settings: { - 'import/parse-options': { plugins: [ 'decorators' - , 'classProperties' - , 'objectRestSpread' - , 'exportExtensions' - , 'exponentiationOperator' - , 'trailingFunctionCommas' - // react - , 'jsx' - ] - } - } -} diff --git a/config/package.json b/config/package.json deleted file mode 100644 index 8b818ed22f..0000000000 --- a/config/package.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "eslint-config-import", - "version": "0.9.1", - "description": "Sibling config package for eslint-plugin-import.", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/benmosher/eslint-plugin-import.git" - }, - "keywords": [ - "eslint", - "eslint-config", - "eslint-plugin-import", - "import" - ], - "author": "Ben Mosher ", - "license": "MIT", - "bugs": { - "url": "https://github.com/benmosher/eslint-plugin-import/issues" - }, - "homepage": "https://github.com/benmosher/eslint-plugin-import#readme" -} diff --git a/config/warnings.js b/config/warnings.js index 444e7f6a10..dfd61be441 100644 --- a/config/warnings.js +++ b/config/warnings.js @@ -3,9 +3,8 @@ * @type {Object} */ module.exports = { - extends: 'import', + plugins: ['import'], rules: { 'import/no-named-as-default': 1 , 'import/no-duplicates': 1 - , 'import/no-require': 1 } } diff --git a/gulpfile.js b/gulpfile.js index 8b4299b01f..ff8b64d61d 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -5,6 +5,7 @@ var gulp = require('gulp') , path = require('path') , glob = require('glob') , fs = require('fs') + , rimraf = require('rimraf') var SRC = 'src/**/*.js' , DEST = 'lib' @@ -54,6 +55,16 @@ function wipeExtras(src, dest, done) { }) } +gulp.task('clean-src', function (done) { + rimraf(DEST, done) +}) + +gulp.task('clean-tests', function (done) { + rimraf('tests/lib', done) +}) + +gulp.task('clean', ['clean-src', 'clean-tests']) + gulp.task('wipe-extras', function (done) { var unfinished = 2 function megadone(err) { @@ -78,7 +89,7 @@ gulp.task('pretest', ['src', 'tests', 'wipe-extras']) gulp.task('test', ['pretest'], function () { return gulp.src('tests/lib/**/*.js', { read: false }) - .pipe(mocha({ reporter: 'dot' })) + .pipe(mocha({ reporter: 'spec', grep: process.env.TEST_GREP })) // NODE_PATH=./lib mocha --recursive --reporter dot tests/lib/ }) diff --git a/package.json b/package.json index 1f67ad1126..703d0e06d1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-import", - "version": "0.13.0", + "version": "1.0.0-beta.0", "description": "Import with sanity.", "main": "lib/index.js", "directories": { @@ -13,7 +13,7 @@ "ci-test": "eslint ./src && gulp pretest && istanbul cover --report lcovonly --dir reports/coverage _mocha tests/lib/ -- --recursive --reporter dot", "debug": "NODE_PATH=./lib mocha debug --recursive --reporter dot tests/lib/", "prepublish": "eslint ./src && gulp prepublish", - "coveralls": "remap-istanbul -i reports/coverage/coverage.json -o reports/coverage/lcov.info --type lcovonly && cat ./reports/coverage/lcov.info | coveralls" + "coveralls": "cat ./reports/coverage/lcov.info | coveralls" }, "repository": { "type": "git", @@ -35,29 +35,32 @@ }, "homepage": "https://github.com/benmosher/eslint-plugin-import", "devDependencies": { - "babel": "5.x", - "babel-eslint": "^4.1.4", + "babel": "6.5.1", + "babel-eslint": "^4.1.8", + "babel-plugin-transform-runtime": "6.5.2", + "babel-preset-es2015": "6.5.0", + "babel-preset-react": "6.5.0", + "babel-preset-stage-1": "6.5.0", "chai": "^3.4.0", "coveralls": "^2.11.4", - "eslint": ">=1.8.0", + "eslint": "2.x", "eslint-import-resolver-node": "file:./resolvers/node", "eslint-import-resolver-webpack": "file:./resolvers/webpack", "glob": "^6.0.2", "gulp": "^3.9.0", - "gulp-babel": "5.x", + "gulp-babel": "6.1.2", "gulp-changed": "^1.3.0", "gulp-mocha": "^2.2.0", "istanbul": "^0.4.0", "mocha": "^2.2.1", "redux": "^3.0.4", - "remap-istanbul": "^0.5.1" + "rimraf": "2.5.2" }, "peerDependencies": { - "eslint": ">=1.4.0" + "eslint": "2.x" }, "dependencies": { - "babel-runtime": "5.x", - "babylon": "^6.1.2", + "babel-runtime": "6.5.0", "eslint-import-resolver-node": "^0.1.0" }, "greenkeeper": { diff --git a/resolvers/webpack/package.json b/resolvers/webpack/package.json index 59c9bdad8a..b34e16192c 100644 --- a/resolvers/webpack/package.json +++ b/resolvers/webpack/package.json @@ -1,6 +1,6 @@ { "name": "eslint-import-resolver-webpack", - "version": "0.1.4", + "version": "0.1.5", "description": "Resolve paths to dependencies, given a webpack.config.js. Plugin for eslint-plugin-import.", "main": "index.js", "scripts": { diff --git a/resolvers/webpack/resolve-alias.js b/resolvers/webpack/resolve-alias.js index 046a6121d5..485b41eecf 100644 --- a/resolvers/webpack/resolve-alias.js +++ b/resolvers/webpack/resolve-alias.js @@ -18,13 +18,23 @@ var sep = '/' function matchAlias(source, alias, value) { var isExact = (alias[alias.length - 1] === '$') , isFile = (path.extname(value) !== '') - , segments = source.split(sep) + , sourceSegments = source.split(sep) + , ptr = 0 + , aliasSegments if (isExact) alias = alias.slice(0, -1) - if (segments[0] === alias) { + aliasSegments = alias.split(sep) + + // look for a common prefix + while(sourceSegments[ptr] == aliasSegments[ptr] && ptr < sourceSegments.length && ptr < aliasSegments.length) { + ptr++; + } + + // the common prefix must be the entirety of the alias + if (ptr === aliasSegments.length) { // always return exact match - if (segments.length === 1) return value + if (sourceSegments.length === aliasSegments.length) return value // prefix match on exact match for file is an error if (isFile && (isExact || !/^[./]/.test(value))) { @@ -32,7 +42,7 @@ function matchAlias(source, alias, value) { } // otherwise, prefix match is fine for non-file paths - if (!isExact && !isFile) return [value].concat(segments.slice(1)).join(sep) + if (!isExact && !isFile) return [value].concat(sourceSegments.slice(ptr)).join(sep) } } diff --git a/resolvers/webpack/test/alias.js b/resolvers/webpack/test/alias.js index 8ea0e1b3dd..74f7b49f44 100644 --- a/resolvers/webpack/test/alias.js +++ b/resolvers/webpack/test/alias.js @@ -73,3 +73,60 @@ describe("webpack alias spec", function () { tableLine( { xyz$: "xyz/dir" } , 'xyz/dir', 'xyz/file' ) }) + +describe("nested module names", function () { + // from table: http://webpack.github.io/docs/configuration.html#resolve-alias + function nestedName(alias, xyz, xyzFile) { + describe(JSON.stringify(alias), function () { + it("top/xyz: " + xyz, function () { + expect(resolveAlias('top/xyz', alias)).to.equal(xyz) + }) + it("top/xyz/file: " + (xyzFile.name || xyzFile), function () { + if (xyzFile === Error) { + expect(resolveAlias.bind(null, 'top/xyz/file', alias)).to.throw(xyzFile) + } else { + expect(resolveAlias('top/xyz/file', alias)).to.equal(xyzFile) + } + }) + }) + } + + nestedName( { 'top/xyz': "/absolute/path/to/file.js" } + , '/absolute/path/to/file.js', 'top/xyz/file' ) + + nestedName( { 'top/xyz$': "/absolute/path/to/file.js" } + , "/absolute/path/to/file.js", Error ) + + nestedName( { 'top/xyz': "./dir/file.js" } + , './dir/file.js', 'top/xyz/file' ) + + nestedName( { 'top/xyz$': "./dir/file.js" } + , './dir/file.js', Error ) + + nestedName( { 'top/xyz': "/some/dir" } + , '/some/dir', '/some/dir/file' ) + + nestedName( { 'top/xyz$': "/some/dir" } + , '/some/dir', 'top/xyz/file' ) + + nestedName( { 'top/xyz': "./dir" } + , './dir', './dir/file' ) + + nestedName( { 'top/xyz': "modu" } + , 'modu', 'modu/file' ) + + nestedName( { 'top/xyz$': "modu" } + , 'modu', 'top/xyz/file' ) + + nestedName( { 'top/xyz': "modu/some/file.js" } + , 'modu/some/file.js', Error ) + + nestedName( { 'top/xyz': "modu/dir" } + , 'modu/dir', 'modu/dir/file' ) + + nestedName( { 'top/xyz': "top/xyz/dir" } + , 'top/xyz/dir', 'top/xyz/dir/file' ) + + nestedName( { 'top/xyz$': "top/xyz/dir" } + , 'top/xyz/dir', 'top/xyz/file' ) +}) diff --git a/src/.eslintrc b/src/.eslintrc index a3e81e44f8..340d66bf69 100644 --- a/src/.eslintrc +++ b/src/.eslintrc @@ -1,11 +1,3 @@ --- -extends: '../.eslintrc' - -env: - es6: true - -ecmaFeatures: - modules: true - rules: comma-dangle: [1, "always-multiline"] diff --git a/src/core/getExports.js b/src/core/getExports.js index cc63647e5e..c40f500c5c 100644 --- a/src/core/getExports.js +++ b/src/core/getExports.js @@ -33,7 +33,11 @@ export default class ExportMap { static for(path, context) { let exportMap - const cacheKey = hashObject(context.settings) + const cacheKey = hashObject({ + settings: context.settings, + parserPath: context.parserPath, + parserOptions: context.parserOptions, + }) let exportCache = exportCaches.get(cacheKey) if (exportCache === undefined) { exportCache = new Map() @@ -150,6 +154,16 @@ export default class ExportMap { this.named.add(s.exported.name) }.bind(this)) } + + reportErrors(context, declaration) { + context.report({ + node: declaration.source, + message: `Parse errors in imported module '${declaration.source.value}': ` + + `${this.errors + .map(e => `${e.message} (${e.lineNumber}:${e.column})`) + .join(', ')}`, + }) + } } diff --git a/src/core/parse.js b/src/core/parse.js index 0c2f228464..1d9fa60d57 100644 --- a/src/core/parse.js +++ b/src/core/parse.js @@ -1,45 +1,49 @@ import fs from 'fs' -const defaultParseOptions = { - ecmaVersion: 6, // for espree, esprima. not needed for babylon - sourceType: 'module', -} - -export default function (path, { settings, ecmaFeatures } = {}) { - const parser = (settings && settings['import/parser']) || 'babylon' +export default function (p, context) { - const { parse } = require(parser) - , options = getOptions(parser, settings, ecmaFeatures) + if (context == null) throw new Error("need context to parse properly") - const ast = parse( fs.readFileSync(path, {encoding: 'utf8'}) - , options - ) + let { parserOptions, parserPath } = context - // bablyon returns top-level "File" node. - return ast.type === 'File' ? ast.program : ast -} + if (!parserPath) throw new Error("parserPath is required!") + // hack: espree blows up with frozen options + parserOptions = Object.assign({}, parserOptions) + parserOptions.ecmaFeatures = Object.assign({}, parserOptions.ecmaFeatures) -function getOptions(parser, settings, ecmaFeatures) { + // require the parser relative to the main module (i.e., ESLint) + const parser = requireParser(parserPath) - let options = Object.assign( {} - , defaultParseOptions - , settings && settings['import/parse-options']) + return parser.parse( + fs.readFileSync(p, {encoding: 'utf8'}), + parserOptions) +} - function inferFeature(feat) { - if (ecmaFeatures[feat] && (options.plugins.indexOf(feat) < 0)) { - options.plugins.push(feat) - } - } +import Module from 'module' +import * as path from 'path' - // detect and handle "jsx" ecmaFeature - if (parser === 'babylon') { - if (ecmaFeatures) { - options.plugins = options.plugins ? options.plugins.slice() : [] - inferFeature('jsx') - inferFeature('flow') - } - } +// borrowed from babel-eslint +function createModule(filename) { + var mod = new Module(filename) + mod.filename = filename + mod.paths = Module._nodeModulePaths(path.dirname(filename)) + return mod +} - return options +function requireParser(p) { + try { + // attempt to get espree relative to eslint + const eslintPath = require.resolve('eslint') + const eslintModule = createModule(eslintPath) + return require(Module._resolveFilename(p, eslintModule)) + } catch(err) { /* ignore */ } + + try { + // try relative to entry point + return require.main.require(p) + } catch(err) { /* ignore */ } + + // finally, try from here + return require(p) } diff --git a/src/index.js b/src/index.js index a0f8c9db38..5067399b81 100644 --- a/src/index.js +++ b/src/index.js @@ -13,17 +13,7 @@ export const rules = { 'imports-first': require('./rules/imports-first'), } -export const rulesConfig = { - 'no-unresolved': 0, - 'named': 0, - 'namespace': 0, - 'default': 0, - 'export': 0, - - 'no-named-as-default': 0, - - 'no-commonjs': 0, - 'no-amd': 0, - 'no-duplicates': 0, - 'imports-first': 0, +export const configs = { + 'errors': require('../config/errors'), + 'warnings': require('../config/warnings'), } diff --git a/src/rules/default.js b/src/rules/default.js index 04e5960f51..8ac9aece54 100644 --- a/src/rules/default.js +++ b/src/rules/default.js @@ -18,11 +18,7 @@ module.exports = function (context) { if (imports == null) return if (imports.errors.length) { - context.report({ - node: node.source, - message: `Parse errors in imported module ` + - `'${node.source.value}'.`, - }) + imports.reportErrors(context, node) } else if (!imports.hasDefault) { context.report(defaultSpecifier, 'No default export found in module.') } diff --git a/src/rules/export.js b/src/rules/export.js index 5dc531b3f3..25bfdbe32d 100644 --- a/src/rules/export.js +++ b/src/rules/export.js @@ -45,11 +45,7 @@ module.exports = function (context) { if (remoteExports == null) return if (remoteExports.errors.length) { - context.report({ - node: node.source, - message: `Parse errors in imported module ` + - `'${node.source.value}'.`, - }) + remoteExports.reportErrors(context, node) return } diff --git a/src/rules/named.js b/src/rules/named.js index 13ae469705..aed6b13c9a 100644 --- a/src/rules/named.js +++ b/src/rules/named.js @@ -13,11 +13,7 @@ module.exports = function (context) { if (imports == null) return if (imports.errors.length) { - context.report({ - node: node.source, - message: `Parse errors in imported module ` + - `'${node.source.value}'.`, - }) + imports.reportErrors(context, node) return } diff --git a/src/rules/namespace.js b/src/rules/namespace.js index 98632ed899..2d78c6a966 100644 --- a/src/rules/namespace.js +++ b/src/rules/namespace.js @@ -12,11 +12,7 @@ module.exports = function (context) { if (imports == null) return null if (imports.errors.length) { - context.report({ - node: declaration.source, - message: `Parse errors in imported module ` + - `'${declaration.source.value}'.`, - }) + imports.reportErrors(context, declaration) return } diff --git a/src/rules/no-named-as-default.js b/src/rules/no-named-as-default.js index af9e7c7ec2..f1f3e613a6 100644 --- a/src/rules/no-named-as-default.js +++ b/src/rules/no-named-as-default.js @@ -9,11 +9,7 @@ module.exports = function (context) { if (imports == null) return if (imports.errors.length) { - context.report({ - node: declaration.source, - message: `Parse errors in imported module ` + - `'${declaration.source.value}'.`, - }) + imports.reportErrors(context, declaration) return } diff --git a/tests/.eslintrc b/tests/.eslintrc index 7a25d76e5b..27d4220555 100644 --- a/tests/.eslintrc +++ b/tests/.eslintrc @@ -1,10 +1,6 @@ --- -extends: '../.eslintrc' env: mocha: true - es6: true -ecmaFeatures: - modules: true rules: no-unused-expressions: 0 quotes: [2, 'single', 'avoid-escape'] diff --git a/tests/files/.eslintrc b/tests/files/.eslintrc index 968aeb9cca..5970c5fa16 100644 --- a/tests/files/.eslintrc +++ b/tests/files/.eslintrc @@ -1,7 +1,5 @@ --- parser: 'babel-eslint' -env: - es6: true -ecmaFeatures: - jsx: true - modules: true +parserOptions: + ecmaFeatures: + jsx: true diff --git a/tests/src/core/getExports.js b/tests/src/core/getExports.js index e6c42a4f94..940f406257 100644 --- a/tests/src/core/getExports.js +++ b/tests/src/core/getExports.js @@ -1,13 +1,16 @@ import { expect } from 'chai' -import ExportMap from '../../../lib/core/getExports' +import ExportMap from 'core/getExports' import * as fs from 'fs' import { getFilename } from '../utils' describe('getExports', function () { - const fakeContext = { getFilename: getFilename - , settings: {} } + const fakeContext = { + getFilename: getFilename, + settings: {}, + parserPath: 'babel-eslint', + } it('should handle ExportAllDeclaration', function () { var imports @@ -45,7 +48,7 @@ describe('getExports', function () { const differentSettings = Object.assign( {}, fakeContext, - { settings: { 'import/parser': 'babel-eslint' } }) + { parserPath: 'espree' }) expect(ExportMap.get('./named-exports', differentSettings)) .to.exist.and @@ -74,29 +77,32 @@ describe('getExports', function () { }) it('finds exports for an ES7 module with babel-eslint', function () { - var imports = ExportMap.parse( getFilename('jsx/FooES7.js') - , { settings: { 'import/parser': 'babel-eslint' } }) + var imports = ExportMap.parse( + getFilename('jsx/FooES7.js'), + { parserPath: 'babel-eslint' } + ) expect(imports).to.exist expect(imports).to.have.property('hasDefault', true) expect(imports.named.has('Bar')).to.be.true }) - it('finds exports for an ES7 module with proper parse options', function () { - var imports = ExportMap.parse(getFilename('jsx/FooES7.js'), { settings: { - 'import/parse-options': { - plugins: [ - 'decorators', - 'jsx', - 'classProperties', - 'objectRestSpread', - ], - }, - }}) - - expect(imports).to.exist - expect(imports).to.have.property('hasDefault', true) - expect(imports.named.has('Bar')).to.be.true - }) + // it('finds exports for an ES7 module with proper parse options', function () { + // var imports = ExportMap.parse( + // getFilename('jsx/FooES7.js'), + // { + // parserPath: 'espree', + // parserOptions: { + // ecmaVersion: 7, + // ecmaFeatures: { jsx: true }, + // }, + // } + // ) + + // expect(imports).to.exist + // expect(imports.errors).to.be.empty + // expect(imports).to.have.property('hasDefault', true) + // expect(imports.named.has('Bar')).to.be.true + // }) }) diff --git a/tests/src/core/parse.js b/tests/src/core/parse.js index 7a6f669465..a054f393df 100644 --- a/tests/src/core/parse.js +++ b/tests/src/core/parse.js @@ -5,22 +5,10 @@ import { getFilename } from '../utils' describe('parse(path, { settings, ecmaFeatures })', function () { it("doesn't support JSX by default", function () { - expect(() => parse(getFilename('jsx.js'))).to.throw(Error) + expect(() => parse(getFilename('jsx.js'), { parserPath: 'espree' })).to.throw(Error) }) - it('infers jsx from ecmaFeatures when using stock Babylon', function () { - expect(() => parse(getFilename('jsx.js'), { ecmaFeatures: { jsx: true }})) + it('infers jsx from ecmaFeatures when using stock parser', function () { + expect(() => parse(getFilename('jsx.js'), { parserPath: 'espree', parserOptions: { sourceType: 'module', ecmaFeatures: { jsx: true } } })) .not.to.throw(Error) }) - it('adds plugin if not found', function () { - expect(() => parse(getFilename('jsx.js'), { - ecmaFeatures: { jsx: true }, - settings: { 'import/parse-options': { plugins: ['exportExtentions'] } }, - })).not.to.throw(Error) - }) - it('keeps plugin if found', function () { - expect(() => parse(getFilename('jsx.js'), { - ecmaFeatures: { jsx: true }, - settings: { 'import/parse-options': { plugins: ['jsx'] } }, - })).not.to.throw(Error) - }) }) diff --git a/tests/src/package.js b/tests/src/package.js index 5d40a2b538..2312b09d28 100644 --- a/tests/src/package.js +++ b/tests/src/package.js @@ -4,18 +4,18 @@ var path = require('path') , fs = require('fs') describe('package', function () { - let pkg + let pkg = path.join(process.cwd(), 'lib') + , module - before(function () { - pkg = path.join(process.cwd(), 'lib') + before('is importable', function () { + module = require(pkg) }) - it('is importable', function () { - expect(require(pkg)).to.exist + it('exists', function () { + expect(module).to.exist }) it('has every rule', function (done) { - var module = require(pkg) fs.readdir( path.join(pkg, 'rules') @@ -31,21 +31,16 @@ describe('package', function () { }) }) - it('has config for every rule', function (done) { - var module = require(pkg) + it('has configs only for rules that exist', function () { + for (let configFile in module.configs) { + let preamble = 'import/' - fs.readdir( - path.join(pkg, 'rules') - , function (err, files) { - expect(err).not.to.exist - - files.forEach(function (f) { - expect(module.rulesConfig).to.have - .property(path.basename(f, '.js')) - }) - - done() - }) + for (let rule in module.configs[configFile].rules) { + expect(() => require('rules/'+rule.slice(preamble.length))) + .not.to.throw(Error) + } + } }) + }) diff --git a/tests/src/rules/default.js b/tests/src/rules/default.js index 3a777eddb0..a2cfb41827 100644 --- a/tests/src/rules/default.js +++ b/tests/src/rules/default.js @@ -2,7 +2,7 @@ import { test } from '../utils' import { RuleTester } from 'eslint' var ruleTester = new RuleTester() - , rule = require('../../../lib/rules/default') + , rule = require('rules/default') ruleTester.run('default', rule, { valid: [ @@ -35,11 +35,20 @@ ruleTester.run('default', rule, { // sanity check test({ code: 'export {a} from "./named-exports"' }), - test({ code: 'import twofer from "./trampoline"' - , settings: { 'import/parse-options': { plugins: ['exportExtensions']}} }), + test({ + code: 'import twofer from "./trampoline"', + parser: 'babel-eslint', + }), + // jsx - test({ code: 'import MyCoolComponent from "./jsx/MyCoolComponent.jsx"' - , ecmaFeatures: { jsx: true, modules: true } }), + test({ + code: 'import MyCoolComponent from "./jsx/MyCoolComponent.jsx"', + parserOptions: { + sourceType: 'module', + ecmaVersion: 6, + ecmaFeatures: { jsx: true }, + }, + }), // #54: import of named export default test({ code: 'import foo from "./named-default-export"' }), @@ -52,30 +61,16 @@ ruleTester.run('default', rule, { // from no-errors test({ code: "import Foo from './jsx/FooES7.js';", - settings: { 'import/parse-options': { - plugins: [ - 'decorators', - 'jsx', - 'classProperties', - 'objectRestSpread', - ], - }}, + parser: 'babel-eslint', }), + ], + invalid: [ test({ code: "import Foo from './jsx/FooES7.js';", - ecmaFeatures: { modules: true, jsx: true }, - settings: { 'import/parse-options': { - plugins: [ - 'decorators', - 'classProperties', - 'objectRestSpread', - ], - }}, + errors: ["Parse errors in imported module './jsx/FooES7.js': Unexpected token = (6:16)"], }), - ], - invalid: [ test({ code: 'import crypto from "./common";', settings: { 'import/ignore': ['foo'] }, @@ -93,22 +88,30 @@ ruleTester.run('default', rule, { test({ code: "import Foo from './jsx/FooES7.js';", - errors: ["Parse errors in imported module './jsx/FooES7.js'."], + errors: ["Parse errors in imported module './jsx/FooES7.js': Unexpected token = (6:16)"], }), // es7 export syntax - test({ code: 'export baz from "./named-exports"' - , parser: 'babel-eslint' - , errors: 1 }), - test({ code: 'export baz, { bar } from "./named-exports"' - , parser: 'babel-eslint' - , errors: 1 }), - test({ code: 'export baz, * as names from "./named-exports"' - , parser: 'babel-eslint' - , errors: 1 }), + test({ + code: 'export baz from "./named-exports"', + parser: 'babel-eslint', + errors: ['No default export found in module.'], + }), + test({ + code: 'export baz, { bar } from "./named-exports"', + parser: 'babel-eslint', + errors: ['No default export found in module.'], + }), + test({ + code: 'export baz, * as names from "./named-exports"', + parser: 'babel-eslint', + errors: ['No default export found in module.'], + }), // exports default from a module with no default - test({ code: 'import twofer from "./broken-trampoline"' - , settings: { 'import/parse-options': { plugins: ['exportExtensions']}} - , errors: 1 }), + test({ + code: 'import twofer from "./broken-trampoline"', + parser: 'babel-eslint', + errors: ['No default export found in module.'], + }), ], }) diff --git a/tests/src/rules/export.js b/tests/src/rules/export.js index 9505f98df8..3276495289 100644 --- a/tests/src/rules/export.js +++ b/tests/src/rules/export.js @@ -3,7 +3,7 @@ import { test } from '../utils' import { RuleTester } from 'eslint' var ruleTester = new RuleTester() - , rule = require('../../../lib/rules/export') + , rule = require('rules/export') ruleTester.run('export', rule, { valid: [ @@ -16,38 +16,45 @@ ruleTester.run('export', rule, { test({ code: 'export var { foo, bar } = object;' }), test({ code: 'export var [ foo, bar ] = array;' }), test({ code: 'export { foo, foo as bar }' }), - test({ - code: 'export { bar }; export * from "./export-all"', - settings: { 'import/parse-options': { plugins: ['exportExtensions']}}, - }), - test({ - code: 'export * from "./export-all"', - settings: { 'import/parse-options': { plugins: ['exportExtensions']}}, - }), + test({ code: 'export { bar }; export * from "./export-all"' }), + test({ code: 'export * from "./export-all"' }), test({ code: 'export * from "./does-not-exist"' }), ], invalid: [ // multiple defaults - test({ code: 'export default foo; export default bar' - , errors: 2 }), - test({ code: 'export default function foo() {}; ' + - 'export default function bar() {}' - , errors: 2 }), - test({ code: 'export function foo() {}; ' + - 'export { bar as foo }' - , errors: 2 }), - test({ code: 'export {foo}; export {foo};' - , errors: 2 }), - test({ code: 'export {foo}; export {bar as foo};' - , errors: 2 }), - test({ code: 'export var foo = "foo"; export var foo = "bar";' - , errors: 2 }), - test({ code: 'export var foo = "foo", foo = "bar";' - , errors: 2 }), + test({ + code: 'export default foo; export default bar', + errors: ['Multiple default exports.', 'Multiple default exports.'], + }), + test({ + code: 'export default function foo() {}; ' + + 'export default function bar() {}', + errors: ['Multiple default exports.', 'Multiple default exports.'], + }), + test({ + code: 'export function foo() {}; ' + + 'export { bar as foo }', + errors: ["Multiple exports of name 'foo'.", "Multiple exports of name 'foo'."], + }), + test({ + code: 'export {foo}; export {foo};', + errors: ["Multiple exports of name 'foo'.", "Multiple exports of name 'foo'."], + }), + test({ + code: 'export {foo}; export {bar as foo};', + errors: ["Multiple exports of name 'foo'.", "Multiple exports of name 'foo'."], + }), + test({ + code: 'export var foo = "foo"; export var foo = "bar";', + errors: ["Multiple exports of name 'foo'.", "Multiple exports of name 'foo'."], + }), + test({ + code: 'export var foo = "foo", foo = "bar";', + errors: ["Multiple exports of name 'foo'.", "Multiple exports of name 'foo'."], + }), test({ code: 'export { foo }; export * from "./export-all"', - settings: { 'import/parse-options': { plugins: ['exportExtensions']}}, errors: ['Multiple exports of name \'foo\'.', 'Multiple exports of name \'foo\'.'], }), @@ -59,7 +66,7 @@ ruleTester.run('export', rule, { test({ code: 'export * from "./malformed.js"', errors: [{ - message: "Parse errors in imported module './malformed.js'.", + message: "Parse errors in imported module './malformed.js': 'return' outside of function (1:1)", type: 'Literal', }], }), diff --git a/tests/src/rules/imports-first.js b/tests/src/rules/imports-first.js index 04691d02c9..1733c31343 100644 --- a/tests/src/rules/imports-first.js +++ b/tests/src/rules/imports-first.js @@ -3,7 +3,7 @@ import { test } from '../utils' import { linter, RuleTester } from 'eslint' const ruleTester = new RuleTester() - , rule = require('../../../lib/rules/imports-first') + , rule = require('rules/imports-first') ruleTester.run('imports-first', rule, { valid: [ diff --git a/tests/src/rules/named.js b/tests/src/rules/named.js index d4fd6429e3..e6a192fada 100644 --- a/tests/src/rules/named.js +++ b/tests/src/rules/named.js @@ -2,7 +2,7 @@ import { test } from '../utils' import { RuleTester } from 'eslint' var ruleTester = new RuleTester() - , rule = require('../../../lib/rules/named') + , rule = require('rules/named') function error(name, module) { return { message: name + ' not found in \'' + module + '\'' @@ -48,10 +48,14 @@ ruleTester.run('named', rule, { test({ code: 'export { foo } from "./does-not-exist"' }), // es7 - test({ code: 'export bar, { foo } from "./bar"' - , parser: 'babel-eslint' }), - test({ code: 'import { foo, bar } from "./named-trampoline"' - , settings: { 'import/parse-options': { plugins: ['exportExtensions'] }} }), + test({ + code: 'export bar, { foo } from "./bar"', + parser: 'babel-eslint', + }), + test({ + code: 'import { foo, bar } from "./named-trampoline"', + parser: 'babel-eslint', + }), // regression tests test({ code: 'export { foo as bar }'}), @@ -63,17 +67,9 @@ ruleTester.run('named', rule, { test({ code: 'import { deepSparseElement } from "./named-exports"' }), // flow types - test({ code: 'import type { MyType } from "./flowtypes"' - , settings: { 'import/parser': 'babel-eslint' }}), - // infer flow from ecmaFeatures - test({ - code: 'import type { MyType } from "./flowtypes"', - ecmaFeatures: { flow: true, modules: true }, - }), - // ...or explicit parser plugin test({ code: 'import type { MyType } from "./flowtypes"', - settings: { 'import/parse-options': { plugins: [ 'flow' ] } }, + 'parser': 'babel-eslint', }), // jsnext @@ -127,49 +123,53 @@ ruleTester.run('named', rule, { test({code: 'import {a, b, c, d, e} from "./re-export"', errors: [error('e', './re-export')]}), - test({code: 'import { a } from "./re-export-names"', + test({ + code: 'import { a } from "./re-export-names"', args: [2, 'es6-only'], - errors: [error('a', './re-export-names')]}), + errors: [error('a', './re-export-names')], + }), // export tests - test({ code: 'export { bar } from "./bar"' - , errors: 1 }), + test({ + code: 'export { bar } from "./bar"', + errors: ["bar not found in './bar'"], + }), // es7 - test({ code: 'export bar2, { bar } from "./bar"' - , parser: 'babel-eslint' - , errors: 1 }), - test({ code: 'import { foo, bar, baz } from "./named-trampoline"' - , settings: { 'import/parse-options': { plugins: ['exportExtensions']}} - , errors: 1 }), - test({ code: 'import { baz } from "./broken-trampoline"' - , settings: { 'import/parse-options': { plugins: ['exportExtensions']}} - , errors: 1 }), + test({ + code: 'export bar2, { bar } from "./bar"', + parser: 'babel-eslint', + errors: ["bar not found in './bar'"], + }), + test({ + code: 'import { foo, bar, baz } from "./named-trampoline"', + parser: 'babel-eslint', + errors: ["baz not found in './named-trampoline'"], + }), + test({ + code: 'import { baz } from "./broken-trampoline"', + parser: 'babel-eslint', + errors: ["baz not found in './broken-trampoline'"], + }), // parse errors test({ code: "import { a } from './test.coffee';", errors: [{ - message: "Parse errors in imported module './test.coffee'.", + message: "Parse errors in imported module './test.coffee': Unexpected token > (1:20)", type: 'Literal', }], }), // flow types - test({ code: 'import type { MissingType } from "./flowtypes"' - , settings: { 'import/parser': 'babel-eslint' } - , errors: [{ - message: "MissingType not found in './flowtypes'", - type: 'Identifier', - }]}), - // infer flow from ecmaFeatures test({ code: 'import type { MissingType } from "./flowtypes"', - ecmaFeatures: { flow: true, modules: true }, + parser: 'babel-eslint', errors: [{ message: "MissingType not found in './flowtypes'", type: 'Identifier', - }]}), + }], + }), // jsnext test({ diff --git a/tests/src/rules/namespace.js b/tests/src/rules/namespace.js index d1a5fb0d9d..c8db87003b 100644 --- a/tests/src/rules/namespace.js +++ b/tests/src/rules/namespace.js @@ -2,7 +2,7 @@ var test = require('../utils').test import { RuleTester } from 'eslint' var ruleTester = new RuleTester({ env: { es6: true }}) - , rule = require('../../../lib/rules/namespace') + , rule = require('rules/namespace') function error(name, namespace) { @@ -20,8 +20,13 @@ ruleTester.run('namespace', rule, { 'console.log(names.a);' }), test({ code: 'import * as names from "./re-export-names"; ' + 'console.log(names.foo);' }), - test({ code: "import * as elements from './jsx';" - , settings: { 'import/parse-options': { plugins: ['jsx'] }}}), + test({ + code: "import * as elements from './jsx';", + parserOptions: { + sourceType: 'module', + ecmaFeatures: { jsx: true }, + }, + }), test({ code: "import * as foo from './common';" , settings: { 'import/ignore': ['common'] } }), @@ -71,44 +76,49 @@ ruleTester.run('namespace', rule, { test({ code: "import * as names from './named-exports';" + " console.log(names['a']);" - , errors: 1 }), + , errors: ["Unable to validate computed reference to imported namespace 'names'."] }), // assignment warning (from no-reassign) test({ code: 'import * as foo from \'./bar\'; foo.foo = \'y\';' , errors: [{ message: 'Assignment to member of namespace \'foo\'.'}] }), test({ code: 'import * as foo from \'./bar\'; foo.x = \'y\';' - , errors: 2 }), + , errors: ['Assignment to member of namespace \'foo\'.', '\'x\' not found in imported namespace foo.'] }), // invalid destructuring - test({ code: 'import * as names from "./named-exports";' + - 'const { c } = names' - , errors: [{ type: 'Property' }] }), - test({ code: 'import * as names from "./named-exports";' + - 'function b() { const { c } = names }' - , errors: [{ type: 'Property' }] }), - test({ code: 'import * as names from "./named-exports";' + - 'const { c: d } = names' - , errors: [{ type: 'Property' }] }), - test({ code: 'import * as names from "./named-exports";' + - 'const { c: { d } } = names' - , errors: [{ type: 'Property' }] }), + test({ + code: 'import * as names from "./named-exports"; const { c } = names', + errors: [{ type: 'Property', message: "'c' not found in imported namespace names." }], + }), + test({ + code: 'import * as names from "./named-exports"; function b() { const { c } = names }', + errors: [{ type: 'Property', message: "'c' not found in imported namespace names." }], + }), + test({ + code: 'import * as names from "./named-exports"; const { c: d } = names', + errors: [{ type: 'Property', message: "'c' not found in imported namespace names." }], + }), + test({ + code: 'import * as names from "./named-exports";' + + 'const { c: { d } } = names', + errors: [{ type: 'Property', message: "'c' not found in imported namespace names." }], + }), ///////// // es7 // ///////// test({ code: 'export * as names from "./default-export"' , parser: 'babel-eslint' - , errors: 1 }), + , errors: ["No exported names found in module './default-export'."] }), test({ code: 'export defport, * as names from "./default-export"' , parser: 'babel-eslint' - , errors: 1 }), + , errors: ["No exported names found in module './default-export'."] }), // parse errors test({ code: "import * as namespace from './malformed.js';", errors: [{ - message: "Parse errors in imported module './malformed.js'.", + message: "Parse errors in imported module './malformed.js': 'return' outside of function (1:1)", type: 'Literal', }], }), diff --git a/tests/src/rules/no-amd.js b/tests/src/rules/no-amd.js index a46406f7e7..5b0e39f4f6 100644 --- a/tests/src/rules/no-amd.js +++ b/tests/src/rules/no-amd.js @@ -3,10 +3,11 @@ import { RuleTester } from 'eslint' var ruleTester = new RuleTester() ruleTester.run('no-amd', require('rules/no-amd'), { - valid: [ - { code: 'import "x";', ecmaFeatures: { modules: true } }, - { code: 'import x from "x"', ecmaFeatures: { modules: true } }, - 'var x = require("x")', + valid: [ + { code: 'import "x";', parserOptions: { sourceType: 'module' } }, + { code: 'import x from "x"', parserOptions: { sourceType: 'module' } }, + 'var x = require("x")', + 'require("x")', // 2-args, not an array 'require("x", "y")', diff --git a/tests/src/rules/no-commonjs.js b/tests/src/rules/no-commonjs.js index 735757c1cc..243bb16dc9 100644 --- a/tests/src/rules/no-commonjs.js +++ b/tests/src/rules/no-commonjs.js @@ -9,14 +9,14 @@ ruleTester.run('no-commonjs', require('rules/no-commonjs'), { valid: [ // imports - { code: 'import "x";', ecmaFeatures: { modules: true } }, - { code: 'import x from "x"', ecmaFeatures: { modules: true } }, - { code: 'import x from "x"', ecmaFeatures: { modules: true } }, - { code: 'import { x } from "x"', ecmaFeatures: { modules: true } }, + { code: 'import "x";', parserOptions: { sourceType: 'module' } }, + { code: 'import x from "x"', parserOptions: { sourceType: 'module' } }, + { code: 'import x from "x"', parserOptions: { sourceType: 'module' } }, + { code: 'import { x } from "x"', parserOptions: { sourceType: 'module' } }, // exports - { code: 'export default "x"', ecmaFeatures: { modules: true } }, - { code: 'export function house() {}', ecmaFeatures: { modules: true } }, + { code: 'export default "x"', parserOptions: { sourceType: 'module' } }, + { code: 'export function house() {}', parserOptions: { sourceType: 'module' } }, // allowed requires { code: 'function a() { var x = require("y"); }' }, // nested requires allowed diff --git a/tests/src/rules/no-duplicates.js b/tests/src/rules/no-duplicates.js index 0c5c3e2033..f2ca388c66 100644 --- a/tests/src/rules/no-duplicates.js +++ b/tests/src/rules/no-duplicates.js @@ -4,7 +4,7 @@ import { test } from '../utils' import { RuleTester } from 'eslint' const ruleTester = new RuleTester() - , rule = require('../../../lib/rules/no-duplicates') + , rule = require('rules/no-duplicates') ruleTester.run('no-duplicates', rule, { valid: [ @@ -17,25 +17,22 @@ ruleTester.run('no-duplicates', rule, { invalid: [ test({ code: "import { x } from './foo'; import { y } from './foo'", - errors: 2, + errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'], }), test({ - code: "import { x } from './foo';\ - import { y } from './foo';\ - import { z } from './foo'", - errors: 3, + code: "import { x } from './foo'; import { y } from './foo'; import { z } from './foo'", + errors: ['\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.', '\'./foo\' imported multiple times.'], }), // ensure resolved path results in warnings test({ - code: "import { x } from './bar';\ - import { y } from 'bar';", + code: "import { x } from './bar'; import { y } from 'bar';", settings: { 'import/resolve': { paths: [path.join( process.cwd() , 'tests', 'files' )] }}, - errors: 2, + errors: 2, // path ends up hardcoded }), // #86: duplicate unresolved modules should be flagged diff --git a/tests/src/rules/no-named-as-default.js b/tests/src/rules/no-named-as-default.js index 6183a48cd6..af7ef581f6 100644 --- a/tests/src/rules/no-named-as-default.js +++ b/tests/src/rules/no-named-as-default.js @@ -2,7 +2,7 @@ import { test } from '../utils' import { RuleTester } from 'eslint' const ruleTester = new RuleTester() - , rule = require('../../../lib/rules/no-named-as-default') + , rule = require('rules/no-named-as-default') ruleTester.run('no-named-as-default', rule, { valid: [ @@ -45,7 +45,7 @@ ruleTester.run('no-named-as-default', rule, { test({ code: 'import foo from "./malformed.js"', errors: [{ - message: "Parse errors in imported module './malformed.js'.", + message: "Parse errors in imported module './malformed.js': 'return' outside of function (1:1)", type: 'Literal', }], }), diff --git a/tests/src/rules/no-unresolved.js b/tests/src/rules/no-unresolved.js index 633d33914d..e5ad104f3d 100644 --- a/tests/src/rules/no-unresolved.js +++ b/tests/src/rules/no-unresolved.js @@ -5,7 +5,7 @@ import { test } from '../utils' import { RuleTester } from 'eslint' var ruleTester = new RuleTester() - , rule = require('../../../lib/rules/no-unresolved') + , rule = require('rules/no-unresolved') function runResolverTests(resolver) { // redefine 'test' to set a resolver @@ -113,24 +113,24 @@ function runResolverTests(resolver) { }]}), rest({ code: 'export { foo } from "./does-not-exist"' - , errors: 1 }), + , errors: ["Unable to resolve path to module './does-not-exist'."] }), rest({ code: 'export * from "./does-not-exist"', - errors: 1, + errors: ["Unable to resolve path to module './does-not-exist'."], }), // export symmetry proposal rest({ code: 'export * as bar from "./does-not-exist"' , parser: 'babel-eslint' - , errors: 1, + , errors: ["Unable to resolve path to module './does-not-exist'."], }), rest({ code: 'export bar from "./does-not-exist"' , parser: 'babel-eslint' - , errors: 1, + , errors: ["Unable to resolve path to module './does-not-exist'."], }), rest({ code: 'import foo from "./jsx/MyUncoolComponent.jsx"' - , errors: 1 }), + , errors: ["Unable to resolve path to module './jsx/MyUncoolComponent.jsx'."] }), // commonjs setting diff --git a/tests/src/utils.js b/tests/src/utils.js index 24be4d037f..285fe34903 100644 --- a/tests/src/utils.js +++ b/tests/src/utils.js @@ -12,7 +12,10 @@ export const FILENAME = testFilePath('foo.js') export function test(t) { return Object.assign({ filename: FILENAME, - ecmaFeatures: {modules: true, destructuring: true}, + parserOptions: { + sourceType: 'module', + ecmaVersion: 6, + }, }, t) }