Compare commits

...

81 Commits

Author SHA1 Message Date
Nicolò Ribaudo
8b132c0889 v7.2.1 2018-12-04 16:21:47 +01:00
Nicolò Ribaudo
b927fb2a7e Don't use isClassPrivateMethod because is isn't supported in <7.2.0 (#9121) 2018-12-04 08:35:10 +01:00
Nicolò Ribaudo
282129ea66 v7.2.0 2018-12-03 20:00:35 +01:00
Nicolò Ribaudo
fc5d49b6f6 Add access:public to @babel/helper-create-class-features-plugin 2018-12-03 20:00:24 +01:00
Nicolò Ribaudo
6c2771c116 Add @babel/plugin-proposal-private-methods to @babel/standalone (#9115) 2018-12-03 19:40:00 +01:00
Sven Sauleau
fdc869ce16 Merge pull request #8289 from valtech-nyc/implement-smart-pipeline-in-parser
Implement Smart Pipeline proposal in @babel/parser
2018-12-03 19:28:45 +01:00
Daniel Tschinder
fa9df678ac Move tests from babylon to babel-parser and enable one test that works now 2018-12-03 00:46:54 -08:00
Daniel Tschinder
3932830535 Parse non-octals with leading zeros in non strict mode correctly (#9114)
* Parse non-octals with leading zeros in non strict mode correctly

* Better error message
2018-12-03 00:04:37 -08:00
Daniel Tschinder
07eaa3c63f Ignore empty fixture directories and fix fixtures in the parser (#9113)
* Ignore fixture directories that do not contain input or exec

* Fix parser test fixtures structures for some imported esprima tests.

* Warn on test folders that are not empty and do not contain testfiles
2018-12-02 22:55:06 -08:00
Daniel Tschinder
3530d11418 Update find-cache-dir (#9111)
Dropped support for node <6
2018-12-02 12:12:19 -08:00
Kai Cataldo
806e133473 Export @babel/parser#tokTypes in @babel/core (#8986)
* Export @babel/parser in @babel/core

* Expose tokTypes instead of parser
2018-11-30 18:41:58 -08:00
Veaceslav Cotruta
2bf8dde782 Propagates the extensions overrides provided by CLI during files walk (#8668)
* Propagates the extensions overrides provided by CLI during files walk

* Adds tests for issue #7620, PR #8668
2018-11-29 18:57:27 -08:00
Nicolò Ribaudo
4e28459a2f Make @babel/plugin-class-features a normal helper package (#9083)
* Make @babel/plugin-class-features a normal helper package

This effectively disallows using it directly.

* Rename helper

* Style

* Don't add prefix to plugin name

* Move private methods plugin
2018-11-29 16:42:45 +01:00
wtgtybhertgeghgtwtg
c4d6f6dcce Pass rootMode from @babel/node. (#9078)
* Pass `root-mode` from `@babel/node`.

* Filter `babelOptions`.
2018-11-28 21:29:38 -08:00
Tim McClure
0859535b62 Private class methods stage 3 (#8654)
* Add private method syntax support

* Add private method spec support

* Add private method loose support

* Throw error if static private method is used

* Add more isStatic & isMethod checks

* Remove `writable:false` from private method inits

`writable` is false by default.

* Add private method func obj equality check

* Throw if private accessor is used

* Add check for fields === private method loose mode

* Throw buildCodeFrameErrors instead of Errors

* Move obj destructuring inside for loop

* Remove "computed" from ClassPrivateMethod type def
2018-11-28 16:20:09 -08:00
Daniel Tschinder
6e39b58f8a Add node 11 to CI and remove node 9 (#9096) 2018-11-28 12:36:58 -08:00
Daniel Tschinder
559d649994 Skip minifying standalone (#9094)
Also remove unused dependency on uglify js. gulp-uglify uses its own version.
2018-11-28 12:36:24 -08:00
Brian Ng
3fda01b185 Update mapping for regex unicode plugin in preset-env (#9091) 2018-11-27 22:09:15 -06:00
Daniel Tschinder
4f2eacf615 chore: Fix warning when using prettier in code generators (#9093)
Also add more output to the generation
2018-11-27 19:34:11 -08:00
Gcaufy
0047ae84b3 Remove unused variable (#9089)
When I was reading the code, I see `parent` is not used in `_getComments` function.
so it make me confused why we delivery the `parent` in those functions.

If I'm wrong, please correct me.
2018-11-27 14:03:39 -08:00
Paul Happ
2bb24f996f Fix yield expression transform (#9076) 2018-11-27 09:45:06 -06:00
Nicolò Ribaudo
61f2aed5b0 Disallow await inside arrow functions (#9074)
* Disallow await inside arrow functions

* Update test262 whitelist
2018-11-26 12:43:04 +01:00
Ruben Verborgh
9308c870f5 Fix destructuring assignment in arrow functions. (#8916)
Fixes 8912.
2018-11-25 19:29:58 +01:00
wtgtybhertgeghgtwtg
1b8d664bbe Move fs-readdir-recursive and output-file-sync to devDependencies (#9079)
For `@babel/node`.
2018-11-25 18:04:03 +01:00
Justin Ridgewell
844dd33f3d Microbouji patch/8136 (#9073)
* Fix optional chaining bug regarding spread in function calls

* Revamp optional-chain to be top down

Instead of going both upwards and downwards from the first real optional expression, we can just start from the top down.

* Add more tests
2018-11-24 09:32:24 -05:00
Nicolò Ribaudo
856edbf95f [flow] Allow type casts in array patterns inside arrow parameters (#9069) 2018-11-24 12:23:49 +01:00
mAAdhaTTah
100b38784d Replace else with fall through 2018-11-21 21:07:03 -05:00
mAAdhaTTah
4cbd22a15f Hardcode "#" in error message
It's not going to be anything else...
2018-11-21 21:05:51 -05:00
Daniel Tschinder
d2971a1959 Fix compatibility between typescript and jsx plugins in interface declarations (#9058) 2018-11-21 15:58:50 -08:00
Brian Ng
4f16a12c03 Fix bug with parsing TS generic async arrow function (#9055) 2018-11-21 15:34:09 -06:00
Brian Ng
e7f0c065cf Bump some deps (#9056) 2018-11-21 15:21:36 -06:00
mAAdhaTTah
70318c9413 s/may/should 2018-11-21 16:02:34 -05:00
mAAdhaTTah
6e84352b51 PrimaryTopicReference -> PipelinePrimaryTopicReference 2018-11-21 15:54:56 -05:00
mAAdhaTTah
0eb9b2463d Move plugin check to pipeline op appearance
No need to recheck it throughout then.
2018-11-21 15:54:26 -05:00
Grigory Moroz
445b14148e Better error for disallowed trailing commas/parameters after rest elements (#9046)
* handle disordered rest parameter in function expressions

* remove spaces [lint]

* polish function parameters validation

* add test with arrow function and comma after rest parameter [babel-parser]
2018-11-21 07:49:36 +01:00
Brian Ng
61c1c77a28 Update mappings for node 10 in preset-env (#9048) 2018-11-20 15:29:45 -06:00
Nicolò Ribaudo
5979b0669b Merge class features plugins
* Create @babel/plugin-class-features

* Move class properties transformation logic to enanced-classes (#8130)
2018-11-20 21:14:35 +01:00
Daniel Tschinder
a2afb974be Fix parsing typescript function types with destructuring (#9035)
* Fix parsing typescript function types with destructuring

* Use integer instead of actual stack
2018-11-19 13:55:58 -08:00
Nicolò Ribaudo
c11cdcb6d8 Fix recursive async function expressions (#9039)
* Fix recursive async function expressions

* Update fixtures
2018-11-19 17:19:54 +01:00
Nicolò Ribaudo
8c7d4b55c9 Add plugins name (#8769)
* Add plugins name

* Add missing names found by the plugin

* Add eslint plugin
2018-11-18 23:02:58 +01:00
Sergey Rubanov
88696601e1 Add Node 11 support (#9037) 2018-11-18 08:17:06 -07:00
Logan Smyth
20a9d71016 Normalize presets before merging config with others. (#9034) 2018-11-16 21:23:23 -08:00
Daniel Tschinder
1af57e6f71 Fix test262 tests again! 2018-11-14 23:29:17 -08:00
Nicolò Ribaudo
4e1d6e7ff4 v7.1.6 2018-11-13 22:10:06 +01:00
Henry Zhu
efb71ea12b fix publish command [skip ci] (#8982) 2018-11-13 11:47:05 -08:00
Logan Smyth
cbbb3c7962 Ensure that the arrow nodes have a location before using them. (#9003) 2018-11-12 17:10:49 -08:00
Greg Bergé
4fcee1751a Fix cloneNode with typeAnnotation. (#8997)
Fixes #8996
2018-11-12 17:10:09 -08:00
Tien Pham
efa571a42c Update CHANGELOG.md (#9014) 2018-11-11 23:33:56 +01:00
Alican Çubukçuoğlu
bf8c4785f2 Fix "TypeError: comments is not iterable" (#8701) 2018-11-09 13:58:28 -08:00
Brian Ng
4f206b2416 prettier@1.15.1 (#9001) 2018-11-09 15:25:13 -06:00
Daniel Tschinder
504b331da4 Fix browser files to have the same API as the nodejs ones (#9004) 2018-11-09 13:11:46 -08:00
Daniel Tschinder
74f969b603 Update debug dependency (#8989) 2018-11-09 16:27:41 +01:00
Remi Liu
4dfd801887 [Types] fix generated TS/Flow comment types (#9007) 2018-11-09 09:03:53 -06:00
Daniel Tschinder
62233ed7c9 Update json5 to latest version (#8990) 2018-11-08 17:29:13 -08:00
ylemkimon
7b54ab620b preset-env: fix opera from esmodules target and Browserslist not used (#8555) 2018-11-08 10:29:49 -06:00
Daniel Tschinder
343f776ca5 Rename primitive types to reserved types (#8984) 2018-11-07 16:50:36 -06:00
Daniel Tschinder
756ded4d64 Remove definition of micromatch which was removed. (#8988) 2018-11-07 16:49:27 -06:00
Nicolò Ribaudo
b706e34fc8 [decorators] Correctly insert _initialize(this) after super(). (#8970)
* [decorators] Correctly insert `_initialize(this)` after `super()`.

This commit fixes to problem:
1) After `super();` statements, `_initialize(this)` was inserted without
   a trailing semicolon.
2) `(0, super())` causes an infinite recursion.

* Fix tests

* Add test
2018-11-06 21:58:09 -08:00
Daniel Tschinder
5d5cd8612f Fix several edge cases with context expression state (#8972)
* Fix several edge cases with context expression state

* Fix review comments

* Remove unused field
2018-11-06 19:37:24 -08:00
mAAdhaTTah
a0e94ec24d Move PipelineStyle to types.js file 2018-11-03 14:03:17 -04:00
mAAdhaTTah
b593af17a9 Replace codePointToString with ES6 method 2018-11-03 14:00:42 -04:00
mAAdhaTTah
4521204ea0 Merge branch 'master' into implement-smart-pipeline-in-parser
* master: (222 commits)
  Set correct methods name
  Use toPropertyKey in the "decorate" helper
  Allow function types in type params within arrow return types (#8954)
  Fix message when plugin of a wrong type is passed (#8950)
  rename colliding let bindings with for loop init (#8937)
  edge incomplete support for arrow destructuring (babel #8349) (#8926)
  fix single-arg async arrows when retainLines=true (#8868)
  [flow] Explicit inexact objects with `...` (#8884)
  Update preset-env data (#8898)
  Treat break inside block inside loop (#8914)
  fixed "source map" formatting in comment (#8878) [skip ci]
  fix typo in contributing guidelines (#8901) [skip ci]
  fix: Expression x === 'y' && '' should not evaluate to undefined. (#8880)
  fixed an extra word
  Fixes #8865 (#8866)
  v7.1.4
  v7.1.3
  Bump Babel deps (#8770)
  flow-bin@0.82.0 (#8832)
  Insertafter jsx fix (#8833)
  ...

# Conflicts:
#	packages/babel-parser/src/tokenizer/index.js
#	packages/babel-parser/test/fixtures/experimental/class-private-properties/failure-numeric-literal/options.json
#	packages/babel-parser/test/fixtures/experimental/pipeline-operator/invalid-proposal/options.json
2018-11-03 14:00:12 -04:00
James DiGioia
122906d525 Verify if MemberExpression is computed
If a property access is computed, e.g. a[b], then it's in topic style. Currently,
this isn't accounted for. Test & change ensures this doesn't parse.
2018-08-10 08:06:38 -04:00
James DiGioia
25d01460fd Fix error message for #4 case
This impact private fields as well as smart pipeline, providing a clearer
error message for both.
2018-08-10 07:52:55 -04:00
James DiGioia
ba5642d4ee Add test for computer properties
This seems to parse fine. Should it?
2018-08-09 22:08:39 -04:00
James DiGioia
15e6d844ae Remove additional parser logic
These are parsable only in follow-on proposals, not in the base proposal,
so we'll introduce that in a separate PR.
2018-08-09 22:08:23 -04:00
James DiGioia
d1cae2dec2 Remove unneeded comment
This is no longer true, now that we return `tt.hash`.
2018-08-09 21:10:43 -04:00
James DiGioia
11aee13ff2 Swap Yoda condition 2018-08-09 21:04:47 -04:00
James DiGioia
39e7ee6e65 Switch Pipeline types to extend NodeBase
This doesn't work because the `type` values are not compatible.
2018-07-22 18:55:12 -04:00
James DiGioia
094ef31c01 Wrap callback in try/finally
This ensures we clean up always if the callback throws.
2018-07-22 18:52:07 -04:00
James DiGioia
afd0638b74 Reuse hash token instead of new primaryTopicToken
Set whether we're in a pipeline in order to determine how to parse the
hash. The error message changes as a result, since the `hash` never
enters the block.
2018-07-22 18:46:31 -04:00
James DiGioia
6e41edb90f Fix TopicContextState type in Flow 2018-07-22 17:58:51 -04:00
James DiGioia
7931f4c241 Rename topicContextState -> .topicContext 2018-07-12 23:11:55 -04:00
James DiGioia
b847d40842 Inline readTopicContextState method 2018-07-12 23:10:07 -04:00
James DiGioia
e91a02cc49 Reuse declared type in function return value 2018-07-12 23:08:11 -04:00
James DiGioia
cc526940ee Quote proposals in error message 2018-07-12 23:07:09 -04:00
James DiGioia
7188820151 Delete commented code 2018-07-12 22:55:01 -04:00
James DiGioia
00845709ce Add comment for number sign 2018-07-12 22:48:53 -04:00
James DiGioia
b50fdc191e Inline function checkSmartPipelineHeadEarlyErrors
It's only used once.
2018-07-12 22:47:45 -04:00
James DiGioia
ef0f723fc5 Reverse yoda conditions
If "smart" proposal is, we'll no longer say.
2018-07-12 22:46:34 -04:00
J. S. Choi
fbf62b4830 Implement Smart Pipeline proposal in @babel/parser 2018-07-09 22:44:27 -04:00
972 changed files with 31708 additions and 2819 deletions

View File

@@ -34,7 +34,7 @@ jobs:
build:
working_directory: ~/babel
docker:
- image: circleci/node:10
- image: circleci/node:11
steps:
- checkout
- restore-cache: *restore-yarn-cache

View File

@@ -26,6 +26,13 @@
"env": {
"jest": true
}
},
{
"files": ["packages/babel-plugin-*/src/index.js"],
"excludedFiles": ["packages/babel-plugin-transform-regenerator/**/*.js"],
"rules": {
"local-rules/plugin-name": "error"
}
}
]
}

View File

@@ -1,14 +1,12 @@
git:
depth: 10
depth: 5
sudo: false
language: node_js
cache:
yarn: true
directories:
- node_modules
node_js:
# We test the latest version on circleci
- '9'
- '10'
- '8'
- '6'
@@ -20,7 +18,9 @@ env:
before_install:
- curl -o- -L https://yarnpkg.com/install.sh | bash
install: yarn --ignore-engines
install:
# the `make test-ci` script runs this command already
- if [ "$JOB" != "test" ]; then yarn install; fi
before_script:
- 'if [ "$JOB" = "babel-parser-flow-tests" ]; then make bootstrap-flow; fi'

View File

@@ -2542,7 +2542,7 @@ Also started Babel to compile itself with Babel 7! (We'll be working on making i
#### :nail_care: Polish
* `babel-register`
* [#5411](https://github.com/babel/babel/pull/5411) Seperate version env cache files. ([@pwmckenna](https://github.com/pwmckenna))
* [#5411](https://github.com/babel/babel/pull/5411) Separate version env cache files. ([@pwmckenna](https://github.com/pwmckenna))
#### :memo: Documentation
* `babel-plugin-transform-runtime`

View File

@@ -1,6 +1,6 @@
MAKEFLAGS = -j1
FLOW_COMMIT = e192e1a4793dd8e43415fbfe8046d832cb513c8b
TEST262_COMMIT = 69c1efd325deedf54db92a23008399e2b00fa51e
TEST262_COMMIT = 238c88d4a084d9928372954e2fec54af2c951281
# Fix color output until TravisCI fixes https://github.com/travis-ci/travis-ci/issues/7967
export FORCE_COLOR = true
@@ -115,7 +115,7 @@ prepublish-build:
rm -rf packages/babel-runtime/helpers
rm -rf packages/babel-runtime-corejs2/helpers
rm -rf packages/babel-runtime-corejs2/core-js
BABEL_ENV=production make build-dist
BABEL_ENV=production IS_PUBLISH=true make build-dist
make clone-license
prepublish:
@@ -125,7 +125,7 @@ prepublish:
publish: prepublish
# --only-explicit-updates
./node_modules/.bin/lerna publish
./node_modules/.bin/lerna publish --force-publish="@babel/runtime,@babel/runtime-corejs2" --dangerously-only-publish-explicit-updates-this-is-a-custom-flag-for-babel-and-you-should-not-be-using-it-just-deal-with-more-packages-being-published-it-is-not-a-big-deal
make clean
bootstrap: clean-all

View File

@@ -2,8 +2,10 @@
const noDeprecatedClone = require("./scripts/eslint_rules/no-deprecated-clone");
const noUndefinedIdentifier = require("./scripts/eslint_rules/no-undefined-identifier");
const pluginName = require("./scripts/eslint_rules/plugin-name");
module.exports = {
"no-deprecated-clone": noDeprecatedClone,
"no-undefined-identifier": noUndefinedIdentifier,
"plugin-name": pluginName,
};

View File

@@ -1,6 +1,6 @@
{
"lerna": "2.11.0",
"version": "7.1.5",
"version": "7.2.1",
"changelog": {
"repo": "babel/babel",
"cacheDir": ".changelog",

View File

@@ -2,12 +2,6 @@
* Basic declarations for the npm modules we use.
*/
declare module "micromatch" {
declare module.exports: {
(Array<string>, Array<string>, ?{ nocase: boolean }): Array<string>,
};
}
declare module "resolve" {
declare export default {
sync: (string, {| basedir: string |}) => string;

View File

@@ -9,17 +9,17 @@
"test": "make test"
},
"devDependencies": {
"@babel/cli": "^7.1.2",
"@babel/core": "^7.1.2",
"@babel/cli": "^7.1.5",
"@babel/core": "^7.1.6",
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-proposal-export-namespace-from": "^7.0.0",
"@babel/plugin-proposal-numeric-separator": "^7.0.0",
"@babel/plugin-transform-modules-commonjs": "^7.1.0",
"@babel/plugin-transform-runtime": "^7.1.0",
"@babel/preset-env": "^7.1.0",
"@babel/preset-env": "^7.1.6",
"@babel/preset-flow": "^7.0.0",
"@babel/register": "^7.0.0",
"@babel/runtime": "^7.1.2",
"@babel/runtime": "^7.1.5",
"babel-core": "^7.0.0-0",
"babel-eslint": "^10.0.1",
"babel-jest": "^23.6.0",
@@ -31,39 +31,38 @@
"charcodes": "^0.1.0",
"derequire": "^2.0.2",
"enhanced-resolve": "^3.0.0",
"eslint": "^5.6.0",
"eslint-config-babel": "^8.0.1",
"eslint-plugin-flowtype": "^2.50.1",
"eslint": "^5.9.0",
"eslint-config-babel": "^8.0.2",
"eslint-plugin-flowtype": "^3.2.0",
"eslint-plugin-local-rules": "0.1.0",
"eslint-plugin-prettier": "^2.6.2",
"eslint-plugin-prettier": "^3.0.0",
"flow-bin": "^0.82.0",
"graceful-fs": "^4.1.11",
"gulp": "^4.0.0",
"gulp-babel": "^8.0.0-beta.2",
"gulp-babel": "^8.0.0",
"gulp-filter": "^5.1.0",
"gulp-newer": "^1.0.0",
"gulp-plumber": "^1.0.1",
"gulp-rename": "^1.2.2",
"gulp-uglify": "^3.0.0",
"gulp-plumber": "^1.2.0",
"gulp-rename": "^1.4.0",
"gulp-uglify": "^3.0.1",
"gulp-util": "^3.0.7",
"gulp-watch": "^5.0.0",
"husky": "^1.0.0-rc.15",
"gulp-watch": "^5.0.1",
"husky": "^1.2.0",
"jest": "^23.6.0",
"lerna": "^2.11.0",
"lerna-changelog": "^0.5.0",
"lint-staged": "^7.3.0",
"lint-staged": "^8.1.0",
"lodash": "^4.17.10",
"merge-stream": "^1.0.1",
"output-file-sync": "^2.0.0",
"prettier": "^1.14.3",
"pump": "^1.0.2",
"prettier": "^1.15.2",
"pump": "^3.0.0",
"rimraf": "^2.4.3",
"rollup-plugin-babel": "^4.0.0-beta.0",
"rollup-plugin-node-resolve": "^3.0.2",
"rollup-stream": "^1.24.1",
"test262-stream": "^1.2.0",
"through2": "^2.0.0",
"uglify-js": "^2.4.16",
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0",
"webpack": "^3.4.1",
@@ -71,7 +70,7 @@
"webpack-stream": "^4.0.0"
},
"engines": {
"node": ">= 6.9.0 <= 11.0.0-0",
"node": ">= 6.9.0 < 12.0.0",
"npm": ">= 3.x <= 6.x",
"yarn": ">=0.27.5 || >=1.0.0-20170811"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/cli",
"version": "7.1.5",
"version": "7.2.0",
"description": "Babel command line.",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
@@ -36,8 +36,8 @@
"@babel/core": "^7.0.0-0"
},
"devDependencies": {
"@babel/core": "^7.1.5",
"@babel/helper-fixtures": "^7.0.0"
"@babel/core": "^7.2.0",
"@babel/helper-fixtures": "^7.2.0"
},
"bin": {
"babel": "./bin/babel.js",

View File

@@ -137,7 +137,11 @@ export default async function({ cliOptions, babelOptions }) {
const dirname = filename;
util
.readdirForCompilable(filename, cliOptions.includeDotfiles)
.readdirForCompilable(
filename,
cliOptions.includeDotfiles,
cliOptions.extensions,
)
.forEach(function(filename) {
_filenames.push(path.join(dirname, filename));
});

View File

@@ -29,8 +29,11 @@ export function readdir(
export function readdirForCompilable(
dirname: string,
includeDotfiles: boolean,
altExts?: Array<string>,
) {
return readdir(dirname, includeDotfiles, isCompilableExtension);
return readdir(dirname, includeDotfiles, function(filename) {
return isCompilableExtension(filename, altExts);
});
}
/**

View File

@@ -0,0 +1 @@
(() => 42)

View File

@@ -0,0 +1 @@
arr.map(x => x * MULTIPLIER);

View File

@@ -0,0 +1,3 @@
{
"args": ["src", "--out-file", "test.js", "--extensions", ".es"]
}

View File

@@ -0,0 +1,10 @@
"use strict";
(function () {
return 42;
});
"use strict";
arr.map(function (x) {
return x * MULTIPLIER;
});

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/core",
"version": "7.1.5",
"version": "7.2.0",
"description": "Babel compiler core.",
"main": "lib/index.js",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
@@ -34,15 +34,15 @@
},
"dependencies": {
"@babel/code-frame": "^7.0.0",
"@babel/generator": "^7.1.5",
"@babel/helpers": "^7.1.5",
"@babel/parser": "^7.1.5",
"@babel/generator": "^7.2.0",
"@babel/helpers": "^7.2.0",
"@babel/parser": "^7.2.0",
"@babel/template": "^7.1.2",
"@babel/traverse": "^7.1.5",
"@babel/types": "^7.1.5",
"@babel/traverse": "^7.1.6",
"@babel/types": "^7.2.0",
"convert-source-map": "^1.1.0",
"debug": "^3.1.0",
"json5": "^0.5.0",
"debug": "^4.1.0",
"json5": "^2.1.0",
"lodash": "^4.17.10",
"resolve": "^1.3.2",
"semver": "^5.4.1",

View File

@@ -67,7 +67,7 @@ export function buildPresetChain(
return {
plugins: dedupDescriptors(chain.plugins),
presets: dedupDescriptors(chain.presets),
options: chain.options,
options: chain.options.map(o => normalizeOptions(o)),
};
}

View File

@@ -55,6 +55,7 @@ export default function makeAPI(
async: () => false,
caller,
assertVersion,
tokTypes: undefined,
};
}

View File

@@ -10,6 +10,8 @@ export { version } from "../package.json";
export { getEnv } from "./config/helpers/environment";
export * as types from "@babel/types";
export { tokTypes } from "@babel/parser";
export { default as traverse } from "@babel/traverse";
export { default as template } from "@babel/template";

View File

@@ -1,14 +1,29 @@
// @flow
import type { FileResult } from "./transformation";
export default function transformFile(
filename: string,
opts?: Object = {},
callback: (?Error, FileResult | null) => void,
// duplicated from transform-file so we do not have to import anything here
type TransformFile = {
(filename: string, callback: Function): void,
(filename: string, opts: ?Object, callback: Function): void,
};
export const transformFile: TransformFile = (function transformFile(
filename,
opts,
callback,
) {
if (typeof opts === "function") {
callback = opts;
}
callback(new Error("Transforming files is not supported in browsers"), null);
}: Function);
export function transformFileSync() {
throw new Error("Transforming files is not supported in browsers");
}
export function transformFileAsync() {
return Promise.reject(
new Error("Transforming files is not supported in browsers"),
);
}

View File

@@ -1,5 +0,0 @@
// @flow
export default function transformFileSync() {
throw new Error("Transforming files is not supported in browsers");
}

View File

@@ -9,6 +9,14 @@ import {
type FileResultCallback,
} from "./transformation";
import typeof * as transformFileBrowserType from "./transform-file-browser";
import typeof * as transformFileType from "./transform-file";
// Kind of gross, but essentially asserting that the exports of this module are the same as the
// exports of transform-file-browser, since this file may be replaced at bundle time with
// transform-file-browser.
((({}: any): $Exact<transformFileBrowserType>): $Exact<transformFileType>);
type TransformFile = {
(filename: string, callback: FileResultCallback): void,
(filename: string, opts: ?InputOptions, callback: FileResultCallback): void,

View File

@@ -154,6 +154,14 @@ describe("api", function() {
);
});
it("exposes types", function() {
expect(babel.types).toBeDefined();
});
it("exposes the parser's token types", function() {
expect(babel.tokTypes).toBeDefined();
});
it("transformFile", function(done) {
const options = {
babelrc: false,

View File

@@ -43,9 +43,11 @@ function () {
}, _callee, this);
}));
return function bar() {
function bar() {
return _bar.apply(this, arguments);
};
}
return bar;
}()
}]);

View File

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

View File

@@ -140,6 +140,12 @@ export function ClassMethod(node: Object) {
this.print(node.body, node);
}
export function ClassPrivateMethod(node: Object) {
this._classMethodHead(node);
this.space();
this.print(node.body, node);
}
export function _classMethodHead(node) {
this.printJoin(node.decorators, node);

View File

@@ -113,10 +113,12 @@ export function ArrowFunctionExpression(node: Object) {
) {
if (
this.format.retainLines &&
node.loc &&
node.body.loc &&
node.loc.start.line < node.body.loc.start.line
) {
this.token("(");
if (firstParam.loc.start.line > node.loc.start.line) {
if (firstParam.loc && firstParam.loc.start.line > node.loc.start.line) {
this.indent();
this.print(firstParam, node);
this.dedent();

View File

@@ -166,6 +166,7 @@ export function YieldExpression(node: Object, parent: Object): boolean {
t.isCallExpression(parent) ||
t.isMemberExpression(parent) ||
t.isNewExpression(parent) ||
(t.isAwaitExpression(parent) && t.isYieldExpression(node)) ||
(t.isConditionalExpression(parent) && node === parent.test) ||
isClassExtendsClause(node, parent)
);

View File

@@ -363,14 +363,14 @@ export default class Printer {
}
if (needsParens) this.token("(");
this._printLeadingComments(node, parent);
this._printLeadingComments(node);
const loc = t.isProgram(node) || t.isFile(node) ? null : node.loc;
this.withSource("start", loc, () => {
this[node.type](node, parent);
});
this._printTrailingComments(node, parent);
this._printTrailingComments(node);
if (needsParens) this.token(")");
@@ -472,12 +472,12 @@ export default class Printer {
this.print(node, parent);
}
_printTrailingComments(node, parent) {
this._printComments(this._getComments(false, node, parent));
_printTrailingComments(node) {
this._printComments(this._getComments(false, node));
}
_printLeadingComments(node, parent) {
this._printComments(this._getComments(true, node, parent));
_printLeadingComments(node) {
this._printComments(this._getComments(true, node));
}
printInnerComments(node, indent = true) {

View File

@@ -10,3 +10,7 @@ function* asdf() {
function* a(b) {
(yield xhr({ url: "views/test.html" })).data;
}
(async function* () {
await (yield 1);
});

View File

@@ -11,4 +11,8 @@ function* a(b) {
(yield xhr({
url: "views/test.html"
})).data;
}
}
(async function* () {
await (yield 1);
});

View File

@@ -5,6 +5,15 @@ class Foo {
get foo() {}
set foo(bar) {}
async #foo() {}
#foo() {}
get #foo() {}
set #foo(bar) {}
* #foo() {}
async * #foo() {}
get #bar() {}
set #baz(taz) {}
static async foo() {}
static foo() {}
static ["foo"]() {}
@@ -52,4 +61,4 @@ class Foo {
get
static
() {}
}
}

View File

@@ -0,0 +1 @@
{ "plugins": ["classPrivateMethods", "asyncGenerators"] }

View File

@@ -9,6 +9,22 @@ class Foo {
set foo(bar) {}
async #foo() {}
#foo() {}
get #foo() {}
set #foo(bar) {}
*#foo() {}
async *#foo() {}
get #bar() {}
set #baz(taz) {}
static async foo() {}
static foo() {}

View File

@@ -0,0 +1,3 @@
src
test
*.log

View File

@@ -0,0 +1,19 @@
# @babel/plugin-class-features
> 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.
## Install
Using npm:
```sh
npm install --save-dev @babel/plugin-class-features
```
or using yarn:
```sh
yarn add @babel/plugin-class-features --dev
```

View File

@@ -0,0 +1,30 @@
{
"name": "@babel/helper-create-class-features-plugin",
"version": "7.2.1",
"author": "The Babel Team (https://babeljs.io/team)",
"license": "MIT",
"description": "Compile class public and private fields, private methods and decorators to ES6",
"repository": "https://github.com/babel/babel/tree/master/packages/babel-plugin-class-features",
"main": "lib/index.js",
"publishConfig": {
"access": "public"
},
"keywords": [
"babel",
"babel-plugin"
],
"dependencies": {
"@babel/helper-function-name": "^7.1.0",
"@babel/helper-member-expression-to-functions": "^7.0.0",
"@babel/helper-optimise-call-expression": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-replace-supers": "^7.1.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0"
},
"devDependencies": {
"@babel/core": "^7.2.0",
"@babel/helper-plugin-test-runner": "^7.0.0"
}
}

View File

@@ -0,0 +1,3 @@
export function hasDecorators(path) {
return !!(path.node.decorators && path.node.decorators.length);
}

View File

@@ -0,0 +1,87 @@
import { hasDecorators } from "./decorators";
export const FEATURES = Object.freeze({
//classes: 1 << 0,
fields: 1 << 1,
privateMethods: 1 << 2,
decorators: 1 << 3,
});
// We can't use a symbol because this needs to always be the same, even if
// this package isn't deduped by npm. e.g.
// - node_modules/
// - @babel/plugin-class-features
// - @babel/plugin-proposal-decorators
// - node_modules
// - @babel-plugin-class-features
const featuresKey = "@babel/plugin-class-features/featuresKey";
const looseKey = "@babel/plugin-class-features/looseKey";
export function enableFeature(file, feature, loose) {
// We can't blindly enable the feature because, if it was already set,
// "loose" can't be changed, so that
// @babel/plugin-class-properties { loose: true }
// @babel/plugin-class-properties { loose: false }
// is transformed in loose mode.
// We only enabled the feature if it was previously disabled.
if (!hasFeature(file, feature)) {
file.set(featuresKey, file.get(featuresKey) | feature);
if (loose) file.set(looseKey, file.get(looseKey) | feature);
}
}
function hasFeature(file, feature) {
return !!(file.get(featuresKey) & feature);
}
export function isLoose(file, feature) {
return !!(file.get(looseKey) & feature);
}
export function verifyUsedFeatures(path, file) {
if (hasDecorators(path) && !hasFeature(file, FEATURES.decorators)) {
throw path.buildCodeFrameError("Decorators are not enabled.");
}
if (hasFeature(file, FEATURES.decorators)) {
throw new Error(
"@babel/plugin-class-features doesn't support decorators yet.",
);
}
// NOTE: We can't use path.isPrivateMethod() because it isn't supported in <7.2.0
if (path.isPrivate() && path.isMethod()) {
if (!hasFeature(file, FEATURES.privateMethods)) {
throw path.buildCodeFrameError("Class private methods are not enabled.");
}
if (path.node.static) {
throw path.buildCodeFrameError(
"@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 (
hasFeature(file, FEATURES.privateMethods) &&
hasFeature(file, FEATURES.fields) &&
isLoose(file, FEATURES.privateMethods) !== isLoose(file, FEATURES.fields)
) {
throw path.buildCodeFrameError(
"'loose' mode configuration must be the same for both @babel/plugin-proposal-class-properties " +
"and @babel/plugin-proposal-private-methods",
);
}
if (path.isProperty()) {
if (!hasFeature(file, FEATURES.fields)) {
throw path.buildCodeFrameError("Class fields are not enabled.");
}
}
}

View File

@@ -0,0 +1,401 @@
import { template, traverse, types as t } from "@babel/core";
import { environmentVisitor } from "@babel/helper-replace-supers";
import memberExpressionToFunctions from "@babel/helper-member-expression-to-functions";
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 { 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,
});
}
}
return privateNamesMap;
}
export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
const initNodes = [];
for (const [name, value] of privateNamesMap) {
// In loose mode, both static and instance fields are transpiled using a
// secret non-enumerable property. Hence, we also need to generate that
// key (using the classPrivateFieldLooseKey helper).
// 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;
if (loose) {
initNodes.push(
template.statement.ast`
var ${id} = ${state.addHelper("classPrivateFieldLooseKey")}("${name}")
`,
);
} else if (isMethod && !isStatic) {
initNodes.push(template.statement.ast`var ${id} = new WeakSet();`);
} else if (!isStatic) {
initNodes.push(template.statement.ast`var ${id} = new WeakMap();`);
}
}
return initNodes;
}
// Traverses the class scope, handling private name references. If an inner
// class redeclares the same private name, it will hand off traversal to the
// restricted visitor (which doesn't traverse the inner class's inner scope).
const privateNameVisitor = {
PrivateName(path) {
const { privateNamesMap } = this;
const { node, parentPath } = path;
if (!parentPath.isMemberExpression({ property: node })) return;
if (!privateNamesMap.has(node.id.name)) return;
this.handle(parentPath);
},
Class(path) {
const { privateNamesMap } = this;
const body = path.get("body.body");
for (const prop of body) {
if (!prop.isPrivate()) {
continue;
}
if (!privateNamesMap.has(prop.node.key.id.name)) continue;
// This class redeclares the private name.
// So, we can only evaluate the things in the outer scope.
path.traverse(privateNameInnerVisitor, this);
path.skip();
break;
}
},
};
// Traverses the outer portion of a class, without touching the class's inner
// scope, for private names.
const privateNameInnerVisitor = traverse.visitors.merge([
{
PrivateName: privateNameVisitor.PrivateName,
},
environmentVisitor,
]);
const privateNameHandlerSpec = {
memoise(member, count) {
const { scope } = member;
const { object } = member.node;
const memo = scope.maybeGenerateMemoised(object);
if (!memo) {
return;
}
this.memoiser.set(object, memo, count);
},
receiver(member) {
const { object } = member.node;
if (this.memoiser.has(object)) {
return t.cloneNode(this.memoiser.get(object));
}
return t.cloneNode(object);
},
get(member) {
const { classRef, privateNamesMap, file } = this;
const { name } = member.node.property.id;
const {
id,
static: isStatic,
method: isMethod,
methodId,
} = privateNamesMap.get(name);
if (isStatic && !isMethod) {
return t.callExpression(
file.addHelper("classStaticPrivateFieldSpecGet"),
[this.receiver(member), t.cloneNode(classRef), t.cloneNode(id)],
);
} else if (isMethod) {
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),
]);
}
},
set(member, value) {
const { classRef, privateNamesMap, file } = this;
const { name } = member.node.property.id;
const { id, static: isStatic, method: isMethod } = 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,
]);
}
},
call(member, args) {
// The first access (the get) should do the memo assignment.
this.memoise(member, 1);
return optimiseCall(this.get(member), this.receiver(member), args);
},
};
const privateNameHandlerLoose = {
handle(member) {
const { privateNamesMap, file } = this;
const { object } = member.node;
const { name } = member.node.property.id;
member.replaceWith(
template.expression`BASE(REF, PROP)[PROP]`({
BASE: file.addHelper("classPrivateFieldLooseBase"),
REF: object,
PROP: privateNamesMap.get(name).id,
}),
);
},
};
export function transformPrivateNamesUsage(
ref,
path,
privateNamesMap,
loose,
state,
) {
const body = path.get("body");
if (loose) {
body.traverse(privateNameVisitor, {
privateNamesMap,
file: state,
...privateNameHandlerLoose,
});
} else {
memberExpressionToFunctions(body, privateNameVisitor, {
privateNamesMap,
classRef: ref,
file: state,
...privateNameHandlerSpec,
});
}
}
function buildPrivateFieldInitLoose(ref, prop, privateNamesMap) {
const { id } = privateNamesMap.get(prop.node.key.id.name);
const value = prop.node.value || prop.scope.buildUndefinedNode();
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
// configurable is false by default
// enumerable is false by default
writable: true,
value: ${value}
});
`;
}
function buildPrivateInstanceFieldInitSpec(ref, prop, privateNamesMap) {
const { id } = privateNamesMap.get(prop.node.key.id.name);
const value = prop.node.value || prop.scope.buildUndefinedNode();
return template.statement.ast`${id}.set(${ref}, {
// configurable is always false for private elements
// enumerable is always false for private elements
writable: true,
value: ${value},
})`;
}
function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) {
const { id } = privateNamesMap.get(prop.node.key.id.name);
const value = prop.node.value || prop.scope.buildUndefinedNode();
return template.statement.ast`
var ${id} = {
// configurable is false by default
// enumerable is false by default
writable: true,
value: ${value}
};
`;
}
function buildPrivateMethodInitLoose(ref, prop, privateNamesMap) {
const { methodId, id } = privateNamesMap.get(prop.node.key.id.name);
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}
});
`;
}
function buildPrivateInstanceMethodInitSpec(ref, prop, privateNamesMap) {
const { id } = privateNamesMap.get(prop.node.key.id.name);
return template.statement.ast`${id}.add(${ref})`;
}
function buildPublicFieldInitLoose(ref, prop) {
const { key, computed } = prop.node;
const value = prop.node.value || prop.scope.buildUndefinedNode();
return t.expressionStatement(
t.assignmentExpression(
"=",
t.memberExpression(ref, key, computed || t.isLiteral(key)),
value,
),
);
}
function buildPublicFieldInitSpec(ref, prop, state) {
const { key, computed } = prop.node;
const value = prop.node.value || prop.scope.buildUndefinedNode();
return t.expressionStatement(
t.callExpression(state.addHelper("defineProperty"), [
ref,
computed || t.isLiteral(key) ? key : t.stringLiteral(key.name),
value,
]),
);
}
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);
return t.variableDeclaration("var", [
t.variableDeclarator(methodId, methodValue),
]);
}
export function buildFieldsInitNodes(
ref,
props,
privateNamesMap,
state,
loose,
) {
const staticNodes = [];
const instanceNodes = [];
for (const prop of props) {
const isStatic = prop.node.static;
const isInstance = !isStatic;
const isPrivate = prop.isPrivate();
const isPublic = !isPrivate;
const isField = prop.isProperty();
const isMethod = !isField;
switch (true) {
case isStatic && isPrivate && isField && loose:
staticNodes.push(
buildPrivateFieldInitLoose(t.cloneNode(ref), prop, privateNamesMap),
);
break;
case isStatic && isPrivate && isField && !loose:
staticNodes.push(
buildPrivateStaticFieldInitSpec(prop, privateNamesMap),
);
break;
case isStatic && isPublic && isField && loose:
staticNodes.push(buildPublicFieldInitLoose(t.cloneNode(ref), prop));
break;
case isStatic && isPublic && isField && !loose:
staticNodes.push(
buildPublicFieldInitSpec(t.cloneNode(ref), prop, state),
);
break;
case isInstance && isPrivate && isField && loose:
instanceNodes.push(
buildPrivateFieldInitLoose(t.thisExpression(), prop, privateNamesMap),
);
break;
case isInstance && isPrivate && isField && !loose:
instanceNodes.push(
buildPrivateInstanceFieldInitSpec(
t.thisExpression(),
prop,
privateNamesMap,
),
);
break;
case isInstance && isPrivate && isMethod && loose:
instanceNodes.push(
buildPrivateMethodInitLoose(
t.thisExpression(),
prop,
privateNamesMap,
),
);
staticNodes.push(
buildPrivateInstanceMethodDeclaration(prop, privateNamesMap),
);
break;
case isInstance && isPrivate && isMethod && !loose:
instanceNodes.push(
buildPrivateInstanceMethodInitSpec(
t.thisExpression(),
prop,
privateNamesMap,
),
);
staticNodes.push(
buildPrivateInstanceMethodDeclaration(prop, privateNamesMap),
);
break;
case isInstance && isPublic && isField && loose:
instanceNodes.push(buildPublicFieldInitLoose(t.thisExpression(), prop));
break;
case isInstance && isPublic && isField && !loose:
instanceNodes.push(
buildPublicFieldInitSpec(t.thisExpression(), prop, state),
);
break;
default:
throw new Error("Unreachable.");
}
}
return { staticNodes, instanceNodes };
}

View File

@@ -0,0 +1,166 @@
import nameFunction from "@babel/helper-function-name";
import { types as t } from "@babel/core";
import {
buildPrivateNamesNodes,
buildPrivateNamesMap,
transformPrivateNamesUsage,
buildFieldsInitNodes,
} from "./fields";
import { injectInitialization, extractComputedKeys } from "./misc";
import {
enableFeature,
verifyUsedFeatures,
FEATURES,
isLoose,
} from "./features";
import pkg from "../package.json";
export { FEATURES };
// Note: Versions are represented as an integer. e.g. 7.1.5 is represented
// as 70000100005. This method is easier than using a semver-parsing
// package, but it breaks if we relese x.y.z where x, y or z are
// greater than 99_999.
const version = pkg.version.split(".").reduce((v, x) => v * 1e5 + +x, 0);
const versionKey = "@babel/plugin-class-features/version";
export function createClassFeaturePlugin({
name,
feature,
loose,
manipulateOptions,
}) {
return {
name,
manipulateOptions,
pre() {
enableFeature(this.file, feature, loose);
if (!this.file.get(versionKey) || this.file.get(versionKey) < version) {
this.file.set(versionKey, version);
}
},
visitor: {
Class(path, state) {
if (this.file.get(versionKey) !== version) return;
verifyUsedFeatures(path, this.file);
// Only fields are currently supported, this needs to be moved somewhere
// else when other features are added.
const loose = isLoose(this.file, FEATURES.fields);
let constructor;
const props = [];
const computedPaths = [];
const privateNames = new Set();
const body = path.get("body");
for (const path of body.get("body")) {
verifyUsedFeatures(path, this.file);
if (path.node.computed) {
computedPaths.push(path);
}
if (path.isPrivate()) {
const { name } = path.node.key.id;
if (privateNames.has(name)) {
throw path.buildCodeFrameError("Duplicate private field");
}
privateNames.add(name);
}
if (path.isProperty() || path.isPrivate()) {
props.push(path);
} else if (path.isClassMethod({ kind: "constructor" })) {
constructor = path;
}
}
if (!props.length) return;
let ref;
if (path.isClassExpression() || !path.node.id) {
nameFunction(path);
ref = path.scope.generateUidIdentifier("class");
} else {
ref = path.node.id;
}
const keysNodes = extractComputedKeys(
ref,
path,
computedPaths,
this.file,
);
const privateNamesMap = buildPrivateNamesMap(props);
const privateNamesNodes = buildPrivateNamesNodes(
privateNamesMap,
loose,
state,
);
transformPrivateNamesUsage(ref, path, privateNamesMap, loose, state);
const { staticNodes, instanceNodes } = buildFieldsInitNodes(
ref,
props,
privateNamesMap,
state,
loose,
);
if (instanceNodes.length > 0) {
injectInitialization(
path,
constructor,
instanceNodes,
(referenceVisitor, state) => {
for (const prop of props) {
if (prop.node.static) continue;
prop.traverse(referenceVisitor, state);
}
},
);
}
for (const prop of props) {
prop.remove();
}
if (
keysNodes.length === 0 &&
staticNodes.length === 0 &&
privateNamesNodes.length === 0
) {
return;
}
if (path.isClassExpression()) {
path.scope.push({ id: ref });
path.replaceWith(
t.assignmentExpression("=", t.cloneNode(ref), path.node),
);
} else if (!path.node.id) {
// Anonymous class declaration
path.node.id = ref;
}
path.insertBefore(keysNodes);
path.insertAfter([...privateNamesNodes, ...staticNodes]);
},
PrivateName(path) {
if (this.file.get(versionKey) !== version) return;
throw path.buildCodeFrameError(`Unknown PrivateName "${path}"`);
},
},
};
}

View File

@@ -0,0 +1,111 @@
import { template, traverse, types as t } from "@babel/core";
import { environmentVisitor } from "@babel/helper-replace-supers";
const findBareSupers = traverse.visitors.merge([
{
Super(path) {
const { node, parentPath } = path;
if (parentPath.isCallExpression({ callee: node })) {
this.push(parentPath);
}
},
},
environmentVisitor,
]);
const referenceVisitor = {
"TSTypeAnnotation|TypeAnnotation"(path) {
path.skip();
},
ReferencedIdentifier(path) {
if (this.scope.hasOwnBinding(path.node.name)) {
this.scope.rename(path.node.name);
path.skip();
}
},
};
const classFieldDefinitionEvaluationTDZVisitor = traverse.visitors.merge([
{
ReferencedIdentifier(path) {
if (
this.classBinding &&
this.classBinding === path.scope.getBinding(path.node.name)
) {
const classNameTDZError = this.file.addHelper("classNameTDZError");
const throwNode = t.callExpression(classNameTDZError, [
t.stringLiteral(path.node.name),
]);
path.replaceWith(t.sequenceExpression([throwNode, path.node]));
path.skip();
}
},
},
environmentVisitor,
]);
export function injectInitialization(path, constructor, nodes, renamer) {
if (!nodes.length) return;
const isDerived = !!path.node.superClass;
if (!constructor) {
const newConstructor = t.classMethod(
"constructor",
t.identifier("constructor"),
[],
t.blockStatement([]),
);
if (isDerived) {
newConstructor.params = [t.restElement(t.identifier("args"))];
newConstructor.body.body.push(template.statement.ast`super(...args)`);
}
[constructor] = path.get("body").unshiftContainer("body", newConstructor);
}
if (renamer) {
renamer(referenceVisitor, { scope: constructor.scope });
}
if (isDerived) {
const bareSupers = [];
constructor.traverse(findBareSupers, bareSupers);
for (const bareSuper of bareSupers) {
bareSuper.insertAfter(nodes);
}
} else {
constructor.get("body").unshiftContainer("body", nodes);
}
}
export function extractComputedKeys(ref, path, computedPaths, file) {
const declarations = [];
for (const computedPath of computedPaths) {
computedPath.traverse(classFieldDefinitionEvaluationTDZVisitor, {
classBinding: path.node.id && path.scope.getBinding(path.node.id.name),
file,
});
const computedNode = computedPath.node;
// Make sure computed property names are only evaluated once (upon class definition)
// and in the right order in combination with static properties
if (!computedPath.get("key").isConstantExpression()) {
const ident = path.scope.generateUidIdentifierBasedOnNode(
computedNode.key,
);
declarations.push(
t.variableDeclaration("var", [
t.variableDeclarator(ident, computedNode.key),
]),
);
computedNode.key = t.cloneNode(ident);
}
}
return declarations;
}

View File

@@ -0,0 +1,6 @@
{
"plugins": [
["proposal-class-properties", { "loose": true }, "name 1"],
["proposal-class-properties", { "loose": false }, "name 2"]
]
}

View File

@@ -0,0 +1,6 @@
class A {
constructor() {
this.foo = void 0;
}
}

View File

@@ -0,0 +1,3 @@
import runner from "@babel/helper-plugin-test-runner";
runner(__dirname);

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/helper-fixtures",
"version": "7.0.0",
"version": "7.2.0",
"description": "Helper function to support fixtures",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"license": "MIT",

View File

@@ -70,7 +70,7 @@ function findFile(filepath: string, allowJSON: boolean) {
throw new Error(`Found conflicting file matches: ${matches.join(", ")}`);
}
return matches[0] || filepath + ".js";
return matches[0];
}
export default function get(entryLoc): Array<Suite> {
@@ -101,10 +101,26 @@ export default function get(entryLoc): Array<Suite> {
}
function push(taskName, taskDir) {
const actualLoc = findFile(taskDir + "/input");
const expectLoc = findFile(taskDir + "/output", true /* allowJSON */);
const taskDirStats = fs.statSync(taskDir);
let actualLoc = findFile(taskDir + "/input");
let execLoc = findFile(taskDir + "/exec");
// If neither input nor exec is present it is not a real testcase
if (taskDirStats.isDirectory() && !actualLoc && !execLoc) {
if (fs.readdirSync(taskDir).length > 0) {
console.warn(`Skipped test folder with invalid layout: ${taskDir}`);
}
return;
} else if (!actualLoc) {
actualLoc = taskDir + "/input.js";
} else if (!execLoc) {
execLoc = taskDir + "/exec.js";
}
const expectLoc =
findFile(taskDir + "/output", true /* allowJSON */) ||
taskDir + "/output.js";
const actualLocAlias =
suiteName + "/" + taskName + "/" + path.basename(actualLoc);
const expectLocAlias =
@@ -112,7 +128,7 @@ export default function get(entryLoc): Array<Suite> {
let execLocAlias =
suiteName + "/" + taskName + "/" + path.basename(actualLoc);
if (fs.statSync(taskDir).isFile()) {
if (taskDirStats.isFile()) {
const ext = path.extname(taskDir);
if (EXTENSIONS.indexOf(ext) === -1) return;

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/helper-wrap-function",
"version": "7.1.0",
"version": "7.2.0",
"description": "Helper to wrap functions inside a function call.",
"repository": "https://github.com/babel/babel/tree/master/packages/babel-helper-wrap-function",
"license": "MIT",
@@ -12,6 +12,6 @@
"@babel/helper-function-name": "^7.1.0",
"@babel/template": "^7.1.0",
"@babel/traverse": "^7.1.0",
"@babel/types": "^7.0.0"
"@babel/types": "^7.2.0"
}
}

View File

@@ -3,7 +3,7 @@ import nameFunction from "@babel/helper-function-name";
import template from "@babel/template";
import * as t from "@babel/types";
const buildExpressionWrapper = template.expression(`
const buildAnonymousExpressionWrapper = template.expression(`
(function () {
var REF = FUNCTION;
return function NAME(PARAMS) {
@@ -12,6 +12,16 @@ const buildExpressionWrapper = template.expression(`
})()
`);
const buildNamedExpressionWrapper = template.expression(`
(function () {
var REF = FUNCTION;
function NAME(PARAMS) {
return REF.apply(this, arguments);
}
return NAME;
})()
`);
const buildDeclarationWrapper = template(`
function NAME(PARAMS) { return REF.apply(this, arguments); }
function REF() {
@@ -53,7 +63,9 @@ function plainFunction(path: NodePath, callId: Object) {
const functionId = node.id;
const wrapper = isDeclaration
? buildDeclarationWrapper
: buildExpressionWrapper;
: functionId
? buildNamedExpressionWrapper
: buildAnonymousExpressionWrapper;
if (path.isArrowFunctionExpression()) {
path.arrowFunctionToExpression();

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/helpers",
"version": "7.1.5",
"version": "7.2.0",
"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.1.5"
"@babel/types": "^7.2.0"
},
"devDependencies": {
"@babel/helper-plugin-test-runner": "^7.0.0"

View File

@@ -1739,3 +1739,18 @@ helpers.decorate = helper("7.1.5")`
return constructor;
}
`;
helpers.classPrivateMethodGet = helper("7.1.6")`
export default function _classPrivateMethodGet(receiver, privateSet, fn) {
if (!privateSet.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return fn;
}
`;
helpers.classPrivateMethodSet = helper("7.1.6")`
export default function _classPrivateMethodSet() {
throw new TypeError("attempted to reassign private method");
}
`;

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/node",
"version": "7.0.0",
"version": "7.2.0",
"description": "Babel command line",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
@@ -22,17 +22,17 @@
"@babel/polyfill": "^7.0.0",
"@babel/register": "^7.0.0",
"commander": "^2.8.1",
"fs-readdir-recursive": "^1.0.0",
"lodash": "^4.17.10",
"output-file-sync": "^2.0.0",
"v8flags": "^3.1.1"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/helper-fixtures": "^7.0.0"
"@babel/core": "^7.2.0",
"@babel/helper-fixtures": "^7.2.0",
"fs-readdir-recursive": "^1.0.0",
"output-file-sync": "^2.0.0"
},
"bin": {
"babel-node": "./bin/babel-node.js"

View File

@@ -52,6 +52,11 @@ program.option(
"The name of the 'env' to use when loading configs and plugins. " +
"Defaults to the value of BABEL_ENV, or else NODE_ENV, or else 'development'.",
);
commander.option(
"--root-mode [mode]",
"The project-root resolution mode. " +
"One of 'root' (the default), 'upward', or 'upward-optional'.",
);
program.option("-w, --plugins [string]", "", collect);
program.option("-b, --presets [string]", "", collect);
@@ -59,7 +64,7 @@ program.version(pkg.version);
program.usage("[options] [ -e script | script.js ] [arguments]");
program.parse(process.argv);
register({
const babelOptions = {
caller: {
name: "@babel/node",
},
@@ -70,12 +75,21 @@ register({
presets: program.presets,
configFile: program.configFile,
envName: program.envName,
rootMode: program.rootMode,
// Commander will default the "--no-" arguments to true, but we want to
// leave them undefined so that @babel/core can handle the
// default-assignment logic on its own.
babelrc: program.babelrc === true ? undefined : program.babelrc,
});
};
for (const key of Object.keys(babelOptions)) {
if (babelOptions[key] === undefined) {
delete babelOptions[key];
}
}
register(babelOptions);
const replPlugin = ({ types: t }) => ({
visitor: {

View File

@@ -1,6 +1,6 @@
{
"name": "@babel/parser",
"version": "7.1.5",
"version": "7.2.0",
"description": "A JavaScript parser",
"author": "Sebastian McKenzie <sebmck@gmail.com>",
"homepage": "https://babeljs.io/",
@@ -28,7 +28,7 @@
"node": ">=6.0.0"
},
"devDependencies": {
"@babel/helper-fixtures": "^7.0.0",
"@babel/helper-fixtures": "^7.2.0",
"charcodes": "0.1.0",
"unicode-11.0.0": "^0.7.7"
},

View File

@@ -23,6 +23,7 @@ import * as N from "../types";
import LValParser from "./lval";
import { reservedWords } from "../util/identifier";
import type { Pos, Position } from "../util/location";
import * as charCodes from "charcodes";
export default class ExpressionParser extends LValParser {
// Forward-declaration: defined in statement.js
@@ -296,18 +297,21 @@ export default class ExpressionParser extends LValParser {
}
const op = this.state.type;
if (op === tt.nullishCoalescing) {
this.expectPlugin("nullishCoalescingOperator");
} else if (op === tt.pipeline) {
if (op === tt.pipeline) {
this.expectPlugin("pipelineOperator");
this.state.inPipeline = true;
this.checkPipelineAtInfixOperator(left, leftStartPos);
} else if (op === tt.nullishCoalescing) {
this.expectPlugin("nullishCoalescingOperator");
}
this.next();
const startPos = this.state.start;
const startLoc = this.state.startLoc;
if (op === tt.pipeline) {
if (
op === tt.pipeline &&
this.getPluginOption("pipelineOperator", "proposal") === "minimal"
) {
if (
this.match(tt.name) &&
this.state.value === "await" &&
@@ -320,22 +324,17 @@ export default class ExpressionParser extends LValParser {
}
}
node.right = this.parseExprOp(
this.parseMaybeUnary(),
startPos,
startLoc,
op.rightAssociative ? prec - 1 : prec,
noIn,
);
node.right = this.parseExprOpRightExpr(op, prec, noIn);
this.finishNode(
node,
op === tt.logicalOR ||
op === tt.logicalAND ||
op === tt.nullishCoalescing
op === tt.logicalAND ||
op === tt.nullishCoalescing
? "LogicalExpression"
: "BinaryExpression",
);
return this.parseExprOp(
node,
leftStartPos,
@@ -348,6 +347,54 @@ export default class ExpressionParser extends LValParser {
return left;
}
// Helper function for `parseExprOp`. Parse the right-hand side of binary-
// operator expressions, then apply any operator-specific functions.
parseExprOpRightExpr(
op: TokenType,
prec: number,
noIn: ?boolean,
): N.Expression {
switch (op) {
case tt.pipeline:
if (this.getPluginOption("pipelineOperator", "proposal") === "smart") {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
return this.withTopicPermittingContext(() => {
return this.parseSmartPipelineBody(
this.parseExprOpBaseRightExpr(op, prec, noIn),
startPos,
startLoc,
);
});
}
// falls through
default:
return this.parseExprOpBaseRightExpr(op, prec, noIn);
}
}
// Helper function for `parseExprOpRightExpr`. Parse the right-hand side of
// binary-operator expressions without applying any operator-specific functions.
parseExprOpBaseRightExpr(
op: TokenType,
prec: number,
noIn: ?boolean,
): N.Expression {
const startPos = this.state.start;
const startLoc = this.state.startLoc;
return this.parseExprOp(
this.parseMaybeUnary(),
startPos,
startLoc,
op.rightAssociative ? prec - 1 : prec,
noIn,
);
}
// Parse unary operators, both prefix and postfix.
parseMaybeUnary(refShorthandDefaultPos: ?Pos): N.Expression {
@@ -565,7 +612,7 @@ export default class ExpressionParser extends LValParser {
);
this.state.yieldOrAwaitInPossibleArrowParameters = oldYOAIPAP;
} else {
this.toReferencedList(node.arguments);
this.toReferencedListDeep(node.arguments);
// We keep the old value if it isn't null, for cases like
// (x = async(yield)) => {}
@@ -718,6 +765,10 @@ export default class ExpressionParser extends LValParser {
// or `{}`.
parseExprAtom(refShorthandDefaultPos?: ?Pos): N.Expression {
// If a division operator appears in an expression position, the
// tokenizer got confused, and we force it to read a regexp instead.
if (this.state.type === tt.slash) this.readRegexp();
const canBeArrow = this.state.potentialArrowAt === this.state.start;
let node;
@@ -886,7 +937,14 @@ export default class ExpressionParser extends LValParser {
true,
refShorthandDefaultPos,
);
this.toReferencedList(node.elements);
if (!this.state.maybeInArrowParameters) {
// This could be an array pattern:
// ([a: string, b: string]) => {}
// In this case, we don't have to call toReferencedList. We will
// call it, if needed, when we are sure that it is a parenthesized
// expression by calling toReferencedListDeep.
this.toReferencedList(node.elements);
}
return this.finishNode(node, "ArrayExpression");
case tt.braceL:
@@ -924,6 +982,32 @@ export default class ExpressionParser extends LValParser {
}
}
case tt.hash: {
if (this.state.inPipeline) {
node = this.startNode();
if (
this.getPluginOption("pipelineOperator", "proposal") !== "smart"
) {
this.raise(
node.start,
"Primary Topic Reference found but pipelineOperator not passed 'smart' for 'proposal' option.",
);
}
this.next();
if (this.primaryTopicReferenceIsAllowedInCurrentTopicContext()) {
this.registerTopicReference();
return this.finishNode(node, "PipelinePrimaryTopicReference");
} else {
throw this.raise(
node.start,
`Topic reference was used in a lexical context without topic binding`,
);
}
}
}
default:
throw this.unexpected();
}
@@ -964,7 +1048,16 @@ export default class ExpressionParser extends LValParser {
parseFunctionExpression(): N.FunctionExpression | N.MetaProperty {
const node = this.startNode();
const meta = this.parseIdentifier(true);
// We do not do parseIdentifier here because when parseFunctionExpression
// is called we already know that the current token is a "name" with the value "function"
// This will improve perf a tiny little bit as we do not do validation but more importantly
// here is that parseIdentifier will remove an item from the expression stack
// if "function" or "class" is parsed as identifier (in objects e.g.), which should not happen here.
let meta = this.startNode();
this.next();
meta = this.createIdentifier(meta, "function");
if (this.state.inGenerator && this.eat(tt.dot)) {
return this.parseMetaProperty(node, meta, "sent");
}
@@ -1099,11 +1192,13 @@ export default class ExpressionParser extends LValParser {
),
);
if (this.match(tt.comma) && this.lookahead().type === tt.parenR) {
this.raise(
this.state.start,
"A trailing comma is not permitted after the rest element",
);
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);
}
break;
@@ -1157,10 +1252,10 @@ export default class ExpressionParser extends LValParser {
}
if (refNeedsArrowPos.start) this.unexpected(refNeedsArrowPos.start);
this.toReferencedListDeep(exprList, /* isParenthesizedExpr */ true);
if (exprList.length > 1) {
val = this.startNodeAt(innerStartPos, innerStartLoc);
val.expressions = exprList;
this.toReferencedList(val.expressions);
this.finishNodeAt(val, "SequenceExpression", innerEndPos, innerEndLoc);
} else {
val = exprList[0];
@@ -1693,7 +1788,7 @@ export default class ExpressionParser extends LValParser {
const oldInAsync = this.state.inAsync;
const oldInGenerator = this.state.inGenerator;
const oldMaybeInArrowParameters = this.state.maybeInArrowParameters;
this.state.inAsync = true;
this.state.inAsync = isAsync;
this.state.inGenerator = false;
this.state.maybeInArrowParameters = false;
this.parseFunctionBody(node, true);
@@ -1863,8 +1958,14 @@ export default class ExpressionParser extends LValParser {
parseIdentifier(liberal?: boolean): N.Identifier {
const node = this.startNode();
const name = this.parseIdentifierName(node.start, liberal);
return this.createIdentifier(node, name);
}
createIdentifier(node: N.Identifier, name: string): N.Identifier {
node.name = name;
node.loc.identifierName = name;
return this.finishNode(node, "Identifier");
}
@@ -1884,6 +1985,19 @@ export default class ExpressionParser extends LValParser {
name = this.state.value;
} else if (this.state.type.keyword) {
name = this.state.type.keyword;
// `class` and `function` keywords push new context into this.context.
// But there is no chance to pop the context if the keyword is consumed
// as an identifier such as a property name.
// If the previous token is a dot, this does not apply because the
// context-managing code already ignored the keyword
if (
(name === "class" || name === "function") &&
(this.state.lastTokEnd !== this.state.lastTokStart + 1 ||
this.input.charCodeAt(this.state.lastTokStart) !== charCodes.dot)
) {
this.state.context.pop();
}
} else {
throw this.unexpected();
}
@@ -1995,4 +2109,180 @@ export default class ExpressionParser extends LValParser {
}
return this.finishNode(node, "YieldExpression");
}
// Validates a pipeline (for any of the pipeline Babylon plugins) at the point
// of the infix operator `|>`.
checkPipelineAtInfixOperator(left: N.Expression, leftStartPos: number) {
if (this.getPluginOption("pipelineOperator", "proposal") === "smart") {
if (left.type === "SequenceExpression") {
// Ensure that the pipeline head is not a comma-delimited
// sequence expression.
throw this.raise(
leftStartPos,
`Pipeline head should not be a comma-separated sequence expression`,
);
}
}
}
parseSmartPipelineBody(
childExpression: N.Expression,
startPos: number,
startLoc: Position,
): N.PipelineBody {
const pipelineStyle = this.checkSmartPipelineBodyStyle(childExpression);
this.checkSmartPipelineBodyEarlyErrors(
childExpression,
pipelineStyle,
startPos,
);
return this.parseSmartPipelineBodyInStyle(
childExpression,
pipelineStyle,
startPos,
startLoc,
);
}
checkSmartPipelineBodyEarlyErrors(
childExpression: N.Expression,
pipelineStyle: N.PipelineStyle,
startPos: number,
): void {
if (this.match(tt.arrow)) {
// If the following token is invalidly `=>`, then throw a human-friendly error
// instead of something like 'Unexpected token, expected ";"'.
throw this.raise(
this.state.start,
`Unexpected arrow "=>" after pipeline body; arrow function in pipeline body must be parenthesized`,
);
} else if (
pipelineStyle === "PipelineTopicExpression" &&
childExpression.type === "SequenceExpression"
) {
throw this.raise(
startPos,
`Pipeline body may not be a comma-separated sequence expression`,
);
}
}
parseSmartPipelineBodyInStyle(
childExpression: N.Expression,
pipelineStyle: N.PipelineStyle,
startPos: number,
startLoc: Position,
): N.PipelineBody {
const bodyNode = this.startNodeAt(startPos, startLoc);
switch (pipelineStyle) {
case "PipelineBareFunction":
bodyNode.callee = childExpression;
break;
case "PipelineBareConstructor":
bodyNode.callee = childExpression.callee;
break;
case "PipelineBareAwaitedFunction":
bodyNode.callee = childExpression.argument;
break;
case "PipelineTopicExpression":
if (!this.topicReferenceWasUsedInCurrentTopicContext()) {
throw this.raise(
startPos,
`Pipeline is in topic style but does not use topic reference`,
);
}
bodyNode.expression = childExpression;
break;
default:
throw this.raise(startPos, `Unknown pipeline style ${pipelineStyle}`);
}
return this.finishNode(bodyNode, pipelineStyle);
}
checkSmartPipelineBodyStyle(expression: N.Expression): N.PipelineStyle {
switch (expression.type) {
default:
return this.isSimpleReference(expression)
? "PipelineBareFunction"
: "PipelineTopicExpression";
}
}
isSimpleReference(expression: N.Expression): boolean {
switch (expression.type) {
case "MemberExpression":
return (
!expression.computed && this.isSimpleReference(expression.object)
);
case "Identifier":
return true;
default:
return false;
}
}
// Enable topic references from outer contexts within smart pipeline bodies.
// The function modifies the parser's topic-context state to enable or disable
// the use of topic references with the smartPipelines plugin. They then run a
// callback, then they reset the parser to the old topic-context state that it
// had before the function was called.
withTopicPermittingContext<T>(callback: () => T): T {
const outerContextTopicState = this.state.topicContext;
this.state.topicContext = {
// Enable the use of the primary topic reference.
maxNumOfResolvableTopics: 1,
// Hide the use of any topic references from outer contexts.
maxTopicIndex: null,
};
try {
return callback();
} finally {
this.state.topicContext = outerContextTopicState;
}
}
// Disable topic references from outer contexts within syntax constructs
// such as the bodies of iteration statements.
// The function modifies the parser's topic-context state to enable or disable
// the use of topic references with the smartPipelines plugin. They then run a
// callback, then they reset the parser to the old topic-context state that it
// had before the function was called.
withTopicForbiddingContext<T>(callback: () => T): T {
const outerContextTopicState = this.state.topicContext;
this.state.topicContext = {
// Disable the use of the primary topic reference.
maxNumOfResolvableTopics: 0,
// Hide the use of any topic references from outer contexts.
maxTopicIndex: null,
};
try {
return callback();
} finally {
this.state.topicContext = outerContextTopicState;
}
}
// Register the use of a primary topic reference (`#`) within the current
// topic context.
registerTopicReference(): void {
this.state.topicContext.maxTopicIndex = 0;
}
primaryTopicReferenceIsAllowedInCurrentTopicContext(): boolean {
return this.state.topicContext.maxNumOfResolvableTopics >= 1;
}
topicReferenceWasUsedInCurrentTopicContext(): boolean {
return (
this.state.topicContext.maxTopicIndex != null &&
this.state.topicContext.maxTopicIndex >= 0
);
}
}

View File

@@ -177,11 +177,26 @@ export default class LValParser extends NodeUtils {
toReferencedList(
exprList: $ReadOnlyArray<?Expression>,
isInParens?: boolean, // eslint-disable-line no-unused-vars
isParenthesizedExpr?: boolean, // eslint-disable-line no-unused-vars
): $ReadOnlyArray<?Expression> {
return exprList;
}
toReferencedListDeep(
exprList: $ReadOnlyArray<?Expression>,
isParenthesizedExpr?: boolean,
): $ReadOnlyArray<?Expression> {
this.toReferencedList(exprList, isParenthesizedExpr);
for (const expr of exprList) {
if (expr && expr.type === "ArrayExpression") {
this.toReferencedListDeep(expr.elements);
}
}
return exprList;
}
// Parses spread element.
parseSpread<T: RestElement | SpreadElement>(
@@ -258,7 +273,20 @@ export default class LValParser extends NodeUtils {
break;
} else if (this.match(tt.ellipsis)) {
elts.push(this.parseAssignableListItemTypes(this.parseRest()));
this.expect(close);
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);
}
break;
} else {
const decorators = [];

View File

@@ -369,8 +369,18 @@ export default class StatementParser extends ExpressionParser {
parseDoStatement(node: N.DoWhileStatement): N.DoWhileStatement {
this.next();
this.state.labels.push(loopLabel);
node.body = this.parseStatement(false);
node.body =
// For the smartPipelines plugin: Disable topic references from outer
// contexts within the loop body. They are permitted in test expressions,
// outside of the loop body.
this.withTopicForbiddingContext(() =>
// Parse the loop body's body.
this.parseStatement(false),
);
this.state.labels.pop();
this.expect(tt._while);
node.test = this.parseParenExpression();
this.eat(tt.semi);
@@ -557,7 +567,17 @@ export default class StatementParser extends ExpressionParser {
} else {
clause.param = null;
}
clause.body = this.parseBlock();
clause.body =
// For the smartPipelines plugin: Disable topic references from outer
// contexts within the function body. They are permitted in function
// default-parameter expressions, which are part of the outer context,
// outside of the function body.
this.withTopicForbiddingContext(() =>
// Parse the catch clause's body.
this.parseBlock(false),
);
node.handler = this.finishNode(clause, "CatchClause");
}
@@ -585,8 +605,18 @@ export default class StatementParser extends ExpressionParser {
this.next();
node.test = this.parseParenExpression();
this.state.labels.push(loopLabel);
node.body = this.parseStatement(false);
node.body =
// For the smartPipelines plugin:
// Disable topic references from outer contexts within the loop body.
// They are permitted in test expressions, outside of the loop body.
this.withTopicForbiddingContext(() =>
// Parse loop body.
this.parseStatement(false),
);
this.state.labels.pop();
return this.finishNode(node, "WhileStatement");
}
@@ -596,7 +626,17 @@ export default class StatementParser extends ExpressionParser {
}
this.next();
node.object = this.parseParenExpression();
node.body = this.parseStatement(false);
node.body =
// For the smartPipelines plugin:
// Disable topic references from outer contexts within the function body.
// They are permitted in function default-parameter expressions, which are
// part of the outer context, outside of the function body.
this.withTopicForbiddingContext(() =>
// Parse the statement body.
this.parseStatement(false),
);
return this.finishNode(node, "WithStatement");
}
@@ -619,8 +659,8 @@ export default class StatementParser extends ExpressionParser {
const kind = this.state.type.isLoop
? "loop"
: this.match(tt._switch)
? "switch"
: null;
? "switch"
: null;
for (let i = this.state.labels.length - 1; i >= 0; i--) {
const label = this.state.labels[i];
if (label.statementStart === node.start) {
@@ -753,8 +793,18 @@ export default class StatementParser extends ExpressionParser {
this.expect(tt.semi);
node.update = this.match(tt.parenR) ? null : this.parseExpression();
this.expect(tt.parenR);
node.body = this.parseStatement(false);
node.body =
// For the smartPipelines plugin: Disable topic references from outer
// contexts within the loop body. They are permitted in test expressions,
// outside of the loop body.
this.withTopicForbiddingContext(() =>
// Parse the loop body.
this.parseStatement(false),
);
this.state.labels.pop();
return this.finishNode(node, "ForStatement");
}
@@ -778,8 +828,18 @@ export default class StatementParser extends ExpressionParser {
node.left = init;
node.right = this.parseExpression();
this.expect(tt.parenR);
node.body = this.parseStatement(false);
node.body =
// For the smartPipelines plugin:
// Disable topic references from outer contexts within the loop body.
// They are permitted in test expressions, outside of the loop body.
this.withTopicForbiddingContext(() =>
// Parse loop body.
this.parseStatement(false),
);
this.state.labels.pop();
return this.finishNode(node, type);
}
@@ -887,11 +947,18 @@ export default class StatementParser extends ExpressionParser {
}
this.parseFunctionParams(node);
this.parseFunctionBodyAndFinish(
node,
isStatement ? "FunctionDeclaration" : "FunctionExpression",
allowExpressionBody,
);
// For the smartPipelines plugin: Disable topic references from outer
// contexts within the function body. They are permitted in test
// expressions, outside of the function body.
this.withTopicForbiddingContext(() => {
// Parse the function body.
this.parseFunctionBodyAndFinish(
node,
isStatement ? "FunctionDeclaration" : "FunctionExpression",
allowExpressionBody,
);
});
this.state.inFunction = oldInFunc;
this.state.inMethod = oldInMethod;
@@ -966,44 +1033,49 @@ export default class StatementParser extends ExpressionParser {
this.expect(tt.braceL);
while (!this.eat(tt.braceR)) {
if (this.eat(tt.semi)) {
if (decorators.length > 0) {
// For the smartPipelines plugin: Disable topic references from outer
// contexts within the class body. They are permitted in test expressions,
// outside of the class body.
this.withTopicForbiddingContext(() => {
while (!this.eat(tt.braceR)) {
if (this.eat(tt.semi)) {
if (decorators.length > 0) {
this.raise(
this.state.lastTokEnd,
"Decorators must not be followed by a semicolon",
);
}
continue;
}
if (this.match(tt.at)) {
decorators.push(this.parseDecorator());
continue;
}
const member = this.startNode();
// steal the decorators if there are any
if (decorators.length) {
member.decorators = decorators;
this.resetStartLocationFromNode(member, decorators[0]);
decorators = [];
}
this.parseClassMember(classBody, member, state);
if (
member.kind === "constructor" &&
member.decorators &&
member.decorators.length > 0
) {
this.raise(
this.state.lastTokEnd,
"Decorators must not be followed by a semicolon",
member.start,
"Decorators can't be used with a constructor. Did you mean '@dec class { ... }'?",
);
}
continue;
}
if (this.match(tt.at)) {
decorators.push(this.parseDecorator());
continue;
}
const member = this.startNode();
// steal the decorators if there are any
if (decorators.length) {
member.decorators = decorators;
this.resetStartLocationFromNode(member, decorators[0]);
decorators = [];
}
this.parseClassMember(classBody, member, state);
if (
member.kind === "constructor" &&
member.decorators &&
member.decorators.length > 0
) {
this.raise(
member.start,
"Decorators can't be used with a constructor. Did you mean '@dec class { ... }'?",
);
}
}
});
if (decorators.length) {
this.raise(

View File

@@ -38,7 +38,7 @@ export function getPluginOption(
return null;
}
const PIPELINE_PROPOSALS = ["minimal"];
const PIPELINE_PROPOSALS = ["minimal", "smart"];
export function validatePlugins(plugins: PluginList) {
if (hasPlugin(plugins, "decorators")) {
@@ -77,7 +77,7 @@ export function validatePlugins(plugins: PluginList) {
) {
throw new Error(
"'pipelineOperator' requires 'proposal' option whose value should be one of: " +
PIPELINE_PROPOSALS.join(", "),
PIPELINE_PROPOSALS.map(p => `'${p}'`).join(", "),
);
}
}

View File

@@ -6,10 +6,11 @@ import * as N from "../types";
import type { Options } from "../options";
import type { Pos, Position } from "../util/location";
import type State from "../tokenizer/state";
import { types as tc } from "../tokenizer/context";
import * as charCodes from "charcodes";
import { isIteratorStart } from "../util/identifier";
const primitiveTypes = [
const reservedTypes = [
"any",
"bool",
"boolean",
@@ -503,8 +504,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
checkReservedType(word: string, startLoc: number) {
if (primitiveTypes.indexOf(word) > -1) {
this.raise(startLoc, `Cannot overwrite primitive type ${word}`);
if (reservedTypes.indexOf(word) > -1) {
this.raise(startLoc, `Cannot overwrite reserved type ${word}`);
}
}
@@ -1976,7 +1977,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// type casts that we've found that are illegal in this context
toReferencedList(
exprList: $ReadOnlyArray<?N.Expression>,
isInParens?: boolean,
isParenthesizedExpr?: boolean,
): $ReadOnlyArray<?N.Expression> {
for (let i = 0; i < exprList.length; i++) {
const expr = exprList[i];
@@ -1984,7 +1985,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
expr &&
expr.type === "TypeCastExpression" &&
(!expr.extra || !expr.extra.parenthesized) &&
(exprList.length > 1 || !isInParens)
(exprList.length > 1 || !isParenthesizedExpr)
) {
this.raise(
expr.typeAnnotation.start,
@@ -2392,7 +2393,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
refNeedsArrowPos?: ?Pos,
): N.Expression {
let jsxError = null;
if (tt.jsxTagStart && this.match(tt.jsxTagStart)) {
if (
this.hasPlugin("jsx") &&
(this.match(tt.jsxTagStart) || this.isRelational("<"))
) {
const state = this.state.clone();
try {
return super.parseMaybeAssign(
@@ -2408,7 +2412,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
// Remove `tc.j_expr` and `tc.j_oTag` from context added
// by parsing `jsxTagStart` to stop the JSX plugin from
// messing with the tokens
this.state.context.length -= 2;
const cLength = this.state.context.length;
if (this.state.context[cLength - 1] === tc.j_oTag) {
this.state.context.length -= 2;
}
jsxError = err;
} else {

View File

@@ -506,6 +506,15 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return this.parseLiteral(this.state.value, "JSXText");
} else if (this.match(tt.jsxTagStart)) {
return this.jsxParseElement();
} else if (
this.isRelational("<") &&
this.state.input.charCodeAt(this.state.pos) !==
charCodes.exclamationMark
) {
// In case we encounter an lt token here it will always be the start of
// jsx as the lt sign is not allowed in places that expect an expression
this.finishToken(tt.jsxTagStart);
return this.jsxParseElement();
} else {
return super.parseExprAtom(refShortHandDefaultPos);
}
@@ -538,7 +547,12 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}
if (code === charCodes.lessThan && this.state.exprAllowed) {
if (
code === charCodes.lessThan &&
this.state.exprAllowed &&
this.state.input.charCodeAt(this.state.pos + 1) !==
charCodes.exclamationMark
) {
++this.state.pos;
return this.finishToken(tt.jsxTagStart);
}

View File

@@ -314,13 +314,19 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
tsParseBindingListForSignature(): $ReadOnlyArray<
N.Identifier | N.RestElement,
N.Identifier | N.RestElement | N.ObjectPattern,
> {
return this.parseBindingList(tt.parenR).map(pattern => {
if (pattern.type !== "Identifier" && pattern.type !== "RestElement") {
if (
pattern.type !== "Identifier" &&
pattern.type !== "RestElement" &&
pattern.type !== "ObjectPattern"
) {
throw this.unexpected(
pattern.start,
"Name in a signature must be an Identifier.",
`Name in a signature must be an Identifier or ObjectPattern, instead got ${
pattern.type
}`,
);
}
return pattern;
@@ -597,8 +603,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
const type = this.match(tt._void)
? "TSVoidKeyword"
: this.match(tt._null)
? "TSNullKeyword"
: keywordTypeFromName(this.state.value);
? "TSNullKeyword"
: keywordTypeFromName(this.state.value);
if (type !== undefined && this.lookahead().type !== tt.dot) {
const node: N.TsKeywordType = this.startNode();
this.next();
@@ -691,8 +697,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return operator
? this.tsParseTypeOperator(operator)
: this.isContextual("infer")
? this.tsParseInferType()
: this.tsParseArrayTypeOrHigher();
? this.tsParseInferType()
: this.tsParseArrayTypeOrHigher();
}
tsParseUnionOrIntersectionType(
@@ -747,6 +753,22 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.next();
return true;
}
if (this.match(tt.braceL)) {
let braceStackCounter = 1;
this.next();
while (braceStackCounter > 0) {
if (this.match(tt.braceL)) {
++braceStackCounter;
} else if (this.match(tt.braceR)) {
--braceStackCounter;
}
this.next();
}
return true;
}
return false;
}
@@ -908,7 +930,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
node.extends = this.tsParseHeritageClause();
}
const body: N.TSInterfaceBody = this.startNode();
body.body = this.tsParseObjectTypeMembers();
body.body = this.tsInType(this.tsParseObjectTypeMembers.bind(this));
node.body = this.finishNode(body, "TSInterfaceBody");
return this.finishNode(node, "TSInterfaceDeclaration");
}
@@ -1277,11 +1299,17 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return undefined;
}
const oldInAsync = this.state.inAsync;
const oldInGenerator = this.state.inGenerator;
this.state.inAsync = true;
this.state.inGenerator = false;
res.id = null;
res.generator = false;
res.expression = true; // May be set again by parseFunctionBody.
res.async = true;
this.parseFunctionBody(res, true);
this.state.inAsync = oldInAsync;
this.state.inGenerator = oldInGenerator;
return this.finishNode(res, "ArrowFunctionExpression");
}
@@ -1381,8 +1409,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
type === "FunctionDeclaration"
? "TSDeclareFunction"
: type === "ClassMethod"
? "TSDeclareMethod"
: undefined;
? "TSDeclareMethod"
: undefined;
if (bodilessType && !this.match(tt.braceL) && this.isLineTerminator()) {
this.finishNode(node, bodilessType);
return;

View File

@@ -12,7 +12,7 @@ export class TokContext {
token: string,
isExpr?: boolean,
preserveSpace?: boolean,
override?: Function, // Takes a Tokenizer as a this-parameter, and returns void.
override?: ?Function, // Takes a Tokenizer as a this-parameter, and returns void.
) {
this.token = token;
this.isExpr = !!isExpr;
@@ -31,11 +31,12 @@ export const types: {
} = {
braceStatement: new TokContext("{", false),
braceExpression: new TokContext("{", true),
templateQuasi: new TokContext("${", true),
templateQuasi: new TokContext("${", false),
parenStatement: new TokContext("(", false),
parenExpression: new TokContext("(", true),
template: new TokContext("`", true, true, p => p.readTmplToken()),
functionExpression: new TokContext("function", true),
functionStatement: new TokContext("function", false),
};
// Token-specific context update code
@@ -46,33 +47,26 @@ tt.parenR.updateContext = tt.braceR.updateContext = function() {
return;
}
const out = this.state.context.pop();
if (
out === types.braceStatement &&
this.curContext() === types.functionExpression
) {
this.state.context.pop();
this.state.exprAllowed = false;
} else if (out === types.templateQuasi) {
this.state.exprAllowed = true;
} else {
this.state.exprAllowed = !out.isExpr;
let out = this.state.context.pop();
if (out === types.braceStatement && this.curContext().token === "function") {
out = this.state.context.pop();
}
this.state.exprAllowed = !out.isExpr;
};
tt.name.updateContext = function(prevType) {
if (this.state.value === "of" && this.curContext() === types.parenStatement) {
this.state.exprAllowed = !prevType.beforeExpr;
return;
}
this.state.exprAllowed = false;
if (prevType === tt._let || prevType === tt._const || prevType === tt._var) {
if (lineBreak.test(this.input.slice(this.state.end))) {
this.state.exprAllowed = true;
let allowed = false;
if (prevType !== tt.dot) {
if (
(this.state.value === "of" && !this.state.exprAllowed) ||
(this.state.value === "yield" && this.state.inGenerator)
) {
allowed = true;
}
}
this.state.exprAllowed = allowed;
if (this.state.isIterator) {
this.state.isIterator = false;
}
@@ -107,8 +101,22 @@ tt.incDec.updateContext = function() {
};
tt._function.updateContext = tt._class.updateContext = function(prevType) {
if (this.state.exprAllowed && !this.braceIsBlock(prevType)) {
if (
prevType.beforeExpr &&
prevType !== tt.semi &&
prevType !== tt._else &&
!(
prevType === tt._return &&
lineBreak.test(this.input.slice(this.state.lastTokEnd, this.state.start))
) &&
!(
(prevType === tt.colon || prevType === tt.braceL) &&
this.curContext() === types.b_stat
)
) {
this.state.context.push(types.functionExpression);
} else {
this.state.context.push(types.functionStatement);
}
this.state.exprAllowed = false;

View File

@@ -374,7 +374,36 @@ export default class Tokenizer extends LocationParser {
// into it.
//
// All in the name of speed.
//
// number sign is "#"
readToken_numberSign(): void {
if (this.state.pos === 0 && this.readToken_interpreter()) {
return;
}
const nextPos = this.state.pos + 1;
const next = this.input.charCodeAt(nextPos);
if (next >= charCodes.digit0 && next <= charCodes.digit9) {
this.raise(this.state.pos, "Unexpected digit after hash token");
}
if (
(this.hasPlugin("classPrivateProperties") ||
this.hasPlugin("classPrivateMethods")) &&
this.state.classLevel > 0
) {
++this.state.pos;
this.finishToken(tt.hash);
return;
} else if (
this.getPluginOption("pipelineOperator", "proposal") === "smart"
) {
this.finishOp(tt.hash, 1);
} else {
this.raise(this.state.pos, "Unexpected character '#'");
}
}
readToken_dot(): void {
const next = this.input.charCodeAt(this.state.pos + 1);
if (next >= charCodes.digit0 && next <= charCodes.digit9) {
@@ -623,24 +652,8 @@ export default class Tokenizer extends LocationParser {
getTokenFromCode(code: number): void {
switch (code) {
case charCodes.numberSign:
if (this.state.pos === 0 && this.readToken_interpreter()) {
return;
}
if (
(this.hasPlugin("classPrivateProperties") ||
this.hasPlugin("classPrivateMethods")) &&
this.state.classLevel > 0
) {
++this.state.pos;
this.finishToken(tt.hash);
return;
} else {
this.raise(
this.state.pos,
`Unexpected character '${String.fromCodePoint(code)}'`,
);
}
this.readToken_numberSign();
return;
// The interpretation of a dot depends on whether it is followed
// by a digit or another two dots.
@@ -881,10 +894,10 @@ export default class Tokenizer extends LocationParser {
radix === 16
? allowedNumericSeparatorSiblings.hex
: radix === 10
? allowedNumericSeparatorSiblings.dec
: radix === 8
? allowedNumericSeparatorSiblings.oct
: allowedNumericSeparatorSiblings.bin;
? allowedNumericSeparatorSiblings.dec
: radix === 8
? allowedNumericSeparatorSiblings.oct
: allowedNumericSeparatorSiblings.bin;
let total = 0;
@@ -971,14 +984,26 @@ export default class Tokenizer extends LocationParser {
readNumber(startsWithDot: boolean): void {
const start = this.state.pos;
let octal = this.input.charCodeAt(start) === charCodes.digit0;
let isFloat = false;
let isBigInt = false;
if (!startsWithDot && this.readInt(10) === null) {
this.raise(start, "Invalid number");
}
if (octal && this.state.pos == start + 1) octal = false; // number === 0
let octal =
this.state.pos - start >= 2 &&
this.input.charCodeAt(start) === charCodes.digit0;
if (octal) {
if (this.state.strict) {
this.raise(
start,
"Legacy octal literals are not allowed in strict mode",
);
}
if (/[89]/.test(this.input.slice(start, this.state.pos))) {
octal = false;
}
}
let next = this.input.charCodeAt(this.state.pos);
if (next === charCodes.dot && !octal) {
@@ -1022,18 +1047,7 @@ export default class Tokenizer extends LocationParser {
return;
}
let val;
if (isFloat) {
val = parseFloat(str);
} else if (!octal || str.length === 1) {
val = parseInt(str, 10);
} else if (this.state.strict) {
this.raise(start, "Invalid number");
} else if (/[89]/.test(str)) {
val = parseInt(str, 10);
} else {
val = parseInt(str, 8);
}
const val = octal ? parseInt(str, 8) : parseFloat(str);
this.finishToken(tt.num, val);
}
@@ -1324,14 +1338,25 @@ export default class Tokenizer extends LocationParser {
}
braceIsBlock(prevType: TokenType): boolean {
if (prevType === tt.colon) {
const parent = this.curContext();
if (parent === ct.braceStatement || parent === ct.braceExpression) {
return !parent.isExpr;
}
const parent = this.curContext();
if (parent === ct.functionExpression || parent === ct.functionStatement) {
return true;
}
if (
prevType === tt.colon &&
(parent === ct.braceStatement || parent === ct.braceExpression)
) {
return !parent.isExpr;
}
if (prevType === tt._return) {
// The check for `tt.name && exprAllowed` detects whether we are
// after a `yield` or `of` construct. See the `updateContext` for
// `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),
);
@@ -1341,13 +1366,22 @@ export default class Tokenizer extends LocationParser {
prevType === tt._else ||
prevType === tt.semi ||
prevType === tt.eof ||
prevType === tt.parenR
prevType === tt.parenR ||
prevType === tt.arrow
) {
return true;
}
if (prevType === tt.braceL) {
return this.curContext() === ct.braceStatement;
return parent === ct.braceStatement;
}
if (
prevType === tt._var ||
prevType === tt._let ||
prevType === tt._const
) {
return false;
}
if (prevType === tt.relational) {

View File

@@ -6,7 +6,7 @@ import { Position } from "../util/location";
import { types as ct, type TokContext } from "./context";
import type { Token } from "./index";
import { types as tt, type TokenType } from "./types";
import { types as tt, type TokenType, type TopicContextState } from "./types";
export default class State {
init(options: Options, input: string): void {
@@ -26,6 +26,7 @@ export default class State {
this.maybeInArrowParameters = false;
this.inGenerator = false;
this.inAsync = false;
this.inPipeline = false;
this.inPropertyName = false;
this.inType = false;
this.inClassProperty = false;
@@ -33,6 +34,12 @@ export default class State {
this.hasFlowComment = false;
this.isIterator = false;
// Used by smartPipelines.
this.topicContext = {
maxNumOfResolvableTopics: 0,
maxTopicIndex: null,
};
this.classLevel = 0;
this.labels = [];
@@ -104,6 +111,7 @@ export default class State {
inGenerator: boolean;
inMethod: boolean | N.MethodKind;
inAsync: boolean;
inPipeline: boolean;
inType: boolean;
noAnonFunctionType: boolean;
inPropertyName: boolean;
@@ -111,6 +119,9 @@ export default class State {
hasFlowComment: boolean;
isIterator: boolean;
// For the smartPipelines plugin:
topicContext: TopicContextState;
// Check whether we are in a (nested) class or not.
classLevel: number;

View File

@@ -174,7 +174,7 @@ export const keywords = {
new: new KeywordTokenType("new", { beforeExpr, startsExpr }),
this: new KeywordTokenType("this", { startsExpr }),
super: new KeywordTokenType("super", { startsExpr }),
class: new KeywordTokenType("class"),
class: new KeywordTokenType("class", { startsExpr }),
extends: new KeywordTokenType("extends", { beforeExpr }),
export: new KeywordTokenType("export"),
import: new KeywordTokenType("import", { startsExpr }),
@@ -193,3 +193,17 @@ export const keywords = {
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

@@ -566,6 +566,38 @@ export type SequenceExpression = NodeBase & {
expressions: $ReadOnlyArray<Expression>,
};
// Pipelines
export type PipelineBody = NodeBase & {
type: "PipelineBody",
};
export type PipelineBareFunctionBody = NodeBase & {
type: "PipelineBareFunctionBody",
callee: Expression,
};
export type PipelineBareConstructorBody = NodeBase & {
type: "PipelineBareConstructorBody",
callee: Expression,
};
export type PipelineBareAwaitedFunctionBody = NodeBase & {
type: "PipelineBareAwaitedFunctionBody",
callee: Expression,
};
export type PipelineTopicBody = NodeBase & {
type: "PipelineTopicBody",
expression: Expression,
};
export type PipelineStyle =
| "PipelineBareFunction"
| "PipelineBareConstructor"
| "PipelineBareAwaitedFunction"
| "PipelineTopicExpression";
// Template Literals
export type TemplateLiteral = NodeBase & {
@@ -1037,7 +1069,7 @@ export type TsSignatureDeclaration =
export type TsSignatureDeclarationOrIndexSignatureBase = NodeBase & {
// Not using TypeScript's "ParameterDeclaration" here, since it's inconsistent with regular functions.
parameters: $ReadOnlyArray<Identifier | RestElement>,
parameters: $ReadOnlyArray<Identifier | RestElement | ObjectPattern>,
typeAnnotation: ?TsTypeAnnotation,
};

View File

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

View File

@@ -0,0 +1 @@
09.5

View File

@@ -0,0 +1,70 @@
{
"type": "File",
"start": 0,
"end": 4,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 4
}
},
"program": {
"type": "Program",
"start": 0,
"end": 4,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 4
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start": 0,
"end": 4,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 4
}
},
"expression": {
"type": "NumericLiteral",
"start": 0,
"end": 4,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 4
}
},
"extra": {
"rawValue": 9.5,
"raw": "09.5"
},
"value": 9.5
}
}
],
"directives": []
}
}

View File

@@ -0,0 +1 @@
07.5

View File

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

View File

@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \")\" (1:18)"
"throws": "Rest parameter must be last formal parameter (1:18)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Invalid number (1:33)"
"throws": "Legacy octal literals are not allowed in strict mode (1:33)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Invalid number (1:36)"
"throws": "Legacy octal literals are not allowed in strict mode (1:36)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Invalid number (1:65)"
"throws": "Legacy octal literals are not allowed in strict mode (1:65)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Invalid number (2:10)"
"throws": "Legacy octal literals are not allowed in strict mode (2:10)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Invalid number (2:10)"
"throws": "Legacy octal literals are not allowed in strict mode (2:10)"
}

View File

@@ -0,0 +1,6 @@
function foo (
first,
...second,
third,
) {
};

View File

@@ -0,0 +1,3 @@
{
"throws": "Rest parameter must be last formal parameter (3:13)"
}

View File

@@ -0,0 +1 @@
(...rest,) => {}

View File

@@ -0,0 +1,3 @@
{
"throws": "A trailing comma is not permitted after the rest element (1:8)"
}

View File

@@ -0,0 +1,5 @@
(
first,
...second,
third
) => {};

View File

@@ -0,0 +1,3 @@
{
"throws": "Rest parameter must be last formal parameter (3:13)"
}

View File

@@ -0,0 +1 @@
for (const {a} of /b/) {}

View File

@@ -0,0 +1,194 @@
{
"type": "File",
"start": 0,
"end": 25,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 25
}
},
"program": {
"type": "Program",
"start": 0,
"end": 25,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 25
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ForOfStatement",
"start": 0,
"end": 25,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 25
}
},
"await": false,
"left": {
"type": "VariableDeclaration",
"start": 5,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 14
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 11,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 14
}
},
"id": {
"type": "ObjectPattern",
"start": 11,
"end": 14,
"loc": {
"start": {
"line": 1,
"column": 11
},
"end": {
"line": 1,
"column": 14
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 13
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 13
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": true,
"value": {
"type": "Identifier",
"start": 12,
"end": 13,
"loc": {
"start": {
"line": 1,
"column": 12
},
"end": {
"line": 1,
"column": 13
},
"identifierName": "a"
},
"name": "a"
},
"extra": {
"shorthand": true
}
}
]
},
"init": null
}
],
"kind": "const"
},
"right": {
"type": "RegExpLiteral",
"start": 18,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 18
},
"end": {
"line": 1,
"column": 21
}
},
"extra": {
"raw": "/b/"
},
"pattern": "b",
"flags": ""
},
"body": {
"type": "BlockStatement",
"start": 23,
"end": 25,
"loc": {
"start": {
"line": 1,
"column": 23
},
"end": {
"line": 1,
"column": 25
}
},
"body": [],
"directives": []
}
}
],
"directives": []
}
}

View File

@@ -0,0 +1 @@
for (let {a} of /b/) {}

View File

@@ -0,0 +1,194 @@
{
"type": "File",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"program": {
"type": "Program",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ForOfStatement",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"await": false,
"left": {
"type": "VariableDeclaration",
"start": 5,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 12
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 9,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 12
}
},
"id": {
"type": "ObjectPattern",
"start": 9,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 12
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": true,
"value": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "a"
},
"name": "a"
},
"extra": {
"shorthand": true
}
}
]
},
"init": null
}
],
"kind": "let"
},
"right": {
"type": "RegExpLiteral",
"start": 16,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 19
}
},
"extra": {
"raw": "/b/"
},
"pattern": "b",
"flags": ""
},
"body": {
"type": "BlockStatement",
"start": 21,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 21
},
"end": {
"line": 1,
"column": 23
}
},
"body": [],
"directives": []
}
}
],
"directives": []
}
}

View File

@@ -0,0 +1 @@
for (var {a} of /b/) {}

View File

@@ -0,0 +1,194 @@
{
"type": "File",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"program": {
"type": "Program",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ForOfStatement",
"start": 0,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 1,
"column": 23
}
},
"await": false,
"left": {
"type": "VariableDeclaration",
"start": 5,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 12
}
},
"declarations": [
{
"type": "VariableDeclarator",
"start": 9,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 12
}
},
"id": {
"type": "ObjectPattern",
"start": 9,
"end": 12,
"loc": {
"start": {
"line": 1,
"column": 9
},
"end": {
"line": 1,
"column": 12
}
},
"properties": [
{
"type": "ObjectProperty",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
}
},
"method": false,
"key": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "a"
},
"name": "a"
},
"computed": false,
"shorthand": true,
"value": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "a"
},
"name": "a"
},
"extra": {
"shorthand": true
}
}
]
},
"init": null
}
],
"kind": "var"
},
"right": {
"type": "RegExpLiteral",
"start": 16,
"end": 19,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 19
}
},
"extra": {
"raw": "/b/"
},
"pattern": "b",
"flags": ""
},
"body": {
"type": "BlockStatement",
"start": 21,
"end": 23,
"loc": {
"start": {
"line": 1,
"column": 21
},
"end": {
"line": 1,
"column": 23
}
},
"body": [],
"directives": []
}
}
],
"directives": []
}
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Invalid number (1:21)"
"throws": "Legacy octal literals are not allowed in strict mode (1:21)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \")\" (1:18)"
"throws": "Rest parameter must be last formal parameter (1:18)"
}

View File

@@ -1,3 +1,3 @@
{
"throws": "Unexpected token, expected \")\" (1:5)"
"throws": "Rest parameter must be last formal parameter (1:5)"
}

View File

@@ -0,0 +1,3 @@
function *f() { yield
{}/1/g
}

View File

@@ -0,0 +1,172 @@
{
"type": "File",
"start": 0,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"program": {
"type": "Program",
"start": 0,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "FunctionDeclaration",
"start": 0,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 0
},
"end": {
"line": 3,
"column": 1
}
},
"id": {
"type": "Identifier",
"start": 10,
"end": 11,
"loc": {
"start": {
"line": 1,
"column": 10
},
"end": {
"line": 1,
"column": 11
},
"identifierName": "f"
},
"name": "f"
},
"generator": true,
"async": false,
"params": [],
"body": {
"type": "BlockStatement",
"start": 14,
"end": 30,
"loc": {
"start": {
"line": 1,
"column": 14
},
"end": {
"line": 3,
"column": 1
}
},
"body": [
{
"type": "ExpressionStatement",
"start": 16,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 21
}
},
"expression": {
"type": "YieldExpression",
"start": 16,
"end": 21,
"loc": {
"start": {
"line": 1,
"column": 16
},
"end": {
"line": 1,
"column": 21
}
},
"delegate": false,
"argument": null
}
},
{
"type": "BlockStatement",
"start": 22,
"end": 24,
"loc": {
"start": {
"line": 2,
"column": 0
},
"end": {
"line": 2,
"column": 2
}
},
"body": [],
"directives": []
},
{
"type": "ExpressionStatement",
"start": 24,
"end": 28,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 6
}
},
"expression": {
"type": "RegExpLiteral",
"start": 24,
"end": 28,
"loc": {
"start": {
"line": 2,
"column": 2
},
"end": {
"line": 2,
"column": 6
}
},
"extra": {
"raw": "/1/g"
},
"pattern": "1",
"flags": "g"
}
}
],
"directives": []
}
}
],
"directives": []
}
}

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