Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b132c0889 | ||
|
|
b927fb2a7e | ||
|
|
282129ea66 | ||
|
|
fc5d49b6f6 | ||
|
|
6c2771c116 | ||
|
|
fdc869ce16 | ||
|
|
fa9df678ac | ||
|
|
3932830535 | ||
|
|
07eaa3c63f | ||
|
|
3530d11418 | ||
|
|
806e133473 | ||
|
|
2bf8dde782 | ||
|
|
4e28459a2f | ||
|
|
c4d6f6dcce | ||
|
|
0859535b62 | ||
|
|
6e39b58f8a | ||
|
|
559d649994 | ||
|
|
3fda01b185 | ||
|
|
4f2eacf615 | ||
|
|
0047ae84b3 | ||
|
|
2bb24f996f | ||
|
|
61f2aed5b0 | ||
|
|
9308c870f5 | ||
|
|
1b8d664bbe | ||
|
|
844dd33f3d | ||
|
|
856edbf95f | ||
|
|
100b38784d | ||
|
|
4cbd22a15f | ||
|
|
d2971a1959 | ||
|
|
4f16a12c03 | ||
|
|
e7f0c065cf | ||
|
|
70318c9413 | ||
|
|
6e84352b51 | ||
|
|
0eb9b2463d | ||
|
|
445b14148e | ||
|
|
61c1c77a28 | ||
|
|
5979b0669b | ||
|
|
a2afb974be | ||
|
|
c11cdcb6d8 | ||
|
|
8c7d4b55c9 | ||
|
|
88696601e1 | ||
|
|
20a9d71016 | ||
|
|
1af57e6f71 | ||
|
|
4e1d6e7ff4 | ||
|
|
efb71ea12b | ||
|
|
cbbb3c7962 | ||
|
|
4fcee1751a | ||
|
|
efa571a42c | ||
|
|
bf8c4785f2 | ||
|
|
4f206b2416 | ||
|
|
504b331da4 | ||
|
|
74f969b603 | ||
|
|
4dfd801887 | ||
|
|
62233ed7c9 | ||
|
|
7b54ab620b | ||
|
|
343f776ca5 | ||
|
|
756ded4d64 | ||
|
|
b706e34fc8 | ||
|
|
5d5cd8612f | ||
|
|
a0e94ec24d | ||
|
|
b593af17a9 | ||
|
|
4521204ea0 | ||
|
|
122906d525 | ||
|
|
25d01460fd | ||
|
|
ba5642d4ee | ||
|
|
15e6d844ae | ||
|
|
d1cae2dec2 | ||
|
|
11aee13ff2 | ||
|
|
39e7ee6e65 | ||
|
|
094ef31c01 | ||
|
|
afd0638b74 | ||
|
|
6e41edb90f | ||
|
|
7931f4c241 | ||
|
|
b847d40842 | ||
|
|
e91a02cc49 | ||
|
|
cc526940ee | ||
|
|
7188820151 | ||
|
|
00845709ce | ||
|
|
b50fdc191e | ||
|
|
ef0f723fc5 | ||
|
|
fbf62b4830 |
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
10
.travis.yml
10
.travis.yml
@@ -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'
|
||||
|
||||
@@ -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`
|
||||
|
||||
6
Makefile
6
Makefile
@@ -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
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"lerna": "2.11.0",
|
||||
"version": "7.1.5",
|
||||
"version": "7.2.1",
|
||||
"changelog": {
|
||||
"repo": "babel/babel",
|
||||
"cacheDir": ".changelog",
|
||||
|
||||
@@ -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;
|
||||
|
||||
37
package.json
37
package.json
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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));
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
1
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/in-files/src/bar/bar.es
vendored
Normal file
1
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/in-files/src/bar/bar.es
vendored
Normal file
@@ -0,0 +1 @@
|
||||
(() => 42)
|
||||
1
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/in-files/src/foo.es
vendored
Normal file
1
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/in-files/src/foo.es
vendored
Normal file
@@ -0,0 +1 @@
|
||||
arr.map(x => x * MULTIPLIER);
|
||||
3
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/options.json
vendored
Normal file
3
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"args": ["src", "--out-file", "test.js", "--extensions", ".es"]
|
||||
}
|
||||
10
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/out-files/test.js
vendored
Normal file
10
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/out-files/test.js
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
"use strict";
|
||||
|
||||
(function () {
|
||||
return 42;
|
||||
});
|
||||
"use strict";
|
||||
|
||||
arr.map(function (x) {
|
||||
return x * MULTIPLIER;
|
||||
});
|
||||
0
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/stdout.txt
vendored
Normal file
0
packages/babel-cli/test/fixtures/babel/dir --out-file --extensions/stdout.txt
vendored
Normal 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",
|
||||
|
||||
@@ -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)),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ export default function makeAPI(
|
||||
async: () => false,
|
||||
caller,
|
||||
assertVersion,
|
||||
tokTypes: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
@@ -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"),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// @flow
|
||||
|
||||
export default function transformFileSync() {
|
||||
throw new Error("Transforming files is not supported in browsers");
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -43,9 +43,11 @@ function () {
|
||||
}, _callee, this);
|
||||
}));
|
||||
|
||||
return function bar() {
|
||||
function bar() {
|
||||
return _bar.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
return bar;
|
||||
}()
|
||||
}]);
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -10,3 +10,7 @@ function* asdf() {
|
||||
function* a(b) {
|
||||
(yield xhr({ url: "views/test.html" })).data;
|
||||
}
|
||||
|
||||
(async function* () {
|
||||
await (yield 1);
|
||||
});
|
||||
|
||||
@@ -11,4 +11,8 @@ function* a(b) {
|
||||
(yield xhr({
|
||||
url: "views/test.html"
|
||||
})).data;
|
||||
}
|
||||
}
|
||||
|
||||
(async function* () {
|
||||
await (yield 1);
|
||||
});
|
||||
|
||||
@@ -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
|
||||
() {}
|
||||
}
|
||||
}
|
||||
1
packages/babel-generator/test/fixtures/types/ClassBody-MethodDefinition/options.json
vendored
Normal file
1
packages/babel-generator/test/fixtures/types/ClassBody-MethodDefinition/options.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{ "plugins": ["classPrivateMethods", "asyncGenerators"] }
|
||||
@@ -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() {}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
src
|
||||
test
|
||||
*.log
|
||||
19
packages/babel-helper-create-class-features-plugin/README.md
Normal file
19
packages/babel-helper-create-class-features-plugin/README.md
Normal 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
|
||||
```
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
export function hasDecorators(path) {
|
||||
return !!(path.node.decorators && path.node.decorators.length);
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
401
packages/babel-helper-create-class-features-plugin/src/fields.js
Normal file
401
packages/babel-helper-create-class-features-plugin/src/fields.js
Normal 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 };
|
||||
}
|
||||
166
packages/babel-helper-create-class-features-plugin/src/index.js
Normal file
166
packages/babel-helper-create-class-features-plugin/src/index.js
Normal 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}"`);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
111
packages/babel-helper-create-class-features-plugin/src/misc.js
Normal file
111
packages/babel-helper-create-class-features-plugin/src/misc.js
Normal 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;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
class A {
|
||||
foo;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"plugins": [
|
||||
["proposal-class-properties", { "loose": true }, "name 1"],
|
||||
["proposal-class-properties", { "loose": false }, "name 2"]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class A {
|
||||
constructor() {
|
||||
this.foo = void 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import runner from "@babel/helper-plugin-test-runner";
|
||||
|
||||
runner(__dirname);
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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(", "),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
1
packages/babel-parser/test/fixtures/core/regression/non-octal-float-strict-mode/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/core/regression/non-octal-float-strict-mode/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
09.5
|
||||
4
packages/babel-parser/test/fixtures/core/regression/non-octal-float-strict-mode/options.json
vendored
Normal file
4
packages/babel-parser/test/fixtures/core/regression/non-octal-float-strict-mode/options.json
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"sourceType": "module",
|
||||
"throws": "Legacy octal literals are not allowed in strict mode (1:0)"
|
||||
}
|
||||
1
packages/babel-parser/test/fixtures/core/regression/non-octal-float/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/core/regression/non-octal-float/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
09.5
|
||||
70
packages/babel-parser/test/fixtures/core/regression/non-octal-float/output.json
vendored
Normal file
70
packages/babel-parser/test/fixtures/core/regression/non-octal-float/output.json
vendored
Normal 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": []
|
||||
}
|
||||
}
|
||||
1
packages/babel-parser/test/fixtures/core/regression/octal-float-fail/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/core/regression/octal-float-fail/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
07.5
|
||||
3
packages/babel-parser/test/fixtures/core/regression/octal-float-fail/options.json
vendored
Normal file
3
packages/babel-parser/test/fixtures/core/regression/octal-float-fail/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "Unexpected token, expected \";\" (1:2)"
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "Unexpected token, expected \")\" (1:18)"
|
||||
"throws": "Rest parameter must be last formal parameter (1:18)"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "Invalid number (1:33)"
|
||||
"throws": "Legacy octal literals are not allowed in strict mode (1:33)"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "Invalid number (1:36)"
|
||||
"throws": "Legacy octal literals are not allowed in strict mode (1:36)"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "Invalid number (1:65)"
|
||||
"throws": "Legacy octal literals are not allowed in strict mode (1:65)"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "Invalid number (2:10)"
|
||||
"throws": "Legacy octal literals are not allowed in strict mode (2:10)"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "Invalid number (2:10)"
|
||||
"throws": "Legacy octal literals are not allowed in strict mode (2:10)"
|
||||
}
|
||||
|
||||
6
packages/babel-parser/test/fixtures/core/uncategorised/555/input.js
vendored
Normal file
6
packages/babel-parser/test/fixtures/core/uncategorised/555/input.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
function foo (
|
||||
first,
|
||||
...second,
|
||||
third,
|
||||
) {
|
||||
};
|
||||
3
packages/babel-parser/test/fixtures/core/uncategorised/555/options.json
vendored
Normal file
3
packages/babel-parser/test/fixtures/core/uncategorised/555/options.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "Rest parameter must be last formal parameter (3:13)"
|
||||
}
|
||||
1
packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/es2015/arrow-functions/comma-after-rest-param/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
(...rest,) => {}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "A trailing comma is not permitted after the rest element (1:8)"
|
||||
}
|
||||
5
packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/input.js
vendored
Normal file
5
packages/babel-parser/test/fixtures/es2015/arrow-functions/invalid-rest-in-params/input.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
(
|
||||
first,
|
||||
...second,
|
||||
third
|
||||
) => {};
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"throws": "Rest parameter must be last formal parameter (3:13)"
|
||||
}
|
||||
1
packages/babel-parser/test/fixtures/es2015/for-of/brackets-const/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/es2015/for-of/brackets-const/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
for (const {a} of /b/) {}
|
||||
194
packages/babel-parser/test/fixtures/es2015/for-of/brackets-const/output.json
vendored
Normal file
194
packages/babel-parser/test/fixtures/es2015/for-of/brackets-const/output.json
vendored
Normal 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": []
|
||||
}
|
||||
}
|
||||
1
packages/babel-parser/test/fixtures/es2015/for-of/brackets-let/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/es2015/for-of/brackets-let/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
for (let {a} of /b/) {}
|
||||
194
packages/babel-parser/test/fixtures/es2015/for-of/brackets-let/output.json
vendored
Normal file
194
packages/babel-parser/test/fixtures/es2015/for-of/brackets-let/output.json
vendored
Normal 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": []
|
||||
}
|
||||
}
|
||||
1
packages/babel-parser/test/fixtures/es2015/for-of/brackets-var/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/es2015/for-of/brackets-var/input.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
for (var {a} of /b/) {}
|
||||
194
packages/babel-parser/test/fixtures/es2015/for-of/brackets-var/output.json
vendored
Normal file
194
packages/babel-parser/test/fixtures/es2015/for-of/brackets-var/output.json
vendored
Normal 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": []
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "Invalid number (1:21)"
|
||||
"throws": "Legacy octal literals are not allowed in strict mode (1:21)"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "Unexpected token, expected \")\" (1:18)"
|
||||
"throws": "Rest parameter must be last formal parameter (1:18)"
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "Unexpected token, expected \")\" (1:5)"
|
||||
"throws": "Rest parameter must be last formal parameter (1:5)"
|
||||
}
|
||||
|
||||
3
packages/babel-parser/test/fixtures/es2015/yield/asi2/input.js
vendored
Normal file
3
packages/babel-parser/test/fixtures/es2015/yield/asi2/input.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
function *f() { yield
|
||||
{}/1/g
|
||||
}
|
||||
172
packages/babel-parser/test/fixtures/es2015/yield/asi2/output.json
vendored
Normal file
172
packages/babel-parser/test/fixtures/es2015/yield/asi2/output.json
vendored
Normal 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": []
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"throws": "yield is not allowed in the parameters of an arrow function inside a generator (2:8)"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user