Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions tests/src/core/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,63 @@ describe('parse(content, { settings, ecmaFeatures })', function () {
expect(parse.bind(null, path, content, { settings: { 'import/parsers': { [parseStubParserPath]: [ '.js' ] } }, parserPath: null, parserOptions })).not.to.throw(Error);
expect(parseSpy.callCount, 'custom parser to be called once').to.equal(1);
});

it('throws on invalid languageOptions', function () {
expect(parse.bind(null, path, content, { settings: {}, parserPath: null, languageOptions: null })).to.throw(Error);
});

it('throws on non-object languageOptions.parser', function () {
expect(parse.bind(null, path, content, { settings: {}, parserPath: null, languageOptions: { parser: 'espree' } })).to.throw(Error);
});

it('throws on null languageOptions.parser', function () {
expect(parse.bind(null, path, content, { settings: {}, parserPath: null, languageOptions: { parser: null } })).to.throw(Error);
});

it('throws on empty languageOptions.parser', function () {
expect(parse.bind(null, path, content, { settings: {}, parserPath: null, languageOptions: { parser: {} } })).to.throw(Error);
});

it('throws on non-function languageOptions.parser.parse', function () {
expect(parse.bind(null, path, content, { settings: {}, parserPath: null, languageOptions: { parser: { parse: 'espree' } } })).to.throw(Error);
});

it('throws on non-function languageOptions.parser.parse', function () {
expect(parse.bind(null, path, content, { settings: {}, parserPath: null, languageOptions: { parser: { parseForESLint: 'espree' } } })).to.throw(Error);
});

it('requires only one of the parse methods', function () {
expect(parse.bind(null, path, content, { settings: {}, parserPath: null, languageOptions: { parser: { parseForESLint: () => ({ ast: {} }) } } })).not.to.throw(Error);
});

it('uses parse from languageOptions.parser', function () {
const parseSpy = sinon.spy();
expect(parse.bind(null, path, content, { settings: {}, languageOptions: { parser: { parse: parseSpy } } })).not.to.throw(Error);
expect(parseSpy.callCount, 'passed parser to be called once').to.equal(1);
});

it('uses parseForESLint from languageOptions.parser', function () {
const parseSpy = sinon.spy(() => ({ ast: {} }));
expect(parse.bind(null, path, content, { settings: {}, languageOptions: { parser: { parseForESLint: parseSpy } } })).not.to.throw(Error);
expect(parseSpy.callCount, 'passed parser to be called once').to.equal(1);
});

it('prefers parsers specified in the settings over languageOptions.parser', () => {
const parseSpy = sinon.spy();
parseStubParser.parse = parseSpy;
expect(parse.bind(null, path, content, { settings: { 'import/parsers': { [parseStubParserPath]: [ '.js' ] } }, parserPath: null, languageOptions: { parser: { parse() {} } } })).not.to.throw(Error);
expect(parseSpy.callCount, 'custom parser to be called once').to.equal(1);
});

it('ignores parser options from language options set to null', () => {
const parseSpy = sinon.spy();
parseStubParser.parse = parseSpy;
expect(parse.bind(null, path, content, { settings: {}, parserPath: 'espree', languageOptions: { parserOptions: null }, parserOptions: { sourceType: 'module', ecmaVersion: 2015, ecmaFeatures: { jsx: true } } })).not.to.throw(Error);
});

it('prefers languageOptions.parserOptions over parserOptions', () => {
const parseSpy = sinon.spy();
parseStubParser.parse = parseSpy;
expect(parse.bind(null, path, content, { settings: {}, parserPath: 'espree', languageOptions: { parserOptions: { sourceType: 'module', ecmaVersion: 2015, ecmaFeatures: { jsx: true } } }, parserOptions: { sourceType: 'script' } })).not.to.throw(Error);
});
});
22 changes: 22 additions & 0 deletions tests/src/rules/no-unused-modules.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ import fs from 'fs';
import eslintPkg from 'eslint/package.json';
import semver from 'semver';

let FlatRuleTester;
try {
({ FlatRuleTester } = require('eslint/use-at-your-own-risk'));
} catch (e) { /**/ }

// TODO: figure out why these tests fail in eslint 4 and 5
const isESLint4TODO = semver.satisfies(eslintPkg.version, '^4 || ^5');

Expand Down Expand Up @@ -1371,3 +1376,20 @@ describe('parser ignores prefixes like BOM and hashbang', () => {
invalid: [],
});
});

