Compare commits

..

105 Commits

Author SHA1 Message Date
Nicolò Ribaudo
d896ce2b53 v7.3.2 2019-02-04 23:20:05 +01:00
Nicolò Ribaudo
44d8a59361 Use a GitHub Action to generate the changelog (#9434) [skip ci]
* Use a GitHub Action to generate the changelog

* Update main.workflow [skip ci]
2019-02-04 22:15:44 +01:00
Daniel Tschinder
344d35bbe9 Simplify await and yield tracking in params (#9405) 2019-02-04 22:01:17 +01:00
Thiago Arrais
fe71154626 Support for await and yield in pipelines (#9401) 2019-02-04 21:58:46 +01:00
gverni
65cbbc1ef8 Fix duplicate definition error in private class methods (#9453) 2019-02-04 09:19:04 -06:00
Nicolò Ribaudo
d37c958637 Transform private async and generator functions (#9423) 2019-02-04 15:10:46 +01:00
Daniel Tschinder
9eb010da50 Unify reserved word checking and update error messages (#9402)
* Unify reserved word checking and update error messages

* Fix test
2019-01-31 19:02:32 -08:00
Galymzhan Abdugalimov
7e9029e337 Switched gutil.log to fancyLog due to deprecation (#9432) 2019-01-30 08:23:02 -06:00
Galymzhan Abdugalimov
00c3e3c8e0 Fixed link to @babel/parser's issues in README (#9427) 2019-01-30 08:18:43 -06:00
Nicolò Ribaudo
7192546eb8 Run prettier again 2019-01-30 11:35:42 +01:00
Nicolò Ribaudo
4c4c22a316 Run prettier 2019-01-30 11:30:31 +01:00
Rizky
56044c7851 install polyfill & runtime to dependency instead of devDependency [skip ci] (#9409) 2019-01-29 08:09:08 -06:00
Daniel Tschinder
828169e611 Fix line continuation with Unicode line terminators (#9403) 2019-01-28 13:35:35 -08:00
Moti Zilberman
1452e977a0 Destructuring: Create assignments from ForX non-declaration patterns (#9414) 2019-01-28 09:50:24 +01:00
Brian Ng
ede69eef7f Bump deps (#9417) 2019-01-26 22:49:48 -05:00
Dylan Staley
03230eaa9c Retain JSX pragma if defined as a comment (#9095) 2019-01-26 15:36:10 -06:00
Brian Ng
7dc157f9be Fix location/range on TypeScript ExportNamedDeclarations (#9406) 2019-01-24 19:44:22 -06:00
Yuri Karadzhov
854313a759 Correctly visit param decorators to prevent their imports being removed in typescript transform (#8738)
* Remove types on program exit in typescript transform

* Revert changes to typescript transform

* Correctly add visitors for param decorators

* Fix plugin for node 6
2019-01-24 15:07:56 -08:00
Daniel Tschinder
46ba5940c2 Make yield a contextual keyword (#9400) 2019-01-23 14:33:23 -08:00
Daniel Tschinder
42c5d3fc4b Correctly fail for invalid yield in for (#9398) 2019-01-23 13:39:30 -08:00
Brian Ng
d4e045ac24 Fix support for Flow's QualifiedTypeIdentifier (#9396) 2019-01-23 15:19:17 -06:00
Daniel Tschinder
8bc9f9a05f fix: Allow toplevel await when option true and correctly mark await keyword as unexpected (#9371) 2019-01-22 14:56:30 -08:00
Daniel Tschinder
93e1b5e612 Merge pull request #9375 from danez/contextual-let
Make let a contextual keyword
2019-01-22 14:55:49 -08:00
Daniel Tschinder
4f69699b71 Fix parsing in non-declaration places 2019-01-22 13:12:03 -08:00
Daniel Tschinder
f4f5ca2aaa Parse class name in strict mode
The specification defines that the whole class declaration is parsed in strict mode
2019-01-22 13:12:03 -08:00
Daniel Tschinder
8071dca9ad Disallow const let or let let 2019-01-22 13:12:02 -08:00
Daniel Tschinder
178f2d7949 Make let a contextual keyword 2019-01-22 13:12:02 -08:00
Nicolò Ribaudo
65febdd13a Refactor import and export parsing (#9326)
* [parser] Refactor import parsing

* [parser] Refactor export parsing

* Fix types
2019-01-22 19:52:56 +01:00
Brian Ng
f77c450cda Bump prettier (#9373) 2019-01-22 09:16:32 -06:00
Nicolò Ribaudo
f2af6c1170 v7.3.1 2019-01-22 08:07:23 +01:00
Daniel Tschinder
43b83f8ed7 Revert "Differentiate object spread and non-spread properties (#9341)" (#9379)
This reverts commit 3ae5e79ec8.
2019-01-21 23:03:54 -08:00
Daniel Tschinder
af88e63dff fix new keyword broken by recent refactoring (#9377) 2019-01-21 22:25:37 -08:00
Nicolò Ribaudo
f6ee26c3da v7.3.0 2019-01-21 22:22:39 +01:00
Tim McClure
e8de6fa5d4 Private Class Methods Stage 3: Private Accessors (#9101)
* Add accessor loose support

* Add private accessors spec support

* Fix private dupe name check

* Changes from code review

* Add duplicated names tests

* Add get/set-only tests

* Move accessors tests

* Split out updates tests

* Add helper change tests

* Update test output

* Update test options
2019-01-21 22:05:37 +01:00
Kagami Sascha Rosylight
3ae5e79ec8 Differentiate object spread and non-spread properties (#9341)
* add isSpread field

* use argument

* t.booleanLiteral

* fix typo

* push empty-argument object

* .object

* .value

* object field should be an expression

* lint

* update outputs

* isSpread for the second argument is redundant

* add test

* alternating spread
2019-01-21 22:04:47 +01:00
Thiago Arrais
e9331aa0c0 Transform for the smart pipeline operator proposal (#9179) 2019-01-21 22:04:14 +01:00
Henry Zhu
ba4141934f add v7 downloads [skip ci] (#9370) 2019-01-21 12:48:15 -05:00
Daniel Tschinder
96a7343142 Merge pull request #9348 from danez/perf
Parser Performance Collection
2019-01-21 02:27:42 -08:00
Armano
a2e6d8e968 Disallow usage of invalid keyword after export abstract statement in Typescript (#9336) 2019-01-19 15:48:05 -06:00
Nicolò Ribaudo
4ce37b7aca Update test262 sha (#9365) 2019-01-19 18:10:28 +01:00
Brian Ng
b92ad318f1 Add support for transform-named-capturing-groups-regex in preset-env (#9345) 2019-01-17 19:51:38 -06:00
Daniel Tschinder
2d6231fd3d Update flow whitelist 2019-01-17 16:16:32 -08:00
Daniel Tschinder
4e5e319d5b perf: remove double check for keywords in readWord
Instead of calling isKeyword we simple check directly if the keyword token is available
2019-01-17 16:16:31 -08:00
Daniel Tschinder
b66d921053 perf: Use === or Set.has instead of array.indexOf for keyword checks 2019-01-17 16:16:30 -08:00
Daniel Tschinder
f12905b531 perf: Use for loops while cloning classes 2019-01-17 16:16:29 -08:00
Daniel Tschinder
f216975378 perf: call isLineTerminator as last check 2019-01-17 16:16:28 -08:00
Daniel Tschinder
3a3d5cbe9c perf: Check for plugin only once before looping 2019-01-17 16:16:28 -08:00
Daniel Tschinder
10555c719e Build the parser also for node 6.9 and up 2019-01-17 16:16:27 -08:00
Daniel Tschinder
58768072ef perf: Ensure canInsertSemicolon is always called last
It does a lot of checks and a regex test
2019-01-17 16:16:26 -08:00
Daniel Tschinder
455e003567 perf: Optimize regex
This saves some steps, as the regex parser does not have to backtrack for character classes, but is has to for alternates
2019-01-17 16:15:07 -08:00
Daniel Tschinder
49f7bcf271 perf: Remove unnecessary check for flow plugin inside of flow plugin 2019-01-17 16:15:07 -08:00
Daniel Tschinder
c2e41588aa perf: run flow code in flow plugin 2019-01-17 16:15:05 -08:00
Daniel Tschinder
a1eac37bd2 Generate prettier comments 2019-01-17 16:15:04 -08:00
Daniel Tschinder
0370af58f1 perf: Use strict equals 2019-01-17 16:15:03 -08:00
Daniel Tschinder
8df0500f55 perf: Simplify reading of tokens.
This avoids checking isIdentifierStart for every single token
2019-01-17 16:15:01 -08:00
Daniel Tschinder
e4b8cfc768 perf: use Set instead of string indexOf 2019-01-17 16:15:00 -08:00
Daniel Tschinder
a7757ec4d0 perf: Use increment operator 2019-01-17 16:14:58 -08:00
Daniel Tschinder
25a8db2a29 perf: use normal equality check in stead of indexOf 2019-01-17 16:14:57 -08:00
Daniel Tschinder
48fd387779 perf: precalculate length 2019-01-17 16:14:56 -08:00
Daniel Tschinder
59c4bbb4ab perf: Make plugins a map instead of object
Fix plugin options
2019-01-17 16:14:55 -08:00
Daniel Tschinder
2dc1c91955 perf: Move input to state and precalculate length
This also fixes a bug with async functions
2019-01-17 16:14:54 -08:00
Daniel Tschinder
ae154c86ed perf: Minor optimizations 2019-01-17 16:14:53 -08:00
unconfident
e9588061d7 Copy "optional" property when cloning Identifier node (#9333)
Fixes #9331
2019-01-17 17:12:16 -05:00
Nicolò Ribaudo
0a88230ec4 Disallow async functions as loop bodies (#9314) 2019-01-17 17:07:48 -05:00
Nicolò Ribaudo
a27b9b4299 Add @babel/plugin-transform-named-capturing-groups-regex (#7105)
When the `runtime` flag is on (by default), this plugin adds a new helper which wraps the native `RegExp` class to provide groups support. People nees to use a polyfill (I implemented it in core-js) for browsers that don't support ES6 regexps.
2019-01-15 18:21:17 +01:00
Brian Ng
aaec2cd51d Fix handling newline with TypeScript declare and abstract classes (#9328) 2019-01-15 06:56:52 -06:00
Brian Ng
34c9890f41 Fix range on TypeScript index signature parameters (#9335) 2019-01-15 06:52:33 -06:00
Armano
e8038863c3 Fix range on TypeScript this type predicate (#9339) 2019-01-15 10:35:49 +01:00
Nicolò Ribaudo
694e3fd8cf Merge declaration and init of props in parser's state (#9312)
* Merge declaration and init of props in parser's state

* Move type def
2019-01-13 23:54:44 +01:00
Brian Ng
40ae6568a4 Add support for proposal-json-strings in preset-env (#9323) 2019-01-13 08:32:33 -06:00
Henry Zhu
4944e9e180 update sponsor link again [skip ci] 2019-01-13 08:00:46 -05:00
Nicolò Ribaudo
a24206eb96 Fix error for decorators not enabled (#9321)
* Fix error for decorators not enabled

* Update error message
2019-01-13 00:35:22 +01:00
Henry Zhu
d6b4ab75ee fix sponsor link [skip ci] 2019-01-12 10:41:49 -05:00
Nicolò Ribaudo
3e4b608a80 Parse class heritage as strict mode code (#9315) 2019-01-12 14:54:23 +01:00
Henry Zhu
28319eb07e add sponsor [skip ci] 2019-01-11 13:50:48 -05:00
Nicolò Ribaudo
5889620a6a Disallow new import(x) and import(x,) (#9313)
* Disallow "new import(...)"

* Disallow trailing comma inside dynamic import

* Rename test

* Update error message
2019-01-11 18:59:51 +01:00
Nicolò Ribaudo
9764718c32 Disallow trailing comma after rest (#9311)
* Add new tests

* Use state instead of param and disallow comma in [...a,]=[]

* Unify error messages

* Object destructuring

* Update whitelist
2019-01-11 13:08:38 +01:00
Nicolò Ribaudo
28b70e5910 Generate types for TSImportType 2019-01-11 11:46:15 +01:00
Henry Zhu
4c2f8d9337 @babel/generator: Add emit and builder for TSImportType (#9309) 2019-01-10 13:57:00 -05:00
Armano
2cc0376756 @babel/parser(ts): Add parsing of type import (#9302) 2019-01-10 11:14:48 -05:00
Nicolò Ribaudo
8e051cae46 [decorators] Set method names at compile time instead of at runtime (#9244) 2019-01-10 00:45:02 +01:00
Cameron Martin
778a61a3c2 [@babel/types] Moved generators related to babel-types into the babel-types package directory. (#9245) 2019-01-09 00:14:31 +01:00
Armano
46e3f6df1f @babel/parser: include leading character into range of generic ArrowFunctionExpression (#9295) 2019-01-08 07:19:55 -06:00
Brian Ng
03022d169e Throw error if TypeScript class has empty implements (#9292) 2019-01-07 15:27:27 -06:00
David Laban
9803253363 flow type update: babel-types.isType(?string, string): boolean (#9275) 2019-01-07 08:53:01 -06:00
Brian Ng
a55382e4ad Test262 update (#9288) 2019-01-07 08:52:36 -06:00
Sven Sauleau
b211b810d1 Use 2014-present in license (#9290) 2019-01-07 08:52:11 -06:00
James George
25e880d355 Add follow on twitter badge (#9264) [skip ci] 2019-01-07 09:49:20 -05:00
Daniel Tschinder
e43777bb5f Fix location for typescript type assertions in AST (#9284) 2019-01-06 16:39:14 -08:00
Nicolò Ribaudo
efc60a1703 Add test sources to prettierignore (#9287) [skip ci] 2019-01-06 20:59:02 +01:00
Daniel Tschinder
54f072991d Revert "Revert babel-helper-builder-react-jsx change from #4988" (#9119)
This reverts commit dbc07220ae.

# Conflicts:
#	packages/babel-helper-builder-react-jsx/src/index.js
2019-01-05 22:22:49 -08:00
Brian Ng
a58893d1e3 Ensure modifiers are included in TSParameterProperty ranges (#9276) 2019-01-04 10:02:09 -06:00
Nicolò Ribaudo
865eb93c2d [private methods] Define private methods before executing initializers (#9248) 2019-01-03 20:33:44 +01:00
Berlam Henderson
49f52bbcb3 Bump license years for 2019 (#9271) 2019-01-03 09:12:03 -06:00
Nicolò Ribaudo
9d1d0fe57a Add mixins support to the _decorate helper (#9166) 2018-12-29 22:54:30 +01:00
Brian Ng
ea1c436ea1 Fix handling scoped packages in preset-env include/exclude options (#9219) 2018-12-27 09:54:28 -06:00
David Laban
3f9a1c08cc Add tests for babel-types.isType (#9243) 2018-12-27 12:49:34 +01:00
J. S. Choi
c586d4e8ca parser, smart pipes: Add support for yield in pipeline bodies
Fixes #9178.
2018-12-23 17:09:18 +01:00
J. S. Choi
60ffe1d103 parser, smart pipes: Add test for async–await 2018-12-23 17:09:18 +01:00
Armano
b5177ce290 babel-parser: typescript: add missing bigint keyword (#9230) 2018-12-22 17:18:32 -06:00
Henry Zhu
d1aa665657 update sponsors [skip ci] 2018-12-21 21:39:06 -05:00
Nicolò Ribaudo
f130981546 v7.2.5 2018-12-21 23:32:48 +01:00
Nicolò Ribaudo
bc347bab7a Add @babel/helpers to devDependencies of runtime and runtime-corejs2 (#9222) 2018-12-21 10:08:47 +01:00
Nicolò Ribaudo
21228abfde v7.2.4 2018-12-20 13:08:41 +01:00
Nicolò Ribaudo
e417437355 Minify standalone 2018-12-20 12:50:41 +01:00
742 changed files with 13324 additions and 6276 deletions

View File

@@ -0,0 +1,18 @@
FROM node:10
LABEL "name" = "trigger-github-release"
LABEL "version" = "0.0.1"
LABEL "com.github.actions.name" = "Trigger GitHub release"
LABEL "com.github.actions.description" = "Trigger a new GitHub release and generate the changelog using lerna-changelog."
LABEL "com.github.actions.icon" = "tag"
LABEL "com.github.actions.color" = "yellow"
ADD entrypoint.sh /action/entrypoint.sh
ADD package.json /action/package.json
ADD package-lock.json /action/package-lock.json
ADD release.js /action/release.js
RUN chmod +x /action/entrypoint.sh
ENTRYPOINT ["/action/entrypoint.sh"]

View File

@@ -0,0 +1,29 @@
#!/bin/sh
set -e
echo "INFO: Installing action dependencies..."
(cd /action; npm ci)
echo "INFO: Checking out current tag..."
git -c advice.detachedHead=false checkout $GITHUB_REF
echo "INFO: Getting tag info..."
current_tag=$(git describe --abbrev=0 --tags)
last_tag=$(git describe --abbrev=0 --tags HEAD^)
echo "INFO: New version is $current_tag; last version is $last_tag."
echo "INFO: Generating the changelog..."
# lerna-changelog expects the token to be provided as GITHUB_AUTH,
# but GitHub actions don't allow to predefine custom env vars prefixed with
# GITHUB_. We need to define it here.
changelog=$(
GITHUB_AUTH="$GITHUB_TOKEN" \
node /action/node_modules/.bin/lerna-changelog --tag-from $last_tag --tag-to $current_tag
)
echo "INFO: Publishing the new GitHub release..."
echo "$changelog" | node /action/release $current_tag
echo "INFO: Done! Don't forget to thank new contributors :)"

1415
.github/actions/trigger-github-release/package-lock.json generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
{
"private": true,
"name": "@internal/trigger-github-release",
"version": "0.0.1",
"author": "Nicolò Ribaudo <nicolo.ribaudo@gmail.com>",
"license": "MIT",
"dependencies": {
"@octokit/rest": "^16.3.0",
"get-stdin": "^6.0.0",
"lerna-changelog": "^0.8.2"
}
}

View File

@@ -0,0 +1,25 @@
"use strict";
const [ /* node */, /* file */, tag ] = process.argv;
const getStdin = require("get-stdin");
const octokit = require("@octokit/rest")();
octokit.authenticate({
type: "token",
token: process.env.GITHUB_TOKEN
});
const [ repoOwner, repoName ] = process.env.GITHUB_REPOSITORY.split("/");
getStdin()
.then(changelog => octokit.repos.createRelease({
owner: repoOwner,
repo: repoName,
tag_name: tag,
body: changelog,
}))
.catch(err => {
console.error(err);
process.exit(1);
});

26
.github/main.workflow vendored Normal file
View File

@@ -0,0 +1,26 @@
workflow "Release" {
on = "push"
resolves = ["Trigger GitHub release"]
}
action "Trigger GitHub release" {
uses = "./.github/actions/trigger-github-release/"
secrets = ["GITHUB_TOKEN"]
# When GitHub Actions will support the "release" event for public
# repositories, we won't need these checks anymore.
needs = [
"Is version tag",
"On master branch",
]
}
action "Is version tag" {
uses = "actions/bin/filter@master"
args = "tag v*"
}
action "On master branch" {
uses = "actions/bin/filter@master"
args = "branch master"
}

2
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.DS_Store
/node_modules
/.github/actions/*/node_modules
/packages/*/node_modules
/packages/*/LICENSE
!/packages/babel-parser/LICENSE
@@ -15,6 +16,7 @@ coverage
dist
/.package.json
package-lock.json
!/.github/actions/*/package-lock.json
/packages/babel-runtime/helpers/*.js
!/packages/babel-runtime/helpers/toArray.js

View File

@@ -1,2 +1,5 @@
package.json
packages/babel-preset-env/data
packages/*/test/fixtures/**/input.*
packages/*/test/fixtures/**/exec.*
packages/*/test/fixtures/**/output.*

View File

@@ -6,7 +6,7 @@ const chalk = require("chalk");
const newer = require("gulp-newer");
const babel = require("gulp-babel");
const gulpWatch = require("gulp-watch");
const gutil = require("gulp-util");
const fancyLog = require("fancy-log");
const filter = require("gulp-filter");
const gulp = require("gulp");
const path = require("path");
@@ -38,7 +38,7 @@ function getIndexFromPackage(name) {
function compilationLogger(rollup) {
return through.obj(function(file, enc, callback) {
gutil.log(
fancyLog(
`Compiling '${chalk.cyan(file.relative)}'${
rollup ? " with rollup " : ""
}...`
@@ -50,7 +50,7 @@ function compilationLogger(rollup) {
function errorsLogger() {
return plumber({
errorHandler(err) {
gutil.log(err.stack);
fancyLog(err.stack);
},
});
}

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2014-2018 Sebastian McKenzie and other contributors
Copyright (c) 2014-present Sebastian McKenzie and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@@ -1,6 +1,6 @@
MAKEFLAGS = -j1
FLOW_COMMIT = e192e1a4793dd8e43415fbfe8046d832cb513c8b
TEST262_COMMIT = 238c88d4a084d9928372954e2fec54af2c951281
FLOW_COMMIT = 2ac56861e3ceff9ca406ae586fbafb3480c6c0b7
TEST262_COMMIT = 4f1155c566a222238fd86f179c6635ecb4c289bb
# Fix color output until TravisCI fixes https://github.com/travis-ci/travis-ci/issues/7967
export FORCE_COLOR = true
@@ -15,8 +15,8 @@ build: clean clean-lib
# call build again as the generated files might need to be compiled again.
./node_modules/.bin/gulp build
# generate flow and typescript typings
node scripts/generators/flow.js > ./packages/babel-types/lib/index.js.flow
node scripts/generators/typescript.js > ./packages/babel-types/lib/index.d.ts
node packages/babel-types/scripts/generators/flow.js > ./packages/babel-types/lib/index.js.flow
node packages/babel-types/scripts/generators/typescript.js > ./packages/babel-types/lib/index.d.ts
ifneq ("$(BABEL_COVERAGE)", "true")
make build-standalone
make build-preset-env-standalone
@@ -46,7 +46,8 @@ watch: clean clean-lib
# development too.
BABEL_ENV=development ./node_modules/.bin/gulp build-no-bundle
node ./packages/babel-types/scripts/generateTypeHelpers.js
node scripts/generators/flow.js > ./packages/babel-types/lib/index.js.flow
node packages/babel-types/scripts/generators/flow.js > ./packages/babel-types/lib/index.js.flow
node packages/babel-types/scripts/generators/typescript.js > ./packages/babel-types/lib/index.d.ts
BABEL_ENV=development ./node_modules/.bin/gulp watch
flow:
@@ -102,7 +103,7 @@ test-flow-update-whitelist:
bootstrap-test262:
rm -rf ./build/test262
mkdir -p ./build
git clone --branch=master --single-branch --shallow-since=2018-11-01 https://github.com/tc39/test262.git ./build/test262
git clone --branch=master --single-branch --shallow-since=2010-01-10 https://github.com/tc39/test262.git ./build/test262
cd build/test262 && git checkout $(TEST262_COMMIT)
test-test262:
@@ -130,7 +131,7 @@ prepublish:
make test
publish: prepublish
./node_modules/.bin/lerna publish --force-publish="@babel/runtime,@babel/runtime-corejs2,@babel/standalone,@babel/preset-env-standalone"
./node_modules/.bin/lerna publish --force-publish="@babel/runtime,@babel/runtime-corejs2,@babel/standalone,@babel/preset-env-standalone" --require-scripts
make clean
bootstrap: clean-all

View File

@@ -8,12 +8,16 @@
The compiler for writing next generation JavaScript.
</p>
<p align="center">
<a href="https://www.npmjs.com/package/@babel/core"><img alt="v7 npm Downloads" src="https://img.shields.io/npm/dm/@babel/core.svg?maxAge=43200&label=v7%20downloads"></a>
<a href="https://www.npmjs.com/package/babel-core"><img alt="v6 npm Downloads" src="https://img.shields.io/npm/dm/babel-core.svg?maxAge=43200&label=v6%20downloads"></a>
</p>
<p align="center">
<a href="https://travis-ci.org/babel/babel"><img alt="Travis Status" src="https://img.shields.io/travis/babel/babel/master.svg?label=travis&maxAge=43200"></a>
<a href="https://circleci.com/gh/babel/babel"><img alt="CircleCI Status" src="https://img.shields.io/circleci/project/github/babel/babel/master.svg?label=circle&maxAge=43200"></a>
<a href="https://codecov.io/github/babel/babel"><img alt="Coverage Status" src="https://img.shields.io/codecov/c/github/babel/babel/master.svg?maxAge=43200"></a>
<a href="https://slack.babeljs.io/"><img alt="Slack Status" src="https://slack.babeljs.io/badge.svg"></a>
<a href="https://www.npmjs.com/package/babel-core"><img alt="npm Downloads" src="https://img.shields.io/npm/dm/babel-core.svg?maxAge=43200"></a>
<a href="https://twitter.com/intent/follow?screen_name=babeljs"><img alt="Follow on Twitter" src="https://img.shields.io/twitter/follow/babeljs.svg?style=social&label=Follow"></a>
</p>
<h2 align="center">Supporting Babel</h2>
@@ -55,8 +59,8 @@ Become a sponsor and get your logo on our README on Github with a link to your s
## Bronze
<a href="http://teamextension.io/" target="_blank"><img src="https://teamextension.io/dist/img/logo/te-logo-compact.png" height="64"></a>
<a href="https://webflow.com/" target="_blank"><img src="https://opencollective.com/proxy/images/?src=https%3A%2F%2Fopencollective-production.s3-us-west-1.amazonaws.com%2F4a5024b0-8cf2-11e7-b1a2-b30b1de1463c.png&height=64"></a>
<a href="https://webflow.com" target="_blank"><img src="https://opencollective.com/proxy/images/?src=https%3A%2F%2Fopencollective-production.s3-us-west-1.amazonaws.com%2F4a5024b0-8cf2-11e7-b1a2-b30b1de1463c.png&height=64"></a>
<a href="https://issuehunt.io" target="_blank"><img src="https://github.com/BoostIO/issuehunt-materials/blob/master/v1/issuehunt-logo-and-word-v1.png?raw=true" height="64"></a>
## Intro
@@ -83,7 +87,7 @@ Try it out at our [REPL](https://babeljs.io/repl/build/master#?code_lz=NoRgNATGD
### Who maintains Babel?
Mostly a handful of volunteers! Please check out our [team page](https://babeljs.io/team)!
Mostly a handful of volunteers, funded by you! Please check out our [team page](https://babeljs.io/team)!
### Looking for support?

View File

@@ -14,12 +14,16 @@ module.exports = function(api) {
let convertESM = true;
let ignoreLib = true;
let includeRuntime = false;
const nodeVersion = "6.9";
switch (env) {
// Configs used during bundling builds.
case "babel-parser":
convertESM = false;
ignoreLib = false;
envOpts.targets = {
node: nodeVersion,
};
break;
case "standalone":
convertESM = false;
@@ -29,7 +33,7 @@ module.exports = function(api) {
case "production":
// Config during builds before publish.
envOpts.targets = {
node: "6.9",
node: nodeVersion,
};
break;
case "development":

View File

@@ -1,5 +1,5 @@
{
"version": "7.2.3",
"version": "7.3.2",
"changelog": {
"repo": "babel/babel",
"cacheDir": ".changelog",

View File

@@ -9,55 +9,54 @@
"test": "make test"
},
"devDependencies": {
"@babel/cli": "^7.2.0",
"@babel/core": "^7.2.0",
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/eslint-plugin-development": "^1.0.1",
"@babel/plugin-proposal-class-properties": "^7.2.1",
"@babel/plugin-proposal-class-properties": "^7.3.0",
"@babel/plugin-proposal-export-namespace-from": "^7.2.0",
"@babel/plugin-proposal-numeric-separator": "^7.2.0",
"@babel/plugin-transform-modules-commonjs": "^7.2.0",
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.2.0",
"@babel/preset-env": "^7.3.1",
"@babel/preset-flow": "^7.0.0",
"@babel/register": "^7.0.0",
"@babel/runtime": "^7.2.0",
"babel-core": "^7.0.0-0",
"babel-eslint": "^10.0.1",
"babel-jest": "^23.6.0",
"babel-loader": "^8.0.4",
"babel-plugin-transform-charcodes": "^0.1.1",
"browserify": "^16.2.2",
"@babel/runtime": "^7.3.1",
"babel-eslint": "^11.0.0-beta.0",
"babel-jest": "^24.0.0",
"babel-loader": "^8.0.5",
"babel-plugin-transform-charcodes": "^0.2.0",
"browserify": "^16.2.3",
"bundle-collapser": "^1.2.1",
"chalk": "^2.3.2",
"charcodes": "^0.1.1",
"charcodes": "^0.2.0",
"derequire": "^2.0.2",
"enhanced-resolve": "^3.0.0",
"eslint": "^5.9.0",
"eslint": "^5.12.1",
"eslint-config-babel": "^8.0.2",
"eslint-plugin-flowtype": "^3.2.0",
"eslint-plugin-prettier": "^3.0.0",
"eslint-plugin-flowtype": "^3.2.1",
"eslint-plugin-prettier": "^3.0.1",
"fancy-log": "^1.3.3",
"flow-bin": "^0.87.0",
"graceful-fs": "^4.1.11",
"graceful-fs": "^4.1.15",
"gulp": "^4.0.0",
"gulp-babel": "^8.0.0",
"gulp-filter": "^5.1.0",
"gulp-newer": "^1.0.0",
"gulp-plumber": "^1.2.0",
"gulp-plumber": "^1.2.1",
"gulp-rename": "^1.4.0",
"gulp-uglify": "^3.0.1",
"gulp-util": "^3.0.7",
"gulp-watch": "^5.0.1",
"husky": "^1.2.0",
"jest": "^23.6.0",
"husky": "^1.3.1",
"jest": "^24.0.0",
"lerna": "^3.6.0",
"lerna-changelog": "^0.5.0",
"lint-staged": "^8.1.0",
"lodash": "^4.17.10",
"lodash": "^4.17.11",
"merge-stream": "^1.0.1",
"output-file-sync": "^2.0.0",
"prettier": "^1.15.2",
"prettier": "^1.16.1",
"pump": "^3.0.0",
"rimraf": "^2.4.3",
"rimraf": "^2.6.3",
"rollup-plugin-babel": "^4.0.0-beta.0",
"rollup-plugin-node-resolve": "^3.0.2",
"rollup-stream": "^1.24.1",
@@ -108,7 +107,9 @@
"_browser\\.js"
],
"testEnvironment": "node",
"setupTestFrameworkScriptFile": "<rootDir>/test/testSetupFile.js",
"setupFilesAfterEnv": [
"<rootDir>/test/testSetupFile.js"
],
"transformIgnorePatterns": [
"/node_modules/",
"<rootDir>/packages/babel-standalone/babel(\\.min)?\\.js",
@@ -131,5 +132,6 @@
"moduleNameMapper": {
"^@babel/([a-zA-Z0-9_-]+)$": "<rootDir>/packages/babel-$1/"
}
}
},
"dependencies": {}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/generator",
"version": "7.2.2",
"version": "7.3.2",
"description": "Turns an AST into code.",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
@@ -14,7 +14,7 @@
"lib"
],
"dependencies": {
"@babel/types": "^7.2.2",
"@babel/types": "^7.3.2",
"jsesc": "^2.5.1",
"lodash": "^4.17.10",
"source-map": "^0.5.0",
@@ -22,6 +22,6 @@
},
"devDependencies": {
"@babel/helper-fixtures": "^7.2.0",
"@babel/parser": "^7.2.2"
"@babel/parser": "^7.3.2"
}
}

View File

@@ -476,6 +476,21 @@ export function TSModuleBlock(node) {
this.tsPrintBraced(node.body, node);
}
export function TSImportType(node) {
const { argument, qualifier, typeParameters } = node;
this.word("import");
this.token("(");
this.print(argument, node);
this.token(")");
if (qualifier) {
this.token(".");
this.print(qualifier, node);
}
if (typeParameters) {
this.print(typeParameters, node);
}
}
export function TSImportEqualsDeclaration(node) {
const { isExport, id, moduleReference } = node;
if (isExport) {

View File

@@ -1,3 +1,4 @@
type A = interface { p: string };
type B = interface extends X { p: string };
type C = interface extends X, Y { p: string };
type D = interface extends X.Y<Z> { p: string };

View File

@@ -6,4 +6,7 @@ type B = interface extends X {
};
type C = interface extends X, Y {
p: string
};
};
type D = interface extends X.Y<Z> {
p: string
};

View File

@@ -14,3 +14,5 @@ type overloads =
;
type func = string => string;
type D = X.Y<Z>;

View File

@@ -9,3 +9,4 @@ type union = {
};
type overloads = (x: string) => number & (x: number) => string;
type func = (string) => string;
type D = X.Y<Z>;

View File

@@ -0,0 +1,3 @@
let x: typeof import('./x');
let Y: import('./y').Y;
let z: import("/z").foo.bar<string>;

View File

@@ -0,0 +1,3 @@
let x: typeof import('./x');
let Y: import('./y').Y;
let z: import("/z").foo.bar<string>;

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/helper-builder-react-jsx",
"version": "7.0.0",
"version": "7.3.0",
"description": "Helper function to build react jsx",
"repository": "https://github.com/babel/babel/tree/master/packages/babel-helper-builder-react-jsx",
"license": "MIT",
@@ -9,7 +9,7 @@
},
"main": "lib/index.js",
"dependencies": {
"@babel/types": "^7.0.0",
"@babel/types": "^7.3.0",
"esutils": "^2.0.0"
}
}

View File

@@ -19,6 +19,13 @@ You can turn on the 'throwIfNamespace' flag to bypass this warning.`,
);
}
};
visitor.JSXSpreadChild = function(path) {
throw path.buildCodeFrameError(
"Spread children are not supported in React.",
);
};
visitor.JSXElement = {
exit(path, file) {
const callExpr = buildElementCall(path, file);

View File

@@ -1,19 +1,19 @@
# @babel/plugin-class-features
# @babel/helper-create-class-features-plugin
> Compile class public and private fields, private methods and decorators to ES6
See our website [@babel/plugin-class-features](https://babeljs.io/docs/en/next/babel-plugin-class-features.html) for more information.
See our website [@babel/helper-create-class-features-plugin](https://babeljs.io/docs/en/next/babel-helper-create-class-features-plugin.html) for more information.
## Install
Using npm:
```sh
npm install --save-dev @babel/plugin-class-features
npm install --save-dev @babel/helper-create-class-features-plugin
```
or using yarn:
```sh
yarn add @babel/plugin-class-features --dev
yarn add @babel/helper-create-class-features-plugin --dev
```

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/helper-create-class-features-plugin",
"version": "7.2.3",
"version": "7.3.2",
"author": "The Babel Team (https://babeljs.io/team)",
"license": "MIT",
"description": "Compile class public and private fields, private methods and decorators to ES6",

View File

@@ -1,5 +1,6 @@
import { types as t, template } from "@babel/core";
import ReplaceSupers from "@babel/helper-replace-supers";
import nameFunction from "@babel/helper-function-name";
export function hasOwnDecorators(node) {
return !!(node.decorators && node.decorators.length);
@@ -14,11 +15,13 @@ function prop(key, value) {
return t.objectProperty(t.identifier(key), value);
}
function value(body, params = [], async, generator) {
const method = t.objectMethod("method", t.identifier("value"), params, body);
method.async = !!async;
method.generator = !!generator;
return method;
function method(key, body) {
return t.objectMethod(
"method",
t.identifier(key),
[],
t.blockStatement(body),
);
}
function takeDecorators(node) {
@@ -74,13 +77,20 @@ function extractElementDescriptor(/* this: File, */ classRef, superRef, path) {
prop("decorators", takeDecorators(node)),
prop("static", node.static && t.booleanLiteral(true)),
prop("key", getKey(node)),
isMethod
? value(node.body, node.params, node.async, node.generator)
: node.value
? value(template.ast`{ return ${node.value} }`)
: prop("value", scope.buildUndefinedNode()),
].filter(Boolean);
if (isMethod) {
const id = node.computed ? null : node.key;
t.toExpression(node);
properties.push(prop("value", nameFunction({ node, id, scope }) || node));
} else if (node.value) {
properties.push(
method("value", template.statements.ast`return ${node.value}`),
);
} else {
properties.push(prop("value", scope.buildUndefinedNode()));
}
path.remove();
return t.objectExpression(properties);

View File

@@ -39,9 +39,17 @@ export function isLoose(file, feature) {
}
export function verifyUsedFeatures(path, file) {
if (hasOwnDecorators(path)) {
if (hasOwnDecorators(path.node)) {
if (!hasFeature(file, FEATURES.decorators)) {
throw path.buildCodeFrameError("Decorators are not enabled.");
throw path.buildCodeFrameError(
"Decorators are not enabled." +
"\nIf you are using " +
'["@babel/plugin-proposal-decorators", { "legacy": true }], ' +
'make sure it comes *before* "@babel/plugin-proposal-class-properties" ' +
"and enable loose mode, like so:\n" +
'\t["@babel/plugin-proposal-decorators", { "legacy": true }]\n' +
'\t["@babel/plugin-proposal-class-properties", { "loose": true }]',
);
}
if (path.isPrivate()) {
@@ -64,12 +72,6 @@ export function verifyUsedFeatures(path, file) {
"@babel/plugin-class-features doesn't support class static private methods yet.",
);
}
if (path.node.kind !== "method") {
throw path.buildCodeFrameError(
"@babel/plugin-class-features doesn't support class private accessors yet.",
);
}
}
if (

View File

@@ -6,16 +6,26 @@ import optimiseCall from "@babel/helper-optimise-call-expression";
export function buildPrivateNamesMap(props) {
const privateNamesMap = new Map();
for (const prop of props) {
if (prop.isPrivate()) {
const isPrivate = prop.isPrivate();
const isMethod = !prop.isProperty();
const isInstance = !prop.node.static;
if (isPrivate) {
const { name } = prop.node.key.id;
privateNamesMap.set(name, {
id: prop.scope.generateUidIdentifier(name),
static: !!prop.node.static,
method: prop.isMethod(),
methodId: prop.isMethod()
? prop.scope.generateUidIdentifier(name)
: undefined,
});
const update = privateNamesMap.has(name)
? privateNamesMap.get(name)
: {
id: prop.scope.generateUidIdentifier(name),
static: !isInstance,
method: isMethod,
};
if (prop.node.kind === "get") {
update.getId = prop.scope.generateUidIdentifier(`get_${name}`);
} else if (prop.node.kind === "set") {
update.setId = prop.scope.generateUidIdentifier(`set_${name}`);
} else if (prop.node.kind === "method" && isMethod && isInstance) {
update.methodId = prop.scope.generateUidIdentifier(name);
}
privateNamesMap.set(name, update);
}
}
return privateNamesMap;
@@ -31,7 +41,7 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
// In spec mode, only instance fields need a "private name" initializer
// because static fields are directly assigned to a variable in the
// buildPrivateStaticFieldInitSpec function.
const { id, static: isStatic, method: isMethod } = value;
const { id, static: isStatic, method: isMethod, getId, setId } = value;
if (loose) {
initNodes.push(
template.statement.ast`
@@ -39,7 +49,11 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
`,
);
} else if (isMethod && !isStatic) {
initNodes.push(template.statement.ast`var ${id} = new WeakSet();`);
if (getId || setId) {
initNodes.push(template.statement.ast`var ${id} = new WeakMap();`);
} else {
initNodes.push(template.statement.ast`var ${id} = new WeakSet();`);
}
} else if (!isStatic) {
initNodes.push(template.statement.ast`var ${id} = new WeakMap();`);
}
@@ -121,6 +135,8 @@ const privateNameHandlerSpec = {
static: isStatic,
method: isMethod,
methodId,
getId,
setId,
} = privateNamesMap.get(name);
if (isStatic && !isMethod) {
@@ -128,41 +144,57 @@ const privateNameHandlerSpec = {
file.addHelper("classStaticPrivateFieldSpecGet"),
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id)],
);
} else if (isMethod) {
}
if (isMethod) {
if (getId || setId) {
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
this.receiver(member),
t.cloneNode(id),
]);
}
return t.callExpression(file.addHelper("classPrivateMethodGet"), [
this.receiver(member),
t.cloneNode(id),
t.cloneNode(methodId),
]);
} else {
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
this.receiver(member),
t.cloneNode(id),
]);
}
return t.callExpression(file.addHelper("classPrivateFieldGet"), [
this.receiver(member),
t.cloneNode(id),
]);
},
set(member, value) {
const { classRef, privateNamesMap, file } = this;
const { name } = member.node.property.id;
const { id, static: isStatic, method: isMethod } = privateNamesMap.get(
name,
);
const {
id,
static: isStatic,
method: isMethod,
setId,
} = privateNamesMap.get(name);
if (isStatic && !isMethod) {
return t.callExpression(
file.addHelper("classStaticPrivateFieldSpecSet"),
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id), value],
);
} else if (isMethod) {
return t.callExpression(file.addHelper("classPrivateMethodSet"), []);
} else {
return t.callExpression(file.addHelper("classPrivateFieldSet"), [
this.receiver(member),
t.cloneNode(id),
value,
]);
}
if (isMethod) {
if (setId) {
return t.callExpression(file.addHelper("classPrivateFieldSet"), [
this.receiver(member),
t.cloneNode(id),
value,
]);
}
return t.callExpression(file.addHelper("classPrivateMethodSet"), []);
}
return t.callExpression(file.addHelper("classPrivateFieldSet"), [
this.receiver(member),
t.cloneNode(id),
value,
]);
},
call(member, args) {
@@ -255,21 +287,91 @@ function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) {
}
function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) {
const { methodId, id } = privateNamesMap.get(prop.node.key.id.name);
const privateName = privateNamesMap.get(prop.node.key.id.name);
const { methodId, id, getId, setId, initAdded } = privateName;
if (initAdded) return;
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
value: ${methodId.name}
if (methodId) {
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
value: ${methodId.name}
});
`;
}
if (getId || setId) {
privateNamesMap.set(prop.node.key.id.name, {
...privateName,
initAdded: true,
});
`;
if (getId && setId) {
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId.name},
set: ${setId.name}
});
`;
} else if (getId && !setId) {
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
get: ${getId.name}
});
`;
} else if (!getId && setId) {
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
// writable is false by default
set: ${setId.name}
});
`;
}
}
}
function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) {
const { id } = privateNamesMap.get(prop.node.key.id.name);
const privateName = privateNamesMap.get(prop.node.key.id.name);
const { id, getId, setId, initAdded } = privateName;
if (initAdded) return;
if (getId || setId) {
privateNamesMap.set(prop.node.key.id.name, {
...privateName,
initAdded: true,
});
if (getId && setId) {
return template.statement.ast`
${id}.set(${ref}, {
get: ${getId.name},
set: ${setId.name}
});
`;
} else if (getId && !setId) {
return template.statement.ast`
${id}.set(${ref}, {
get: ${getId.name}
});
`;
} else if (!getId && setId) {
return template.statement.ast`
${id}.set(${ref}, {
set: ${setId.name}
});
`;
}
}
return template.statement.ast`${id}.add(${ref})`;
}
@@ -300,9 +402,43 @@ function buildPublicFieldInitSpec(ref, prop, state) {
}
function buildPrivateInstanceMethodDeclaration(prop, privateNamesMap) {
const { methodId } = privateNamesMap.get(prop.node.key.id.name);
const { params, body } = prop.node;
const methodValue = t.functionExpression(methodId, params, body);
const privateName = privateNamesMap.get(prop.node.key.id.name);
const {
methodId,
getId,
setId,
getterDeclared,
setterDeclared,
} = privateName;
const { params, body, generator, async } = prop.node;
const methodValue = t.functionExpression(
methodId,
params,
body,
generator,
async,
);
const isGetter = getId && !getterDeclared && params.length === 0;
const isSetter = setId && !setterDeclared && params.length > 0;
if (isGetter) {
privateNamesMap.set(prop.node.key.id.name, {
...privateName,
getterDeclared: true,
});
return t.variableDeclaration("var", [
t.variableDeclarator(getId, methodValue),
]);
}
if (isSetter) {
privateNamesMap.set(prop.node.key.id.name, {
...privateName,
setterDeclared: true,
});
return t.variableDeclaration("var", [
t.variableDeclarator(setId, methodValue),
]);
}
return t.variableDeclaration("var", [
t.variableDeclarator(methodId, methodValue),
@@ -366,7 +502,7 @@ export function buildFieldsInitNodes(
);
break;
case isInstance && isPrivate && isMethod && loose:
instanceNodes.push(
instanceNodes.unshift(
buildPrivateMethodInitLoose(
t.thisExpression(),
prop,
@@ -378,7 +514,7 @@ export function buildFieldsInitNodes(
);
break;
case isInstance && isPrivate && isMethod && !loose:
instanceNodes.push(
instanceNodes.unshift(
buildPrivateInstanceMethodInitSpec(
t.thisExpression(),
prop,
@@ -404,7 +540,7 @@ export function buildFieldsInitNodes(
return {
staticNodes,
instanceNodes,
instanceNodes: instanceNodes.filter(Boolean),
wrapClass(path) {
for (const prop of props) {
prop.remove();

View File

@@ -75,11 +75,39 @@ export function createClassFeaturePlugin({
if (path.isPrivate()) {
const { name } = path.node.key.id;
const getName = `get ${name}`;
const setName = `set ${name}`;
if (privateNames.has(name)) {
throw path.buildCodeFrameError("Duplicate private field");
if (path.node.kind === "get") {
if (
privateNames.has(getName) ||
(privateNames.has(name) && !privateNames.has(setName))
) {
throw path.buildCodeFrameError("Duplicate private field");
}
privateNames.add(getName).add(name);
} else if (path.node.kind === "set") {
if (
privateNames.has(setName) ||
(privateNames.has(name) && !privateNames.has(getName))
) {
throw path.buildCodeFrameError("Duplicate private field");
}
privateNames.add(setName).add(name);
} else {
if (
(privateNames.has(name) &&
(!privateNames.has(getName) && !privateNames.has(setName))) ||
(privateNames.has(name) &&
(privateNames.has(getName) || privateNames.has(setName)))
) {
throw path.buildCodeFrameError("Duplicate private field");
}
privateNames.add(name);
}
privateNames.add(name);
}
if (path.isClassMethod({ kind: "constructor" })) {

View File

@@ -1,8 +1,4 @@
{
"presets": [
"flow"
],
"plugins": [
"proposal-class-properties"
]
"presets": ["flow"],
"plugins": ["proposal-class-properties"]
}

View File

@@ -1,8 +1,4 @@
{
"presets": [
"flow"
],
"plugins": [
"proposal-class-properties"
]
"presets": ["flow"],
"plugins": ["proposal-class-properties"]
}

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/helpers",
"version": "7.2.0",
"version": "7.3.1",
"description": "Collection of helper functions used by Babel transforms.",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
@@ -13,7 +13,7 @@
"dependencies": {
"@babel/template": "^7.1.2",
"@babel/traverse": "^7.1.5",
"@babel/types": "^7.2.0"
"@babel/types": "^7.3.0"
},
"devDependencies": {
"@babel/helper-plugin-test-runner": "^7.0.0"

View File

@@ -1048,7 +1048,11 @@ helpers.classPrivateFieldGet = helper("7.0.0-beta.0")`
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return privateMap.get(receiver).value;
var descriptor = privateMap.get(receiver);
if (descriptor.get) {
return descriptor.get.call(receiver);
}
return descriptor.value;
}
`;
@@ -1058,13 +1062,19 @@ helpers.classPrivateFieldSet = helper("7.0.0-beta.0")`
throw new TypeError("attempted to set private field on non-instance");
}
var descriptor = privateMap.get(receiver);
if (!descriptor.writable) {
// This should only throw in strict mode, but class bodies are
// always strict and private fields can only be used inside
// class bodies.
throw new TypeError("attempted to set read only private field");
if (descriptor.set) {
descriptor.set.call(receiver, value);
} else {
if (!descriptor.writable) {
// This should only throw in strict mode, but class bodies are
// always strict and private fields can only be used inside
// class bodies.
throw new TypeError("attempted to set read only private field");
}
descriptor.value = value;
}
descriptor.value = value;
return value;
}
`;
@@ -1213,23 +1223,430 @@ helpers.decorate = helper("7.1.5")`
*/
/*::
type Placements = {
static: Key[],
prototype: Key[],
own: Key[],
};
*/
// ClassDefinitionEvaluation (Steps 26-*)
export default function _decorate(
decorators /*: ClassDecorator[] */,
factory /*: ClassFactory */,
superClass /*: ?Class<*> */,
mixins /*: ?Array<Function> */,
) /*: Class<*> */ {
var api = _getDecoratorsApi();
if (mixins) {
for (var i = 0; i < mixins.length; i++) {
api = mixins[i](api);
}
}
var r = factory(function initialize(O) {
_initializeInstanceElements(O, decorated.elements);
api.initializeInstanceElements(O, decorated.elements);
}, superClass);
var decorated = _decorateClass(
var decorated = api.decorateClass(
_coalesceClassElements(r.d.map(_createElementDescriptor)),
decorators,
);
_initializeClassElements(r.F, decorated.elements);
api.initializeClassElements(r.F, decorated.elements);
return _runClassFinishers(r.F, decorated.finishers);
return api.runClassFinishers(r.F, decorated.finishers);
}
function _getDecoratorsApi() {
_getDecoratorsApi = function() {
return api;
};
var api = {
elementsDefinitionOrder: [["method"], ["field"]],
// InitializeInstanceElements
initializeInstanceElements: function(
/*::<C>*/ O /*: C */,
elements /*: ElementDescriptor[] */,
) {
["method", "field"].forEach(function(kind) {
elements.forEach(function(element /*: ElementDescriptor */) {
if (element.kind === kind && element.placement === "own") {
this.defineClassElement(O, element);
}
}, this);
}, this);
},
// InitializeClassElements
initializeClassElements: function(
/*::<C>*/ F /*: Class<C> */,
elements /*: ElementDescriptor[] */,
) {
var proto = F.prototype;
["method", "field"].forEach(function(kind) {
elements.forEach(function(element /*: ElementDescriptor */) {
var placement = element.placement;
if (
element.kind === kind &&
(placement === "static" || placement === "prototype")
) {
var receiver = placement === "static" ? F : proto;
this.defineClassElement(receiver, element);
}
}, this);
}, this);
},
// DefineClassElement
defineClassElement: function(
/*::<C>*/ receiver /*: C | Class<C> */,
element /*: ElementDescriptor */,
) {
var descriptor /*: PropertyDescriptor */ = element.descriptor;
if (element.kind === "field") {
var initializer = element.initializer;
descriptor = {
enumerable: descriptor.enumerable,
writable: descriptor.writable,
configurable: descriptor.configurable,
value: initializer === void 0 ? void 0 : initializer.call(receiver),
};
}
Object.defineProperty(receiver, element.key, descriptor);
},
// DecorateClass
decorateClass: function(
elements /*: ElementDescriptor[] */,
decorators /*: ClassDecorator[] */,
) /*: ElementsFinishers */ {
var newElements /*: ElementDescriptor[] */ = [];
var finishers /*: ClassFinisher[] */ = [];
var placements /*: Placements */ = {
static: [],
prototype: [],
own: [],
};
elements.forEach(function(element /*: ElementDescriptor */) {
this.addElementPlacement(element, placements);
}, this);
elements.forEach(function(element /*: ElementDescriptor */) {
if (!_hasDecorators(element)) return newElements.push(element);
var elementFinishersExtras /*: ElementFinishersExtras */ = this.decorateElement(
element,
placements,
);
newElements.push(elementFinishersExtras.element);
newElements.push.apply(newElements, elementFinishersExtras.extras);
finishers.push.apply(finishers, elementFinishersExtras.finishers);
}, this);
if (!decorators) {
return { elements: newElements, finishers: finishers };
}
var result /*: ElementsFinishers */ = this.decorateConstructor(
newElements,
decorators,
);
finishers.push.apply(finishers, result.finishers);
result.finishers = finishers;
return result;
},
// AddElementPlacement
addElementPlacement: function(
element /*: ElementDescriptor */,
placements /*: Placements */,
silent /*: boolean */,
) {
var keys = placements[element.placement];
if (!silent && keys.indexOf(element.key) !== -1) {
throw new TypeError("Duplicated element (" + element.key + ")");
}
keys.push(element.key);
},
// DecorateElement
decorateElement: function(
element /*: ElementDescriptor */,
placements /*: Placements */,
) /*: ElementFinishersExtras */ {
var extras /*: ElementDescriptor[] */ = [];
var finishers /*: ClassFinisher[] */ = [];
for (
var decorators = element.decorators, i = decorators.length - 1;
i >= 0;
i--
) {
// (inlined) RemoveElementPlacement
var keys = placements[element.placement];
keys.splice(keys.indexOf(element.key), 1);
var elementObject /*: ElementObjectInput */ = this.fromElementDescriptor(
element,
);
var elementFinisherExtras /*: ElementFinisherExtras */ = this.toElementFinisherExtras(
(0, decorators[i])(elementObject) /*: ElementObjectOutput */ ||
elementObject,
);
element = elementFinisherExtras.element;
this.addElementPlacement(element, placements);
if (elementFinisherExtras.finisher) {
finishers.push(elementFinisherExtras.finisher);
}
var newExtras /*: ElementDescriptor[] | void */ =
elementFinisherExtras.extras;
if (newExtras) {
for (var j = 0; j < newExtras.length; j++) {
this.addElementPlacement(newExtras[j], placements);
}
extras.push.apply(extras, newExtras);
}
}
return { element: element, finishers: finishers, extras: extras };
},
// DecorateConstructor
decorateConstructor: function(
elements /*: ElementDescriptor[] */,
decorators /*: ClassDecorator[] */,
) /*: ElementsFinishers */ {
var finishers /*: ClassFinisher[] */ = [];
for (var i = decorators.length - 1; i >= 0; i--) {
var obj /*: ClassObject */ = this.fromClassDescriptor(elements);
var elementsAndFinisher /*: ElementsFinisher */ = this.toClassDescriptor(
(0, decorators[i])(obj) /*: ClassObject */ || obj,
);
if (elementsAndFinisher.finisher !== undefined) {
finishers.push(elementsAndFinisher.finisher);
}
if (elementsAndFinisher.elements !== undefined) {
elements = elementsAndFinisher.elements;
for (var j = 0; j < elements.length - 1; j++) {
for (var k = j + 1; k < elements.length; k++) {
if (
elements[j].key === elements[k].key &&
elements[j].placement === elements[k].placement
) {
throw new TypeError(
"Duplicated element (" + elements[j].key + ")",
);
}
}
}
}
}
return { elements: elements, finishers: finishers };
},
// FromElementDescriptor
fromElementDescriptor: function(
element /*: ElementDescriptor */,
) /*: ElementObject */ {
var obj /*: ElementObject */ = {
kind: element.kind,
key: element.key,
placement: element.placement,
descriptor: element.descriptor,
};
var desc = {
value: "Descriptor",
configurable: true,
};
Object.defineProperty(obj, Symbol.toStringTag, desc);
if (element.kind === "field") obj.initializer = element.initializer;
return obj;
},
// ToElementDescriptors
toElementDescriptors: function(
elementObjects /*: ElementObject[] */,
) /*: ElementDescriptor[] */ {
if (elementObjects === undefined) return;
return toArray(elementObjects).map(function(elementObject) {
var element = this.toElementDescriptor(elementObject);
this.disallowProperty(elementObject, "finisher", "An element descriptor");
this.disallowProperty(elementObject, "extras", "An element descriptor");
return element;
}, this);
},
// ToElementDescriptor
toElementDescriptor: function(
elementObject /*: ElementObject */,
) /*: ElementDescriptor */ {
var kind = String(elementObject.kind);
if (kind !== "method" && kind !== "field") {
throw new TypeError(
'An element descriptor\\'s .kind property must be either "method" or' +
' "field", but a decorator created an element descriptor with' +
' .kind "' +
kind +
'"',
);
}
var key = toPropertyKey(elementObject.key);
var placement = String(elementObject.placement);
if (
placement !== "static" &&
placement !== "prototype" &&
placement !== "own"
) {
throw new TypeError(
'An element descriptor\\'s .placement property must be one of "static",' +
' "prototype" or "own", but a decorator created an element descriptor' +
' with .placement "' +
placement +
'"',
);
}
var descriptor /*: PropertyDescriptor */ = elementObject.descriptor;
this.disallowProperty(elementObject, "elements", "An element descriptor");
var element /*: ElementDescriptor */ = {
kind: kind,
key: key,
placement: placement,
descriptor: Object.assign({}, descriptor),
};
if (kind !== "field") {
this.disallowProperty(elementObject, "initializer", "A method descriptor");
} else {
this.disallowProperty(
descriptor,
"get",
"The property descriptor of a field descriptor",
);
this.disallowProperty(
descriptor,
"set",
"The property descriptor of a field descriptor",
);
this.disallowProperty(
descriptor,
"value",
"The property descriptor of a field descriptor",
);
element.initializer = elementObject.initializer;
}
return element;
},
toElementFinisherExtras: function(
elementObject /*: ElementObject */,
) /*: ElementFinisherExtras */ {
var element /*: ElementDescriptor */ = this.toElementDescriptor(
elementObject,
);
var finisher /*: ClassFinisher */ = _optionalCallableProperty(
elementObject,
"finisher",
);
var extras /*: ElementDescriptors[] */ = this.toElementDescriptors(
elementObject.extras,
);
return { element: element, finisher: finisher, extras: extras };
},
// FromClassDescriptor
fromClassDescriptor: function(
elements /*: ElementDescriptor[] */,
) /*: ClassObject */ {
var obj = {
kind: "class",
elements: elements.map(this.fromElementDescriptor, this),
};
var desc = { value: "Descriptor", configurable: true };
Object.defineProperty(obj, Symbol.toStringTag, desc);
return obj;
},
// ToClassDescriptor
toClassDescriptor: function(
obj /*: ClassObject */,
) /*: ElementsFinisher */ {
var kind = String(obj.kind);
if (kind !== "class") {
throw new TypeError(
'A class descriptor\\'s .kind property must be "class", but a decorator' +
' created a class descriptor with .kind "' +
kind +
'"',
);
}
this.disallowProperty(obj, "key", "A class descriptor");
this.disallowProperty(obj, "placement", "A class descriptor");
this.disallowProperty(obj, "descriptor", "A class descriptor");
this.disallowProperty(obj, "initializer", "A class descriptor");
this.disallowProperty(obj, "extras", "A class descriptor");
var finisher = _optionalCallableProperty(obj, "finisher");
var elements = this.toElementDescriptors(obj.elements);
return { elements: elements, finisher: finisher };
},
// RunClassFinishers
runClassFinishers: function(
constructor /*: Class<*> */,
finishers /*: ClassFinisher[] */,
) /*: Class<*> */ {
for (var i = 0; i < finishers.length; i++) {
var newConstructor /*: ?Class<*> */ = (0, finishers[i])(constructor);
if (newConstructor !== undefined) {
// NOTE: This should check if IsConstructor(newConstructor) is false.
if (typeof newConstructor !== "function") {
throw new TypeError("Finishers must return a constructor.");
}
constructor = newConstructor;
}
}
return constructor;
},
disallowProperty: function(obj, name, objectType) {
if (obj[name] !== undefined) {
throw new TypeError(objectType + " can't have a ." + name + " property.");
}
}
};
return api;
}
// ClassElementEvaluation
@@ -1246,10 +1663,6 @@ helpers.decorate = helper("7.1.5")`
configurable: true,
enumerable: false,
};
Object.defineProperty(def.value, "name", {
value: typeof key === "symbol" ? "" : key,
configurable: true,
});
} else if (def.kind === "get") {
descriptor = { get: def.value, configurable: true, enumerable: false };
} else if (def.kind === "set") {
@@ -1264,8 +1677,8 @@ helpers.decorate = helper("7.1.5")`
placement: def.static
? "static"
: def.kind === "field"
? "own"
: "prototype",
? "own"
: "prototype",
descriptor: descriptor,
};
if (def.decorators) element.decorators = def.decorators;
@@ -1292,7 +1705,9 @@ helpers.decorate = helper("7.1.5")`
) /*: ElementDescriptor[] */ {
var newElements /*: ElementDescriptor[] */ = [];
var isSameElement = function(other /*: ElementDescriptor */) /*: boolean */ {
var isSameElement = function(
other /*: ElementDescriptor */,
) /*: boolean */ {
return (
other.kind === "method" &&
other.key === element.key &&
@@ -1351,365 +1766,6 @@ helpers.decorate = helper("7.1.5")`
);
}
// InitializeClassElements
function _initializeClassElements /*::<C>*/(
F /*: Class<C> */,
elements /*: ElementDescriptor[] */,
) {
var proto = F.prototype;
["method", "field"].forEach(function(kind) {
elements.forEach(function(element /*: ElementDescriptor */) {
var placement = element.placement;
if (
element.kind === kind &&
(placement === "static" || placement === "prototype")
) {
var receiver = placement === "static" ? F : proto;
_defineClassElement(receiver, element);
}
});
});
}
// InitializeInstanceElements
function _initializeInstanceElements /*::<C>*/(
O /*: C */,
elements /*: ElementDescriptor[] */,
) {
["method", "field"].forEach(function(kind) {
elements.forEach(function(element /*: ElementDescriptor */) {
if (element.kind === kind && element.placement === "own") {
_defineClassElement(O, element);
}
});
});
}
// DefineClassElement
function _defineClassElement /*::<C>*/(
receiver /*: C | Class<C> */,
element /*: ElementDescriptor */,
) {
var descriptor /*: PropertyDescriptor */ = element.descriptor;
if (element.kind === "field") {
var initializer = element.initializer;
descriptor = {
enumerable: descriptor.enumerable,
writable: descriptor.writable,
configurable: descriptor.configurable,
value: initializer === void 0 ? void 0 : initializer.call(receiver),
};
}
Object.defineProperty(receiver, element.key, descriptor);
}
/*::
type Placements = {
static: Key[],
prototype: Key[],
own: Key[],
};
*/
// DecorateClass
function _decorateClass(
elements /*: ElementDescriptor[] */,
decorators /*: ClassDecorator[] */,
) /*: ElementsFinishers */ {
var newElements /*: ElementDescriptor[] */ = [];
var finishers /*: ClassFinisher[] */ = [];
var placements /*: Placements */ = { static: [], prototype: [], own: [] };
elements.forEach(function(element /*: ElementDescriptor */) {
_addElementPlacement(element, placements);
});
elements.forEach(function(element /*: ElementDescriptor */) {
if (!_hasDecorators(element)) return newElements.push(element);
var elementFinishersExtras /*: ElementFinishersExtras */ = _decorateElement(
element,
placements,
);
newElements.push(elementFinishersExtras.element);
newElements.push.apply(newElements, elementFinishersExtras.extras);
finishers.push.apply(finishers, elementFinishersExtras.finishers);
});
if (!decorators) {
return { elements: newElements, finishers: finishers };
}
var result /*: ElementsFinishers */ = _decorateConstructor(
newElements,
decorators,
);
finishers.push.apply(finishers, result.finishers);
result.finishers = finishers;
return result;
}
// AddElementPlacement
function _addElementPlacement(
element /*: ElementDescriptor */,
placements /*: Placements */,
silent /*: boolean */,
) {
var keys = placements[element.placement];
if (!silent && keys.indexOf(element.key) !== -1) {
throw new TypeError("Duplicated element (" + element.key + ")");
}
keys.push(element.key);
}
// DecorateElement
function _decorateElement(
element /*: ElementDescriptor */,
placements /*: Placements */,
) /*: ElementFinishersExtras */ {
var extras /*: ElementDescriptor[] */ = [];
var finishers /*: ClassFinisher[] */ = [];
for (
var decorators = element.decorators, i = decorators.length - 1;
i >= 0;
i--
) {
// (inlined) RemoveElementPlacement
var keys = placements[element.placement];
keys.splice(keys.indexOf(element.key), 1);
var elementObject /*: ElementObjectInput */ = _fromElementDescriptor(
element,
);
var elementFinisherExtras /*: ElementFinisherExtras */ = _toElementFinisherExtras(
(0, decorators[i])(elementObject) /*: ElementObjectOutput */ ||
elementObject,
);
element = elementFinisherExtras.element;
_addElementPlacement(element, placements);
if (elementFinisherExtras.finisher) {
finishers.push(elementFinisherExtras.finisher);
}
var newExtras /*: ElementDescriptor[] | void */ =
elementFinisherExtras.extras;
if (newExtras) {
for (var j = 0; j < newExtras.length; j++) {
_addElementPlacement(newExtras[j], placements);
}
extras.push.apply(extras, newExtras);
}
}
return { element: element, finishers: finishers, extras: extras };
}
// DecorateConstructor
function _decorateConstructor(
elements /*: ElementDescriptor[] */,
decorators /*: ClassDecorator[] */,
) /*: ElementsFinishers */ {
var finishers /*: ClassFinisher[] */ = [];
for (var i = decorators.length - 1; i >= 0; i--) {
var obj /*: ClassObject */ = _fromClassDescriptor(elements);
var elementsAndFinisher /*: ElementsFinisher */ = _toClassDescriptor(
(0, decorators[i])(obj) /*: ClassObject */ || obj,
);
if (elementsAndFinisher.finisher !== undefined) {
finishers.push(elementsAndFinisher.finisher);
}
if (elementsAndFinisher.elements !== undefined) {
elements = elementsAndFinisher.elements;
for (var j = 0; j < elements.length - 1; j++) {
for (var k = j + 1; k < elements.length; k++) {
if (
elements[j].key === elements[k].key &&
elements[j].placement === elements[k].placement
) {
throw new TypeError("Duplicated element (" + elements[j].key + ")");
}
}
}
}
}
return { elements: elements, finishers: finishers };
}
// FromElementDescriptor
function _fromElementDescriptor(
element /*: ElementDescriptor */,
) /*: ElementObject */ {
var obj /*: ElementObject */ = {
kind: element.kind,
key: element.key,
placement: element.placement,
descriptor: element.descriptor,
};
var desc = {
value: "Descriptor",
configurable: true,
};
Object.defineProperty(obj, Symbol.toStringTag, desc);
if (element.kind === "field") obj.initializer = element.initializer;
return obj;
}
// ToElementDescriptors
function _toElementDescriptors(
elementObjects /*: ElementObject[] */,
) /*: ElementDescriptor[] */ {
if (elementObjects === undefined) return;
return toArray(elementObjects).map(function(elementObject) {
var element = _toElementDescriptor(elementObject);
_disallowProperty(elementObject, "finisher", "An element descriptor");
_disallowProperty(elementObject, "extras", "An element descriptor");
return element;
});
}
// ToElementDescriptor
function _toElementDescriptor(
elementObject /*: ElementObject */,
) /*: ElementDescriptor */ {
var kind = String(elementObject.kind);
if (kind !== "method" && kind !== "field") {
throw new TypeError(
'An element descriptor\\'s .kind property must be either "method" or' +
' "field", but a decorator created an element descriptor with' +
' .kind "' +
kind +
'"',
);
}
var key = toPropertyKey(elementObject.key);
var placement = String(elementObject.placement);
if (
placement !== "static" &&
placement !== "prototype" &&
placement !== "own"
) {
throw new TypeError(
'An element descriptor\\'s .placement property must be one of "static",' +
' "prototype" or "own", but a decorator created an element descriptor' +
' with .placement "' +
placement +
'"',
);
}
var descriptor /*: PropertyDescriptor */ = elementObject.descriptor;
_disallowProperty(elementObject, "elements", "An element descriptor");
var element /*: ElementDescriptor */ = {
kind: kind,
key: key,
placement: placement,
descriptor: Object.assign({}, descriptor),
};
if (kind !== "field") {
_disallowProperty(elementObject, "initializer", "A method descriptor");
} else {
_disallowProperty(
descriptor,
"get",
"The property descriptor of a field descriptor",
);
_disallowProperty(
descriptor,
"set",
"The property descriptor of a field descriptor",
);
_disallowProperty(
descriptor,
"value",
"The property descriptor of a field descriptor",
);
element.initializer = elementObject.initializer;
}
return element;
}
function _toElementFinisherExtras(
elementObject /*: ElementObject */,
) /*: ElementFinisherExtras */ {
var element /*: ElementDescriptor */ = _toElementDescriptor(elementObject);
var finisher /*: ClassFinisher */ = _optionalCallableProperty(
elementObject,
"finisher",
);
var extras /*: ElementDescriptors[] */ = _toElementDescriptors(
elementObject.extras,
);
return { element: element, finisher: finisher, extras: extras };
}
// FromClassDescriptor
function _fromClassDescriptor(
elements /*: ElementDescriptor[] */,
) /*: ClassObject */ {
var obj = {
kind: "class",
elements: elements.map(_fromElementDescriptor),
};
var desc = { value: "Descriptor", configurable: true };
Object.defineProperty(obj, Symbol.toStringTag, desc);
return obj;
}
// ToClassDescriptor
function _toClassDescriptor(obj /*: ClassObject */) /*: ElementsFinisher */ {
var kind = String(obj.kind);
if (kind !== "class") {
throw new TypeError(
'A class descriptor\\'s .kind property must be "class", but a decorator' +
' created a class descriptor with .kind "' +
kind +
'"',
);
}
_disallowProperty(obj, "key", "A class descriptor");
_disallowProperty(obj, "placement", "A class descriptor");
_disallowProperty(obj, "descriptor", "A class descriptor");
_disallowProperty(obj, "initializer", "A class descriptor");
_disallowProperty(obj, "extras", "A class descriptor");
var finisher = _optionalCallableProperty(obj, "finisher");
var elements = _toElementDescriptors(obj.elements);
return { elements: elements, finisher: finisher };
}
function _disallowProperty(obj, name, objectType) {
if (obj[name] !== undefined) {
throw new TypeError(objectType + " can't have a ." + name + " property.");
}
}
function _optionalCallableProperty /*::<T>*/(
obj /*: T */,
name /*: $Keys<T> */,
@@ -1721,23 +1777,6 @@ helpers.decorate = helper("7.1.5")`
return value;
}
// RunClassFinishers
function _runClassFinishers(
constructor /*: Class<*> */,
finishers /*: ClassFinisher[] */,
) /*: Class<*> */ {
for (var i = 0; i < finishers.length; i++) {
var newConstructor /*: ?Class<*> */ = (0, finishers[i])(constructor);
if (newConstructor !== undefined) {
// NOTE: This should check if IsConstructor(newConstructor) is false.
if (typeof newConstructor !== "function") {
throw new TypeError("Finishers must return a constructor.");
}
constructor = newConstructor;
}
}
return constructor;
}
`;
helpers.classPrivateMethodGet = helper("7.1.6")`
@@ -1754,3 +1793,75 @@ helpers.classPrivateMethodSet = helper("7.1.6")`
throw new TypeError("attempted to reassign private method");
}
`;
helpers.wrapRegExp = helper("7.2.6")`
import wrapNativeSuper from "wrapNativeSuper";
import getPrototypeOf from "getPrototypeOf";
import possibleConstructorReturn from "possibleConstructorReturn";
import inherits from "inherits";
export default function _wrapRegExp(re, groups) {
_wrapRegExp = function(re, groups) {
return new BabelRegExp(re, groups);
};
var _RegExp = wrapNativeSuper(RegExp);
var _super = RegExp.prototype;
var _groups = new WeakMap();
function BabelRegExp(re, groups) {
var _this = _RegExp.call(this, re);
_groups.set(_this, groups);
return _this;
}
inherits(BabelRegExp, _RegExp);
BabelRegExp.prototype.exec = function(str) {
var result = _super.exec.call(this, str);
if (result) result.groups = buildGroups(result, this);
return result;
};
BabelRegExp.prototype[Symbol.replace] = function(str, substitution) {
if (typeof substitution === "string") {
var groups = _groups.get(this);
return _super[Symbol.replace].call(
this,
str,
substitution.replace(/\\$<([^>]+)>/g, function(_, name) {
return "$" + groups[name];
})
);
} else if (typeof substitution === "function") {
var _this = this;
return _super[Symbol.replace].call(
this,
str,
function() {
var args = [];
args.push.apply(args, arguments);
if (typeof args[args.length - 1] !== "object") {
// Modern engines already pass result.groups as the last arg.
args.push(buildGroups(args, _this));
}
return substitution.apply(this, args);
}
);
} else {
return _super[Symbol.replace].call(this, str, substitution);
}
}
function buildGroups(result, re) {
// NOTE: This function should return undefined if there are no groups,
// but in that case Babel doesn't add the wrapper anyway.
var g = _groups.get(re);
return Object.keys(groups).reduce(function(groups, name) {
groups[name] = result[g[name]];
return groups;
}, Object.create(null));
}
return _wrapRegExp.apply(this, arguments);
}
`;

View File

@@ -2,7 +2,7 @@
> A JavaScript parser
See our website [@babel/parser](https://babeljs.io/docs/en/next/babel-parser.html) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A%20babylon%22+is%3Aopen) associated with this package.
See our website [@babel/parser](https://babeljs.io/docs/en/next/babel-parser.html) for more information or the [issues](https://github.com/babel/babel/issues?utf8=%E2%9C%93&q=is%3Aissue+label%3A%22pkg%3A+parser+%28babylon%29%22+is%3Aopen) associated with this package.
## Install

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/parser",
"version": "7.2.3",
"version": "7.3.2",
"description": "A JavaScript parser",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
@@ -30,7 +30,7 @@
"devDependencies": {
"@babel/helper-fixtures": "^7.2.0",
"charcodes": "0.1.0",
"unicode-11.0.0": "^0.7.7"
"unicode-11.0.0": "^0.7.8"
},
"bin": {
"parser": "./bin/babel-parser.js"

View File

@@ -60,11 +60,15 @@ function generate(chars) {
const startData = generate(start);
const contData = generate(cont);
console.log("/* prettier-ignore */");
console.log('let nonASCIIidentifierStartChars = "' + startData.nonASCII + '";');
console.log("/* prettier-ignore */");
console.log('let nonASCIIidentifierChars = "' + contData.nonASCII + '";');
console.log("/* prettier-ignore */");
console.log(
"const astralIdentifierStartCodes = " + JSON.stringify(startData.astral) + ";"
);
console.log("/* prettier-ignore */");
console.log(
"const astralIdentifierCodes = " + JSON.stringify(contData.astral) + ";"
);

View File

@@ -1,8 +1,6 @@
// @flow
import type { Options } from "../options";
import { reservedWords } from "../util/identifier";
import type State from "../tokenizer/state";
import type { PluginsMap } from "./index";
@@ -16,21 +14,13 @@ export default class BaseParser {
// 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 Object.hasOwnProperty.call(this.plugins, name);
return this.plugins.has(name);
}
getPluginOption(plugin: string, name: string) {
if (this.hasPlugin(plugin)) return this.plugins[plugin][name];
// $FlowIssue
if (this.hasPlugin(plugin)) return this.plugins.get(plugin)[name];
}
}

View File

@@ -21,7 +21,12 @@
import { types as tt, type TokenType } from "../tokenizer/types";
import * as N from "../types";
import LValParser from "./lval";
import { reservedWords } from "../util/identifier";
import {
isKeyword,
isReservedWord,
isStrictReservedWord,
isStrictBindReservedWord,
} from "../util/identifier";
import type { Pos, Position } from "../util/location";
import * as charCodes from "charcodes";
@@ -122,14 +127,23 @@ export default class ExpressionParser extends LValParser {
): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
if (this.match(tt._yield) && this.state.inGenerator) {
let left = this.parseYield();
if (afterLeftParse) {
left = afterLeftParse.call(this, left, startPos, startLoc);
if (this.isContextual("yield")) {
if (this.state.inGenerator) {
let left = this.parseYield(noIn);
if (afterLeftParse) {
left = afterLeftParse.call(this, left, startPos, startLoc);
}
return left;
} else {
// The tokenizer will assume an expression is allowed after
// `yield`, but this isn't that kind of yield
this.state.exprAllowed = false;
}
return left;
}
const oldCommaAfterSpreadAt = this.state.commaAfterSpreadAt;
this.state.commaAfterSpreadAt = -1;
let failOnShorthandAssign;
if (refShorthandDefaultPos) {
failOnShorthandAssign = false;
@@ -138,7 +152,7 @@ export default class ExpressionParser extends LValParser {
failOnShorthandAssign = true;
}
if (this.match(tt.parenL) || this.match(tt.name) || this.match(tt._yield)) {
if (this.match(tt.parenL) || this.match(tt.name)) {
this.state.potentialArrowAt = this.state.start;
}
@@ -169,21 +183,26 @@ export default class ExpressionParser extends LValParser {
this.checkLVal(left, undefined, undefined, "assignment expression");
if (left.extra && left.extra.parenthesized) {
let errorMsg;
if (left.type === "ObjectPattern") {
errorMsg = "`({a}) = 0` use `({a} = 0)`";
} else if (left.type === "ArrayPattern") {
errorMsg = "`([a]) = 0` use `([a] = 0)`";
}
if (errorMsg) {
this.raise(
left.start,
`You're trying to assign to a parenthesized expression, eg. instead of ${errorMsg}`,
);
}
let patternErrorMsg;
let elementName;
if (left.type === "ObjectPattern") {
patternErrorMsg = "`({a}) = 0` use `({a} = 0)`";
elementName = "property";
} else if (left.type === "ArrayPattern") {
patternErrorMsg = "`([a]) = 0` use `([a] = 0)`";
elementName = "element";
}
if (patternErrorMsg && left.extra && left.extra.parenthesized) {
this.raise(
left.start,
`You're trying to assign to a parenthesized expression, eg. instead of ${patternErrorMsg}`,
);
}
if (elementName) this.checkCommaAfterRestFromSpread(elementName);
this.state.commaAfterSpreadAt = oldCommaAfterSpreadAt;
this.next();
node.right = this.parseMaybeAssign(noIn);
return this.finishNode(node, "AssignmentExpression");
@@ -191,6 +210,8 @@ export default class ExpressionParser extends LValParser {
this.unexpected(refShorthandDefaultPos.start);
}
this.state.commaAfterSpreadAt = oldCommaAfterSpreadAt;
return left;
}
@@ -398,7 +419,13 @@ export default class ExpressionParser extends LValParser {
// Parse unary operators, both prefix and postfix.
parseMaybeUnary(refShorthandDefaultPos: ?Pos): N.Expression {
if (this.state.type.prefix) {
if (
this.isContextual("await") &&
(this.state.inAsync ||
(!this.state.inFunction && this.options.allowAwaitOutsideFunction))
) {
return this.parseAwait();
} else if (this.state.type.prefix) {
const node = this.startNode();
const update = this.match(tt.incDec);
node.operator = this.state.value;
@@ -515,7 +542,7 @@ export default class ExpressionParser extends LValParser {
} else if (this.match(tt.questionDot)) {
this.expectPlugin("optionalChaining");
state.optionalChainMember = true;
if (noCalls && this.lookahead().type == tt.parenL) {
if (noCalls && this.lookahead().type === tt.parenL) {
state.stop = true;
return base;
}
@@ -570,9 +597,11 @@ export default class ExpressionParser extends LValParser {
return this.finishNode(node, "MemberExpression");
} else if (!noCalls && this.match(tt.parenL)) {
const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
const oldYOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
const oldYieldPos = this.state.yieldPos;
const oldAwaitPos = this.state.awaitPos;
this.state.maybeInArrowParameters = true;
this.state.yieldOrAwaitInPossibleArrowParameters = null;
this.state.yieldPos = 0;
this.state.awaitPos = 0;
const possibleAsync = this.atPossibleAsync(base);
this.next();
@@ -580,15 +609,13 @@ export default class ExpressionParser extends LValParser {
let node = this.startNodeAt(startPos, startLoc);
node.callee = base;
// TODO: Clean up/merge this into `this.state` or a class like acorn's
// `DestructuringErrors` alongside refShorthandDefaultPos and
// refNeedsArrowPos.
const refTrailingCommaPos: Pos = { start: -1 };
const oldCommaAfterSpreadAt = this.state.commaAfterSpreadAt;
this.state.commaAfterSpreadAt = -1;
node.arguments = this.parseCallExpressionArguments(
tt.parenR,
possibleAsync,
refTrailingCommaPos,
base.type === "Import",
);
if (!state.optionalChainMember) {
this.finishCallExpression(node);
@@ -599,28 +626,26 @@ export default class ExpressionParser extends LValParser {
if (possibleAsync && this.shouldParseAsyncArrow()) {
state.stop = true;
if (refTrailingCommaPos.start > -1) {
this.raise(
refTrailingCommaPos.start,
"A trailing comma is not permitted after the rest element",
);
}
this.checkCommaAfterRestFromSpread("parameter");
node = this.parseAsyncArrowFromCallExpression(
this.startNodeAt(startPos, startLoc),
node,
);
this.state.yieldOrAwaitInPossibleArrowParameters = oldYOAIPAP;
this.checkYieldAwaitInDefaultParams();
this.state.yieldPos = oldYieldPos;
this.state.awaitPos = oldAwaitPos;
} else {
this.toReferencedListDeep(node.arguments);
// We keep the old value if it isn't null, for cases like
// (x = async(yield)) => {}
this.state.yieldOrAwaitInPossibleArrowParameters =
this.state.yieldOrAwaitInPossibleArrowParameters || oldYOAIPAP;
this.state.yieldPos = oldYieldPos || this.state.yieldPos;
this.state.awaitPos = oldAwaitPos || this.state.awaitPos;
}
this.state.maybeInArrowParameters = oldMaybeInArrowParameters;
this.state.commaAfterSpreadAt = oldCommaAfterSpreadAt;
return node;
} else if (this.match(tt.backQuote)) {
@@ -700,7 +725,7 @@ export default class ExpressionParser extends LValParser {
parseCallExpressionArguments(
close: TokenType,
possibleAsyncArrow: boolean,
refTrailingCommaPos?: Pos,
dynamicImport?: boolean,
): $ReadOnlyArray<?N.Expression> {
const elts = [];
let innerParenStart;
@@ -711,7 +736,15 @@ export default class ExpressionParser extends LValParser {
first = false;
} else {
this.expect(tt.comma);
if (this.eat(close)) break;
if (this.eat(close)) {
if (dynamicImport) {
this.raise(
this.state.lastTokStart,
"Trailing comma is disallowed inside import(...) arguments",
);
}
break;
}
}
// we need to make sure that if this is an async arrow functions,
@@ -725,7 +758,6 @@ export default class ExpressionParser extends LValParser {
false,
possibleAsyncArrow ? { start: 0 } : undefined,
possibleAsyncArrow ? { start: 0 } : undefined,
possibleAsyncArrow ? refTrailingCommaPos : undefined,
),
);
}
@@ -826,29 +858,12 @@ export default class ExpressionParser extends LValParser {
this.next();
return this.finishNode(node, "ThisExpression");
case tt._yield:
if (this.state.inGenerator) this.unexpected();
case tt.name: {
node = this.startNode();
const allowAwait =
this.state.value === "await" &&
(this.state.inAsync ||
(!this.state.inFunction && this.options.allowAwaitOutsideFunction));
const containsEsc = this.state.containsEsc;
const allowYield = this.shouldAllowYieldIdentifier();
const id = this.parseIdentifier(allowAwait || allowYield);
const id = this.parseIdentifier();
if (id.name === "await") {
if (
this.state.inAsync ||
this.inModule ||
(!this.state.inFunction && this.options.allowAwaitOutsideFunction)
) {
return this.parseAwait(node);
}
} else if (
if (
!containsEsc &&
id.name === "async" &&
this.match(tt._function) &&
@@ -858,28 +873,23 @@ export default class ExpressionParser extends LValParser {
return this.parseFunction(node, false, false, true);
} else if (
canBeArrow &&
!this.canInsertSemicolon() &&
id.name === "async" &&
this.match(tt.name)
this.match(tt.name) &&
!this.canInsertSemicolon()
) {
const oldYOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
const oldInAsync = this.state.inAsync;
this.state.yieldOrAwaitInPossibleArrowParameters = null;
this.state.inAsync = true;
const params = [this.parseIdentifier()];
this.expect(tt.arrow);
// let foo = async bar => {};
this.parseArrowExpression(node, params, true);
this.state.yieldOrAwaitInPossibleArrowParameters = oldYOAIPAP;
this.state.inAsync = oldInAsync;
return node;
}
if (canBeArrow && !this.canInsertSemicolon() && this.eat(tt.arrow)) {
const oldYOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
this.state.yieldOrAwaitInPossibleArrowParameters = null;
this.parseArrowExpression(node, [id]);
this.state.yieldOrAwaitInPossibleArrowParameters = oldYOAIPAP;
if (canBeArrow && this.match(tt.arrow) && !this.canInsertSemicolon()) {
this.next();
this.parseArrowExpression(node, [id], false);
return node;
}
@@ -1135,7 +1145,11 @@ export default class ExpressionParser extends LValParser {
const node = this.startNodeAt(startPos, startLoc);
this.addExtra(node, "rawValue", value);
this.addExtra(node, "raw", this.input.slice(startPos, this.state.end));
this.addExtra(
node,
"raw",
this.state.input.slice(startPos, this.state.end),
);
node.value = value;
this.next();
return this.finishNode(node, type);
@@ -1156,9 +1170,11 @@ export default class ExpressionParser extends LValParser {
this.expect(tt.parenL);
const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
const oldYOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
const oldYieldPos = this.state.yieldPos;
const oldAwaitPos = this.state.awaitPos;
this.state.maybeInArrowParameters = true;
this.state.yieldOrAwaitInPossibleArrowParameters = null;
this.state.yieldPos = 0;
this.state.awaitPos = 0;
const innerStartPos = this.state.start;
const innerStartLoc = this.state.startLoc;
@@ -1192,14 +1208,7 @@ export default class ExpressionParser extends LValParser {
),
);
if (this.match(tt.comma)) {
const nextTokenType = this.lookahead().type;
const errorMessage =
nextTokenType === tt.parenR
? "A trailing comma is not permitted after the rest element"
: "Rest parameter must be last formal parameter";
this.raise(this.state.start, errorMessage);
}
this.checkCommaAfterRest(tt.parenR, "parameter");
break;
} else {
@@ -1226,21 +1235,23 @@ export default class ExpressionParser extends LValParser {
this.shouldParseArrow() &&
(arrowNode = this.parseArrow(arrowNode))
) {
this.checkYieldAwaitInDefaultParams();
this.state.yieldPos = oldYieldPos;
this.state.awaitPos = oldAwaitPos;
for (const param of exprList) {
if (param.extra && param.extra.parenthesized) {
this.unexpected(param.extra.parenStart);
}
}
this.parseArrowExpression(arrowNode, exprList);
this.state.yieldOrAwaitInPossibleArrowParameters = oldYOAIPAP;
this.parseArrowExpression(arrowNode, exprList, false);
return arrowNode;
}
// We keep the old value if it isn't null, for cases like
// (x = (yield)) => {}
this.state.yieldOrAwaitInPossibleArrowParameters =
this.state.yieldOrAwaitInPossibleArrowParameters || oldYOAIPAP;
this.state.yieldPos = oldYieldPos || this.state.yieldPos;
this.state.awaitPos = oldAwaitPos || this.state.awaitPos;
if (!exprList.length) {
this.unexpected(this.state.lastTokStart);
@@ -1312,7 +1323,10 @@ export default class ExpressionParser extends LValParser {
}
node.callee = this.parseNoCallExpr();
if (
if (node.callee.type === "Import") {
this.raise(node.callee.start, "Cannot use new with import(...)");
} else if (
node.callee.type === "OptionalMemberExpression" ||
node.callee.type === "OptionalCallExpression"
) {
@@ -1320,13 +1334,13 @@ export default class ExpressionParser extends LValParser {
this.state.lastTokEnd,
"constructors in/after an Optional Chain are not allowed",
);
}
if (this.eat(tt.questionDot)) {
} else if (this.eat(tt.questionDot)) {
this.raise(
this.state.start,
"constructors in/after an Optional Chain are not allowed",
);
}
this.parseNewArguments(node);
return this.finishNode(node, "NewExpression");
}
@@ -1358,7 +1372,7 @@ export default class ExpressionParser extends LValParser {
}
}
elem.value = {
raw: this.input
raw: this.state.input
.slice(this.state.start, this.state.end)
.replace(/\r\n?/g, "\n"),
cooked: this.state.value,
@@ -1398,8 +1412,6 @@ export default class ExpressionParser extends LValParser {
node.properties = [];
this.next();
let firstRestLocation = null;
while (!this.eat(tt.braceR)) {
if (first) {
first = false;
@@ -1435,34 +1447,14 @@ export default class ExpressionParser extends LValParser {
if (this.match(tt.ellipsis)) {
prop = this.parseSpread(isPattern ? { start: 0 } : undefined);
if (isPattern) {
this.toAssignable(prop, true, "object pattern");
}
node.properties.push(prop);
if (isPattern) {
const position = this.state.start;
if (firstRestLocation !== null) {
this.unexpected(
firstRestLocation,
"Cannot have multiple rest elements when destructuring",
);
} else if (this.eat(tt.braceR)) {
break;
} else if (
this.match(tt.comma) &&
this.lookahead().type === tt.braceR
) {
this.unexpected(
position,
"A trailing comma is not permitted after the rest element",
);
} else {
firstRestLocation = position;
continue;
}
} else {
continue;
this.toAssignable(prop, true, "object pattern");
this.checkCommaAfterRest(tt.braceR, "property");
this.expect(tt.braceR);
break;
}
continue;
}
prop.method = false;
@@ -1519,13 +1511,6 @@ export default class ExpressionParser extends LValParser {
node.properties.push(prop);
}
if (firstRestLocation !== null) {
this.unexpected(
firstRestLocation,
"The rest element has to be the last element when destructuring",
);
}
if (decorators.length) {
this.raise(
this.state.start,
@@ -1734,21 +1719,28 @@ export default class ExpressionParser extends LValParser {
const oldInMethod = this.state.inMethod;
const oldInAsync = this.state.inAsync;
const oldInGenerator = this.state.inGenerator;
const oldYieldPos = this.state.yieldPos;
const oldAwaitPos = this.state.awaitPos;
this.state.inFunction = true;
this.state.inMethod = node.kind || true;
this.state.inAsync = isAsync;
this.state.inGenerator = isGenerator;
this.state.yieldPos = 0;
this.state.awaitPos = 0;
this.initFunction(node, isAsync);
node.generator = !!isGenerator;
const allowModifiers = isConstructor; // For TypeScript parameter properties
this.parseFunctionParams((node: any), allowModifiers);
this.checkYieldAwaitInDefaultParams();
this.parseFunctionBodyAndFinish(node, type);
this.state.inFunction = oldInFunc;
this.state.inMethod = oldInMethod;
this.state.inAsync = oldInAsync;
this.state.inGenerator = oldInGenerator;
this.state.yieldPos = oldYieldPos;
this.state.awaitPos = oldAwaitPos;
return node;
}
@@ -1758,44 +1750,33 @@ export default class ExpressionParser extends LValParser {
// assignable list.
parseArrowExpression(
node: N.ArrowFunctionExpression,
params?: ?(N.Expression[]),
isAsync?: boolean = false,
params: ?(N.Expression[]),
isAsync: boolean,
): N.ArrowFunctionExpression {
// if we got there, it's no more "yield in possible arrow parameters";
// it's just "yield in arrow parameters"
const yOAIPAP = this.state.yieldOrAwaitInPossibleArrowParameters;
if (yOAIPAP) {
if (yOAIPAP.type === "YieldExpression") {
this.raise(
yOAIPAP.start,
"yield is not allowed in the parameters of an arrow function" +
" inside a generator",
);
} else {
this.raise(
yOAIPAP.start,
"await is not allowed in the parameters of an arrow function" +
" inside an async function",
);
}
}
this.initFunction(node, isAsync);
const oldInFunc = this.state.inFunction;
this.state.inFunction = true;
this.initFunction(node, isAsync);
if (params) this.setArrowFunctionParameters(node, params);
const oldInAsync = this.state.inAsync;
const oldInGenerator = this.state.inGenerator;
const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
const oldYieldPos = this.state.yieldPos;
const oldAwaitPos = this.state.awaitPos;
this.state.inFunction = true;
this.state.inAsync = isAsync;
this.state.inGenerator = false;
this.state.maybeInArrowParameters = false;
this.state.yieldPos = 0;
this.state.awaitPos = 0;
if (params) this.setArrowFunctionParameters(node, params);
this.parseFunctionBody(node, true);
this.state.inAsync = oldInAsync;
this.state.inGenerator = oldInGenerator;
this.state.inFunction = oldInFunc;
this.state.maybeInArrowParameters = oldMaybeInArrowParameters;
this.state.yieldPos = oldYieldPos;
this.state.awaitPos = oldAwaitPos;
return this.finishNode(node, "ArrowFunctionExpression");
}
@@ -1845,17 +1826,14 @@ export default class ExpressionParser extends LValParser {
if (isExpression) {
node.body = this.parseMaybeAssign();
} else {
// Start a new scope with regard to labels and the `inGenerator`
// Start a new scope with regard to labels
// flag (restore them to their old value afterwards).
const oldInGen = this.state.inGenerator;
const oldInFunc = this.state.inFunction;
const oldLabels = this.state.labels;
this.state.inGenerator = node.generator;
this.state.inFunction = true;
this.state.labels = [];
node.body = this.parseBlock(true);
this.state.inFunction = oldInFunc;
this.state.inGenerator = oldInGen;
this.state.labels = oldLabels;
}
@@ -1923,7 +1901,6 @@ export default class ExpressionParser extends LValParser {
allowEmpty: ?boolean,
refShorthandDefaultPos: ?Pos,
refNeedsArrowPos: ?Pos,
refTrailingCommaPos?: Pos,
): ?N.Expression {
let elt;
if (allowEmpty && this.match(tt.comma)) {
@@ -1936,10 +1913,6 @@ export default class ExpressionParser extends LValParser {
spreadNodeStartPos,
spreadNodeStartLoc,
);
if (refTrailingCommaPos && this.match(tt.comma)) {
refTrailingCommaPos.start = this.state.start;
}
} else {
elt = this.parseMaybeAssign(
false,
@@ -1970,15 +1943,6 @@ export default class ExpressionParser extends LValParser {
}
parseIdentifierName(pos: number, liberal?: boolean): string {
if (!liberal) {
this.checkReservedWord(
this.state.value,
this.state.start,
!!this.state.type.keyword,
false,
);
}
let name: string;
if (this.match(tt.name)) {
@@ -1994,7 +1958,8 @@ export default class ExpressionParser extends LValParser {
if (
(name === "class" || name === "function") &&
(this.state.lastTokEnd !== this.state.lastTokStart + 1 ||
this.input.charCodeAt(this.state.lastTokStart) !== charCodes.dot)
this.state.input.charCodeAt(this.state.lastTokStart) !==
charCodes.dot)
) {
this.state.context.pop();
}
@@ -2002,11 +1967,17 @@ export default class ExpressionParser extends LValParser {
throw this.unexpected();
}
if (!liberal && name === "await" && this.state.inAsync) {
this.raise(pos, "invalid use of await inside of an async function");
if (!liberal) {
this.checkReservedWord(
name,
this.state.start,
!!this.state.type.keyword,
false,
);
}
this.next();
return name;
}
@@ -2016,43 +1987,58 @@ export default class ExpressionParser extends LValParser {
checkKeywords: boolean,
isBinding: boolean,
): void {
if (
this.state.strict &&
(reservedWords.strict(word) ||
(isBinding && reservedWords.strictBind(word)))
) {
this.raise(startLoc, word + " is a reserved word in strict mode");
}
if (this.state.inGenerator && word === "yield") {
const state = this.state;
if (state.inGenerator && word === "yield") {
this.raise(
startLoc,
"yield is a reserved word inside generator functions",
"Can not use 'yield' as identifier inside a generator",
);
}
if (this.state.inClassProperty && word === "arguments") {
if (state.inAsync && word === "await") {
this.raise(
startLoc,
"Can not use 'await' as identifier inside an async function",
);
}
if (state.inClassProperty && word === "arguments") {
this.raise(
startLoc,
"'arguments' is not allowed in class field initializer",
);
}
if (checkKeywords && isKeyword(word)) {
this.raise(startLoc, `Unexpected keyword '${word}'`);
}
if (this.isReservedWord(word) || (checkKeywords && this.isKeyword(word))) {
this.raise(startLoc, word + " is a reserved word");
const reservedTest = !state.strict
? isReservedWord
: isBinding
? isStrictBindReservedWord
: isStrictReservedWord;
if (reservedTest(word, this.inModule)) {
if (!state.inAsync && word === "await") {
this.raise(
startLoc,
"Can not use keyword 'await' outside an async function",
);
}
this.raise(startLoc, `Unexpected reserved word '${word}'`);
}
}
// Parses await expression inside async function.
parseAwait(node: N.AwaitExpression): N.AwaitExpression {
// istanbul ignore next: this condition is checked at the call site so won't be hit here
if (
!this.state.inAsync &&
(this.state.inFunction || !this.options.allowAwaitOutsideFunction)
) {
this.unexpected();
parseAwait(): N.AwaitExpression {
if (!this.state.awaitPos) {
this.state.awaitPos = this.state.start;
}
const node = this.startNode();
this.next();
if (this.state.inParameters) {
this.raise(
node.start,
@@ -2065,14 +2051,6 @@ export default class ExpressionParser extends LValParser {
"await* has been removed from the async functions proposal. Use Promise.all() instead.",
);
}
if (
this.state.maybeInArrowParameters &&
// We only set yieldOrAwaitInPossibleArrowParameters if we haven't already
// found a possible invalid AwaitExpression.
!this.state.yieldOrAwaitInPossibleArrowParameters
) {
this.state.yieldOrAwaitInPossibleArrowParameters = node;
}
node.argument = this.parseMaybeUnary();
return this.finishNode(node, "AwaitExpression");
@@ -2080,32 +2058,27 @@ export default class ExpressionParser extends LValParser {
// Parses yield expression inside generator.
parseYield(): N.YieldExpression {
parseYield(noIn?: ?boolean): N.YieldExpression {
if (!this.state.yieldPos) {
this.state.yieldPos = this.state.start;
}
const node = this.startNode();
if (this.state.inParameters) {
this.raise(node.start, "yield is not allowed in generator parameters");
}
if (
this.state.maybeInArrowParameters &&
// We only set yieldOrAwaitInPossibleArrowParameters if we haven't already
// found a possible invalid YieldExpression.
!this.state.yieldOrAwaitInPossibleArrowParameters
) {
this.state.yieldOrAwaitInPossibleArrowParameters = node;
}
this.next();
if (
this.match(tt.semi) ||
this.canInsertSemicolon() ||
(!this.match(tt.star) && !this.state.type.startsExpr)
(!this.match(tt.star) && !this.state.type.startsExpr) ||
this.canInsertSemicolon()
) {
node.delegate = false;
node.argument = null;
} else {
node.delegate = this.eat(tt.star);
node.argument = this.parseMaybeAssign();
node.argument = this.parseMaybeAssign(noIn);
}
return this.finishNode(node, "YieldExpression");
}

View File

@@ -6,9 +6,7 @@ import type { PluginList } from "../plugin-utils";
import { getOptions } from "../options";
import StatementParser from "./statement";
export type PluginsMap = {
[key: string]: { [option: string]: any },
};
export type PluginsMap = Map<string, { [string]: any }>;
export default class Parser extends StatementParser {
// Forward-declaration so typescript plugin can override jsx plugin
@@ -22,7 +20,6 @@ export default class Parser extends StatementParser {
this.options = options;
this.inModule = this.options.sourceType === "module";
this.input = input;
this.plugins = pluginsMap(this.options.plugins);
this.filename = options.sourceFilename;
}
@@ -36,10 +33,10 @@ export default class Parser extends StatementParser {
}
function pluginsMap(plugins: PluginList): PluginsMap {
const pluginMap: PluginsMap = (Object.create(null): Object);
const pluginMap: PluginsMap = new Map();
for (const plugin of plugins) {
const [name, options = {}] = Array.isArray(plugin) ? plugin : [plugin, {}];
if (!pluginMap[name]) pluginMap[name] = options || {};
const [name, options] = Array.isArray(plugin) ? plugin : [plugin, {}];
if (!pluginMap.has(name)) pluginMap.set(name, options || {});
}
return pluginMap;
}

View File

@@ -21,7 +21,7 @@ export default class LocationParser extends CommentsParser {
code?: string,
} = {},
): empty {
const loc = getLineInfo(this.input, pos);
const loc = getLineInfo(this.state.input, pos);
message += ` (${loc.line}:${loc.column})`;
// $FlowIgnore
const err: SyntaxError & { pos: number, loc: Position } = new SyntaxError(

View File

@@ -14,16 +14,11 @@ import type {
SpreadElement,
} from "../types";
import type { Pos, Position } from "../util/location";
import { isStrictBindReservedWord } from "../util/identifier";
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,
@@ -56,9 +51,13 @@ export default class LValParser extends NodeUtils {
case "ObjectExpression":
node.type = "ObjectPattern";
for (let index = 0; index < node.properties.length; index++) {
const prop = node.properties[index];
const isLast = index === node.properties.length - 1;
for (
let i = 0, length = node.properties.length, last = length - 1;
i < length;
i++
) {
const prop = node.properties[i];
const isLast = i === last;
this.toAssignableObjectExpressionProp(prop, isBinding, isLast);
}
break;
@@ -122,10 +121,7 @@ export default class LValParser extends NodeUtils {
this.raise(prop.key.start, error);
} else if (prop.type === "SpreadElement" && !isLast) {
this.raise(
prop.start,
"The rest element has to be the last element when destructuring",
);
this.raiseRestNotLast(prop.start, "property");
} else {
this.toAssignable(prop, isBinding, "object destructuring pattern");
}
@@ -148,12 +144,10 @@ export default class LValParser extends NodeUtils {
const arg = last.argument;
this.toAssignable(arg, isBinding, contextDescription);
if (
[
"Identifier",
"MemberExpression",
"ArrayPattern",
"ObjectPattern",
].indexOf(arg.type) === -1
arg.type !== "Identifier" &&
arg.type !== "MemberExpression" &&
arg.type !== "ArrayPattern" &&
arg.type !== "ObjectPattern"
) {
this.unexpected(arg.start);
}
@@ -162,13 +156,12 @@ export default class LValParser extends NodeUtils {
}
for (let i = 0; i < end; i++) {
const elt = exprList[i];
if (elt && elt.type === "SpreadElement") {
this.raise(
elt.start,
"The rest element has to be the last element when destructuring",
);
if (elt) {
this.toAssignable(elt, isBinding, contextDescription);
if (elt.type === "RestElement") {
this.raiseRestNotLast(elt.start, "element");
}
}
if (elt) this.toAssignable(elt, isBinding, contextDescription);
}
return exprList;
}
@@ -199,10 +192,10 @@ export default class LValParser extends NodeUtils {
// Parses spread element.
parseSpread<T: RestElement | SpreadElement>(
parseSpread(
refShorthandDefaultPos: ?Pos,
refNeedsArrowPos?: ?Pos,
): T {
): SpreadElement {
const node = this.startNode();
this.next();
node.argument = this.parseMaybeAssign(
@@ -211,6 +204,11 @@ export default class LValParser extends NodeUtils {
undefined,
refNeedsArrowPos,
);
if (this.state.commaAfterSpreadAt === -1 && this.match(tt.comma)) {
this.state.commaAfterSpreadAt = this.state.start;
}
return this.finishNode(node, "SpreadElement");
}
@@ -221,22 +219,11 @@ export default class LValParser extends NodeUtils {
return this.finishNode(node, "RestElement");
}
shouldAllowYieldIdentifier(): boolean {
return (
this.match(tt._yield) && !this.state.strict && !this.state.inGenerator
);
}
parseBindingIdentifier(): Identifier {
return this.parseIdentifier(this.shouldAllowYieldIdentifier());
}
// Parses lvalue (assignable) atom.
parseBindingAtom(): Pattern {
switch (this.state.type) {
case tt._yield:
case tt.name:
return this.parseBindingIdentifier();
return this.parseIdentifier();
case tt.bracketL: {
const node = this.startNode();
@@ -273,20 +260,13 @@ export default class LValParser extends NodeUtils {
break;
} else if (this.match(tt.ellipsis)) {
elts.push(this.parseAssignableListItemTypes(this.parseRest()));
if (
this.state.inFunction &&
this.state.inParameters &&
this.match(tt.comma)
) {
const nextTokenType = this.lookahead().type;
const errorMessage =
nextTokenType === tt.parenR
? "A trailing comma is not permitted after the rest element"
: "Rest parameter must be last formal parameter";
this.raise(this.state.start, errorMessage);
} else {
this.expect(close);
}
this.checkCommaAfterRest(
close,
this.state.inFunction && this.state.inParameters
? "parameter"
: "element",
);
this.expect(close);
break;
} else {
const decorators = [];
@@ -351,7 +331,17 @@ export default class LValParser extends NodeUtils {
): void {
switch (expr.type) {
case "Identifier":
this.checkReservedWord(expr.name, expr.start, false, true);
if (
this.state.strict &&
isStrictBindReservedWord(expr.name, this.inModule)
) {
this.raise(
expr.start,
`${isBinding ? "Binding" : "Assigning to"} '${
expr.name
}' in strict mode`,
);
}
if (checkClashes) {
// we need to prefix this with an underscore for the cases where we have a key of
@@ -432,12 +422,35 @@ export default class LValParser extends NodeUtils {
}
checkToRestConversion(node: SpreadElement): void {
const validArgumentTypes = ["Identifier", "MemberExpression"];
if (validArgumentTypes.indexOf(node.argument.type) !== -1) {
return;
if (
node.argument.type !== "Identifier" &&
node.argument.type !== "MemberExpression"
) {
this.raise(node.argument.start, "Invalid rest operator's argument");
}
}
this.raise(node.argument.start, "Invalid rest operator's argument");
checkCommaAfterRest(close: TokenType, kind: string): void {
if (this.match(tt.comma)) {
if (this.lookahead().type === close) {
this.raiseCommaAfterRest(this.state.start, kind);
} else {
this.raiseRestNotLast(this.state.start, kind);
}
}
}
checkCommaAfterRestFromSpread(kind: string): void {
if (this.state.commaAfterSpreadAt > -1) {
this.raiseCommaAfterRest(this.state.commaAfterSpreadAt, kind);
}
}
raiseCommaAfterRest(pos: number, kind: string) {
this.raise(pos, `A trailing comma is not permitted after the rest ${kind}`);
}
raiseRestNotLast(pos: number, kind: string) {
this.raise(pos, `The rest ${kind} must be the last ${kind}`);
}
}

View File

@@ -7,8 +7,6 @@ import type { Comment, Node as NodeType, NodeBase } from "../types";
// Start an AST node, attaching a start offset.
const commentKeys = ["leadingComments", "trailingComments", "innerComments"];
class Node implements NodeBase {
constructor(parser: Parser, pos: number, loc: Position) {
this.type = "";
@@ -31,16 +29,22 @@ class Node implements NodeBase {
__clone(): this {
// $FlowIgnore
const node2: any = new Node();
Object.keys(this).forEach(key => {
const newNode: any = new Node();
const keys = Object.keys(this);
for (let i = 0, length = keys.length; i < length; i++) {
const key = keys[i];
// Do not clone comments that are already attached to the node
if (commentKeys.indexOf(key) < 0) {
if (
key !== "leadingComments" &&
key !== "trailingComments" &&
key !== "innerComments"
) {
// $FlowIgnore
node2[key] = this[key];
newNode[key] = this[key];
}
});
}
return node2;
return newNode;
}
}
@@ -87,12 +91,16 @@ export class NodeUtils extends UtilParser {
return node;
}
resetStartLocation(node: NodeBase, start: number, startLoc: Position): void {
node.start = start;
node.loc.start = startLoc;
if (this.options.ranges) node.range[0] = start;
}
/**
* Reset the start location of node to the start location of locationNode
*/
resetStartLocationFromNode(node: NodeBase, locationNode: NodeBase): void {
node.start = locationNode.start;
node.loc.start = locationNode.loc.start;
if (this.options.ranges) node.range[0] = locationNode.range[0];
this.resetStartLocation(node, locationNode.start, locationNode.loc.start);
}
}

View File

@@ -3,8 +3,13 @@
import * as N from "../types";
import { types as tt, type TokenType } from "../tokenizer/types";
import ExpressionParser from "./expression";
import { isIdentifierChar } from "../util/identifier";
import {
isIdentifierChar,
isIdentifierStart,
keywordRelationalOperator,
} from "../util/identifier";
import { lineBreak, skipWhiteSpace } from "../util/whitespace";
import * as charCodes from "charcodes";
// Reused empty array added for node fields that are always empty.
@@ -44,7 +49,7 @@ export default class StatementParser extends ExpressionParser {
const directiveLiteral = this.startNodeAt(expr.start, expr.loc.start);
const directive = this.startNodeAt(stmt.start, stmt.loc.start);
const raw = this.input.slice(expr.start, expr.end);
const raw = this.state.input.slice(expr.start, expr.end);
const val = (directiveLiteral.value = raw.slice(1, -1)); // remove quotes
this.addExtra(directiveLiteral, "raw", raw);
@@ -71,6 +76,39 @@ export default class StatementParser extends ExpressionParser {
return this.finishNode(node, "InterpreterDirective");
}
isLet(declaration?: boolean): boolean {
if (!this.isContextual("let")) {
return false;
}
skipWhiteSpace.lastIndex = this.state.pos;
const skip = skipWhiteSpace.exec(this.state.input);
// $FlowIgnore
const next = this.state.pos + skip[0].length;
const nextCh = this.state.input.charCodeAt(next);
if (
(nextCh === charCodes.leftCurlyBrace &&
!lineBreak.test(this.state.input.slice(this.state.end, next))) ||
nextCh === charCodes.leftSquareBracket
) {
return true;
}
if (isIdentifierStart(nextCh)) {
if (
!declaration &&
lineBreak.test(this.state.input.slice(this.state.end, next))
) {
return false;
}
let pos = next + 1;
while (isIdentifierChar(this.state.input.charCodeAt(pos))) {
++pos;
}
const ident = this.state.input.slice(next, pos);
if (!keywordRelationalOperator.test(ident)) return true;
}
return false;
}
// Parse a single statement.
//
// If expecting a statement and finding a slash operator, parse a
@@ -86,8 +124,14 @@ export default class StatementParser extends ExpressionParser {
}
parseStatementContent(declaration: boolean, topLevel: ?boolean): N.Statement {
const starttype = this.state.type;
let starttype = this.state.type;
const node = this.startNode();
let kind;
if (this.isLet(declaration)) {
starttype = tt._var;
kind = "let";
}
// Most types of statements are recognized by the keyword they
// start with. Many are trivial to parse, some require a bit of
@@ -106,7 +150,12 @@ export default class StatementParser extends ExpressionParser {
return this.parseForStatement(node);
case tt._function:
if (this.lookahead().type === tt.dot) break;
if (!declaration) this.unexpected();
if (!declaration) {
this.raise(
this.state.start,
"Function declaration not allowed in this context",
);
}
return this.parseFunctionStatement(node);
case tt._class:
@@ -124,12 +173,11 @@ export default class StatementParser extends ExpressionParser {
case tt._try:
return this.parseTryStatement(node);
case tt._let:
case tt._const:
if (!declaration) this.unexpected(); // NOTE: falls through to _var
case tt._var:
return this.parseVarStatement(node, starttype);
kind = kind || this.state.value;
if (!declaration && kind !== "var") this.unexpected();
return this.parseVarStatement(node, kind);
case tt._while:
return this.parseWhileStatement(node);
@@ -156,7 +204,7 @@ export default class StatementParser extends ExpressionParser {
this.next();
let result;
if (starttype == tt._import) {
if (starttype === tt._import) {
result = this.parseImport(node);
if (
@@ -189,7 +237,13 @@ export default class StatementParser extends ExpressionParser {
const state = this.state.clone();
this.next();
if (this.match(tt._function) && !this.canInsertSemicolon()) {
this.expect(tt._function);
if (!declaration) {
this.raise(
this.state.lastTokStart,
"Function declaration not allowed in this context",
);
}
this.next();
return this.parseFunction(node, true, false, true);
} else {
this.state = state;
@@ -210,7 +264,7 @@ export default class StatementParser extends ExpressionParser {
expr.type === "Identifier" &&
this.eat(tt.colon)
) {
return this.parseLabeledStatement(node, maybeName, expr);
return this.parseLabeledStatement(node, maybeName, expr, declaration);
} else {
return this.parseExpressionStatement(node, expr);
}
@@ -399,32 +453,36 @@ export default class StatementParser extends ExpressionParser {
this.next();
this.state.labels.push(loopLabel);
let forAwait = false;
if (this.state.inAsync && this.isContextual("await")) {
forAwait = true;
this.next();
let awaitAt = -1;
if (
(this.state.inAsync ||
(!this.state.inFunction && this.options.allowAwaitOutsideFunction)) &&
this.eatContextual("await")
) {
awaitAt = this.state.lastTokStart;
}
this.expect(tt.parenL);
if (this.match(tt.semi)) {
if (forAwait) {
this.unexpected();
if (awaitAt > -1) {
this.unexpected(awaitAt);
}
return this.parseFor(node, null);
}
if (this.match(tt._var) || this.match(tt._let) || this.match(tt._const)) {
const isLet = this.isLet();
if (this.match(tt._var) || this.match(tt._const) || isLet) {
const init = this.startNode();
const varKind = this.state.type;
const kind = isLet ? "let" : this.state.value;
this.next();
this.parseVar(init, true, varKind);
this.parseVar(init, true, kind);
this.finishNode(init, "VariableDeclaration");
if (this.match(tt._in) || this.isContextual("of")) {
if (init.declarations.length === 1) {
const declaration = init.declarations[0];
const isForInInitializer =
varKind === tt._var &&
kind === "var" &&
declaration.init &&
declaration.id.type != "ObjectPattern" &&
declaration.id.type != "ArrayPattern" &&
@@ -432,12 +490,12 @@ export default class StatementParser extends ExpressionParser {
if (this.state.strict && isForInInitializer) {
this.raise(this.state.start, "for-in initializer in strict mode");
} else if (isForInInitializer || !declaration.init) {
return this.parseForIn(node, init, forAwait);
return this.parseForIn(node, init, awaitAt);
}
}
}
if (forAwait) {
this.unexpected();
if (awaitAt > -1) {
this.unexpected(awaitAt);
}
return this.parseFor(node, init);
}
@@ -450,12 +508,12 @@ export default class StatementParser extends ExpressionParser {
: "for-in statement";
this.toAssignable(init, undefined, description);
this.checkLVal(init, undefined, undefined, description);
return this.parseForIn(node, init, forAwait);
return this.parseForIn(node, init, awaitAt);
} else if (refShorthandDefaultPos.start) {
this.unexpected(refShorthandDefaultPos.start);
}
if (forAwait) {
this.unexpected();
if (awaitAt > -1) {
this.unexpected(awaitAt);
}
return this.parseFor(node, init);
}
@@ -540,7 +598,9 @@ export default class StatementParser extends ExpressionParser {
parseThrowStatement(node: N.ThrowStatement): N.ThrowStatement {
this.next();
if (
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start))
lineBreak.test(
this.state.input.slice(this.state.lastTokEnd, this.state.start),
)
) {
this.raise(this.state.lastTokEnd, "Illegal newline after throw");
}
@@ -593,7 +653,7 @@ export default class StatementParser extends ExpressionParser {
parseVarStatement(
node: N.VariableDeclaration,
kind: TokenType,
kind: "var" | "let" | "const",
): N.VariableDeclaration {
this.next();
this.parseVar(node, false, kind);
@@ -649,6 +709,7 @@ export default class StatementParser extends ExpressionParser {
node: N.LabeledStatement,
maybeName: string,
expr: N.Identifier,
declaration: boolean,
): N.LabeledStatement {
for (const label of this.state.labels) {
if (label.name === maybeName) {
@@ -676,12 +737,12 @@ export default class StatementParser extends ExpressionParser {
kind: kind,
statementStart: this.state.start,
});
node.body = this.parseStatement(true);
node.body = this.parseStatement(declaration);
if (
node.body.type == "ClassDeclaration" ||
(node.body.type == "VariableDeclaration" && node.body.kind !== "var") ||
(node.body.type == "FunctionDeclaration" &&
node.body.type === "ClassDeclaration" ||
(node.body.type === "VariableDeclaration" && node.body.kind !== "var") ||
(node.body.type === "FunctionDeclaration" &&
(this.state.strict || node.body.generator || node.body.async))
) {
this.raise(node.body.start, "Invalid labeled declaration");
@@ -814,16 +875,16 @@ export default class StatementParser extends ExpressionParser {
parseForIn(
node: N.ForInOf,
init: N.VariableDeclaration,
forAwait: boolean,
awaitAt: number,
): N.ForInOf {
const type = this.match(tt._in) ? "ForInStatement" : "ForOfStatement";
if (forAwait) {
if (awaitAt > -1) {
this.eatContextual("of");
} else {
this.next();
}
if (type === "ForOfStatement") {
node.await = !!forAwait;
node.await = awaitAt > -1;
}
node.left = init;
node.right = this.parseExpression();
@@ -848,24 +909,24 @@ export default class StatementParser extends ExpressionParser {
parseVar(
node: N.VariableDeclaration,
isFor: boolean,
kind: TokenType,
kind: "var" | "let" | "const",
): N.VariableDeclaration {
const declarations = (node.declarations = []);
// $FlowFixMe
node.kind = kind.keyword;
const isTypescript = this.hasPlugin("typescript");
node.kind = kind;
for (;;) {
const decl = this.startNode();
this.parseVarHead(decl);
this.parseVarId(decl, kind);
if (this.eat(tt.eq)) {
decl.init = this.parseMaybeAssign(isFor);
} else {
if (
kind === tt._const &&
kind === "const" &&
!(this.match(tt._in) || this.isContextual("of"))
) {
// `const` with no initializer is allowed in TypeScript.
// It could be a declaration like `const x: number;`.
if (!this.hasPlugin("typescript")) {
if (!isTypescript) {
this.unexpected();
}
} else if (
@@ -885,7 +946,10 @@ export default class StatementParser extends ExpressionParser {
return node;
}
parseVarHead(decl: N.VariableDeclarator): void {
parseVarId(decl: N.VariableDeclarator, kind: "var" | "let" | "const"): void {
if ((kind === "const" || kind === "let") && this.isContextual("let")) {
this.unexpected(null, "let is disallowed as a lexically bound name");
}
decl.id = this.parseBindingAtom();
this.checkLVal(decl.id, true, undefined, "variable declaration");
}
@@ -905,23 +969,19 @@ export default class StatementParser extends ExpressionParser {
const oldInAsync = this.state.inAsync;
const oldInGenerator = this.state.inGenerator;
const oldInClassProperty = this.state.inClassProperty;
const oldYieldPos = this.state.yieldPos;
const oldAwaitPos = this.state.awaitPos;
this.state.inFunction = true;
this.state.inMethod = false;
this.state.inClassProperty = false;
this.state.yieldPos = 0;
this.state.awaitPos = 0;
this.initFunction(node, isAsync);
if (this.match(tt.star)) {
node.generator = true;
this.next();
}
node.generator = this.eat(tt.star);
if (
isStatement &&
!optionalId &&
!this.match(tt.name) &&
!this.match(tt._yield)
) {
if (isStatement && !optionalId && !this.match(tt.name)) {
this.unexpected();
}
@@ -938,8 +998,8 @@ export default class StatementParser extends ExpressionParser {
this.state.inAsync = isAsync;
this.state.inGenerator = node.generator;
}
if (this.match(tt.name) || this.match(tt._yield)) {
node.id = this.parseBindingIdentifier();
if (this.match(tt.name)) {
node.id = this.parseIdentifier();
}
if (isStatement) {
this.state.inAsync = isAsync;
@@ -965,6 +1025,8 @@ export default class StatementParser extends ExpressionParser {
this.state.inAsync = oldInAsync;
this.state.inGenerator = oldInGenerator;
this.state.inClassProperty = oldInClassProperty;
this.state.yieldPos = oldYieldPos;
this.state.awaitPos = oldAwaitPos;
return node;
}
@@ -981,6 +1043,7 @@ export default class StatementParser extends ExpressionParser {
);
this.state.inParameters = oldInParameters;
this.checkYieldAwaitInDefaultParams();
}
// Parse a class declaration or literal (depending on the
@@ -993,9 +1056,17 @@ export default class StatementParser extends ExpressionParser {
): T {
this.next();
this.takeDecorators(node);
// A class definition is always strict mode code.
const oldStrict = this.state.strict;
this.state.strict = true;
this.parseClassId(node, isStatement, optionalId);
this.parseClassSuper(node);
this.parseClassBody(node);
this.state.strict = oldStrict;
return this.finishNode(
node,
isStatement ? "ClassDeclaration" : "ClassExpression",
@@ -1020,9 +1091,6 @@ export default class StatementParser extends ExpressionParser {
}
parseClassBody(node: N.Class): void {
// class bodies are implicitly strict
const oldStrict = this.state.strict;
this.state.strict = true;
this.state.classLevel++;
const state = { hadConstructor: false };
@@ -1087,7 +1155,6 @@ export default class StatementParser extends ExpressionParser {
node.body = this.finishNode(classBody, "ClassBody");
this.state.classLevel--;
this.state.strict = oldStrict;
}
parseClassMember(
@@ -1262,7 +1329,7 @@ export default class StatementParser extends ExpressionParser {
} else if (
isSimple &&
(key.name === "get" || key.name === "set") &&
!(this.isLineTerminator() && this.match(tt.star))
!(this.match(tt.star) && this.isLineTerminator())
) {
// `get\n*` is an uninitialized property named 'get' followed by a generator.
// a getter or setter
@@ -1451,35 +1518,109 @@ export default class StatementParser extends ExpressionParser {
// Parses module export declaration.
// TODO: better type. Node is an N.AnyExport.
parseExport(node: N.Node): N.Node {
// export * from '...'
if (this.shouldParseExportStar()) {
this.parseExportStar(node);
if (node.type === "ExportAllDeclaration") return node;
} else if (this.isExportDefaultSpecifier()) {
this.expectPlugin("exportDefaultFrom");
const specifier = this.startNode();
specifier.exported = this.parseIdentifier(true);
const specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
node.specifiers = specifiers;
if (this.match(tt.comma) && this.lookahead().type === tt.star) {
this.expect(tt.comma);
const specifier = this.startNode();
this.expect(tt.star);
this.expectContextual("as");
specifier.exported = this.parseIdentifier();
specifiers.push(this.finishNode(specifier, "ExportNamespaceSpecifier"));
} else {
this.parseExportSpecifiersMaybe(node);
}
parseExport(node: N.Node): N.AnyExport {
const hasDefault = this.maybeParseExportDefaultSpecifier(node);
const parseAfterDefault = !hasDefault || this.eat(tt.comma);
const hasStar = parseAfterDefault && this.eatExportStar(node);
const hasNamespace =
hasStar && this.maybeParseExportNamespaceSpecifier(node);
const parseAfterNamespace =
parseAfterDefault && (!hasNamespace || this.eat(tt.comma));
const isFromRequired = hasDefault || hasStar;
if (hasStar && !hasNamespace) {
if (hasDefault) this.unexpected();
this.parseExportFrom(node, true);
} else if (this.eat(tt._default)) {
return this.finishNode(node, "ExportAllDeclaration");
}
const hasSpecifiers = this.maybeParseExportNamedSpecifiers(node);
if (
(hasDefault && parseAfterDefault && !hasStar && !hasSpecifiers) ||
(hasNamespace && parseAfterNamespace && !hasSpecifiers)
) {
throw this.unexpected(null, tt.braceL);
}
let hasDeclaration;
if (isFromRequired || hasSpecifiers) {
hasDeclaration = false;
this.parseExportFrom(node, isFromRequired);
} else {
hasDeclaration = this.maybeParseExportDeclaration(node);
}
if (isFromRequired || hasSpecifiers || hasDeclaration) {
this.checkExport(node, true);
return this.finishNode(node, "ExportNamedDeclaration");
}
if (this.eat(tt._default)) {
// export default ...
node.declaration = this.parseExportDefaultExpression();
this.checkExport(node, true, true);
return this.finishNode(node, "ExportDefaultDeclaration");
} else if (this.shouldParseExportDeclaration()) {
}
throw this.unexpected(null, tt.braceL);
}
// eslint-disable-next-line no-unused-vars
eatExportStar(node: N.Node): boolean {
return this.eat(tt.star);
}
maybeParseExportDefaultSpecifier(node: N.Node): boolean {
if (this.isExportDefaultSpecifier()) {
// export defaultObj ...
this.expectPlugin("exportDefaultFrom");
const specifier = this.startNode();
specifier.exported = this.parseIdentifier(true);
node.specifiers = [this.finishNode(specifier, "ExportDefaultSpecifier")];
return true;
}
return false;
}
maybeParseExportNamespaceSpecifier(node: N.Node): boolean {
if (this.isContextual("as")) {
if (!node.specifiers) node.specifiers = [];
this.expectPlugin("exportNamespaceFrom");
const specifier = this.startNodeAt(
this.state.lastTokStart,
this.state.lastTokStartLoc,
);
this.next();
specifier.exported = this.parseIdentifier(true);
node.specifiers.push(
this.finishNode(specifier, "ExportNamespaceSpecifier"),
);
return true;
}
return false;
}
maybeParseExportNamedSpecifiers(node: N.Node): boolean {
if (this.match(tt.braceL)) {
if (!node.specifiers) node.specifiers = [];
node.specifiers.push(...this.parseExportSpecifiers());
node.source = null;
node.declaration = null;
return true;
}
return false;
}
maybeParseExportDeclaration(node: N.Node): boolean {
if (this.shouldParseExportDeclaration()) {
if (this.isContextual("async")) {
const next = this.lookahead();
@@ -1492,20 +1633,16 @@ export default class StatementParser extends ExpressionParser {
node.specifiers = [];
node.source = null;
node.declaration = this.parseExportDeclaration(node);
} else {
// export { x, y as z } [from '...']
node.declaration = null;
node.specifiers = this.parseExportSpecifiers();
this.parseExportFrom(node);
return true;
}
this.checkExport(node, true);
return this.finishNode(node, "ExportNamedDeclaration");
return false;
}
isAsyncFunction() {
if (!this.isContextual("async")) return false;
const { input, pos } = this.state;
const { input, pos, length } = this.state;
skipWhiteSpace.lastIndex = pos;
const skip = skipWhiteSpace.exec(input);
@@ -1517,7 +1654,7 @@ export default class StatementParser extends ExpressionParser {
return (
!lineBreak.test(input.slice(pos, next)) &&
input.slice(next, next + 8) === "function" &&
(next + 8 === input.length || !isIdentifierChar(input.charAt(next + 8)))
(next + 8 === length || !isIdentifierChar(input.charCodeAt(next + 8)))
);
}
@@ -1549,11 +1686,7 @@ export default class StatementParser extends ExpressionParser {
}
this.parseDecorators(false);
return this.parseClass(expr, true, true);
} else if (
this.match(tt._let) ||
this.match(tt._const) ||
this.match(tt._var)
) {
} else if (this.match(tt._const) || this.match(tt._var) || this.isLet()) {
return this.raise(
this.state.start,
"Only expressions, functions or classes are allowed as the `default` export.",
@@ -1572,7 +1705,7 @@ export default class StatementParser extends ExpressionParser {
isExportDefaultSpecifier(): boolean {
if (this.match(tt.name)) {
return this.state.value !== "async";
return this.state.value !== "async" && this.state.value !== "let";
}
if (!this.match(tt._default)) {
@@ -1586,17 +1719,9 @@ export default class StatementParser extends ExpressionParser {
);
}
parseExportSpecifiersMaybe(node: N.ExportNamedDeclaration): void {
if (this.eat(tt.comma)) {
node.specifiers = node.specifiers.concat(this.parseExportSpecifiers());
}
}
parseExportFrom(node: N.ExportNamedDeclaration, expect?: boolean): void {
if (this.eatContextual("from")) {
node.source = this.match(tt.string)
? this.parseExprAtom()
: this.unexpected();
node.source = this.parseImportSource();
this.checkExport(node);
} else {
if (expect) {
@@ -1609,39 +1734,6 @@ export default class StatementParser extends ExpressionParser {
this.semicolon();
}
shouldParseExportStar(): boolean {
return this.match(tt.star);
}
parseExportStar(node: N.ExportNamedDeclaration): void {
this.expect(tt.star);
if (this.isContextual("as")) {
this.parseExportNamespace(node);
} else {
this.parseExportFrom(node, true);
this.finishNode(node, "ExportAllDeclaration");
}
}
parseExportNamespace(node: N.ExportNamedDeclaration): void {
this.expectPlugin("exportNamespaceFrom");
const specifier = this.startNodeAt(
this.state.lastTokStart,
this.state.lastTokStartLoc,
);
this.next();
specifier.exported = this.parseIdentifier(true);
node.specifiers = [this.finishNode(specifier, "ExportNamespaceSpecifier")];
this.parseExportSpecifiersMaybe(node);
this.parseExportFrom(node, true);
}
shouldParseExportDeclaration(): boolean {
if (this.match(tt.at)) {
this.expectOnePlugin(["decorators", "decorators-legacy"]);
@@ -1662,9 +1754,9 @@ export default class StatementParser extends ExpressionParser {
return (
this.state.type.keyword === "var" ||
this.state.type.keyword === "const" ||
this.state.type.keyword === "let" ||
this.state.type.keyword === "function" ||
this.state.type.keyword === "class" ||
this.isLet() ||
this.isAsyncFunction()
);
}
@@ -1741,27 +1833,24 @@ export default class StatementParser extends ExpressionParser {
}
checkDuplicateExports(
node: N.Identifier | N.ExportNamedDeclaration | N.ExportSpecifier,
node:
| N.Identifier
| N.ExportNamedDeclaration
| N.ExportSpecifier
| N.ExportDefaultSpecifier,
name: string,
): void {
if (this.state.exportedIdentifiers.indexOf(name) > -1) {
this.raiseDuplicateExportError(node, name);
throw this.raise(
node.start,
name === "default"
? "Only one default export allowed per module."
: `\`${name}\` has already been exported. Exported identifiers must be unique.`,
);
}
this.state.exportedIdentifiers.push(name);
}
raiseDuplicateExportError(
node: N.Identifier | N.ExportNamedDeclaration | N.ExportSpecifier,
name: string,
): empty {
throw this.raise(
node.start,
name === "default"
? "Only one default export allowed per module."
: `\`${name}\` has already been exported. Exported identifiers must be unique.`,
);
}
// Parses a comma-separated list of module exports.
parseExportSpecifiers(): Array<N.ExportSpecifier> {
@@ -1801,23 +1890,26 @@ export default class StatementParser extends ExpressionParser {
// Parses import declaration.
parseImport(node: N.Node): N.ImportDeclaration | N.TsImportEqualsDeclaration {
parseImport(node: N.Node): N.AnyImport {
// import '...'
if (this.match(tt.string)) {
node.specifiers = [];
node.source = this.parseExprAtom();
} else {
node.specifiers = [];
this.parseImportSpecifiers(node);
node.specifiers = [];
if (!this.match(tt.string)) {
const hasDefault = this.maybeParseDefaultImportSpecifier(node);
const parseNext = !hasDefault || this.eat(tt.comma);
const hasStar = parseNext && this.maybeParseStarImportSpecifier(node);
if (parseNext && !hasStar) this.parseNamedImportSpecifiers(node);
this.expectContextual("from");
node.source = this.match(tt.string)
? this.parseExprAtom()
: this.unexpected();
}
node.source = this.parseImportSource();
this.semicolon();
return this.finishNode(node, "ImportDeclaration");
}
parseImportSource(): N.StringLiteral {
if (!this.match(tt.string)) this.unexpected();
return this.parseExprAtom();
}
// eslint-disable-next-line no-unused-vars
shouldParseDefaultImport(node: N.ImportDeclaration): boolean {
return this.match(tt.name);
@@ -1834,9 +1926,7 @@ export default class StatementParser extends ExpressionParser {
node.specifiers.push(this.finishNode(specifier, type));
}
// Parses a comma-separated list of module imports.
parseImportSpecifiers(node: N.ImportDeclaration): void {
let first = true;
maybeParseDefaultImportSpecifier(node: N.ImportDeclaration): boolean {
if (this.shouldParseDefaultImport(node)) {
// import defaultObj, { x, y as z } from '...'
this.parseImportSpecifierLocal(
@@ -1845,10 +1935,12 @@ export default class StatementParser extends ExpressionParser {
"ImportDefaultSpecifier",
"default import specifier",
);
if (!this.eat(tt.comma)) return;
return true;
}
return false;
}
maybeParseStarImportSpecifier(node: N.ImportDeclaration): boolean {
if (this.match(tt.star)) {
const specifier = this.startNode();
this.next();
@@ -1860,10 +1952,13 @@ export default class StatementParser extends ExpressionParser {
"ImportNamespaceSpecifier",
"import namespace specifier",
);
return;
return true;
}
return false;
}
parseNamedImportSpecifiers(node: N.ImportDeclaration) {
let first = true;
this.expect(tt.braceL);
while (!this.eat(tt.braceR)) {
if (first) {

View File

@@ -25,7 +25,7 @@ export default class UtilParser extends Tokenizer {
isLookaheadRelational(op: "<" | ">"): boolean {
const l = this.lookahead();
return l.type == tt.relational && l.value == op;
return l.type === tt.relational && l.value === op;
}
// TODO
@@ -87,7 +87,7 @@ export default class UtilParser extends Tokenizer {
hasPrecedingLineBreak(): boolean {
return lineBreak.test(
this.input.slice(this.state.lastTokEnd, this.state.start),
this.state.input.slice(this.state.lastTokEnd, this.state.start),
);
}
@@ -147,4 +147,22 @@ export default class UtilParser extends Tokenizer {
);
}
}
checkYieldAwaitInDefaultParams() {
if (
this.state.yieldPos &&
(!this.state.awaitPos || this.state.yieldPos < this.state.awaitPos)
) {
this.raise(
this.state.yieldPos,
"Yield cannot be used as name inside a generator function",
);
}
if (this.state.awaitPos) {
this.raise(
this.state.awaitPos,
"Await cannot be used as name inside an async function",
);
}
}
}

View File

@@ -344,7 +344,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
} else {
if (
this.match(tt._const) ||
this.match(tt._let) ||
this.isLet() ||
((this.isContextual("type") || this.isContextual("interface")) &&
!insideModule)
) {
@@ -1124,7 +1124,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.types = [];
this.expect(tt.bracketL);
// We allow trailing commas
while (this.state.pos < this.input.length && !this.match(tt.bracketR)) {
while (this.state.pos < this.state.length && !this.match(tt.bracketR)) {
node.types.push(this.flowParseType());
if (this.match(tt.bracketR)) break;
this.expect(tt.comma);
@@ -1190,9 +1190,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
case "any":
return this.finishNode(node, "AnyTypeAnnotation");
case "void":
return this.finishNode(node, "VoidTypeAnnotation");
case "bool":
case "boolean":
return this.finishNode(node, "BooleanTypeAnnotation");
@@ -1369,6 +1366,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
"NumberLiteralTypeAnnotation",
);
case tt._void:
this.next();
return this.finishNode(node, "VoidTypeAnnotation");
case tt._null:
this.next();
return this.finishNode(node, "NullLiteralTypeAnnotation");
@@ -1398,7 +1399,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
const startPos = this.state.start,
startLoc = this.state.startLoc;
let type = this.flowParsePrimaryType();
while (!this.canInsertSemicolon() && this.match(tt.bracketL)) {
while (this.match(tt.bracketL) && !this.canInsertSemicolon()) {
const node = this.startNodeAt(startPos, startLoc);
node.elementType = type;
this.expect(tt.bracketL);
@@ -1630,7 +1631,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.match(tt.name) &&
(this.state.value === "type" ||
this.state.value === "interface" ||
this.state.value == "opaque")
this.state.value === "opaque")
) {
return false;
}
@@ -1846,17 +1847,15 @@ export default (superClass: Class<Parser>): Class<Parser> =>
super.assertModuleNodeAllowed(node);
}
parseExport(
node: N.ExportNamedDeclaration | N.ExportAllDeclaration,
): N.ExportNamedDeclaration | N.ExportAllDeclaration {
node = super.parseExport(node);
parseExport(node: N.Node): N.AnyExport {
const decl = super.parseExport(node);
if (
node.type === "ExportNamedDeclaration" ||
node.type === "ExportAllDeclaration"
decl.type === "ExportNamedDeclaration" ||
decl.type === "ExportAllDeclaration"
) {
node.exportKind = node.exportKind || "value";
decl.exportKind = decl.exportKind || "value";
}
return node;
return decl;
}
parseExportDeclaration(node: N.ExportNamedDeclaration): ?N.Declaration {
@@ -1892,27 +1891,26 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}
shouldParseExportStar(): boolean {
return (
super.shouldParseExportStar() ||
(this.isContextual("type") && this.lookahead().type === tt.star)
);
}
eatExportStar(node: N.Node): boolean {
if (super.eatExportStar(...arguments)) return true;
parseExportStar(node: N.ExportNamedDeclaration): void {
if (this.eatContextual("type")) {
if (this.isContextual("type") && this.lookahead().type === tt.star) {
node.exportKind = "type";
this.next();
this.next();
return true;
}
return super.parseExportStar(node);
return false;
}
parseExportNamespace(node: N.ExportNamedDeclaration) {
if (node.exportKind === "type") {
this.unexpected();
maybeParseExportNamespaceSpecifier(node: N.Node): boolean {
const pos = this.state.start;
const hasNamespace = super.maybeParseExportNamespaceSpecifier(node);
if (hasNamespace && node.exportKind === "type") {
this.unexpected(pos);
}
return super.parseExportNamespace(node);
return hasNamespace;
}
parseClassId(node: N.Class, isStatement: boolean, optionalId: ?boolean) {
@@ -1922,20 +1920,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}
// don't consider `void` to be a keyword as then it'll use the void token type
// and set startExpr
isKeyword(name: string): boolean {
if (this.state.inType && name === "void") {
return false;
} else {
return super.isKeyword(name);
}
}
// ensure that inside flow types, we bypass the jsx parser plugin
readToken(code: number): void {
const next = this.input.charCodeAt(this.state.pos + 1);
if (
getTokenFromCode(code: number): void {
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (code === charCodes.leftCurlyBrace && next === charCodes.verticalBar) {
return this.finishOp(tt.braceBarL, 2);
} else if (
this.state.inType &&
(code === charCodes.greaterThan || code === charCodes.lessThan)
) {
@@ -1944,7 +1934,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.state.isIterator = true;
return super.readWord();
} else {
return super.readToken(code);
return super.getTokenFromCode(code);
}
}
@@ -2232,7 +2222,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
// parse typeof and type imports
parseImportSpecifiers(node: N.ImportDeclaration): void {
maybeParseDefaultImportSpecifier(node: N.ImportDeclaration): boolean {
node.importKind = "value";
let kind = null;
@@ -2259,7 +2249,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}
super.parseImportSpecifiers(node);
return super.maybeParseDefaultImportSpecifier(node);
}
// parse import-type/typeof shorthand
@@ -2354,8 +2344,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
// parse flow type annotations on variable declarator heads - let foo: string = bar
parseVarHead(decl: N.VariableDeclarator): void {
super.parseVarHead(decl);
parseVarId(
decl: N.VariableDeclarator,
kind: "var" | "let" | "const",
): void {
super.parseVarId(decl, kind);
if (this.match(tt.colon)) {
decl.id.typeAnnotation = this.flowParseTypeAnnotation();
this.finishNode(decl.id, decl.id.type);
@@ -2686,7 +2679,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
readToken_mult_modulo(code: number): void {
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (
code === charCodes.asterisk &&
next === charCodes.slash &&
@@ -2701,6 +2694,20 @@ export default (superClass: Class<Parser>): Class<Parser> =>
super.readToken_mult_modulo(code);
}
readToken_pipe_amp(code: number): void {
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (
code === charCodes.verticalBar &&
next === charCodes.rightCurlyBrace
) {
// '|}'
this.finishOp(tt.braceBarR, 2);
return;
}
super.readToken_pipe_amp(code);
}
parseTopLevel(file: N.File, program: N.Program): N.File {
const fileNode = super.parseTopLevel(file, program);
if (this.state.hasFlowComment) {
@@ -2710,11 +2717,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
skipBlockComment(): void {
if (
this.hasPlugin("flow") &&
this.hasPlugin("flowComments") &&
this.skipFlowComment()
) {
if (this.hasPlugin("flowComments") && this.skipFlowComment()) {
if (this.state.hasFlowComment) {
this.unexpected(
null,
@@ -2727,8 +2730,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return;
}
if (this.hasPlugin("flow") && this.state.hasFlowComment) {
const end = this.input.indexOf("*-/", (this.state.pos += 2));
if (this.state.hasFlowComment) {
const end = this.state.input.indexOf("*-/", (this.state.pos += 2));
if (end === -1) this.raise(this.state.pos - 2, "Unterminated comment");
this.state.pos = end + 3;
return;
@@ -2742,20 +2745,22 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let shiftToFirstNonWhiteSpace = 2;
while (
[charCodes.space, charCodes.tab].includes(
this.input.charCodeAt(pos + shiftToFirstNonWhiteSpace),
this.state.input.charCodeAt(pos + shiftToFirstNonWhiteSpace),
)
) {
shiftToFirstNonWhiteSpace++;
}
const ch2 = this.input.charCodeAt(shiftToFirstNonWhiteSpace + pos);
const ch3 = this.input.charCodeAt(shiftToFirstNonWhiteSpace + pos + 1);
const ch2 = this.state.input.charCodeAt(shiftToFirstNonWhiteSpace + pos);
const ch3 = this.state.input.charCodeAt(
shiftToFirstNonWhiteSpace + pos + 1,
);
if (ch2 === charCodes.colon && ch3 === charCodes.colon) {
return shiftToFirstNonWhiteSpace + 2; // check for /*::
}
if (
this.input.slice(
this.state.input.slice(
shiftToFirstNonWhiteSpace + pos,
shiftToFirstNonWhiteSpace + pos + 12,
) === "flow-include"
@@ -2769,7 +2774,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
hasFlowCommentCompletion(): void {
const end = this.input.indexOf("*/", this.state.pos);
const end = this.state.input.indexOf("*/", this.state.pos);
if (end === -1) {
this.raise(this.state.pos, "Unterminated comment");
}

View File

@@ -79,11 +79,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let out = "";
let chunkStart = this.state.pos;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(this.state.start, "Unterminated JSX contents");
}
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
switch (ch) {
case charCodes.lessThan:
@@ -93,20 +93,20 @@ export default (superClass: Class<Parser>): Class<Parser> =>
++this.state.pos;
return this.finishToken(tt.jsxTagStart);
}
return this.getTokenFromCode(ch);
return super.getTokenFromCode(ch);
}
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
return this.finishToken(tt.jsxText, out);
case charCodes.ampersand:
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
out += this.jsxReadEntity();
chunkStart = this.state.pos;
break;
default:
if (isNewLine(ch)) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
out += this.jsxReadNewLine(true);
chunkStart = this.state.pos;
} else {
@@ -117,12 +117,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
jsxReadNewLine(normalizeCRLF: boolean): string {
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
let out;
++this.state.pos;
if (
ch === charCodes.carriageReturn &&
this.input.charCodeAt(this.state.pos) === charCodes.lineFeed
this.state.input.charCodeAt(this.state.pos) === charCodes.lineFeed
) {
++this.state.pos;
out = normalizeCRLF ? "\n" : "\r\n";
@@ -139,25 +139,25 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let out = "";
let chunkStart = ++this.state.pos;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(this.state.start, "Unterminated string constant");
}
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
if (ch === quote) break;
if (ch === charCodes.ampersand) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
out += this.jsxReadEntity();
chunkStart = this.state.pos;
} else if (isNewLine(ch)) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
out += this.jsxReadNewLine(false);
chunkStart = this.state.pos;
} else {
++this.state.pos;
}
}
out += this.input.slice(chunkStart, this.state.pos++);
out += this.state.input.slice(chunkStart, this.state.pos++);
return this.finishToken(tt.string, out);
}
@@ -165,11 +165,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let str = "";
let count = 0;
let entity;
let ch = this.input[this.state.pos];
let ch = this.state.input[this.state.pos];
const startPos = ++this.state.pos;
while (this.state.pos < this.input.length && count++ < 10) {
ch = this.input[this.state.pos++];
while (this.state.pos < this.state.length && count++ < 10) {
ch = this.state.input[this.state.pos++];
if (ch === ";") {
if (str[0] === "#") {
if (str[1] === "x") {
@@ -208,11 +208,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
let ch;
const start = this.state.pos;
do {
ch = this.input.charCodeAt(++this.state.pos);
ch = this.state.input.charCodeAt(++this.state.pos);
} while (isIdentifierChar(ch) || ch === charCodes.dash);
return this.finishToken(
tt.jsxName,
this.input.slice(start, this.state.pos),
this.state.input.slice(start, this.state.pos),
);
}
@@ -520,8 +520,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}
readToken(code: number): void {
if (this.state.inPropertyName) return super.readToken(code);
getTokenFromCode(code: number): void {
if (this.state.inPropertyName) return super.getTokenFromCode(code);
const context = this.curContext();
@@ -557,7 +557,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishToken(tt.jsxTagStart);
}
return super.readToken(code);
return super.getTokenFromCode(code);
}
updateContext(prevType: TokenType): void {

View File

@@ -45,6 +45,8 @@ function keywordTypeFromName(
return "TSAnyKeyword";
case "boolean":
return "TSBooleanKeyword";
case "bigint":
return "TSBigIntKeyword";
case "never":
return "TSNeverKeyword";
case "number":
@@ -218,6 +220,28 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return result;
}
tsParseImportType(): N.TsImportType {
const node: N.TsImportType = this.startNode();
this.expect(tt._import);
this.expect(tt.parenL);
if (!this.match(tt.string)) {
throw this.unexpected(
null,
"Argument in a type import must be a string literal",
);
}
node.argument = this.parseLiteral(this.state.value, "StringLiteral");
this.expect(tt.parenR);
if (this.eat(tt.dot)) {
node.qualifier = this.tsParseEntityName(/* allowReservedWords */ true);
}
if (this.isRelational("<")) {
node.typeParameters = this.tsParseTypeArguments();
}
return this.finishNode(node, "TSImportType");
}
tsParseEntityName(allowReservedWords: boolean): N.TsEntityName {
let entity: N.TsEntityName = this.parseIdentifier();
while (this.eat(tt.dot)) {
@@ -240,7 +264,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
tsParseThisTypePredicate(lhs: N.TsThisType): N.TsTypePredicate {
this.next();
const node: N.TsTypePredicate = this.startNode();
const node: N.TsTypePredicate = this.startNodeAtNode(lhs);
node.parameterName = lhs;
node.typeAnnotation = this.tsParseTypeAnnotation(/* eatColon */ false);
return this.finishNode(node, "TSTypePredicate");
@@ -255,7 +279,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
tsParseTypeQuery(): N.TsTypeQuery {
const node: N.TsTypeQuery = this.startNode();
this.expect(tt._typeof);
node.exprName = this.tsParseEntityName(/* allowReservedWords */ true);
if (this.match(tt._import)) {
node.exprName = this.tsParseImportType();
} else {
node.exprName = this.tsParseEntityName(/* allowReservedWords */ true);
}
return this.finishNode(node, "TSTypeQuery");
}
@@ -370,8 +398,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.expect(tt.bracketL);
const id = this.parseIdentifier();
this.expect(tt.colon);
id.typeAnnotation = this.tsParseTypeAnnotation(/* eatColon */ false);
id.typeAnnotation = this.tsParseTypeAnnotation();
this.finishNode(id, "Identifier"); // set end position to end of type
this.expect(tt.bracketR);
node.parameters = [id];
@@ -518,17 +547,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// No mandatory elements may follow optional elements
// If there's a rest element, it must be at the end of the tuple
let seenOptionalElement = false;
node.elementTypes.forEach((elementNode, i) => {
if (elementNode.type === "TSRestType") {
if (i !== node.elementTypes.length - 1) {
this.raise(
elementNode.start,
"A rest element must be last in a tuple type.",
);
}
} else if (elementNode.type === "TSOptionalType") {
node.elementTypes.forEach(elementNode => {
if (elementNode.type === "TSOptionalType") {
seenOptionalElement = true;
} else if (seenOptionalElement) {
} else if (seenOptionalElement && elementNode.type !== "TSRestType") {
this.raise(
elementNode.start,
"A required element cannot follow an optional element.",
@@ -545,6 +567,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
const restNode: N.TsRestType = this.startNode();
this.next(); // skips ellipsis
restNode.typeAnnotation = this.tsParseType();
this.checkCommaAfterRest(tt.bracketR, "type");
return this.finishNode(restNode, "TSRestType");
}
@@ -643,6 +666,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
case tt._typeof:
return this.tsParseTypeQuery();
case tt._import:
return this.tsParseImportType();
case tt.braceL:
return this.tsLookAhead(this.tsIsStartOfMappedType.bind(this))
? this.tsParseMappedType()
@@ -894,6 +919,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
tsParseTypeAssertion(): N.TsTypeAssertion {
const node: N.TsTypeAssertion = this.startNode();
this.next(); // <
// Not actually necessary to set state.inType because we never reach here if JSX plugin is enabled,
// but need `tsInType` to satisfy the assertion in `tsParseType`.
node.typeAnnotation = this.tsInType(() => this.tsParseType());
@@ -902,11 +928,21 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.finishNode(node, "TSTypeAssertion");
}
tsParseHeritageClause(): $ReadOnlyArray<N.TsExpressionWithTypeArguments> {
return this.tsParseDelimitedList(
tsParseHeritageClause(
descriptor: string,
): $ReadOnlyArray<N.TsExpressionWithTypeArguments> {
const originalStart = this.state.start;
const delimitedList = this.tsParseDelimitedList(
"HeritageClauseElement",
this.tsParseExpressionWithTypeArguments.bind(this),
);
if (!delimitedList.length) {
this.raise(originalStart, `'${descriptor}' list cannot be empty.`);
}
return delimitedList;
}
tsParseExpressionWithTypeArguments(): N.TsExpressionWithTypeArguments {
@@ -927,7 +963,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.id = this.parseIdentifier();
node.typeParameters = this.tsTryParseTypeParameters();
if (this.eat(tt._extends)) {
node.extends = this.tsParseHeritageClause();
node.extends = this.tsParseHeritageClause("extends");
}
const body: N.TSInterfaceBody = this.startNode();
body.body = this.tsInType(this.tsParseObjectTypeMembers.bind(this));
@@ -1151,7 +1187,18 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
tsTryParseDeclare(nany: any): ?N.Declaration {
switch (this.state.type) {
if (this.isLineTerminator()) {
return;
}
let starttype = this.state.type;
let kind;
if (this.isContextual("let")) {
starttype = tt._var;
kind = "let";
}
switch (starttype) {
case tt._function:
this.next();
return this.parseFunction(nany, /* isStatement */ true);
@@ -1170,8 +1217,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
// falls through
case tt._var:
case tt._let:
return this.parseVarStatement(nany, this.state.type);
kind = kind || this.state.value;
return this.parseVarStatement(nany, kind);
case tt.name: {
const value = this.state.value;
if (value === "global") {
@@ -1227,10 +1274,15 @@ export default (superClass: Class<Parser>): Class<Parser> =>
): ?N.Declaration {
switch (value) {
case "abstract":
if (next || this.match(tt._class)) {
if (this.tsCheckLineTerminatorAndMatch(tt._class, next)) {
const cls: N.ClassDeclaration = node;
cls.abstract = true;
if (next) this.next();
if (next) {
this.next();
if (!this.match(tt._class)) {
this.unexpected(null, tt._class);
}
}
return this.parseClass(
cls,
/* isStatement */ true,
@@ -1247,7 +1299,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
break;
case "interface":
if (next || this.match(tt.name)) {
if (this.tsCheckLineTerminatorAndMatch(tt.name, next)) {
if (next) this.next();
return this.tsParseInterfaceDeclaration(node);
}
@@ -1257,20 +1309,20 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (next) this.next();
if (this.match(tt.string)) {
return this.tsParseAmbientExternalModuleDeclaration(node);
} else if (next || this.match(tt.name)) {
} else if (this.tsCheckLineTerminatorAndMatch(tt.name, next)) {
return this.tsParseModuleOrNamespaceDeclaration(node);
}
break;
case "namespace":
if (next || this.match(tt.name)) {
if (this.tsCheckLineTerminatorAndMatch(tt.name, next)) {
if (next) this.next();
return this.tsParseModuleOrNamespaceDeclaration(node);
}
break;
case "type":
if (next || this.match(tt.name)) {
if (this.tsCheckLineTerminatorAndMatch(tt.name, next)) {
if (next) this.next();
return this.tsParseTypeAliasDeclaration(node);
}
@@ -1278,6 +1330,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}
tsCheckLineTerminatorAndMatch(tokenType: TokenType, next: boolean) {
return (next || this.match(tokenType)) && !this.isLineTerminator();
}
tsTryParseGenericAsyncArrowFunction(
startPos: number,
startLoc: Position,
@@ -1362,6 +1418,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
allowModifiers: ?boolean,
decorators: N.Decorator[],
): N.Pattern | N.TSParameterProperty {
// Store original location/position to include modifiers in range
const startPos = this.state.start;
const startLoc = this.state.startLoc;
let accessibility: ?N.Accessibility;
let readonly = false;
if (allowModifiers) {
@@ -1373,7 +1433,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.parseAssignableListItemTypes(left);
const elt = this.parseMaybeDefault(left.start, left.loc.start, left);
if (accessibility || readonly) {
const pp: N.TSParameterProperty = this.startNodeAtNode(elt);
const pp: N.TSParameterProperty = this.startNodeAt(startPos, startLoc);
if (decorators.length) {
pp.decorators = decorators;
}
@@ -1387,12 +1447,13 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
pp.parameter = elt;
return this.finishNode(pp, "TSParameterProperty");
} else {
if (decorators.length) {
left.decorators = decorators;
}
return elt;
}
if (decorators.length) {
left.decorators = decorators;
}
return elt;
}
parseFunctionBodyAndFinish(
@@ -1561,16 +1622,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
*/
checkDuplicateExports() {}
parseImport(
node: N.Node,
): N.ImportDeclaration | N.TsImportEqualsDeclaration {
parseImport(node: N.Node): N.AnyImport {
if (this.match(tt.name) && this.lookahead().type === tt.eq) {
return this.tsParseImportEqualsDeclaration(node);
}
return super.parseImport(node);
}
parseExport(node: N.Node): N.Node {
parseExport(node: N.Node): N.AnyExport {
if (this.match(tt._import)) {
// `export import A = B;`
this.expect(tt._import);
@@ -1794,10 +1853,15 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
parseExportDeclaration(node: N.ExportNamedDeclaration): ?N.Declaration {
// Store original location/position
const startPos = this.state.start;
const startLoc = this.state.startLoc;
// "export declare" is equivalent to just "export".
const isDeclare = this.eatContextual("declare");
let declaration: ?N.Declaration;
if (this.match(tt.name)) {
declaration = this.tsTryParseExportDeclaration();
}
@@ -1806,6 +1870,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
if (declaration && isDeclare) {
// Reset location to include `declare` in range
this.resetStartLocation(declaration, startPos, startLoc);
declaration.declare = true;
}
@@ -1871,7 +1938,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.superTypeParameters = this.tsParseTypeArguments();
}
if (this.eatContextual("implements")) {
node.implements = this.tsParseHeritageClause();
node.implements = this.tsParseHeritageClause("implements");
}
}
@@ -1889,8 +1956,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
// `let x: number;`
parseVarHead(decl: N.VariableDeclarator): void {
super.parseVarHead(decl);
parseVarId(
decl: N.VariableDeclarator,
kind: "var" | "let" | "const",
): void {
super.parseVarId(decl, kind);
if (decl.id.type === "Identifier" && this.eat(tt.bang)) {
decl.definite = true;
}
@@ -1983,10 +2053,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// Correct TypeScript code should have at least 1 type parameter, but don't crash on bad code.
if (typeParameters && typeParameters.params.length !== 0) {
this.resetStartLocationFromNode(
arrowExpression,
typeParameters.params[0],
);
this.resetStartLocationFromNode(arrowExpression, typeParameters);
}
arrowExpression.typeParameters = typeParameters;
return arrowExpression;
@@ -1994,7 +2061,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// Handle type assertions
parseMaybeUnary(refShorthandDefaultPos?: ?Pos): N.Expression {
if (!this.hasPlugin("jsx") && this.eatRelational("<")) {
if (!this.hasPlugin("jsx") && this.isRelational("<")) {
return this.tsParseTypeAssertion();
} else {
return super.parseMaybeUnary(refShorthandDefaultPos);
@@ -2167,11 +2234,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
// ensure that inside types, we bypass the jsx parser plugin
readToken(code: number): void {
getTokenFromCode(code: number): void {
if (this.state.inType && (code === 62 || code === 60)) {
return this.finishOp(tt.relational, 1);
} else {
return super.readToken(code);
return super.getTokenFromCode(code);
}
}

View File

@@ -107,7 +107,9 @@ tt._function.updateContext = tt._class.updateContext = function(prevType) {
prevType !== tt._else &&
!(
prevType === tt._return &&
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start))
lineBreak.test(
this.state.input.slice(this.state.lastTokEnd, this.state.start),
)
) &&
!(
(prevType === tt.colon || prevType === tt.braceL) &&

View File

@@ -3,11 +3,7 @@
import type { Options } from "../options";
import type { Position } from "../util/location";
import * as charCodes from "charcodes";
import {
isIdentifierStart,
isIdentifierChar,
isKeyword,
} from "../util/identifier";
import { isIdentifierStart, isIdentifierChar } from "../util/identifier";
import { types as tt, keywords as keywordTypes, type TokenType } from "./types";
import { type TokContext, types as ct } from "./context";
import LocationParser from "../parser/location";
@@ -20,7 +16,7 @@ import {
} from "../util/whitespace";
import State from "./state";
const VALID_REGEX_FLAGS = "gmsiyu";
const VALID_REGEX_FLAGS = new Set(["g", "m", "s", "i", "y", "u"]);
// The following character codes are forbidden from being
// an immediate sibling of NumericLiteralSeparator _
@@ -157,12 +153,6 @@ export default class Tokenizer extends LocationParser {
// TODO
isKeyword(word: string): boolean {
return isKeyword(word);
}
// TODO
lookahead(): State {
const old = this.state;
this.state = old.clone(true);
@@ -185,7 +175,7 @@ export default class Tokenizer extends LocationParser {
this.state.pos = this.state.start;
while (this.state.pos < this.state.lineStart) {
this.state.lineStart =
this.input.lastIndexOf("\n", this.state.lineStart - 2) + 1;
this.state.input.lastIndexOf("\n", this.state.lineStart - 2) + 1;
--this.state.curLine;
}
this.nextToken();
@@ -206,7 +196,7 @@ export default class Tokenizer extends LocationParser {
this.state.octalPosition = null;
this.state.start = this.state.pos;
this.state.startLoc = this.state.curPosition();
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.finishToken(tt.eof);
return;
}
@@ -214,17 +204,7 @@ export default class Tokenizer extends LocationParser {
if (curContext.override) {
curContext.override(this);
} else {
this.readToken(this.input.codePointAt(this.state.pos));
}
}
readToken(code: number): void {
// Identifier or keyword. '\uXXXX' sequences are allowed in
// identifiers, so '\' also dispatches to that.
if (isIdentifierStart(code) || code === charCodes.backslash) {
this.readWord();
} else {
this.getTokenFromCode(code);
this.getTokenFromCode(this.state.input.codePointAt(this.state.pos));
}
}
@@ -254,14 +234,14 @@ export default class Tokenizer extends LocationParser {
skipBlockComment(): void {
const startLoc = this.state.curPosition();
const start = this.state.pos;
const end = this.input.indexOf("*/", (this.state.pos += 2));
const end = this.state.input.indexOf("*/", (this.state.pos += 2));
if (end === -1) this.raise(this.state.pos - 2, "Unterminated comment");
this.state.pos = end + 2;
lineBreakG.lastIndex = start;
let match;
while (
(match = lineBreakG.exec(this.input)) &&
(match = lineBreakG.exec(this.state.input)) &&
match.index < this.state.pos
) {
++this.state.curLine;
@@ -270,7 +250,7 @@ export default class Tokenizer extends LocationParser {
this.pushComment(
true,
this.input.slice(start + 2, end),
this.state.input.slice(start + 2, end),
start,
this.state.pos,
startLoc,
@@ -281,22 +261,22 @@ export default class Tokenizer extends LocationParser {
skipLineComment(startSkip: number): void {
const start = this.state.pos;
const startLoc = this.state.curPosition();
let ch = this.input.charCodeAt((this.state.pos += startSkip));
if (this.state.pos < this.input.length) {
let ch = this.state.input.charCodeAt((this.state.pos += startSkip));
if (this.state.pos < this.state.length) {
while (
ch !== charCodes.lineFeed &&
ch !== charCodes.carriageReturn &&
ch !== charCodes.lineSeparator &&
ch !== charCodes.paragraphSeparator &&
++this.state.pos < this.input.length
++this.state.pos < this.state.length
) {
ch = this.input.charCodeAt(this.state.pos);
ch = this.state.input.charCodeAt(this.state.pos);
}
}
this.pushComment(
false,
this.input.slice(start + startSkip, this.state.pos),
this.state.input.slice(start + startSkip, this.state.pos),
start,
this.state.pos,
startLoc,
@@ -308,12 +288,18 @@ export default class Tokenizer extends LocationParser {
// whitespace and comments, and.
skipSpace(): void {
loop: while (this.state.pos < this.input.length) {
const ch = this.input.charCodeAt(this.state.pos);
loop: while (this.state.pos < this.state.length) {
const ch = this.state.input.charCodeAt(this.state.pos);
switch (ch) {
case charCodes.space:
case charCodes.nonBreakingSpace:
case charCodes.tab:
++this.state.pos;
break;
case charCodes.carriageReturn:
if (
this.input.charCodeAt(this.state.pos + 1) === charCodes.lineFeed
this.state.input.charCodeAt(this.state.pos + 1) ===
charCodes.lineFeed
) {
++this.state.pos;
}
@@ -327,7 +313,7 @@ export default class Tokenizer extends LocationParser {
break;
case charCodes.slash:
switch (this.input.charCodeAt(this.state.pos + 1)) {
switch (this.state.input.charCodeAt(this.state.pos + 1)) {
case charCodes.asterisk:
this.skipBlockComment();
break;
@@ -382,7 +368,7 @@ export default class Tokenizer extends LocationParser {
}
const nextPos = this.state.pos + 1;
const next = this.input.charCodeAt(nextPos);
const next = this.state.input.charCodeAt(nextPos);
if (next >= charCodes.digit0 && next <= charCodes.digit9) {
this.raise(this.state.pos, "Unexpected digit after hash token");
}
@@ -405,13 +391,13 @@ export default class Tokenizer extends LocationParser {
}
readToken_dot(): void {
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next >= charCodes.digit0 && next <= charCodes.digit9) {
this.readNumber(true);
return;
}
const next2 = this.input.charCodeAt(this.state.pos + 2);
const next2 = this.state.input.charCodeAt(this.state.pos + 2);
if (next === charCodes.dot && next2 === charCodes.dot) {
this.state.pos += 3;
this.finishToken(tt.ellipsis);
@@ -429,7 +415,7 @@ export default class Tokenizer extends LocationParser {
return;
}
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(tt.assign, 2);
} else {
@@ -438,12 +424,12 @@ export default class Tokenizer extends LocationParser {
}
readToken_interpreter(): boolean {
if (this.state.pos !== 0 || this.state.input.length < 2) return false;
if (this.state.pos !== 0 || this.state.length < 2) return false;
const start = this.state.pos;
this.state.pos += 1;
let ch = this.input.charCodeAt(this.state.pos);
let ch = this.state.input.charCodeAt(this.state.pos);
if (ch !== charCodes.exclamationMark) return false;
while (
@@ -451,12 +437,12 @@ export default class Tokenizer extends LocationParser {
ch !== charCodes.carriageReturn &&
ch !== charCodes.lineSeparator &&
ch !== charCodes.paragraphSeparator &&
++this.state.pos < this.input.length
++this.state.pos < this.state.length
) {
ch = this.input.charCodeAt(this.state.pos);
ch = this.state.input.charCodeAt(this.state.pos);
}
const value = this.input.slice(start + 2, this.state.pos);
const value = this.state.input.slice(start + 2, this.state.pos);
this.finishToken(tt.interpreterDirective, value);
@@ -467,13 +453,13 @@ export default class Tokenizer extends LocationParser {
// '%*'
let type = code === charCodes.asterisk ? tt.star : tt.modulo;
let width = 1;
let next = this.input.charCodeAt(this.state.pos + 1);
let next = this.state.input.charCodeAt(this.state.pos + 1);
const exprAllowed = this.state.exprAllowed;
// Exponentiation operator **
if (code === charCodes.asterisk && next === charCodes.asterisk) {
width++;
next = this.input.charCodeAt(this.state.pos + 2);
next = this.state.input.charCodeAt(this.state.pos + 2);
type = tt.exponent;
}
@@ -486,11 +472,13 @@ export default class Tokenizer extends LocationParser {
}
readToken_pipe_amp(code: number): void {
// '|&'
const next = this.input.charCodeAt(this.state.pos + 1);
// '||' '&&' '||=' '&&='
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === code) {
if (this.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo) {
if (
this.state.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo
) {
this.finishOp(tt.assign, 3);
} else {
this.finishOp(
@@ -506,10 +494,6 @@ export default class Tokenizer extends LocationParser {
if (next === charCodes.greaterThan) {
this.finishOp(tt.pipeline, 2);
return;
} else if (next === charCodes.rightCurlyBrace && this.hasPlugin("flow")) {
// '|}'
this.finishOp(tt.braceBarR, 2);
return;
}
}
@@ -526,7 +510,7 @@ export default class Tokenizer extends LocationParser {
readToken_caret(): void {
// '^'
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(tt.assign, 2);
} else {
@@ -536,14 +520,17 @@ export default class Tokenizer extends LocationParser {
readToken_plus_min(code: number): void {
// '+-'
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === code) {
if (
next === charCodes.dash &&
!this.inModule &&
this.input.charCodeAt(this.state.pos + 2) === charCodes.greaterThan &&
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.pos))
this.state.input.charCodeAt(this.state.pos + 2) ===
charCodes.greaterThan &&
lineBreak.test(
this.state.input.slice(this.state.lastTokEnd, this.state.pos),
)
) {
// A `-->` line comment
this.skipLineComment(3);
@@ -564,16 +551,20 @@ export default class Tokenizer extends LocationParser {
readToken_lt_gt(code: number): void {
// '<>'
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
let size = 1;
if (next === code) {
size =
code === charCodes.greaterThan &&
this.input.charCodeAt(this.state.pos + 2) === charCodes.greaterThan
this.state.input.charCodeAt(this.state.pos + 2) ===
charCodes.greaterThan
? 3
: 2;
if (this.input.charCodeAt(this.state.pos + size) === charCodes.equalsTo) {
if (
this.state.input.charCodeAt(this.state.pos + size) ===
charCodes.equalsTo
) {
this.finishOp(tt.assign, size + 1);
return;
}
@@ -585,8 +576,8 @@ export default class Tokenizer extends LocationParser {
next === charCodes.exclamationMark &&
code === charCodes.lessThan &&
!this.inModule &&
this.input.charCodeAt(this.state.pos + 2) === charCodes.dash &&
this.input.charCodeAt(this.state.pos + 3) === charCodes.dash
this.state.input.charCodeAt(this.state.pos + 2) === charCodes.dash &&
this.state.input.charCodeAt(this.state.pos + 3) === charCodes.dash
) {
// `<!--`, an XML-style comment that should be interpreted as a line comment
this.skipLineComment(4);
@@ -605,11 +596,11 @@ export default class Tokenizer extends LocationParser {
readToken_eq_excl(code: number): void {
// '=!'
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(
tt.equality,
this.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo
this.state.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo
? 3
: 2,
);
@@ -626,8 +617,8 @@ export default class Tokenizer extends LocationParser {
readToken_question(): void {
// '?'
const next = this.input.charCodeAt(this.state.pos + 1);
const next2 = this.input.charCodeAt(this.state.pos + 2);
const next = this.state.input.charCodeAt(this.state.pos + 1);
const next2 = this.state.input.charCodeAt(this.state.pos + 2);
if (next === charCodes.questionMark && !this.state.inType) {
if (next2 === charCodes.equalsTo) {
// '??='
@@ -651,10 +642,6 @@ export default class Tokenizer extends LocationParser {
getTokenFromCode(code: number): void {
switch (code) {
case charCodes.numberSign:
this.readToken_numberSign();
return;
// The interpretation of a dot depends on whether it is followed
// by a digit or another two dots.
@@ -687,19 +674,10 @@ export default class Tokenizer extends LocationParser {
++this.state.pos;
this.finishToken(tt.bracketR);
return;
case charCodes.leftCurlyBrace:
if (
this.hasPlugin("flow") &&
this.input.charCodeAt(this.state.pos + 1) === charCodes.verticalBar
) {
this.finishOp(tt.braceBarL, 2);
} else {
++this.state.pos;
this.finishToken(tt.braceL);
}
++this.state.pos;
this.finishToken(tt.braceL);
return;
case charCodes.rightCurlyBrace:
++this.state.pos;
this.finishToken(tt.braceR);
@@ -708,7 +686,7 @@ export default class Tokenizer extends LocationParser {
case charCodes.colon:
if (
this.hasPlugin("functionBind") &&
this.input.charCodeAt(this.state.pos + 1) === charCodes.colon
this.state.input.charCodeAt(this.state.pos + 1) === charCodes.colon
) {
this.finishOp(tt.doubleColon, 2);
} else {
@@ -720,10 +698,6 @@ export default class Tokenizer extends LocationParser {
case charCodes.questionMark:
this.readToken_question();
return;
case charCodes.atSign:
++this.state.pos;
this.finishToken(tt.at);
return;
case charCodes.graveAccent:
++this.state.pos;
@@ -731,7 +705,7 @@ export default class Tokenizer extends LocationParser {
return;
case charCodes.digit0: {
const next = this.input.charCodeAt(this.state.pos + 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
// '0x', '0X' - hex number
if (next === charCodes.lowercaseX || next === charCodes.uppercaseX) {
this.readRadixNumber(16);
@@ -809,6 +783,25 @@ export default class Tokenizer extends LocationParser {
case charCodes.tilde:
this.finishOp(tt.tilde, 1);
return;
case charCodes.atSign:
++this.state.pos;
this.finishToken(tt.at);
return;
case charCodes.numberSign:
this.readToken_numberSign();
return;
case charCodes.backslash:
this.readWord();
return;
default:
if (isIdentifierStart(code)) {
this.readWord();
return;
}
}
this.raise(
@@ -818,7 +811,7 @@ export default class Tokenizer extends LocationParser {
}
finishOp(type: TokenType, size: number): void {
const str = this.input.slice(this.state.pos, this.state.pos + size);
const str = this.state.input.slice(this.state.pos, this.state.pos + size);
this.state.pos += size;
this.finishToken(type, str);
}
@@ -827,10 +820,10 @@ export default class Tokenizer extends LocationParser {
const start = this.state.pos;
let escaped, inClass;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(start, "Unterminated regular expression");
}
const ch = this.input.charAt(this.state.pos);
const ch = this.state.input.charAt(this.state.pos);
if (lineBreak.test(ch)) {
this.raise(start, "Unterminated regular expression");
}
@@ -848,16 +841,16 @@ export default class Tokenizer extends LocationParser {
}
++this.state.pos;
}
const content = this.input.slice(start, this.state.pos);
const content = this.state.input.slice(start, this.state.pos);
++this.state.pos;
let mods = "";
while (this.state.pos < this.input.length) {
const char = this.input[this.state.pos];
const charCode = this.input.codePointAt(this.state.pos);
while (this.state.pos < this.state.length) {
const char = this.state.input[this.state.pos];
const charCode = this.state.input.codePointAt(this.state.pos);
if (VALID_REGEX_FLAGS.indexOf(char) > -1) {
if (VALID_REGEX_FLAGS.has(char)) {
if (mods.indexOf(char) > -1) {
this.raise(this.state.pos + 1, "Duplicate regular expression flag");
}
@@ -902,12 +895,12 @@ export default class Tokenizer extends LocationParser {
let total = 0;
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
const code = this.input.charCodeAt(this.state.pos);
const code = this.state.input.charCodeAt(this.state.pos);
let val;
if (this.hasPlugin("numericSeparator")) {
const prev = this.input.charCodeAt(this.state.pos - 1);
const next = this.input.charCodeAt(this.state.pos + 1);
const prev = this.state.input.charCodeAt(this.state.pos - 1);
const next = this.state.input.charCodeAt(this.state.pos + 1);
if (code === charCodes.underscore) {
if (allowedSiblings.indexOf(next) === -1) {
this.raise(this.state.pos, "Invalid or unexpected token");
@@ -961,18 +954,22 @@ export default class Tokenizer extends LocationParser {
}
if (this.hasPlugin("bigInt")) {
if (this.input.charCodeAt(this.state.pos) === charCodes.lowercaseN) {
if (
this.state.input.charCodeAt(this.state.pos) === charCodes.lowercaseN
) {
++this.state.pos;
isBigInt = true;
}
}
if (isIdentifierStart(this.input.codePointAt(this.state.pos))) {
if (isIdentifierStart(this.state.input.codePointAt(this.state.pos))) {
this.raise(this.state.pos, "Identifier directly after number");
}
if (isBigInt) {
const str = this.input.slice(start, this.state.pos).replace(/[_n]/g, "");
const str = this.state.input
.slice(start, this.state.pos)
.replace(/[_n]/g, "");
this.finishToken(tt.bigint, str);
return;
}
@@ -992,7 +989,7 @@ export default class Tokenizer extends LocationParser {
}
let octal =
this.state.pos - start >= 2 &&
this.input.charCodeAt(start) === charCodes.digit0;
this.state.input.charCodeAt(start) === charCodes.digit0;
if (octal) {
if (this.state.strict) {
this.raise(
@@ -1000,30 +997,30 @@ export default class Tokenizer extends LocationParser {
"Legacy octal literals are not allowed in strict mode",
);
}
if (/[89]/.test(this.input.slice(start, this.state.pos))) {
if (/[89]/.test(this.state.input.slice(start, this.state.pos))) {
octal = false;
}
}
let next = this.input.charCodeAt(this.state.pos);
let next = this.state.input.charCodeAt(this.state.pos);
if (next === charCodes.dot && !octal) {
++this.state.pos;
this.readInt(10);
isFloat = true;
next = this.input.charCodeAt(this.state.pos);
next = this.state.input.charCodeAt(this.state.pos);
}
if (
(next === charCodes.uppercaseE || next === charCodes.lowercaseE) &&
!octal
) {
next = this.input.charCodeAt(++this.state.pos);
next = this.state.input.charCodeAt(++this.state.pos);
if (next === charCodes.plusSign || next === charCodes.dash) {
++this.state.pos;
}
if (this.readInt(10) === null) this.raise(start, "Invalid number");
isFloat = true;
next = this.input.charCodeAt(this.state.pos);
next = this.state.input.charCodeAt(this.state.pos);
}
if (this.hasPlugin("bigInt")) {
@@ -1035,12 +1032,14 @@ export default class Tokenizer extends LocationParser {
}
}
if (isIdentifierStart(this.input.codePointAt(this.state.pos))) {
if (isIdentifierStart(this.state.input.codePointAt(this.state.pos))) {
this.raise(this.state.pos, "Identifier directly after number");
}
// remove "_" for numeric literal separator, and "n" for BigInts
const str = this.input.slice(start, this.state.pos).replace(/[_n]/g, "");
const str = this.state.input
.slice(start, this.state.pos)
.replace(/[_n]/g, "");
if (isBigInt) {
this.finishToken(tt.bigint, str);
@@ -1054,13 +1053,13 @@ export default class Tokenizer extends LocationParser {
// Read a string value, interpreting backslash-escapes.
readCodePoint(throwOnInvalid: boolean): number | null {
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
let code;
if (ch === charCodes.leftCurlyBrace) {
const codePos = ++this.state.pos;
code = this.readHexChar(
this.input.indexOf("}", this.state.pos) - this.state.pos,
this.state.input.indexOf("}", this.state.pos) - this.state.pos,
throwOnInvalid,
);
++this.state.pos;
@@ -1085,13 +1084,13 @@ export default class Tokenizer extends LocationParser {
let out = "",
chunkStart = ++this.state.pos;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(this.state.start, "Unterminated string constant");
}
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
if (ch === quote) break;
if (ch === charCodes.backslash) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
// $FlowFixMe
out += this.readEscapedChar(false);
chunkStart = this.state.pos;
@@ -1107,7 +1106,7 @@ export default class Tokenizer extends LocationParser {
++this.state.pos;
}
}
out += this.input.slice(chunkStart, this.state.pos++);
out += this.state.input.slice(chunkStart, this.state.pos++);
this.finishToken(tt.string, out);
}
@@ -1118,14 +1117,14 @@ export default class Tokenizer extends LocationParser {
chunkStart = this.state.pos,
containsInvalid = false;
for (;;) {
if (this.state.pos >= this.input.length) {
if (this.state.pos >= this.state.length) {
this.raise(this.state.start, "Unterminated template");
}
const ch = this.input.charCodeAt(this.state.pos);
const ch = this.state.input.charCodeAt(this.state.pos);
if (
ch === charCodes.graveAccent ||
(ch === charCodes.dollarSign &&
this.input.charCodeAt(this.state.pos + 1) ===
this.state.input.charCodeAt(this.state.pos + 1) ===
charCodes.leftCurlyBrace)
) {
if (this.state.pos === this.state.start && this.match(tt.template)) {
@@ -1139,12 +1138,12 @@ export default class Tokenizer extends LocationParser {
return;
}
}
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
this.finishToken(tt.template, containsInvalid ? null : out);
return;
}
if (ch === charCodes.backslash) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
const escaped = this.readEscapedChar(true);
if (escaped === null) {
containsInvalid = true;
@@ -1153,11 +1152,13 @@ export default class Tokenizer extends LocationParser {
}
chunkStart = this.state.pos;
} else if (isNewLine(ch)) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.state.input.slice(chunkStart, this.state.pos);
++this.state.pos;
switch (ch) {
case charCodes.carriageReturn:
if (this.input.charCodeAt(this.state.pos) === charCodes.lineFeed) {
if (
this.state.input.charCodeAt(this.state.pos) === charCodes.lineFeed
) {
++this.state.pos;
}
case charCodes.lineFeed:
@@ -1180,7 +1181,7 @@ export default class Tokenizer extends LocationParser {
readEscapedChar(inTemplate: boolean): string | null {
const throwOnInvalid = !inTemplate;
const ch = this.input.charCodeAt(++this.state.pos);
const ch = this.state.input.charCodeAt(++this.state.pos);
++this.state.pos;
switch (ch) {
case charCodes.lowercaseN:
@@ -1204,18 +1205,22 @@ export default class Tokenizer extends LocationParser {
case charCodes.lowercaseF:
return "\f";
case charCodes.carriageReturn:
if (this.input.charCodeAt(this.state.pos) === charCodes.lineFeed) {
if (
this.state.input.charCodeAt(this.state.pos) === charCodes.lineFeed
) {
++this.state.pos;
}
case charCodes.lineFeed:
this.state.lineStart = this.state.pos;
++this.state.curLine;
case charCodes.lineSeparator:
case charCodes.paragraphSeparator:
return "";
default:
if (ch >= charCodes.digit0 && ch <= charCodes.digit7) {
const codePos = this.state.pos - 1;
// $FlowFixMe
let octalStr = this.input
let octalStr = this.state.input
.substr(this.state.pos - 1, 3)
.match(/^[0-7]+/)[0];
let octal = parseInt(octalStr, 8);
@@ -1239,6 +1244,7 @@ export default class Tokenizer extends LocationParser {
this.state.pos += octalStr.length - 1;
return String.fromCharCode(octal);
}
return String.fromCharCode(ch);
}
}
@@ -1266,23 +1272,28 @@ export default class Tokenizer extends LocationParser {
// as a micro-optimization.
readWord1(): string {
let word = "";
this.state.containsEsc = false;
let word = "",
first = true,
chunkStart = this.state.pos;
while (this.state.pos < this.input.length) {
const ch = this.input.codePointAt(this.state.pos);
const start = this.state.pos;
let chunkStart = this.state.pos;
while (this.state.pos < this.state.length) {
const ch = this.state.input.codePointAt(this.state.pos);
if (isIdentifierChar(ch)) {
this.state.pos += ch <= 0xffff ? 1 : 2;
} else if (this.state.isIterator && ch === charCodes.atSign) {
this.state.pos += 1;
++this.state.pos;
} else if (ch === charCodes.backslash) {
this.state.containsEsc = true;
word += this.input.slice(chunkStart, this.state.pos);
word += this.state.input.slice(chunkStart, this.state.pos);
const escStart = this.state.pos;
const identifierCheck =
this.state.pos === start ? isIdentifierStart : isIdentifierChar;
if (this.input.charCodeAt(++this.state.pos) !== charCodes.lowercaseU) {
if (
this.state.input.charCodeAt(++this.state.pos) !== charCodes.lowercaseU
) {
this.raise(
this.state.pos,
"Expecting Unicode escape sequence \\uXXXX",
@@ -1291,8 +1302,11 @@ export default class Tokenizer extends LocationParser {
++this.state.pos;
const esc = this.readCodePoint(true);
// $FlowFixMe (thinks esc may be null, but throwOnInvalid is true)
if (!(first ? isIdentifierStart : isIdentifierChar)(esc, true)) {
if (
// $FlowFixMe (thinks esc may be null, but throwOnInvalid is true)
!identifierCheck(esc, true)
) {
this.raise(escStart, "Invalid Unicode escape");
}
@@ -1302,9 +1316,8 @@ export default class Tokenizer extends LocationParser {
} else {
break;
}
first = false;
}
return word + this.input.slice(chunkStart, this.state.pos);
return word + this.state.input.slice(chunkStart, this.state.pos);
}
isIterator(word: string): boolean {
@@ -1316,14 +1329,10 @@ export default class Tokenizer extends LocationParser {
readWord(): void {
const word = this.readWord1();
let type = tt.name;
const type = keywordTypes[word] || tt.name;
if (this.isKeyword(word)) {
if (this.state.containsEsc) {
this.raise(this.state.pos, `Escape sequence in keyword ${word}`);
}
type = keywordTypes[word];
if (type.keyword && this.state.containsEsc) {
this.raise(this.state.pos, `Escape sequence in keyword ${word}`);
}
// Allow @@iterator and @@asyncIterator as a identifier only inside type
@@ -1354,11 +1363,10 @@ export default class Tokenizer extends LocationParser {
// `tt.name`.
if (
prevType === tt._return ||
prevType === tt._yield ||
(prevType === tt.name && this.state.exprAllowed)
) {
return lineBreak.test(
this.input.slice(this.state.lastTokEnd, this.state.start),
this.state.input.slice(this.state.lastTokEnd, this.state.start),
);
}
@@ -1378,8 +1386,8 @@ export default class Tokenizer extends LocationParser {
if (
prevType === tt._var ||
prevType === tt._let ||
prevType === tt._const
prevType === tt._const ||
prevType === tt.name
) {
return false;
}

View File

@@ -6,95 +6,52 @@ import { Position } from "../util/location";
import { types as ct, type TokContext } from "./context";
import type { Token } from "./index";
import { types as tt, type TokenType, type TopicContextState } from "./types";
import { types as tt, type TokenType } from "./types";
type TopicContextState = {
// When a topic binding has been currently established,
// then this is 1. Otherwise, it is 0. This is forwards compatible
// with a future plugin for multiple lexical topics.
maxNumOfResolvableTopics: number,
// When a topic binding has been currently established, and if that binding
// has been used as a topic reference `#`, then this is 0. Otherwise, it is
// `null`. This is forwards compatible with a future plugin for multiple
// lexical topics.
maxTopicIndex: null | 0,
};
export default class State {
strict: boolean;
input: string;
length: number;
curLine: number;
// And, if locations are used, the {line, column} object
// corresponding to those offsets
startLoc: Position;
endLoc: Position;
init(options: Options, input: string): void {
this.strict =
options.strictMode === false ? false : options.sourceType === "module";
this.input = input;
this.length = input.length;
this.potentialArrowAt = -1;
this.noArrowAt = [];
this.noArrowParamsConversionAt = [];
this.inMethod = false;
this.inFunction = false;
this.inParameters = false;
this.maybeInArrowParameters = false;
this.inGenerator = false;
this.inAsync = false;
this.inPipeline = false;
this.inPropertyName = false;
this.inType = false;
this.inClassProperty = false;
this.noAnonFunctionType = false;
this.hasFlowComment = false;
this.isIterator = false;
// Used by smartPipelines.
this.topicContext = {
maxNumOfResolvableTopics: 0,
maxTopicIndex: null,
};
this.classLevel = 0;
this.labels = [];
this.decoratorStack = [[]];
this.yieldOrAwaitInPossibleArrowParameters = null;
this.tokens = [];
this.comments = [];
this.trailingComments = [];
this.leadingComments = [];
this.commentStack = [];
// $FlowIgnore
this.commentPreviousNode = null;
this.pos = this.lineStart = 0;
this.curLine = options.startLine;
this.type = tt.eof;
this.value = null;
this.start = this.end = this.pos;
this.startLoc = this.endLoc = this.curPosition();
// $FlowIgnore
this.lastTokEndLoc = this.lastTokStartLoc = null;
this.lastTokStart = this.lastTokEnd = this.pos;
this.context = [ct.braceStatement];
this.exprAllowed = true;
this.containsEsc = this.containsOctal = false;
this.octalPosition = null;
this.invalidTemplateEscapePosition = null;
this.exportedIdentifiers = [];
}
// TODO
strict: boolean;
// TODO
input: string;
// Used to signify the start of a potential arrow function
potentialArrowAt: number;
potentialArrowAt: number = -1;
// Used to signify the start of an expression which looks like a
// typed arrow function, but it isn't
// e.g. a ? (b) : c => d
// ^
noArrowAt: number[];
noArrowAt: number[] = [];
// Used to signify the start of an expression whose params, if it looks like
// an arrow function, shouldn't be converted to assignable nodes.
@@ -102,113 +59,114 @@ export default class State {
// conditional expressions.
// e.g. a ? (b) : c => d
// ^
noArrowParamsConversionAt: number[];
noArrowParamsConversionAt: number[] = [];
// A comma after "...a" is only allowed in spread, but not in rest.
// Since we parse destructuring patterns as array/object literals
// and then convert them, we need to track it.
commaAfterSpreadAt: number = -1;
// Flags to track whether we are in a function, a generator.
inFunction: boolean;
inParameters: boolean;
maybeInArrowParameters: boolean;
inGenerator: boolean;
inMethod: boolean | N.MethodKind;
inAsync: boolean;
inPipeline: boolean;
inType: boolean;
noAnonFunctionType: boolean;
inPropertyName: boolean;
inClassProperty: boolean;
hasFlowComment: boolean;
isIterator: boolean;
inFunction: boolean = false;
inParameters: boolean = false;
maybeInArrowParameters: boolean = false;
inGenerator: boolean = false;
inMethod: boolean | N.MethodKind = false;
inAsync: boolean = false;
inPipeline: boolean = false;
inType: boolean = false;
noAnonFunctionType: boolean = false;
inPropertyName: boolean = false;
inClassProperty: boolean = false;
hasFlowComment: boolean = false;
isIterator: boolean = false;
// For the smartPipelines plugin:
topicContext: TopicContextState;
topicContext: TopicContextState = {
maxNumOfResolvableTopics: 0,
maxTopicIndex: null,
};
// Check whether we are in a (nested) class or not.
classLevel: number;
classLevel: number = 0;
// Labels in scope.
labels: Array<{
kind: ?("loop" | "switch"),
name?: ?string,
statementStart?: number,
}>;
}> = [];
// Leading decorators. Last element of the stack represents the decorators in current context.
// Supports nesting of decorators, e.g. @foo(@bar class inner {}) class outer {}
// where @foo belongs to the outer class and @bar to the inner
decoratorStack: Array<Array<N.Decorator>>;
decoratorStack: Array<Array<N.Decorator>> = [[]];
// The first yield or await expression inside parenthesized expressions
// and arrow function parameters. It is used to disallow yield and await in
// arrow function parameters.
yieldOrAwaitInPossibleArrowParameters:
| N.YieldExpression
| N.AwaitExpression
| null;
// Positions to delayed-check that yield/await does not exist in default parameters.
yieldPos: number = 0;
awaitPos: number = 0;
// Token store.
tokens: Array<Token | N.Comment>;
tokens: Array<Token | N.Comment> = [];
// Comment store.
comments: Array<N.Comment>;
comments: Array<N.Comment> = [];
// Comment attachment store
trailingComments: Array<N.Comment>;
leadingComments: Array<N.Comment>;
trailingComments: Array<N.Comment> = [];
leadingComments: Array<N.Comment> = [];
commentStack: Array<{
start: number,
leadingComments: ?Array<N.Comment>,
trailingComments: ?Array<N.Comment>,
type: string,
}>;
commentPreviousNode: N.Node;
}> = [];
// $FlowIgnore this is initialized when the parser starts.
commentPreviousNode: N.Node = null;
// The current position of the tokenizer in the input.
pos: number;
lineStart: number;
curLine: number;
pos: number = 0;
lineStart: number = 0;
// Properties of the current token:
// Its type
type: TokenType;
type: TokenType = tt.eof;
// For tokens that include more information than their type, the value
value: any;
value: any = null;
// Its start and end offset
start: number;
end: number;
// And, if locations are used, the {line, column} object
// corresponding to those offsets
startLoc: Position;
endLoc: Position;
start: number = 0;
end: number = 0;
// Position information for the previous token
lastTokEndLoc: Position;
lastTokStartLoc: Position;
lastTokStart: number;
lastTokEnd: number;
// $FlowIgnore this is initialized when generating the second token.
lastTokEndLoc: Position = null;
// $FlowIgnore this is initialized when generating the second token.
lastTokStartLoc: Position = null;
lastTokStart: number = 0;
lastTokEnd: number = 0;
// The context stack is used to superficially track syntactic
// context to predict whether a regular expression is allowed in a
// given position.
context: Array<TokContext>;
exprAllowed: boolean;
context: Array<TokContext> = [ct.braceStatement];
exprAllowed: boolean = true;
// Used to signal to callers of `readWord1` whether the word
// contained any escape sequences. This is needed because words with
// escape sequences must not be interpreted as keywords.
containsEsc: boolean;
containsEsc: boolean = false;
// TODO
containsOctal: boolean;
octalPosition: ?number;
containsOctal: boolean = false;
octalPosition: ?number = null;
// Names of exports store. `default` is stored as a name for both
// `export default foo;` and `export { foo as default };`.
exportedIdentifiers: Array<string>;
exportedIdentifiers: Array<string> = [];
invalidTemplateEscapePosition: ?number;
invalidTemplateEscapePosition: ?number = null;
curPosition(): Position {
return new Position(this.curLine, this.pos - this.lineStart);
@@ -216,7 +174,9 @@ export default class State {
clone(skipArrays?: boolean): State {
const state = new State();
Object.keys(this).forEach(key => {
const keys = Object.keys(this);
for (let i = 0, length = keys.length; i < length; i++) {
const key = keys[i];
// $FlowIgnore
let val = this[key];
@@ -226,7 +186,8 @@ export default class State {
// $FlowIgnore
state[key] = val;
});
}
return state;
}
}

View File

@@ -13,7 +13,12 @@
// expressions and divisions. It is set on all token types that can
// be followed by an expression (thus, a slash after them would be a
// regular expression).
//
// The `startsExpr` property is used to determine whether an expression
// may be the “argument” subexpression of a `yield` expression or
// `yield` statement. It is set on all token types that may be at the
// start of a subexpression.
// `isLoop` marks a keyword as starting a loop, which is important
// to know when parsing a label, in order to allow or disallow
// continue jumps to that label.
@@ -104,7 +109,7 @@ export const types: { [name: string]: TokenType } = {
backQuote: new TokenType("`", { startsExpr }),
dollarBraceL: new TokenType("${", { beforeExpr, startsExpr }),
at: new TokenType("@"),
hash: new TokenType("#"),
hash: new TokenType("#", { startsExpr }),
// Special hashbang token.
interpreterDirective: new TokenType("#!..."),
@@ -128,20 +133,20 @@ export const types: { [name: string]: TokenType } = {
incDec: new TokenType("++/--", { prefix, postfix, startsExpr }),
bang: new TokenType("!", { beforeExpr, prefix, startsExpr }),
tilde: new TokenType("~", { beforeExpr, prefix, startsExpr }),
pipeline: new BinopTokenType("|>", 0),
nullishCoalescing: new BinopTokenType("??", 1),
logicalOR: new BinopTokenType("||", 1),
logicalAND: new BinopTokenType("&&", 2),
bitwiseOR: new BinopTokenType("|", 3),
bitwiseXOR: new BinopTokenType("^", 4),
bitwiseAND: new BinopTokenType("&", 5),
equality: new BinopTokenType("==/!=", 6),
relational: new BinopTokenType("</>", 7),
bitShift: new BinopTokenType("<</>>", 8),
pipeline: BinopTokenType("|>", 0),
nullishCoalescing: BinopTokenType("??", 1),
logicalOR: BinopTokenType("||", 1),
logicalAND: BinopTokenType("&&", 2),
bitwiseOR: BinopTokenType("|", 3),
bitwiseXOR: BinopTokenType("^", 4),
bitwiseAND: BinopTokenType("&", 5),
equality: BinopTokenType("==/!=", 6),
relational: BinopTokenType("</>", 7),
bitShift: BinopTokenType("<</>>", 8),
plusMin: new TokenType("+/-", { beforeExpr, binop: 9, prefix, startsExpr }),
modulo: new BinopTokenType("%", 10),
star: new BinopTokenType("*", 10),
slash: new BinopTokenType("/", 10),
modulo: BinopTokenType("%", 10),
star: BinopTokenType("*", 10),
slash: BinopTokenType("/", 10),
exponent: new TokenType("**", {
beforeExpr,
binop: 11,
@@ -149,61 +154,53 @@ export const types: { [name: string]: TokenType } = {
}),
};
export const keywords = {
break: new KeywordTokenType("break"),
case: new KeywordTokenType("case", { beforeExpr }),
catch: new KeywordTokenType("catch"),
continue: new KeywordTokenType("continue"),
debugger: new KeywordTokenType("debugger"),
default: new KeywordTokenType("default", { beforeExpr }),
do: new KeywordTokenType("do", { isLoop, beforeExpr }),
else: new KeywordTokenType("else", { beforeExpr }),
finally: new KeywordTokenType("finally"),
for: new KeywordTokenType("for", { isLoop }),
function: new KeywordTokenType("function", { startsExpr }),
if: new KeywordTokenType("if"),
return: new KeywordTokenType("return", { beforeExpr }),
switch: new KeywordTokenType("switch"),
throw: new KeywordTokenType("throw", { beforeExpr, prefix, startsExpr }),
try: new KeywordTokenType("try"),
var: new KeywordTokenType("var"),
let: new KeywordTokenType("let"),
const: new KeywordTokenType("const"),
while: new KeywordTokenType("while", { isLoop }),
with: new KeywordTokenType("with"),
new: new KeywordTokenType("new", { beforeExpr, startsExpr }),
this: new KeywordTokenType("this", { startsExpr }),
super: new KeywordTokenType("super", { startsExpr }),
class: new KeywordTokenType("class", { startsExpr }),
extends: new KeywordTokenType("extends", { beforeExpr }),
export: new KeywordTokenType("export"),
import: new KeywordTokenType("import", { startsExpr }),
yield: new KeywordTokenType("yield", { beforeExpr, startsExpr }),
null: new KeywordTokenType("null", { startsExpr }),
true: new KeywordTokenType("true", { startsExpr }),
false: new KeywordTokenType("false", { startsExpr }),
in: new KeywordTokenType("in", { beforeExpr, binop: 7 }),
instanceof: new KeywordTokenType("instanceof", { beforeExpr, binop: 7 }),
typeof: new KeywordTokenType("typeof", { beforeExpr, prefix, startsExpr }),
void: new KeywordTokenType("void", { beforeExpr, prefix, startsExpr }),
delete: new KeywordTokenType("delete", { beforeExpr, prefix, startsExpr }),
};
function makeKeywordProps(
name: string,
conf: any,
): PropertyDescriptor<TokenType> {
return { value: KeywordTokenType(name, conf), enumerable: true };
}
// $FlowIssue
export const keywords = Object.create(null, {
break: makeKeywordProps("break"),
case: makeKeywordProps("case", { beforeExpr }),
catch: makeKeywordProps("catch"),
continue: makeKeywordProps("continue"),
debugger: makeKeywordProps("debugger"),
default: makeKeywordProps("default", { beforeExpr }),
do: makeKeywordProps("do", { isLoop, beforeExpr }),
else: makeKeywordProps("else", { beforeExpr }),
finally: makeKeywordProps("finally"),
for: makeKeywordProps("for", { isLoop }),
function: makeKeywordProps("function", { startsExpr }),
if: makeKeywordProps("if"),
return: makeKeywordProps("return", { beforeExpr }),
switch: makeKeywordProps("switch"),
throw: makeKeywordProps("throw", { beforeExpr, prefix, startsExpr }),
try: makeKeywordProps("try"),
var: makeKeywordProps("var"),
const: makeKeywordProps("const"),
while: makeKeywordProps("while", { isLoop }),
with: makeKeywordProps("with"),
new: makeKeywordProps("new", { beforeExpr, startsExpr }),
this: makeKeywordProps("this", { startsExpr }),
super: makeKeywordProps("super", { startsExpr }),
class: makeKeywordProps("class", { startsExpr }),
extends: makeKeywordProps("extends", { beforeExpr }),
export: makeKeywordProps("export"),
import: makeKeywordProps("import", { startsExpr }),
null: makeKeywordProps("null", { startsExpr }),
true: makeKeywordProps("true", { startsExpr }),
false: makeKeywordProps("false", { startsExpr }),
in: makeKeywordProps("in", { beforeExpr, binop: 7 }),
instanceof: makeKeywordProps("instanceof", { beforeExpr, binop: 7 }),
typeof: makeKeywordProps("typeof", { beforeExpr, prefix, startsExpr }),
void: makeKeywordProps("void", { beforeExpr, prefix, startsExpr }),
delete: makeKeywordProps("delete", { beforeExpr, prefix, startsExpr }),
});
// Map keyword names to token types.
Object.keys(keywords).forEach(name => {
types["_" + name] = keywords[name];
});
// A type for the smartPipelines plugin.
export type TopicContextState = {
// When a topic binding has been currently established,
// then this is 1. Otherwise, it is 0. This is forwards compatible
// with a future plugin for multiple lexical topics.
maxNumOfResolvableTopics: number,
// When a topic binding has been currently established, and if that binding
// has been used as a topic reference `#`, then this is 0. Otherwise, it is
// `null`. This is forwards compatible with a future plugin for multiple
// lexical topics.
maxTopicIndex: null | 0,
};

View File

@@ -783,7 +783,9 @@ export type AnyExport =
| ExportNamedDeclaration
| ExportDefaultDeclaration
| ExportAllDeclaration
| TsExportAssignment;
| TsExportAssignment
| TsImportEqualsDeclaration
| TsNamespaceExportDeclaration;
export type ModuleSpecifier = NodeBase & {
local: Identifier,
@@ -820,7 +822,7 @@ export type ImportNamespaceSpecifier = ModuleSpecifier & {
export type ExportNamedDeclaration = NodeBase & {
type: "ExportNamedDeclaration",
declaration: ?Declaration,
specifiers: $ReadOnlyArray<ExportSpecifier>,
specifiers: $ReadOnlyArray<ExportSpecifier | ExportDefaultSpecifier>,
source: ?Literal,
exportKind?: "type" | "value", // TODO: Not in spec
@@ -831,6 +833,11 @@ export type ExportSpecifier = NodeBase & {
exported: Identifier,
};
export type ExportDefaultSpecifier = NodeBase & {
type: "ExportDefaultSpecifier",
exported: Identifier,
};
export type ExportDefaultDeclaration = NodeBase & {
type: "ExportDefaultDeclaration",
declaration:
@@ -1146,6 +1153,7 @@ export type TsType =
| TsIndexedAccessType
| TsMappedType
| TsLiteralType
| TsImportType
// TODO: This probably shouldn't be included here.
| TsTypePredicate;
@@ -1157,6 +1165,7 @@ export type TsKeywordTypeType =
| "TSNumberKeyword"
| "TSObjectKeyword"
| "TSBooleanKeyword"
| "TSBigIntKeyword"
| "TSStringKeyword"
| "TSSymbolKeyword"
| "TSVoidKeyword"
@@ -1200,7 +1209,7 @@ export type TsTypePredicate = TsTypeBase & {
// `typeof` operator
export type TsTypeQuery = TsTypeBase & {
type: "TSTypeQuery",
exprName: TsEntityName,
exprName: TsEntityName | TsImportType,
};
export type TsTypeLiteral = TsTypeBase & {
@@ -1285,6 +1294,13 @@ export type TsLiteralType = TsTypeBase & {
literal: NumericLiteral | StringLiteral | BooleanLiteral,
};
export type TsImportType = TsTypeBase & {
type: "TsImportType",
argument: StringLiteral,
qualifier?: TsEntityName,
typeParameters?: TsTypeParameterInstantiation,
};
// ================
// TypeScript declarations
// ================

View File

@@ -4,29 +4,98 @@
import * as charCodes from "charcodes";
function makePredicate(words: string): (str: string) => boolean {
const wordsArr = words.split(" ");
return function(str) {
return wordsArr.indexOf(str) >= 0;
};
}
// Reserved word lists for various dialects of the language
export const reservedWords = {
"6": makePredicate("enum await"),
strict: makePredicate(
"implements interface let package private protected public static yield",
),
strictBind: makePredicate("eval arguments"),
const reservedWords = {
strict: [
"implements",
"interface",
"let",
"package",
"private",
"protected",
"public",
"static",
"yield",
],
strictBind: ["eval", "arguments"],
};
// And the keywords
export const isKeyword = makePredicate(
"break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this let const class extends export import yield super",
const reservedWordsStrictSet = new Set(reservedWords.strict);
const reservedWordsStrictBindSet = new Set(
reservedWords.strict.concat(reservedWords.strictBind),
);
/**
* Checks if word is a reserved word in non-strict mode
*/
export const isReservedWord = (word: string, inModule: boolean): boolean => {
return (inModule && word === "await") || word === "enum";
};
/**
* Checks if word is a reserved word in non-binding strict mode
*
* Includes non-strict reserved words
*/
export function isStrictReservedWord(word: string, inModule: boolean): boolean {
return isReservedWord(word, inModule) || reservedWordsStrictSet.has(word);
}
/**
* Checks if word is a reserved word in binding strict mode
*
* Includes non-strict reserved words and non-binding strict reserved words
*/
export function isStrictBindReservedWord(
word: string,
inModule: boolean,
): boolean {
return isReservedWord(word, inModule) || reservedWordsStrictBindSet.has(word);
}
const keywords = new Set([
"break",
"case",
"catch",
"continue",
"debugger",
"default",
"do",
"else",
"finally",
"for",
"function",
"if",
"return",
"switch",
"throw",
"try",
"var",
"while",
"with",
"null",
"true",
"false",
"instanceof",
"typeof",
"void",
"delete",
"new",
"in",
"this",
"const",
"class",
"extends",
"export",
"import",
"super",
]);
export function isKeyword(word: string): boolean {
return keywords.has(word);
}
export const keywordRelationalOperator = /^in(stanceof)?$/;
// ## Character categories
// Big ugly regular expressions that matches characters in the
@@ -64,7 +133,7 @@ const astralIdentifierCodes = [509,0,227,0,150,4,294,9,1368,2,2,1,6,3,41,2,5,0,1
// rare.
function isInAstralSet(code: number, set: $ReadOnlyArray<number>): boolean {
let pos = 0x10000;
for (let i = 0; i < set.length; i += 2) {
for (let i = 0, length = set.length; i < length; i += 2) {
pos += set[i];
if (pos > code) return false;

View File

@@ -4,7 +4,7 @@ import * as charCodes from "charcodes";
// Matches a whole line break (where CRLF is considered a single
// line break). Used to count lines.
export const lineBreak = /\r\n?|\n|\u2028|\u2029/;
export const lineBreak = /\r\n?|[\n\u2028\u2029]/;
export const lineBreakG = new RegExp(lineBreak.source, "g");
// https://tc39.github.io/ecma262/#sec-line-terminators

View File

@@ -1,4 +1,4 @@
{
"strictMode": true,
"throws": "public is a reserved word in strict mode (2:0)"
"throws": "Unexpected reserved word 'public' (2:0)"
}

View File

@@ -0,0 +1,3 @@
{
"throws": "Function declaration not allowed in this context (1:10)"
}

View File

@@ -0,0 +1 @@
while (1) foo: bar: function foo(){}

View File

@@ -0,0 +1,3 @@
{
"throws": "Function declaration not allowed in this context (1:20)"
}

View File

@@ -0,0 +1 @@
for await (const i of imports) {}

View File

@@ -0,0 +1,3 @@
{
"throws": "Unexpected token, expected \"(\" (1:4)"
}

View File

@@ -0,0 +1 @@
for await (const i of imports) {}

View File

@@ -0,0 +1,3 @@
{
"allowAwaitOutsideFunction": true
}

View File

@@ -0,0 +1,136 @@
{
"type": "File",
"start": 0,
"end": 33,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 33
}
},
"program": {
"type": "Program",
"start": 0,
"end": 33,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 33
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ForOfStatement",
"start": 0,
"end": 33,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 33
}
},
"await": true,
"left": {
"type": "VariableDeclaration",
"start": 11,
"end": 18,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 18
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 17,
"end": 18,
"loc": {
"start": {
"line": 1,
"column": 17
},
"end": {
"line": 1,
"column": 18
}
},
"id": {
"type": "Identifier",
"start": 17,
"end": 18,
"loc": {
"start": {
"line": 1,
"column": 17
},
"end": {
"line": 1,
"column": 18
},
"identifierName": "i"
},
"name": "i"
},
"init": null
}
],
"kind": "const"
},
"right": {
"type": "Identifier",
"start": 22,
"end": 29,
"loc": {
"start": {
"line": 1,
"column": 22
},
"end": {
"line": 1,
"column": 29
},
"identifierName": "imports"
},
"name": "imports"
},
"body": {
"type": "BlockStatement",
"start": 31,
"end": 33,
"loc": {
"start": {
"line": 1,
"column": 31
},
"end": {
"line": 1,
"column": 33
}
},
"body": [],
"directives": []
}
}
],
"directives": []
}
}

View File

@@ -0,0 +1,3 @@
function* test() {
yield new Foo();
}

View File

@@ -0,0 +1,152 @@
{
"type": "File",
"start": 0,
"end": 39,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"program": {
"type": "Program",
"start": 0,
"end": 39,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 39,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"id": {
"type": "Identifier",
"start": 10,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 14
},
"identifierName": "test"
},
"name": "test"
},
"generator": true,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 17,
"end": 39,
"loc": {
"start": {
"line": 1,
"column": 17
},
"end": {
"line": 3,
"column": 1
}
},
"body": [
{
"type": "ExpressionStatement",
"start": 21,
"end": 37,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 18
}
},
"expression": {
"type": "YieldExpression",
"start": 21,
"end": 36,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 17
}
},
"delegate": false,
"argument": {
"type": "NewExpression",
"start": 27,
"end": 36,
"loc": {
"start": {
"line": 2,
"column": 8
},
"end": {
"line": 2,
"column": 17
}
},
"callee": {
"type": "Identifier",
"start": 31,
"end": 34,
"loc": {
"start": {
"line": 2,
"column": 12
},
"end": {
"line": 2,
"column": 15
},
"identifierName": "Foo"
},
"name": "Foo"
},
"arguments": []
}
}
}
],
"directives": []
}
}
],
"directives": []
}
}

View File

@@ -1,4 +1,4 @@
{
"sourceType": "module",
"throws": "Legacy octal literals are not allowed in strict mode (1:0)"
"sourceType": "module",
"throws": "Legacy octal literals are not allowed in strict mode (1:0)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \";\" (1:2)"
}
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Rest parameter must be last formal parameter (1:18)"
"throws": "The rest parameter must be the last parameter (1:18)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:36)"
}
"throws": "Binding 'eval' in strict mode (1:36)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:36)"
}
"throws": "Binding 'arguments' in strict mode (1:36)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:47)"
}
"throws": "Binding 'eval' in strict mode (1:47)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:47)"
}
"throws": "Binding 'arguments' in strict mode (1:47)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:32)"
}
"throws": "Assigning to 'eval' in strict mode (1:32)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:32)"
}
"throws": "Assigning to 'arguments' in strict mode (1:32)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:34)"
}
"throws": "Assigning to 'eval' in strict mode (1:34)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:34)"
}
"throws": "Assigning to 'eval' in strict mode (1:34)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:34)"
}
"throws": "Assigning to 'arguments' in strict mode (1:34)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:34)"
}
"throws": "Assigning to 'arguments' in strict mode (1:34)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:32)"
}
"throws": "Assigning to 'eval' in strict mode (1:32)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:32)"
}
"throws": "Assigning to 'eval' in strict mode (1:32)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:32)"
}
"throws": "Assigning to 'arguments' in strict mode (1:32)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:32)"
}
"throws": "Assigning to 'arguments' in strict mode (1:32)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:41)"
}
"throws": "Binding 'eval' in strict mode (1:41)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:41)"
}
"throws": "Binding 'arguments' in strict mode (1:41)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:9)"
}
"throws": "Binding 'eval' in strict mode (1:9)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:9)"
}
"throws": "Binding 'arguments' in strict mode (1:9)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:42)"
}
"throws": "Binding 'eval' in strict mode (1:42)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:42)"
}
"throws": "Binding 'arguments' in strict mode (1:42)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:10)"
}
"throws": "Binding 'eval' in strict mode (1:10)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:10)"
}
"throws": "Binding 'arguments' in strict mode (1:10)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:47)"
}
"throws": "Binding 'eval' in strict mode (1:47)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "package is a reserved word in strict mode (1:10)"
}
"throws": "Binding 'package' in strict mode (1:10)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:48)"
}
"throws": "Binding 'eval' in strict mode (1:48)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:41)"
}
"throws": "Binding 'eval' in strict mode (1:41)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:49)"
}
"throws": "Binding 'eval' in strict mode (1:49)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "eval is a reserved word in strict mode (1:15)"
}
"throws": "Binding 'eval' in strict mode (1:15)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "arguments is a reserved word in strict mode (1:15)"
}
"throws": "Binding 'arguments' in strict mode (1:15)"
}

Some files were not shown because too many files have changed in this diff Show More