Skip to content
This repository was archived by the owner on Aug 18, 2021. It is now read-only.
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: babel/babel-eslint
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 94bb5a1d36c5624fb612de2dd704ffa586d38845
Choose a base ref
...
head repository: babel/babel-eslint
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4bd049e06e2c7ab31053020fc662f51bf6c179e3
Choose a head ref

Commits on May 30, 2017

  1. Fix: Convert RegExpLieteral value to RegExp object (fixes #477) (#478)

    soda0289 authored and Kent C. Dodds committed May 30, 2017
    Copy the full SHA
    54ed517 View commit details

Commits on Jun 7, 2017

  1. Update to Babylon 7 (fixes #481) (#482)

    * Update to Babylon 7 (fixes #481)
    
    * Pin dependencies to alpha version
    
    * fix deprecation, add other plugins
    
    * oops
    
    * Update index.js
    
    * Add tests for private class properties with rules no-undef no-unused-vars
    soda0289 authored and hzoo committed Jun 7, 2017
    Copy the full SHA
    c66ec51 View commit details
  2. Use Node 8 and drop Node 5 from travis (#483)

    * Use Node 8 and drop Node 5 from travis
    
    * switch the order [skip ci]
    soda0289 authored and hzoo committed Jun 7, 2017
    Copy the full SHA
    a8003c0 View commit details

Commits on Jun 8, 2017

  1. Copy the full SHA
    1aedb95 View commit details

Commits on Jun 15, 2017

  1. Use babylon estree and ranges (#489)

    danez authored and hzoo committed Jun 15, 2017
    Copy the full SHA
    39b4a6a View commit details

Commits on Jun 16, 2017

  1. 8.0.0-alpha.12

    hzoo committed Jun 16, 2017
    Copy the full SHA
    945f00a View commit details

Commits on Jun 17, 2017

  1. Test for babylon regression

    danez committed Jun 17, 2017
    Copy the full SHA
    d0c3223 View commit details
  2. Add Prettier (#491)

    existentialism authored Jun 17, 2017
    Copy the full SHA
    37f9242 View commit details

Commits on Jun 18, 2017

  1. Update babylon

    danez committed Jun 18, 2017
    Copy the full SHA
    5736be6 View commit details
  2. Merge pull request #493 from danez/regression-test

    Test for babylon regression
    hzoo authored Jun 18, 2017
    Copy the full SHA
    f757e22 View commit details
  3. 8.0.0-alpha.13

    hzoo committed Jun 18, 2017
    Copy the full SHA
    8e3e088 View commit details

Commits on Jun 20, 2017

  1. Copy the full SHA
    e052d5a View commit details

Commits on Jun 22, 2017

  1. chore(package): update husky to version 0.14.0 (#498)

    greenkeeper[bot] authored and Kent C. Dodds committed Jun 22, 2017
    Copy the full SHA
    3c6b2de View commit details

Commits on Jun 25, 2017

  1. Update eslint to the latest version 🚀 (#500)

    * chore(package): update eslint to version 4.1.0
    
    * escope -> eslint-scope
    
    * Fix linting
    greenkeeper[bot] authored and danez committed Jun 25, 2017
    Copy the full SHA
    c2626f9 View commit details

Commits on Jul 10, 2017

  1. Readme update usage section (#501) [skip ci]

    * Updates README: Consolidates versioning table
    
    Basically a revert of 52b4a13. It is easier to read a single table instead of two locations in the README for the version compatabilities between ESLint and babel-eslint
    
    * Updates README: Add yarn command for installation
    
    * [skip ci]
    ecbrodie authored and hzoo committed Jul 10, 2017
    Copy the full SHA
    c31b577 View commit details

Commits on Jul 13, 2017

  1. update (#504)

    hzoo authored Jul 13, 2017
    Copy the full SHA
    1e41162 View commit details
  2. 8.0.0-alpha.15

    hzoo committed Jul 13, 2017
    Copy the full SHA
    57c133e View commit details

Commits on Jul 26, 2017

  1. alpha.17

    hzoo committed Jul 26, 2017
    Copy the full SHA
    1468905 View commit details
  2. 8.0.0-alpha.17

    hzoo committed Jul 26, 2017
    Copy the full SHA
    25bd208 View commit details

Commits on Aug 2, 2017

  1. Remove already fixed workaround (#508)

    danez authored and hzoo committed Aug 2, 2017
    Copy the full SHA
    42d0c5b View commit details

Commits on Sep 12, 2017

  1. update to beta.0

    hzoo committed Sep 12, 2017
    Copy the full SHA
    49493e4 View commit details
  2. 8.0.0

    hzoo committed Sep 12, 2017
    Copy the full SHA
    905887c View commit details

Commits on Sep 26, 2017

  1. Adding optionalCatchBinding to plugins. (#521)

    kesne authored and hzoo committed Sep 26, 2017
    Copy the full SHA
    5742b71 View commit details

Commits on Oct 11, 2017

  1. Copy the full SHA
    51100c9 View commit details

Commits on Oct 31, 2017

  1. Update README.md support (#531) [skip ci]

    #linting channel is now archived in babel slack.
    clemmy authored and hzoo committed Oct 31, 2017
    Copy the full SHA
    c1a7882 View commit details

Commits on Nov 6, 2017

  1. 8.0.1

    hzoo committed Nov 6, 2017
    Copy the full SHA
    54ab4ac View commit details
  2. Copy the full SHA
    d3b8519 View commit details
  3. Copy the full SHA
    295091d View commit details
  4. Always use unpad (#535)

    hzoo authored Nov 6, 2017
    Copy the full SHA
    fa56d21 View commit details
  5. require correct deps

    hzoo committed Nov 6, 2017
    Copy the full SHA
    2004b91 View commit details
  6. 8.0.2

    hzoo committed Nov 6, 2017
    Copy the full SHA
    a0fbd50 View commit details

Commits on Dec 1, 2017

  1. 2
    Copy the full SHA
    0609da8 View commit details
  2. Fix mocha command path.

    loganfsmyth committed Dec 1, 2017
    Copy the full SHA
    cf5ab03 View commit details
  3. 8.0.3

    loganfsmyth committed Dec 1, 2017
    Copy the full SHA
    1f220c2 View commit details

Commits on Dec 24, 2017

  1. Copy the full SHA
    dbc6546 View commit details
  2. Copy the full SHA
    bba9d00 View commit details
  3. 8.1.0

    not-an-aardvark committed Dec 24, 2017
    Copy the full SHA
    893a5e3 View commit details

Commits on Dec 25, 2017

  1. Fix: Prevent parseForESLint() behavior from changing after parse() is…

    … called (fixes #558)(#559)
    
    * Prevent parseForESLint() behavior from changing after parse() is called
    
    (fixes #558, fixes eslint/eslint#9767)
    
    * Avoid using the enhanced referencer after monkeypatching
    
    * Chore: add test for #558
    
    * Pass correct scope analyzer options
    
    * fix escope patch and improve tests
    
    * remove process.exit(1)
    not-an-aardvark authored and mysticatea committed Dec 25, 2017
    Copy the full SHA
    e4bed5a View commit details
  2. 8.1.1

    mysticatea committed Dec 25, 2017
    Copy the full SHA
    d84b236 View commit details

Commits on Dec 26, 2017

  1. Copy the full SHA
    bf9092a View commit details
  2. Fix: add Literal type to visitorKeys (#562)

    * Fix: add Literal type to visitorKeys
    * Fix: use ./visitor-keys
    mysticatea authored Dec 26, 2017
    Copy the full SHA
    5aaf0e1 View commit details
  3. 8.1.2

    mysticatea committed Dec 26, 2017
    Copy the full SHA
    36bf8b4 View commit details

Commits on Jan 8, 2018

  1. update babel packages (#565)

    * update babel packages 
    
    There is some critical bug fixes in version babylon#7.0.0-beta.33 regard `async` - `await` syntax which is needed pretty immediately :)
    
    * remove test 42 (test for import type *)
    
    `import type *` is invalid, since the namespace can't be a type
    jony89 authored and hzoo committed Jan 8, 2018
    Copy the full SHA
    1dedd1b View commit details
  2. Copy the full SHA
    e201fb4 View commit details
  3. Copy the full SHA
    eba5920 View commit details
  4. 8.2.0

    Kai Cataldo committed Jan 8, 2018
    Copy the full SHA
    ef27670 View commit details

Commits on Jan 9, 2018

  1. fix export change (#571)

    hzoo authored Jan 9, 2018
    Copy the full SHA
    d96ce55 View commit details
  2. 8.2.1

    hzoo committed Jan 9, 2018
    Copy the full SHA
    bf27f60 View commit details

Commits on Jan 17, 2018

  1. Copy the full SHA
    236adb8 View commit details

Commits on Feb 16, 2018

  1. Bump deps (#591)

    existentialism authored Feb 16, 2018
    Copy the full SHA
    29b12ab View commit details
6 changes: 5 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
module.exports = {
root: true,
extends: "babel",
"plugins": [
"prettier"
],
rules: {
"no-var": 0,
"max-len": 0
"max-len": 0,
"prettier/prettier": "error",
},
env: {
node: true,
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.json
3 changes: 3 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"trailingComma": "es5"
}
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
sudo: false
language: node_js
node_js:
- "4"
- "5"
- "10"
- "8"
- "6"

matrix:
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.PHONY: publish-patch

publish-patch:
mocha
./node_modules/.bin/mocha
npm version patch
npm publish
git push --follow-tags
23 changes: 13 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ You only need to use babel-eslint if you are using types (Flow) or experimental

> If there is an issue, first check if it can be reproduced with the regular parser or with the latest versions of `eslint` and `babel-eslint`!
For questions and support please visit the [`#linting`](https://babeljs.slack.com/messages/linting/) babel slack channel (sign up [here](https://babel-slack.herokuapp.com))!
For questions and support please visit the [`#discussion`](https://babeljs.slack.com/messages/discussion/) babel slack channel (sign up [here](https://github.com/babel/notes/issues/38)) or eslint [gitter](https://gitter.im/eslint/eslint)!

> Note that the `ecmaFeatures` config property may still be required for ESLint to work properly with features not in ECMAScript 5 by default. Examples are `globalReturn` and `modules`).
@@ -43,20 +43,23 @@ It just needs to export a `parse` method that takes in a string of code and outp

## Usage

> ESLint 1.x | Use <= 5.x
> ESLint 2.x | Use >= 6.x
### Supported ESLint versions

ESLint | babel-eslint
------------ | -------------
4.x | >= 6.x
3.x | >= 6.x
2.x | >= 6.x
1.x | >= 5.x

### Install

Ensure that you have substituted the correct version lock for `eslint` and `babel-eslint` into this command:

```sh
$ npm install eslint@3.x babel-eslint@6 --save-dev
$ npm install eslint@4.x babel-eslint@8 --save-dev
# or
$ yarn add eslint@4.x babel-eslint@8 -D
```

### Setup
@@ -76,9 +79,9 @@ Check out the [ESLint docs](http://eslint.org/docs/rules/) for all possible rule

### Configuration

`sourceType` can be set to `'module'`(default) or `'script'` if your code isn't using ECMAScript modules.
`allowImportExportEverywhere` can be set to true to allow import and export declarations to appear anywhere a statement is allowed if your build environment supports that. By default, import and export declarations can only appear at a program's top level.
`codeFrame` can be set to false to disable the code frame in the reporter. This is useful since some eslint formatters don't play well with it.
- `sourceType` can be set to `'module'`(default) or `'script'` if your code isn't using ECMAScript modules.
- `allowImportExportEverywhere` (default `false`) can be set to `true` to allow import and export declarations to appear anywhere a statement is allowed if your build environment supports that. Otherwise import and export declarations can only appear at a program's top level.
- `codeFrame` (default `true`) can be set to `false` to disable the code frame in the reporter. This is useful since some eslint formatters don't play well with it.

**.eslintrc**

@@ -88,7 +91,7 @@ Check out the [ESLint docs](http://eslint.org/docs/rules/) for all possible rule
"parserOptions": {
"sourceType": "module",
"allowImportExportEverywhere": false,
"codeFrame": false
"codeFrame": true
}
}
```
95 changes: 0 additions & 95 deletions babylon-to-espree/convertTemplateType.js

This file was deleted.

237 changes: 0 additions & 237 deletions babylon-to-espree/toAST.js

This file was deleted.

19 changes: 0 additions & 19 deletions babylon-to-espree/toTokens.js

This file was deleted.

431 changes: 0 additions & 431 deletions index.js

This file was deleted.

346 changes: 346 additions & 0 deletions lib/analyze-scope.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,346 @@
"use strict";

const t = require("@babel/types");
const requireFromESLint = require("./require-from-eslint");

const escope = requireFromESLint("eslint-scope");
const Definition = requireFromESLint("eslint-scope/lib/definition").Definition;
const OriginalPatternVisitor = requireFromESLint(
"eslint-scope/lib/pattern-visitor"
);
const OriginalReferencer = requireFromESLint("eslint-scope/lib/referencer");
const fallback = require("eslint-visitor-keys").getKeys;
const childVisitorKeys = require("./visitor-keys");

const flowFlippedAliasKeys = t.FLIPPED_ALIAS_KEYS.Flow.concat([
"ArrayPattern",
"ClassDeclaration",
"ClassExpression",
"FunctionDeclaration",
"FunctionExpression",
"Identifier",
"ObjectPattern",
"RestElement",
]);
const visitorKeysMap = Object.keys(t.VISITOR_KEYS).reduce(function(acc, key) {
const value = t.VISITOR_KEYS[key];
if (flowFlippedAliasKeys.indexOf(value) === -1) {
acc[key] = value;
}
return acc;
}, {});

const propertyTypes = {
// loops
callProperties: { type: "loop", values: ["value"] },
indexers: { type: "loop", values: ["key", "value"] },
properties: { type: "loop", values: ["argument", "value"] },
types: { type: "loop" },
params: { type: "loop" },
// single property
argument: { type: "single" },
elementType: { type: "single" },
qualification: { type: "single" },
rest: { type: "single" },
returnType: { type: "single" },
// others
typeAnnotation: { type: "typeAnnotation" },
typeParameters: { type: "typeParameters" },
id: { type: "id" },
};

class PatternVisitor extends OriginalPatternVisitor {
ArrayPattern(node) {
node.elements.forEach(this.visit, this);
}

ObjectPattern(node) {
node.properties.forEach(this.visit, this);
}
}

class Referencer extends OriginalReferencer {
// inherits.
visitPattern(node, options, callback) {
if (!node) {
return;
}

// Visit type annotations.
this._checkIdentifierOrVisit(node.typeAnnotation);
if (t.isAssignmentPattern(node)) {
this._checkIdentifierOrVisit(node.left.typeAnnotation);
}

// Overwrite `super.visitPattern(node, options, callback)` in order to not visit `ArrayPattern#typeAnnotation` and `ObjectPattern#typeAnnotation`.
if (typeof options === "function") {
callback = options;
options = { processRightHandNodes: false };
}

const visitor = new PatternVisitor(this.options, node, callback);
visitor.visit(node);

// Process the right hand nodes recursively.
if (options.processRightHandNodes) {
visitor.rightHandNodes.forEach(this.visit, this);
}
}

// inherits.
visitClass(node) {
// Decorators.
this._visitArray(node.decorators);

// Flow type parameters.
const typeParamScope = this._nestTypeParamScope(node);

// Flow super types.
this._visitTypeAnnotation(node.implements);
this._visitTypeAnnotation(
node.superTypeParameters && node.superTypeParameters.params
);

// Basic.
super.visitClass(node);

// Close the type parameter scope.
if (typeParamScope) {
this.close(node);
}
}

// inherits.
visitFunction(node) {
const typeParamScope = this._nestTypeParamScope(node);

// Flow return types.
this._checkIdentifierOrVisit(node.returnType);

// Basic.
super.visitFunction(node);

// Close the type parameter scope.
if (typeParamScope) {
this.close(node);
}
}

// inherits.
visitProperty(node) {
if (node.value && node.value.type === "TypeCastExpression") {
this._visitTypeAnnotation(node.value);
}
this._visitArray(node.decorators);
super.visitProperty(node);
}

InterfaceDeclaration(node) {
this._createScopeVariable(node, node.id);

const typeParamScope = this._nestTypeParamScope(node);

// TODO: Handle mixins
this._visitArray(node.extends);
this.visit(node.body);

if (typeParamScope) {
this.close(node);
}
}

EnumDeclaration(node) {
this._createScopeVariable(node, node.id);
}

TypeAlias(node) {
this._createScopeVariable(node, node.id);

const typeParamScope = this._nestTypeParamScope(node);

this.visit(node.right);

if (typeParamScope) {
this.close(node);
}
}

ClassProperty(node) {
this._visitClassProperty(node);
}

ClassPrivateProperty(node) {
this._visitClassProperty(node);
}

DeclareModule(node) {
this._visitDeclareX(node);
}

DeclareFunction(node) {
this._visitDeclareX(node);
}

DeclareVariable(node) {
this._visitDeclareX(node);
}

DeclareClass(node) {
this._visitDeclareX(node);
}

// visit OptionalMemberExpression as a MemberExpression.
OptionalMemberExpression(node) {
super.MemberExpression(node);
}

_visitClassProperty(node) {
this._visitTypeAnnotation(node.typeAnnotation);
this.visitProperty(node);
}

_visitDeclareX(node) {
if (node.id) {
this._createScopeVariable(node, node.id);
}

const typeParamScope = this._nestTypeParamScope(node);
if (typeParamScope) {
this.close(node);
}
}

_createScopeVariable(node, name) {
this.currentScope().variableScope.__define(
name,
new Definition("Variable", name, node, null, null, null)
);
}

_nestTypeParamScope(node) {
if (!node.typeParameters) {
return null;
}

const parentScope = this.scopeManager.__currentScope;
const scope = new escope.Scope(
this.scopeManager,
"type-parameters",
parentScope,
node,
false
);

this.scopeManager.__nestScope(scope);
for (let j = 0; j < node.typeParameters.params.length; j++) {
const name = node.typeParameters.params[j];
scope.__define(name, new Definition("TypeParameter", name, name));
if (name.typeAnnotation) {
this._checkIdentifierOrVisit(name);
}
}
scope.__define = function() {
return parentScope.__define.apply(parentScope, arguments);
};

return scope;
}

_visitTypeAnnotation(node) {
if (!node) {
return;
}
if (Array.isArray(node)) {
node.forEach(this._visitTypeAnnotation, this);
return;
}

// get property to check (params, id, etc...)
const visitorValues = visitorKeysMap[node.type];
if (!visitorValues) {
return;
}

// can have multiple properties
for (let i = 0; i < visitorValues.length; i++) {
const visitorValue = visitorValues[i];
const propertyType = propertyTypes[visitorValue];
const nodeProperty = node[visitorValue];
// check if property or type is defined
if (propertyType == null || nodeProperty == null) {
continue;
}
if (propertyType.type === "loop") {
for (let j = 0; j < nodeProperty.length; j++) {
if (Array.isArray(propertyType.values)) {
for (let k = 0; k < propertyType.values.length; k++) {
const loopPropertyNode = nodeProperty[j][propertyType.values[k]];
if (loopPropertyNode) {
this._checkIdentifierOrVisit(loopPropertyNode);
}
}
} else {
this._checkIdentifierOrVisit(nodeProperty[j]);
}
}
} else if (propertyType.type === "single") {
this._checkIdentifierOrVisit(nodeProperty);
} else if (propertyType.type === "typeAnnotation") {
this._visitTypeAnnotation(node.typeAnnotation);
} else if (propertyType.type === "typeParameters") {
for (let l = 0; l < node.typeParameters.params.length; l++) {
this._checkIdentifierOrVisit(node.typeParameters.params[l]);
}
} else if (propertyType.type === "id") {
if (node.id.type === "Identifier") {
this._checkIdentifierOrVisit(node.id);
} else {
this._visitTypeAnnotation(node.id);
}
}
}
}

_checkIdentifierOrVisit(node) {
if (node && node.typeAnnotation) {
this._visitTypeAnnotation(node.typeAnnotation);
} else if (node && node.type === "Identifier") {
this.visit(node);
} else {
this._visitTypeAnnotation(node);
}
}

_visitArray(nodeList) {
if (nodeList) {
for (const node of nodeList) {
this.visit(node);
}
}
}
}

module.exports = function(ast, parserOptions) {
const options = {
ignoreEval: true,
optimistic: false,
directive: false,
nodejsScope:
ast.sourceType === "script" &&
(parserOptions.ecmaFeatures &&
parserOptions.ecmaFeatures.globalReturn) === true,
impliedStrict: false,
sourceType: ast.sourceType,
ecmaVersion: parserOptions.ecmaVersion || 2018,
fallback,
};

options.childVisitorKeys = childVisitorKeys;

const scopeManager = new escope.ScopeManager(options);
const referencer = new Referencer(options, scopeManager);

referencer.visit(ast);

return scopeManager;
};
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use strict";

// comment fixes
module.exports = function (ast, comments, tokens) {
module.exports = function(ast, comments, tokens) {
if (comments.length) {
var firstComment = comments[0];
var lastComment = comments[comments.length - 1];
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";

module.exports = function (comments) {
module.exports = function(comments) {
for (var i = 0; i < comments.length; i++) {
var comment = comments[i];
if (comment.type === "CommentBlock") {
92 changes: 92 additions & 0 deletions lib/babylon-to-espree/convertTemplateType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"use strict";

module.exports = function(tokens, tt) {
let curlyBrace = null;
let templateTokens = [];
const result = [];

function addTemplateType() {
const start = templateTokens[0];
const end = templateTokens[templateTokens.length - 1];

const value = templateTokens.reduce((result, token) => {
if (token.value) {
result += token.value;
} else if (token.type !== tt.template) {
result += token.type.label;
}

return result;
}, "");

result.push({
type: "Template",
value: value,
start: start.start,
end: end.end,
loc: {
start: start.loc.start,
end: end.loc.end,
},
});

templateTokens = [];
}

tokens.forEach(token => {
switch (token.type) {
case tt.backQuote:
if (curlyBrace) {
result.push(curlyBrace);
curlyBrace = null;
}

templateTokens.push(token);

if (templateTokens.length > 1) {
addTemplateType();
}

break;

case tt.dollarBraceL:
templateTokens.push(token);
addTemplateType();
break;

case tt.braceR:
if (curlyBrace) {
result.push(curlyBrace);
}

curlyBrace = token;
break;

case tt.template:
if (curlyBrace) {
templateTokens.push(curlyBrace);
curlyBrace = null;
}

templateTokens.push(token);
break;

case tt.eof:
if (curlyBrace) {
result.push(curlyBrace);
}

break;

default:
if (curlyBrace) {
result.push(curlyBrace);
curlyBrace = null;
}

result.push(token);
}
});

return result;
};
14 changes: 4 additions & 10 deletions babylon-to-espree/index.js → lib/babylon-to-espree/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
"use strict";

var attachComments = require("./attachComments");
var attachComments = require("./attachComments");
var convertComments = require("./convertComments");
var toTokens = require("./toTokens");
var toAST = require("./toAST");

module.exports = function (ast, traverse, tt, code) {
// remove EOF token, eslint doesn't use this for anything and it interferes
// with some rules see https://github.com/babel/babel-eslint/issues/2
// todo: find a more elegant way to do this
ast.tokens.pop();
var toTokens = require("./toTokens");
var toAST = require("./toAST");

module.exports = function(ast, traverse, tt, code) {
// convert tokens
ast.tokens = toTokens(ast.tokens, tt, code);

@@ -30,7 +25,6 @@ module.exports = function (ast, traverse, tt, code) {
ast.directives = ast.program.directives;
ast.body = ast.program.body;
delete ast.program;
delete ast._paths;

attachComments(ast, ast.comments, ast.tokens);
};
118 changes: 118 additions & 0 deletions lib/babylon-to-espree/toAST.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"use strict";

var t = require("@babel/types");
var convertComments = require("./convertComments");

module.exports = function(ast, traverse, code) {
var state = { source: code };

// Monkey patch visitor keys in order to be able to traverse the estree nodes
t.VISITOR_KEYS.Property = t.VISITOR_KEYS.ObjectProperty;
t.VISITOR_KEYS.MethodDefinition = [
"key",
"value",
"decorators",
"returnType",
"typeParameters",
];

traverse(ast, astTransformVisitor, null, state);

delete t.VISITOR_KEYS.Property;
delete t.VISITOR_KEYS.MethodDefinition;
};

var astTransformVisitor = {
noScope: true,
enter(path) {
var node = path.node;

// private var to track original node type
node._babelType = node.type;

if (node.innerComments) {
node.trailingComments = node.innerComments;
delete node.innerComments;
}

if (node.trailingComments) {
convertComments(node.trailingComments);
}

if (node.leadingComments) {
convertComments(node.leadingComments);
}
},
exit(path) {
var node = path.node;

if (path.isJSXText()) {
node.type = "Literal";
}

if (
path.isRestElement() &&
path.parent &&
path.parent.type === "ObjectPattern"
) {
node.type = "ExperimentalRestProperty";
}

if (
path.isSpreadElement() &&
path.parent &&
path.parent.type === "ObjectExpression"
) {
node.type = "ExperimentalSpreadProperty";
}

if (path.isTypeParameter()) {
node.type = "Identifier";
node.typeAnnotation = node.bound;
delete node.bound;
}

// flow: prevent "no-undef"
// for "Component" in: "let x: React.Component"
if (path.isQualifiedTypeIdentifier()) {
delete node.id;
}
// for "b" in: "var a: { b: Foo }"
if (path.isObjectTypeProperty()) {
delete node.key;
}
// for "indexer" in: "var a: {[indexer: string]: number}"
if (path.isObjectTypeIndexer()) {
delete node.id;
}
// for "param" in: "var a: { func(param: Foo): Bar };"
if (path.isFunctionTypeParam()) {
delete node.name;
}

// modules

if (path.isImportDeclaration()) {
delete node.isType;
}

// template string range fixes
if (path.isTemplateLiteral()) {
for (var j = 0; j < node.quasis.length; j++) {
var q = node.quasis[j];
q.range[0] -= 1;
if (q.tail) {
q.range[1] += 1;
} else {
q.range[1] += 2;
}
q.loc.start.column -= 1;
if (q.tail) {
q.loc.end.column += 1;
} else {
q.loc.end.column += 2;
}
}
}
},
};
62 changes: 42 additions & 20 deletions babylon-to-espree/toToken.js → lib/babylon-to-espree/toToken.js
Original file line number Diff line number Diff line change
@@ -1,29 +1,51 @@
"use strict";

module.exports = function (token, tt, source) {
module.exports = function(token, tt, source) {
var type = token.type;
token.range = [token.start, token.end];

if (type === tt.name) {
token.type = "Identifier";
} else if (type === tt.semi || type === tt.comma ||
type === tt.parenL || type === tt.parenR ||
type === tt.braceL || type === tt.braceR ||
type === tt.slash || type === tt.dot ||
type === tt.bracketL || type === tt.bracketR ||
type === tt.ellipsis || type === tt.arrow ||
type === tt.star || type === tt.incDec ||
type === tt.colon || type === tt.question ||
type === tt.template || type === tt.backQuote ||
type === tt.dollarBraceL || type === tt.at ||
type === tt.logicalOR || type === tt.logicalAND ||
type === tt.bitwiseOR || type === tt.bitwiseXOR ||
type === tt.bitwiseAND || type === tt.equality ||
type === tt.relational || type === tt.bitShift ||
type === tt.plusMin || type === tt.modulo ||
type === tt.exponent || type === tt.prefix ||
type === tt.doubleColon ||
type.isAssign) {
} else if (
type === tt.semi ||
type === tt.comma ||
type === tt.parenL ||
type === tt.parenR ||
type === tt.braceL ||
type === tt.braceR ||
type === tt.slash ||
type === tt.dot ||
type === tt.bracketL ||
type === tt.bracketR ||
type === tt.ellipsis ||
type === tt.arrow ||
type === tt.pipeline ||
type === tt.star ||
type === tt.incDec ||
type === tt.colon ||
type === tt.question ||
type === tt.questionDot ||
type === tt.template ||
type === tt.backQuote ||
type === tt.dollarBraceL ||
type === tt.at ||
type === tt.logicalOR ||
type === tt.logicalAND ||
type === tt.nullishCoalescing ||
type === tt.bitwiseOR ||
type === tt.bitwiseXOR ||
type === tt.bitwiseAND ||
type === tt.equality ||
type === tt.relational ||
type === tt.bitShift ||
type === tt.plusMin ||
type === tt.modulo ||
type === tt.exponent ||
type === tt.bang ||
type === tt.tilde ||
type === tt.doubleColon ||
type.isAssign
) {
token.type = "Punctuator";
if (!token.value) token.value = type.label;
} else if (type === tt.jsxTagStart) {
@@ -53,7 +75,7 @@ module.exports = function (token, tt, source) {
var value = token.value;
token.regex = {
pattern: value.pattern,
flags: value.flags
flags: value.flags,
};
token.value = `/${value.pattern}/${value.flags}`;
}
10 changes: 10 additions & 0 deletions lib/babylon-to-espree/toTokens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use strict";

var convertTemplateType = require("./convertTemplateType");
var toToken = require("./toToken");

module.exports = function(tokens, tt, code) {
return convertTemplateType(tokens, tt)
.filter(t => t.type !== "CommentLine" && t.type !== "CommentBlock")
.map(t => toToken(t, tt, code));
};
19 changes: 19 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use strict";

exports.parse = function(code, options) {
return exports.parseForESLint(code, options).ast;
};

exports.parseForESLint = function(code, options) {
options = options || {};
options.ecmaVersion = options.ecmaVersion || 2018;
options.sourceType = options.sourceType || "module";
options.allowImportExportEverywhere =
options.allowImportExportEverywhere || false;

return require("./parse-with-scope")(code, options);
};

exports.parseNoPatch = function(code, options) {
return require("./parse")(code, options);
};
12 changes: 12 additions & 0 deletions lib/parse-with-scope.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use strict";

const visitorKeys = require("./visitor-keys");
const analyzeScope = require("./analyze-scope");
const parse = require("./parse");

module.exports = function(code, options) {
const ast = parse(code, options);
const scopeManager = analyzeScope(ast, options);

return { ast, scopeManager, visitorKeys };
};
93 changes: 93 additions & 0 deletions lib/parse.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"use strict";

var babylonToEspree = require("./babylon-to-espree");
var parse = require("@babel/parser").parse;
var tt = require("@babel/parser").tokTypes;
var traverse = require("@babel/traverse").default;
var codeFrameColumns = require("@babel/code-frame").codeFrameColumns;

module.exports = function(code, options) {
const legacyDecorators =
options.ecmaFeatures && options.ecmaFeatures.legacyDecorators;

var opts = {
codeFrame: options.hasOwnProperty("codeFrame") ? options.codeFrame : true,
sourceType: options.sourceType,
allowImportExportEverywhere: options.allowImportExportEverywhere, // consistent with espree
allowReturnOutsideFunction: true,
allowSuperOutsideMethod: true,
ranges: true,
tokens: true,
plugins: [
["flow", { all: true, enums: true }],
"jsx",
"estree",
"asyncFunctions",
"asyncGenerators",
"classConstructorCall",
"classProperties",
legacyDecorators
? "decorators-legacy"
: ["decorators", { decoratorsBeforeExport: false }],
"doExpressions",
"exponentiationOperator",
"exportDefaultFrom",
"exportNamespaceFrom",
"functionBind",
"functionSent",
"objectRestSpread",
"trailingFunctionCommas",
"dynamicImport",
"numericSeparator",
"optionalChaining",
"importMeta",
"classPrivateProperties",
"bigInt",
"optionalCatchBinding",
"throwExpressions",
["pipelineOperator", { proposal: "minimal" }],
"nullishCoalescingOperator",
"logicalAssignment",
],
};

var ast;
try {
ast = parse(code, opts);
} catch (err) {
if (err instanceof SyntaxError) {
err.lineNumber = err.loc.line;
err.column = err.loc.column;

if (opts.codeFrame) {
err.lineNumber = err.loc.line;
err.column = err.loc.column + 1;

// remove trailing "(LINE:COLUMN)" acorn message and add in esprima syntax error message start
err.message =
"Line " +
err.lineNumber +
": " +
err.message.replace(/ \((\d+):(\d+)\)$/, "") +
// add codeframe
"\n\n" +
codeFrameColumns(
code,
{
start: {
line: err.lineNumber,
column: err.column,
},
},
{ highlightCode: true }
);
}
}

throw err;
}

babylonToEspree(ast, traverse, tt, code);

return ast;
};
9 changes: 9 additions & 0 deletions lib/require-from-eslint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use strict";

const resolve = require("resolve");
const eslintBase = require.resolve("eslint");

module.exports = function requireFromESLint(id) {
const path = resolve.sync(id, { basedir: eslintBase });
return require(path);
};
15 changes: 15 additions & 0 deletions lib/visitor-keys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"use strict";

const BABEL_VISITOR_KEYS = require("@babel/types").VISITOR_KEYS;
const ESLINT_VISITOR_KEYS = require("eslint-visitor-keys").KEYS;

module.exports = Object.assign(
{
Literal: ESLINT_VISITOR_KEYS.Literal,
MethodDefinition: ["decorators"].concat(
ESLINT_VISITOR_KEYS.MethodDefinition
),
Property: ["decorators"].concat(ESLINT_VISITOR_KEYS.Property),
},
BABEL_VISITOR_KEYS
);
50 changes: 33 additions & 17 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,46 +1,62 @@
{
"name": "babel-eslint",
"version": "7.2.3",
"version": "10.1.0",
"description": "Custom parser for ESLint",
"main": "index.js",
"main": "lib/index.js",
"files": [
"index.js",
"babylon-to-espree"
"lib"
],
"repository": {
"type": "git",
"url": "https://github.com/babel/babel-eslint.git"
},
"dependencies": {
"babel-code-frame": "^6.22.0",
"babel-traverse": "^6.23.1",
"babel-types": "^6.23.0",
"babylon": "^6.17.0"
"@babel/code-frame": "^7.0.0",
"@babel/parser": "^7.7.0",
"@babel/traverse": "^7.7.0",
"@babel/types": "^7.7.0",
"eslint-visitor-keys": "^1.0.0",
"resolve": "^1.12.0"
},
"scripts": {
"test": "npm run lint && npm run test-only",
"test-only": "mocha",
"lint": "eslint index.js babylon-to-espree test",
"fix": "eslint index.js babylon-to-espree test --fix",
"test-only": "mocha && mocha --require test/fixtures/preprocess-to-patch.js",
"lint": "eslint lib test",
"fix": "eslint lib test --fix",
"precommit": "lint-staged",
"preversion": "npm test",
"changelog": "git log `git describe --tags --abbrev=0`..HEAD --pretty=format:' * %s (%an)' | grep -v 'Merge pull request'"
},
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"license": "MIT",
"engines": {
"node": ">=4"
"node": ">=6"
},
"bugs": {
"url": "https://github.com/babel/babel-eslint/issues"
},
"homepage": "https://github.com/babel/babel-eslint",
"peerDependencies": {
"eslint": ">= 4.12.1"
},
"devDependencies": {
"babel-eslint": "^7.0.0",
"babel-eslint": "^8.2.6",
"dedent": "^0.7.0",
"eslint": "^3.18.0",
"eslint-config-babel": "^6.0.0",
"eslint": "^5.6.0",
"eslint-config-babel": "^7.0.1",
"eslint-plugin-flowtype": "^2.30.3",
"espree": "^3.4.0",
"mocha": "^3.0.0"
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-prettier": "^2.1.2",
"espree": "^3.5.2",
"husky": "^1.0.0-rc.13",
"lint-staged": "^7.2.2",
"mocha": "^5.0.1",
"prettier": "^1.4.4"
},
"lint-staged": {
"*.js": [
"eslint --format=codeframe --fix",
"git add"
]
}
}
489 changes: 272 additions & 217 deletions test/babel-eslint.js

Large diffs are not rendered by default.

41 changes: 41 additions & 0 deletions test/fixtures/assert-implements-ast.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Checks if the source ast implements the target ast. Ignores extra keys on source ast
module.exports = function assertImplementsAST(target, source, path) {
if (!path) {
path = [];
}

function error(text) {
var err = new Error(`At ${path.join(".")}: ${text}:`);
err.depth = path.length + 1;
throw err;
}

var typeA = target === null ? "null" : typeof target;
var typeB = source === null ? "null" : typeof source;
if (typeA !== typeB) {
error(
`have different types (${typeA} !== ${typeB}) (${target} !== ${source})`
);
} else if (
typeA === "object" &&
["RegExp"].indexOf(target.constructor.name) !== -1 &&
target.constructor.name !== source.constructor.name
) {
error(
`object have different constructors (${target.constructor
.name} !== ${source.constructor.name}`
);
} else if (typeA === "object") {
var keysTarget = Object.keys(target);
for (var i in keysTarget) {
var key = keysTarget[i];
path.push(key);
assertImplementsAST(target[key], source[key], path);
path.pop();
}
} else if (target !== source) {
error(
`are different (${JSON.stringify(target)} !== ${JSON.stringify(source)})`
);
}
};
11 changes: 11 additions & 0 deletions test/fixtures/eslint-plugin-import/.eslintrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
root: true

# babel-eslint
parser: ../../../lib/index.js

# use eslint-plugin-import
plugins:
- import
rules:
import/no-named-as-default: error
no-unused-vars: error
1 change: 1 addition & 0 deletions test/fixtures/eslint-plugin-import/a.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default function foo() { }
1 change: 1 addition & 0 deletions test/fixtures/eslint-plugin-import/b.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import foo from './a.js';
4 changes: 4 additions & 0 deletions test/fixtures/eslint-plugin-import/c.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// @flow
type Foo = {};

const FlowTypeButton = ({ }: Foo) => { };
5 changes: 5 additions & 0 deletions test/fixtures/preprocess-to-patch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"use strict"
const babelEslint = require("../..")

// Apply monkeypatch to eslint-scope.
babelEslint.parse("var x = 0;")
320 changes: 176 additions & 144 deletions test/integration.js

Large diffs are not rendered by default.

1,323 changes: 730 additions & 593 deletions test/non-regression.js

Large diffs are not rendered by default.

45 changes: 45 additions & 0 deletions test/z_parser-for-eslint-after-patched.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"use strict";

const eslint = require("eslint");
const assert = require("assert");
const babelEslint = require("..");
const espree = require("espree");
var assertImplementsAST = require("./fixtures/assert-implements-ast");

describe("https://github.com/babel/babel-eslint/issues/558", () => {
it("don't crash with eslint-plugin-import", () => {
const engine = new eslint.CLIEngine({ ignore: false });
engine.executeOnFiles([
"test/fixtures/eslint-plugin-import/a.js",
"test/fixtures/eslint-plugin-import/b.js",
"test/fixtures/eslint-plugin-import/c.js",
]);
});

/*
* This test ensures that the enhanced referencer does not get used if eslint-scope has already been
* monkeypatched, because this causes some correctness issues. For example, if the enhanced referencer
* is used after the original referencer is monkeypatched, type annotation references are counted twice.
*/
it("does not visit type annotations multiple times after monkeypatching and calling parseForESLint()", () => {
assertImplementsAST(
espree.parse("foo", { sourceType: "module" }),
babelEslint.parse("foo", {})
);
const parseResult = babelEslint.parseForESLint(
"type Foo = {}; function x(): Foo {}",
{
eslintVisitorKeys: true,
eslintScopeManager: true,
}
);
assert(parseResult.visitorKeys);
assert(parseResult.scopeManager);

const fooVariable = parseResult.scopeManager.getDeclaredVariables(
parseResult.ast.body[0]
)[0];

assert.strictEqual(fooVariable.references.length, 1);
});
});
2,319 changes: 1,814 additions & 505 deletions yarn.lock

Large diffs are not rendered by default.