describe('supports flat eslint', { skip: !FlatRuleTester }, () => {
const flatRuleTester = new FlatRuleTester();
flatRuleTester.run('no-unused-modules', rule, {
valid: [{
options: unusedExportsOptions,
code: 'import { o2 } from "./file-o";export default () => 12',
filename: testFilePath('./no-unused-modules/file-a.js'),
}],
invalid: [{
options: unusedExportsOptions,
code: 'export default () => 13',
filename: testFilePath('./no-unused-modules/file-f.js'),
errors: [error(`exported declaration 'default' not used within other modules`)],
}],
});
});
38 changes: 27 additions & 11 deletions utils/parse.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ function keysFromParser(parserPath, parserInstance, parsedResult) {
if (parsedResult && parsedResult.visitorKeys) {
return parsedResult.visitorKeys;
}
if (/.*espree.*/.test(parserPath)) {
if (typeof parserPath === 'string' && /.*espree.*/.test(parserPath)) {
return parserInstance.VisitorKeys;
}
if (/.*babel-eslint.*/.test(parserPath)) {
if (typeof parserPath === 'string' && /.*babel-eslint.*/.test(parserPath)) {
return getBabelEslintVisitorKeys(parserPath);
}
return null;
Expand All @@ -51,13 +51,13 @@ function transformHashbang(text) {
}

exports.default = function parse(path, content, context) {

if (context == null) throw new Error('need context to parse properly');

let parserOptions = context.parserOptions;
const parserPath = getParserPath(path, context);
// ESLint in "flat" mode only sets context.languageOptions.parserOptions
let parserOptions = (context.languageOptions && context.languageOptions.parserOptions) || context.parserOptions;
const parserOrPath = getParser(path, context);

if (!parserPath) throw new Error('parserPath is required!');
if (!parserOrPath) throw new Error('parserPath or languageOptions.parser is required!');

// hack: espree blows up with frozen options
parserOptions = Object.assign({}, parserOptions);
Expand All @@ -84,7 +84,7 @@ exports.default = function parse(path, content, context) {
delete parserOptions.projects;

// require the parser relative to the main module (i.e., ESLint)
const parser = moduleRequire(parserPath);
const parser = typeof parserOrPath === 'string' ? moduleRequire(parserOrPath) : parserOrPath;

// replicate bom strip and hashbang transform of ESLint
// https://github.com/eslint/eslint/blob/b93af98b3c417225a027cabc964c38e779adb945/lib/linter/linter.js#L779
Expand All @@ -95,7 +95,7 @@ exports.default = function parse(path, content, context) {
try {
const parserRaw = parser.parseForESLint(content, parserOptions);
ast = parserRaw.ast;
return makeParseReturn(ast, keysFromParser(parserPath, parser, parserRaw));
return makeParseReturn(ast, keysFromParser(parserOrPath, parser, parserRaw));
} catch (e) {
console.warn();
console.warn('Error while parsing ' + parserOptions.filePath);
Expand All @@ -104,18 +104,34 @@ exports.default = function parse(path, content, context) {
if (!ast || typeof ast !== 'object') {
console.warn(
'`parseForESLint` from parser `' +
parserPath +
(typeof parserOrPath === 'string' ? parserOrPath : '`context.languageOptions.parser`') + // Can only be invalid for custom parser per imports/parser
'` is invalid and will just be ignored'
);
} else {
return makeParseReturn(ast, keysFromParser(parserPath, parser, undefined));
return makeParseReturn(ast, keysFromParser(parserOrPath, parser, undefined));
}
}

const ast = parser.parse(content, parserOptions);
return makeParseReturn(ast, keysFromParser(parserPath, parser, undefined));
return makeParseReturn(ast, keysFromParser(parserOrPath, parser, undefined));
};

function getParser(path, context) {
const parserPath = getParserPath(path, context);
if (parserPath) {
return parserPath;
}
const isFlat = context.languageOptions
&& context.languageOptions.parser
&& typeof context.languageOptions.parser !== 'string'
&& (
typeof context.languageOptions.parser.parse === 'function'
|| typeof context.languageOptions.parser.parseForESLint === 'function'
);

return isFlat ? context.languageOptions.parser : null;
}

function getParserPath(path, context) {
const parsers = context.settings['import/parsers'];
if (parsers != null) {
Expand Down