Merge branch 'master' into feat-optional-chaining
This commit is contained in:
commit
d3bc8fcbdf
@ -11,3 +11,4 @@
|
|||||||
strip_root=true
|
strip_root=true
|
||||||
suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe
|
suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe
|
||||||
suppress_comment= \\(.\\|\n\\)*\\$FlowIssue
|
suppress_comment= \\(.\\|\n\\)*\\$FlowIssue
|
||||||
|
suppress_comment= \\(.\\|\n\\)*\\$FlowIgnore
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ build
|
|||||||
coverage
|
coverage
|
||||||
lib
|
lib
|
||||||
node_modules
|
node_modules
|
||||||
|
npm-debug.log
|
||||||
|
|||||||
82
CHANGELOG.md
82
CHANGELOG.md
@ -15,6 +15,88 @@ _Note: Gaps between patch versions are faulty, broken or test releases._
|
|||||||
|
|
||||||
See the [Babel Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md) for the pre-6.8.0 version Changelog.
|
See the [Babel Changelog](https://github.com/babel/babel/blob/master/CHANGELOG.md) for the pre-6.8.0 version Changelog.
|
||||||
|
|
||||||
|
## 6.17.1 (2017-05-10)
|
||||||
|
|
||||||
|
### :bug: Bug Fix
|
||||||
|
* Fix typo in flow spread operator error (Brian Ng)
|
||||||
|
* Fixed invalid number literal parsing ([#473](https://github.com/babel/babylon/pull/473)) (Alex Kuzmenko)
|
||||||
|
* Fix number parser ([#433](https://github.com/babel/babylon/pull/433)) (Alex Kuzmenko)
|
||||||
|
* Ensure non pattern shorthand props are checked for reserved words ([#479](https://github.com/babel/babylon/pull/479)) (Brian Ng)
|
||||||
|
* Remove jsx context when parsing arrow functions ([#475](https://github.com/babel/babylon/pull/475)) (Brian Ng)
|
||||||
|
* Allow super in class properties ([#499](https://github.com/babel/babylon/pull/499)) (Brian Ng)
|
||||||
|
* Allow flow class field to be named constructor ([#510](https://github.com/babel/babylon/pull/510)) (Brian Ng)
|
||||||
|
|
||||||
|
## 6.17.0 (2017-04-20)
|
||||||
|
|
||||||
|
### :bug: Bug Fix
|
||||||
|
* Cherry-pick #418 to 6.x ([#476](https://github.com/babel/babylon/pull/476)) (Sebastian McKenzie)
|
||||||
|
* Add support for invalid escapes in tagged templates ([#274](https://github.com/babel/babylon/pull/274)) (Kevin Gibbons)
|
||||||
|
* Throw error if new.target is used outside of a function ([#402](https://github.com/babel/babylon/pull/402)) (Brian Ng)
|
||||||
|
* Fix parsing of class properties ([#351](https://github.com/babel/babylon/pull/351)) (Kevin Gibbons)
|
||||||
|
* Fix parsing yield with dynamicImport ([#383](https://github.com/babel/babylon/pull/383)) (Brian Ng)
|
||||||
|
* Ensure consistent start args for parseParenItem ([#386](https://github.com/babel/babylon/pull/386)) (Brian Ng)
|
||||||
|
|
||||||
|
## 7.0.0-beta.8 (2017-04-04)
|
||||||
|
|
||||||
|
### New Feature
|
||||||
|
* Add support for flow type spread (#418) (Conrad Buck)
|
||||||
|
* Allow statics in flow interfaces (#427) (Brian Ng)
|
||||||
|
|
||||||
|
### Bug Fix
|
||||||
|
* Fix predicate attachment to match flow parser (#428) (Brian Ng)
|
||||||
|
* Add extra.raw back to JSXText and JSXAttribute (#344) (Alex Rattray)
|
||||||
|
* Fix rest parameters with array and objects (#424) (Brian Ng)
|
||||||
|
* Fix number parser (#433) (Alex Kuzmenko)
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
* Fix CONTRIBUTING.md [skip ci] (#432) (Alex Kuzmenko)
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
* Use babel-register script when running babel smoke tests (#442) (Brian Ng)
|
||||||
|
|
||||||
|
## 7.0.0-beta.7 (2017-03-22)
|
||||||
|
|
||||||
|
### Spec Compliancy
|
||||||
|
* Remove babylon plugin for template revision since it's stage-4 (#426) (Henry Zhu)
|
||||||
|
|
||||||
|
### Bug Fix
|
||||||
|
|
||||||
|
* Fix push-pop logic in flow (#405) (Daniel Tschinder)
|
||||||
|
|
||||||
|
## 7.0.0-beta.6 (2017-03-21)
|
||||||
|
|
||||||
|
### New Feature
|
||||||
|
* Add support for invalid escapes in tagged templates (#274) (Kevin Gibbons)
|
||||||
|
|
||||||
|
### Polish
|
||||||
|
* Improves error message when super is called outside of constructor (#408) (Arshabh Kumar Agarwal)
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
|
||||||
|
* [7.0] Moved value field in spec from ObjectMember to ObjectProperty as ObjectMethod's don't have it (#415) [skip ci] (James Browning)
|
||||||
|
|
||||||
|
## 7.0.0-beta.5 (2017-03-21)
|
||||||
|
|
||||||
|
### Bug Fix
|
||||||
|
* Throw error if new.target is used outside of a function (#402) (Brian Ng)
|
||||||
|
* Fix parsing of class properties (#351) (Kevin Gibbons)
|
||||||
|
|
||||||
|
### Other
|
||||||
|
* Test runner: Detect extra property in 'actual' but not in 'expected'. (#407) (Andy)
|
||||||
|
* Optimize travis builds (#419) (Daniel Tschinder)
|
||||||
|
* Update codecov to 2.0 (#412) (Daniel Tschinder)
|
||||||
|
* Fix spec for ClassMethod: It doesn't have a function, it *is* a function. (#406) [skip ci] (Andy)
|
||||||
|
* Changed Non-existent RestPattern to RestElement which is what is actually parsed (#409) [skip ci] (James Browning)
|
||||||
|
* Upgrade flow to 0.41 (Daniel Tschinder)
|
||||||
|
* Fix watch command (#403) (Brian Ng)
|
||||||
|
* Update yarn lock (Daniel Tschinder)
|
||||||
|
* Fix watch command (#403) (Brian Ng)
|
||||||
|
* chore(package): update flow-bin to version 0.41.0 (#395) (greenkeeper[bot])
|
||||||
|
* Add estree test for correct order of directives (Daniel Tschinder)
|
||||||
|
* Add DoExpression to spec (#364) (Alex Kuzmenko)
|
||||||
|
* Mention cloning of repository in CONTRIBUTING.md (#391) [skip ci] (Sumedh Nimkarde)
|
||||||
|
* Explain how to run only one test (#389) [skip ci] (Aaron Ang)
|
||||||
|
|
||||||
## 7.0.0-beta.4 (2017-03-01)
|
## 7.0.0-beta.4 (2017-03-01)
|
||||||
|
|
||||||
* Don't consume async when checking for async func decl (#377) (Brian Ng)
|
* Don't consume async when checking for async func decl (#377) (Brian Ng)
|
||||||
|
|||||||
@ -106,3 +106,15 @@ make test
|
|||||||
```
|
```
|
||||||
|
|
||||||
From now on Babel will use your local checkout of Babylon for its tests.
|
From now on Babel will use your local checkout of Babylon for its tests.
|
||||||
|
|
||||||
|
## Creating a new plugin (`spec-new`)
|
||||||
|
|
||||||
|
> Example: https://github.com/babel/babylon/pull/541
|
||||||
|
|
||||||
|
- Create a new issue that describes the proposal (ex: [#538](https://github.com/babel/babylon/issues/538)). Include any relevant information like proposal repo/author, examples, parsing approaches, meeting notes, presentation slides, and more.
|
||||||
|
- The pull request should include:
|
||||||
|
- [ ] An update to the [#plugins](https://github.com/babel/babylon#plugins) part of the readme. Add a new entry to that list for the new plugin flag (and link to the proposal)
|
||||||
|
- [ ] If any new nodes or modifications need to be added to the AST, update [ast/spec.md](https://github.com/babel/babylon/blob/master/ast/spec.md)
|
||||||
|
- [ ] Make sure you use the `this.hasPlugin("plugin-name-here")` check so that your new plugin code only runs when that flag is turned on (not default behavior)
|
||||||
|
- [ ] Add failing/passing tests according to spec behavior
|
||||||
|
- [ ] Start working about the Babel transform itself!
|
||||||
|
|||||||
38
README.md
38
README.md
@ -14,9 +14,13 @@
|
|||||||
|
|
||||||
- The latest ECMAScript version enabled by default (ES2017).
|
- The latest ECMAScript version enabled by default (ES2017).
|
||||||
- Comment attachment.
|
- Comment attachment.
|
||||||
- Support for JSX and Flow.
|
- Support for JSX, Flow, Typescript (WIP).
|
||||||
- Support for experimental language proposals (accepting PRs for anything at least [stage-0](https://github.com/tc39/proposals/blob/master/stage-0-proposals.md)).
|
- Support for experimental language proposals (accepting PRs for anything at least [stage-0](https://github.com/tc39/proposals/blob/master/stage-0-proposals.md)).
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Check out [contributing.md](https://github.com/babel/babylon/blob/master/CONTRIBUTING.md)
|
||||||
|
|
||||||
## Credits
|
## Credits
|
||||||
|
|
||||||
Heavily based on [acorn](https://github.com/marijnh/acorn) and [acorn-jsx](https://github.com/RReverser/acorn-jsx),
|
Heavily based on [acorn](https://github.com/marijnh/acorn) and [acorn-jsx](https://github.com/RReverser/acorn-jsx),
|
||||||
@ -126,12 +130,32 @@ require("babylon").parse("code", {
|
|||||||
- `jsx`
|
- `jsx`
|
||||||
- `flow`
|
- `flow`
|
||||||
- `doExpressions`
|
- `doExpressions`
|
||||||
- `objectRestSpread`
|
- `objectRestSpread` ([proposal](https://github.com/tc39/proposal-object-rest-spread))
|
||||||
- `decorators` (Based on an outdated version of the Decorators proposal. Will be removed in a future version of `Babylon`)
|
- `decorators` (Based on an outdated version of the Decorators proposal. Will be removed in a future version of `Babylon`)
|
||||||
- `classProperties`
|
- `classProperties` ([proposal](https://github.com/zenparsing/es-function-bind))
|
||||||
- `exportExtensions`
|
- `exportExtensions` ([proposal 1](https://github.com/leebyron/ecmascript-export-default-from)), ([proposal 2](https://github.com/leebyron/ecmascript-export-ns-from))
|
||||||
- `asyncGenerators`
|
- `asyncGenerators` ([proposal](https://github.com/tc39/proposal-async-iteration))
|
||||||
- `functionBind`
|
- `functionBind` ([proposal](https://github.com/zenparsing/es-function-bind))
|
||||||
- `functionSent`
|
- `functionSent`
|
||||||
- `dynamicImport`
|
- `dynamicImport` ([proposal](https://github.com/tc39/proposal-dynamic-import))
|
||||||
|
- `numericSeparator` ([proposal](https://github.com/samuelgoto/proposal-numeric-separator))
|
||||||
|
|
||||||
|
### FAQ
|
||||||
|
|
||||||
|
#### Will Babylon support a plugin system?
|
||||||
|
|
||||||
|
Previous issues: [babel/babel#1351](https://github.com/babel/babel/issues/1351), [#500](https://github.com/babel/babylon/issues/500).
|
||||||
|
|
||||||
|
We currently aren't willing to commit to supporting the API for plugins or the resulting ecosystem (there is already enough work maintaining Babel's own plugin system). It's not clear how to make that API effective, and it would limit out ability to refactor and optimize the codebase.
|
||||||
|
|
||||||
|
Our current recommendation for those that want to create their own custom syntax is for users to fork Babylon.
|
||||||
|
|
||||||
|
To consume your custom parser, you can add to your `.babelrc` via its npm package name or require it if using JavaScript,
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"parserOpts": {
|
||||||
|
"parser": "custom-fork-of-babylon-on-npm-here"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
42
ast/spec.md
42
ast/spec.md
@ -3,6 +3,7 @@ These are the core Babylon AST node types.
|
|||||||
- [Node objects](#node-objects)
|
- [Node objects](#node-objects)
|
||||||
- [Changes](#changes)
|
- [Changes](#changes)
|
||||||
- [Identifier](#identifier)
|
- [Identifier](#identifier)
|
||||||
|
- [PrivateName](#privatename)
|
||||||
- [Literals](#literals)
|
- [Literals](#literals)
|
||||||
- [RegExpLiteral](#regexpliteral)
|
- [RegExpLiteral](#regexpliteral)
|
||||||
- [NullLiteral](#nullliteral)
|
- [NullLiteral](#nullliteral)
|
||||||
@ -90,6 +91,7 @@ These are the core Babylon AST node types.
|
|||||||
- [ClassBody](#classbody)
|
- [ClassBody](#classbody)
|
||||||
- [ClassMethod](#classmethod)
|
- [ClassMethod](#classmethod)
|
||||||
- [ClassProperty](#classproperty)
|
- [ClassProperty](#classproperty)
|
||||||
|
- [ClassPrivateProperty](#classprivateproperty)
|
||||||
- [ClassDeclaration](#classdeclaration)
|
- [ClassDeclaration](#classdeclaration)
|
||||||
- [ClassExpression](#classexpression)
|
- [ClassExpression](#classexpression)
|
||||||
- [MetaProperty](#metaproperty)
|
- [MetaProperty](#metaproperty)
|
||||||
@ -166,6 +168,18 @@ interface Identifier <: Expression, Pattern {
|
|||||||
|
|
||||||
An identifier. Note that an identifier may be an expression or a destructuring pattern.
|
An identifier. Note that an identifier may be an expression or a destructuring pattern.
|
||||||
|
|
||||||
|
|
||||||
|
# PrivateName
|
||||||
|
|
||||||
|
```js
|
||||||
|
interface PrivateName <: Expression, Pattern {
|
||||||
|
type: "PrivateName";
|
||||||
|
name: Identifier;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
A Private Name Identifier.
|
||||||
|
|
||||||
|
|
||||||
# Literals
|
# Literals
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -514,7 +528,7 @@ interface FunctionDeclaration <: Function, Declaration {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
A function declaration. Note that unlike in the parent interface `Function`, the `id` cannot be `null`.
|
A function declaration. Note that unlike in the parent interface `Function`, the `id` cannot be `null`, except when this is the child of an `ExportDefaultDeclaration`.
|
||||||
|
|
||||||
## VariableDeclaration
|
## VariableDeclaration
|
||||||
|
|
||||||
@ -856,8 +870,8 @@ A member expression. If `computed` is `true`, the node corresponds to a computed
|
|||||||
```js
|
```js
|
||||||
interface BindExpression <: Expression {
|
interface BindExpression <: Expression {
|
||||||
type: "BindExpression";
|
type: "BindExpression";
|
||||||
object: [ Expression | null ];
|
object: Expression | null;
|
||||||
callee: [ Expression ]
|
callee: Expression;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1016,7 +1030,7 @@ interface Class <: Node {
|
|||||||
```js
|
```js
|
||||||
interface ClassBody <: Node {
|
interface ClassBody <: Node {
|
||||||
type: "ClassBody";
|
type: "ClassBody";
|
||||||
body: [ ClassMethod | ClassProperty ];
|
body: [ ClassMethod | ClassProperty | ClassPrivateProperty ];
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1044,6 +1058,16 @@ interface ClassProperty <: Node {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## ClassPrivateProperty
|
||||||
|
|
||||||
|
```js
|
||||||
|
interface ClassPrivateProperty <: Node {
|
||||||
|
type: "ClassPrivateProperty";
|
||||||
|
key: Identifier;
|
||||||
|
value: Expression;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## ClassDeclaration
|
## ClassDeclaration
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@ -1167,9 +1191,17 @@ An exported variable binding, e.g., `{foo}` in `export {foo}` or `{bar as foo}`
|
|||||||
### ExportDefaultDeclaration
|
### ExportDefaultDeclaration
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
interface OptFunctionDeclaration <: FunctionDeclaration {
|
||||||
|
id: Identifier | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface OptClasDeclaration <: ClassDeclaration {
|
||||||
|
id: Identifier | null;
|
||||||
|
}
|
||||||
|
|
||||||
interface ExportDefaultDeclaration <: ModuleDeclaration {
|
interface ExportDefaultDeclaration <: ModuleDeclaration {
|
||||||
type: "ExportDefaultDeclaration";
|
type: "ExportDefaultDeclaration";
|
||||||
declaration: Declaration | Expression;
|
declaration: OptFunctionDeclaration | OptClassDeclaration | Expression;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
29
package.json
29
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "babylon",
|
"name": "babylon",
|
||||||
"version": "7.0.0-beta.8",
|
"version": "7.0.0-beta.11",
|
||||||
"description": "A JavaScript parser",
|
"description": "A JavaScript parser",
|
||||||
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
||||||
"homepage": "https://babeljs.io/",
|
"homepage": "https://babeljs.io/",
|
||||||
@ -22,20 +22,20 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"ava": "^0.19.0",
|
"ava": "^0.19.0",
|
||||||
"babel-cli": "^7.0.0-alpha.6",
|
"babel-cli": "7.0.0-alpha.9",
|
||||||
"babel-eslint": "^7.0.0",
|
"babel-eslint": "^7.0.0",
|
||||||
"babel-helper-fixtures": "^7.0.0-alpha.3",
|
"babel-helper-fixtures": "7.0.0-alpha.9",
|
||||||
"babel-plugin-external-helpers": "^7.0.0-alpha.3",
|
"babel-plugin-external-helpers": "7.0.0-alpha.9",
|
||||||
"babel-plugin-istanbul": "^4.0.0",
|
"babel-plugin-istanbul": "^4.0.0",
|
||||||
"babel-plugin-transform-flow-strip-types": "^7.0.0-alpha.3",
|
"babel-plugin-transform-flow-strip-types": "7.0.0-alpha.9",
|
||||||
"babel-preset-es2015": "^7.0.0-alpha.3",
|
"babel-preset-es2015": "7.0.0-alpha.9",
|
||||||
"babel-preset-stage-0": "^7.0.0-alpha.3",
|
"babel-preset-stage-0": "7.0.0-alpha.9",
|
||||||
"chalk": "^1.1.3",
|
"chalk": "^1.1.3",
|
||||||
"cross-env": "^4.0.0",
|
"cross-env": "^5.0.0",
|
||||||
"eslint": "^3.7.1",
|
"eslint": "^3.7.1",
|
||||||
"eslint-config-babel": "^6.0.0",
|
"eslint-config-babel": "^6.0.0",
|
||||||
"eslint-plugin-flowtype": "^2.20.0",
|
"eslint-plugin-flowtype": "^2.20.0",
|
||||||
"flow-bin": "^0.43.0",
|
"flow-bin": "^0.47.0",
|
||||||
"nyc": "^10.0.0",
|
"nyc": "^10.0.0",
|
||||||
"rimraf": "^2.5.4",
|
"rimraf": "^2.5.4",
|
||||||
"rollup": "^0.41.0",
|
"rollup": "^0.41.0",
|
||||||
@ -76,5 +76,16 @@
|
|||||||
"src/**/*.js",
|
"src/**/*.js",
|
||||||
"bin/**/*.js"
|
"bin/**/*.js"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"changelog": {
|
||||||
|
"repo": "babel/babylon",
|
||||||
|
"labels": {
|
||||||
|
"Tag: Breaking Change": ":boom: Breaking Change",
|
||||||
|
"Tag: Bug Fix": ":bug: Bug Fix",
|
||||||
|
"Tag: Docs": ":memo: Documentation",
|
||||||
|
"Tag: Internal": ":house: Internal",
|
||||||
|
"Tag: New Feature": ":rocket: New Feature",
|
||||||
|
"Tag: Polish": ":nail_care: Polish"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/index.js
49
src/index.js
@ -1,3 +1,6 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import type { Options } from "./options";
|
||||||
import Parser, { plugins } from "./parser";
|
import Parser, { plugins } from "./parser";
|
||||||
import "./parser/util";
|
import "./parser/util";
|
||||||
import "./parser/statement";
|
import "./parser/statement";
|
||||||
@ -11,6 +14,8 @@ import { types as tokTypes } from "./tokenizer/types";
|
|||||||
import "./tokenizer";
|
import "./tokenizer";
|
||||||
import "./tokenizer/context";
|
import "./tokenizer/context";
|
||||||
|
|
||||||
|
import type { Expression, File } from "./types";
|
||||||
|
|
||||||
import estreePlugin from "./plugins/estree";
|
import estreePlugin from "./plugins/estree";
|
||||||
import flowPlugin from "./plugins/flow";
|
import flowPlugin from "./plugins/flow";
|
||||||
import jsxPlugin from "./plugins/jsx";
|
import jsxPlugin from "./plugins/jsx";
|
||||||
@ -18,12 +23,12 @@ plugins.estree = estreePlugin;
|
|||||||
plugins.flow = flowPlugin;
|
plugins.flow = flowPlugin;
|
||||||
plugins.jsx = jsxPlugin;
|
plugins.jsx = jsxPlugin;
|
||||||
|
|
||||||
export function parse(input, options) {
|
export function parse(input: string, options?: Options): File {
|
||||||
return new Parser(options, input).parse();
|
return getParser(options, input).parse();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseExpression(input, options) {
|
export function parseExpression(input: string, options?: Options): Expression {
|
||||||
const parser = new Parser(options, input);
|
const parser = getParser(options, input);
|
||||||
if (parser.options.strictMode) {
|
if (parser.options.strictMode) {
|
||||||
parser.state.strict = true;
|
parser.state.strict = true;
|
||||||
}
|
}
|
||||||
@ -32,3 +37,39 @@ export function parseExpression(input, options) {
|
|||||||
|
|
||||||
|
|
||||||
export { tokTypes };
|
export { tokTypes };
|
||||||
|
|
||||||
|
function getParser(options: ?Options, input: string): Parser {
|
||||||
|
const cls = options && options.plugins ? getParserClass(options.plugins) : Parser;
|
||||||
|
return new cls(options, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
const parserClassCache: { [key: string]: Class<Parser> } = {};
|
||||||
|
|
||||||
|
/** Get a Parser class with plugins applied. */
|
||||||
|
function getParserClass(pluginsFromOptions: $ReadOnlyArray<string>): Class<Parser> {
|
||||||
|
// Filter out just the plugins that have an actual mixin associated with them.
|
||||||
|
let pluginList = pluginsFromOptions.filter((p) => p === "estree" || p === "flow" || p === "jsx");
|
||||||
|
|
||||||
|
if (pluginList.indexOf("flow") >= 0) {
|
||||||
|
// ensure flow plugin loads last
|
||||||
|
pluginList = pluginList.filter((plugin) => plugin !== "flow");
|
||||||
|
pluginList.push("flow");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pluginList.indexOf("estree") >= 0) {
|
||||||
|
// ensure estree plugin loads first
|
||||||
|
pluginList = pluginList.filter((plugin) => plugin !== "estree");
|
||||||
|
pluginList.unshift("estree");
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = pluginList.join("/");
|
||||||
|
let cls = parserClassCache[key];
|
||||||
|
if (!cls) {
|
||||||
|
cls = Parser;
|
||||||
|
for (const plugin of pluginList) {
|
||||||
|
cls = plugins[plugin](cls);
|
||||||
|
}
|
||||||
|
parserClassCache[key] = cls;
|
||||||
|
}
|
||||||
|
return cls;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,17 +1,21 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
// A second optional argument can be given to further configure
|
// A second optional argument can be given to further configure
|
||||||
// the parser process. These options are recognized:
|
// the parser process. These options are recognized:
|
||||||
|
|
||||||
export const defaultOptions: {
|
export type Options = {
|
||||||
sourceType: string,
|
sourceType: "script" | "module";
|
||||||
sourceFilename: any,
|
sourceFilename?: string;
|
||||||
startLine: number,
|
startLine: number;
|
||||||
allowReturnOutsideFunction: boolean,
|
allowReturnOutsideFunction: boolean;
|
||||||
allowImportExportEverywhere: boolean,
|
allowImportExportEverywhere: boolean;
|
||||||
allowSuperOutsideMethod: boolean,
|
allowSuperOutsideMethod: boolean;
|
||||||
plugins: Array<string>,
|
plugins: $ReadOnlyArray<string>;
|
||||||
strictMode: any,
|
strictMode: ?boolean;
|
||||||
ranges: boolean,
|
ranges: boolean;
|
||||||
} = {
|
};
|
||||||
|
|
||||||
|
export const defaultOptions: Options = {
|
||||||
// Source type ("script" or "module") for different semantics
|
// Source type ("script" or "module") for different semantics
|
||||||
sourceType: "script",
|
sourceType: "script",
|
||||||
// Source filename.
|
// Source filename.
|
||||||
@ -44,8 +48,8 @@ export const defaultOptions: {
|
|||||||
|
|
||||||
// Interpret and default an options object
|
// Interpret and default an options object
|
||||||
|
|
||||||
export function getOptions(opts?: Object): Object {
|
export function getOptions(opts: ?Options): Options {
|
||||||
const options = {};
|
const options: any = {};
|
||||||
for (const key in defaultOptions) {
|
for (const key in defaultOptions) {
|
||||||
options[key] = opts && key in opts ? opts[key] : defaultOptions[key];
|
options[key] = opts && key in opts ? opts[key] : defaultOptions[key];
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/parser/base.js
Normal file
31
src/parser/base.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import type { Options } from "../options";
|
||||||
|
import { reservedWords } from "../util/identifier";
|
||||||
|
|
||||||
|
import type State from "../tokenizer/state";
|
||||||
|
|
||||||
|
export default class BaseParser {
|
||||||
|
// Properties set by constructor in index.js
|
||||||
|
options: Options;
|
||||||
|
inModule: boolean;
|
||||||
|
plugins: { [key: string]: boolean };
|
||||||
|
filename: ?string;
|
||||||
|
|
||||||
|
// Initialized by Tokenizer
|
||||||
|
state: State;
|
||||||
|
input: string;
|
||||||
|
|
||||||
|
|
||||||
|
isReservedWord(word: string): boolean {
|
||||||
|
if (word === "await") {
|
||||||
|
return this.inModule;
|
||||||
|
} else {
|
||||||
|
return reservedWords[6](word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPlugin(name: string): boolean {
|
||||||
|
return !!this.plugins[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
/* eslint max-len: 0 */
|
/* eslint max-len: 0 */
|
||||||
|
|
||||||
|
// @flow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Based on the comment attachment algorithm used in espree and estraverse.
|
* Based on the comment attachment algorithm used in espree and estraverse.
|
||||||
*
|
*
|
||||||
@ -24,26 +26,26 @@
|
|||||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Parser from "./index";
|
import BaseParser from "./base";
|
||||||
|
import type { Comment, Node } from "../types";
|
||||||
|
|
||||||
function last(stack) {
|
function last<T>(stack: $ReadOnlyArray<T>): T {
|
||||||
return stack[stack.length - 1];
|
return stack[stack.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
const pp = Parser.prototype;
|
export default class CommentsParser extends BaseParser {
|
||||||
|
addComment(comment: Comment): void {
|
||||||
pp.addComment = function (comment) {
|
|
||||||
if (this.filename) comment.loc.filename = this.filename;
|
if (this.filename) comment.loc.filename = this.filename;
|
||||||
this.state.trailingComments.push(comment);
|
this.state.trailingComments.push(comment);
|
||||||
this.state.leadingComments.push(comment);
|
this.state.leadingComments.push(comment);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.processComment = function (node) {
|
processComment(node: Node): void {
|
||||||
if (node.type === "Program" && node.body.length > 0) return;
|
if (node.type === "Program" && node.body.length > 0) return;
|
||||||
|
|
||||||
const stack = this.state.commentStack;
|
const stack = this.state.commentStack;
|
||||||
|
|
||||||
let lastChild, trailingComments, i, j;
|
let firstChild, lastChild, trailingComments, i, j;
|
||||||
|
|
||||||
if (this.state.trailingComments.length > 0) {
|
if (this.state.trailingComments.length > 0) {
|
||||||
// If the first comment in trailingComments comes after the
|
// If the first comment in trailingComments comes after the
|
||||||
@ -71,10 +73,41 @@ pp.processComment = function (node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Eating the stack.
|
// Eating the stack.
|
||||||
|
if (stack.length > 0 && last(stack).start >= node.start) {
|
||||||
|
firstChild = stack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
while (stack.length > 0 && last(stack).start >= node.start) {
|
while (stack.length > 0 && last(stack).start >= node.start) {
|
||||||
lastChild = stack.pop();
|
lastChild = stack.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!lastChild && firstChild) lastChild = firstChild;
|
||||||
|
|
||||||
|
// Attach comments that follow a trailing comma on the last
|
||||||
|
// property in an object literal or a trailing comma in function arguments
|
||||||
|
// as trailing comments
|
||||||
|
if (firstChild &&
|
||||||
|
(firstChild.type === "ObjectProperty" ||
|
||||||
|
(node.type === "CallExpression")) &&
|
||||||
|
this.state.leadingComments.length > 0) {
|
||||||
|
const lastComment = last(this.state.leadingComments);
|
||||||
|
if (lastComment.start >= node.start) {
|
||||||
|
if (this.state.commentPreviousNode) {
|
||||||
|
for (j = 0; j < this.state.leadingComments.length; j++) {
|
||||||
|
if (this.state.leadingComments[j].end < this.state.commentPreviousNode.end) {
|
||||||
|
this.state.leadingComments.splice(j, 1);
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.state.leadingComments.length > 0) {
|
||||||
|
firstChild.trailingComments = this.state.leadingComments;
|
||||||
|
this.state.leadingComments = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (lastChild) {
|
if (lastChild) {
|
||||||
if (lastChild.leadingComments) {
|
if (lastChild.leadingComments) {
|
||||||
if (lastChild !== node && last(lastChild.leadingComments).end <= node.start) {
|
if (lastChild !== node && last(lastChild.leadingComments).end <= node.start) {
|
||||||
@ -128,10 +161,8 @@ pp.processComment = function (node) {
|
|||||||
// that comes after the node. Keep in mind that this could
|
// that comes after the node. Keep in mind that this could
|
||||||
// result in an empty array, and if so, the array must be
|
// result in an empty array, and if so, the array must be
|
||||||
// deleted.
|
// deleted.
|
||||||
node.leadingComments = this.state.leadingComments.slice(0, i);
|
const leadingComments = this.state.leadingComments.slice(0, i);
|
||||||
if ((node.leadingComments: Array<any>).length === 0) {
|
node.leadingComments = leadingComments.length === 0 ? null : leadingComments;
|
||||||
node.leadingComments = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Similarly, trailing comments are attached later. The variable
|
// Similarly, trailing comments are attached later. The variable
|
||||||
// must be reset to null if there are no trailing comments.
|
// must be reset to null if there are no trailing comments.
|
||||||
@ -153,4 +184,5 @@ pp.processComment = function (node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stack.push(node);
|
stack.push(node);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
/* eslint max-len: 0 */
|
/* eslint max-len: 0 */
|
||||||
|
|
||||||
|
// @flow
|
||||||
|
|
||||||
// A recursive descent parser operates by defining functions for all
|
// A recursive descent parser operates by defining functions for all
|
||||||
// syntactic elements, and recursively calling those, each function
|
// syntactic elements, and recursively calling those, each function
|
||||||
// advancing the input stream and returning an AST node. Precedence
|
// advancing the input stream and returning an AST node. Precedence
|
||||||
@ -18,18 +20,26 @@
|
|||||||
//
|
//
|
||||||
// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
|
// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
|
||||||
|
|
||||||
import { types as tt } from "../tokenizer/types";
|
import { types as tt, type TokenType } from "../tokenizer/types";
|
||||||
import Parser from "./index";
|
import * as N from "../types";
|
||||||
|
import LValParser from "./lval";
|
||||||
import { reservedWords } from "../util/identifier";
|
import { reservedWords } from "../util/identifier";
|
||||||
|
import type { Pos, Position } from "../util/location";
|
||||||
|
|
||||||
const pp = Parser.prototype;
|
export default class ExpressionParser extends LValParser {
|
||||||
|
// Forward-declaration: defined in statement.js
|
||||||
|
+parseBlock: (allowDirectives?: boolean) => N.BlockStatement;
|
||||||
|
+parseClass: (node: N.Class, isStatement: boolean, optionalId?: boolean) => N.Class;
|
||||||
|
+parseDecorators: (allowExport?: boolean) => void;
|
||||||
|
+parseFunction: <T : N.NormalFunction>(node: T, isStatement: boolean, allowExpressionBody?: boolean, isAsync?: boolean, optionalId?: boolean) => T;
|
||||||
|
+takeDecorators: (node: N.HasDecorators) => void;
|
||||||
|
|
||||||
// Check if property name clashes with already added.
|
// Check if property name clashes with already added.
|
||||||
// Object/class getters and setters are not allowed to clash —
|
// Object/class getters and setters are not allowed to clash —
|
||||||
// either with each other or with an init property — and in
|
// either with each other or with an init property — and in
|
||||||
// strict mode, init properties are also not allowed to be repeated.
|
// strict mode, init properties are also not allowed to be repeated.
|
||||||
|
|
||||||
pp.checkPropClash = function (prop, propHash) {
|
checkPropClash(prop: N.ObjectMember, propHash: { [key: string]: boolean }): void {
|
||||||
if (prop.computed || prop.kind) return;
|
if (prop.computed || prop.kind) return;
|
||||||
|
|
||||||
const key = prop.key;
|
const key = prop.key;
|
||||||
@ -40,17 +50,17 @@ pp.checkPropClash = function (prop, propHash) {
|
|||||||
if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property");
|
if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property");
|
||||||
propHash.proto = true;
|
propHash.proto = true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Convenience method to parse an Expression only
|
// Convenience method to parse an Expression only
|
||||||
pp.getExpression = function() {
|
getExpression(): N.Expression {
|
||||||
this.nextToken();
|
this.nextToken();
|
||||||
const expr = this.parseExpression();
|
const expr = this.parseExpression();
|
||||||
if (!this.match(tt.eof)) {
|
if (!this.match(tt.eof)) {
|
||||||
this.unexpected();
|
this.unexpected();
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
};
|
}
|
||||||
|
|
||||||
// ### Expression parsing
|
// ### Expression parsing
|
||||||
|
|
||||||
@ -67,7 +77,7 @@ pp.getExpression = function() {
|
|||||||
// and object pattern might appear (so it's possible to raise
|
// and object pattern might appear (so it's possible to raise
|
||||||
// delayed syntax error at correct position).
|
// delayed syntax error at correct position).
|
||||||
|
|
||||||
pp.parseExpression = function (noIn, refShorthandDefaultPos) {
|
parseExpression(noIn?: boolean, refShorthandDefaultPos?: Pos): N.Expression {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
const expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos);
|
const expr = this.parseMaybeAssign(noIn, refShorthandDefaultPos);
|
||||||
@ -81,15 +91,14 @@ pp.parseExpression = function (noIn, refShorthandDefaultPos) {
|
|||||||
return this.finishNode(node, "SequenceExpression");
|
return this.finishNode(node, "SequenceExpression");
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse an assignment expression. This includes applications of
|
// Parse an assignment expression. This includes applications of
|
||||||
// operators like `+=`.
|
// operators like `+=`.
|
||||||
|
|
||||||
pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse, refNeedsArrowPos) {
|
parseMaybeAssign(noIn?: ?boolean, refShorthandDefaultPos?: ?Pos, afterLeftParse?: Function, refNeedsArrowPos?: ?Pos): N.Expression {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
|
|
||||||
if (this.match(tt._yield) && this.state.inGenerator) {
|
if (this.match(tt._yield) && this.state.inGenerator) {
|
||||||
let left = this.parseYield();
|
let left = this.parseYield();
|
||||||
if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc);
|
if (afterLeftParse) left = afterLeftParse.call(this, left, startPos, startLoc);
|
||||||
@ -138,20 +147,28 @@ pp.parseMaybeAssign = function (noIn, refShorthandDefaultPos, afterLeftParse, re
|
|||||||
}
|
}
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse a ternary conditional (`?:`) operator.
|
// Parse a ternary conditional (`?:`) operator.
|
||||||
|
|
||||||
pp.parseMaybeConditional = function (noIn, refShorthandDefaultPos, refNeedsArrowPos) {
|
parseMaybeConditional(noIn: ?boolean, refShorthandDefaultPos: Pos, refNeedsArrowPos?: ?Pos): N.Expression {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
const expr = this.parseExprOps(noIn, refShorthandDefaultPos);
|
const expr = this.parseExprOps(noIn, refShorthandDefaultPos);
|
||||||
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
|
if (refShorthandDefaultPos && refShorthandDefaultPos.start) return expr;
|
||||||
|
|
||||||
return this.parseConditional(expr, noIn, startPos, startLoc, refNeedsArrowPos);
|
return this.parseConditional(expr, noIn, startPos, startLoc, refNeedsArrowPos);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseConditional = function (expr, noIn, startPos, startLoc) {
|
parseConditional(
|
||||||
|
expr: N.Expression,
|
||||||
|
noIn: ?boolean,
|
||||||
|
startPos: number,
|
||||||
|
startLoc: Position,
|
||||||
|
// FIXME: Disabling this for now since can't seem to get it to play nicely
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
refNeedsArrowPos?: ?Pos
|
||||||
|
): N.Expression {
|
||||||
if (this.eat(tt.question)) {
|
if (this.eat(tt.question)) {
|
||||||
const node = this.startNodeAt(startPos, startLoc);
|
const node = this.startNodeAt(startPos, startLoc);
|
||||||
node.test = expr;
|
node.test = expr;
|
||||||
@ -161,11 +178,11 @@ pp.parseConditional = function (expr, noIn, startPos, startLoc) {
|
|||||||
return this.finishNode(node, "ConditionalExpression");
|
return this.finishNode(node, "ConditionalExpression");
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Start the precedence parser.
|
// Start the precedence parser.
|
||||||
|
|
||||||
pp.parseExprOps = function (noIn, refShorthandDefaultPos) {
|
parseExprOps(noIn: ?boolean, refShorthandDefaultPos: Pos): N.Expression {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
const expr = this.parseMaybeUnary(refShorthandDefaultPos);
|
const expr = this.parseMaybeUnary(refShorthandDefaultPos);
|
||||||
@ -174,7 +191,7 @@ pp.parseExprOps = function (noIn, refShorthandDefaultPos) {
|
|||||||
} else {
|
} else {
|
||||||
return this.parseExprOp(expr, startPos, startLoc, -1, noIn);
|
return this.parseExprOp(expr, startPos, startLoc, -1, noIn);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse binary operators with the operator precedence parsing
|
// Parse binary operators with the operator precedence parsing
|
||||||
// algorithm. `left` is the left-hand side of the operator.
|
// algorithm. `left` is the left-hand side of the operator.
|
||||||
@ -182,7 +199,7 @@ pp.parseExprOps = function (noIn, refShorthandDefaultPos) {
|
|||||||
// defer further parser to one of its callers when it encounters an
|
// defer further parser to one of its callers when it encounters an
|
||||||
// operator that has a lower precedence than the set it is parsing.
|
// operator that has a lower precedence than the set it is parsing.
|
||||||
|
|
||||||
pp.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) {
|
parseExprOp(left: N.Expression, leftStartPos: number, leftStartLoc: Position, minPrec: number, noIn: ?boolean): N.Expression {
|
||||||
const prec = this.state.type.binop;
|
const prec = this.state.type.binop;
|
||||||
if (prec != null && (!noIn || !this.match(tt._in))) {
|
if (prec != null && (!noIn || !this.match(tt._in))) {
|
||||||
if (prec > minPrec) {
|
if (prec > minPrec) {
|
||||||
@ -212,11 +229,11 @@ pp.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return left;
|
return left;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse unary operators, both prefix and postfix.
|
// Parse unary operators, both prefix and postfix.
|
||||||
|
|
||||||
pp.parseMaybeUnary = function (refShorthandDefaultPos) {
|
parseMaybeUnary(refShorthandDefaultPos: ?Pos): N.Expression {
|
||||||
if (this.state.type.prefix) {
|
if (this.state.type.prefix) {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
const update = this.match(tt.incDec);
|
const update = this.match(tt.incDec);
|
||||||
@ -256,11 +273,11 @@ pp.parseMaybeUnary = function (refShorthandDefaultPos) {
|
|||||||
expr = this.finishNode(node, "UpdateExpression");
|
expr = this.finishNode(node, "UpdateExpression");
|
||||||
}
|
}
|
||||||
return expr;
|
return expr;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse call, dot, and `[]`-subscript expressions.
|
// Parse call, dot, and `[]`-subscript expressions.
|
||||||
|
|
||||||
pp.parseExprSubscripts = function (refShorthandDefaultPos) {
|
parseExprSubscripts(refShorthandDefaultPos: ?Pos): N.Expression {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
const potentialArrowAt = this.state.potentialArrowAt;
|
const potentialArrowAt = this.state.potentialArrowAt;
|
||||||
@ -275,15 +292,16 @@ pp.parseExprSubscripts = function (refShorthandDefaultPos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.parseSubscripts(expr, startPos, startLoc);
|
return this.parseSubscripts(expr, startPos, startLoc);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseSubscripts = function (base, startPos, startLoc, noCalls) {
|
parseSubscripts(base: N.Expression, startPos: number, startLoc: Position, noCalls?: boolean): N.Expression {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!noCalls && this.eat(tt.doubleColon)) {
|
if (!noCalls && this.eat(tt.doubleColon)) {
|
||||||
const node = this.startNodeAt(startPos, startLoc);
|
const node = this.startNodeAt(startPos, startLoc);
|
||||||
node.object = base;
|
node.object = base;
|
||||||
node.callee = this.parseNoCallExpr();
|
node.callee = this.parseNoCallExpr();
|
||||||
return this.parseSubscripts(this.finishNode(node, "BindExpression"), startPos, startLoc, noCalls);
|
return this.parseSubscripts(this.finishNode(node, "BindExpression"), startPos, startLoc, noCalls);
|
||||||
|
|
||||||
} else if (this.eat(tt.questionDot)) {
|
} else if (this.eat(tt.questionDot)) {
|
||||||
if (this.eat(tt.bracketL)) {
|
if (this.eat(tt.bracketL)) {
|
||||||
const node = this.startNodeAt(startPos, startLoc);
|
const node = this.startNodeAt(startPos, startLoc);
|
||||||
@ -304,7 +322,7 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) {
|
|||||||
} else if (this.eat(tt.dot)) {
|
} else if (this.eat(tt.dot)) {
|
||||||
const node = this.startNodeAt(startPos, startLoc);
|
const node = this.startNodeAt(startPos, startLoc);
|
||||||
node.object = base;
|
node.object = base;
|
||||||
node.property = this.parseIdentifier(true);
|
node.property = this.hasPlugin("classPrivateProperties") ? this.parseMaybePrivateName() : this.parseIdentifier(true);
|
||||||
node.computed = false;
|
node.computed = false;
|
||||||
base = this.finishNode(node, "MemberExpression");
|
base = this.finishNode(node, "MemberExpression");
|
||||||
} else if (this.eat(tt.bracketL)) {
|
} else if (this.eat(tt.bracketL)) {
|
||||||
@ -321,9 +339,16 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) {
|
|||||||
const node = this.startNodeAt(startPos, startLoc);
|
const node = this.startNodeAt(startPos, startLoc);
|
||||||
node.callee = base;
|
node.callee = base;
|
||||||
node.arguments = this.parseCallExpressionArguments(tt.parenR, possibleAsync);
|
node.arguments = this.parseCallExpressionArguments(tt.parenR, possibleAsync);
|
||||||
if (node.callee.type === "Import" && node.arguments.length !== 1) {
|
if (node.callee.type === "Import") {
|
||||||
|
if (node.arguments.length !== 1) {
|
||||||
this.raise(node.start, "import() requires exactly one argument");
|
this.raise(node.start, "import() requires exactly one argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const importArg = node.arguments[0];
|
||||||
|
if (importArg && importArg.type === "SpreadElement") {
|
||||||
|
this.raise(importArg.start, "... is not allowed in import()");
|
||||||
|
}
|
||||||
|
}
|
||||||
base = this.finishNode(node, "CallExpression");
|
base = this.finishNode(node, "CallExpression");
|
||||||
|
|
||||||
if (possibleAsync && this.shouldParseAsyncArrow()) {
|
if (possibleAsync && this.shouldParseAsyncArrow()) {
|
||||||
@ -340,9 +365,11 @@ pp.parseSubscripts = function (base, startPos, startLoc, noCalls) {
|
|||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
// istanbul ignore next
|
||||||
|
throw new Error("Unreachable");
|
||||||
|
}
|
||||||
|
|
||||||
pp.parseCallExpressionArguments = function (close, possibleAsyncArrow) {
|
parseCallExpressionArguments(close: TokenType, possibleAsyncArrow: boolean): $ReadOnlyArray<?N.Expression> {
|
||||||
const elts = [];
|
const elts = [];
|
||||||
let innerParenStart;
|
let innerParenStart;
|
||||||
let first = true;
|
let first = true;
|
||||||
@ -369,37 +396,41 @@ pp.parseCallExpressionArguments = function (close, possibleAsyncArrow) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return elts;
|
return elts;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.shouldParseAsyncArrow = function () {
|
shouldParseAsyncArrow(): boolean {
|
||||||
return this.match(tt.arrow);
|
return this.match(tt.arrow);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseAsyncArrowFromCallExpression = function (node, call) {
|
parseAsyncArrowFromCallExpression(node: N.ArrowFunctionExpression, call: N.CallExpression): N.ArrowFunctionExpression {
|
||||||
this.expect(tt.arrow);
|
this.expect(tt.arrow);
|
||||||
return this.parseArrowExpression(node, call.arguments, true);
|
return this.parseArrowExpression(node, call.arguments, true);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse a no-call expression (like argument of `new` or `::` operators).
|
// Parse a no-call expression (like argument of `new` or `::` operators).
|
||||||
|
|
||||||
pp.parseNoCallExpr = function () {
|
parseNoCallExpr(): N.Expression {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
return this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true);
|
return this.parseSubscripts(this.parseExprAtom(), startPos, startLoc, true);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse an atomic expression — either a single token that is an
|
// Parse an atomic expression — either a single token that is an
|
||||||
// expression, an expression started by a keyword like `function` or
|
// expression, an expression started by a keyword like `function` or
|
||||||
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
|
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
|
||||||
// or `{}`.
|
// or `{}`.
|
||||||
|
|
||||||
pp.parseExprAtom = function (refShorthandDefaultPos) {
|
parseExprAtom(refShorthandDefaultPos?: ?Pos): N.Expression {
|
||||||
const canBeArrow = this.state.potentialArrowAt === this.state.start;
|
const canBeArrow = this.state.potentialArrowAt === this.state.start;
|
||||||
let node;
|
let node;
|
||||||
|
|
||||||
switch (this.state.type) {
|
switch (this.state.type) {
|
||||||
case tt._super:
|
case tt._super:
|
||||||
if (!this.state.inMethod && !this.options.allowSuperOutsideMethod) {
|
if (
|
||||||
|
!this.state.inMethod &&
|
||||||
|
!this.state.inClassProperty &&
|
||||||
|
!this.options.allowSuperOutsideMethod
|
||||||
|
) {
|
||||||
this.raise(this.state.start, "'super' outside of function or class");
|
this.raise(this.state.start, "'super' outside of function or class");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -465,7 +496,7 @@ pp.parseExprAtom = function (refShorthandDefaultPos) {
|
|||||||
const oldLabels = this.state.labels;
|
const oldLabels = this.state.labels;
|
||||||
this.state.labels = [];
|
this.state.labels = [];
|
||||||
this.state.inFunction = false;
|
this.state.inFunction = false;
|
||||||
node.body = this.parseBlock(false, true);
|
node.body = this.parseBlock(false);
|
||||||
this.state.inFunction = oldInFunction;
|
this.state.inFunction = oldInFunction;
|
||||||
this.state.labels = oldLabels;
|
this.state.labels = oldLabels;
|
||||||
return this.finishNode(node, "DoExpression");
|
return this.finishNode(node, "DoExpression");
|
||||||
@ -496,7 +527,7 @@ pp.parseExprAtom = function (refShorthandDefaultPos) {
|
|||||||
return this.finishNode(node, "BooleanLiteral");
|
return this.finishNode(node, "BooleanLiteral");
|
||||||
|
|
||||||
case tt.parenL:
|
case tt.parenL:
|
||||||
return this.parseParenAndDistinguishExpression(null, null, canBeArrow);
|
return this.parseParenAndDistinguishExpression(canBeArrow);
|
||||||
|
|
||||||
case tt.bracketL:
|
case tt.bracketL:
|
||||||
node = this.startNode();
|
node = this.startNode();
|
||||||
@ -519,6 +550,13 @@ pp.parseExprAtom = function (refShorthandDefaultPos) {
|
|||||||
this.takeDecorators(node);
|
this.takeDecorators(node);
|
||||||
return this.parseClass(node, false);
|
return this.parseClass(node, false);
|
||||||
|
|
||||||
|
case tt.hash:
|
||||||
|
if (this.hasPlugin("classPrivateProperties")) {
|
||||||
|
return this.parseMaybePrivateName();
|
||||||
|
} else {
|
||||||
|
this.unexpected();
|
||||||
|
}
|
||||||
|
|
||||||
case tt._new:
|
case tt._new:
|
||||||
return this.parseNew();
|
return this.parseNew();
|
||||||
|
|
||||||
@ -533,15 +571,27 @@ pp.parseExprAtom = function (refShorthandDefaultPos) {
|
|||||||
if (callee.type === "MemberExpression") {
|
if (callee.type === "MemberExpression") {
|
||||||
return this.finishNode(node, "BindExpression");
|
return this.finishNode(node, "BindExpression");
|
||||||
} else {
|
} else {
|
||||||
this.raise(callee.start, "Binding should be performed on object property.");
|
throw this.raise(callee.start, "Binding should be performed on object property.");
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.unexpected();
|
throw this.unexpected();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
pp.parseFunctionExpression = function () {
|
parseMaybePrivateName(): N.PrivateName | N.Identifier {
|
||||||
|
const isPrivate = this.eat(tt.hash);
|
||||||
|
|
||||||
|
if (isPrivate) {
|
||||||
|
const node = this.startNode();
|
||||||
|
node.name = this.parseIdentifier(true);
|
||||||
|
return this.finishNode(node, "PrivateName");
|
||||||
|
} else {
|
||||||
|
return this.parseIdentifier(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parseFunctionExpression(): N.FunctionExpression | N.MetaProperty {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
const meta = this.parseIdentifier(true);
|
const meta = this.parseIdentifier(true);
|
||||||
if (this.state.inGenerator && this.eat(tt.dot) && this.hasPlugin("functionSent")) {
|
if (this.state.inGenerator && this.eat(tt.dot) && this.hasPlugin("functionSent")) {
|
||||||
@ -549,9 +599,9 @@ pp.parseFunctionExpression = function () {
|
|||||||
} else {
|
} else {
|
||||||
return this.parseFunction(node, false);
|
return this.parseFunction(node, false);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseMetaProperty = function (node, meta, propertyName) {
|
parseMetaProperty(node: N.MetaProperty, meta: N.Identifier, propertyName: string): N.MetaProperty {
|
||||||
node.meta = meta;
|
node.meta = meta;
|
||||||
node.property = this.parseIdentifier(true);
|
node.property = this.parseIdentifier(true);
|
||||||
|
|
||||||
@ -560,9 +610,9 @@ pp.parseMetaProperty = function (node, meta, propertyName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.finishNode(node, "MetaProperty");
|
return this.finishNode(node, "MetaProperty");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseLiteral = function (value, type, startPos, startLoc) {
|
parseLiteral<T : N.Literal>(value: any, type: /*T["kind"]*/string, startPos?: number, startLoc?: Position): T {
|
||||||
startPos = startPos || this.state.start;
|
startPos = startPos || this.state.start;
|
||||||
startLoc = startLoc || this.state.startLoc;
|
startLoc = startLoc || this.state.startLoc;
|
||||||
|
|
||||||
@ -572,18 +622,18 @@ pp.parseLiteral = function (value, type, startPos, startLoc) {
|
|||||||
node.value = value;
|
node.value = value;
|
||||||
this.next();
|
this.next();
|
||||||
return this.finishNode(node, type);
|
return this.finishNode(node, type);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseParenExpression = function () {
|
parseParenExpression(): N.Expression {
|
||||||
this.expect(tt.parenL);
|
this.expect(tt.parenL);
|
||||||
const val = this.parseExpression();
|
const val = this.parseExpression();
|
||||||
this.expect(tt.parenR);
|
this.expect(tt.parenR);
|
||||||
return val;
|
return val;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow) {
|
parseParenAndDistinguishExpression(canBeArrow: boolean): N.Expression {
|
||||||
startPos = startPos || this.state.start;
|
const startPos = this.state.start;
|
||||||
startLoc = startLoc || this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
|
|
||||||
let val;
|
let val;
|
||||||
this.expect(tt.parenL);
|
this.expect(tt.parenL);
|
||||||
@ -654,27 +704,28 @@ pp.parseParenAndDistinguishExpression = function (startPos, startLoc, canBeArrow
|
|||||||
this.addExtra(val, "parenStart", startPos);
|
this.addExtra(val, "parenStart", startPos);
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.shouldParseArrow = function () {
|
shouldParseArrow(): boolean {
|
||||||
return !this.canInsertSemicolon();
|
return !this.canInsertSemicolon();
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseArrow = function (node) {
|
parseArrow(node: N.ArrowFunctionExpression): ?N.ArrowFunctionExpression {
|
||||||
if (this.eat(tt.arrow)) {
|
if (this.eat(tt.arrow)) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseParenItem = function (node) {
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
parseParenItem(node: N.Expression, startPos: number, startLoc: Position): N.Expression {
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
|
|
||||||
// New's precedence is slightly tricky. It must allow its argument
|
// New's precedence is slightly tricky. It must allow its argument
|
||||||
// to be a `[]` or dot subscript expression, but not a call — at
|
// to be a `[]` or dot subscript expression, but not a call — at
|
||||||
// least, not without wrapping it in parentheses. Thus, it uses the
|
// least, not without wrapping it in parentheses. Thus, it uses the
|
||||||
|
|
||||||
pp.parseNew = function () {
|
parseNew(): N.NewExpression | N.MetaProperty {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
const meta = this.parseIdentifier(true);
|
const meta = this.parseIdentifier(true);
|
||||||
|
|
||||||
@ -698,14 +749,15 @@ pp.parseNew = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.finishNode(node, "NewExpression");
|
return this.finishNode(node, "NewExpression");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse template expression.
|
// Parse template expression.
|
||||||
|
|
||||||
pp.parseTemplateElement = function (isTagged) {
|
parseTemplateElement(isTagged: boolean): N.TemplateElement {
|
||||||
const elem = this.startNode();
|
const elem = this.startNode();
|
||||||
if (this.state.value === null) {
|
if (this.state.value === null) {
|
||||||
if (!isTagged) {
|
if (!isTagged) {
|
||||||
|
// $FlowFixMe
|
||||||
this.raise(this.state.invalidTemplateEscapePosition, "Invalid escape sequence in template");
|
this.raise(this.state.invalidTemplateEscapePosition, "Invalid escape sequence in template");
|
||||||
} else {
|
} else {
|
||||||
this.state.invalidTemplateEscapePosition = null;
|
this.state.invalidTemplateEscapePosition = null;
|
||||||
@ -718,9 +770,9 @@ pp.parseTemplateElement = function (isTagged) {
|
|||||||
this.next();
|
this.next();
|
||||||
elem.tail = this.match(tt.backQuote);
|
elem.tail = this.match(tt.backQuote);
|
||||||
return this.finishNode(elem, "TemplateElement");
|
return this.finishNode(elem, "TemplateElement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseTemplate = function (isTagged) {
|
parseTemplate(isTagged: boolean): N.TemplateLiteral {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
node.expressions = [];
|
node.expressions = [];
|
||||||
@ -734,11 +786,11 @@ pp.parseTemplate = function (isTagged) {
|
|||||||
}
|
}
|
||||||
this.next();
|
this.next();
|
||||||
return this.finishNode(node, "TemplateLiteral");
|
return this.finishNode(node, "TemplateLiteral");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse an object literal or binding pattern.
|
// Parse an object literal or binding pattern.
|
||||||
|
|
||||||
pp.parseObj = function (isPattern, refShorthandDefaultPos) {
|
parseObj<T : N.ObjectPattern | N.ObjectExpression>(isPattern: boolean, refShorthandDefaultPos?: ?Pos): T {
|
||||||
let decorators = [];
|
let decorators = [];
|
||||||
const propHash = Object.create(null);
|
const propHash = Object.create(null);
|
||||||
let first = true;
|
let first = true;
|
||||||
@ -790,7 +842,6 @@ pp.parseObj = function (isPattern, refShorthandDefaultPos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prop.method = false;
|
prop.method = false;
|
||||||
prop.shorthand = false;
|
|
||||||
|
|
||||||
if (isPattern || refShorthandDefaultPos) {
|
if (isPattern || refShorthandDefaultPos) {
|
||||||
startPos = this.state.start;
|
startPos = this.state.start;
|
||||||
@ -836,9 +887,9 @@ pp.parseObj = function (isPattern, refShorthandDefaultPos) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression");
|
return this.finishNode(node, isPattern ? "ObjectPattern" : "ObjectExpression");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.isGetterOrSetterMethod = function (prop, isPattern) {
|
isGetterOrSetterMethod(prop: N.ObjectMethod, isPattern: boolean): boolean {
|
||||||
return !isPattern &&
|
return !isPattern &&
|
||||||
!prop.computed &&
|
!prop.computed &&
|
||||||
prop.key.type === "Identifier" &&
|
prop.key.type === "Identifier" &&
|
||||||
@ -848,13 +899,13 @@ pp.isGetterOrSetterMethod = function (prop, isPattern) {
|
|||||||
this.match(tt.num) || // get 1() {}
|
this.match(tt.num) || // get 1() {}
|
||||||
this.match(tt.bracketL) || // get ["string"]() {}
|
this.match(tt.bracketL) || // get ["string"]() {}
|
||||||
this.match(tt.name) || // get foo() {}
|
this.match(tt.name) || // get foo() {}
|
||||||
this.state.type.keyword // get debugger() {}
|
!!this.state.type.keyword // get debugger() {}
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
// get methods aren't allowed to have any parameters
|
// get methods aren't allowed to have any parameters
|
||||||
// set methods must have exactly 1 parameter
|
// set methods must have exactly 1 parameter
|
||||||
pp.checkGetterSetterParamCount = function (method) {
|
checkGetterSetterParamCount(method: N.ObjectMethod | N.ClassMethod): void {
|
||||||
const paramCount = method.kind === "get" ? 0 : 1;
|
const paramCount = method.kind === "get" ? 0 : 1;
|
||||||
if (method.params.length !== paramCount) {
|
if (method.params.length !== paramCount) {
|
||||||
const start = method.start;
|
const start = method.start;
|
||||||
@ -864,9 +915,9 @@ pp.checkGetterSetterParamCount = function (method) {
|
|||||||
this.raise(start, "setter should have exactly one param");
|
this.raise(start, "setter should have exactly one param");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseObjectMethod = function (prop, isGenerator, isAsync, isPattern) {
|
parseObjectMethod(prop: N.ObjectMethod, isGenerator: boolean, isAsync: boolean, isPattern: boolean): ?N.ObjectMethod {
|
||||||
if (isAsync || isGenerator || this.match(tt.parenL)) {
|
if (isAsync || isGenerator || this.match(tt.parenL)) {
|
||||||
if (isPattern) this.unexpected();
|
if (isPattern) this.unexpected();
|
||||||
prop.kind = "method";
|
prop.kind = "method";
|
||||||
@ -885,9 +936,11 @@ pp.parseObjectMethod = function (prop, isGenerator, isAsync, isPattern) {
|
|||||||
|
|
||||||
return this.finishNode(prop, "ObjectMethod");
|
return this.finishNode(prop, "ObjectMethod");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
parseObjectProperty(prop: N.ObjectProperty, startPos: ?number, startLoc: ?Position, isPattern: boolean, refShorthandDefaultPos: ?Pos): ?N.ObjectProperty {
|
||||||
|
prop.shorthand = false;
|
||||||
|
|
||||||
pp.parseObjectProperty = function (prop, startPos, startLoc, isPattern, refShorthandDefaultPos) {
|
|
||||||
if (this.eat(tt.colon)) {
|
if (this.eat(tt.colon)) {
|
||||||
prop.value = isPattern ? this.parseMaybeDefault(this.state.start, this.state.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos);
|
prop.value = isPattern ? this.parseMaybeDefault(this.state.start, this.state.startLoc) : this.parseMaybeAssign(false, refShorthandDefaultPos);
|
||||||
|
|
||||||
@ -895,8 +948,9 @@ pp.parseObjectProperty = function (prop, startPos, startLoc, isPattern, refShort
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!prop.computed && prop.key.type === "Identifier") {
|
if (!prop.computed && prop.key.type === "Identifier") {
|
||||||
if (isPattern) {
|
|
||||||
this.checkReservedWord(prop.key.name, prop.key.start, true, true);
|
this.checkReservedWord(prop.key.name, prop.key.start, true, true);
|
||||||
|
|
||||||
|
if (isPattern) {
|
||||||
prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key.__clone());
|
prop.value = this.parseMaybeDefault(startPos, startLoc, prop.key.__clone());
|
||||||
} else if (this.match(tt.eq) && refShorthandDefaultPos) {
|
} else if (this.match(tt.eq) && refShorthandDefaultPos) {
|
||||||
if (!refShorthandDefaultPos.start) {
|
if (!refShorthandDefaultPos.start) {
|
||||||
@ -910,24 +964,24 @@ pp.parseObjectProperty = function (prop, startPos, startLoc, isPattern, refShort
|
|||||||
|
|
||||||
return this.finishNode(prop, "ObjectProperty");
|
return this.finishNode(prop, "ObjectProperty");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseObjPropValue = function (prop, startPos, startLoc, isGenerator, isAsync, isPattern, refShorthandDefaultPos) {
|
parseObjPropValue(prop: any, startPos: ?number, startLoc: ?Position, isGenerator: boolean, isAsync: boolean, isPattern: boolean, refShorthandDefaultPos: ?Pos): void {
|
||||||
const node =
|
const node =
|
||||||
this.parseObjectMethod(prop, isGenerator, isAsync, isPattern) ||
|
this.parseObjectMethod(prop, isGenerator, isAsync, isPattern) ||
|
||||||
this.parseObjectProperty(prop, startPos, startLoc, isPattern, refShorthandDefaultPos);
|
this.parseObjectProperty(prop, startPos, startLoc, isPattern, refShorthandDefaultPos);
|
||||||
|
|
||||||
if (!node) this.unexpected();
|
if (!node) this.unexpected();
|
||||||
|
}
|
||||||
|
|
||||||
return node;
|
parsePropertyName(prop: N.ObjectOrClassMember): N.Identifier {
|
||||||
};
|
|
||||||
|
|
||||||
pp.parsePropertyName = function (prop) {
|
|
||||||
if (this.eat(tt.bracketL)) {
|
if (this.eat(tt.bracketL)) {
|
||||||
|
// $FlowFixMe (ClassPrivateMember shouldn't be allowed to be computed!)
|
||||||
prop.computed = true;
|
prop.computed = true;
|
||||||
prop.key = this.parseMaybeAssign();
|
prop.key = this.parseMaybeAssign();
|
||||||
this.expect(tt.bracketR);
|
this.expect(tt.bracketR);
|
||||||
} else {
|
} else {
|
||||||
|
// $FlowFixMe (ClassPrivateMember shouldn't be allowed to be computed!)
|
||||||
prop.computed = false;
|
prop.computed = false;
|
||||||
const oldInPropertyName = this.state.inPropertyName;
|
const oldInPropertyName = this.state.inPropertyName;
|
||||||
this.state.inPropertyName = true;
|
this.state.inPropertyName = true;
|
||||||
@ -935,20 +989,20 @@ pp.parsePropertyName = function (prop) {
|
|||||||
this.state.inPropertyName = oldInPropertyName;
|
this.state.inPropertyName = oldInPropertyName;
|
||||||
}
|
}
|
||||||
return prop.key;
|
return prop.key;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Initialize empty function node.
|
// Initialize empty function node.
|
||||||
|
|
||||||
pp.initFunction = function (node, isAsync) {
|
initFunction(node: N.Function, isAsync: ?boolean): void {
|
||||||
node.id = null;
|
node.id = null;
|
||||||
node.generator = false;
|
node.generator = false;
|
||||||
node.expression = false;
|
node.expression = false;
|
||||||
node.async = !!isAsync;
|
node.async = !!isAsync;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse object or class method.
|
// Parse object or class method.
|
||||||
|
|
||||||
pp.parseMethod = function (node, isGenerator, isAsync) {
|
parseMethod(node: N.MethodLike, isGenerator?: boolean, isAsync?: boolean): N.MethodLike {
|
||||||
const oldInMethod = this.state.inMethod;
|
const oldInMethod = this.state.inMethod;
|
||||||
this.state.inMethod = node.kind || true;
|
this.state.inMethod = node.kind || true;
|
||||||
this.initFunction(node, isAsync);
|
this.initFunction(node, isAsync);
|
||||||
@ -958,20 +1012,20 @@ pp.parseMethod = function (node, isGenerator, isAsync) {
|
|||||||
this.parseFunctionBody(node);
|
this.parseFunctionBody(node);
|
||||||
this.state.inMethod = oldInMethod;
|
this.state.inMethod = oldInMethod;
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse arrow function expression with given parameters.
|
// Parse arrow function expression with given parameters.
|
||||||
|
|
||||||
pp.parseArrowExpression = function (node, params, isAsync) {
|
parseArrowExpression(node: N.ArrowFunctionExpression, params: N.Expression[], isAsync?: boolean): N.ArrowFunctionExpression {
|
||||||
this.initFunction(node, isAsync);
|
this.initFunction(node, isAsync);
|
||||||
node.params = this.toAssignableList(params, true, "arrow function parameters");
|
node.params = this.toAssignableList(params, true, "arrow function parameters");
|
||||||
this.parseFunctionBody(node, true);
|
this.parseFunctionBody(node, true);
|
||||||
return this.finishNode(node, "ArrowFunctionExpression");
|
return this.finishNode(node, "ArrowFunctionExpression");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.isStrictBody = function (node, isExpression) {
|
isStrictBody(node: { body: N.BlockStatement }, isExpression?: boolean): boolean {
|
||||||
if (!isExpression && node.body.directives.length) {
|
if (!isExpression && node.body.directives.length) {
|
||||||
for (const directive of (node.body.directives: Array<Object>)) {
|
for (const directive of node.body.directives) {
|
||||||
if (directive.value.value === "use strict") {
|
if (directive.value.value === "use strict") {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -979,10 +1033,10 @@ pp.isStrictBody = function (node, isExpression) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse function body and check parameters.
|
// Parse function body and check parameters.
|
||||||
pp.parseFunctionBody = function (node, allowExpression) {
|
parseFunctionBody(node: N.Function, allowExpression?: boolean): void {
|
||||||
const isExpression = allowExpression && !this.match(tt.braceL);
|
const isExpression = allowExpression && !this.match(tt.braceL);
|
||||||
|
|
||||||
const oldInAsync = this.state.inAsync;
|
const oldInAsync = this.state.inAsync;
|
||||||
@ -1021,7 +1075,7 @@ pp.parseFunctionBody = function (node, allowExpression) {
|
|||||||
if (node.id) {
|
if (node.id) {
|
||||||
this.checkLVal(node.id, true, undefined, "function name");
|
this.checkLVal(node.id, true, undefined, "function name");
|
||||||
}
|
}
|
||||||
for (const param of (node.params: Array<Object>)) {
|
for (const param of node.params) {
|
||||||
if (isStrict && param.type !== "Identifier") {
|
if (isStrict && param.type !== "Identifier") {
|
||||||
this.raise(param.start, "Non-simple parameter in strict mode");
|
this.raise(param.start, "Non-simple parameter in strict mode");
|
||||||
}
|
}
|
||||||
@ -1029,7 +1083,7 @@ pp.parseFunctionBody = function (node, allowExpression) {
|
|||||||
}
|
}
|
||||||
this.state.strict = oldStrict;
|
this.state.strict = oldStrict;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses a comma-separated list of expressions, and returns them as
|
// Parses a comma-separated list of expressions, and returns them as
|
||||||
// an array. `close` is the token type that ends the list, and
|
// an array. `close` is the token type that ends the list, and
|
||||||
@ -1037,7 +1091,7 @@ pp.parseFunctionBody = function (node, allowExpression) {
|
|||||||
// nothing in between them to be parsed as `null` (which is needed
|
// nothing in between them to be parsed as `null` (which is needed
|
||||||
// for array literals).
|
// for array literals).
|
||||||
|
|
||||||
pp.parseExprList = function (close, allowEmpty, refShorthandDefaultPos) {
|
parseExprList(close: TokenType, allowEmpty?: boolean, refShorthandDefaultPos?: ?Pos): $ReadOnlyArray<?N.Expression> {
|
||||||
const elts = [];
|
const elts = [];
|
||||||
let first = true;
|
let first = true;
|
||||||
|
|
||||||
@ -1052,9 +1106,9 @@ pp.parseExprList = function (close, allowEmpty, refShorthandDefaultPos) {
|
|||||||
elts.push(this.parseExprListItem(allowEmpty, refShorthandDefaultPos));
|
elts.push(this.parseExprListItem(allowEmpty, refShorthandDefaultPos));
|
||||||
}
|
}
|
||||||
return elts;
|
return elts;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseExprListItem = function (allowEmpty, refShorthandDefaultPos, refNeedsArrowPos) {
|
parseExprListItem(allowEmpty: ?boolean, refShorthandDefaultPos: ?Pos, refNeedsArrowPos: ?Pos): ?N.Expression {
|
||||||
let elt;
|
let elt;
|
||||||
if (allowEmpty && this.match(tt.comma)) {
|
if (allowEmpty && this.match(tt.comma)) {
|
||||||
elt = null;
|
elt = null;
|
||||||
@ -1064,13 +1118,13 @@ pp.parseExprListItem = function (allowEmpty, refShorthandDefaultPos, refNeedsArr
|
|||||||
elt = this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem, refNeedsArrowPos);
|
elt = this.parseMaybeAssign(false, refShorthandDefaultPos, this.parseParenItem, refNeedsArrowPos);
|
||||||
}
|
}
|
||||||
return elt;
|
return elt;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse the next token as an identifier. If `liberal` is true (used
|
// Parse the next token as an identifier. If `liberal` is true (used
|
||||||
// when parsing properties), it will also convert keywords into
|
// when parsing properties), it will also convert keywords into
|
||||||
// identifiers.
|
// identifiers.
|
||||||
|
|
||||||
pp.parseIdentifier = function (liberal) {
|
parseIdentifier(liberal?: boolean): N.Identifier {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
if (!liberal) {
|
if (!liberal) {
|
||||||
this.checkReservedWord(this.state.value, this.state.start, !!this.state.type.keyword, false);
|
this.checkReservedWord(this.state.value, this.state.start, !!this.state.type.keyword, false);
|
||||||
@ -1092,9 +1146,9 @@ pp.parseIdentifier = function (liberal) {
|
|||||||
|
|
||||||
this.next();
|
this.next();
|
||||||
return this.finishNode(node, "Identifier");
|
return this.finishNode(node, "Identifier");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.checkReservedWord = function (word, startLoc, checkKeywords, isBinding) {
|
checkReservedWord(word: string, startLoc: number, checkKeywords: boolean, isBinding: boolean): void {
|
||||||
if (this.isReservedWord(word) || (checkKeywords && this.isKeyword(word))) {
|
if (this.isReservedWord(word) || (checkKeywords && this.isKeyword(word))) {
|
||||||
this.raise(startLoc, word + " is a reserved word");
|
this.raise(startLoc, word + " is a reserved word");
|
||||||
}
|
}
|
||||||
@ -1102,11 +1156,11 @@ pp.checkReservedWord = function (word, startLoc, checkKeywords, isBinding) {
|
|||||||
if (this.state.strict && (reservedWords.strict(word) || (isBinding && reservedWords.strictBind(word)))) {
|
if (this.state.strict && (reservedWords.strict(word) || (isBinding && reservedWords.strictBind(word)))) {
|
||||||
this.raise(startLoc, word + " is a reserved word in strict mode");
|
this.raise(startLoc, word + " is a reserved word in strict mode");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses await expression inside async function.
|
// Parses await expression inside async function.
|
||||||
|
|
||||||
pp.parseAwait = function (node) {
|
parseAwait(node: N.AwaitExpression): N.AwaitExpression {
|
||||||
// istanbul ignore next: this condition is checked at the call site so won't be hit here
|
// istanbul ignore next: this condition is checked at the call site so won't be hit here
|
||||||
if (!this.state.inAsync) {
|
if (!this.state.inAsync) {
|
||||||
this.unexpected();
|
this.unexpected();
|
||||||
@ -1116,11 +1170,11 @@ pp.parseAwait = function (node) {
|
|||||||
}
|
}
|
||||||
node.argument = this.parseMaybeUnary();
|
node.argument = this.parseMaybeUnary();
|
||||||
return this.finishNode(node, "AwaitExpression");
|
return this.finishNode(node, "AwaitExpression");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses yield expression inside generator.
|
// Parses yield expression inside generator.
|
||||||
|
|
||||||
pp.parseYield = function () {
|
parseYield(): N.YieldExpression {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
if (
|
if (
|
||||||
@ -1135,4 +1189,5 @@ pp.parseYield = function () {
|
|||||||
node.argument = this.parseMaybeAssign();
|
node.argument = this.parseMaybeAssign();
|
||||||
}
|
}
|
||||||
return this.finishNode(node, "YieldExpression");
|
return this.finishNode(node, "YieldExpression");
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,18 +1,21 @@
|
|||||||
import { reservedWords } from "../util/identifier";
|
// @flow
|
||||||
|
|
||||||
|
import type { Options } from "../options";
|
||||||
|
import type { File } from "../types";
|
||||||
import { getOptions } from "../options";
|
import { getOptions } from "../options";
|
||||||
import Tokenizer from "../tokenizer";
|
import StatementParser from "./statement";
|
||||||
|
|
||||||
export const plugins = {};
|
export const plugins: { [name: string]: (superClass: Class<Parser>) => Class<Parser> } = {};
|
||||||
|
|
||||||
export default class Parser extends Tokenizer {
|
export default class Parser extends StatementParser {
|
||||||
constructor(options: Object, input: string) {
|
constructor(options: ?Options, input: string) {
|
||||||
options = getOptions(options);
|
options = getOptions(options);
|
||||||
super(options, input);
|
super(options, input);
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
this.inModule = this.options.sourceType === "module";
|
this.inModule = this.options.sourceType === "module";
|
||||||
this.input = input;
|
this.input = input;
|
||||||
this.plugins = this.loadPlugins(this.options.plugins);
|
this.plugins = pluginsMap(this.options.plugins);
|
||||||
this.filename = options.sourceFilename;
|
this.filename = options.sourceFilename;
|
||||||
|
|
||||||
// If enabled, skip leading hashbang line.
|
// If enabled, skip leading hashbang line.
|
||||||
@ -21,59 +24,18 @@ export default class Parser extends Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isReservedWord(word: string): boolean {
|
parse(): File {
|
||||||
if (word === "await") {
|
|
||||||
return this.inModule;
|
|
||||||
} else {
|
|
||||||
return reservedWords[6](word);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hasPlugin(name: string): boolean {
|
|
||||||
return !!this.plugins[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
extend(name: string, f: Function) {
|
|
||||||
this[name] = f(this[name]);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadPlugins(pluginList: Array<string>): { [key: string]: boolean } {
|
|
||||||
const pluginMap = {};
|
|
||||||
|
|
||||||
if (pluginList.indexOf("flow") >= 0) {
|
|
||||||
// ensure flow plugin loads last
|
|
||||||
pluginList = pluginList.filter((plugin) => plugin !== "flow");
|
|
||||||
pluginList.push("flow");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pluginList.indexOf("estree") >= 0) {
|
|
||||||
// ensure estree plugin loads first
|
|
||||||
pluginList = pluginList.filter((plugin) => plugin !== "estree");
|
|
||||||
pluginList.unshift("estree");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const name of pluginList) {
|
|
||||||
if (!pluginMap[name]) {
|
|
||||||
pluginMap[name] = true;
|
|
||||||
|
|
||||||
const plugin = plugins[name];
|
|
||||||
if (plugin) plugin(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return pluginMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
parse(): {
|
|
||||||
type: "File",
|
|
||||||
program: {
|
|
||||||
type: "Program",
|
|
||||||
body: Array<Object>
|
|
||||||
}
|
|
||||||
} {
|
|
||||||
const file = this.startNode();
|
const file = this.startNode();
|
||||||
const program = this.startNode();
|
const program = this.startNode();
|
||||||
this.nextToken();
|
this.nextToken();
|
||||||
return this.parseTopLevel(file, program);
|
return this.parseTopLevel(file, program);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pluginsMap(pluginList: $ReadOnlyArray<string>): { [key: string]: boolean } {
|
||||||
|
const pluginMap = {};
|
||||||
|
for (const name of pluginList) {
|
||||||
|
pluginMap[name] = true;
|
||||||
|
}
|
||||||
|
return pluginMap;
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { getLineInfo } from "../util/location";
|
// @flow
|
||||||
import Parser from "./index";
|
|
||||||
|
|
||||||
const pp = Parser.prototype;
|
import { getLineInfo } from "../util/location";
|
||||||
|
import CommentsParser from "./comments";
|
||||||
|
|
||||||
// This function is used to raise exceptions on parse errors. It
|
// This function is used to raise exceptions on parse errors. It
|
||||||
// takes an offset integer (into the current `input`) to indicate
|
// takes an offset integer (into the current `input`) to indicate
|
||||||
@ -9,11 +9,14 @@ const pp = Parser.prototype;
|
|||||||
// of the error message, and then raises a `SyntaxError` with that
|
// of the error message, and then raises a `SyntaxError` with that
|
||||||
// message.
|
// message.
|
||||||
|
|
||||||
pp.raise = function (pos, message) {
|
export default class LocationParser extends CommentsParser {
|
||||||
|
raise(pos: number, message: string): empty {
|
||||||
const loc = getLineInfo(this.input, pos);
|
const loc = getLineInfo(this.input, pos);
|
||||||
message += ` (${loc.line}:${loc.column})`;
|
message += ` (${loc.line}:${loc.column})`;
|
||||||
const err = new SyntaxError(message);
|
// $FlowIgnore
|
||||||
|
const err: SyntaxError & { pos: number, loc: Position } = new SyntaxError(message);
|
||||||
err.pos = pos;
|
err.pos = pos;
|
||||||
err.loc = loc;
|
err.loc = loc;
|
||||||
throw err;
|
throw err;
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,15 +1,32 @@
|
|||||||
import { types as tt } from "../tokenizer/types";
|
// @flow
|
||||||
import Parser from "./index";
|
|
||||||
|
|
||||||
const pp = Parser.prototype;
|
import { types as tt, type TokenType } from "../tokenizer/types";
|
||||||
|
import type { Decorator, Expression, Identifier, Node, ObjectExpression, ObjectPattern, Pattern, RestElement,
|
||||||
|
SpreadElement } from "../types";
|
||||||
|
import type { Pos, Position } from "../util/location";
|
||||||
|
import { NodeUtils } from "./node";
|
||||||
|
|
||||||
|
export default class LValParser extends NodeUtils {
|
||||||
|
// Forward-declaration: defined in expression.js
|
||||||
|
+checkReservedWord: (word: string, startLoc: number, checkKeywords: boolean, isBinding: boolean) => void;
|
||||||
|
+parseIdentifier: (liberal?: boolean) => Identifier;
|
||||||
|
+parseMaybeAssign: (
|
||||||
|
noIn?: ?boolean,
|
||||||
|
refShorthandDefaultPos?: ?Pos,
|
||||||
|
afterLeftParse?: Function,
|
||||||
|
refNeedsArrowPos?: ?Pos) => Expression;
|
||||||
|
+parseObj: <T : ObjectPattern | ObjectExpression>(isPattern: boolean, refShorthandDefaultPos?: ?Pos) => T;
|
||||||
|
// Forward-declaration: defined in statement.js
|
||||||
|
+parseDecorator: () => Decorator;
|
||||||
|
|
||||||
// Convert existing expression atom to assignable pattern
|
// Convert existing expression atom to assignable pattern
|
||||||
// if possible.
|
// if possible.
|
||||||
|
|
||||||
pp.toAssignable = function (node, isBinding, contextDescription) {
|
toAssignable(node: Node, isBinding: ?boolean, contextDescription: string): Node {
|
||||||
if (node) {
|
if (node) {
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case "Identifier":
|
case "Identifier":
|
||||||
|
case "PrivateName":
|
||||||
case "ObjectPattern":
|
case "ObjectPattern":
|
||||||
case "ArrayPattern":
|
case "ArrayPattern":
|
||||||
case "AssignmentPattern":
|
case "AssignmentPattern":
|
||||||
@ -17,7 +34,7 @@ pp.toAssignable = function (node, isBinding, contextDescription) {
|
|||||||
|
|
||||||
case "ObjectExpression":
|
case "ObjectExpression":
|
||||||
node.type = "ObjectPattern";
|
node.type = "ObjectPattern";
|
||||||
for (const prop of (node.properties: Array<Object>)) {
|
for (const prop of node.properties) {
|
||||||
if (prop.type === "ObjectMethod") {
|
if (prop.type === "ObjectMethod") {
|
||||||
if (prop.kind === "get" || prop.kind === "set") {
|
if (prop.kind === "get" || prop.kind === "set") {
|
||||||
this.raise(prop.key.start, "Object pattern can't contain getter or setter");
|
this.raise(prop.key.start, "Object pattern can't contain getter or setter");
|
||||||
@ -36,6 +53,8 @@ pp.toAssignable = function (node, isBinding, contextDescription) {
|
|||||||
|
|
||||||
case "SpreadElement":
|
case "SpreadElement":
|
||||||
node.type = "RestElement";
|
node.type = "RestElement";
|
||||||
|
const arg = node.argument;
|
||||||
|
this.toAssignable(arg, isBinding, contextDescription);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ArrayExpression":
|
case "ArrayExpression":
|
||||||
@ -63,11 +82,12 @@ pp.toAssignable = function (node, isBinding, contextDescription) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Convert list of expression atoms to binding list.
|
// Convert list of expression atoms to binding list.
|
||||||
|
|
||||||
pp.toAssignableList = function (exprList, isBinding, contextDescription) {
|
toAssignableList(
|
||||||
|
exprList: Expression[], isBinding: ?boolean, contextDescription: string): $ReadOnlyArray<Pattern> {
|
||||||
let end = exprList.length;
|
let end = exprList.length;
|
||||||
if (end) {
|
if (end) {
|
||||||
const last = exprList[end - 1];
|
const last = exprList[end - 1];
|
||||||
@ -77,7 +97,11 @@ pp.toAssignableList = function (exprList, isBinding, contextDescription) {
|
|||||||
last.type = "RestElement";
|
last.type = "RestElement";
|
||||||
const arg = last.argument;
|
const arg = last.argument;
|
||||||
this.toAssignable(arg, isBinding, contextDescription);
|
this.toAssignable(arg, isBinding, contextDescription);
|
||||||
if (arg.type !== "Identifier" && arg.type !== "MemberExpression" && arg.type !== "ArrayPattern") {
|
if (
|
||||||
|
arg.type !== "Identifier" &&
|
||||||
|
arg.type !== "MemberExpression" &&
|
||||||
|
arg.type !== "ArrayPattern"
|
||||||
|
) {
|
||||||
this.unexpected(arg.start);
|
this.unexpected(arg.start);
|
||||||
}
|
}
|
||||||
--end;
|
--end;
|
||||||
@ -90,40 +114,40 @@ pp.toAssignableList = function (exprList, isBinding, contextDescription) {
|
|||||||
if (elt) this.toAssignable(elt, isBinding, contextDescription);
|
if (elt) this.toAssignable(elt, isBinding, contextDescription);
|
||||||
}
|
}
|
||||||
return exprList;
|
return exprList;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Convert list of expression atoms to a list of
|
// Convert list of expression atoms to a list of
|
||||||
|
|
||||||
pp.toReferencedList = function (exprList) {
|
toReferencedList(exprList: $ReadOnlyArray<?Expression>): $ReadOnlyArray<?Expression> {
|
||||||
return exprList;
|
return exprList;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses spread element.
|
// Parses spread element.
|
||||||
|
|
||||||
pp.parseSpread = function (refShorthandDefaultPos) {
|
parseSpread<T : RestElement | SpreadElement>(refShorthandDefaultPos: ?Pos): T {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
node.argument = this.parseMaybeAssign(false, refShorthandDefaultPos);
|
node.argument = this.parseMaybeAssign(false, refShorthandDefaultPos);
|
||||||
return this.finishNode(node, "SpreadElement");
|
return this.finishNode(node, "SpreadElement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseRest = function () {
|
parseRest(): RestElement {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
node.argument = this.parseBindingAtom();
|
node.argument = this.parseBindingAtom();
|
||||||
return this.finishNode(node, "RestElement");
|
return this.finishNode(node, "RestElement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.shouldAllowYieldIdentifier = function () {
|
shouldAllowYieldIdentifier(): boolean {
|
||||||
return this.match(tt._yield) && !this.state.strict && !this.state.inGenerator;
|
return this.match(tt._yield) && !this.state.strict && !this.state.inGenerator;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseBindingIdentifier = function () {
|
parseBindingIdentifier(): Identifier {
|
||||||
return this.parseIdentifier(this.shouldAllowYieldIdentifier());
|
return this.parseIdentifier(this.shouldAllowYieldIdentifier());
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses lvalue (assignable) atom.
|
// Parses lvalue (assignable) atom.
|
||||||
pp.parseBindingAtom = function () {
|
parseBindingAtom(): Pattern {
|
||||||
switch (this.state.type) {
|
switch (this.state.type) {
|
||||||
case tt._yield:
|
case tt._yield:
|
||||||
case tt.name:
|
case tt.name:
|
||||||
@ -139,11 +163,11 @@ pp.parseBindingAtom = function () {
|
|||||||
return this.parseObj(true);
|
return this.parseObj(true);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.unexpected();
|
throw this.unexpected();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
pp.parseBindingList = function (close, allowEmpty) {
|
parseBindingList(close: TokenType, allowEmpty?: boolean): $ReadOnlyArray<Pattern> {
|
||||||
const elts = [];
|
const elts = [];
|
||||||
let first = true;
|
let first = true;
|
||||||
while (!this.eat(close)) {
|
while (!this.eat(close)) {
|
||||||
@ -153,6 +177,7 @@ pp.parseBindingList = function (close, allowEmpty) {
|
|||||||
this.expect(tt.comma);
|
this.expect(tt.comma);
|
||||||
}
|
}
|
||||||
if (allowEmpty && this.match(tt.comma)) {
|
if (allowEmpty && this.match(tt.comma)) {
|
||||||
|
// $FlowFixMe This method returns `$ReadOnlyArray<?Pattern>` if `allowEmpty` is set.
|
||||||
elts.push(null);
|
elts.push(null);
|
||||||
} else if (this.eat(close)) {
|
} else if (this.eat(close)) {
|
||||||
break;
|
break;
|
||||||
@ -174,15 +199,15 @@ pp.parseBindingList = function (close, allowEmpty) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return elts;
|
return elts;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseAssignableListItemTypes = function (param) {
|
parseAssignableListItemTypes(param: Pattern): Pattern {
|
||||||
return param;
|
return param;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses assignment pattern around given atom if possible.
|
// Parses assignment pattern around given atom if possible.
|
||||||
|
|
||||||
pp.parseMaybeDefault = function (startPos, startLoc, left) {
|
parseMaybeDefault(startPos?: ?number, startLoc?: ?Position, left?: ?Pattern): Pattern {
|
||||||
startLoc = startLoc || this.state.startLoc;
|
startLoc = startLoc || this.state.startLoc;
|
||||||
startPos = startPos || this.state.start;
|
startPos = startPos || this.state.start;
|
||||||
left = left || this.parseBindingAtom();
|
left = left || this.parseBindingAtom();
|
||||||
@ -192,13 +217,18 @@ pp.parseMaybeDefault = function (startPos, startLoc, left) {
|
|||||||
node.left = left;
|
node.left = left;
|
||||||
node.right = this.parseMaybeAssign();
|
node.right = this.parseMaybeAssign();
|
||||||
return this.finishNode(node, "AssignmentPattern");
|
return this.finishNode(node, "AssignmentPattern");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Verify that a node is an lval — something that can be assigned
|
// Verify that a node is an lval — something that can be assigned
|
||||||
// to.
|
// to.
|
||||||
|
|
||||||
pp.checkLVal = function (expr, isBinding, checkClashes, contextDescription) {
|
checkLVal(
|
||||||
|
expr: Expression,
|
||||||
|
isBinding: ?boolean,
|
||||||
|
checkClashes: ?{ [key: string]: boolean },
|
||||||
|
contextDescription: string): void {
|
||||||
switch (expr.type) {
|
switch (expr.type) {
|
||||||
|
case "PrivateName":
|
||||||
case "Identifier":
|
case "Identifier":
|
||||||
this.checkReservedWord(expr.name, expr.start, false, true);
|
this.checkReservedWord(expr.name, expr.start, false, true);
|
||||||
|
|
||||||
@ -225,18 +255,19 @@ pp.checkLVal = function (expr, isBinding, checkClashes, contextDescription) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "MemberExpression":
|
case "MemberExpression":
|
||||||
if (isBinding) this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression");
|
if (isBinding)
|
||||||
|
this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " member expression");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ObjectPattern":
|
case "ObjectPattern":
|
||||||
for (let prop of (expr.properties: Array<Object>)) {
|
for (let prop of expr.properties) {
|
||||||
if (prop.type === "ObjectProperty") prop = prop.value;
|
if (prop.type === "ObjectProperty") prop = prop.value;
|
||||||
this.checkLVal(prop, isBinding, checkClashes, "object destructuring pattern");
|
this.checkLVal(prop, isBinding, checkClashes, "object destructuring pattern");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "ArrayPattern":
|
case "ArrayPattern":
|
||||||
for (const elem of (expr.elements: Array<Object>)) {
|
for (const elem of expr.elements) {
|
||||||
if (elem) this.checkLVal(elem, isBinding, checkClashes, "array destructuring pattern");
|
if (elem) this.checkLVal(elem, isBinding, checkClashes, "array destructuring pattern");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -256,4 +287,5 @@ pp.checkLVal = function (expr, isBinding, checkClashes, contextDescription) {
|
|||||||
this.raise(expr.start, message);
|
this.raise(expr.start, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
import Parser from "./index";
|
import Parser from "./index";
|
||||||
|
import UtilParser from "./util";
|
||||||
import { SourceLocation, type Position } from "../util/location";
|
import { SourceLocation, type Position } from "../util/location";
|
||||||
|
import type { Comment, Node as NodeType, NodeBase } from "../types";
|
||||||
|
|
||||||
// Start an AST node, attaching a start offset.
|
// Start an AST node, attaching a start offset.
|
||||||
|
|
||||||
const pp = Parser.prototype;
|
|
||||||
const commentKeys = ["leadingComments", "trailingComments", "innerComments"];
|
const commentKeys = ["leadingComments", "trailingComments", "innerComments"];
|
||||||
|
|
||||||
class Node {
|
class Node implements NodeBase {
|
||||||
constructor(parser?: Parser, pos?: number, loc?: Position) {
|
constructor(parser: Parser, pos: number, loc: Position) {
|
||||||
this.type = "";
|
this.type = "";
|
||||||
this.start = pos;
|
this.start = pos;
|
||||||
this.end = 0;
|
this.end = 0;
|
||||||
@ -17,15 +20,22 @@ class Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type: string;
|
type: string;
|
||||||
start: ?number;
|
start: number;
|
||||||
end: number;
|
end: number;
|
||||||
loc: SourceLocation;
|
loc: SourceLocation;
|
||||||
|
range: [number, number];
|
||||||
|
leadingComments: ?Array<Comment>;
|
||||||
|
trailingComments: ?Array<Comment>;
|
||||||
|
innerComments: ?Array<Comment>;
|
||||||
|
extra: { [key: string]: any };
|
||||||
|
|
||||||
__clone(): Node {
|
__clone(): this {
|
||||||
const node2 = new Node;
|
// $FlowIgnore
|
||||||
|
const node2: any = new Node;
|
||||||
for (const key in this) {
|
for (const key in this) {
|
||||||
// Do not clone comments that are already attached to the node
|
// Do not clone comments that are already attached to the node
|
||||||
if (commentKeys.indexOf(key) < 0) {
|
if (commentKeys.indexOf(key) < 0) {
|
||||||
|
// $FlowIgnore
|
||||||
node2[key] = this[key];
|
node2[key] = this[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,15 +44,26 @@ class Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pp.startNode = function () {
|
export class NodeUtils extends UtilParser {
|
||||||
|
startNode<T : NodeType>(): T {
|
||||||
|
// $FlowIgnore
|
||||||
return new Node(this, this.state.start, this.state.startLoc);
|
return new Node(this, this.state.start, this.state.startLoc);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.startNodeAt = function (pos, loc) {
|
startNodeAt<T : NodeType>(pos: number, loc: Position): T {
|
||||||
|
// $FlowIgnore
|
||||||
return new Node(this, pos, loc);
|
return new Node(this, pos, loc);
|
||||||
};
|
}
|
||||||
|
|
||||||
function finishNodeAt(node, type, pos, loc) {
|
// Finish an AST node, adding `type` and `end` properties.
|
||||||
|
|
||||||
|
finishNode<T : NodeType>(node: T, type: string): T {
|
||||||
|
return this.finishNodeAt(node, type, this.state.lastTokEnd, this.state.lastTokEndLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish node at given position
|
||||||
|
|
||||||
|
finishNodeAt<T : NodeType>(node: T, type: string, pos: number, loc: Position): T {
|
||||||
node.type = type;
|
node.type = type;
|
||||||
node.end = pos;
|
node.end = pos;
|
||||||
node.loc.end = loc;
|
node.loc.end = loc;
|
||||||
@ -51,26 +72,12 @@ function finishNodeAt(node, type, pos, loc) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish an AST node, adding `type` and `end` properties.
|
|
||||||
|
|
||||||
pp.finishNode = function (node, type) {
|
|
||||||
return finishNodeAt.call(this, node, type, this.state.lastTokEnd, this.state.lastTokEndLoc);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Finish node at given position
|
|
||||||
|
|
||||||
pp.finishNodeAt = function (node, type, pos, loc) {
|
|
||||||
return finishNodeAt.call(this, node, type, pos, loc);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the start location of node to the start location of locationNode
|
* Reset the start location of node to the start location of locationNode
|
||||||
*/
|
*/
|
||||||
pp.resetStartLocationFromNode = function (node, locationNode) {
|
resetStartLocationFromNode(node: NodeBase, locationNode: NodeBase): void {
|
||||||
node.start = locationNode.start;
|
node.start = locationNode.start;
|
||||||
node.loc.start = locationNode.loc.start;
|
node.loc.start = locationNode.loc.start;
|
||||||
if (this.options.ranges) node.range[0] = locationNode.range[0];
|
if (this.options.ranges) node.range[0] = locationNode.range[0];
|
||||||
|
}
|
||||||
return node;
|
}
|
||||||
};
|
|
||||||
|
|||||||
@ -1,10 +1,20 @@
|
|||||||
/* eslint max-len: 0 */
|
/* eslint max-len: 0 */
|
||||||
|
|
||||||
import { types as tt } from "../tokenizer/types";
|
// @flow
|
||||||
import Parser from "./index";
|
|
||||||
|
import * as N from "../types";
|
||||||
|
import { types as tt, TokenType } from "../tokenizer/types";
|
||||||
|
import ExpressionParser from "./expression";
|
||||||
|
import type { Position } from "../util/location";
|
||||||
import { lineBreak } from "../util/whitespace";
|
import { lineBreak } from "../util/whitespace";
|
||||||
|
|
||||||
const pp = Parser.prototype;
|
// Reused empty array added for node fields that are always empty.
|
||||||
|
|
||||||
|
const empty = [];
|
||||||
|
|
||||||
|
const loopLabel = { kind: "loop" }, switchLabel = { kind: "switch" };
|
||||||
|
|
||||||
|
export default class StatementParser extends ExpressionParser {
|
||||||
|
|
||||||
// ### Statement parsing
|
// ### Statement parsing
|
||||||
|
|
||||||
@ -13,7 +23,7 @@ const pp = Parser.prototype;
|
|||||||
// `program` argument. If present, the statements will be appended
|
// `program` argument. If present, the statements will be appended
|
||||||
// to its body instead of creating a new node.
|
// to its body instead of creating a new node.
|
||||||
|
|
||||||
pp.parseTopLevel = function (file, program) {
|
parseTopLevel(file: N.File, program: N.Program): N.File {
|
||||||
program.sourceType = this.options.sourceType;
|
program.sourceType = this.options.sourceType;
|
||||||
|
|
||||||
this.parseBlockBody(program, true, true, tt.eof);
|
this.parseBlockBody(program, true, true, tt.eof);
|
||||||
@ -23,13 +33,11 @@ pp.parseTopLevel = function (file, program) {
|
|||||||
file.tokens = this.state.tokens;
|
file.tokens = this.state.tokens;
|
||||||
|
|
||||||
return this.finishNode(file, "File");
|
return this.finishNode(file, "File");
|
||||||
};
|
}
|
||||||
|
|
||||||
const loopLabel = { kind: "loop" }, switchLabel = { kind: "switch" };
|
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
pp.stmtToDirective = function (stmt) {
|
stmtToDirective(stmt: N.Statement): N.Directive {
|
||||||
const expr = stmt.expression;
|
const expr = stmt.expression;
|
||||||
|
|
||||||
const directiveLiteral = this.startNodeAt(expr.start, expr.loc.start);
|
const directiveLiteral = this.startNodeAt(expr.start, expr.loc.start);
|
||||||
@ -44,7 +52,7 @@ pp.stmtToDirective = function (stmt) {
|
|||||||
directive.value = this.finishNodeAt(directiveLiteral, "DirectiveLiteral", expr.end, expr.loc.end);
|
directive.value = this.finishNodeAt(directiveLiteral, "DirectiveLiteral", expr.end, expr.loc.end);
|
||||||
|
|
||||||
return this.finishNodeAt(directive, "Directive", stmt.end, stmt.loc.end);
|
return this.finishNodeAt(directive, "Directive", stmt.end, stmt.loc.end);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse a single statement.
|
// Parse a single statement.
|
||||||
//
|
//
|
||||||
@ -53,7 +61,7 @@ pp.stmtToDirective = function (stmt) {
|
|||||||
// `if (foo) /blah/.exec(foo)`, where looking at the previous token
|
// `if (foo) /blah/.exec(foo)`, where looking at the previous token
|
||||||
// does not help.
|
// does not help.
|
||||||
|
|
||||||
pp.parseStatement = function (declaration, topLevel) {
|
parseStatement(declaration: boolean, topLevel?: boolean): N.Statement {
|
||||||
if (this.match(tt.at)) {
|
if (this.match(tt.at)) {
|
||||||
this.parseDecorators(true);
|
this.parseDecorators(true);
|
||||||
}
|
}
|
||||||
@ -66,6 +74,7 @@ pp.parseStatement = function (declaration, topLevel) {
|
|||||||
// complexity.
|
// complexity.
|
||||||
|
|
||||||
switch (starttype) {
|
switch (starttype) {
|
||||||
|
// $FlowFixMe
|
||||||
case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword);
|
case tt._break: case tt._continue: return this.parseBreakContinueStatement(node, starttype.keyword);
|
||||||
case tt._debugger: return this.parseDebuggerStatement(node);
|
case tt._debugger: return this.parseDebuggerStatement(node);
|
||||||
case tt._do: return this.parseDoStatement(node);
|
case tt._do: return this.parseDoStatement(node);
|
||||||
@ -137,16 +146,16 @@ pp.parseStatement = function (declaration, topLevel) {
|
|||||||
} else {
|
} else {
|
||||||
return this.parseExpressionStatement(node, expr);
|
return this.parseExpressionStatement(node, expr);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.takeDecorators = function (node) {
|
takeDecorators(node: N.HasDecorators): void {
|
||||||
if (this.state.decorators.length) {
|
if (this.state.decorators.length) {
|
||||||
node.decorators = this.state.decorators;
|
node.decorators = this.state.decorators;
|
||||||
this.state.decorators = [];
|
this.state.decorators = [];
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseDecorators = function (allowExport) {
|
parseDecorators(allowExport?: boolean): void {
|
||||||
while (this.match(tt.at)) {
|
while (this.match(tt.at)) {
|
||||||
const decorator = this.parseDecorator();
|
const decorator = this.parseDecorator();
|
||||||
this.state.decorators.push(decorator);
|
this.state.decorators.push(decorator);
|
||||||
@ -159,9 +168,9 @@ pp.parseDecorators = function (allowExport) {
|
|||||||
if (!this.match(tt._class)) {
|
if (!this.match(tt._class)) {
|
||||||
this.raise(this.state.start, "Leading decorators must be attached to a class declaration");
|
this.raise(this.state.start, "Leading decorators must be attached to a class declaration");
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseDecorator = function () {
|
parseDecorator(): N.Decorator {
|
||||||
if (!this.hasPlugin("decorators")) {
|
if (!this.hasPlugin("decorators")) {
|
||||||
this.unexpected();
|
this.unexpected();
|
||||||
}
|
}
|
||||||
@ -169,9 +178,9 @@ pp.parseDecorator = function () {
|
|||||||
this.next();
|
this.next();
|
||||||
node.expression = this.parseMaybeAssign();
|
node.expression = this.parseMaybeAssign();
|
||||||
return this.finishNode(node, "Decorator");
|
return this.finishNode(node, "Decorator");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseBreakContinueStatement = function (node, keyword) {
|
parseBreakContinueStatement(node: N.BreakStatement | N.ContinueStatement, keyword: string): N.BreakStatement | N.ContinueStatement {
|
||||||
const isBreak = keyword === "break";
|
const isBreak = keyword === "break";
|
||||||
this.next();
|
this.next();
|
||||||
|
|
||||||
@ -196,15 +205,15 @@ pp.parseBreakContinueStatement = function (node, keyword) {
|
|||||||
}
|
}
|
||||||
if (i === this.state.labels.length) this.raise(node.start, "Unsyntactic " + keyword);
|
if (i === this.state.labels.length) this.raise(node.start, "Unsyntactic " + keyword);
|
||||||
return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
|
return this.finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseDebuggerStatement = function (node) {
|
parseDebuggerStatement(node: N.DebuggerStatement): N.DebuggerStatement {
|
||||||
this.next();
|
this.next();
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
return this.finishNode(node, "DebuggerStatement");
|
return this.finishNode(node, "DebuggerStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseDoStatement = function (node) {
|
parseDoStatement(node: N.DoWhileStatement): N.DoWhileStatement {
|
||||||
this.next();
|
this.next();
|
||||||
this.state.labels.push(loopLabel);
|
this.state.labels.push(loopLabel);
|
||||||
node.body = this.parseStatement(false);
|
node.body = this.parseStatement(false);
|
||||||
@ -213,7 +222,7 @@ pp.parseDoStatement = function (node) {
|
|||||||
node.test = this.parseParenExpression();
|
node.test = this.parseParenExpression();
|
||||||
this.eat(tt.semi);
|
this.eat(tt.semi);
|
||||||
return this.finishNode(node, "DoWhileStatement");
|
return this.finishNode(node, "DoWhileStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Disambiguating between a `for` and a `for`/`in` or `for`/`of`
|
// Disambiguating between a `for` and a `for`/`in` or `for`/`of`
|
||||||
// loop is non-trivial. Basically, we have to parse the init `var`
|
// loop is non-trivial. Basically, we have to parse the init `var`
|
||||||
@ -223,7 +232,7 @@ pp.parseDoStatement = function (node) {
|
|||||||
// part (semicolon immediately after the opening parenthesis), it
|
// part (semicolon immediately after the opening parenthesis), it
|
||||||
// is a regular `for` loop.
|
// is a regular `for` loop.
|
||||||
|
|
||||||
pp.parseForStatement = function (node) {
|
parseForStatement(node: N.Node): N.ForLike {
|
||||||
this.next();
|
this.next();
|
||||||
this.state.labels.push(loopLabel);
|
this.state.labels.push(loopLabel);
|
||||||
|
|
||||||
@ -273,22 +282,22 @@ pp.parseForStatement = function (node) {
|
|||||||
this.unexpected();
|
this.unexpected();
|
||||||
}
|
}
|
||||||
return this.parseFor(node, init);
|
return this.parseFor(node, init);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseFunctionStatement = function (node) {
|
parseFunctionStatement(node: N.FunctionDeclaration): N.FunctionDeclaration {
|
||||||
this.next();
|
this.next();
|
||||||
return this.parseFunction(node, true);
|
return this.parseFunction(node, true);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseIfStatement = function (node) {
|
parseIfStatement(node: N.IfStatement): N.IfStatement {
|
||||||
this.next();
|
this.next();
|
||||||
node.test = this.parseParenExpression();
|
node.test = this.parseParenExpression();
|
||||||
node.consequent = this.parseStatement(false);
|
node.consequent = this.parseStatement(false);
|
||||||
node.alternate = this.eat(tt._else) ? this.parseStatement(false) : null;
|
node.alternate = this.eat(tt._else) ? this.parseStatement(false) : null;
|
||||||
return this.finishNode(node, "IfStatement");
|
return this.finishNode(node, "IfStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseReturnStatement = function (node) {
|
parseReturnStatement(node: N.ReturnStatement): N.ReturnStatement {
|
||||||
if (!this.state.inFunction && !this.options.allowReturnOutsideFunction) {
|
if (!this.state.inFunction && !this.options.allowReturnOutsideFunction) {
|
||||||
this.raise(this.state.start, "'return' outside of function");
|
this.raise(this.state.start, "'return' outside of function");
|
||||||
}
|
}
|
||||||
@ -307,12 +316,12 @@ pp.parseReturnStatement = function (node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.finishNode(node, "ReturnStatement");
|
return this.finishNode(node, "ReturnStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseSwitchStatement = function (node) {
|
parseSwitchStatement(node: N.SwitchStatement): N.SwitchStatement {
|
||||||
this.next();
|
this.next();
|
||||||
node.discriminant = this.parseParenExpression();
|
node.discriminant = this.parseParenExpression();
|
||||||
node.cases = [];
|
const cases = node.cases = [];
|
||||||
this.expect(tt.braceL);
|
this.expect(tt.braceL);
|
||||||
this.state.labels.push(switchLabel);
|
this.state.labels.push(switchLabel);
|
||||||
|
|
||||||
@ -325,7 +334,7 @@ pp.parseSwitchStatement = function (node) {
|
|||||||
if (this.match(tt._case) || this.match(tt._default)) {
|
if (this.match(tt._case) || this.match(tt._default)) {
|
||||||
const isCase = this.match(tt._case);
|
const isCase = this.match(tt._case);
|
||||||
if (cur) this.finishNode(cur, "SwitchCase");
|
if (cur) this.finishNode(cur, "SwitchCase");
|
||||||
node.cases.push(cur = this.startNode());
|
cases.push(cur = this.startNode());
|
||||||
cur.consequent = [];
|
cur.consequent = [];
|
||||||
this.next();
|
this.next();
|
||||||
if (isCase) {
|
if (isCase) {
|
||||||
@ -348,22 +357,18 @@ pp.parseSwitchStatement = function (node) {
|
|||||||
this.next(); // Closing brace
|
this.next(); // Closing brace
|
||||||
this.state.labels.pop();
|
this.state.labels.pop();
|
||||||
return this.finishNode(node, "SwitchStatement");
|
return this.finishNode(node, "SwitchStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseThrowStatement = function (node) {
|
parseThrowStatement(node: N.ThrowStatement): N.ThrowStatement {
|
||||||
this.next();
|
this.next();
|
||||||
if (lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start)))
|
if (lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start)))
|
||||||
this.raise(this.state.lastTokEnd, "Illegal newline after throw");
|
this.raise(this.state.lastTokEnd, "Illegal newline after throw");
|
||||||
node.argument = this.parseExpression();
|
node.argument = this.parseExpression();
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
return this.finishNode(node, "ThrowStatement");
|
return this.finishNode(node, "ThrowStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Reused empty array added for node fields that are always empty.
|
parseTryStatement(node: N.TryStatement): N.TryStatement {
|
||||||
|
|
||||||
const empty = [];
|
|
||||||
|
|
||||||
pp.parseTryStatement = function (node) {
|
|
||||||
this.next();
|
this.next();
|
||||||
|
|
||||||
node.block = this.parseBlock();
|
node.block = this.parseBlock();
|
||||||
@ -390,39 +395,39 @@ pp.parseTryStatement = function (node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.finishNode(node, "TryStatement");
|
return this.finishNode(node, "TryStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseVarStatement = function (node, kind) {
|
parseVarStatement(node: N.VariableDeclaration, kind: TokenType): N.VariableDeclaration {
|
||||||
this.next();
|
this.next();
|
||||||
this.parseVar(node, false, kind);
|
this.parseVar(node, false, kind);
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
return this.finishNode(node, "VariableDeclaration");
|
return this.finishNode(node, "VariableDeclaration");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseWhileStatement = function (node) {
|
parseWhileStatement(node: N.WhileStatement): N.WhileStatement {
|
||||||
this.next();
|
this.next();
|
||||||
node.test = this.parseParenExpression();
|
node.test = this.parseParenExpression();
|
||||||
this.state.labels.push(loopLabel);
|
this.state.labels.push(loopLabel);
|
||||||
node.body = this.parseStatement(false);
|
node.body = this.parseStatement(false);
|
||||||
this.state.labels.pop();
|
this.state.labels.pop();
|
||||||
return this.finishNode(node, "WhileStatement");
|
return this.finishNode(node, "WhileStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseWithStatement = function (node) {
|
parseWithStatement(node: N.WithStatement): N.WithStatement {
|
||||||
if (this.state.strict) this.raise(this.state.start, "'with' in strict mode");
|
if (this.state.strict) this.raise(this.state.start, "'with' in strict mode");
|
||||||
this.next();
|
this.next();
|
||||||
node.object = this.parseParenExpression();
|
node.object = this.parseParenExpression();
|
||||||
node.body = this.parseStatement(false);
|
node.body = this.parseStatement(false);
|
||||||
return this.finishNode(node, "WithStatement");
|
return this.finishNode(node, "WithStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseEmptyStatement = function (node) {
|
parseEmptyStatement(node: N.EmptyStatement): N.EmptyStatement {
|
||||||
this.next();
|
this.next();
|
||||||
return this.finishNode(node, "EmptyStatement");
|
return this.finishNode(node, "EmptyStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseLabeledStatement = function (node, maybeName, expr) {
|
parseLabeledStatement(node: N.LabeledStatement, maybeName: string, expr: N.Identifier): N.LabeledStatement {
|
||||||
for (const label of (this.state.labels: Array<Object>)) {
|
for (const label of this.state.labels) {
|
||||||
if (label.name === maybeName) {
|
if (label.name === maybeName) {
|
||||||
this.raise(expr.start, `Label '${maybeName}' is already declared`);
|
this.raise(expr.start, `Label '${maybeName}' is already declared`);
|
||||||
}
|
}
|
||||||
@ -444,34 +449,34 @@ pp.parseLabeledStatement = function (node, maybeName, expr) {
|
|||||||
this.state.labels.pop();
|
this.state.labels.pop();
|
||||||
node.label = expr;
|
node.label = expr;
|
||||||
return this.finishNode(node, "LabeledStatement");
|
return this.finishNode(node, "LabeledStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseExpressionStatement = function (node, expr) {
|
parseExpressionStatement(node: N.ExpressionStatement, expr: N.Expression): N.ExpressionStatement {
|
||||||
node.expression = expr;
|
node.expression = expr;
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
return this.finishNode(node, "ExpressionStatement");
|
return this.finishNode(node, "ExpressionStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse a semicolon-enclosed block of statements, handling `"use
|
// Parse a semicolon-enclosed block of statements, handling `"use
|
||||||
// strict"` declarations when `allowStrict` is true (used for
|
// strict"` declarations when `allowStrict` is true (used for
|
||||||
// function bodies).
|
// function bodies).
|
||||||
|
|
||||||
pp.parseBlock = function (allowDirectives?) {
|
parseBlock(allowDirectives?: boolean): N.BlockStatement {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.expect(tt.braceL);
|
this.expect(tt.braceL);
|
||||||
this.parseBlockBody(node, allowDirectives, false, tt.braceR);
|
this.parseBlockBody(node, allowDirectives, false, tt.braceR);
|
||||||
return this.finishNode(node, "BlockStatement");
|
return this.finishNode(node, "BlockStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.isValidDirective = function (stmt) {
|
isValidDirective(stmt: N.Statement): boolean {
|
||||||
return stmt.type === "ExpressionStatement" &&
|
return stmt.type === "ExpressionStatement" &&
|
||||||
stmt.expression.type === "StringLiteral" &&
|
stmt.expression.type === "StringLiteral" &&
|
||||||
!stmt.expression.extra.parenthesized;
|
!stmt.expression.extra.parenthesized;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseBlockBody = function (node, allowDirectives, topLevel, end) {
|
parseBlockBody(node: N.BlockStatementLike, allowDirectives: ?boolean, topLevel: boolean, end: TokenType): void {
|
||||||
node.body = [];
|
const body = node.body = [];
|
||||||
node.directives = [];
|
const directives = node.directives = [];
|
||||||
|
|
||||||
let parsedNonDirective = false;
|
let parsedNonDirective = false;
|
||||||
let oldStrict;
|
let oldStrict;
|
||||||
@ -486,7 +491,7 @@ pp.parseBlockBody = function (node, allowDirectives, topLevel, end) {
|
|||||||
|
|
||||||
if (allowDirectives && !parsedNonDirective && this.isValidDirective(stmt)) {
|
if (allowDirectives && !parsedNonDirective && this.isValidDirective(stmt)) {
|
||||||
const directive = this.stmtToDirective(stmt);
|
const directive = this.stmtToDirective(stmt);
|
||||||
node.directives.push(directive);
|
directives.push(directive);
|
||||||
|
|
||||||
if (oldStrict === undefined && directive.value.value === "use strict") {
|
if (oldStrict === undefined && directive.value.value === "use strict") {
|
||||||
oldStrict = this.state.strict;
|
oldStrict = this.state.strict;
|
||||||
@ -501,19 +506,19 @@ pp.parseBlockBody = function (node, allowDirectives, topLevel, end) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parsedNonDirective = true;
|
parsedNonDirective = true;
|
||||||
node.body.push(stmt);
|
body.push(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldStrict === false) {
|
if (oldStrict === false) {
|
||||||
this.setStrict(false);
|
this.setStrict(false);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse a regular `for` loop. The disambiguation code in
|
// Parse a regular `for` loop. The disambiguation code in
|
||||||
// `parseStatement` will already have parsed the init statement or
|
// `parseStatement` will already have parsed the init statement or
|
||||||
// expression.
|
// expression.
|
||||||
|
|
||||||
pp.parseFor = function (node, init) {
|
parseFor(node: N.ForStatement, init: ?(N.VariableDeclaration | N.Expression)): N.ForStatement {
|
||||||
node.init = init;
|
node.init = init;
|
||||||
this.expect(tt.semi);
|
this.expect(tt.semi);
|
||||||
node.test = this.match(tt.semi) ? null : this.parseExpression();
|
node.test = this.match(tt.semi) ? null : this.parseExpression();
|
||||||
@ -523,31 +528,34 @@ pp.parseFor = function (node, init) {
|
|||||||
node.body = this.parseStatement(false);
|
node.body = this.parseStatement(false);
|
||||||
this.state.labels.pop();
|
this.state.labels.pop();
|
||||||
return this.finishNode(node, "ForStatement");
|
return this.finishNode(node, "ForStatement");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse a `for`/`in` and `for`/`of` loop, which are almost
|
// Parse a `for`/`in` and `for`/`of` loop, which are almost
|
||||||
// same from parser's perspective.
|
// same from parser's perspective.
|
||||||
|
|
||||||
pp.parseForIn = function (node, init, forAwait) {
|
parseForIn(node: N.ForInOf, init: N.VariableDeclaration, forAwait: boolean): N.ForInOf {
|
||||||
const type = this.match(tt._in) ? "ForInStatement" : "ForOfStatement";
|
const type = this.match(tt._in) ? "ForInStatement" : "ForOfStatement";
|
||||||
if (forAwait) {
|
if (forAwait) {
|
||||||
this.eatContextual("of");
|
this.eatContextual("of");
|
||||||
} else {
|
} else {
|
||||||
this.next();
|
this.next();
|
||||||
}
|
}
|
||||||
|
if (type === "ForOfStatement") {
|
||||||
node.await = !!forAwait;
|
node.await = !!forAwait;
|
||||||
|
}
|
||||||
node.left = init;
|
node.left = init;
|
||||||
node.right = this.parseExpression();
|
node.right = this.parseExpression();
|
||||||
this.expect(tt.parenR);
|
this.expect(tt.parenR);
|
||||||
node.body = this.parseStatement(false);
|
node.body = this.parseStatement(false);
|
||||||
this.state.labels.pop();
|
this.state.labels.pop();
|
||||||
return this.finishNode(node, type);
|
return this.finishNode(node, type);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse a list of variable declarations.
|
// Parse a list of variable declarations.
|
||||||
|
|
||||||
pp.parseVar = function (node, isFor, kind) {
|
parseVar(node: N.VariableDeclaration, isFor: boolean, kind: TokenType): N.VariableDeclaration {
|
||||||
node.declarations = [];
|
const declarations = node.declarations = [];
|
||||||
|
// $FlowFixMe
|
||||||
node.kind = kind.keyword;
|
node.kind = kind.keyword;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const decl = this.startNode();
|
const decl = this.startNode();
|
||||||
@ -561,21 +569,21 @@ pp.parseVar = function (node, isFor, kind) {
|
|||||||
} else {
|
} else {
|
||||||
decl.init = null;
|
decl.init = null;
|
||||||
}
|
}
|
||||||
node.declarations.push(this.finishNode(decl, "VariableDeclarator"));
|
declarations.push(this.finishNode(decl, "VariableDeclarator"));
|
||||||
if (!this.eat(tt.comma)) break;
|
if (!this.eat(tt.comma)) break;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseVarHead = function (decl) {
|
parseVarHead(decl: N.VariableDeclarator): void {
|
||||||
decl.id = this.parseBindingAtom();
|
decl.id = this.parseBindingAtom();
|
||||||
this.checkLVal(decl.id, true, undefined, "variable declaration");
|
this.checkLVal(decl.id, true, undefined, "variable declaration");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse a function declaration or literal (depending on the
|
// Parse a function declaration or literal (depending on the
|
||||||
// `isStatement` parameter).
|
// `isStatement` parameter).
|
||||||
|
|
||||||
pp.parseFunction = function (node, isStatement, allowExpressionBody, isAsync, optionalId) {
|
parseFunction<T : N.NormalFunction>(node: T, isStatement: boolean, allowExpressionBody?: boolean, isAsync?: boolean, optionalId?: boolean): T {
|
||||||
const oldInMethod = this.state.inMethod;
|
const oldInMethod = this.state.inMethod;
|
||||||
this.state.inMethod = false;
|
this.state.inMethod = false;
|
||||||
|
|
||||||
@ -604,46 +612,49 @@ pp.parseFunction = function (node, isStatement, allowExpressionBody, isAsync, op
|
|||||||
this.state.inMethod = oldInMethod;
|
this.state.inMethod = oldInMethod;
|
||||||
|
|
||||||
return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
|
return this.finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseFunctionParams = function (node) {
|
parseFunctionParams(node: N.NormalFunction): void {
|
||||||
this.expect(tt.parenL);
|
this.expect(tt.parenL);
|
||||||
node.params = this.parseBindingList(tt.parenR);
|
node.params = this.parseBindingList(tt.parenR);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse a class declaration or literal (depending on the
|
// Parse a class declaration or literal (depending on the
|
||||||
// `isStatement` parameter).
|
// `isStatement` parameter).
|
||||||
|
|
||||||
pp.parseClass = function (node, isStatement, optionalId) {
|
parseClass(node: N.Class, isStatement: boolean, optionalId?: boolean): N.Class {
|
||||||
this.next();
|
this.next();
|
||||||
this.takeDecorators(node);
|
this.takeDecorators(node);
|
||||||
this.parseClassId(node, isStatement, optionalId);
|
this.parseClassId(node, isStatement, optionalId);
|
||||||
this.parseClassSuper(node);
|
this.parseClassSuper(node);
|
||||||
this.parseClassBody(node);
|
this.parseClassBody(node);
|
||||||
return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
|
return this.finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.isClassProperty = function () {
|
isClassProperty(): boolean {
|
||||||
return this.match(tt.eq) || this.match(tt.semi) || this.match(tt.braceR);
|
return this.match(tt.eq) || this.match(tt.semi) || this.match(tt.braceR);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.isClassMethod = function () {
|
isClassMethod(): boolean {
|
||||||
return this.match(tt.parenL);
|
return this.match(tt.parenL);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.isNonstaticConstructor = function (method) {
|
isNonstaticConstructor(method: N.ClassMethod | N.ClassProperty): boolean {
|
||||||
return !method.computed && !method.static && (
|
return !method.computed && !method.static && (
|
||||||
|
// $FlowFixMe ('key' downcasting)
|
||||||
(method.key.name === "constructor") || // Identifier
|
(method.key.name === "constructor") || // Identifier
|
||||||
|
// $FlowFixMe ('key' downcasting)
|
||||||
(method.key.value === "constructor") // Literal
|
(method.key.value === "constructor") // Literal
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseClassBody = function (node) {
|
parseClassBody(node: N.Class): void {
|
||||||
// class bodies are implicitly strict
|
// class bodies are implicitly strict
|
||||||
const oldStrict = this.state.strict;
|
const oldStrict = this.state.strict;
|
||||||
this.state.strict = true;
|
this.state.strict = true;
|
||||||
|
this.state.inClass = true;
|
||||||
|
|
||||||
let hadConstructor = false;
|
const state = { hadConstructor: false };
|
||||||
let decorators = [];
|
let decorators = [];
|
||||||
const classBody = this.startNode();
|
const classBody = this.startNode();
|
||||||
|
|
||||||
@ -664,15 +675,43 @@ pp.parseClassBody = function (node) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const method = this.startNode();
|
const member = this.startNode();
|
||||||
|
|
||||||
// steal the decorators if there are any
|
// steal the decorators if there are any
|
||||||
if (decorators.length) {
|
if (decorators.length) {
|
||||||
method.decorators = decorators;
|
member.decorators = decorators;
|
||||||
decorators = [];
|
decorators = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
method.static = false;
|
this.parseClassMember(classBody, member, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decorators.length) {
|
||||||
|
this.raise(this.state.start, "You have trailing decorators with no method");
|
||||||
|
}
|
||||||
|
|
||||||
|
node.body = this.finishNode(classBody, "ClassBody");
|
||||||
|
|
||||||
|
this.state.inClass = false;
|
||||||
|
this.state.strict = oldStrict;
|
||||||
|
}
|
||||||
|
|
||||||
|
parseClassMember(classBody: N.ClassBody, member: N.ClassMember, state: { hadConstructor: boolean }): void {
|
||||||
|
// Use the appropriate variable to represent `member` once a more specific type is known.
|
||||||
|
const memberAny: any = member;
|
||||||
|
const methodOrProp: N.ClassMethod | N.ClassProperty = memberAny;
|
||||||
|
const method: N.ClassMethod = memberAny;
|
||||||
|
const prop: N.ClassProperty = memberAny;
|
||||||
|
|
||||||
|
if (this.hasPlugin("classPrivateProperties") && this.match(tt.hash)) { // Private property
|
||||||
|
this.next();
|
||||||
|
const privateProp: N.ClassPrivateProperty = memberAny;
|
||||||
|
this.parsePropertyName(privateProp);
|
||||||
|
classBody.body.push(this.parsePrivateClassProperty(privateProp));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
methodOrProp.static = false;
|
||||||
if (this.match(tt.name) && this.state.value === "static") {
|
if (this.match(tt.name) && this.state.value === "static") {
|
||||||
const key = this.parseIdentifier(true); // eats 'static'
|
const key = this.parseIdentifier(true); // eats 'static'
|
||||||
if (this.isClassMethod()) {
|
if (this.isClassMethod()) {
|
||||||
@ -681,16 +720,16 @@ pp.parseClassBody = function (node) {
|
|||||||
method.computed = false;
|
method.computed = false;
|
||||||
method.key = key;
|
method.key = key;
|
||||||
this.parseClassMethod(classBody, method, false, false);
|
this.parseClassMethod(classBody, method, false, false);
|
||||||
continue;
|
return;
|
||||||
} else if (this.isClassProperty()) {
|
} else if (this.isClassProperty()) {
|
||||||
// a property named 'static'
|
// a property named 'static'
|
||||||
method.computed = false;
|
prop.computed = false;
|
||||||
method.key = key;
|
prop.key = key;
|
||||||
classBody.body.push(this.parseClassProperty(method));
|
classBody.body.push(this.parseClassProperty(prop));
|
||||||
continue;
|
return;
|
||||||
}
|
}
|
||||||
// otherwise something static
|
// otherwise something static
|
||||||
method.static = true;
|
methodOrProp.static = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.eat(tt.star)) {
|
if (this.eat(tt.star)) {
|
||||||
@ -704,21 +743,24 @@ pp.parseClassBody = function (node) {
|
|||||||
this.raise(method.key.start, "Classes may not have static property named prototype");
|
this.raise(method.key.start, "Classes may not have static property named prototype");
|
||||||
}
|
}
|
||||||
this.parseClassMethod(classBody, method, true, false);
|
this.parseClassMethod(classBody, method, true, false);
|
||||||
} else {
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isSimple = this.match(tt.name);
|
const isSimple = this.match(tt.name);
|
||||||
const key = this.parsePropertyName(method);
|
const key = this.parsePropertyName(methodOrProp);
|
||||||
if (!method.computed && method.static && (method.key.name === "prototype" || method.key.value === "prototype")) {
|
// $FlowFixMe ('key' downcasting)
|
||||||
this.raise(method.key.start, "Classes may not have static property named prototype");
|
if (!methodOrProp.computed && methodOrProp.static && (methodOrProp.key.name === "prototype" || methodOrProp.key.value === "prototype")) {
|
||||||
|
this.raise(methodOrProp.key.start, "Classes may not have static property named prototype");
|
||||||
}
|
}
|
||||||
if (this.isClassMethod()) {
|
if (this.isClassMethod()) {
|
||||||
// a normal method
|
// a normal method
|
||||||
if (this.isNonstaticConstructor(method)) {
|
if (this.isNonstaticConstructor(method)) {
|
||||||
if (hadConstructor) {
|
if (state.hadConstructor) {
|
||||||
this.raise(key.start, "Duplicate constructor in the same class");
|
this.raise(key.start, "Duplicate constructor in the same class");
|
||||||
} else if (method.decorators) {
|
} else if (method.decorators) {
|
||||||
this.raise(method.start, "You can't attach decorators to a class constructor");
|
this.raise(method.start, "You can't attach decorators to a class constructor");
|
||||||
}
|
}
|
||||||
hadConstructor = true;
|
state.hadConstructor = true;
|
||||||
method.kind = "constructor";
|
method.kind = "constructor";
|
||||||
} else {
|
} else {
|
||||||
method.kind = "method";
|
method.kind = "method";
|
||||||
@ -726,10 +768,10 @@ pp.parseClassBody = function (node) {
|
|||||||
this.parseClassMethod(classBody, method, false, false);
|
this.parseClassMethod(classBody, method, false, false);
|
||||||
} else if (this.isClassProperty()) {
|
} else if (this.isClassProperty()) {
|
||||||
// a normal property
|
// a normal property
|
||||||
if (this.isNonstaticConstructor(method)) {
|
if (this.isNonstaticConstructor(prop)) {
|
||||||
this.raise(method.key.start, "Classes may not have a non-static field named 'constructor'");
|
this.raise(prop.key.start, "Classes may not have a non-static field named 'constructor'");
|
||||||
}
|
}
|
||||||
classBody.body.push(this.parseClassProperty(method));
|
classBody.body.push(this.parseClassProperty(prop));
|
||||||
} else if (isSimple && key.name === "async" && !this.isLineTerminator()) {
|
} else if (isSimple && key.name === "async" && !this.isLineTerminator()) {
|
||||||
// an async method
|
// an async method
|
||||||
const isGenerator = this.hasPlugin("asyncGenerators") && this.eat(tt.star);
|
const isGenerator = this.hasPlugin("asyncGenerators") && this.eat(tt.star);
|
||||||
@ -750,73 +792,83 @@ pp.parseClassBody = function (node) {
|
|||||||
this.checkGetterSetterParamCount(method);
|
this.checkGetterSetterParamCount(method);
|
||||||
} else if (this.isLineTerminator()) {
|
} else if (this.isLineTerminator()) {
|
||||||
// an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
|
// an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
|
||||||
if (this.isNonstaticConstructor(method)) {
|
if (this.isNonstaticConstructor(prop)) {
|
||||||
this.raise(method.key.start, "Classes may not have a non-static field named 'constructor'");
|
this.raise(prop.key.start, "Classes may not have a non-static field named 'constructor'");
|
||||||
}
|
}
|
||||||
classBody.body.push(this.parseClassProperty(method));
|
classBody.body.push(this.parseClassProperty(prop));
|
||||||
} else {
|
} else {
|
||||||
this.unexpected();
|
this.unexpected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (decorators.length) {
|
parsePrivateClassProperty(node: N.ClassPrivateProperty): N.ClassPrivateProperty {
|
||||||
this.raise(this.state.start, "You have trailing decorators with no method");
|
this.state.inClassProperty = true;
|
||||||
}
|
|
||||||
|
|
||||||
node.body = this.finishNode(classBody, "ClassBody");
|
|
||||||
|
|
||||||
this.state.strict = oldStrict;
|
|
||||||
};
|
|
||||||
|
|
||||||
pp.parseClassProperty = function (node) {
|
|
||||||
const noPluginMsg = "You can only use Class Properties when the 'classProperties' plugin is enabled.";
|
|
||||||
if (!node.typeAnnotation && !this.hasPlugin("classProperties")) {
|
|
||||||
this.raise(node.start, noPluginMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.match(tt.eq)) {
|
if (this.match(tt.eq)) {
|
||||||
if (!this.hasPlugin("classProperties")) this.raise(this.state.start, noPluginMsg);
|
|
||||||
this.next();
|
this.next();
|
||||||
node.value = this.parseMaybeAssign();
|
node.value = this.parseMaybeAssign();
|
||||||
} else {
|
} else {
|
||||||
node.value = null;
|
node.value = null;
|
||||||
}
|
}
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
return this.finishNode(node, "ClassProperty");
|
this.state.inClassProperty = false;
|
||||||
};
|
return this.finishNode(node, "ClassPrivateProperty");
|
||||||
|
}
|
||||||
|
|
||||||
pp.parseClassMethod = function (classBody, method, isGenerator, isAsync) {
|
|
||||||
|
parseClassProperty(node: N.ClassProperty): N.ClassProperty {
|
||||||
|
const hasPlugin = this.hasPlugin("classProperties");
|
||||||
|
const noPluginMsg = "You can only use Class Properties when the 'classProperties' plugin is enabled.";
|
||||||
|
if (!node.typeAnnotation && !hasPlugin) {
|
||||||
|
this.raise(node.start, noPluginMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.state.inClassProperty = true;
|
||||||
|
|
||||||
|
if (this.match(tt.eq)) {
|
||||||
|
if (!hasPlugin) this.raise(this.state.start, noPluginMsg);
|
||||||
|
this.next();
|
||||||
|
node.value = this.parseMaybeAssign();
|
||||||
|
} else {
|
||||||
|
node.value = null;
|
||||||
|
}
|
||||||
|
this.semicolon();
|
||||||
|
this.state.inClassProperty = false;
|
||||||
|
return this.finishNode(node, "ClassProperty");
|
||||||
|
}
|
||||||
|
|
||||||
|
parseClassMethod(classBody: N.ClassBody, method: N.ClassMethod, isGenerator: boolean, isAsync: boolean): void {
|
||||||
this.parseMethod(method, isGenerator, isAsync);
|
this.parseMethod(method, isGenerator, isAsync);
|
||||||
classBody.body.push(this.finishNode(method, "ClassMethod"));
|
classBody.body.push(this.finishNode(method, "ClassMethod"));
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseClassId = function (node, isStatement, optionalId) {
|
parseClassId(node: N.Class, isStatement: boolean, optionalId: ?boolean): void {
|
||||||
if (this.match(tt.name)) {
|
if (this.match(tt.name)) {
|
||||||
node.id = this.parseIdentifier();
|
node.id = this.parseIdentifier();
|
||||||
} else {
|
} else {
|
||||||
if (optionalId || !isStatement) {
|
if (optionalId || !isStatement) {
|
||||||
node.id = null;
|
node.id = null;
|
||||||
} else {
|
} else {
|
||||||
this.unexpected();
|
this.unexpected(null, "A class name is required");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
pp.parseClassSuper = function (node) {
|
parseClassSuper(node: N.Class): void {
|
||||||
node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null;
|
node.superClass = this.eat(tt._extends) ? this.parseExprSubscripts() : null;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses module export declaration.
|
// Parses module export declaration.
|
||||||
|
|
||||||
pp.parseExport = function (node) {
|
parseExport(node: N.ExportNamedDeclaration): N.ExportNamedDeclaration {
|
||||||
this.next();
|
this.eat(tt._export);
|
||||||
|
|
||||||
// export * from '...'
|
// export * from '...'
|
||||||
if (this.match(tt.star)) {
|
if (this.match(tt.star)) {
|
||||||
const specifier = this.startNode();
|
const specifier = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
if (this.hasPlugin("exportExtensions") && this.eatContextual("as")) {
|
if (this.hasPlugin("exportExtensions") && this.eatContextual("as")) {
|
||||||
specifier.exported = this.parseIdentifier();
|
specifier.exported = this.parseIdentifier(true);
|
||||||
node.specifiers = [this.finishNode(specifier, "ExportNamespaceSpecifier")];
|
node.specifiers = [this.finishNode(specifier, "ExportNamespaceSpecifier")];
|
||||||
this.parseExportSpecifiersMaybe(node);
|
this.parseExportSpecifiersMaybe(node);
|
||||||
this.parseExportFrom(node, true);
|
this.parseExportFrom(node, true);
|
||||||
@ -827,14 +879,15 @@ pp.parseExport = function (node) {
|
|||||||
} else if (this.hasPlugin("exportExtensions") && this.isExportDefaultSpecifier()) {
|
} else if (this.hasPlugin("exportExtensions") && this.isExportDefaultSpecifier()) {
|
||||||
const specifier = this.startNode();
|
const specifier = this.startNode();
|
||||||
specifier.exported = this.parseIdentifier(true);
|
specifier.exported = this.parseIdentifier(true);
|
||||||
node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
|
const specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
|
||||||
|
node.specifiers = specifiers;
|
||||||
if (this.match(tt.comma) && this.lookahead().type === tt.star) {
|
if (this.match(tt.comma) && this.lookahead().type === tt.star) {
|
||||||
this.expect(tt.comma);
|
this.expect(tt.comma);
|
||||||
const specifier = this.startNode();
|
const specifier = this.startNode();
|
||||||
this.expect(tt.star);
|
this.expect(tt.star);
|
||||||
this.expectContextual("as");
|
this.expectContextual("as");
|
||||||
specifier.exported = this.parseIdentifier();
|
specifier.exported = this.parseIdentifier();
|
||||||
node.specifiers.push(this.finishNode(specifier, "ExportNamespaceSpecifier"));
|
specifiers.push(this.finishNode(specifier, "ExportNamespaceSpecifier"));
|
||||||
} else {
|
} else {
|
||||||
this.parseExportSpecifiersMaybe(node);
|
this.parseExportSpecifiersMaybe(node);
|
||||||
}
|
}
|
||||||
@ -857,6 +910,7 @@ pp.parseExport = function (node) {
|
|||||||
needsSemi = true;
|
needsSemi = true;
|
||||||
expr = this.parseMaybeAssign();
|
expr = this.parseMaybeAssign();
|
||||||
}
|
}
|
||||||
|
// $FlowFixMe
|
||||||
node.declaration = expr;
|
node.declaration = expr;
|
||||||
if (needsSemi) this.semicolon();
|
if (needsSemi) this.semicolon();
|
||||||
this.checkExport(node, true, true);
|
this.checkExport(node, true, true);
|
||||||
@ -872,17 +926,16 @@ pp.parseExport = function (node) {
|
|||||||
}
|
}
|
||||||
this.checkExport(node, true);
|
this.checkExport(node, true);
|
||||||
return this.finishNode(node, "ExportNamedDeclaration");
|
return this.finishNode(node, "ExportNamedDeclaration");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseExportDeclaration = function () {
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
parseExportDeclaration(node: N.ExportNamedDeclaration): ?N.Declaration {
|
||||||
return this.parseStatement(true);
|
return this.parseStatement(true);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.isExportDefaultSpecifier = function () {
|
isExportDefaultSpecifier(): boolean {
|
||||||
if (this.match(tt.name)) {
|
if (this.match(tt.name)) {
|
||||||
return this.state.value !== "type"
|
return this.state.value !== "async";
|
||||||
&& this.state.value !== "async"
|
|
||||||
&& this.state.value !== "interface";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.match(tt._default)) {
|
if (!this.match(tt._default)) {
|
||||||
@ -891,15 +944,15 @@ pp.isExportDefaultSpecifier = function () {
|
|||||||
|
|
||||||
const lookahead = this.lookahead();
|
const lookahead = this.lookahead();
|
||||||
return lookahead.type === tt.comma || (lookahead.type === tt.name && lookahead.value === "from");
|
return lookahead.type === tt.comma || (lookahead.type === tt.name && lookahead.value === "from");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseExportSpecifiersMaybe = function (node) {
|
parseExportSpecifiersMaybe(node: N.ExportNamedDeclaration): void {
|
||||||
if (this.eat(tt.comma)) {
|
if (this.eat(tt.comma)) {
|
||||||
node.specifiers = node.specifiers.concat(this.parseExportSpecifiers());
|
node.specifiers = node.specifiers.concat(this.parseExportSpecifiers());
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseExportFrom = function (node, expect?) {
|
parseExportFrom(node: N.ExportNamedDeclaration, expect?: boolean): void {
|
||||||
if (this.eatContextual("from")) {
|
if (this.eatContextual("from")) {
|
||||||
node.source = this.match(tt.string) ? this.parseExprAtom() : this.unexpected();
|
node.source = this.match(tt.string) ? this.parseExprAtom() : this.unexpected();
|
||||||
this.checkExport(node);
|
this.checkExport(node);
|
||||||
@ -912,18 +965,18 @@ pp.parseExportFrom = function (node, expect?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.shouldParseExportDeclaration = function (): boolean {
|
shouldParseExportDeclaration(): boolean {
|
||||||
return this.state.type.keyword === "var"
|
return this.state.type.keyword === "var"
|
||||||
|| this.state.type.keyword === "const"
|
|| this.state.type.keyword === "const"
|
||||||
|| this.state.type.keyword === "let"
|
|| this.state.type.keyword === "let"
|
||||||
|| this.state.type.keyword === "function"
|
|| this.state.type.keyword === "function"
|
||||||
|| this.state.type.keyword === "class"
|
|| this.state.type.keyword === "class"
|
||||||
|| this.isContextual("async");
|
|| this.isContextual("async");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.checkExport = function (node, checkNames, isDefault) {
|
checkExport(node: N.ExportNamedDeclaration, checkNames: ?boolean, isDefault: ?boolean): void {
|
||||||
if (checkNames) {
|
if (checkNames) {
|
||||||
// Check for duplicate exports
|
// Check for duplicate exports
|
||||||
if (isDefault) {
|
if (isDefault) {
|
||||||
@ -949,15 +1002,16 @@ pp.checkExport = function (node, checkNames, isDefault) {
|
|||||||
if (this.state.decorators.length) {
|
if (this.state.decorators.length) {
|
||||||
const isClass = node.declaration && (node.declaration.type === "ClassDeclaration" || node.declaration.type === "ClassExpression");
|
const isClass = node.declaration && (node.declaration.type === "ClassDeclaration" || node.declaration.type === "ClassExpression");
|
||||||
if (!node.declaration || !isClass) {
|
if (!node.declaration || !isClass) {
|
||||||
this.raise(node.start, "You can only use decorators on an export when exporting a class");
|
throw this.raise(node.start, "You can only use decorators on an export when exporting a class");
|
||||||
}
|
}
|
||||||
this.takeDecorators(node.declaration);
|
this.takeDecorators(node.declaration);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.checkDeclaration = function(node) {
|
checkDeclaration(node: N.Pattern): void {
|
||||||
if (node.type === "ObjectPattern") {
|
if (node.type === "ObjectPattern") {
|
||||||
for (const prop of node.properties) {
|
for (const prop of node.properties) {
|
||||||
|
// $FlowFixMe (prop may be an AssignmentProperty, in which case this does nothing?)
|
||||||
this.checkDeclaration(prop);
|
this.checkDeclaration(prop);
|
||||||
}
|
}
|
||||||
} else if (node.type === "ArrayPattern") {
|
} else if (node.type === "ArrayPattern") {
|
||||||
@ -973,25 +1027,25 @@ pp.checkDeclaration = function(node) {
|
|||||||
} else if (node.type === "Identifier") {
|
} else if (node.type === "Identifier") {
|
||||||
this.checkDuplicateExports(node, node.name);
|
this.checkDuplicateExports(node, node.name);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.checkDuplicateExports = function(node, name) {
|
checkDuplicateExports(node: N.Identifier | N.ExportNamedDeclaration | N.ExportSpecifier, name: string): void {
|
||||||
if (this.state.exportedIdentifiers.indexOf(name) > -1) {
|
if (this.state.exportedIdentifiers.indexOf(name) > -1) {
|
||||||
this.raiseDuplicateExportError(node, name);
|
this.raiseDuplicateExportError(node, name);
|
||||||
}
|
}
|
||||||
this.state.exportedIdentifiers.push(name);
|
this.state.exportedIdentifiers.push(name);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.raiseDuplicateExportError = function(node, name) {
|
raiseDuplicateExportError(node: N.Identifier | N.ExportNamedDeclaration | N.ExportSpecifier, name: string): empty {
|
||||||
this.raise(node.start, name === "default" ?
|
throw this.raise(node.start, name === "default" ?
|
||||||
"Only one default export allowed per module." :
|
"Only one default export allowed per module." :
|
||||||
`\`${name}\` has already been exported. Exported identifiers must be unique.`
|
`\`${name}\` has already been exported. Exported identifiers must be unique.`
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses a comma-separated list of module exports.
|
// Parses a comma-separated list of module exports.
|
||||||
|
|
||||||
pp.parseExportSpecifiers = function () {
|
parseExportSpecifiers(): $ReadOnlyArray<N.ExportSpecifier> {
|
||||||
const nodes = [];
|
const nodes = [];
|
||||||
let first = true;
|
let first = true;
|
||||||
let needsFrom;
|
let needsFrom;
|
||||||
@ -1022,11 +1076,11 @@ pp.parseExportSpecifiers = function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return nodes;
|
return nodes;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses import declaration.
|
// Parses import declaration.
|
||||||
|
|
||||||
pp.parseImport = function (node) {
|
parseImport(node: N.ImportDeclaration): N.ImportDeclaration {
|
||||||
this.eat(tt._import);
|
this.eat(tt._import);
|
||||||
|
|
||||||
// import '...'
|
// import '...'
|
||||||
@ -1041,11 +1095,11 @@ pp.parseImport = function (node) {
|
|||||||
}
|
}
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
return this.finishNode(node, "ImportDeclaration");
|
return this.finishNode(node, "ImportDeclaration");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses a comma-separated list of module imports.
|
// Parses a comma-separated list of module imports.
|
||||||
|
|
||||||
pp.parseImportSpecifiers = function (node) {
|
parseImportSpecifiers(node: N.ImportDeclaration): void {
|
||||||
let first = true;
|
let first = true;
|
||||||
if (this.match(tt.name)) {
|
if (this.match(tt.name)) {
|
||||||
// import defaultObj, { x, y as z } from '...'
|
// import defaultObj, { x, y as z } from '...'
|
||||||
@ -1081,9 +1135,9 @@ pp.parseImportSpecifiers = function (node) {
|
|||||||
|
|
||||||
this.parseImportSpecifier(node);
|
this.parseImportSpecifier(node);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseImportSpecifier = function (node) {
|
parseImportSpecifier(node: N.ImportDeclaration): void {
|
||||||
const specifier = this.startNode();
|
const specifier = this.startNode();
|
||||||
specifier.imported = this.parseIdentifier(true);
|
specifier.imported = this.parseIdentifier(true);
|
||||||
if (this.eatContextual("as")) {
|
if (this.eatContextual("as")) {
|
||||||
@ -1094,11 +1148,12 @@ pp.parseImportSpecifier = function (node) {
|
|||||||
}
|
}
|
||||||
this.checkLVal(specifier.local, true, undefined, "import specifier");
|
this.checkLVal(specifier.local, true, undefined, "import specifier");
|
||||||
node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"));
|
node.specifiers.push(this.finishNode(specifier, "ImportSpecifier"));
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.parseImportSpecifierDefault = function (id, startPos, startLoc) {
|
parseImportSpecifierDefault(id: N.Identifier, startPos: number, startLoc: Position): N.ImportDefaultSpecifier {
|
||||||
const node = this.startNodeAt(startPos, startLoc);
|
const node = this.startNodeAt(startPos, startLoc);
|
||||||
node.local = id;
|
node.local = id;
|
||||||
this.checkLVal(node.local, true, undefined, "default import specifier");
|
this.checkLVal(node.local, true, undefined, "default import specifier");
|
||||||
return this.finishNode(node, "ImportDefaultSpecifier");
|
return this.finishNode(node, "ImportDefaultSpecifier");
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,88 +1,91 @@
|
|||||||
import { types as tt } from "../tokenizer/types";
|
// @flow
|
||||||
import Parser from "./index";
|
|
||||||
import { lineBreak } from "../util/whitespace";
|
|
||||||
|
|
||||||
const pp = Parser.prototype;
|
import { types as tt, type TokenType } from "../tokenizer/types";
|
||||||
|
import Tokenizer from "../tokenizer";
|
||||||
|
import type { Node } from "../types";
|
||||||
|
import { lineBreak } from "../util/whitespace";
|
||||||
|
|
||||||
// ## Parser utilities
|
// ## Parser utilities
|
||||||
|
|
||||||
|
export default class UtilParser extends Tokenizer {
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
pp.addExtra = function (node, key, val) {
|
addExtra(node: Node, key: string, val: any): void {
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
|
|
||||||
const extra = node.extra = node.extra || {};
|
const extra = node.extra = node.extra || {};
|
||||||
extra[key] = val;
|
extra[key] = val;
|
||||||
};
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
pp.isRelational = function (op) {
|
isRelational(op: "<" | ">"): boolean {
|
||||||
return this.match(tt.relational) && this.state.value === op;
|
return this.match(tt.relational) && this.state.value === op;
|
||||||
};
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
pp.expectRelational = function (op) {
|
expectRelational(op: "<" | ">"): void {
|
||||||
if (this.isRelational(op)) {
|
if (this.isRelational(op)) {
|
||||||
this.next();
|
this.next();
|
||||||
} else {
|
} else {
|
||||||
this.unexpected(null, tt.relational);
|
this.unexpected(null, tt.relational);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// Tests whether parsed token is a contextual keyword.
|
// Tests whether parsed token is a contextual keyword.
|
||||||
|
|
||||||
pp.isContextual = function (name) {
|
isContextual(name: string): boolean {
|
||||||
return this.match(tt.name) && this.state.value === name;
|
return this.match(tt.name) && this.state.value === name;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Consumes contextual keyword if possible.
|
// Consumes contextual keyword if possible.
|
||||||
|
|
||||||
pp.eatContextual = function (name) {
|
eatContextual(name: string): boolean {
|
||||||
return this.state.value === name && this.eat(tt.name);
|
return this.state.value === name && this.eat(tt.name);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Asserts that following token is given contextual keyword.
|
// Asserts that following token is given contextual keyword.
|
||||||
|
|
||||||
pp.expectContextual = function (name, message) {
|
expectContextual(name: string, message?: string): void {
|
||||||
if (!this.eatContextual(name)) this.unexpected(null, message);
|
if (!this.eatContextual(name)) this.unexpected(null, message);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Test whether a semicolon can be inserted at the current position.
|
// Test whether a semicolon can be inserted at the current position.
|
||||||
|
|
||||||
pp.canInsertSemicolon = function () {
|
canInsertSemicolon(): boolean {
|
||||||
return this.match(tt.eof) ||
|
return this.match(tt.eof) ||
|
||||||
this.match(tt.braceR) ||
|
this.match(tt.braceR) ||
|
||||||
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start));
|
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start));
|
||||||
};
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
pp.isLineTerminator = function () {
|
isLineTerminator(): boolean {
|
||||||
return this.eat(tt.semi) || this.canInsertSemicolon();
|
return this.eat(tt.semi) || this.canInsertSemicolon();
|
||||||
};
|
}
|
||||||
|
|
||||||
// Consume a semicolon, or, failing that, see if we are allowed to
|
// Consume a semicolon, or, failing that, see if we are allowed to
|
||||||
// pretend that there is a semicolon at this position.
|
// pretend that there is a semicolon at this position.
|
||||||
|
|
||||||
pp.semicolon = function () {
|
semicolon(): void {
|
||||||
if (!this.isLineTerminator()) this.unexpected(null, tt.semi);
|
if (!this.isLineTerminator()) this.unexpected(null, tt.semi);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Expect a token of a given type. If found, consume it, otherwise,
|
// Expect a token of a given type. If found, consume it, otherwise,
|
||||||
// raise an unexpected token error at given pos.
|
// raise an unexpected token error at given pos.
|
||||||
|
|
||||||
pp.expect = function (type, pos) {
|
expect(type: TokenType, pos?: ?number): void {
|
||||||
return this.eat(type) || this.unexpected(pos, type);
|
this.eat(type) || this.unexpected(pos, type);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Raise an unexpected token error. Can take the expected token type
|
// Raise an unexpected token error. Can take the expected token type
|
||||||
// instead of a message string.
|
// instead of a message string.
|
||||||
|
|
||||||
pp.unexpected = function (pos, messageOrType = "Unexpected token") {
|
unexpected(pos: ?number, messageOrType: string | TokenType = "Unexpected token"): empty {
|
||||||
if (messageOrType && typeof messageOrType === "object" && messageOrType.label) {
|
if (typeof messageOrType !== "string") {
|
||||||
messageOrType = `Unexpected token, expected ${messageOrType.label}`;
|
messageOrType = `Unexpected token, expected ${messageOrType.label}`;
|
||||||
}
|
}
|
||||||
this.raise(pos != null ? pos : this.state.start, messageOrType);
|
throw this.raise(pos != null ? pos : this.state.start, messageOrType);
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,9 +1,18 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
import { types as tt } from "../tokenizer/types";
|
import { types as tt } from "../tokenizer/types";
|
||||||
import Parser from "../parser";
|
import type Parser from "../parser";
|
||||||
|
import * as N from "../types";
|
||||||
|
|
||||||
const pp = Parser.prototype;
|
function isSimpleProperty(node: N.Node): boolean {
|
||||||
|
return node != null &&
|
||||||
|
node.type === "Property" &&
|
||||||
|
node.kind === "init" &&
|
||||||
|
node.method === false;
|
||||||
|
}
|
||||||
|
|
||||||
pp.estreeParseRegExpLiteral = function ({ pattern, flags }) {
|
export default (superClass: Class<Parser>): Class<Parser> => class extends superClass {
|
||||||
|
estreeParseRegExpLiteral({ pattern, flags }: N.RegExpLiteral): N.Node {
|
||||||
let regex = null;
|
let regex = null;
|
||||||
try {
|
try {
|
||||||
regex = new RegExp(pattern, flags);
|
regex = new RegExp(pattern, flags);
|
||||||
@ -15,13 +24,13 @@ pp.estreeParseRegExpLiteral = function ({ pattern, flags }) {
|
|||||||
node.regex = { pattern, flags };
|
node.regex = { pattern, flags };
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.estreeParseLiteral = function (value) {
|
estreeParseLiteral(value: any): N.Node {
|
||||||
return this.parseLiteral(value, "Literal");
|
return this.parseLiteral(value, "Literal");
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.directiveToStmt = function (directive) {
|
directiveToStmt(directive: N.Directive): N.ExpressionStatement {
|
||||||
const directiveLiteral = directive.value;
|
const directiveLiteral = directive.value;
|
||||||
|
|
||||||
const stmt = this.startNodeAt(directive.start, directive.loc.start);
|
const stmt = this.startNodeAt(directive.start, directive.loc.start);
|
||||||
@ -30,33 +39,29 @@ pp.directiveToStmt = function (directive) {
|
|||||||
expression.value = directiveLiteral.value;
|
expression.value = directiveLiteral.value;
|
||||||
expression.raw = directiveLiteral.extra.raw;
|
expression.raw = directiveLiteral.extra.raw;
|
||||||
|
|
||||||
stmt.expression = this.finishNodeAt(expression, "Literal", directiveLiteral.end, directiveLiteral.loc.end);
|
stmt.expression = this.finishNodeAt(
|
||||||
|
expression, "Literal", directiveLiteral.end, directiveLiteral.loc.end);
|
||||||
stmt.directive = directiveLiteral.extra.raw.slice(1, -1);
|
stmt.directive = directiveLiteral.extra.raw.slice(1, -1);
|
||||||
|
|
||||||
return this.finishNodeAt(stmt, "ExpressionStatement", directive.end, directive.loc.end);
|
return this.finishNodeAt(stmt, "ExpressionStatement", directive.end, directive.loc.end);
|
||||||
};
|
|
||||||
|
|
||||||
function isSimpleProperty(node) {
|
|
||||||
return node &&
|
|
||||||
node.type === "Property" &&
|
|
||||||
node.kind === "init" &&
|
|
||||||
node.method === false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function (instance) {
|
// ==================================
|
||||||
instance.extend("checkDeclaration", function(inner) {
|
// Overrides
|
||||||
return function (node) {
|
// ==================================
|
||||||
|
|
||||||
|
checkDeclaration(node: N.Pattern): void {
|
||||||
if (isSimpleProperty(node)) {
|
if (isSimpleProperty(node)) {
|
||||||
|
// $FlowFixMe
|
||||||
this.checkDeclaration(node.value);
|
this.checkDeclaration(node.value);
|
||||||
} else {
|
} else {
|
||||||
inner.call(this, node);
|
super.checkDeclaration(node);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("checkGetterSetterParamCount", function() {
|
checkGetterSetterParamCount(prop: N.ObjectMethod | N.ClassMethod): void {
|
||||||
return function (prop) {
|
|
||||||
const paramCount = prop.kind === "get" ? 0 : 1;
|
const paramCount = prop.kind === "get" ? 0 : 1;
|
||||||
|
// $FlowFixMe (prop.value present for ObjectMethod, but for ClassMethod should use prop.params?)
|
||||||
if (prop.value.params.length !== paramCount) {
|
if (prop.value.params.length !== paramCount) {
|
||||||
const start = prop.start;
|
const start = prop.start;
|
||||||
if (prop.kind === "get") {
|
if (prop.kind === "get") {
|
||||||
@ -65,11 +70,10 @@ export default function (instance) {
|
|||||||
this.raise(start, "setter should have exactly one param");
|
this.raise(start, "setter should have exactly one param");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("checkLVal", function(inner) {
|
checkLVal(
|
||||||
return function (expr, isBinding, checkClashes, ...args) {
|
expr: N.Expression, isBinding: ?boolean, checkClashes: ?{ [key: string]: boolean }, ...args): void {
|
||||||
switch (expr.type) {
|
switch (expr.type) {
|
||||||
case "ObjectPattern":
|
case "ObjectPattern":
|
||||||
expr.properties.forEach((prop) => {
|
expr.properties.forEach((prop) => {
|
||||||
@ -82,13 +86,11 @@ export default function (instance) {
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
inner.call(this, expr, isBinding, checkClashes, ...args);
|
super.checkLVal(expr, isBinding, checkClashes, ...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("checkPropClash", function () {
|
checkPropClash(prop: N.ObjectMember, propHash: { [key: string]: boolean }): void {
|
||||||
return function (prop, propHash) {
|
|
||||||
if (prop.computed || !isSimpleProperty(prop)) return;
|
if (prop.computed || !isSimpleProperty(prop)) return;
|
||||||
|
|
||||||
const key = prop.key;
|
const key = prop.key;
|
||||||
@ -99,13 +101,11 @@ export default function (instance) {
|
|||||||
if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property");
|
if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property");
|
||||||
propHash.proto = true;
|
propHash.proto = true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("isStrictBody", function () {
|
isStrictBody(node: { body: N.BlockStatement }, isExpression?: boolean): boolean {
|
||||||
return function (node, isExpression) {
|
|
||||||
if (!isExpression && node.body.body.length > 0) {
|
if (!isExpression && node.body.body.length > 0) {
|
||||||
for (const directive of (node.body.body: Array<Object>)) {
|
for (const directive of node.body.body) {
|
||||||
if (directive.type === "ExpressionStatement" && directive.expression.type === "Literal") {
|
if (directive.type === "ExpressionStatement" && directive.expression.type === "Literal") {
|
||||||
if (directive.expression.value === "use strict") return true;
|
if (directive.expression.value === "use strict") return true;
|
||||||
} else {
|
} else {
|
||||||
@ -116,40 +116,32 @@ export default function (instance) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("isValidDirective", function () {
|
isValidDirective(stmt: N.Statement): boolean {
|
||||||
return function (stmt) {
|
|
||||||
return stmt.type === "ExpressionStatement" &&
|
return stmt.type === "ExpressionStatement" &&
|
||||||
stmt.expression.type === "Literal" &&
|
stmt.expression.type === "Literal" &&
|
||||||
typeof stmt.expression.value === "string" &&
|
typeof stmt.expression.value === "string" &&
|
||||||
(!stmt.expression.extra || !stmt.expression.extra.parenthesized);
|
(!stmt.expression.extra || !stmt.expression.extra.parenthesized);
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("parseBlockBody", function (inner) {
|
parseBlockBody(node: N.BlockStatementLike, ...args): void {
|
||||||
return function (node, ...args) {
|
super.parseBlockBody(node, ...args);
|
||||||
inner.call(this, node, ...args);
|
|
||||||
|
|
||||||
node.directives.reverse().forEach((directive) => {
|
const directiveStatements = node.directives.map((d) => this.directiveToStmt(d));
|
||||||
node.body.unshift(this.directiveToStmt(directive));
|
node.body = directiveStatements.concat(node.body);
|
||||||
});
|
|
||||||
delete node.directives;
|
delete node.directives;
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("parseClassMethod", function (inner) {
|
parseClassMethod(classBody: N.ClassBody, ...args) {
|
||||||
return function (classBody, ...args) {
|
super.parseClassMethod(classBody, ...args);
|
||||||
inner.call(this, classBody, ...args);
|
|
||||||
|
|
||||||
const body = classBody.body;
|
const body = classBody.body;
|
||||||
|
// $FlowIgnore
|
||||||
body[body.length - 1].type = "MethodDefinition";
|
body[body.length - 1].type = "MethodDefinition";
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("parseExprAtom", function(inner) {
|
parseExprAtom(...args): N.Expression {
|
||||||
return function (...args) {
|
|
||||||
switch (this.state.type) {
|
switch (this.state.type) {
|
||||||
case tt.regexp:
|
case tt.regexp:
|
||||||
return this.estreeParseRegExpLiteral(this.state.value);
|
return this.estreeParseRegExpLiteral(this.state.value);
|
||||||
@ -168,68 +160,63 @@ export default function (instance) {
|
|||||||
return this.estreeParseLiteral(false);
|
return this.estreeParseLiteral(false);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return inner.call(this, ...args);
|
return super.parseExprAtom(...args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("parseLiteral", function(inner) {
|
parseLiteral<T : N.Literal>(...args): T {
|
||||||
return function (...args) {
|
const node = super.parseLiteral(...args);
|
||||||
const node = inner.call(this, ...args);
|
|
||||||
node.raw = node.extra.raw;
|
node.raw = node.extra.raw;
|
||||||
delete node.extra;
|
delete node.extra;
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("parseMethod", function(inner) {
|
parseMethod(node: N.MethodLike, ...args): N.MethodLike {
|
||||||
return function (node, ...args) {
|
|
||||||
let funcNode = this.startNode();
|
let funcNode = this.startNode();
|
||||||
funcNode.kind = node.kind; // provide kind, so inner method correctly sets state
|
funcNode.kind = node.kind; // provide kind, so super method correctly sets state
|
||||||
funcNode = inner.call(this, funcNode, ...args);
|
funcNode = super.parseMethod(funcNode, ...args);
|
||||||
delete funcNode.kind;
|
delete funcNode.kind;
|
||||||
|
// $FlowIgnore
|
||||||
node.value = this.finishNode(funcNode, "FunctionExpression");
|
node.value = this.finishNode(funcNode, "FunctionExpression");
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("parseObjectMethod", function(inner) {
|
parseObjectMethod(...args): ?N.ObjectMethod {
|
||||||
return function (...args) {
|
const node = super.parseObjectMethod(...args);
|
||||||
const node = inner.call(this, ...args);
|
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
|
// $FlowIgnore
|
||||||
if (node.kind === "method") node.kind = "init";
|
if (node.kind === "method") node.kind = "init";
|
||||||
|
// $FlowIgnore
|
||||||
node.type = "Property";
|
node.type = "Property";
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("parseObjectProperty", function(inner) {
|
parseObjectProperty(...args): ?N.ObjectProperty {
|
||||||
return function (...args) {
|
const node = super.parseObjectProperty(...args);
|
||||||
const node = inner.call(this, ...args);
|
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
|
// $FlowIgnore
|
||||||
node.kind = "init";
|
node.kind = "init";
|
||||||
|
// $FlowIgnore
|
||||||
node.type = "Property";
|
node.type = "Property";
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("toAssignable", function(inner) {
|
toAssignable(node: N.Node, isBinding: ?boolean, ...args): N.Node {
|
||||||
return function (node, isBinding, ...args) {
|
|
||||||
if (isSimpleProperty(node)) {
|
if (isSimpleProperty(node)) {
|
||||||
this.toAssignable(node.value, isBinding, ...args);
|
this.toAssignable(node.value, isBinding, ...args);
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
} else if (node.type === "ObjectExpression") {
|
} else if (node.type === "ObjectExpression") {
|
||||||
node.type = "ObjectPattern";
|
node.type = "ObjectPattern";
|
||||||
for (const prop of (node.properties: Array<Object>)) {
|
for (const prop of node.properties) {
|
||||||
if (prop.kind === "get" || prop.kind === "set") {
|
if (prop.kind === "get" || prop.kind === "set") {
|
||||||
this.raise(prop.key.start, "Object pattern can't contain getter or setter");
|
this.raise(prop.key.start, "Object pattern can't contain getter or setter");
|
||||||
} else if (prop.method) {
|
} else if (prop.method) {
|
||||||
@ -242,7 +229,6 @@ export default function (instance) {
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
return inner.call(this, node, isBinding, ...args);
|
return super.toAssignable(node, isBinding, ...args);
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,12 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
import XHTMLEntities from "./xhtml";
|
import XHTMLEntities from "./xhtml";
|
||||||
|
import type Parser from "../../parser";
|
||||||
import { TokenType, types as tt } from "../../tokenizer/types";
|
import { TokenType, types as tt } from "../../tokenizer/types";
|
||||||
import { TokContext, types as tc } from "../../tokenizer/context";
|
import { TokContext, types as tc } from "../../tokenizer/context";
|
||||||
import Parser from "../../parser";
|
import * as N from "../../types";
|
||||||
import { isIdentifierChar, isIdentifierStart } from "../../util/identifier";
|
import { isIdentifierChar, isIdentifierStart } from "../../util/identifier";
|
||||||
|
import type { Pos, Position } from "../../util/location";
|
||||||
import { isNewLine } from "../../util/whitespace";
|
import { isNewLine } from "../../util/whitespace";
|
||||||
|
|
||||||
const HEX_NUMBER = /^[\da-fA-F]+$/;
|
const HEX_NUMBER = /^[\da-fA-F]+$/;
|
||||||
@ -33,11 +37,29 @@ tt.jsxTagEnd.updateContext = function(prevType) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const pp = Parser.prototype;
|
// Transforms JSX element name to string.
|
||||||
|
|
||||||
|
function getQualifiedJSXName(object: N.JSXIdentifier | N.JSXNamespacedName | N.JSXMemberExpression): string {
|
||||||
|
if (object.type === "JSXIdentifier") {
|
||||||
|
return object.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.type === "JSXNamespacedName") {
|
||||||
|
return object.namespace.name + ":" + object.name.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (object.type === "JSXMemberExpression") {
|
||||||
|
return getQualifiedJSXName(object.object) + "." + getQualifiedJSXName(object.property);
|
||||||
|
}
|
||||||
|
|
||||||
|
// istanbul ignore next
|
||||||
|
throw new Error("Node had unexpected type: " + object.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default (superClass: Class<Parser>): Class<Parser> => class extends superClass {
|
||||||
// Reads inline JSX contents token.
|
// Reads inline JSX contents token.
|
||||||
|
|
||||||
pp.jsxReadToken = function() {
|
jsxReadToken(): void {
|
||||||
let out = "";
|
let out = "";
|
||||||
let chunkStart = this.state.pos;
|
let chunkStart = this.state.pos;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -76,9 +98,9 @@ pp.jsxReadToken = function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.jsxReadNewLine = function(normalizeCRLF) {
|
jsxReadNewLine(normalizeCRLF: boolean): string {
|
||||||
const ch = this.input.charCodeAt(this.state.pos);
|
const ch = this.input.charCodeAt(this.state.pos);
|
||||||
let out;
|
let out;
|
||||||
++this.state.pos;
|
++this.state.pos;
|
||||||
@ -92,9 +114,9 @@ pp.jsxReadNewLine = function(normalizeCRLF) {
|
|||||||
this.state.lineStart = this.state.pos;
|
this.state.lineStart = this.state.pos;
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.jsxReadString = function(quote) {
|
jsxReadString(quote: number): void {
|
||||||
let out = "";
|
let out = "";
|
||||||
let chunkStart = ++this.state.pos;
|
let chunkStart = ++this.state.pos;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -118,9 +140,9 @@ pp.jsxReadString = function(quote) {
|
|||||||
}
|
}
|
||||||
out += this.input.slice(chunkStart, this.state.pos++);
|
out += this.input.slice(chunkStart, this.state.pos++);
|
||||||
return this.finishToken(tt.string, out);
|
return this.finishToken(tt.string, out);
|
||||||
};
|
}
|
||||||
|
|
||||||
pp.jsxReadEntity = function() {
|
jsxReadEntity(): string {
|
||||||
let str = "";
|
let str = "";
|
||||||
let count = 0;
|
let count = 0;
|
||||||
let entity;
|
let entity;
|
||||||
@ -152,7 +174,7 @@ pp.jsxReadEntity = function() {
|
|||||||
return "&";
|
return "&";
|
||||||
}
|
}
|
||||||
return entity;
|
return entity;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
// Read a JSX identifier (valid tag or attribute name).
|
// Read a JSX identifier (valid tag or attribute name).
|
||||||
@ -162,34 +184,18 @@ pp.jsxReadEntity = function() {
|
|||||||
// Also assumes that first character was already checked
|
// Also assumes that first character was already checked
|
||||||
// by isIdentifierStart in readToken.
|
// by isIdentifierStart in readToken.
|
||||||
|
|
||||||
pp.jsxReadWord = function() {
|
jsxReadWord(): void {
|
||||||
let ch;
|
let ch;
|
||||||
const start = this.state.pos;
|
const start = this.state.pos;
|
||||||
do {
|
do {
|
||||||
ch = this.input.charCodeAt(++this.state.pos);
|
ch = this.input.charCodeAt(++this.state.pos);
|
||||||
} while (isIdentifierChar(ch) || ch === 45); // "-"
|
} while (isIdentifierChar(ch) || ch === 45); // "-"
|
||||||
return this.finishToken(tt.jsxName, this.input.slice(start, this.state.pos));
|
return this.finishToken(tt.jsxName, this.input.slice(start, this.state.pos));
|
||||||
};
|
|
||||||
|
|
||||||
// Transforms JSX element name to string.
|
|
||||||
|
|
||||||
function getQualifiedJSXName(object) {
|
|
||||||
if (object.type === "JSXIdentifier") {
|
|
||||||
return object.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.type === "JSXNamespacedName") {
|
|
||||||
return object.namespace.name + ":" + object.name.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (object.type === "JSXMemberExpression") {
|
|
||||||
return getQualifiedJSXName(object.object) + "." + getQualifiedJSXName(object.property);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse next token as JSX identifier
|
// Parse next token as JSX identifier
|
||||||
|
|
||||||
pp.jsxParseIdentifier = function() {
|
jsxParseIdentifier(): N.JSXIdentifier {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
if (this.match(tt.jsxName)) {
|
if (this.match(tt.jsxName)) {
|
||||||
node.name = this.state.value;
|
node.name = this.state.value;
|
||||||
@ -200,11 +206,11 @@ pp.jsxParseIdentifier = function() {
|
|||||||
}
|
}
|
||||||
this.next();
|
this.next();
|
||||||
return this.finishNode(node, "JSXIdentifier");
|
return this.finishNode(node, "JSXIdentifier");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse namespaced identifier.
|
// Parse namespaced identifier.
|
||||||
|
|
||||||
pp.jsxParseNamespacedName = function() {
|
jsxParseNamespacedName(): N.JSXNamespacedName {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
const name = this.jsxParseIdentifier();
|
const name = this.jsxParseIdentifier();
|
||||||
@ -214,12 +220,12 @@ pp.jsxParseNamespacedName = function() {
|
|||||||
node.namespace = name;
|
node.namespace = name;
|
||||||
node.name = this.jsxParseIdentifier();
|
node.name = this.jsxParseIdentifier();
|
||||||
return this.finishNode(node, "JSXNamespacedName");
|
return this.finishNode(node, "JSXNamespacedName");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses element name in any form - namespaced, member
|
// Parses element name in any form - namespaced, member
|
||||||
// or single identifier.
|
// or single identifier.
|
||||||
|
|
||||||
pp.jsxParseElementName = function() {
|
jsxParseElementName(): N.JSXNamespacedName | N.JSXMemberExpression {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
let node = this.jsxParseNamespacedName();
|
let node = this.jsxParseNamespacedName();
|
||||||
@ -230,17 +236,17 @@ pp.jsxParseElementName = function() {
|
|||||||
node = this.finishNode(newNode, "JSXMemberExpression");
|
node = this.finishNode(newNode, "JSXMemberExpression");
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses any type of JSX attribute value.
|
// Parses any type of JSX attribute value.
|
||||||
|
|
||||||
pp.jsxParseAttributeValue = function() {
|
jsxParseAttributeValue(): N.Expression {
|
||||||
let node;
|
let node;
|
||||||
switch (this.state.type) {
|
switch (this.state.type) {
|
||||||
case tt.braceL:
|
case tt.braceL:
|
||||||
node = this.jsxParseExpressionContainer();
|
node = this.jsxParseExpressionContainer();
|
||||||
if (node.expression.type === "JSXEmptyExpression") {
|
if (node.expression.type === "JSXEmptyExpression") {
|
||||||
this.raise(node.start, "JSX attributes must only be assigned a non-empty expression");
|
throw this.raise(node.start, "JSX attributes must only be assigned a non-empty expression");
|
||||||
} else {
|
} else {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
@ -250,22 +256,22 @@ pp.jsxParseAttributeValue = function() {
|
|||||||
return this.parseExprAtom();
|
return this.parseExprAtom();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.raise(this.state.start, "JSX value should be either an expression or a quoted JSX text");
|
throw this.raise(this.state.start, "JSX value should be either an expression or a quoted JSX text");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// JSXEmptyExpression is unique type since it doesn't actually parse anything,
|
// JSXEmptyExpression is unique type since it doesn't actually parse anything,
|
||||||
// and so it should start at the end of last read token (left brace) and finish
|
// and so it should start at the end of last read token (left brace) and finish
|
||||||
// at the beginning of the next one (right brace).
|
// at the beginning of the next one (right brace).
|
||||||
|
|
||||||
pp.jsxParseEmptyExpression = function() {
|
jsxParseEmptyExpression(): N.JSXEmptyExpression {
|
||||||
const node = this.startNodeAt(this.state.lastTokEnd, this.state.lastTokEndLoc);
|
const node = this.startNodeAt(this.state.lastTokEnd, this.state.lastTokEndLoc);
|
||||||
return this.finishNodeAt(node, "JSXEmptyExpression", this.state.start, this.state.startLoc);
|
return this.finishNodeAt(node, "JSXEmptyExpression", this.state.start, this.state.startLoc);
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parse JSX spread child
|
// Parse JSX spread child
|
||||||
|
|
||||||
pp.jsxParseSpreadChild = function() {
|
jsxParseSpreadChild(): N.JSXSpreadChild {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.expect(tt.braceL);
|
this.expect(tt.braceL);
|
||||||
this.expect(tt.ellipsis);
|
this.expect(tt.ellipsis);
|
||||||
@ -273,12 +279,12 @@ pp.jsxParseSpreadChild = function() {
|
|||||||
this.expect(tt.braceR);
|
this.expect(tt.braceR);
|
||||||
|
|
||||||
return this.finishNode(node, "JSXSpreadChild");
|
return this.finishNode(node, "JSXSpreadChild");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses JSX expression enclosed into curly brackets.
|
// Parses JSX expression enclosed into curly brackets.
|
||||||
|
|
||||||
|
|
||||||
pp.jsxParseExpressionContainer = function() {
|
jsxParseExpressionContainer(): N.JSXExpressionContainer {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
if (this.match(tt.braceR)) {
|
if (this.match(tt.braceR)) {
|
||||||
@ -288,11 +294,11 @@ pp.jsxParseExpressionContainer = function() {
|
|||||||
}
|
}
|
||||||
this.expect(tt.braceR);
|
this.expect(tt.braceR);
|
||||||
return this.finishNode(node, "JSXExpressionContainer");
|
return this.finishNode(node, "JSXExpressionContainer");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses following JSX attribute name-value pair.
|
// Parses following JSX attribute name-value pair.
|
||||||
|
|
||||||
pp.jsxParseAttribute = function() {
|
jsxParseAttribute(): N.JSXAttribute {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
if (this.eat(tt.braceL)) {
|
if (this.eat(tt.braceL)) {
|
||||||
this.expect(tt.ellipsis);
|
this.expect(tt.ellipsis);
|
||||||
@ -303,11 +309,11 @@ pp.jsxParseAttribute = function() {
|
|||||||
node.name = this.jsxParseNamespacedName();
|
node.name = this.jsxParseNamespacedName();
|
||||||
node.value = this.eat(tt.eq) ? this.jsxParseAttributeValue() : null;
|
node.value = this.eat(tt.eq) ? this.jsxParseAttributeValue() : null;
|
||||||
return this.finishNode(node, "JSXAttribute");
|
return this.finishNode(node, "JSXAttribute");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses JSX opening tag starting after "<".
|
// Parses JSX opening tag starting after "<".
|
||||||
|
|
||||||
pp.jsxParseOpeningElementAt = function(startPos, startLoc) {
|
jsxParseOpeningElementAt(startPos: number, startLoc: Position): N.JSXOpeningElement {
|
||||||
const node = this.startNodeAt(startPos, startLoc);
|
const node = this.startNodeAt(startPos, startLoc);
|
||||||
node.attributes = [];
|
node.attributes = [];
|
||||||
node.name = this.jsxParseElementName();
|
node.name = this.jsxParseElementName();
|
||||||
@ -317,21 +323,21 @@ pp.jsxParseOpeningElementAt = function(startPos, startLoc) {
|
|||||||
node.selfClosing = this.eat(tt.slash);
|
node.selfClosing = this.eat(tt.slash);
|
||||||
this.expect(tt.jsxTagEnd);
|
this.expect(tt.jsxTagEnd);
|
||||||
return this.finishNode(node, "JSXOpeningElement");
|
return this.finishNode(node, "JSXOpeningElement");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses JSX closing tag starting after "</".
|
// Parses JSX closing tag starting after "</".
|
||||||
|
|
||||||
pp.jsxParseClosingElementAt = function(startPos, startLoc) {
|
jsxParseClosingElementAt(startPos: number, startLoc: Position): N.JSXClosingElement {
|
||||||
const node = this.startNodeAt(startPos, startLoc);
|
const node = this.startNodeAt(startPos, startLoc);
|
||||||
node.name = this.jsxParseElementName();
|
node.name = this.jsxParseElementName();
|
||||||
this.expect(tt.jsxTagEnd);
|
this.expect(tt.jsxTagEnd);
|
||||||
return this.finishNode(node, "JSXClosingElement");
|
return this.finishNode(node, "JSXClosingElement");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses entire JSX element, including it"s opening tag
|
// Parses entire JSX element, including it"s opening tag
|
||||||
// (starting after "<"), attributes, contents and closing tag.
|
// (starting after "<"), attributes, contents and closing tag.
|
||||||
|
|
||||||
pp.jsxParseElementAt = function(startPos, startLoc) {
|
jsxParseElementAt(startPos: number, startLoc: Position): N.JSXElement {
|
||||||
const node = this.startNodeAt(startPos, startLoc);
|
const node = this.startNodeAt(startPos, startLoc);
|
||||||
const children = [];
|
const children = [];
|
||||||
const openingElement = this.jsxParseOpeningElementAt(startPos, startLoc);
|
const openingElement = this.jsxParseOpeningElementAt(startPos, startLoc);
|
||||||
@ -365,12 +371,14 @@ pp.jsxParseElementAt = function(startPos, startLoc) {
|
|||||||
|
|
||||||
// istanbul ignore next - should never happen
|
// istanbul ignore next - should never happen
|
||||||
default:
|
default:
|
||||||
this.unexpected();
|
throw this.unexpected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// $FlowIgnore
|
||||||
if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name)) {
|
if (getQualifiedJSXName(closingElement.name) !== getQualifiedJSXName(openingElement.name)) {
|
||||||
this.raise(
|
this.raise(
|
||||||
|
// $FlowIgnore
|
||||||
closingElement.start,
|
closingElement.start,
|
||||||
"Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">"
|
"Expected corresponding JSX closing tag for <" + getQualifiedJSXName(openingElement.name) + ">"
|
||||||
);
|
);
|
||||||
@ -384,33 +392,33 @@ pp.jsxParseElementAt = function(startPos, startLoc) {
|
|||||||
this.raise(this.state.start, "Adjacent JSX elements must be wrapped in an enclosing tag");
|
this.raise(this.state.start, "Adjacent JSX elements must be wrapped in an enclosing tag");
|
||||||
}
|
}
|
||||||
return this.finishNode(node, "JSXElement");
|
return this.finishNode(node, "JSXElement");
|
||||||
};
|
}
|
||||||
|
|
||||||
// Parses entire JSX element from current position.
|
// Parses entire JSX element from current position.
|
||||||
|
|
||||||
pp.jsxParseElement = function() {
|
jsxParseElement(): N.JSXElement {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
this.next();
|
this.next();
|
||||||
return this.jsxParseElementAt(startPos, startLoc);
|
return this.jsxParseElementAt(startPos, startLoc);
|
||||||
};
|
}
|
||||||
|
|
||||||
export default function(instance) {
|
// ==================================
|
||||||
instance.extend("parseExprAtom", function(inner) {
|
// Overrides
|
||||||
return function(refShortHandDefaultPos) {
|
// ==================================
|
||||||
|
|
||||||
|
parseExprAtom(refShortHandDefaultPos: ?Pos): N.Expression {
|
||||||
if (this.match(tt.jsxText)) {
|
if (this.match(tt.jsxText)) {
|
||||||
return this.parseLiteral(this.state.value, "JSXText");
|
return this.parseLiteral(this.state.value, "JSXText");
|
||||||
} else if (this.match(tt.jsxTagStart)) {
|
} else if (this.match(tt.jsxTagStart)) {
|
||||||
return this.jsxParseElement();
|
return this.jsxParseElement();
|
||||||
} else {
|
} else {
|
||||||
return inner.call(this, refShortHandDefaultPos);
|
return super.parseExprAtom(refShortHandDefaultPos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("readToken", function(inner) {
|
readToken(code: number): void {
|
||||||
return function(code) {
|
if (this.state.inPropertyName) return super.readToken(code);
|
||||||
if (this.state.inPropertyName) return inner.call(this, code);
|
|
||||||
|
|
||||||
const context = this.curContext();
|
const context = this.curContext();
|
||||||
|
|
||||||
@ -438,12 +446,10 @@ export default function(instance) {
|
|||||||
return this.finishToken(tt.jsxTagStart);
|
return this.finishToken(tt.jsxTagStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return inner.call(this, code);
|
return super.readToken(code);
|
||||||
};
|
}
|
||||||
});
|
|
||||||
|
|
||||||
instance.extend("updateContext", function(inner) {
|
updateContext(prevType: TokenType): void {
|
||||||
return function(prevType) {
|
|
||||||
if (this.match(tt.braceL)) {
|
if (this.match(tt.braceL)) {
|
||||||
const curContext = this.curContext();
|
const curContext = this.curContext();
|
||||||
if (curContext === tc.j_oTag) {
|
if (curContext === tc.j_oTag) {
|
||||||
@ -451,7 +457,7 @@ export default function(instance) {
|
|||||||
} else if (curContext === tc.j_expr) {
|
} else if (curContext === tc.j_expr) {
|
||||||
this.state.context.push(tc.templateQuasi);
|
this.state.context.push(tc.templateQuasi);
|
||||||
} else {
|
} else {
|
||||||
inner.call(this, prevType);
|
super.updateContext(prevType);
|
||||||
}
|
}
|
||||||
this.state.exprAllowed = true;
|
this.state.exprAllowed = true;
|
||||||
} else if (this.match(tt.slash) && prevType === tt.jsxTagStart) {
|
} else if (this.match(tt.slash) && prevType === tt.jsxTagStart) {
|
||||||
@ -459,8 +465,7 @@ export default function(instance) {
|
|||||||
this.state.context.push(tc.j_cTag); // reconsider as closing tag context
|
this.state.context.push(tc.j_cTag); // reconsider as closing tag context
|
||||||
this.state.exprAllowed = false;
|
this.state.exprAllowed = false;
|
||||||
} else {
|
} else {
|
||||||
return inner.call(this, prevType);
|
return super.updateContext(prevType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
export default {
|
// @flow
|
||||||
|
|
||||||
|
const entities: { [name: string]: string } = {
|
||||||
quot: "\u0022",
|
quot: "\u0022",
|
||||||
amp: "&",
|
amp: "&",
|
||||||
apos: "\u0027",
|
apos: "\u0027",
|
||||||
@ -253,3 +255,4 @@ export default {
|
|||||||
hearts: "\u2665",
|
hearts: "\u2665",
|
||||||
diams: "\u2666"
|
diams: "\u2666"
|
||||||
};
|
};
|
||||||
|
export default entities;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
// The algorithm used to determine whether a regexp can appear at a
|
// The algorithm used to determine whether a regexp can appear at a
|
||||||
// given point in the program is loosely based on sweet.js' approach.
|
// given point in the program is loosely based on sweet.js' approach.
|
||||||
// See https://github.com/mozilla/sweet.js/wiki/design
|
// See https://github.com/mozilla/sweet.js/wiki/design
|
||||||
|
|||||||
@ -1,19 +1,41 @@
|
|||||||
/* eslint max-len: 0 */
|
/* eslint max-len: 0 */
|
||||||
|
|
||||||
|
// @flow
|
||||||
|
|
||||||
import type { TokenType } from "./types";
|
import type { TokenType } from "./types";
|
||||||
|
import type { Options } from "../options";
|
||||||
|
import type { Position } from "../util/location";
|
||||||
import { isIdentifierStart, isIdentifierChar, isKeyword } from "../util/identifier";
|
import { isIdentifierStart, isIdentifierChar, isKeyword } from "../util/identifier";
|
||||||
import { types as tt, keywords as keywordTypes } from "./types";
|
import { types as tt, keywords as keywordTypes } from "./types";
|
||||||
import { types as ct } from "./context";
|
import { type TokContext, types as ct } from "./context";
|
||||||
|
import LocationParser from "../parser/location";
|
||||||
import { SourceLocation } from "../util/location";
|
import { SourceLocation } from "../util/location";
|
||||||
import { lineBreak, lineBreakG, isNewLine, nonASCIIwhitespace } from "../util/whitespace";
|
import { lineBreak, lineBreakG, isNewLine, nonASCIIwhitespace } from "../util/whitespace";
|
||||||
import State from "./state";
|
import State from "./state";
|
||||||
|
|
||||||
|
|
||||||
|
// The following character codes are forbidden from being
|
||||||
|
// an immediate sibling of NumericLiteralSeparator _
|
||||||
|
|
||||||
|
const forbiddenNumericLiteralSeparatorSiblings = [
|
||||||
|
46, // .
|
||||||
|
66, // B
|
||||||
|
69, // E
|
||||||
|
79, // O
|
||||||
|
88, // X
|
||||||
|
95, // _ (multiple separators are not allowed)
|
||||||
|
98, // b
|
||||||
|
101, // e
|
||||||
|
111, // o
|
||||||
|
120, // x
|
||||||
|
];
|
||||||
|
|
||||||
// Object type used to represent tokens. Note that normally, tokens
|
// Object type used to represent tokens. Note that normally, tokens
|
||||||
// simply exist as properties on the parser object. This is only
|
// simply exist as properties on the parser object. This is only
|
||||||
// used for the onToken callback and the external tokenizer.
|
// used for the onToken callback and the external tokenizer.
|
||||||
|
|
||||||
export class Token {
|
export class Token {
|
||||||
constructor(state) {
|
constructor(state: State) {
|
||||||
this.type = state.type;
|
this.type = state.type;
|
||||||
this.value = state.value;
|
this.value = state.value;
|
||||||
this.start = state.start;
|
this.start = state.start;
|
||||||
@ -30,7 +52,7 @@ export class Token {
|
|||||||
|
|
||||||
// ## Tokenizer
|
// ## Tokenizer
|
||||||
|
|
||||||
function codePointToString(code) {
|
function codePointToString(code: number): string {
|
||||||
// UTF-16 Decoding
|
// UTF-16 Decoding
|
||||||
if (code <= 0xFFFF) {
|
if (code <= 0xFFFF) {
|
||||||
return String.fromCharCode(code);
|
return String.fromCharCode(code);
|
||||||
@ -39,15 +61,22 @@ function codePointToString(code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Tokenizer {
|
export default class Tokenizer extends LocationParser {
|
||||||
constructor(options, input) {
|
// Forward-declarations
|
||||||
|
// parser/util.js
|
||||||
|
+unexpected: (pos?: ?number, messageOrType?: string | TokenType) => empty;
|
||||||
|
|
||||||
|
isLookahead: boolean;
|
||||||
|
|
||||||
|
constructor(options: Options, input: string) {
|
||||||
|
super();
|
||||||
this.state = new State;
|
this.state = new State;
|
||||||
this.state.init(options, input);
|
this.state.init(options, input);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move to the next token
|
// Move to the next token
|
||||||
|
|
||||||
next() {
|
next(): void {
|
||||||
if (!this.isLookahead) {
|
if (!this.isLookahead) {
|
||||||
this.state.tokens.push(new Token(this.state));
|
this.state.tokens.push(new Token(this.state));
|
||||||
}
|
}
|
||||||
@ -61,7 +90,7 @@ export default class Tokenizer {
|
|||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
eat(type) {
|
eat(type: TokenType): boolean {
|
||||||
if (this.match(type)) {
|
if (this.match(type)) {
|
||||||
this.next();
|
this.next();
|
||||||
return true;
|
return true;
|
||||||
@ -72,19 +101,19 @@ export default class Tokenizer {
|
|||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
match(type) {
|
match(type: TokenType): boolean {
|
||||||
return this.state.type === type;
|
return this.state.type === type;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
isKeyword(word) {
|
isKeyword(word: string): boolean {
|
||||||
return isKeyword(word);
|
return isKeyword(word);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
lookahead() {
|
lookahead(): State {
|
||||||
const old = this.state;
|
const old = this.state;
|
||||||
this.state = old.clone(true);
|
this.state = old.clone(true);
|
||||||
|
|
||||||
@ -100,7 +129,7 @@ export default class Tokenizer {
|
|||||||
// Toggle strict mode. Re-reads the next number or string to please
|
// Toggle strict mode. Re-reads the next number or string to please
|
||||||
// pedantic tests (`"use strict"; 010;` should fail).
|
// pedantic tests (`"use strict"; 010;` should fail).
|
||||||
|
|
||||||
setStrict(strict) {
|
setStrict(strict: boolean): void {
|
||||||
this.state.strict = strict;
|
this.state.strict = strict;
|
||||||
if (!this.match(tt.num) && !this.match(tt.string)) return;
|
if (!this.match(tt.num) && !this.match(tt.string)) return;
|
||||||
this.state.pos = this.state.start;
|
this.state.pos = this.state.start;
|
||||||
@ -111,14 +140,14 @@ export default class Tokenizer {
|
|||||||
this.nextToken();
|
this.nextToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
curContext() {
|
curContext(): TokContext {
|
||||||
return this.state.context[this.state.context.length - 1];
|
return this.state.context[this.state.context.length - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read a single token, updating the parser object's token-related
|
// Read a single token, updating the parser object's token-related
|
||||||
// properties.
|
// properties.
|
||||||
|
|
||||||
nextToken() {
|
nextToken(): void {
|
||||||
const curContext = this.curContext();
|
const curContext = this.curContext();
|
||||||
if (!curContext || !curContext.preserveSpace) this.skipSpace();
|
if (!curContext || !curContext.preserveSpace) this.skipSpace();
|
||||||
|
|
||||||
@ -135,7 +164,7 @@ export default class Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readToken(code) {
|
readToken(code: number): void {
|
||||||
// Identifier or keyword. '\uXXXX' sequences are allowed in
|
// Identifier or keyword. '\uXXXX' sequences are allowed in
|
||||||
// identifiers, so '\' also dispatches to that.
|
// identifiers, so '\' also dispatches to that.
|
||||||
if (isIdentifierStart(code) || code === 92 /* '\' */) {
|
if (isIdentifierStart(code) || code === 92 /* '\' */) {
|
||||||
@ -145,7 +174,7 @@ export default class Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fullCharCodeAtPos() {
|
fullCharCodeAtPos(): number {
|
||||||
const code = this.input.charCodeAt(this.state.pos);
|
const code = this.input.charCodeAt(this.state.pos);
|
||||||
if (code <= 0xd7ff || code >= 0xe000) return code;
|
if (code <= 0xd7ff || code >= 0xe000) return code;
|
||||||
|
|
||||||
@ -153,7 +182,7 @@ export default class Tokenizer {
|
|||||||
return (code << 10) + next - 0x35fdc00;
|
return (code << 10) + next - 0x35fdc00;
|
||||||
}
|
}
|
||||||
|
|
||||||
pushComment(block, text, start, end, startLoc, endLoc) {
|
pushComment(block: boolean, text: string, start: number, end: number, startLoc: Position, endLoc: Position): void {
|
||||||
const comment = {
|
const comment = {
|
||||||
type: block ? "CommentBlock" : "CommentLine",
|
type: block ? "CommentBlock" : "CommentLine",
|
||||||
value: text,
|
value: text,
|
||||||
@ -169,7 +198,7 @@ export default class Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skipBlockComment() {
|
skipBlockComment(): void {
|
||||||
const startLoc = this.state.curPosition();
|
const startLoc = this.state.curPosition();
|
||||||
const start = this.state.pos;
|
const start = this.state.pos;
|
||||||
const end = this.input.indexOf("*/", this.state.pos += 2);
|
const end = this.input.indexOf("*/", this.state.pos += 2);
|
||||||
@ -186,7 +215,7 @@ export default class Tokenizer {
|
|||||||
this.pushComment(true, this.input.slice(start + 2, end), start, this.state.pos, startLoc, this.state.curPosition());
|
this.pushComment(true, this.input.slice(start + 2, end), start, this.state.pos, startLoc, this.state.curPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
skipLineComment(startSkip) {
|
skipLineComment(startSkip: number): void {
|
||||||
const start = this.state.pos;
|
const start = this.state.pos;
|
||||||
const startLoc = this.state.curPosition();
|
const startLoc = this.state.curPosition();
|
||||||
let ch = this.input.charCodeAt(this.state.pos += startSkip);
|
let ch = this.input.charCodeAt(this.state.pos += startSkip);
|
||||||
@ -201,7 +230,7 @@ export default class Tokenizer {
|
|||||||
// Called at the start of the parse and after every token. Skips
|
// Called at the start of the parse and after every token. Skips
|
||||||
// whitespace and comments, and.
|
// whitespace and comments, and.
|
||||||
|
|
||||||
skipSpace() {
|
skipSpace(): void {
|
||||||
loop: while (this.state.pos < this.input.length) {
|
loop: while (this.state.pos < this.input.length) {
|
||||||
const ch = this.input.charCodeAt(this.state.pos);
|
const ch = this.input.charCodeAt(this.state.pos);
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
@ -250,7 +279,7 @@ export default class Tokenizer {
|
|||||||
// the token, so that the next one's `start` will point at the
|
// the token, so that the next one's `start` will point at the
|
||||||
// right position.
|
// right position.
|
||||||
|
|
||||||
finishToken(type, val) {
|
finishToken(type: TokenType, val: any): void {
|
||||||
this.state.end = this.state.pos;
|
this.state.end = this.state.pos;
|
||||||
this.state.endLoc = this.state.curPosition();
|
this.state.endLoc = this.state.curPosition();
|
||||||
const prevType = this.state.type;
|
const prevType = this.state.type;
|
||||||
@ -269,7 +298,7 @@ export default class Tokenizer {
|
|||||||
//
|
//
|
||||||
// All in the name of speed.
|
// All in the name of speed.
|
||||||
//
|
//
|
||||||
readToken_dot() {
|
readToken_dot(): void {
|
||||||
const next = this.input.charCodeAt(this.state.pos + 1);
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
||||||
if (next >= 48 && next <= 57) {
|
if (next >= 48 && next <= 57) {
|
||||||
return this.readNumber(true);
|
return this.readNumber(true);
|
||||||
@ -285,7 +314,7 @@ export default class Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readToken_slash() { // '/'
|
readToken_slash(): void { // '/'
|
||||||
if (this.state.exprAllowed) {
|
if (this.state.exprAllowed) {
|
||||||
++this.state.pos;
|
++this.state.pos;
|
||||||
return this.readRegexp();
|
return this.readRegexp();
|
||||||
@ -299,7 +328,7 @@ export default class Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readToken_mult_modulo(code) { // '%*'
|
readToken_mult_modulo(code: number): void { // '%*'
|
||||||
let type = code === 42 ? tt.star : tt.modulo;
|
let type = code === 42 ? tt.star : tt.modulo;
|
||||||
let width = 1;
|
let width = 1;
|
||||||
let next = this.input.charCodeAt(this.state.pos + 1);
|
let next = this.input.charCodeAt(this.state.pos + 1);
|
||||||
@ -318,7 +347,7 @@ export default class Tokenizer {
|
|||||||
return this.finishOp(type, width);
|
return this.finishOp(type, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
readToken_pipe_amp(code) { // '|&'
|
readToken_pipe_amp(code: number): void { // '|&'
|
||||||
const next = this.input.charCodeAt(this.state.pos + 1);
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
||||||
if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2);
|
if (next === code) return this.finishOp(code === 124 ? tt.logicalOR : tt.logicalAND, 2);
|
||||||
if (next === 61) return this.finishOp(tt.assign, 2);
|
if (next === 61) return this.finishOp(tt.assign, 2);
|
||||||
@ -326,7 +355,7 @@ export default class Tokenizer {
|
|||||||
return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1);
|
return this.finishOp(code === 124 ? tt.bitwiseOR : tt.bitwiseAND, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
readToken_caret() { // '^'
|
readToken_caret(): void { // '^'
|
||||||
const next = this.input.charCodeAt(this.state.pos + 1);
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
||||||
if (next === 61) {
|
if (next === 61) {
|
||||||
return this.finishOp(tt.assign, 2);
|
return this.finishOp(tt.assign, 2);
|
||||||
@ -335,7 +364,7 @@ export default class Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readToken_plus_min(code) { // '+-'
|
readToken_plus_min(code: number): void { // '+-'
|
||||||
const next = this.input.charCodeAt(this.state.pos + 1);
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
||||||
|
|
||||||
if (next === code) {
|
if (next === code) {
|
||||||
@ -355,7 +384,7 @@ export default class Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readToken_lt_gt(code) { // '<>'
|
readToken_lt_gt(code: number): void { // '<>'
|
||||||
const next = this.input.charCodeAt(this.state.pos + 1);
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
||||||
let size = 1;
|
let size = 1;
|
||||||
|
|
||||||
@ -381,7 +410,7 @@ export default class Tokenizer {
|
|||||||
return this.finishOp(tt.relational, size);
|
return this.finishOp(tt.relational, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
readToken_eq_excl(code) { // '=!'
|
readToken_eq_excl(code: number): void { // '=!'
|
||||||
const next = this.input.charCodeAt(this.state.pos + 1);
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
||||||
if (next === 61) return this.finishOp(tt.equality, this.input.charCodeAt(this.state.pos + 2) === 61 ? 3 : 2);
|
if (next === 61) return this.finishOp(tt.equality, this.input.charCodeAt(this.state.pos + 2) === 61 ? 3 : 2);
|
||||||
if (code === 61 && next === 62) { // '=>'
|
if (code === 61 && next === 62) { // '=>'
|
||||||
@ -403,10 +432,19 @@ export default class Tokenizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getTokenFromCode(code) {
|
getTokenFromCode(code: number): void {
|
||||||
switch (code) {
|
switch (code) {
|
||||||
|
|
||||||
|
case 35: // '#'
|
||||||
|
if (this.hasPlugin("classPrivateProperties") && this.state.inClass) {
|
||||||
|
++this.state.pos; return this.finishToken(tt.hash);
|
||||||
|
} else {
|
||||||
|
this.raise(this.state.pos, `Unexpected character '${codePointToString(code)}'`);
|
||||||
|
}
|
||||||
|
|
||||||
// The interpretation of a dot depends on whether it is followed
|
// The interpretation of a dot depends on whether it is followed
|
||||||
// by a digit or another two dots.
|
// by a digit or another two dots.
|
||||||
|
|
||||||
case 46: // '.'
|
case 46: // '.'
|
||||||
return this.readToken_dot();
|
return this.readToken_dot();
|
||||||
|
|
||||||
@ -491,13 +529,13 @@ export default class Tokenizer {
|
|||||||
this.raise(this.state.pos, `Unexpected character '${codePointToString(code)}'`);
|
this.raise(this.state.pos, `Unexpected character '${codePointToString(code)}'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
finishOp(type, size) {
|
finishOp(type: TokenType, size: number): void {
|
||||||
const str = this.input.slice(this.state.pos, this.state.pos + size);
|
const str = this.input.slice(this.state.pos, this.state.pos + size);
|
||||||
this.state.pos += size;
|
this.state.pos += size;
|
||||||
return this.finishToken(type, str);
|
return this.finishToken(type, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
readRegexp() {
|
readRegexp(): void {
|
||||||
const start = this.state.pos;
|
const start = this.state.pos;
|
||||||
let escaped, inClass;
|
let escaped, inClass;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -539,13 +577,30 @@ export default class Tokenizer {
|
|||||||
// were read, the integer value otherwise. When `len` is given, this
|
// were read, the integer value otherwise. When `len` is given, this
|
||||||
// will return `null` unless the integer has exactly `len` digits.
|
// will return `null` unless the integer has exactly `len` digits.
|
||||||
|
|
||||||
readInt(radix, len) {
|
readInt(radix: number, len?: number): number | null {
|
||||||
const start = this.state.pos;
|
const start = this.state.pos;
|
||||||
let total = 0;
|
let total = 0;
|
||||||
|
|
||||||
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
|
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
|
||||||
const code = this.input.charCodeAt(this.state.pos);
|
const code = this.input.charCodeAt(this.state.pos);
|
||||||
let val;
|
let val;
|
||||||
|
|
||||||
|
if (this.hasPlugin("numericSeparator")) {
|
||||||
|
const prev = this.input.charCodeAt(this.state.pos - 1);
|
||||||
|
const next = this.input.charCodeAt(this.state.pos + 1);
|
||||||
|
if (code === 95) {
|
||||||
|
if ((forbiddenNumericLiteralSeparatorSiblings.indexOf(prev) > -1) ||
|
||||||
|
(forbiddenNumericLiteralSeparatorSiblings.indexOf(next) > -1) ||
|
||||||
|
Number.isNaN(next)) {
|
||||||
|
this.raise(this.state.pos, "Invalid NumericLiteralSeparator");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore this _ character
|
||||||
|
++this.state.pos;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (code >= 97) {
|
if (code >= 97) {
|
||||||
val = code - 97 + 10; // a
|
val = code - 97 + 10; // a
|
||||||
} else if (code >= 65) {
|
} else if (code >= 65) {
|
||||||
@ -564,7 +619,7 @@ export default class Tokenizer {
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
readRadixNumber(radix) {
|
readRadixNumber(radix: number): void {
|
||||||
this.state.pos += 2; // 0x
|
this.state.pos += 2; // 0x
|
||||||
const val = this.readInt(radix);
|
const val = this.readInt(radix);
|
||||||
if (val == null) this.raise(this.state.start + 2, "Expected number in radix " + radix);
|
if (val == null) this.raise(this.state.start + 2, "Expected number in radix " + radix);
|
||||||
@ -574,32 +629,36 @@ export default class Tokenizer {
|
|||||||
|
|
||||||
// Read an integer, octal integer, or floating-point number.
|
// Read an integer, octal integer, or floating-point number.
|
||||||
|
|
||||||
readNumber(startsWithDot) {
|
readNumber(startsWithDot: boolean): void {
|
||||||
const start = this.state.pos;
|
const start = this.state.pos;
|
||||||
const firstIsZero = this.input.charCodeAt(start) === 48; // '0'
|
let octal = this.input.charCodeAt(start) === 48; // '0'
|
||||||
let isFloat = false;
|
let isFloat = false;
|
||||||
|
|
||||||
if (!startsWithDot && this.readInt(10) === null) this.raise(start, "Invalid number");
|
if (!startsWithDot && this.readInt(10) === null) this.raise(start, "Invalid number");
|
||||||
|
if (octal && this.state.pos == start + 1) octal = false; // number === 0
|
||||||
|
|
||||||
let next = this.input.charCodeAt(this.state.pos);
|
let next = this.input.charCodeAt(this.state.pos);
|
||||||
if (next === 46) { // '.'
|
if (next === 46 && !octal) { // '.'
|
||||||
++this.state.pos;
|
++this.state.pos;
|
||||||
this.readInt(10);
|
this.readInt(10);
|
||||||
isFloat = true;
|
isFloat = true;
|
||||||
next = this.input.charCodeAt(this.state.pos);
|
next = this.input.charCodeAt(this.state.pos);
|
||||||
}
|
}
|
||||||
if (next === 69 || next === 101) { // 'eE'
|
|
||||||
|
if ((next === 69 || next === 101) && !octal) { // 'eE'
|
||||||
next = this.input.charCodeAt(++this.state.pos);
|
next = this.input.charCodeAt(++this.state.pos);
|
||||||
if (next === 43 || next === 45) ++this.state.pos; // '+-'
|
if (next === 43 || next === 45) ++this.state.pos; // '+-'
|
||||||
if (this.readInt(10) === null) this.raise(start, "Invalid number");
|
if (this.readInt(10) === null) this.raise(start, "Invalid number");
|
||||||
isFloat = true;
|
isFloat = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isIdentifierStart(this.fullCharCodeAtPos())) this.raise(this.state.pos, "Identifier directly after number");
|
if (isIdentifierStart(this.fullCharCodeAtPos())) this.raise(this.state.pos, "Identifier directly after number");
|
||||||
|
|
||||||
const str = this.input.slice(start, this.state.pos);
|
const str = this.input.slice(start, this.state.pos).replace(/_/g, "");
|
||||||
let val;
|
let val;
|
||||||
if (isFloat) {
|
if (isFloat) {
|
||||||
val = parseFloat(str);
|
val = parseFloat(str);
|
||||||
} else if (!firstIsZero || str.length === 1) {
|
} else if (!octal || str.length === 1) {
|
||||||
val = parseInt(str, 10);
|
val = parseInt(str, 10);
|
||||||
} else if (this.state.strict) {
|
} else if (this.state.strict) {
|
||||||
this.raise(start, "Invalid number");
|
this.raise(start, "Invalid number");
|
||||||
@ -613,7 +672,7 @@ export default class Tokenizer {
|
|||||||
|
|
||||||
// Read a string value, interpreting backslash-escapes.
|
// Read a string value, interpreting backslash-escapes.
|
||||||
|
|
||||||
readCodePoint(throwOnInvalid) {
|
readCodePoint(throwOnInvalid: boolean): number | null {
|
||||||
const ch = this.input.charCodeAt(this.state.pos);
|
const ch = this.input.charCodeAt(this.state.pos);
|
||||||
let code;
|
let code;
|
||||||
|
|
||||||
@ -622,6 +681,7 @@ export default class Tokenizer {
|
|||||||
code = this.readHexChar(this.input.indexOf("}", this.state.pos) - this.state.pos, throwOnInvalid);
|
code = this.readHexChar(this.input.indexOf("}", this.state.pos) - this.state.pos, throwOnInvalid);
|
||||||
++this.state.pos;
|
++this.state.pos;
|
||||||
if (code === null) {
|
if (code === null) {
|
||||||
|
// $FlowFixMe (is this always non-null?)
|
||||||
--this.state.invalidTemplateEscapePosition; // to point to the '\'' instead of the 'u'
|
--this.state.invalidTemplateEscapePosition; // to point to the '\'' instead of the 'u'
|
||||||
} else if (code > 0x10FFFF) {
|
} else if (code > 0x10FFFF) {
|
||||||
if (throwOnInvalid) {
|
if (throwOnInvalid) {
|
||||||
@ -637,7 +697,7 @@ export default class Tokenizer {
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
readString(quote) {
|
readString(quote: number): void {
|
||||||
let out = "", chunkStart = ++this.state.pos;
|
let out = "", chunkStart = ++this.state.pos;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (this.state.pos >= this.input.length) this.raise(this.state.start, "Unterminated string constant");
|
if (this.state.pos >= this.input.length) this.raise(this.state.start, "Unterminated string constant");
|
||||||
@ -645,6 +705,7 @@ export default class Tokenizer {
|
|||||||
if (ch === quote) break;
|
if (ch === quote) break;
|
||||||
if (ch === 92) { // '\'
|
if (ch === 92) { // '\'
|
||||||
out += this.input.slice(chunkStart, this.state.pos);
|
out += this.input.slice(chunkStart, this.state.pos);
|
||||||
|
// $FlowFixMe
|
||||||
out += this.readEscapedChar(false);
|
out += this.readEscapedChar(false);
|
||||||
chunkStart = this.state.pos;
|
chunkStart = this.state.pos;
|
||||||
} else {
|
} else {
|
||||||
@ -658,7 +719,7 @@ export default class Tokenizer {
|
|||||||
|
|
||||||
// Reads template string tokens.
|
// Reads template string tokens.
|
||||||
|
|
||||||
readTmplToken() {
|
readTmplToken(): void {
|
||||||
let out = "", chunkStart = this.state.pos, containsInvalid = false;
|
let out = "", chunkStart = this.state.pos, containsInvalid = false;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (this.state.pos >= this.input.length) this.raise(this.state.start, "Unterminated template");
|
if (this.state.pos >= this.input.length) this.raise(this.state.start, "Unterminated template");
|
||||||
@ -709,7 +770,7 @@ export default class Tokenizer {
|
|||||||
|
|
||||||
// Used to read escaped characters
|
// Used to read escaped characters
|
||||||
|
|
||||||
readEscapedChar(inTemplate) {
|
readEscapedChar(inTemplate: boolean): string | null {
|
||||||
const throwOnInvalid = !inTemplate;
|
const throwOnInvalid = !inTemplate;
|
||||||
const ch = this.input.charCodeAt(++this.state.pos);
|
const ch = this.input.charCodeAt(++this.state.pos);
|
||||||
++this.state.pos;
|
++this.state.pos;
|
||||||
@ -736,6 +797,7 @@ export default class Tokenizer {
|
|||||||
default:
|
default:
|
||||||
if (ch >= 48 && ch <= 55) {
|
if (ch >= 48 && ch <= 55) {
|
||||||
const codePos = this.state.pos - 1;
|
const codePos = this.state.pos - 1;
|
||||||
|
// $FlowFixMe
|
||||||
let octalStr = this.input.substr(this.state.pos - 1, 3).match(/^[0-7]+/)[0];
|
let octalStr = this.input.substr(this.state.pos - 1, 3).match(/^[0-7]+/)[0];
|
||||||
let octal = parseInt(octalStr, 8);
|
let octal = parseInt(octalStr, 8);
|
||||||
if (octal > 255) {
|
if (octal > 255) {
|
||||||
@ -764,7 +826,7 @@ export default class Tokenizer {
|
|||||||
|
|
||||||
// Used to read character escape sequences ('\x', '\u').
|
// Used to read character escape sequences ('\x', '\u').
|
||||||
|
|
||||||
readHexChar(len, throwOnInvalid) {
|
readHexChar(len: number, throwOnInvalid: boolean): number | null {
|
||||||
const codePos = this.state.pos;
|
const codePos = this.state.pos;
|
||||||
const n = this.readInt(16, len);
|
const n = this.readInt(16, len);
|
||||||
if (n === null) {
|
if (n === null) {
|
||||||
@ -784,7 +846,7 @@ export default class Tokenizer {
|
|||||||
// Incrementally adds only escaped chars, adding other chunks as-is
|
// Incrementally adds only escaped chars, adding other chunks as-is
|
||||||
// as a micro-optimization.
|
// as a micro-optimization.
|
||||||
|
|
||||||
readWord1() {
|
readWord1(): string {
|
||||||
this.state.containsEsc = false;
|
this.state.containsEsc = false;
|
||||||
let word = "", first = true, chunkStart = this.state.pos;
|
let word = "", first = true, chunkStart = this.state.pos;
|
||||||
while (this.state.pos < this.input.length) {
|
while (this.state.pos < this.input.length) {
|
||||||
@ -803,10 +865,12 @@ export default class Tokenizer {
|
|||||||
|
|
||||||
++this.state.pos;
|
++this.state.pos;
|
||||||
const esc = this.readCodePoint(true);
|
const esc = this.readCodePoint(true);
|
||||||
|
// $FlowFixMe (thinks esc may be null, but throwOnInvalid is true)
|
||||||
if (!(first ? isIdentifierStart : isIdentifierChar)(esc, true)) {
|
if (!(first ? isIdentifierStart : isIdentifierChar)(esc, true)) {
|
||||||
this.raise(escStart, "Invalid Unicode escape");
|
this.raise(escStart, "Invalid Unicode escape");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
word += codePointToString(esc);
|
word += codePointToString(esc);
|
||||||
chunkStart = this.state.pos;
|
chunkStart = this.state.pos;
|
||||||
} else {
|
} else {
|
||||||
@ -820,7 +884,7 @@ export default class Tokenizer {
|
|||||||
// Read an identifier or keyword token. Will check for reserved
|
// Read an identifier or keyword token. Will check for reserved
|
||||||
// words when necessary.
|
// words when necessary.
|
||||||
|
|
||||||
readWord() {
|
readWord(): void {
|
||||||
const word = this.readWord1();
|
const word = this.readWord1();
|
||||||
let type = tt.name;
|
let type = tt.name;
|
||||||
if (!this.state.containsEsc && this.isKeyword(word)) {
|
if (!this.state.containsEsc && this.isKeyword(word)) {
|
||||||
@ -829,7 +893,7 @@ export default class Tokenizer {
|
|||||||
return this.finishToken(type, word);
|
return this.finishToken(type, word);
|
||||||
}
|
}
|
||||||
|
|
||||||
braceIsBlock(prevType) {
|
braceIsBlock(prevType: TokenType): boolean {
|
||||||
if (prevType === tt.colon) {
|
if (prevType === tt.colon) {
|
||||||
const parent = this.curContext();
|
const parent = this.curContext();
|
||||||
if (parent === ct.braceStatement || parent === ct.braceExpression) {
|
if (parent === ct.braceStatement || parent === ct.braceExpression) {
|
||||||
@ -852,7 +916,7 @@ export default class Tokenizer {
|
|||||||
return !this.state.exprAllowed;
|
return !this.state.exprAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateContext(prevType) {
|
updateContext(prevType: TokenType): void {
|
||||||
const type = this.state.type;
|
const type = this.state.type;
|
||||||
let update;
|
let update;
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,17 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import type { Options } from "../options";
|
||||||
|
import * as N from "../types";
|
||||||
|
|
||||||
import type { TokContext } from "./context";
|
import type { TokContext } from "./context";
|
||||||
|
import type { Token } from "./index";
|
||||||
import type { TokenType } from "./types";
|
import type { TokenType } from "./types";
|
||||||
import { Position } from "../util/location";
|
import { Position } from "../util/location";
|
||||||
import { types as ct } from "./context";
|
import { types as ct } from "./context";
|
||||||
import { types as tt } from "./types";
|
import { types as tt } from "./types";
|
||||||
|
|
||||||
export default class State {
|
export default class State {
|
||||||
init(options: Object, input: string) {
|
init(options: Options, input: string): void {
|
||||||
this.strict = options.strictMode === false ? false : options.sourceType === "module";
|
this.strict = options.strictMode === false ? false : options.sourceType === "module";
|
||||||
|
|
||||||
this.input = input;
|
this.input = input;
|
||||||
@ -18,6 +24,8 @@ export default class State {
|
|||||||
this.inAsync =
|
this.inAsync =
|
||||||
this.inPropertyName =
|
this.inPropertyName =
|
||||||
this.inType =
|
this.inType =
|
||||||
|
this.inClass =
|
||||||
|
this.inClassProperty =
|
||||||
this.noAnonFunctionType =
|
this.noAnonFunctionType =
|
||||||
false;
|
false;
|
||||||
|
|
||||||
@ -41,6 +49,7 @@ export default class State {
|
|||||||
this.start = this.end = this.pos;
|
this.start = this.end = this.pos;
|
||||||
this.startLoc = this.endLoc = this.curPosition();
|
this.startLoc = this.endLoc = this.curPosition();
|
||||||
|
|
||||||
|
// $FlowIgnore
|
||||||
this.lastTokEndLoc = this.lastTokStartLoc = null;
|
this.lastTokEndLoc = this.lastTokStartLoc = null;
|
||||||
this.lastTokStart = this.lastTokEnd = this.pos;
|
this.lastTokStart = this.lastTokEnd = this.pos;
|
||||||
|
|
||||||
@ -53,8 +62,6 @@ export default class State {
|
|||||||
this.invalidTemplateEscapePosition = null;
|
this.invalidTemplateEscapePosition = null;
|
||||||
|
|
||||||
this.exportedIdentifiers = [];
|
this.exportedIdentifiers = [];
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
@ -69,27 +76,35 @@ export default class State {
|
|||||||
// Flags to track whether we are in a function, a generator.
|
// Flags to track whether we are in a function, a generator.
|
||||||
inFunction: boolean;
|
inFunction: boolean;
|
||||||
inGenerator: boolean;
|
inGenerator: boolean;
|
||||||
inMethod: boolean;
|
inMethod: boolean | N.MethodKind;
|
||||||
inAsync: boolean;
|
inAsync: boolean;
|
||||||
inType: boolean;
|
inType: boolean;
|
||||||
|
noAnonFunctionType: boolean;
|
||||||
inPropertyName: boolean;
|
inPropertyName: boolean;
|
||||||
|
inClassProperty: boolean;
|
||||||
|
inClass: boolean;
|
||||||
|
|
||||||
// Labels in scope.
|
// Labels in scope.
|
||||||
labels: Array<Object>;
|
labels: Array<{ kind: ?("loop" | "switch"), statementStart?: number }>;
|
||||||
|
|
||||||
// Leading decorators.
|
// Leading decorators.
|
||||||
decorators: Array<Object>;
|
decorators: Array<N.Decorator>;
|
||||||
|
|
||||||
// Token store.
|
// Token store.
|
||||||
tokens: Array<Object>;
|
tokens: Array<Token | N.Comment>;
|
||||||
|
|
||||||
// Comment store.
|
// Comment store.
|
||||||
comments: Array<Object>;
|
comments: Array<N.Comment>;
|
||||||
|
|
||||||
// Comment attachment store
|
// Comment attachment store
|
||||||
trailingComments: Array<Object>;
|
trailingComments: Array<N.Comment>;
|
||||||
leadingComments: Array<Object>;
|
leadingComments: Array<N.Comment>;
|
||||||
commentStack: Array<Object>;
|
commentStack: Array<{
|
||||||
|
start: number;
|
||||||
|
leadingComments: ?Array<N.Comment>;
|
||||||
|
trailingComments: ?Array<N.Comment>;
|
||||||
|
}>;
|
||||||
|
commentPreviousNode: N.Node;
|
||||||
|
|
||||||
// The current position of the tokenizer in the input.
|
// The current position of the tokenizer in the input.
|
||||||
pos: number;
|
pos: number;
|
||||||
@ -113,8 +128,8 @@ export default class State {
|
|||||||
endLoc: Position;
|
endLoc: Position;
|
||||||
|
|
||||||
// Position information for the previous token
|
// Position information for the previous token
|
||||||
lastTokEndLoc: ?Position;
|
lastTokEndLoc: Position;
|
||||||
lastTokStartLoc: ?Position;
|
lastTokStartLoc: Position;
|
||||||
lastTokStart: number;
|
lastTokStart: number;
|
||||||
lastTokEnd: number;
|
lastTokEnd: number;
|
||||||
|
|
||||||
@ -137,19 +152,23 @@ export default class State {
|
|||||||
// `export default foo;` and `export { foo as default };`.
|
// `export default foo;` and `export { foo as default };`.
|
||||||
exportedIdentifiers: Array<string>;
|
exportedIdentifiers: Array<string>;
|
||||||
|
|
||||||
curPosition() {
|
invalidTemplateEscapePosition: ?number;
|
||||||
|
|
||||||
|
curPosition(): Position {
|
||||||
return new Position(this.curLine, this.pos - this.lineStart);
|
return new Position(this.curLine, this.pos - this.lineStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
clone(skipArrays?) {
|
clone(skipArrays?: boolean): State {
|
||||||
const state = new State;
|
const state = new State;
|
||||||
for (const key in this) {
|
for (const key in this) {
|
||||||
|
// $FlowIgnore
|
||||||
let val = this[key];
|
let val = this[key];
|
||||||
|
|
||||||
if ((!skipArrays || key === "context") && Array.isArray(val)) {
|
if ((!skipArrays || key === "context") && Array.isArray(val)) {
|
||||||
val = val.slice();
|
val = val.slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// $FlowIgnore
|
||||||
state[key] = val;
|
state[key] = val;
|
||||||
}
|
}
|
||||||
return state;
|
return state;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
// ## Token types
|
// ## Token types
|
||||||
|
|
||||||
// The assignment of fine-grained, information-carrying type objects
|
// The assignment of fine-grained, information-carrying type objects
|
||||||
@ -23,8 +25,33 @@ const isAssign = true;
|
|||||||
const prefix = true;
|
const prefix = true;
|
||||||
const postfix = true;
|
const postfix = true;
|
||||||
|
|
||||||
|
type TokenOptions = {
|
||||||
|
keyword?: string;
|
||||||
|
|
||||||
|
beforeExpr?: boolean;
|
||||||
|
startsExpr?: boolean;
|
||||||
|
rightAssociative?: boolean;
|
||||||
|
isLoop?: boolean;
|
||||||
|
isAssign?: boolean;
|
||||||
|
prefix?: boolean;
|
||||||
|
postfix?: boolean;
|
||||||
|
binop?: ?number;
|
||||||
|
};
|
||||||
|
|
||||||
export class TokenType {
|
export class TokenType {
|
||||||
constructor(label, conf = {}) {
|
label: string;
|
||||||
|
keyword: ?string;
|
||||||
|
beforeExpr: boolean;
|
||||||
|
startsExpr: boolean;
|
||||||
|
rightAssociative: boolean;
|
||||||
|
isLoop: boolean;
|
||||||
|
isAssign: boolean;
|
||||||
|
prefix: boolean;
|
||||||
|
postfix: boolean;
|
||||||
|
binop: ?number;
|
||||||
|
updateContext: ?((prevType: TokenType) => void);
|
||||||
|
|
||||||
|
constructor(label: string, conf: TokenOptions = {}) {
|
||||||
this.label = label;
|
this.label = label;
|
||||||
this.keyword = conf.keyword;
|
this.keyword = conf.keyword;
|
||||||
this.beforeExpr = !!conf.beforeExpr;
|
this.beforeExpr = !!conf.beforeExpr;
|
||||||
@ -40,7 +67,7 @@ export class TokenType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class KeywordTokenType extends TokenType {
|
class KeywordTokenType extends TokenType {
|
||||||
constructor(name, options = {}) {
|
constructor(name: string, options: TokenOptions = {}) {
|
||||||
options.keyword = name;
|
options.keyword = name;
|
||||||
|
|
||||||
super(name, options);
|
super(name, options);
|
||||||
@ -48,12 +75,12 @@ class KeywordTokenType extends TokenType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class BinopTokenType extends TokenType {
|
export class BinopTokenType extends TokenType {
|
||||||
constructor(name, prec) {
|
constructor(name: string, prec: number) {
|
||||||
super(name, { beforeExpr, binop: prec });
|
super(name, { beforeExpr, binop: prec });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const types = {
|
export const types: { [name: string]: TokenType } = {
|
||||||
num: new TokenType("num", { startsExpr }),
|
num: new TokenType("num", { startsExpr }),
|
||||||
regexp: new TokenType("regexp", { startsExpr }),
|
regexp: new TokenType("regexp", { startsExpr }),
|
||||||
string: new TokenType("string", { startsExpr }),
|
string: new TokenType("string", { startsExpr }),
|
||||||
@ -82,6 +109,7 @@ export const types = {
|
|||||||
backQuote: new TokenType("`", { startsExpr }),
|
backQuote: new TokenType("`", { startsExpr }),
|
||||||
dollarBraceL: new TokenType("${", { beforeExpr, startsExpr }),
|
dollarBraceL: new TokenType("${", { beforeExpr, startsExpr }),
|
||||||
at: new TokenType("@"),
|
at: new TokenType("@"),
|
||||||
|
hash: new TokenType("#"),
|
||||||
|
|
||||||
// Operators. These carry several kinds of properties to help the
|
// Operators. These carry several kinds of properties to help the
|
||||||
// parser use them properly (the presence of these properties is
|
// parser use them properly (the presence of these properties is
|
||||||
|
|||||||
726
src/types.js
Normal file
726
src/types.js
Normal file
@ -0,0 +1,726 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
|
import type { Token } from "./tokenizer";
|
||||||
|
import type { SourceLocation } from "./util/location";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If making any changes to the AST, update:
|
||||||
|
* - This repository:
|
||||||
|
* - This file
|
||||||
|
* - `ast` directory
|
||||||
|
* - Babel repository:
|
||||||
|
* - packages/babel-types/src/definitions
|
||||||
|
* - packages/babel-generators/src/generators
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type Comment = {
|
||||||
|
type: "CommentBlock" | "CommentLine";
|
||||||
|
value: string;
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
loc: SourceLocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface NodeBase {
|
||||||
|
start: number;
|
||||||
|
end: number;
|
||||||
|
loc: SourceLocation;
|
||||||
|
range: [number, number];
|
||||||
|
leadingComments?: ?Array<Comment>;
|
||||||
|
trailingComments?: ?Array<Comment>;
|
||||||
|
innerComments?: ?Array<Comment>;
|
||||||
|
|
||||||
|
extra: { [key: string]: any };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using a union type for `Node` makes type-checking too slow.
|
||||||
|
// Instead, add an index signature to allow a Node to be treated as anything.
|
||||||
|
export type Node = NodeBase & { [key: string]: any };
|
||||||
|
export type Expression = Node;
|
||||||
|
export type Statement = Node;
|
||||||
|
export type Pattern =
|
||||||
|
| Identifier
|
||||||
|
| ObjectPattern
|
||||||
|
| ArrayPattern
|
||||||
|
| RestElement
|
||||||
|
| AssignmentPattern;
|
||||||
|
export type Declaration =
|
||||||
|
| VariableDeclaration
|
||||||
|
| ClassDeclaration
|
||||||
|
| FunctionDeclaration;
|
||||||
|
export type DeclarationBase = NodeBase;
|
||||||
|
|
||||||
|
// TODO: Not in spec
|
||||||
|
export type HasDecorators = NodeBase & {
|
||||||
|
decorators?: $ReadOnlyArray<Decorator>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Identifier = PatternBase & {
|
||||||
|
type: "Identifier";
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
__clone(): Identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PrivateName = NodeBase & {
|
||||||
|
type: "PrivateName";
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Literals
|
||||||
|
|
||||||
|
export type Literal = RegExpLiteral | NullLiteral | StringLiteral | BooleanLiteral | NumericLiteral;
|
||||||
|
|
||||||
|
export type RegExpLiteral = NodeBase & {
|
||||||
|
type: "RegExpLiteral";
|
||||||
|
pattern: string;
|
||||||
|
flags: RegExp$flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NullLiteral = NodeBase & {
|
||||||
|
type: "NullLiteral";
|
||||||
|
}
|
||||||
|
|
||||||
|
export type StringLiteral = NodeBase & {
|
||||||
|
type: "StringLiteral";
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BooleanLiteral = NodeBase & {
|
||||||
|
type: "BooleanLiteral";
|
||||||
|
value: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NumericLiteral = NodeBase & {
|
||||||
|
type: "NumericLiteral";
|
||||||
|
value: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Programs
|
||||||
|
|
||||||
|
export type BlockStatementLike = Program | BlockStatement;
|
||||||
|
|
||||||
|
export type File = NodeBase & {
|
||||||
|
type: "File";
|
||||||
|
program: Program;
|
||||||
|
comments: $ReadOnlyArray<Comment>;
|
||||||
|
tokens: $ReadOnlyArray<Token | Comment>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Program = NodeBase & {
|
||||||
|
type: "Program";
|
||||||
|
sourceType: "script" | "module";
|
||||||
|
body: Array<Statement | ModuleDeclaration>; // TODO: $ReadOnlyArray
|
||||||
|
directives: $ReadOnlyArray<Directive>; // TODO: Not in spec
|
||||||
|
};
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
|
||||||
|
export type Function =
|
||||||
|
NormalFunction | ArrowFunctionExpression | ObjectMethod | ClassMethod;
|
||||||
|
|
||||||
|
export type NormalFunction =
|
||||||
|
FunctionDeclaration | FunctionExpression;
|
||||||
|
|
||||||
|
export type FunctionBase = HasDecorators & {
|
||||||
|
id: ?Identifier;
|
||||||
|
params: $ReadOnlyArray<Pattern>;
|
||||||
|
body: BlockStatement;
|
||||||
|
generator: boolean;
|
||||||
|
async: boolean;
|
||||||
|
|
||||||
|
expression: boolean; // TODO: Not in spec
|
||||||
|
typeParameters?: ?FlowTypeParameterDeclaration; // TODO: Not in spec
|
||||||
|
returnType?: ?FlowTypeAnnotation; // TODO: Not in spec
|
||||||
|
};
|
||||||
|
|
||||||
|
// Statements
|
||||||
|
|
||||||
|
export type ExpressionStatement = NodeBase & {
|
||||||
|
type: "ExpressionStatement";
|
||||||
|
expression: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BlockStatement = NodeBase & {
|
||||||
|
type: "BlockStatement";
|
||||||
|
body: Array<Statement>; // TODO: $ReadOnlyArray
|
||||||
|
directives: $ReadOnlyArray<Directive>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type EmptyStatement = NodeBase & {
|
||||||
|
type: "EmptyStatement"
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DebuggerStatement = NodeBase & {
|
||||||
|
type: "DebuggerStatement"
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WithStatement = NodeBase & {
|
||||||
|
type: "WithStatement";
|
||||||
|
object: Expression;
|
||||||
|
body: Statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ReturnStatement = NodeBase & {
|
||||||
|
type: "ReturnStatement";
|
||||||
|
argument: ?Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LabeledStatement = NodeBase & {
|
||||||
|
type: "LabeledStatement";
|
||||||
|
label: Identifier;
|
||||||
|
body: Statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BreakStatement = NodeBase & {
|
||||||
|
type: "BreakStatement";
|
||||||
|
label: ?Identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ContinueStatement = NodeBase & {
|
||||||
|
type: "ContinueStatement";
|
||||||
|
label: ?Identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Choice
|
||||||
|
|
||||||
|
export type IfStatement = NodeBase & {
|
||||||
|
type: "IfStatement";
|
||||||
|
test: Expression;
|
||||||
|
consequent: Statement;
|
||||||
|
alternate: ?Statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SwitchStatement = NodeBase & {
|
||||||
|
type: "SwitchStatement";
|
||||||
|
discriminant: Expression;
|
||||||
|
cases: $ReadOnlyArray<SwitchCase>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SwitchCase = NodeBase & {
|
||||||
|
type: "SwitchCase";
|
||||||
|
test: ?Expression;
|
||||||
|
consequent: $ReadOnlyArray<Statement>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exceptions
|
||||||
|
|
||||||
|
export type ThrowStatement = NodeBase & {
|
||||||
|
type: "ThrowStatement";
|
||||||
|
argument: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TryStatement = NodeBase & {
|
||||||
|
type: "TryStatement";
|
||||||
|
block: BlockStatement;
|
||||||
|
handler: CatchClause | null;
|
||||||
|
finalizer: BlockStatement | null;
|
||||||
|
|
||||||
|
guardedHandlers: $ReadOnlyArray<empty>; // TODO: Not in spec
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CatchClause = NodeBase & {
|
||||||
|
type: "CatchClause";
|
||||||
|
param: Pattern;
|
||||||
|
body: BlockStatement;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Loops
|
||||||
|
|
||||||
|
export type WhileStatement = NodeBase & {
|
||||||
|
type: "WhileStatement";
|
||||||
|
test: Expression;
|
||||||
|
body: Statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DoWhileStatement = NodeBase & {
|
||||||
|
type: "DoWhileStatement";
|
||||||
|
body: Statement;
|
||||||
|
test: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ForLike = ForStatement | ForInOf;
|
||||||
|
|
||||||
|
export type ForStatement = NodeBase & {
|
||||||
|
type: "ForStatement";
|
||||||
|
init: ?(VariableDeclaration | Expression);
|
||||||
|
test: ?Expression;
|
||||||
|
update: ?Expression;
|
||||||
|
body: Statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ForInOf = ForInStatement | ForOfStatement;
|
||||||
|
|
||||||
|
export type ForInOfBase = NodeBase & {
|
||||||
|
type: "ForInStatement";
|
||||||
|
left: VariableDeclaration | Expression;
|
||||||
|
right: Expression;
|
||||||
|
body: Statement;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ForInStatement = ForInOfBase & {
|
||||||
|
type: "ForInStatement";
|
||||||
|
// TODO: Shouldn't be here, but have to declare it because it's assigned to a ForInOf unconditionally.
|
||||||
|
await: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ForOfStatement = ForInOfBase & {
|
||||||
|
type: "ForOfStatement";
|
||||||
|
await: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Declarations
|
||||||
|
|
||||||
|
export type OptFunctionDeclaration = FunctionBase & DeclarationBase & HasDecorators & {
|
||||||
|
type: "FunctionDeclaration";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FunctionDeclaration = OptFunctionDeclaration & {
|
||||||
|
id: Identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type VariableDeclaration = DeclarationBase & HasDecorators & {
|
||||||
|
type: "VariableDeclaration";
|
||||||
|
declarations: $ReadOnlyArray<VariableDeclarator>;
|
||||||
|
kind: "var" | "let" | "const";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type VariableDeclarator = NodeBase & {
|
||||||
|
type: "VariableDeclarator";
|
||||||
|
id: Pattern;
|
||||||
|
init: ?Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Misc
|
||||||
|
|
||||||
|
export type Decorator = NodeBase & {
|
||||||
|
type: "Decorator";
|
||||||
|
expression: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type Directive = NodeBase & {
|
||||||
|
type: "Directive";
|
||||||
|
value: DirectiveLiteral;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type DirectiveLiteral = StringLiteral & { type: "DirectiveLiteral" };
|
||||||
|
|
||||||
|
// Expressions
|
||||||
|
|
||||||
|
export type Super = NodeBase & { type: "Super" };
|
||||||
|
|
||||||
|
export type Import = NodeBase & { type: "Import" };
|
||||||
|
|
||||||
|
export type ThisExpression = NodeBase & { type: "ThisExpression" };
|
||||||
|
|
||||||
|
export type ArrowFunctionExpression = FunctionBase & {
|
||||||
|
type: "ArrowFunctionExpression";
|
||||||
|
body: BlockStatement | Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type YieldExpression = NodeBase & {
|
||||||
|
type: "YieldExpression";
|
||||||
|
argument: ?Expression;
|
||||||
|
delegate: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AwaitExpression = NodeBase & {
|
||||||
|
type: "AwaitExpression";
|
||||||
|
argument: ?Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ArrayExpression = NodeBase & {
|
||||||
|
type: "ArrayExpression";
|
||||||
|
elements: $ReadOnlyArray<?(Expression | SpreadElement)>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ObjectExpression = NodeBase & {
|
||||||
|
type: "ObjectExpression";
|
||||||
|
properties: $ReadOnlyArray<ObjectProperty | ObjectMethod | SpreadElement>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ObjectOrClassMember = ClassMethod | ClassProperty | ClassPrivateProperty | ObjectMember;
|
||||||
|
|
||||||
|
export type ObjectMember = ObjectProperty | ObjectMethod;
|
||||||
|
|
||||||
|
export type ObjectMemberBase = NodeBase & {
|
||||||
|
key: Expression;
|
||||||
|
computed: boolean;
|
||||||
|
value: Expression;
|
||||||
|
decorators: $ReadOnlyArray<Decorator>;
|
||||||
|
kind?: "get" | "set" | "method";
|
||||||
|
method: boolean; // TODO: Not in spec
|
||||||
|
|
||||||
|
variance?: ?FlowVariance; // TODO: Not in spec
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ObjectProperty = ObjectMemberBase & {
|
||||||
|
type: "ObjectProperty";
|
||||||
|
shorthand: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ObjectMethod = ObjectMemberBase & MethodBase & {
|
||||||
|
type: "ObjectMethod";
|
||||||
|
kind: "get" | "set" | "method"; // Never "constructor"
|
||||||
|
};
|
||||||
|
|
||||||
|
export type FunctionExpression = MethodBase & {
|
||||||
|
kind?: void; // never set
|
||||||
|
type: "FunctionExpression";
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unary operations
|
||||||
|
|
||||||
|
export type UnaryExpression = NodeBase & {
|
||||||
|
type: "UnaryExpression";
|
||||||
|
operator: UnaryOperator;
|
||||||
|
prefix: boolean;
|
||||||
|
argument: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UnaryOperator = "-" | "+" | "!" | "~" | "typeof" | "void" | "delete";
|
||||||
|
|
||||||
|
export type UpdateExpression = NodeBase & {
|
||||||
|
type: "UpdateExpression";
|
||||||
|
operator: UpdateOperator;
|
||||||
|
argument: Expression;
|
||||||
|
prefix: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type UpdateOperator = "++" | "--";
|
||||||
|
|
||||||
|
// Binary operations
|
||||||
|
|
||||||
|
export type BinaryExpression = NodeBase & {
|
||||||
|
type: "BinaryExpression";
|
||||||
|
operator: BinaryOperator;
|
||||||
|
left: Expression;
|
||||||
|
right: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type BinaryOperator =
|
||||||
|
| "==" | "!=" | "===" | "!=="
|
||||||
|
| "<" | "<=" | ">" | ">="
|
||||||
|
| "<<" | ">>" | ">>>"
|
||||||
|
| "+" | "-" | "*" | "/" | "%"
|
||||||
|
| "|" | "^" | "&" | "in"
|
||||||
|
| "instanceof";
|
||||||
|
|
||||||
|
export type AssignmentExpression = NodeBase & {
|
||||||
|
type: "AssignmentExpression";
|
||||||
|
operator: AssignmentOperator;
|
||||||
|
left: Pattern | Expression;
|
||||||
|
right: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AssignmentOperator =
|
||||||
|
| "=" | "+=" | "-=" | "*=" | "/=" | "%="
|
||||||
|
| "<<=" | ">>=" | ">>>="
|
||||||
|
| "|=" | "^=" | "&=";
|
||||||
|
|
||||||
|
export type LogicalExpression = NodeBase & {
|
||||||
|
type: "LogicalExpression";
|
||||||
|
operator: LogicalOperator;
|
||||||
|
left: Expression;
|
||||||
|
right: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type LogicalOperator = "||" | "&&";
|
||||||
|
|
||||||
|
export type SpreadElement = NodeBase & {
|
||||||
|
type: "SpreadElement";
|
||||||
|
argument: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MemberExpression = NodeBase & {
|
||||||
|
type: "MemberExpression";
|
||||||
|
object: Expression | Super;
|
||||||
|
property: Expression;
|
||||||
|
computed: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type BindExpression = NodeBase & {
|
||||||
|
type: "BindExpression";
|
||||||
|
object: $ReadOnlyArray<?Expression>;
|
||||||
|
callee: $ReadOnlyArray<Expression>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ConditionalExpression = NodeBase & {
|
||||||
|
type: "ConditionalExpression";
|
||||||
|
test: Expression;
|
||||||
|
alternate: Expression;
|
||||||
|
consequent: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CallOrNewBase = NodeBase & {
|
||||||
|
callee: Expression | Super | Import;
|
||||||
|
arguments: Array<Expression | SpreadElement>; // TODO: $ReadOnlyArray
|
||||||
|
};
|
||||||
|
|
||||||
|
export type CallExpression = CallOrNewBase & {
|
||||||
|
type: "CallExpression";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NewExpression = CallOrNewBase & {
|
||||||
|
type: "NewExpression";
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SequenceExpression = NodeBase & {
|
||||||
|
type: "SequenceExpression";
|
||||||
|
expressions: $ReadOnlyArray<Expression>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Template Literals
|
||||||
|
|
||||||
|
export type TemplateLiteral = NodeBase & {
|
||||||
|
type: "TemplateLiteral";
|
||||||
|
quasis: $ReadOnlyArray<TemplateElement>;
|
||||||
|
expressions: $ReadOnlyArray<Expression>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TaggedTmplateExpression = NodeBase & {
|
||||||
|
type: "TaggedTemplateExpression";
|
||||||
|
tag: Expression;
|
||||||
|
quasi: TemplateLiteral;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TemplateElement = NodeBase & {
|
||||||
|
type: "TemplateElement";
|
||||||
|
tail: boolean;
|
||||||
|
value: {
|
||||||
|
cooked: string;
|
||||||
|
raw: string;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Patterns
|
||||||
|
|
||||||
|
export type PatternBase = HasDecorators & {
|
||||||
|
// Flow only:
|
||||||
|
optional?: true;
|
||||||
|
typeAnnotation?: ?FlowTypeAnnotation;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AssignmentProperty = ObjectProperty & {
|
||||||
|
value: Pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ObjectPattern = PatternBase & {
|
||||||
|
type: "ObjectPattern";
|
||||||
|
properties: $ReadOnlyArray<AssignmentProperty | RestElement>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ArrayPattern = PatternBase & {
|
||||||
|
type: "ArrayPattern";
|
||||||
|
elements: $ReadOnlyArray<?Pattern>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type RestElement = PatternBase & {
|
||||||
|
type: "RestElement";
|
||||||
|
argument: Pattern;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AssignmentPattern = PatternBase & {
|
||||||
|
type: "AssignmentPattern";
|
||||||
|
left: Pattern;
|
||||||
|
right: Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Classes
|
||||||
|
|
||||||
|
export type Class = ClassDeclaration | ClassExpression;
|
||||||
|
|
||||||
|
export type ClassBase = HasDecorators & {
|
||||||
|
id: ?Identifier;
|
||||||
|
superClass: ?Expression;
|
||||||
|
body: ClassBody;
|
||||||
|
decorators: $ReadOnlyArray<Decorator>;
|
||||||
|
|
||||||
|
typeParameters?: ?FlowTypeParameterDeclaration; // TODO: Not in spec
|
||||||
|
superTypeParameters?: ?FlowTypeParameterInstantiation; // TODO: Not in spec
|
||||||
|
implements?: $ReadOnlyArray<FlowClassImplements>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ClassBody = NodeBase & {
|
||||||
|
type: "ClassBody";
|
||||||
|
body: Array<ClassMember>; // TODO: $ReadOnlyArray
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ClassMemberBase = NodeBase & HasDecorators & {
|
||||||
|
static: boolean;
|
||||||
|
computed: boolean;
|
||||||
|
// TypeScript only:
|
||||||
|
access?: ?Accessibility;
|
||||||
|
abstract?: ?true;
|
||||||
|
optional?: ?true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Accessibility = "public" | "protected" | "private";
|
||||||
|
|
||||||
|
export type ClassMember = ClassMethod | ClassProperty | ClassPrivateProperty;
|
||||||
|
|
||||||
|
export type MethodLike = ObjectMethod | FunctionExpression | ClassMethod;
|
||||||
|
|
||||||
|
export type MethodBase = FunctionBase & {
|
||||||
|
+kind?: MethodKind;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type MethodKind = "constructor" | "method" | "get" | "set";
|
||||||
|
|
||||||
|
export type ClassMethod = MethodBase & ClassMemberBase & {
|
||||||
|
type: "ClassMethod";
|
||||||
|
key: Expression;
|
||||||
|
kind: MethodKind;
|
||||||
|
static: boolean;
|
||||||
|
decorators: $ReadOnlyArray<Decorator>;
|
||||||
|
|
||||||
|
variance?: ?FlowVariance; // TODO: Not in spec
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ClassProperty = ClassMemberBase & {
|
||||||
|
type: "ClassProperty";
|
||||||
|
key: Identifier;
|
||||||
|
value: ?Expression; // TODO: Not in spec that this is nullable.
|
||||||
|
|
||||||
|
typeAnnotation?: ?FlowTypeAnnotation; // TODO: Not in spec
|
||||||
|
variance?: ?FlowVariance; // TODO: Not in spec
|
||||||
|
|
||||||
|
// TypeScript only: (TODO: Not in spec)
|
||||||
|
readonly?: true;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ClassPrivateProperty = NodeBase & {
|
||||||
|
type: "ClassPrivateProperty";
|
||||||
|
key: Identifier;
|
||||||
|
value: ?Expression; // TODO: Not in spec that this is nullable.
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OptClassDeclaration = ClassBase & DeclarationBase & HasDecorators & {
|
||||||
|
type: "ClassDeclaration";
|
||||||
|
// TypeScript only
|
||||||
|
abstract?: ?true;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ClassDeclaration = OptClassDeclaration & {
|
||||||
|
id: Identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ClassExpression = ClassBase & { type: "ClassExpression" };
|
||||||
|
|
||||||
|
export type MetaProperty = NodeBase & {
|
||||||
|
type: "MetaProperty";
|
||||||
|
meta: Identifier;
|
||||||
|
property: Identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Modules
|
||||||
|
|
||||||
|
export type ModuleDeclaration = AnyImport | AnyExport;
|
||||||
|
|
||||||
|
export type AnyImport = ImportDeclaration;
|
||||||
|
|
||||||
|
export type AnyExport =
|
||||||
|
| ExportNamedDeclaration
|
||||||
|
| ExportDefaultDeclaration
|
||||||
|
| ExportAllDeclaration;
|
||||||
|
|
||||||
|
export type ModuleSpecifier = NodeBase & {
|
||||||
|
local: Identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Imports
|
||||||
|
|
||||||
|
export type ImportDeclaration = NodeBase & {
|
||||||
|
type: "ImportDeclaration";
|
||||||
|
// TODO: $ReadOnlyArray
|
||||||
|
specifiers: Array<ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier>;
|
||||||
|
source: Literal;
|
||||||
|
|
||||||
|
importKind?: "type" | "typeof" | "value"; // TODO: Not in spec
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ImportSpecifier = ModuleSpecifier & {
|
||||||
|
type: "ImportSpecifier";
|
||||||
|
imported: Identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ImportDefaultSpecifier = ModuleSpecifier & {
|
||||||
|
type: "ImportDefaultSpecifier"
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ImportNamespaceSpecifier = ModuleSpecifier & {
|
||||||
|
type: "ImportNamespaceSpecifier"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
|
||||||
|
export type ExportNamedDeclaration = NodeBase & {
|
||||||
|
type: "ExportNamedDeclaration";
|
||||||
|
declaration: ?Declaration;
|
||||||
|
specifiers: $ReadOnlyArray<ExportSpecifier>;
|
||||||
|
source: ?Literal;
|
||||||
|
|
||||||
|
exportKind?: "type" | "value"; // TODO: Not in spec
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExportSpecifier = NodeBase & {
|
||||||
|
type: "ExportSpecifier";
|
||||||
|
exported: Identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExportDefaultDeclaration = NodeBase & {
|
||||||
|
type: "ExportDefaultDeclaration";
|
||||||
|
declaration: OptFunctionDeclaration | OptClassDeclaration | Expression;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ExportAllDeclaration = NodeBase & {
|
||||||
|
type: "ExportAllDeclaration";
|
||||||
|
source: Literal;
|
||||||
|
};
|
||||||
|
|
||||||
|
// JSX (TODO: Not in spec)
|
||||||
|
|
||||||
|
export type JSXIdentifier = Node;
|
||||||
|
export type JSXNamespacedName = Node;
|
||||||
|
export type JSXMemberExpression = Node;
|
||||||
|
export type JSXEmptyExpression = Node;
|
||||||
|
export type JSXSpreadChild = Node;
|
||||||
|
export type JSXExpressionContainer = Node;
|
||||||
|
export type JSXAttribute = Node;
|
||||||
|
export type JSXOpeningElement = Node;
|
||||||
|
export type JSXClosingElement = Node;
|
||||||
|
export type JSXElement = Node;
|
||||||
|
|
||||||
|
// Flow (TODO: Not in spec)
|
||||||
|
|
||||||
|
export type FlowType = Node;
|
||||||
|
export type FlowPredicate = Node;
|
||||||
|
export type FlowDeclare = Node;
|
||||||
|
export type FlowDeclareClass = Node;
|
||||||
|
export type FlowDeclareExportDeclaration = Node;
|
||||||
|
export type FlowDeclareFunction = Node;
|
||||||
|
export type FlowDeclareVariable = Node;
|
||||||
|
export type FlowDeclareModule = Node;
|
||||||
|
export type FlowDeclareModuleExports = Node;
|
||||||
|
export type FlowDeclareTypeAlias = Node;
|
||||||
|
export type FlowDeclareInterface = Node;
|
||||||
|
export type FlowInterface = Node;
|
||||||
|
export type FlowInterfaceExtends = Node;
|
||||||
|
export type FlowTypeAlias = Node;
|
||||||
|
export type FlowTypeParameter = Node;
|
||||||
|
export type FlowTypeParameterDeclaration = Node;
|
||||||
|
export type FlowTypeParameterInstantiation = Node;
|
||||||
|
export type FlowObjectTypeIndexer = Node;
|
||||||
|
export type FlowFunctionTypeAnnotation = Node;
|
||||||
|
export type FlowObjectTypeProperty = Node;
|
||||||
|
export type FlowObjectTypeSpreadProperty = Node;
|
||||||
|
export type FlowObjectTypeCallProperty = Node;
|
||||||
|
export type FlowObjectTypeAnnotation = Node;
|
||||||
|
export type FlowQualifiedTypeIdentifier = Node;
|
||||||
|
export type FlowGenericTypeAnnotation = Node;
|
||||||
|
export type FlowTypeofTypeAnnotation = Node;
|
||||||
|
export type FlowTupleTypeAnnotation = Node;
|
||||||
|
export type FlowFunctionTypeParam = Node;
|
||||||
|
export type FlowTypeAnnotation = Node;
|
||||||
|
export type FlowVariance = Node;
|
||||||
|
export type FlowClassImplements = Node;
|
||||||
@ -1,5 +1,7 @@
|
|||||||
/* eslint max-len: 0 */
|
/* eslint max-len: 0 */
|
||||||
|
|
||||||
|
// @flow
|
||||||
|
|
||||||
// This is a trick taken from Esprima. It turns out that, on
|
// This is a trick taken from Esprima. It turns out that, on
|
||||||
// non-Chrome browsers, to check whether a string is in a set, a
|
// non-Chrome browsers, to check whether a string is in a set, a
|
||||||
// predicate containing a big ugly `switch` statement is faster than
|
// predicate containing a big ugly `switch` statement is faster than
|
||||||
@ -9,17 +11,17 @@
|
|||||||
//
|
//
|
||||||
// It starts by sorting the words by length.
|
// It starts by sorting the words by length.
|
||||||
|
|
||||||
function makePredicate(words) {
|
function makePredicate(words: string): (str: string) => boolean {
|
||||||
words = words.split(" ");
|
const wordsArr = words.split(" ");
|
||||||
return function (str) {
|
return function (str) {
|
||||||
return words.indexOf(str) >= 0;
|
return wordsArr.indexOf(str) >= 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserved word lists for various dialects of the language
|
// Reserved word lists for various dialects of the language
|
||||||
|
|
||||||
export const reservedWords = {
|
export const reservedWords = {
|
||||||
6: makePredicate("enum await"),
|
"6": makePredicate("enum await"),
|
||||||
strict: makePredicate("implements interface let package private protected public static yield"),
|
strict: makePredicate("implements interface let package private protected public static yield"),
|
||||||
strictBind: makePredicate("eval arguments")
|
strictBind: makePredicate("eval arguments")
|
||||||
};
|
};
|
||||||
@ -57,7 +59,7 @@ const astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,1
|
|||||||
// This has a complexity linear to the value of the code. The
|
// This has a complexity linear to the value of the code. The
|
||||||
// assumption is that looking up astral identifier characters is
|
// assumption is that looking up astral identifier characters is
|
||||||
// rare.
|
// rare.
|
||||||
function isInAstralSet(code, set) {
|
function isInAstralSet(code: number, set: $ReadOnlyArray<number>): boolean {
|
||||||
let pos = 0x10000;
|
let pos = 0x10000;
|
||||||
for (let i = 0; i < set.length; i += 2) {
|
for (let i = 0; i < set.length; i += 2) {
|
||||||
pos += set[i];
|
pos += set[i];
|
||||||
@ -66,11 +68,12 @@ function isInAstralSet(code, set) {
|
|||||||
pos += set[i + 1];
|
pos += set[i + 1];
|
||||||
if (pos >= code) return true;
|
if (pos >= code) return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test whether a given character code starts an identifier.
|
// Test whether a given character code starts an identifier.
|
||||||
|
|
||||||
export function isIdentifierStart(code) {
|
export function isIdentifierStart(code: number): boolean {
|
||||||
if (code < 65) return code === 36;
|
if (code < 65) return code === 36;
|
||||||
if (code < 91) return true;
|
if (code < 91) return true;
|
||||||
if (code < 97) return code === 95;
|
if (code < 97) return code === 95;
|
||||||
@ -81,7 +84,7 @@ export function isIdentifierStart(code) {
|
|||||||
|
|
||||||
// Test whether a given character is part of an identifier.
|
// Test whether a given character is part of an identifier.
|
||||||
|
|
||||||
export function isIdentifierChar(code) {
|
export function isIdentifierChar(code: number): boolean {
|
||||||
if (code < 48) return code === 36;
|
if (code < 48) return code === 36;
|
||||||
if (code < 58) return true;
|
if (code < 58) return true;
|
||||||
if (code < 65) return false;
|
if (code < 65) return false;
|
||||||
|
|||||||
@ -1,9 +1,18 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
import { lineBreakG } from "./whitespace";
|
import { lineBreakG } from "./whitespace";
|
||||||
|
|
||||||
|
export type Pos = {
|
||||||
|
start: number;
|
||||||
|
}
|
||||||
|
|
||||||
// These are used when `options.locations` is on, for the
|
// These are used when `options.locations` is on, for the
|
||||||
// `startLoc` and `endLoc` properties.
|
// `startLoc` and `endLoc` properties.
|
||||||
|
|
||||||
export class Position {
|
export class Position {
|
||||||
|
line: number;
|
||||||
|
column: number;
|
||||||
|
|
||||||
constructor(line: number, col: number) {
|
constructor(line: number, col: number) {
|
||||||
this.line = line;
|
this.line = line;
|
||||||
this.column = col;
|
this.column = col;
|
||||||
@ -11,8 +20,13 @@ export class Position {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class SourceLocation {
|
export class SourceLocation {
|
||||||
|
start: Position;
|
||||||
|
end: Position;
|
||||||
|
filename: string;
|
||||||
|
|
||||||
constructor(start: Position, end?: Position) {
|
constructor(start: Position, end?: Position) {
|
||||||
this.start = start;
|
this.start = start;
|
||||||
|
// $FlowIgnore (may start as null, but initialized later)
|
||||||
this.end = end;
|
this.end = end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -23,7 +37,7 @@ export class SourceLocation {
|
|||||||
// offset. `input` should be the code string that the offset refers
|
// offset. `input` should be the code string that the offset refers
|
||||||
// into.
|
// into.
|
||||||
|
|
||||||
export function getLineInfo(input, offset) {
|
export function getLineInfo(input: string, offset: number): Position {
|
||||||
for (let line = 1, cur = 0; ;) {
|
for (let line = 1, cur = 0; ;) {
|
||||||
lineBreakG.lastIndex = cur;
|
lineBreakG.lastIndex = cur;
|
||||||
const match = lineBreakG.exec(input);
|
const match = lineBreakG.exec(input);
|
||||||
@ -34,4 +48,6 @@ export function getLineInfo(input, offset) {
|
|||||||
return new Position(line, offset - cur);
|
return new Position(line, offset - cur);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// istanbul ignore next
|
||||||
|
throw new Error("Unreachable");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
// @flow
|
||||||
|
|
||||||
// Matches a whole line break (where CRLF is considered a single
|
// Matches a whole line break (where CRLF is considered a single
|
||||||
// line break). Used to count lines.
|
// line break). Used to count lines.
|
||||||
|
|
||||||
|
|||||||
1
test/fixtures/comments/basic/function-trailing-comma-shorthand/actual.js
vendored
Normal file
1
test/fixtures/comments/basic/function-trailing-comma-shorthand/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
fn(a, { b }, /* comment */);
|
||||||
208
test/fixtures/comments/basic/function-trailing-comma-shorthand/expected.json
vendored
Normal file
208
test/fixtures/comments/basic/function-trailing-comma-shorthand/expected.json
vendored
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start": 0,
|
||||||
|
"end": 28,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 28
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start": 0,
|
||||||
|
"end": 28,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 28
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceType": "script",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExpressionStatement",
|
||||||
|
"start": 0,
|
||||||
|
"end": 28,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 28
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expression": {
|
||||||
|
"type": "CallExpression",
|
||||||
|
"start": 0,
|
||||||
|
"end": 27,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 27
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"callee": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 0,
|
||||||
|
"end": 2,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"identifierName": "fn"
|
||||||
|
},
|
||||||
|
"name": "fn"
|
||||||
|
},
|
||||||
|
"arguments": [
|
||||||
|
{
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 3,
|
||||||
|
"end": 4,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 4
|
||||||
|
},
|
||||||
|
"identifierName": "a"
|
||||||
|
},
|
||||||
|
"name": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ObjectExpression",
|
||||||
|
"start": 6,
|
||||||
|
"end": 11,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 6
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 11
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"type": "ObjectProperty",
|
||||||
|
"start": 8,
|
||||||
|
"end": 9,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 8
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 9
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"method": false,
|
||||||
|
"shorthand": true,
|
||||||
|
"computed": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 8,
|
||||||
|
"end": 9,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 8
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 9
|
||||||
|
},
|
||||||
|
"identifierName": "b"
|
||||||
|
},
|
||||||
|
"name": "b"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 8,
|
||||||
|
"end": 9,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 8
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 9
|
||||||
|
},
|
||||||
|
"identifierName": "b"
|
||||||
|
},
|
||||||
|
"name": "b"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"shorthand": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trailingComments": [
|
||||||
|
{
|
||||||
|
"type": "CommentBlock",
|
||||||
|
"value": " comment ",
|
||||||
|
"start": 13,
|
||||||
|
"end": 26,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 13
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 26
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
},
|
||||||
|
"comments": [
|
||||||
|
{
|
||||||
|
"type": "CommentBlock",
|
||||||
|
"value": " comment ",
|
||||||
|
"start": 13,
|
||||||
|
"end": 26,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 13
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 26
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
1
test/fixtures/comments/basic/function-trailing-comma/actual.js
vendored
Normal file
1
test/fixtures/comments/basic/function-trailing-comma/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
fn(a, b, /* comment */);
|
||||||
153
test/fixtures/comments/basic/function-trailing-comma/expected.json
vendored
Normal file
153
test/fixtures/comments/basic/function-trailing-comma/expected.json
vendored
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start": 0,
|
||||||
|
"end": 24,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start": 0,
|
||||||
|
"end": 24,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceType": "script",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExpressionStatement",
|
||||||
|
"start": 0,
|
||||||
|
"end": 24,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expression": {
|
||||||
|
"type": "CallExpression",
|
||||||
|
"start": 0,
|
||||||
|
"end": 23,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 23
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"callee": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 0,
|
||||||
|
"end": 2,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"identifierName": "fn"
|
||||||
|
},
|
||||||
|
"name": "fn"
|
||||||
|
},
|
||||||
|
"arguments": [
|
||||||
|
{
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 3,
|
||||||
|
"end": 4,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 4
|
||||||
|
},
|
||||||
|
"identifierName": "a"
|
||||||
|
},
|
||||||
|
"name": "a"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 6,
|
||||||
|
"end": 7,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 6
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 7
|
||||||
|
},
|
||||||
|
"identifierName": "b"
|
||||||
|
},
|
||||||
|
"name": "b",
|
||||||
|
"trailingComments": [
|
||||||
|
{
|
||||||
|
"type": "CommentBlock",
|
||||||
|
"value": " comment ",
|
||||||
|
"start": 9,
|
||||||
|
"end": 22,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 9
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
},
|
||||||
|
"comments": [
|
||||||
|
{
|
||||||
|
"type": "CommentBlock",
|
||||||
|
"value": " comment ",
|
||||||
|
"start": 9,
|
||||||
|
"end": 22,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 9
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
5
test/fixtures/comments/basic/object-property-trailing-comma/actual.js
vendored
Normal file
5
test/fixtures/comments/basic/object-property-trailing-comma/actual.js
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var obj = {
|
||||||
|
a: '1', // comment 1
|
||||||
|
b: '2', // comment 2
|
||||||
|
c: '3', // comment 3
|
||||||
|
};
|
||||||
372
test/fixtures/comments/basic/object-property-trailing-comma/expected.json
vendored
Normal file
372
test/fixtures/comments/basic/object-property-trailing-comma/expected.json
vendored
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start": 0,
|
||||||
|
"end": 83,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 5,
|
||||||
|
"column": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start": 0,
|
||||||
|
"end": 83,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 5,
|
||||||
|
"column": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceType": "script",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "VariableDeclaration",
|
||||||
|
"start": 0,
|
||||||
|
"end": 83,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 5,
|
||||||
|
"column": 2
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"declarations": [
|
||||||
|
{
|
||||||
|
"type": "VariableDeclarator",
|
||||||
|
"start": 4,
|
||||||
|
"end": 82,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 4
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 5,
|
||||||
|
"column": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 4,
|
||||||
|
"end": 7,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 4
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 7
|
||||||
|
},
|
||||||
|
"identifierName": "obj"
|
||||||
|
},
|
||||||
|
"name": "obj"
|
||||||
|
},
|
||||||
|
"init": {
|
||||||
|
"type": "ObjectExpression",
|
||||||
|
"start": 10,
|
||||||
|
"end": 82,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 10
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 5,
|
||||||
|
"column": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"type": "ObjectProperty",
|
||||||
|
"start": 14,
|
||||||
|
"end": 20,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"method": false,
|
||||||
|
"shorthand": false,
|
||||||
|
"computed": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 14,
|
||||||
|
"end": 15,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"identifierName": "a"
|
||||||
|
},
|
||||||
|
"name": "a"
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "StringLiteral",
|
||||||
|
"start": 17,
|
||||||
|
"end": 20,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 5
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"rawValue": "1",
|
||||||
|
"raw": "'1'"
|
||||||
|
},
|
||||||
|
"value": "1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ObjectProperty",
|
||||||
|
"start": 37,
|
||||||
|
"end": 43,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"method": false,
|
||||||
|
"shorthand": false,
|
||||||
|
"computed": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 37,
|
||||||
|
"end": 38,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"identifierName": "b"
|
||||||
|
},
|
||||||
|
"name": "b",
|
||||||
|
"leadingComments": null
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "StringLiteral",
|
||||||
|
"start": 40,
|
||||||
|
"end": 43,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 5
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"rawValue": "2",
|
||||||
|
"raw": "'2'"
|
||||||
|
},
|
||||||
|
"value": "2"
|
||||||
|
},
|
||||||
|
"leadingComments": [
|
||||||
|
{
|
||||||
|
"type": "CommentLine",
|
||||||
|
"value": " comment 1",
|
||||||
|
"start": 22,
|
||||||
|
"end": 34,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 10
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ObjectProperty",
|
||||||
|
"start": 60,
|
||||||
|
"end": 66,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"method": false,
|
||||||
|
"shorthand": false,
|
||||||
|
"computed": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 60,
|
||||||
|
"end": 61,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 2
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"identifierName": "c"
|
||||||
|
},
|
||||||
|
"name": "c",
|
||||||
|
"leadingComments": null
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "StringLiteral",
|
||||||
|
"start": 63,
|
||||||
|
"end": 66,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 5
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"rawValue": "3",
|
||||||
|
"raw": "'3'"
|
||||||
|
},
|
||||||
|
"value": "3"
|
||||||
|
},
|
||||||
|
"leadingComments": [
|
||||||
|
{
|
||||||
|
"type": "CommentLine",
|
||||||
|
"value": " comment 2",
|
||||||
|
"start": 45,
|
||||||
|
"end": 57,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 10
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"trailingComments": [
|
||||||
|
{
|
||||||
|
"type": "CommentLine",
|
||||||
|
"value": " comment 3",
|
||||||
|
"start": 68,
|
||||||
|
"end": 80,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 10
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "var"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
},
|
||||||
|
"comments": [
|
||||||
|
{
|
||||||
|
"type": "CommentLine",
|
||||||
|
"value": " comment 1",
|
||||||
|
"start": 22,
|
||||||
|
"end": 34,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 10
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 2,
|
||||||
|
"column": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CommentLine",
|
||||||
|
"value": " comment 2",
|
||||||
|
"start": 45,
|
||||||
|
"end": 57,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 10
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 3,
|
||||||
|
"column": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "CommentLine",
|
||||||
|
"value": " comment 3",
|
||||||
|
"start": 68,
|
||||||
|
"end": 80,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 10
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 4,
|
||||||
|
"column": 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -87,7 +87,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -107,6 +106,7 @@
|
|||||||
"name": "spawn",
|
"name": "spawn",
|
||||||
"leadingComments": null
|
"leadingComments": null
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 33,
|
"start": 33,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -123,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"name": "answer"
|
"name": "answer"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 14,
|
"start": 14,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -123,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"name": "if"
|
"name": "if"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 10,
|
"start": 10,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -123,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"name": "true"
|
"name": "true"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 12,
|
"start": 12,
|
||||||
|
|||||||
@ -42,7 +42,6 @@
|
|||||||
"column": 26
|
"column": 26
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"await": false,
|
|
||||||
"left": {
|
"left": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 4,
|
"start": 4,
|
||||||
|
|||||||
@ -42,7 +42,6 @@
|
|||||||
"column": 31
|
"column": 31
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"await": false,
|
|
||||||
"left": {
|
"left": {
|
||||||
"type": "VariableDeclaration",
|
"type": "VariableDeclaration",
|
||||||
"start": 5,
|
"start": 5,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -123,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"name": "false"
|
"name": "false"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 13,
|
"start": 13,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -123,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"name": "null"
|
"name": "null"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 12,
|
"start": 12,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "StringLiteral",
|
"type": "StringLiteral",
|
||||||
@ -126,6 +125,7 @@
|
|||||||
},
|
},
|
||||||
"value": "answer"
|
"value": "answer"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 16,
|
"start": 16,
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -91,6 +90,7 @@
|
|||||||
},
|
},
|
||||||
"name": "message"
|
"name": "message"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "StringLiteral",
|
"type": "StringLiteral",
|
||||||
"start": 17,
|
"start": 17,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -123,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 9,
|
"start": 9,
|
||||||
@ -159,7 +159,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -178,6 +177,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 15,
|
"start": 15,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -100,7 +100,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -119,6 +118,7 @@
|
|||||||
},
|
},
|
||||||
"name": "a"
|
"name": "a"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ArrayExpression",
|
"type": "ArrayExpression",
|
||||||
"start": 5,
|
"start": 5,
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
@ -94,6 +93,7 @@
|
|||||||
},
|
},
|
||||||
"value": 1
|
"value": 1
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "BinaryExpression",
|
"type": "BinaryExpression",
|
||||||
"start": 5,
|
"start": 5,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "StringLiteral",
|
"type": "StringLiteral",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "StringLiteral",
|
"type": "StringLiteral",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -123,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"name": "get"
|
"name": "get"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 11,
|
"start": 11,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -123,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"name": "set"
|
"name": "set"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 11,
|
"start": 11,
|
||||||
|
|||||||
@ -42,7 +42,6 @@
|
|||||||
"column": 31
|
"column": 31
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"await": false,
|
|
||||||
"left": {
|
"left": {
|
||||||
"type": "VariableDeclaration",
|
"type": "VariableDeclaration",
|
||||||
"start": 5,
|
"start": 5,
|
||||||
|
|||||||
@ -87,7 +87,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -106,6 +105,7 @@
|
|||||||
},
|
},
|
||||||
"name": "public"
|
"name": "public"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 8,
|
"start": 8,
|
||||||
|
|||||||
@ -87,7 +87,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -106,6 +105,7 @@
|
|||||||
},
|
},
|
||||||
"name": "arguments"
|
"name": "arguments"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 8,
|
"start": 8,
|
||||||
|
|||||||
1
test/fixtures/core/uncategorised/554/actual.js
vendored
Normal file
1
test/fixtures/core/uncategorised/554/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
var a = 0123.;
|
||||||
3
test/fixtures/core/uncategorised/554/options.json
vendored
Normal file
3
test/fixtures/core/uncategorised/554/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"throws": "Unexpected token (1:13)"
|
||||||
|
}
|
||||||
@ -116,7 +116,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -135,6 +134,7 @@
|
|||||||
},
|
},
|
||||||
"name": "length"
|
"name": "length"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 9,
|
"start": 9,
|
||||||
|
|||||||
@ -123,7 +123,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -142,6 +141,7 @@
|
|||||||
},
|
},
|
||||||
"name": "title"
|
"name": "title"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 14,
|
"start": 14,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "CallExpression",
|
"type": "CallExpression",
|
||||||
@ -139,6 +138,7 @@
|
|||||||
},
|
},
|
||||||
"arguments": []
|
"arguments": []
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "StringLiteral",
|
"type": "StringLiteral",
|
||||||
"start": 23,
|
"start": 23,
|
||||||
|
|||||||
1
test/fixtures/es2015/destructuring/nested/actual.js
vendored
Normal file
1
test/fixtures/es2015/destructuring/nested/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
({ x, ...{ y, z } } = o)
|
||||||
300
test/fixtures/es2015/destructuring/nested/expected.json
vendored
Normal file
300
test/fixtures/es2015/destructuring/nested/expected.json
vendored
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start": 0,
|
||||||
|
"end": 24,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start": 0,
|
||||||
|
"end": 24,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sourceType": "script",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ExpressionStatement",
|
||||||
|
"start": 0,
|
||||||
|
"end": 24,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 0
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 24
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expression": {
|
||||||
|
"type": "AssignmentExpression",
|
||||||
|
"start": 1,
|
||||||
|
"end": 23,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 1
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 23
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"operator": "=",
|
||||||
|
"left": {
|
||||||
|
"type": "ObjectPattern",
|
||||||
|
"start": 1,
|
||||||
|
"end": 19,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 1
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 19
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"type": "ObjectProperty",
|
||||||
|
"start": 3,
|
||||||
|
"end": 4,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"method": false,
|
||||||
|
"computed": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 3,
|
||||||
|
"end": 4,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 4
|
||||||
|
},
|
||||||
|
"identifierName": "x"
|
||||||
|
},
|
||||||
|
"name": "x"
|
||||||
|
},
|
||||||
|
"shorthand": true,
|
||||||
|
"value": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 3,
|
||||||
|
"end": 4,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 3
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 4
|
||||||
|
},
|
||||||
|
"identifierName": "x"
|
||||||
|
},
|
||||||
|
"name": "x"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"shorthand": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "RestElement",
|
||||||
|
"start": 6,
|
||||||
|
"end": 17,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 6
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 17
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"argument": {
|
||||||
|
"type": "ObjectPattern",
|
||||||
|
"start": 9,
|
||||||
|
"end": 17,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 9
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 17
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"type": "ObjectProperty",
|
||||||
|
"start": 11,
|
||||||
|
"end": 12,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 11
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"method": false,
|
||||||
|
"computed": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 11,
|
||||||
|
"end": 12,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 11
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 12
|
||||||
|
},
|
||||||
|
"identifierName": "y"
|
||||||
|
},
|
||||||
|
"name": "y"
|
||||||
|
},
|
||||||
|
"shorthand": true,
|
||||||
|
"value": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 11,
|
||||||
|
"end": 12,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 11
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 12
|
||||||
|
},
|
||||||
|
"identifierName": "y"
|
||||||
|
},
|
||||||
|
"name": "y"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"shorthand": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "ObjectProperty",
|
||||||
|
"start": 14,
|
||||||
|
"end": 15,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 14
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 15
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"method": false,
|
||||||
|
"computed": false,
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 14,
|
||||||
|
"end": 15,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 14
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 15
|
||||||
|
},
|
||||||
|
"identifierName": "z"
|
||||||
|
},
|
||||||
|
"name": "z"
|
||||||
|
},
|
||||||
|
"shorthand": true,
|
||||||
|
"value": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 14,
|
||||||
|
"end": 15,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 14
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 15
|
||||||
|
},
|
||||||
|
"identifierName": "z"
|
||||||
|
},
|
||||||
|
"name": "z"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"shorthand": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start": 22,
|
||||||
|
"end": 23,
|
||||||
|
"loc": {
|
||||||
|
"start": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 22
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"line": 1,
|
||||||
|
"column": 23
|
||||||
|
},
|
||||||
|
"identifierName": "o"
|
||||||
|
},
|
||||||
|
"name": "o"
|
||||||
|
},
|
||||||
|
"extra": {
|
||||||
|
"parenthesized": true,
|
||||||
|
"parenStart": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
3
test/fixtures/es2015/destructuring/nested/options.json
vendored
Normal file
3
test/fixtures/es2015/destructuring/nested/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"plugins": ["objectRestSpread"]
|
||||||
|
}
|
||||||
@ -103,7 +103,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -122,6 +121,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo"
|
"name": "foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 15,
|
"start": 15,
|
||||||
@ -242,7 +242,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -261,6 +260,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo"
|
"name": "foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 48,
|
"start": 48,
|
||||||
@ -378,7 +378,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -397,6 +396,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo"
|
"name": "foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 82,
|
"start": 82,
|
||||||
@ -427,7 +427,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -446,6 +445,7 @@
|
|||||||
},
|
},
|
||||||
"name": "baz"
|
"name": "baz"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 84,
|
"start": 84,
|
||||||
@ -569,7 +569,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -588,6 +587,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo"
|
"name": "foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 119,
|
"start": 119,
|
||||||
@ -618,7 +618,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -637,6 +636,7 @@
|
|||||||
},
|
},
|
||||||
"name": "baz"
|
"name": "baz"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 127,
|
"start": 127,
|
||||||
@ -667,7 +667,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -686,6 +685,7 @@
|
|||||||
},
|
},
|
||||||
"name": "qux"
|
"name": "qux"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 129,
|
"start": 129,
|
||||||
@ -812,7 +812,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -831,6 +830,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo"
|
"name": "foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 166,
|
"start": 166,
|
||||||
@ -861,7 +861,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -880,6 +879,7 @@
|
|||||||
},
|
},
|
||||||
"name": "baz"
|
"name": "baz"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 174,
|
"start": 174,
|
||||||
@ -910,7 +910,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -929,6 +928,7 @@
|
|||||||
},
|
},
|
||||||
"name": "qux2"
|
"name": "qux2"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 176,
|
"start": 176,
|
||||||
@ -971,7 +971,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -990,6 +989,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo3"
|
"name": "foo3"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 186,
|
"start": 186,
|
||||||
@ -1344,7 +1344,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -1363,6 +1362,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo"
|
"name": "foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ArrayPattern",
|
"type": "ArrayPattern",
|
||||||
"start": 277,
|
"start": 277,
|
||||||
@ -1430,7 +1430,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -1449,6 +1448,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo2"
|
"name": "foo2"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ArrayPattern",
|
"type": "ArrayPattern",
|
||||||
"start": 295,
|
"start": 295,
|
||||||
@ -1585,7 +1585,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -1604,6 +1603,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo"
|
"name": "foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 332,
|
"start": 332,
|
||||||
@ -1634,7 +1634,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -1653,6 +1652,7 @@
|
|||||||
},
|
},
|
||||||
"name": "baz"
|
"name": "baz"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 339,
|
"start": 339,
|
||||||
@ -1683,7 +1683,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -1702,6 +1701,7 @@
|
|||||||
},
|
},
|
||||||
"name": "qux3"
|
"name": "qux3"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 341,
|
"start": 341,
|
||||||
@ -1744,7 +1744,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -1763,6 +1762,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo2"
|
"name": "foo2"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 357,
|
"start": 357,
|
||||||
@ -1793,7 +1793,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -1812,6 +1811,7 @@
|
|||||||
},
|
},
|
||||||
"name": "baz2"
|
"name": "baz2"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ArrayPattern",
|
"type": "ArrayPattern",
|
||||||
"start": 365,
|
"start": 365,
|
||||||
@ -1949,7 +1949,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -1968,6 +1967,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo"
|
"name": "foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 402,
|
"start": 402,
|
||||||
@ -1998,7 +1998,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -2017,6 +2016,7 @@
|
|||||||
},
|
},
|
||||||
"name": "baz"
|
"name": "baz"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 409,
|
"start": 409,
|
||||||
@ -2047,7 +2047,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -2066,6 +2065,7 @@
|
|||||||
},
|
},
|
||||||
"name": "qux5"
|
"name": "qux5"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 411,
|
"start": 411,
|
||||||
@ -2108,7 +2108,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -2127,6 +2126,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo2"
|
"name": "foo2"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ObjectPattern",
|
"type": "ObjectPattern",
|
||||||
"start": 427,
|
"start": 427,
|
||||||
@ -2157,7 +2157,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -2176,6 +2175,7 @@
|
|||||||
},
|
},
|
||||||
"name": "baz2"
|
"name": "baz2"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ArrayPattern",
|
"type": "ArrayPattern",
|
||||||
"start": 435,
|
"start": 435,
|
||||||
@ -2221,7 +2221,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -2240,6 +2239,7 @@
|
|||||||
},
|
},
|
||||||
"name": "qux6"
|
"name": "qux6"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 437,
|
"start": 437,
|
||||||
@ -2368,7 +2368,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -2387,6 +2386,7 @@
|
|||||||
},
|
},
|
||||||
"name": "Foo"
|
"name": "Foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 469,
|
"start": 469,
|
||||||
@ -2507,7 +2507,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -2526,6 +2525,7 @@
|
|||||||
},
|
},
|
||||||
"name": "foo"
|
"name": "foo"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "ArrayPattern",
|
"type": "ArrayPattern",
|
||||||
"start": 502,
|
"start": 502,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 11,
|
"start": 11,
|
||||||
@ -123,6 +122,7 @@
|
|||||||
"name": "async"
|
"name": "async"
|
||||||
},
|
},
|
||||||
"computed": false,
|
"computed": false,
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 11,
|
"start": 11,
|
||||||
@ -159,7 +159,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -178,6 +177,7 @@
|
|||||||
},
|
},
|
||||||
"name": "bar"
|
"name": "bar"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 18,
|
"start": 18,
|
||||||
|
|||||||
1
test/fixtures/es2015/shorthand/1/actual.js
vendored
Normal file
1
test/fixtures/es2015/shorthand/1/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
var x = ({ const });
|
||||||
3
test/fixtures/es2015/shorthand/1/options.json
vendored
Normal file
3
test/fixtures/es2015/shorthand/1/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"throws": "const is a reserved word (1:11)"
|
||||||
|
}
|
||||||
1
test/fixtures/es2015/shorthand/2/actual.js
vendored
Normal file
1
test/fixtures/es2015/shorthand/2/actual.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
({ get, this, if });
|
||||||
3
test/fixtures/es2015/shorthand/2/options.json
vendored
Normal file
3
test/fixtures/es2015/shorthand/2/options.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"throws": "this is a reserved word (1:8)"
|
||||||
|
}
|
||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": true,
|
"method": true,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -91,6 +90,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 7,
|
"start": 7,
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "BinaryExpression",
|
"type": "BinaryExpression",
|
||||||
@ -130,6 +129,7 @@
|
|||||||
"value": "y"
|
"value": "y"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 15,
|
"start": 15,
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -91,6 +90,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "FunctionExpression",
|
"type": "FunctionExpression",
|
||||||
"start": 7,
|
"start": 7,
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -91,6 +90,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 7,
|
"start": 7,
|
||||||
@ -127,7 +127,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -146,6 +145,7 @@
|
|||||||
},
|
},
|
||||||
"name": "y"
|
"name": "y"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 14,
|
"start": 14,
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -130,7 +129,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": true,
|
"method": true,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -87,7 +87,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -106,6 +105,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 10,
|
"start": 10,
|
||||||
@ -156,7 +156,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -175,6 +174,7 @@
|
|||||||
},
|
},
|
||||||
"name": "y"
|
"name": "y"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 16,
|
"start": 16,
|
||||||
|
|||||||
@ -93,7 +93,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -112,6 +111,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 17,
|
"start": 17,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": true,
|
"method": true,
|
||||||
"shorthand": false,
|
|
||||||
"computed": true,
|
"computed": true,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
|
|||||||
@ -107,7 +107,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -126,6 +125,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 12,
|
"start": 12,
|
||||||
@ -179,7 +179,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -198,6 +197,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 21,
|
"start": 21,
|
||||||
|
|||||||
@ -137,7 +137,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -156,6 +155,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 14,
|
"start": 14,
|
||||||
@ -209,7 +209,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -228,6 +227,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 23,
|
"start": 23,
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -91,6 +90,7 @@
|
|||||||
},
|
},
|
||||||
"name": "f"
|
"name": "f"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "FunctionExpression",
|
"type": "FunctionExpression",
|
||||||
"start": 5,
|
"start": 5,
|
||||||
@ -154,7 +154,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -173,6 +172,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 15,
|
"start": 15,
|
||||||
@ -226,7 +226,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -245,6 +244,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 24,
|
"start": 24,
|
||||||
|
|||||||
@ -72,7 +72,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": true,
|
"method": true,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -141,7 +140,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -160,6 +158,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 5,
|
"start": 5,
|
||||||
@ -213,7 +212,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -232,6 +230,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 14,
|
"start": 14,
|
||||||
|
|||||||
@ -156,7 +156,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -175,6 +174,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 11,
|
"start": 11,
|
||||||
@ -228,7 +228,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -247,6 +246,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 20,
|
"start": 20,
|
||||||
|
|||||||
@ -105,7 +105,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": true,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -124,6 +123,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": true,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
"start": 3,
|
"start": 3,
|
||||||
@ -177,7 +177,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -196,6 +195,7 @@
|
|||||||
},
|
},
|
||||||
"name": "x"
|
"name": "x"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "NumericLiteral",
|
"type": "NumericLiteral",
|
||||||
"start": 12,
|
"start": 12,
|
||||||
|
|||||||
@ -104,7 +104,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"method": false,
|
"method": false,
|
||||||
"shorthand": false,
|
|
||||||
"computed": false,
|
"computed": false,
|
||||||
"key": {
|
"key": {
|
||||||
"type": "Identifier",
|
"type": "Identifier",
|
||||||
@ -123,6 +122,7 @@
|
|||||||
},
|
},
|
||||||
"name": "f"
|
"name": "f"
|
||||||
},
|
},
|
||||||
|
"shorthand": false,
|
||||||
"value": {
|
"value": {
|
||||||
"type": "FunctionExpression",
|
"type": "FunctionExpression",
|
||||||
"start": 9,
|
"start": 9,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user