Compare commits
245 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72a0ac5e02 | ||
|
|
c5ace10536 | ||
|
|
b833614b87 | ||
|
|
ae067a08b7 | ||
|
|
f56337541f | ||
|
|
1fe8447a1a | ||
|
|
13bbfa041d | ||
|
|
c43bbb9bf6 | ||
|
|
1bca59a921 | ||
|
|
f80fdf7359 | ||
|
|
aefd69d31e | ||
|
|
e328031b19 | ||
|
|
571b6a4cd7 | ||
|
|
41cf942391 | ||
|
|
98f28b8e89 | ||
|
|
8f88afc037 | ||
|
|
6359675a4f | ||
|
|
a265c3f25c | ||
|
|
29eb99ee93 | ||
|
|
0c5c1ff989 | ||
|
|
499951123a | ||
|
|
c0fd4c1f9e | ||
|
|
579e6fecee | ||
|
|
bb3665a3b6 | ||
|
|
e6de688234 | ||
|
|
4c233e88ff | ||
|
|
ae2ba0b5a3 | ||
|
|
e34d950793 | ||
|
|
e4083fbbd7 | ||
|
|
59ed7977ef | ||
|
|
dc441e9a8f | ||
|
|
2e21795f57 | ||
|
|
5c988f7fc8 | ||
|
|
493826973e | ||
|
|
1acc71aa4e | ||
|
|
bbab5f72ec | ||
|
|
58ff9e387a | ||
|
|
5a0d099984 | ||
|
|
05c95e04f7 | ||
|
|
88430b4be2 | ||
|
|
19adcfae4d | ||
|
|
7c4fe984ce | ||
|
|
4476e8311c | ||
|
|
2a3142273d | ||
|
|
bbcb889a49 | ||
|
|
c87f85815b | ||
|
|
48d0df17d0 | ||
|
|
01b243347f | ||
|
|
45a5cbf72f | ||
|
|
05efae1c58 | ||
|
|
c08fff4b44 | ||
|
|
13e910ea83 | ||
|
|
b308602098 | ||
|
|
560a044d8f | ||
|
|
619fbe4c3b | ||
|
|
1d83ad6cce | ||
|
|
5353ccd773 | ||
|
|
a8e23d2eb9 | ||
|
|
95d830fde0 | ||
|
|
c8a5d7d970 | ||
|
|
43481eb2cc | ||
|
|
b8bb665691 | ||
|
|
e6846b2730 | ||
|
|
31c1286a3c | ||
|
|
489f9e92b5 | ||
|
|
073809efac | ||
|
|
c9b8e2f3ce | ||
|
|
c6cb871355 | ||
|
|
1b0e5b3ed1 | ||
|
|
0f70c76312 | ||
|
|
e8c672bf4f | ||
|
|
7083ac61ff | ||
|
|
d256809120 | ||
|
|
26a19f82d2 | ||
|
|
128d3b5c91 | ||
|
|
c1a080d0ca | ||
|
|
0b1ce6c9a4 | ||
|
|
a6f04055c0 | ||
|
|
c3219e8b88 | ||
|
|
a35c863341 | ||
|
|
6f862a4c45 | ||
|
|
cf38210fd2 | ||
|
|
5c9d564339 | ||
|
|
031a61515b | ||
|
|
d3884fd53b | ||
|
|
c6eef3080e | ||
|
|
25be0a974d | ||
|
|
7ccd135e83 | ||
|
|
4fc1bbeb60 | ||
|
|
32a4d7172b | ||
|
|
aa25903c05 | ||
|
|
23ec1a455e | ||
|
|
e6ac2d049b | ||
|
|
084ae31816 | ||
|
|
8e530afd78 | ||
|
|
6c66a82b37 | ||
|
|
737abca3a9 | ||
|
|
9db43ca7a9 | ||
|
|
25b0683316 | ||
|
|
a096f6b1c5 | ||
|
|
e41ab2ab0c | ||
|
|
6a6764fa7b | ||
|
|
a2358d6863 | ||
|
|
612ef79d35 | ||
|
|
2dfa6ddf36 | ||
|
|
2910d4f82c | ||
|
|
4b6c954f5e | ||
|
|
b7e23e3410 | ||
|
|
a19f10e124 | ||
|
|
8e1f134635 | ||
|
|
aa151016f5 | ||
|
|
ce3c6289a2 | ||
|
|
0364519869 | ||
|
|
58cda35831 | ||
|
|
ebaa06f4a2 | ||
|
|
4b0f624fb3 | ||
|
|
aa0f3ac5d0 | ||
|
|
725906a7dc | ||
|
|
13d5c94b8b | ||
|
|
85308a1e8c | ||
|
|
83bcaba1a5 | ||
|
|
185648cb2c | ||
|
|
be355fc1c6 | ||
|
|
7795e11d58 | ||
|
|
8f74e8068c | ||
|
|
4f08a77230 | ||
|
|
4ac33d62af | ||
|
|
2710a914e8 | ||
|
|
8934e7f9da | ||
|
|
b4f18e05fa | ||
|
|
c07540a2c4 | ||
|
|
c409f63bbe | ||
|
|
d3c30b669f | ||
|
|
d10856d16c | ||
|
|
fb08a519c8 | ||
|
|
6a8ecf2507 | ||
|
|
100317e0c8 | ||
|
|
a32f744341 | ||
|
|
c4feff3cb7 | ||
|
|
498297ce6b | ||
|
|
2412c1d502 | ||
|
|
d92e1a4fb8 | ||
|
|
1d0d050413 | ||
|
|
a607ac0077 | ||
|
|
41f5e7c077 | ||
|
|
99604362ed | ||
|
|
2c8e374eaf | ||
|
|
238c68f829 | ||
|
|
09b334ad21 | ||
|
|
d647ede94b | ||
|
|
6386b60b9a | ||
|
|
25749a9933 | ||
|
|
fd4c0dae95 | ||
|
|
80d362c534 | ||
|
|
59820b9a84 | ||
|
|
f6ff366edf | ||
|
|
c7cac7aaba | ||
|
|
0647d374a3 | ||
|
|
25c2816a85 | ||
|
|
b57a80ecae | ||
|
|
574d47a571 | ||
|
|
7c5d2b19b7 | ||
|
|
c7669f44c1 | ||
|
|
0ed5c5f480 | ||
|
|
94c34e0132 | ||
|
|
92c4bbd003 | ||
|
|
ec8e840841 | ||
|
|
1c3c64c12c | ||
|
|
cae80d6e9b | ||
|
|
aaf29ddd82 | ||
|
|
fb485567b9 | ||
|
|
050bcec617 | ||
|
|
6231015557 | ||
|
|
822eb47ee7 | ||
|
|
91161ae9a1 | ||
|
|
4c1b4b6490 | ||
|
|
e792256087 | ||
|
|
19ad22f6e8 | ||
|
|
01818a50fa | ||
|
|
3247851019 | ||
|
|
939c00d33c | ||
|
|
8b096ac705 | ||
|
|
30c4a0cf06 | ||
|
|
e08d400b36 | ||
|
|
7e080aa9d2 | ||
|
|
c0e5059634 | ||
|
|
f8f5684faa | ||
|
|
2c3e9fbc07 | ||
|
|
b9d066d953 | ||
|
|
94e15b0750 | ||
|
|
3256c1d120 | ||
|
|
eba9f0ffbd | ||
|
|
52c3c143f9 | ||
|
|
b0f797205b | ||
|
|
dd52c6a687 | ||
|
|
3cf773b528 | ||
|
|
98424f80af | ||
|
|
708879ff1b | ||
|
|
70042bb0a8 | ||
|
|
0f7711a202 | ||
|
|
27f039488e | ||
|
|
e3ce82e12f | ||
|
|
4934ea56a0 | ||
|
|
ce03457b19 | ||
|
|
1298c67949 | ||
|
|
668274edcb | ||
|
|
0694a7dd06 | ||
|
|
20d19735fc | ||
|
|
b5b6bf4ad5 | ||
|
|
844c10cac0 | ||
|
|
43583e4e9d | ||
|
|
f5b921cda9 | ||
|
|
763892aa79 | ||
|
|
3e6eae4d1a | ||
|
|
7c090c8580 | ||
|
|
a5f6c1c389 | ||
|
|
c159f2d982 | ||
|
|
9205f10244 | ||
|
|
4cd7bcad59 | ||
|
|
7e9660efd3 | ||
|
|
2d66ce5224 | ||
|
|
1257b2cf40 | ||
|
|
f21d935de5 | ||
|
|
2e20364793 | ||
|
|
e47e8a187a | ||
|
|
26924d5944 | ||
|
|
5eb1850a55 | ||
|
|
333e287226 | ||
|
|
80a77bd6a2 | ||
|
|
c9286a1de1 | ||
|
|
52f614dcdf | ||
|
|
600367ae25 | ||
|
|
b761cba135 | ||
|
|
947d3e262d | ||
|
|
4061bea528 | ||
|
|
de195e5bfc | ||
|
|
3bcef86973 | ||
|
|
fa670ac71e | ||
|
|
572261f9ce | ||
|
|
8a320d53a5 | ||
|
|
0650eedeb6 | ||
|
|
2282d066a2 | ||
|
|
f4d7cc55c1 | ||
|
|
eaaa279aa5 | ||
|
|
0595e06e29 |
3
.babelrc
3
.babelrc
@@ -2,5 +2,6 @@
|
||||
"stage": 0,
|
||||
"loose": ["all"],
|
||||
"blacklist": ["es6.tailCall"],
|
||||
"optional": ["optimisation.flow.forOf"]
|
||||
"optional": ["optimisation.flow.forOf"],
|
||||
"plugins": ["./tools/build-plugins/protect"]
|
||||
}
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
"no-fallthrough": 0,
|
||||
"new-cap": 0,
|
||||
"no-loop-func": 0,
|
||||
"no-unreachable": 0
|
||||
"no-unreachable": 0,
|
||||
"no-labels": 0,
|
||||
"no-process-exit": 0
|
||||
},
|
||||
"env": {
|
||||
"node": true
|
||||
|
||||
28
.travis.yml
28
.travis.yml
@@ -1,14 +1,26 @@
|
||||
#sudo: false
|
||||
language: node_js
|
||||
cache:
|
||||
directories:
|
||||
- node_modules
|
||||
- node_modules
|
||||
node_js:
|
||||
- "0.12"
|
||||
- "iojs"
|
||||
|
||||
before_script: "npm install -g codeclimate-test-reporter"
|
||||
script: "make test-travis"
|
||||
|
||||
- '0.12'
|
||||
- iojs
|
||||
before_script: npm install -g codeclimate-test-reporter
|
||||
script: make test-travis
|
||||
notifications:
|
||||
slack: babeljs:5Wy4QX13KVkGy9CnU0rmvgeK
|
||||
before_deploy:
|
||||
- make prepublish
|
||||
after_deploy:
|
||||
- make publish-cli
|
||||
- make publish-runtime
|
||||
deploy:
|
||||
provider: npm
|
||||
email: sebmck@gmail.com
|
||||
skip_cleanup: true
|
||||
api_key:
|
||||
secure: Q/pZStwherdYPCqCa0aUuiEktLcx6ccBxieyH8j9IXdDgty0ydmnajZfUnlZuCjN13XI9esM44nSJFTWZvntTryDQAQm37c63VXhAEnw/qrAINI06yt0gLBTT69/fKvIAkH8l48nmW32ZS2dse3rHRPZF1CwyQLC/pdMip8I4sM=
|
||||
on:
|
||||
branch: master
|
||||
tags: true
|
||||
repo: babel/babel
|
||||
|
||||
107
CHANGELOG.md
107
CHANGELOG.md
@@ -9,10 +9,115 @@
|
||||
> - [Internal]
|
||||
> - [Polish]
|
||||
|
||||
_Note: Gaps between patch versions are faulty/broken releases._
|
||||
_Note: Gaps between patch versions are faulty, broken or test releases._
|
||||
|
||||
See [CHANGELOG - 6to5](CHANGELOG-6to5.md) for the pre-4.0.0 version changelog.
|
||||
|
||||
## 5.6.12
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix finding parent for top-level shadowed functions.
|
||||
|
||||
## 5.6.11
|
||||
|
||||
** **Internal**
|
||||
* Merge `es6.parameters.rest` and `es6.parameters.default` transformers. See commit [c0fd4c1f9e0b18231f585c4fa793e4cb0e01aed1](https://github.com/babel/babel/commit/c0fd4c1f9e0b18231f585c4fa793e4cb0e01aed1) for more info.
|
||||
|
||||
## 5.6.10
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix faulty internal require check.
|
||||
* **Polish**
|
||||
* Add support for trailing commas in arrow function parameter lists.
|
||||
|
||||
## 5.6.8
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix binary expressions colliding with unary expression operators in compact mode.
|
||||
* Fix node properties being set to `null` when using computed properties.
|
||||
|
||||
## 5.6.7
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix hoisting of `ForXStatement` `left` `var`s when inserting a block scoping IIFE.
|
||||
* **Polish**
|
||||
* Combine all leading computed property initialisers into the root object in loose mode.
|
||||
* **Internal**
|
||||
* Deprecate returning of replacement strings from visitor methods.
|
||||
|
||||
## 5.6.6
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix weird parser bug where `void` type annotations were being parsed as keywords causing the tokeniser to lose track of context.
|
||||
|
||||
## 5.6.5
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix nested functions causing rest parameter optimisation to not properly detect when it should deopt on a reference.
|
||||
* **Internal**
|
||||
* Update Regenerator `0.8.31`.
|
||||
|
||||
## 5.6.4
|
||||
|
||||
* **Internal**
|
||||
* Add `ParenthesizedExpression` node type.
|
||||
|
||||
## 5.6.3
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix rest parameter array allocation loop being incorrectly aliased.
|
||||
|
||||
## 5.6.2
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix method key literals not turning into computed member expression in loose mode.
|
||||
* Elect rest parameters in spread element position as candidates instead of replacing them in place.
|
||||
|
||||
## 5.6.0
|
||||
|
||||
* **Bug Fix**
|
||||
* Fix istanbul interop for register hook when registering for non-existence extension.
|
||||
* Fix super class constructor call differing for no constructor in derived classes.
|
||||
* Disable module import receiver when in loose mode.
|
||||
* Fix duplicate filenames when using `babel` CLI when passing multiple matching patterns.
|
||||
* Register labels as bindings to fix undeclared variable checks.
|
||||
* **Polish**
|
||||
* Remove unnecessary string binary expressions when transforming template literals.
|
||||
* Support module live bindings in arbitary positions not in Program statement position.
|
||||
* Throw error when attemping to replace a `Program` root node with another node not of type `Program`.
|
||||
* Optimise rest parameters in spread element position and allocate rest array at the earliest common ancestor of all references.
|
||||
* Generate original number representation when value was not changed.
|
||||
* Check for invalid binding identifiers when generating inferred method names.
|
||||
* Don't terminate CLI when watching files fail compilation on init.
|
||||
* **New Feature**
|
||||
* Add new plugin API.
|
||||
* **Internal**
|
||||
* Split react displayName addition into a plugin.
|
||||
* Add check for `JSXMemberExpression` to `t.isReferenced`.
|
||||
* Move `validation.undeclaredVariableCheck` transformer up.
|
||||
* Start great core-to-plugin exodus.
|
||||
* Add `BindingIdentifier` virtual type.
|
||||
* Hidden class optimisations.
|
||||
* Array allocation optimisations.
|
||||
* Update `regenerator`.
|
||||
* Update `js-tokens`.
|
||||
* Sync with upstream Acorn.
|
||||
|
||||
## 5.5.8
|
||||
|
||||
* **Internal**
|
||||
* Remove extremely unprofessional and harsh error message for those hotlinking to `resolve-rc`.
|
||||
|
||||
## 5.5.7
|
||||
|
||||
* **Bug Fix**
|
||||
* Push newline after decorators when doing code gen.
|
||||
* Rewriting error handling to normalise options before merging them.
|
||||
* Remove duplicate keys in `alias-keys.json` causing errors in strict mode.
|
||||
* Fix `$ babel --help` not showing optional transformers as such.
|
||||
* **New Feature**
|
||||
* Add `auxiliaryCommentBefore` and `auxiliaryCommentAfter` options.
|
||||
|
||||
## 5.5.6
|
||||
|
||||
* **Bug Fix**
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
<strong><a href="#dependencies">Dependencies</a></strong>
|
||||
|
|
||||
<strong><a href="#code-standards">Code Standards</a></strong>
|
||||
|
|
||||
<strong><a href="#internals">Internals</a></strong>
|
||||
</p>
|
||||
|
||||
----
|
||||
@@ -22,11 +24,10 @@ Contributions are always welcome, no matter how large or small. Before
|
||||
contributing, please read the
|
||||
[code of conduct](https://github.com/babel/babel/blob/master/CODE_OF_CONDUCT.md).
|
||||
|
||||
|
||||
## Developing
|
||||
|
||||
>Note: Babel moves fast. Only the latest release is guaranteed to build correctly.
|
||||
>Older releases are not officially supported. If you attempt to build them, do that at your own risk.
|
||||
> Note: Babel moves fast. Only the latest release is guaranteed to build correctly.
|
||||
> Older releases are not officially supported. If you attempt to build them, do that at your own risk.
|
||||
|
||||
#### Setup
|
||||
|
||||
@@ -112,8 +113,6 @@ your [`$PATH`](http://unix.stackexchange.com/questions/26047/how-to-correctly-ad
|
||||
|
||||
+ [js-tokens](http://ghub.io/js-tokens) This is used to get tokens for syntax error highlighting.
|
||||
|
||||
+ [leven](http://ghub.io/leven) A levenstein algorithm to determine how close a word is to another. This is used to offer suggestions when using the utility.undeclaredVariableCheck transformer.
|
||||
|
||||
+ [line-numbers](http://ghub.io/line-numbers) Used to produce the code frames in syntax errors.
|
||||
|
||||
+ [lodash](http://ghub.io/lodash) Used for various utilities.
|
||||
@@ -173,3 +172,6 @@ your [`$PATH`](http://unix.stackexchange.com/questions/26047/how-to-correctly-ad
|
||||
* **Declaration**
|
||||
* No unused variables
|
||||
* No pollution of global variables and prototypes
|
||||
|
||||
#### Internals
|
||||
Please see [`/doc`](/doc) for internals documentation relevant to developing babel.
|
||||
|
||||
38
Makefile
38
Makefile
@@ -9,13 +9,13 @@ BROWSERIFY_IGNORE = -i esprima-fb
|
||||
|
||||
export NODE_ENV = test
|
||||
|
||||
.PHONY: clean test test-cov test-clean test-travis test-simple test-all test-browser test-parser publish build bootstrap publish-core publish-runtime build-core watch-core build-core-test clean-core
|
||||
.PHONY: clean test test-cov test-clean test-travis test-simple test-all test-browser test-parser publish build bootstrap publish-core publish-runtime build-core watch-core build-core-test clean-core prepublish
|
||||
|
||||
build-core: clean-core
|
||||
node $(BABEL_CMD) src --out-dir lib --copy-files
|
||||
|
||||
build-core-test: clean-core
|
||||
node $(BABEL_CMD) src --out-dir lib --copy-files --auxiliary-comment "istanbul ignore next"
|
||||
node $(BABEL_CMD) src --out-dir lib --copy-files --auxiliary-comment-before "istanbul ignore next"
|
||||
|
||||
watch-core: clean-core
|
||||
node $(BABEL_CMD) src --out-dir lib --watch --copy-files
|
||||
@@ -24,7 +24,7 @@ clean-core:
|
||||
rm -rf lib
|
||||
|
||||
lint:
|
||||
eslint src/babel
|
||||
eslint src/babel packages/babel-cli/bin
|
||||
|
||||
build:
|
||||
mkdir -p dist
|
||||
@@ -81,34 +81,20 @@ test-browser:
|
||||
|
||||
publish: lint
|
||||
git pull --rebase
|
||||
|
||||
make test
|
||||
|
||||
read -p "Version: " version; \
|
||||
npm version $$version --message "v%s"
|
||||
|
||||
make build
|
||||
|
||||
cp dist/browser.js browser.js
|
||||
cp dist/browser.min.js browser.min.js
|
||||
|
||||
cp dist/polyfill.js browser-polyfill.js
|
||||
cp dist/polyfill.min.js browser-polyfill.min.js
|
||||
|
||||
cp dist/external-helpers.js external-helpers.js
|
||||
cp dist/external-helpers.min.js external-helpers.min.js
|
||||
|
||||
node tools/cache-templates
|
||||
test -f templates.json
|
||||
|
||||
npm publish
|
||||
|
||||
git push --follow-tags
|
||||
|
||||
make publish-cli
|
||||
make publish-runtime
|
||||
|
||||
rm -rf templates.json browser.js browser.min.js browser-polyfill.js browser-polyfill.min.js external-helpers.js external-helpers.min.js
|
||||
prepublish: build
|
||||
cp dist/browser.js browser.js
|
||||
cp dist/browser.min.js browser.min.js
|
||||
cp dist/polyfill.js browser-polyfill.js
|
||||
cp dist/polyfill.min.js browser-polyfill.min.js
|
||||
cp dist/external-helpers.js external-helpers.js
|
||||
cp dist/external-helpers.min.js external-helpers.min.js
|
||||
node tools/cache-templates
|
||||
test -f templates.json
|
||||
|
||||
publish-runtime:
|
||||
cd packages; \
|
||||
|
||||
16
README.md
16
README.md
@@ -5,17 +5,23 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<strong>Babel</strong> is a compiler for writing next generation JavaScript.
|
||||
The compiler for writing next generation JavaScript.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/babel/babel"><img alt="Build Status" src="https://img.shields.io/travis/babel/babel.svg?style=flat"></a>
|
||||
<a href="http://issuestats.com/github/babel/babel"><img alt="Issue Stats" src="http://issuestats.com/github/babel/babel/badge/pr?style=flat"></a>
|
||||
<a href="http://issuestats.com/github/babel/babel"><img alt="Issue Stats" src="http://issuestats.com/github/babel/babel/badge/issue?style=flat"></a>
|
||||
<a href="http://badge.fury.io/js/babel-core"><img alt="npm version" src="https://badge.fury.io/js/babel-core.svg"></a>
|
||||
<a href="https://npmjs.org/package/babel-core"><img alt="Downloads" src="http://img.shields.io/npm/dm/babel-core.svg"></a>
|
||||
</p>
|
||||
|
||||
----
|
||||
|
||||
<p align="center">
|
||||
For questions and support please visit the <a href="https://babel-slack.herokuapp.com">slack channel</a> or <a href="http://stackoverflow.com/questions/tagged/babeljs">StackOverflow</a>. The Babel issue tracker is <strong>exclusively</strong> for bug reports and feature requests.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Issues without instructions to reproduce <strong>will be immediately closed<strong>.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
For documentation and website issues please visit the <a href="https://github.com/babel/babel.github.io">babel.github.io</a> repo.
|
||||
</p>
|
||||
|
||||
4
doc/index.md
Normal file
4
doc/index.md
Normal file
@@ -0,0 +1,4 @@
|
||||
This is a collection of documentation about babel internals, for use in development of babel.
|
||||
|
||||
# [Properties of nodes](/doc/node-props.md)
|
||||
These are properties babel stores in AST node objects for internal use, as opposed to properties that are part of the AST spec (ESTree at the time of this writing).
|
||||
11
doc/node-props.md
Normal file
11
doc/node-props.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Properties of nodes
|
||||
These are properties babel stores in AST node objects for internal use, as opposed to properties that are part of the AST spec (ESTree at the time of this writing).
|
||||
|
||||
## `_blockHoist`
|
||||
`node._blockHoist != null` triggers the [block-hoist transformer](/src/babel/transformation/transformers/internal/block-hoist.js). Value should be `true` or an integer in the range `0..3`. `true` is equivalent to `2`. The value indicates whether the node should be hoisted and to what degree. See the source code for more detailed information.
|
||||
|
||||
## `_paths`
|
||||
Stores a representation of a node's position in the tree and relationship to other nodes.
|
||||
|
||||
## `shadow`
|
||||
A truthy value on a function node triggers the [shadow-functions transformer](/src/babel/transformation/transformers/internal/shadow-functions.js), which transforms the node so that it references (or inherits) `arguments` and `this` from the parent scope. It is invoked for arrow functions, for example.
|
||||
43
package.json
43
package.json
@@ -1,27 +1,26 @@
|
||||
{
|
||||
"name": "babel-core",
|
||||
"description": "A compiler for writing next generation JavaScript",
|
||||
"version": "5.5.6",
|
||||
"version": "5.6.14",
|
||||
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
||||
"homepage": "https://babeljs.io/",
|
||||
"license": "MIT",
|
||||
"repository": "babel/babel",
|
||||
"main": "lib/babel/api/node.js",
|
||||
"browser": {
|
||||
"./lib/babel/api/register/node.js": "./lib/babel/api/register/browser.js"
|
||||
},
|
||||
"keywords": [
|
||||
"harmony",
|
||||
"6to5",
|
||||
"babel",
|
||||
"classes",
|
||||
"modules",
|
||||
"let",
|
||||
"const",
|
||||
"var",
|
||||
"es6",
|
||||
"harmony",
|
||||
"let",
|
||||
"modules",
|
||||
"transpile",
|
||||
"transpiler",
|
||||
"6to5",
|
||||
"babel"
|
||||
"var"
|
||||
],
|
||||
"scripts": {
|
||||
"bench": "make bench",
|
||||
@@ -30,28 +29,42 @@
|
||||
"dependencies": {
|
||||
"acorn-jsx": "^1.0.0",
|
||||
"ast-types": "~0.7.0",
|
||||
"bluebird": "^2.9.25",
|
||||
"babel-eslint": "^3.1.19",
|
||||
"babel-plugin-constant-folding": "^1.0.1",
|
||||
"babel-plugin-dead-code-elimination": "^1.0.2",
|
||||
"babel-plugin-eval": "^1.0.1",
|
||||
"babel-plugin-inline-environment-variables": "^1.0.1",
|
||||
"babel-plugin-jscript": "^1.0.1",
|
||||
"babel-plugin-member-expression-literals": "^1.0.1",
|
||||
"babel-plugin-property-literals": "^1.0.1",
|
||||
"babel-plugin-proto-to-assign": "^1.0.3",
|
||||
"babel-plugin-react-constant-elements": "^1.0.3",
|
||||
"babel-plugin-react-display-name": "^1.0.3",
|
||||
"babel-plugin-remove-console": "^1.0.1",
|
||||
"babel-plugin-remove-debugger": "^1.0.1",
|
||||
"babel-plugin-runtime": "^1.0.7",
|
||||
"babel-plugin-undeclared-variables-check": "^1.0.2",
|
||||
"babel-plugin-undefined-to-void": "^1.1.6",
|
||||
"chalk": "^1.0.0",
|
||||
"convert-source-map": "^1.1.0",
|
||||
"core-js": "^0.9.0",
|
||||
"debug": "^2.1.1",
|
||||
"detect-indent": "^3.0.0",
|
||||
"esquery": "^0.4.0",
|
||||
"estraverse": "^4.0.0",
|
||||
"esutils": "^2.0.0",
|
||||
"fs-readdir-recursive": "^0.1.0",
|
||||
"globals": "^6.4.0",
|
||||
"home-or-tmp": "^1.0.0",
|
||||
"is-integer": "^1.0.4",
|
||||
"js-tokens": "1.0.0",
|
||||
"leven": "^1.0.1",
|
||||
"js-tokens": "1.0.1",
|
||||
"line-numbers": "0.2.0",
|
||||
"lodash": "^3.6.0",
|
||||
"minimatch": "^2.0.3",
|
||||
"output-file-sync": "^1.1.0",
|
||||
"path-exists": "^1.0.0",
|
||||
"path-is-absolute": "^1.0.0",
|
||||
"private": "^0.1.6",
|
||||
"regenerator": "0.8.28",
|
||||
"regenerator": "0.8.31",
|
||||
"regexpu": "^1.1.2",
|
||||
"repeating": "^1.1.2",
|
||||
"resolve": "^1.1.6",
|
||||
@@ -64,11 +77,11 @@
|
||||
"trim-right": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel": "5.3.1",
|
||||
"babel": "5.6.10",
|
||||
"babel-eslint": "^3.1.9",
|
||||
"browserify": "^9.0.8",
|
||||
"chai": "^2.2.0",
|
||||
"eslint": "^0.21.2",
|
||||
"babel-eslint": "^3.1.9",
|
||||
"esvalid": "^1.1.0",
|
||||
"istanbul": "^0.3.5",
|
||||
"matcha": "^0.6.0",
|
||||
|
||||
141
packages/babel-cli/bin/babel-plugin/index.js
Executable file
141
packages/babel-cli/bin/babel-plugin/index.js
Executable file
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var pathExists = require("path-exists");
|
||||
var readline = require("readline");
|
||||
var child = require("child_process");
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
|
||||
function spawn(cmd, args, callback) {
|
||||
console.log(">", cmd, args);
|
||||
|
||||
var spawn = child.spawn(cmd, args, { stdio: "inherit" });
|
||||
|
||||
spawn.on("exit", function (code) {
|
||||
if (code === 0) {
|
||||
if (callback) callback();
|
||||
} else {
|
||||
console.log("Killing...");
|
||||
process.exit(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function spawnMultiple(cmds) {
|
||||
function next() {
|
||||
var cmd = cmds.shift();
|
||||
if (cmd) {
|
||||
spawn(cmd.command, cmd.args, next);
|
||||
} else {
|
||||
process.exit();
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
}
|
||||
|
||||
function template(name, data) {
|
||||
var source = fs.readFileSync(path.join(__dirname, "templates", name), "utf8");
|
||||
source = source.replace(/[A-Z_]+/g, function (key) {
|
||||
return data[key] === undefined ? key : data[key];
|
||||
});
|
||||
return source;
|
||||
}
|
||||
|
||||
function write(filename, content) {
|
||||
console.log(filename);
|
||||
fs.writeFileSync(filename, content);
|
||||
}
|
||||
|
||||
var rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
var BABEL_PLUGIN_PREFIX = "babel-plugin-";
|
||||
|
||||
var cmds = {
|
||||
init: function () {
|
||||
var name = path.basename(process.cwd());
|
||||
|
||||
if (name.indexOf(BABEL_PLUGIN_PREFIX) === 0) {
|
||||
name = name.slice(BABEL_PLUGIN_PREFIX.length);
|
||||
}
|
||||
|
||||
rl.question("Description (optional): ", function (description) {
|
||||
rl.question("GitHub Repository (eg. sebmck/babel-plugin-foobar) (optional): ", function (repo) {
|
||||
rl.close();
|
||||
|
||||
var templateData = {
|
||||
DESCRIPTION: description,
|
||||
FULL_NAME: BABEL_PLUGIN_PREFIX + name,
|
||||
NAME: name
|
||||
};
|
||||
|
||||
write("package.json", JSON.stringify({
|
||||
name: templateData.FULL_NAME,
|
||||
version: "1.0.0",
|
||||
description: templateData.DESCRIPTION,
|
||||
repository: repo || undefined,
|
||||
license: "MIT",
|
||||
main: "lib/index.js",
|
||||
|
||||
devDependencies: {
|
||||
babel: "^5.6.0"
|
||||
},
|
||||
|
||||
scripts: {
|
||||
build: "babel-plugin build",
|
||||
push: "babel-plugin publish",
|
||||
test: "babel-plugin test"
|
||||
},
|
||||
|
||||
keywords: ["babel-plugin"]
|
||||
}, null, " ") + "\n");
|
||||
|
||||
write(".npmignore", "node_modules\n*.log\nsrc\n");
|
||||
|
||||
write(".gitignore", "node_modules\n*.log\nlib\n");
|
||||
|
||||
write("README.md", template("README.md", templateData));
|
||||
|
||||
if (!pathExists.sync("src")) {
|
||||
fs.mkdirSync("src");
|
||||
write("src/index.js", template("index.js", templateData));
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
build: function () {
|
||||
spawn("babel", ["src", "--out-dir", "lib", "--copy-files"]);
|
||||
},
|
||||
|
||||
publish: function () {
|
||||
var pkg = require(process.cwd() + "/package.json");
|
||||
console.log("Current verison:", pkg.version);
|
||||
|
||||
rl.question("New version (enter nothing for patch): ", function (newVersion) {
|
||||
rl.close();
|
||||
|
||||
newVersion = newVersion || "patch";
|
||||
|
||||
spawnMultiple([
|
||||
{ command: "git", args: ["pull"] },
|
||||
{ command: "git", args: ["push"] },
|
||||
{ command: "babel-plugin", args: ["build"] },
|
||||
{ command: "npm", args: ["version", newVersion] },
|
||||
{ command: "npm", args: ["publish"] },
|
||||
{ command: "git", args: ["push", "--follow-tags"] }
|
||||
]);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var cmd = cmds[process.argv[2]];
|
||||
if (cmd) {
|
||||
cmd();
|
||||
} else {
|
||||
console.error("Unknown command:", cmd);
|
||||
process.exit(1);
|
||||
}
|
||||
35
packages/babel-cli/bin/babel-plugin/templates/README.md
Normal file
35
packages/babel-cli/bin/babel-plugin/templates/README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# FULL_NAME
|
||||
|
||||
DESCRIPTION
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
$ npm install FULL_NAME
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Via `.babelrc` (Recommended)
|
||||
|
||||
**.babelrc**
|
||||
|
||||
```json
|
||||
{
|
||||
"plugins": ["NAME"]
|
||||
}
|
||||
```
|
||||
|
||||
### Via CLI
|
||||
|
||||
```sh
|
||||
$ babel --plugins NAME script.js
|
||||
```
|
||||
|
||||
### Via Node API
|
||||
|
||||
```javascript
|
||||
require("babel-core").transform("code", {
|
||||
plugins: ["NAME"]
|
||||
});
|
||||
```
|
||||
7
packages/babel-cli/bin/babel-plugin/templates/index.js
Normal file
7
packages/babel-cli/bin/babel-plugin/templates/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
export default function ({ Plugin, types: t }) {
|
||||
return new Plugin("NAME", {
|
||||
visitor: {
|
||||
// your visitor methods go here
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
var outputFileSync = require("output-file-sync");
|
||||
var pathExists = require("path-exists");
|
||||
var chokidar = require("chokidar");
|
||||
var slash = require("slash");
|
||||
var path = require("path");
|
||||
@@ -6,7 +7,7 @@ var util = require("./util");
|
||||
var fs = require("fs");
|
||||
var _ = require("lodash");
|
||||
|
||||
module.exports = function (commander, filenames, opts) {
|
||||
module.exports = function (commander, filenames) {
|
||||
var write = function (src, relative) {
|
||||
// remove extension and then append back on .js
|
||||
relative = relative.replace(/\.(\w*?)$/, "") + ".js";
|
||||
@@ -41,7 +42,7 @@ module.exports = function (commander, filenames, opts) {
|
||||
};
|
||||
|
||||
var handle = function (filename) {
|
||||
if (!fs.existsSync(filename)) return;
|
||||
if (!pathExists.sync(filename)) return;
|
||||
|
||||
var stat = fs.statSync(filename);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
var convertSourceMap = require("convert-source-map");
|
||||
var pathExists = require("path-exists");
|
||||
var sourceMap = require("source-map");
|
||||
var chokidar = require("chokidar");
|
||||
var slash = require("slash");
|
||||
@@ -100,7 +101,7 @@ module.exports = function (commander, filenames, opts) {
|
||||
results = [];
|
||||
|
||||
_.each(filenames, function (filename) {
|
||||
if (!fs.existsSync(filename)) return;
|
||||
if (!pathExists.sync(filename)) return;
|
||||
|
||||
var stat = fs.statSync(filename);
|
||||
if (stat.isDirectory()) {
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
require("babel-core");
|
||||
|
||||
var moduleFormatters = require("babel-core/lib/babel/transformation/modules");
|
||||
var pathExists = require("path-exists");
|
||||
var commander = require("commander");
|
||||
var transform = require("babel-core").transform;
|
||||
var kebabCase = require("lodash/string/kebabCase");
|
||||
var options = require("babel-core").options;
|
||||
var util = require("babel-core").util;
|
||||
var uniq = require("lodash/array/uniq");
|
||||
var each = require("lodash/collection/each");
|
||||
var keys = require("lodash/object/keys");
|
||||
var fs = require("fs");
|
||||
var glob = require("glob");
|
||||
|
||||
each(options, function (option, key) {
|
||||
@@ -35,7 +38,7 @@ each(options, function (option, key) {
|
||||
if (option.description) desc.push(option.description);
|
||||
|
||||
commander.option(arg, desc.join(" "));
|
||||
})
|
||||
});
|
||||
|
||||
commander.option("-x, --extensions [extensions]", "List of extensions to compile when a directory has been input [.es6,.js,.es,.jsx]");
|
||||
commander.option("-w, --watch", "Recompile files on changes");
|
||||
@@ -51,7 +54,7 @@ commander.on("--help", function () {
|
||||
each(keys(obj).sort(), function (key) {
|
||||
if (key[0] === "_") return;
|
||||
|
||||
if (obj[key].optional) key = "[" + key + "]";
|
||||
if (obj[key].metadata && obj[key].metadata.optional) key = "[" + key + "]";
|
||||
|
||||
console.log(" - " + key);
|
||||
});
|
||||
@@ -84,8 +87,10 @@ var filenames = commander.args.reduce(function (globbed, input) {
|
||||
return globbed.concat(files);
|
||||
}, []);
|
||||
|
||||
filenames = uniq(filenames);
|
||||
|
||||
each(filenames, function (filename) {
|
||||
if (!fs.existsSync(filename)) {
|
||||
if (!pathExists.sync(filename)) {
|
||||
errors.push(filename + " doesn't exist");
|
||||
}
|
||||
});
|
||||
@@ -118,11 +123,16 @@ if (errors.length) {
|
||||
var opts = exports.opts = {};
|
||||
|
||||
each(options, function (opt, key) {
|
||||
opts[key] = commander[key];
|
||||
if (commander[key] !== undefined) {
|
||||
opts[key] = commander[key];
|
||||
}
|
||||
});
|
||||
|
||||
opts.ignore = util.arrayify(opts.ignore, util.regexify);
|
||||
opts.only = util.arrayify(opts.only, util.regexify);
|
||||
|
||||
if (opts.only) {
|
||||
opts.only = util.arrayify(opts.only, util.regexify);
|
||||
}
|
||||
|
||||
var fn;
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
var readdir = require("fs-readdir-recursive");
|
||||
var index = require("./index");
|
||||
var babel = require("babel-core");
|
||||
var util = require("babel-core").util;
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var _ = require("lodash");
|
||||
var commander = require("commander");
|
||||
var readdir = require("fs-readdir-recursive");
|
||||
var index = require("./index");
|
||||
var babel = require("babel-core");
|
||||
var util = require("babel-core").util;
|
||||
var path = require("path");
|
||||
var fs = require("fs");
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.readdirFilter = function (filename) {
|
||||
return readdir(filename).filter(function (filename) {
|
||||
@@ -37,6 +38,15 @@ exports.transform = function (filename, code, opts) {
|
||||
};
|
||||
|
||||
exports.compile = function (filename, opts) {
|
||||
var code = fs.readFileSync(filename, "utf8");
|
||||
return exports.transform(filename, code, opts);
|
||||
try {
|
||||
var code = fs.readFileSync(filename, "utf8");
|
||||
return exports.transform(filename, code, opts);
|
||||
} catch (err) {
|
||||
if (commander.watch) {
|
||||
console.error(err.stack);
|
||||
return { ignored: true };
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
{
|
||||
"name": "babel",
|
||||
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
|
||||
"version": "5.5.5",
|
||||
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
||||
"homepage": "https://babeljs.io/",
|
||||
"license": "MIT",
|
||||
"repository": "babel/babel",
|
||||
"preferGlobal": true,
|
||||
"dependencies": {
|
||||
"babel-core": "^5.5.5",
|
||||
"babel-core": "^5.6.12",
|
||||
"chokidar": "^1.0.0",
|
||||
"commander": "^2.6.0",
|
||||
"convert-source-map": "^1.1.0",
|
||||
@@ -16,6 +15,7 @@
|
||||
"glob": "^5.0.5",
|
||||
"lodash": "^3.2.0",
|
||||
"output-file-sync": "^1.1.0",
|
||||
"path-exists": "^1.0.0",
|
||||
"path-is-absolute": "^1.0.0",
|
||||
"source-map": "^0.4.0",
|
||||
"slash": "^1.0.0"
|
||||
@@ -23,6 +23,7 @@
|
||||
"bin": {
|
||||
"babel": "./bin/babel/index.js",
|
||||
"babel-node": "./bin/babel-node",
|
||||
"babel-external-helpers": "./bin/babel-external-helpers"
|
||||
"babel-external-helpers": "./bin/babel-external-helpers",
|
||||
"babel-plugin": "./bin/babel-plugin/index.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
{
|
||||
"name": "babel-runtime",
|
||||
"description": "babel selfContained runtime",
|
||||
"version": "5.5.5",
|
||||
"license": "MIT",
|
||||
"repository": "babel/babel",
|
||||
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
||||
"dependencies": {
|
||||
"core-js": "^0.9.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ writeFile("regenerator/runtime.js", selfContainify(readFile("regenerator/runtime
|
||||
|
||||
//
|
||||
|
||||
var coreDefinitions = require("../lib/babel/transformation/transformers/other/runtime/definitions");
|
||||
var coreDefinitions = require("babel-plugin-runtime/lib/definitions");
|
||||
|
||||
var paths = ["is-iterable", "get-iterator"];
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
Error.stackTraceLimit = Infinity;
|
||||
var acorn = require("../src/index")
|
||||
|
||||
var pp = acorn.Parser.prototype
|
||||
@@ -41,8 +42,11 @@ pp.flow_parseDeclareFunction = function (node) {
|
||||
typeNode.rest = tmp.rest
|
||||
this.expect(tt.parenR)
|
||||
|
||||
var oldInType = this.inType
|
||||
this.inType = true
|
||||
this.expect(tt.colon)
|
||||
typeNode.returnType = this.flow_parseType()
|
||||
this.inType = oldInType
|
||||
|
||||
typeContainer.typeAnnotation = this.finishNode(typeNode, "FunctionTypeAnnotation")
|
||||
id.typeAnnotation = this.finishNode(typeContainer, "TypeAnnotation")
|
||||
@@ -352,12 +356,6 @@ pp.flow_parseGenericType = function (start, id) {
|
||||
return this.finishNode(node, "GenericTypeAnnotation")
|
||||
}
|
||||
|
||||
pp.flow_parseVoidType = function () {
|
||||
var node = this.startNode()
|
||||
this.expect(tt._void)
|
||||
return this.finishNode(node, "VoidTypeAnnotation")
|
||||
}
|
||||
|
||||
pp.flow_parseTypeofType = function () {
|
||||
var node = this.startNode()
|
||||
this.expect(tt._typeof)
|
||||
@@ -411,6 +409,9 @@ pp.flow_identToTypeAnnotation = function (start, node, id) {
|
||||
case "any":
|
||||
return this.finishNode(node, "AnyTypeAnnotation")
|
||||
|
||||
case "void":
|
||||
return this.finishNode(node, "VoidTypeAnnotation")
|
||||
|
||||
case "bool":
|
||||
case "boolean":
|
||||
return this.finishNode(node, "BooleanTypeAnnotation")
|
||||
@@ -524,14 +525,8 @@ pp.flow_parsePrimaryType = function () {
|
||||
return this.finishNode(node, "StringLiteralTypeAnnotation")
|
||||
|
||||
default:
|
||||
if (this.type.keyword) {
|
||||
switch (this.type.keyword) {
|
||||
case "void":
|
||||
return this.flow_parseVoidType()
|
||||
|
||||
case "typeof":
|
||||
return this.flow_parseTypeofType()
|
||||
}
|
||||
if (this.type.keyword === "typeof") {
|
||||
return this.flow_parseTypeofType()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -694,6 +689,18 @@ acorn.plugins.flow = function (instance) {
|
||||
}
|
||||
})
|
||||
|
||||
// don't consider `void` to be a keyword as then it'll use the void token type
|
||||
// and set startExpr
|
||||
instance.extend("isKeyword", function (inner) {
|
||||
return function(name) {
|
||||
if (this.inType && name === "void") {
|
||||
return false
|
||||
} else {
|
||||
return inner.call(this, name)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
instance.extend("readToken", function (inner) {
|
||||
return function(code) {
|
||||
if (this.inType && (code === 62 || code === 60)) {
|
||||
|
||||
@@ -29,14 +29,23 @@ const pp = Parser.prototype
|
||||
// strict mode, init properties are also not allowed to be repeated.
|
||||
|
||||
pp.checkPropClash = function(prop, propHash) {
|
||||
if (this.options.ecmaVersion >= 6) return
|
||||
if (this.options.ecmaVersion >= 6 && (prop.computed || prop.method || prop.shorthand))
|
||||
return
|
||||
let key = prop.key, name
|
||||
switch (key.type) {
|
||||
case "Identifier": name = key.name; break
|
||||
case "Literal": name = String(key.value); break
|
||||
default: return
|
||||
}
|
||||
let kind = prop.kind || "init", other
|
||||
let kind = prop.kind
|
||||
if (this.options.ecmaVersion >= 6) {
|
||||
if (name === "__proto__" && kind === "init") {
|
||||
if (propHash.proto) this.raise(key.start, "Redefinition of __proto__ property");
|
||||
propHash.proto = true
|
||||
}
|
||||
return
|
||||
}
|
||||
let other
|
||||
if (has(propHash, name)) {
|
||||
other = propHash[name]
|
||||
let isGetSet = kind !== "init"
|
||||
@@ -260,8 +269,10 @@ pp.parseNoCallExpr = function() {
|
||||
pp.parseExprAtom = function(refShorthandDefaultPos) {
|
||||
let node, canBeArrow = this.potentialArrowAt == this.start
|
||||
switch (this.type) {
|
||||
case tt._this:
|
||||
case tt._super:
|
||||
if (!this.inFunction)
|
||||
this.raise(this.start, "'super' outside of function or class")
|
||||
case tt._this:
|
||||
let type = this.type === tt._this ? "ThisExpression" : "Super"
|
||||
node = this.startNode()
|
||||
this.next()
|
||||
@@ -421,9 +432,18 @@ pp.parseParenAndDistinguishExpression = function(start, isAsync, canBeArrow) {
|
||||
}
|
||||
|
||||
let innerStart = this.markPosition(), exprList = [], first = true
|
||||
let refShorthandDefaultPos = {start: 0}, spreadStart, innerParenStart
|
||||
let refShorthandDefaultPos = {start: 0}, spreadStart, innerParenStart, optionalCommaStart
|
||||
while (this.type !== tt.parenR) {
|
||||
first ? first = false : this.expect(tt.comma)
|
||||
if (first) {
|
||||
first = false;
|
||||
} else {
|
||||
this.expect(tt.comma)
|
||||
if (this.type === tt.parenR && this.options.features["es7.trailingFunctionCommas"]) {
|
||||
optionalCommaStart = this.start
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (this.type === tt.ellipsis) {
|
||||
let spreadNodeStart = this.markPosition()
|
||||
spreadStart = this.start
|
||||
@@ -451,6 +471,7 @@ pp.parseParenAndDistinguishExpression = function(start, isAsync, canBeArrow) {
|
||||
this.unexpected(this.lastTokStart)
|
||||
}
|
||||
}
|
||||
if (optionalCommaStart) this.unexpected(optionalCommaStart)
|
||||
if (spreadStart) this.unexpected(spreadStart)
|
||||
if (refShorthandDefaultPos.start) this.unexpected(refShorthandDefaultPos.start)
|
||||
|
||||
@@ -609,6 +630,14 @@ pp.parseObjPropValue = function (prop, start, isGenerator, isAsync, isPattern, r
|
||||
prop.kind = prop.key.name
|
||||
this.parsePropertyName(prop)
|
||||
prop.value = this.parseMethod(false)
|
||||
let paramCount = prop.kind === "get" ? 0 : 1
|
||||
if (prop.value.params.length !== paramCount) {
|
||||
let start = prop.value.start
|
||||
if (prop.kind === "get")
|
||||
this.raise(start, "getter should have no params");
|
||||
else
|
||||
this.raise(start, "setter should have exactly one param")
|
||||
}
|
||||
} else if (this.options.ecmaVersion >= 6 && !prop.computed && prop.key.type === "Identifier") {
|
||||
prop.kind = "init"
|
||||
if (isPattern) {
|
||||
@@ -634,12 +663,12 @@ pp.parsePropertyName = function(prop) {
|
||||
prop.computed = true
|
||||
prop.key = this.parseMaybeAssign()
|
||||
this.expect(tt.bracketR)
|
||||
return
|
||||
return prop.key
|
||||
} else {
|
||||
prop.computed = false
|
||||
}
|
||||
}
|
||||
prop.key = (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true)
|
||||
return prop.key = (this.type === tt.num || this.type === tt.string) ? this.parseExprAtom() : this.parseIdent(true)
|
||||
}
|
||||
|
||||
// Initialize empty function node.
|
||||
|
||||
@@ -19,7 +19,11 @@ var STATE_KEYS = [
|
||||
"exprAllowed",
|
||||
"potentialArrowAt",
|
||||
"currLine",
|
||||
"input"
|
||||
"input",
|
||||
"inType",
|
||||
"inFunction",
|
||||
"inGenerator",
|
||||
"labels"
|
||||
];
|
||||
|
||||
pp.getState = function () {
|
||||
@@ -29,6 +33,7 @@ pp.getState = function () {
|
||||
state[key] = this[key]
|
||||
}
|
||||
state.context = this.context.slice()
|
||||
state.labels = this.labels.slice()
|
||||
return state
|
||||
};
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ pp.toAssignable = function(node, isBinding) {
|
||||
case "AssignmentExpression":
|
||||
if (node.operator === "=") {
|
||||
node.type = "AssignmentPattern"
|
||||
delete node.operator
|
||||
} else {
|
||||
this.raise(node.left.end, "Only '=' operator can be used for specifying default value.")
|
||||
}
|
||||
@@ -171,7 +172,7 @@ pp.checkLVal = function(expr, isBinding, checkClashes) {
|
||||
break
|
||||
|
||||
case "ObjectPattern":
|
||||
for (let i = 0; i < expr.properties.length; i++) {
|
||||
for (let i = 0; i < expr.properties.length; i++) {
|
||||
var prop = expr.properties[i];
|
||||
if (prop.type === "Property") prop = prop.value;
|
||||
this.checkLVal(prop, isBinding, checkClashes)
|
||||
@@ -194,6 +195,10 @@ pp.checkLVal = function(expr, isBinding, checkClashes) {
|
||||
this.checkLVal(expr.argument, isBinding, checkClashes)
|
||||
break
|
||||
|
||||
case "ParenthesizedExpression":
|
||||
this.checkLVal(expr.expression, isBinding, checkClashes)
|
||||
break
|
||||
|
||||
default:
|
||||
this.raise(expr.start, (isBinding ? "Binding" : "Assigning to") + " rvalue")
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import {reservedWords, keywords} from "./identifier"
|
||||
import {types as tt, lineBreak} from "./tokentype"
|
||||
import {types as tt} from "./tokentype"
|
||||
import {lineBreak} from "./whitespace"
|
||||
|
||||
export function Parser(options, input, startPos) {
|
||||
this.options = options
|
||||
this.loadPlugins(this.options.plugins)
|
||||
this.sourceFile = this.options.sourceFile || null
|
||||
this.isKeyword = keywords[this.options.ecmaVersion >= 6 ? 6 : 5]
|
||||
this.isReservedWord = reservedWords[this.options.ecmaVersion]
|
||||
this.input = input
|
||||
this.loadPlugins(this.options.plugins)
|
||||
|
||||
// Set up token state
|
||||
|
||||
|
||||
@@ -347,7 +347,14 @@ pp.parseLabeledStatement = function(node, maybeName, expr) {
|
||||
for (let i = 0; i < this.labels.length; ++i)
|
||||
if (this.labels[i].name === maybeName) this.raise(expr.start, "Label '" + maybeName + "' is already declared")
|
||||
let kind = this.type.isLoop ? "loop" : this.type === tt._switch ? "switch" : null
|
||||
this.labels.push({name: maybeName, kind: kind})
|
||||
for (let i = this.labels.length - 1; i >= 0; i--) {
|
||||
let label = this.labels[i]
|
||||
if (label.statementStart == node.start) {
|
||||
label.statementStart = this.start;
|
||||
label.kind = kind;
|
||||
} else break;
|
||||
}
|
||||
this.labels.push({name: maybeName, kind: kind, statementStart: this.start})
|
||||
node.body = this.parseStatement(true)
|
||||
this.labels.pop()
|
||||
node.label = expr
|
||||
@@ -466,6 +473,7 @@ pp.parseClass = function(node, isStatement) {
|
||||
this.parseClassId(node, isStatement)
|
||||
this.parseClassSuper(node)
|
||||
var classBody = this.startNode()
|
||||
let hadConstructor = false
|
||||
classBody.body = []
|
||||
this.expect(tt.braceL)
|
||||
let decorators = []
|
||||
@@ -480,16 +488,14 @@ pp.parseClass = function(node, isStatement) {
|
||||
method.decorators = decorators
|
||||
decorators = []
|
||||
}
|
||||
let isMaybeStatic = this.type === tt.name && this.value === "static"
|
||||
var isGenerator = this.eat(tt.star), isAsync = false
|
||||
this.parsePropertyName(method)
|
||||
if (this.type !== tt.parenL && !method.computed && method.key.type === "Identifier" &&
|
||||
method.key.name === "static") {
|
||||
method.static = isMaybeStatic && this.type !== tt.parenL
|
||||
if (method.static) {
|
||||
if (isGenerator) this.unexpected()
|
||||
method['static'] = true
|
||||
isGenerator = this.eat(tt.star)
|
||||
this.parsePropertyName(method)
|
||||
} else {
|
||||
method['static'] = false
|
||||
}
|
||||
if (!isGenerator && method.key.type === "Identifier" && !method.computed && this.isClassProperty()) {
|
||||
classBody.body.push(this.parseClassProperty(method))
|
||||
@@ -500,23 +506,39 @@ pp.parseClass = function(node, isStatement) {
|
||||
isAsync = true
|
||||
this.parsePropertyName(method)
|
||||
}
|
||||
let isGetSet = false
|
||||
method.kind = "method"
|
||||
if (!method.computed && !isGenerator && !isAsync) {
|
||||
if (method.key.type === "Identifier") {
|
||||
if (this.type !== tt.parenL && (method.key.name === "get" || method.key.name === "set")) {
|
||||
method.kind = method.key.name
|
||||
this.parsePropertyName(method)
|
||||
} else if (!method['static'] && method.key.name === "constructor") {
|
||||
method.kind = "constructor"
|
||||
}
|
||||
} else if (!method['static'] && method.key.type === "Literal" && method.key.value === "constructor") {
|
||||
if (!method.computed) {
|
||||
let {key} = method
|
||||
if (!isAsync && !isGenerator && key.type === "Identifier" && this.type !== tt.parenL && (key.name === "get" || key.name === "set")) {
|
||||
isGetSet = true
|
||||
method.kind = key.name
|
||||
key = this.parsePropertyName(method)
|
||||
}
|
||||
if (!method.static && (key.type === "Identifier" && key.name === "constructor" ||
|
||||
key.type === "Literal" && key.value === "constructor")) {
|
||||
if (hadConstructor) this.raise(key.start, "Duplicate constructor in the same class")
|
||||
if (isGetSet) this.raise(key.start, "Constructor can't have get/set modifier")
|
||||
if (isGenerator) this.raise(key.start, "Constructor can't be a generator")
|
||||
if (isAsync) this.raise(key.start, "Constructor can't be an async function")
|
||||
method.kind = "constructor"
|
||||
hadConstructor = true
|
||||
}
|
||||
}
|
||||
if (method.kind === "constructor" && method.decorators) {
|
||||
this.raise(method.start, "You can't attach decorators to a class constructor")
|
||||
}
|
||||
this.parseClassMethod(classBody, method, isGenerator, isAsync)
|
||||
if (isGetSet) {
|
||||
let paramCount = method.kind === "get" ? 0 : 1
|
||||
if (method.value.params.length !== paramCount) {
|
||||
let start = method.value.start
|
||||
if (method.kind === "get")
|
||||
this.raise(start, "getter should have no params");
|
||||
else
|
||||
this.raise(start, "setter should have exactly one param")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (decorators.length) {
|
||||
this.raise(this.start, "You have trailing decorators with no method");
|
||||
|
||||
@@ -25,6 +25,9 @@ export class Token {
|
||||
|
||||
const pp = Parser.prototype
|
||||
|
||||
// Are we running under Rhino?
|
||||
const isRhino = typeof Packages == "object" && Object.prototype.toString.call(Packages) == "[object JavaPackage]"
|
||||
|
||||
// Move to the next token
|
||||
|
||||
pp.next = function() {
|
||||
@@ -430,23 +433,30 @@ pp.readRegexp = function() {
|
||||
// negatives in unlikely scenarios. For example, `[\u{61}-b]` is a
|
||||
// perfectly valid pattern that is equivalent to `[a-b]`, but it would
|
||||
// be replaced by `[x-b]` which throws an error.
|
||||
tmp = tmp.replace(/\\u([a-fA-F0-9]{4})|\\u\{([0-9a-fA-F]+)\}|[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "x")
|
||||
tmp = tmp.replace(/\\u\{([0-9a-fA-F]+)\}/g, (match, code, offset) => {
|
||||
code = Number("0x" + code)
|
||||
if (code > 0x10FFFF) this.raise(start + offset + 3, "Code point out of bounds")
|
||||
return "x"
|
||||
});
|
||||
tmp = tmp.replace(/\\u([a-fA-F0-9]{4})|[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "x")
|
||||
}
|
||||
}
|
||||
// Detect invalid regular expressions.
|
||||
try {
|
||||
new RegExp(tmp)
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) this.raise(start, "Error parsing regular expression: " + e.message)
|
||||
this.raise(e)
|
||||
}
|
||||
// Get a regular expression object for this pattern-flag pair, or `null` in
|
||||
// case the current environment doesn't support the flags it uses.
|
||||
let value
|
||||
try {
|
||||
value = new RegExp(content, mods)
|
||||
} catch (err) {
|
||||
value = null
|
||||
let value = null
|
||||
// Rhino's regular expression parser is flaky and throws uncatchable exceptions,
|
||||
// so don't do detection if we are running under Rhino
|
||||
if (!isRhino) {
|
||||
try {
|
||||
new RegExp(tmp)
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) this.raise(start, "Error parsing regular expression: " + e.message)
|
||||
this.raise(e)
|
||||
}
|
||||
// Get a regular expression object for this pattern-flag pair, or `null` in
|
||||
// case the current environment doesn't support the flags it uses.
|
||||
try {
|
||||
value = new RegExp(content, mods)
|
||||
} catch (err) {}
|
||||
}
|
||||
return this.finishToken(tt.regexp, {pattern: content, flags: mods, value: value})
|
||||
}
|
||||
@@ -514,10 +524,10 @@ pp.readCodePoint = function() {
|
||||
|
||||
if (ch === 123) {
|
||||
if (this.options.ecmaVersion < 6) this.unexpected()
|
||||
++this.pos
|
||||
let codePos = ++this.pos
|
||||
code = this.readHexChar(this.input.indexOf('}', this.pos) - this.pos)
|
||||
++this.pos
|
||||
if (code > 0x10FFFF) this.unexpected()
|
||||
if (code > 0x10FFFF) this.raise(codePos, "Code point out of bounds")
|
||||
} else {
|
||||
code = this.readHexChar(4)
|
||||
}
|
||||
@@ -539,7 +549,7 @@ pp.readString = function(quote) {
|
||||
if (ch === quote) break
|
||||
if (ch === 92) { // '\'
|
||||
out += this.input.slice(chunkStart, this.pos)
|
||||
out += this.readEscapedChar()
|
||||
out += this.readEscapedChar(false)
|
||||
chunkStart = this.pos
|
||||
} else {
|
||||
if (isNewLine(ch)) this.raise(this.start, "Unterminated string constant")
|
||||
@@ -572,7 +582,7 @@ pp.readTmplToken = function() {
|
||||
}
|
||||
if (ch === 92) { // '\'
|
||||
out += this.input.slice(chunkStart, this.pos)
|
||||
out += this.readEscapedChar()
|
||||
out += this.readEscapedChar(true)
|
||||
chunkStart = this.pos
|
||||
} else if (isNewLine(ch)) {
|
||||
out += this.input.slice(chunkStart, this.pos)
|
||||
@@ -600,42 +610,46 @@ pp.readTmplToken = function() {
|
||||
|
||||
// Used to read escaped characters
|
||||
|
||||
pp.readEscapedChar = function() {
|
||||
pp.readEscapedChar = function(inTemplate) {
|
||||
let ch = this.input.charCodeAt(++this.pos)
|
||||
let octal = /^[0-7]+/.exec(this.input.slice(this.pos, this.pos + 3))
|
||||
if (octal) octal = octal[0]
|
||||
while (octal && parseInt(octal, 8) > 255) octal = octal.slice(0, -1)
|
||||
if (octal === "0") octal = null
|
||||
++this.pos
|
||||
if (octal) {
|
||||
if (this.strict) this.raise(this.pos - 2, "Octal literal in strict mode")
|
||||
this.pos += octal.length - 1
|
||||
return String.fromCharCode(parseInt(octal, 8))
|
||||
} else {
|
||||
switch (ch) {
|
||||
case 110: return "\n"; // 'n' -> '\n'
|
||||
case 114: return "\r"; // 'r' -> '\r'
|
||||
case 120: return String.fromCharCode(this.readHexChar(2)); // 'x'
|
||||
case 117: return codePointToString(this.readCodePoint()); // 'u'
|
||||
case 116: return "\t"; // 't' -> '\t'
|
||||
case 98: return "\b"; // 'b' -> '\b'
|
||||
case 118: return "\u000b"; // 'v' -> '\u000b'
|
||||
case 102: return "\f"; // 'f' -> '\f'
|
||||
case 48: return "\0"; // 0 -> '\0'
|
||||
case 13: if (this.input.charCodeAt(this.pos) === 10) ++this.pos; // '\r\n'
|
||||
case 10: // ' \n'
|
||||
if (this.options.locations) { this.lineStart = this.pos; ++this.curLine }
|
||||
return ""
|
||||
default: return String.fromCharCode(ch)
|
||||
switch (ch) {
|
||||
case 110: return "\n"; // 'n' -> '\n'
|
||||
case 114: return "\r"; // 'r' -> '\r'
|
||||
case 120: return String.fromCharCode(this.readHexChar(2)); // 'x'
|
||||
case 117: return codePointToString(this.readCodePoint()); // 'u'
|
||||
case 116: return "\t"; // 't' -> '\t'
|
||||
case 98: return "\b"; // 'b' -> '\b'
|
||||
case 118: return "\u000b"; // 'v' -> '\u000b'
|
||||
case 102: return "\f"; // 'f' -> '\f'
|
||||
case 13: if (this.input.charCodeAt(this.pos) === 10) ++this.pos; // '\r\n'
|
||||
case 10: // ' \n'
|
||||
if (this.options.locations) { this.lineStart = this.pos; ++this.curLine }
|
||||
return ""
|
||||
default:
|
||||
if (ch >= 48 && ch <= 55) {
|
||||
let octalStr = this.input.substr(this.pos - 1, 3).match(/^[0-7]+/)[0]
|
||||
let octal = parseInt(octalStr, 8)
|
||||
if (octal > 255) {
|
||||
octalStr = octalStr.slice(0, -1)
|
||||
octal = parseInt(octalStr, 8)
|
||||
}
|
||||
if (octal > 0 && (this.strict || inTemplate)) {
|
||||
this.raise(this.pos - 2, "Octal literal in strict mode")
|
||||
}
|
||||
this.pos += octalStr.length - 1
|
||||
return String.fromCharCode(octal)
|
||||
}
|
||||
return String.fromCharCode(ch)
|
||||
}
|
||||
}
|
||||
|
||||
// Used to read character escape sequences ('\x', '\u', '\U').
|
||||
|
||||
pp.readHexChar = function(len) {
|
||||
let codePos = this.pos
|
||||
let n = this.readInt(16, len)
|
||||
if (n === null) this.raise(this.start, "Bad character escape sequence")
|
||||
if (n === null) this.raise(codePos, "Bad character escape sequence")
|
||||
return n
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ kw("case", beforeExpr)
|
||||
kw("catch")
|
||||
kw("continue")
|
||||
kw("debugger")
|
||||
kw("default")
|
||||
kw("default", beforeExpr)
|
||||
kw("do", {isLoop: true})
|
||||
kw("else", beforeExpr)
|
||||
kw("finally")
|
||||
|
||||
@@ -8,9 +8,10 @@ export { util, acorn, transform };
|
||||
export { pipeline } from "../transformation";
|
||||
export { canCompile } from "../util";
|
||||
|
||||
export { default as options } from "../transformation/file/options";
|
||||
export { default as options } from "../transformation/file/options/config";
|
||||
export { default as Plugin } from "../transformation/plugin";
|
||||
export { default as Transformer } from "../transformation/transformer";
|
||||
export { default as TransformerPipeline } from "../transformation/transformer-pipeline";
|
||||
export { default as Pipeline } from "../transformation/pipeline";
|
||||
export { default as traverse } from "../traversal";
|
||||
export { default as buildExternalHelpers } from "../tools/build-external-helpers";
|
||||
export { version } from "../../../package";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import homeOrTmp from "home-or-tmp";
|
||||
import pathExists from "path-exists";
|
||||
|
||||
const FILENAME = process.env.BABEL_CACHE_PATH || path.join(homeOrTmp, ".babel.json");
|
||||
var data = {};
|
||||
@@ -15,7 +16,7 @@ export function load() {
|
||||
process.on("exit", save);
|
||||
process.nextTick(save);
|
||||
|
||||
if (!fs.existsSync(FILENAME)) return;
|
||||
if (!pathExists.sync(FILENAME)) return;
|
||||
|
||||
try {
|
||||
data = JSON.parse(fs.readFileSync(FILENAME));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import sourceMapSupport from "source-map-support";
|
||||
import * as registerCache from "./cache";
|
||||
import resolveRc from "../../tools/resolve-rc";
|
||||
import resolveRc from "../../transformation/file/options/resolve-rc";
|
||||
import extend from "lodash/object/extend";
|
||||
import * as babel from "../node";
|
||||
import each from "lodash/collection/each";
|
||||
@@ -90,7 +90,7 @@ var shouldIgnore = function (filename) {
|
||||
if (!ignore && !only) {
|
||||
return getRelativePath(filename).split(path.sep).indexOf("node_modules") >= 0;
|
||||
} else {
|
||||
return util.shouldIgnore(filename, ignore || [], only || []);
|
||||
return util.shouldIgnore(filename, ignore || [], only);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -105,7 +105,7 @@ if (process.env.running_under_istanbul) {
|
||||
if (istanbulMonkey[filename]) {
|
||||
delete istanbulMonkey[filename];
|
||||
var code = compile(filename, {
|
||||
auxiliaryComment: "istanbul ignore next"
|
||||
auxiliaryCommentBefore: "istanbul ignore next"
|
||||
});
|
||||
istanbulMonkey[filename] = true;
|
||||
return code;
|
||||
@@ -125,7 +125,7 @@ var normalLoader = function (m, filename) {
|
||||
};
|
||||
|
||||
var registerExtension = function (ext) {
|
||||
var old = oldHandlers[ext] || oldHandlers[".js"];
|
||||
var old = oldHandlers[ext] || oldHandlers[".js"] || require.extensions[".js"];
|
||||
|
||||
var loader = normalLoader;
|
||||
if (process.env.running_under_istanbul) loader = istanbulLoader;
|
||||
|
||||
@@ -54,9 +54,10 @@ export default class Buffer {
|
||||
this.space();
|
||||
}
|
||||
|
||||
space() {
|
||||
if (this.format.compact) return;
|
||||
if (this.buf && !this.isLast(" ") && !this.isLast("\n")) {
|
||||
space(force?) {
|
||||
if (!force && this.format.compact) return;
|
||||
|
||||
if (force || this.buf && !this.isLast(" ") && !this.isLast("\n")) {
|
||||
this.push(" ");
|
||||
}
|
||||
}
|
||||
@@ -155,8 +156,12 @@ export default class Buffer {
|
||||
this.buf += str;
|
||||
}
|
||||
|
||||
endsWith(str) {
|
||||
return this.buf.slice(-str.length) === str;
|
||||
endsWith(str, buf = this.buf) {
|
||||
if (str.length === 1) {
|
||||
return buf[buf.length - 1] === str;
|
||||
} else {
|
||||
return buf.slice(-str.length) === str;
|
||||
}
|
||||
}
|
||||
|
||||
isLast(cha) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
export function ClassDeclaration(node, print) {
|
||||
print.list(node.decorators);
|
||||
print.list(node.decorators, { separator: "" });
|
||||
this.push("class");
|
||||
|
||||
if (node.id) {
|
||||
@@ -43,7 +43,7 @@ export function ClassBody(node, print) {
|
||||
|
||||
|
||||
export function ClassProperty(node, print) {
|
||||
print.list(node.decorators);
|
||||
print.list(node.decorators, { separator: "" });
|
||||
|
||||
if (node.static) this.push("static ");
|
||||
print.plain(node.key);
|
||||
@@ -58,7 +58,7 @@ export function ClassProperty(node, print) {
|
||||
}
|
||||
|
||||
export function MethodDefinition(node, print) {
|
||||
print.list(node.decorators);
|
||||
print.list(node.decorators, { separator: "" });
|
||||
|
||||
if (node.static) {
|
||||
this.push("static ");
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
import isInteger from "is-integer";
|
||||
import isNumber from "lodash/lang/isNumber";
|
||||
import * as t from "../../types";
|
||||
|
||||
export function UnaryExpression(node, print) {
|
||||
var hasSpace = /[a-z]$/.test(node.operator);
|
||||
var needsSpace = /[a-z]$/.test(node.operator);
|
||||
var arg = node.argument;
|
||||
|
||||
if (t.isUpdateExpression(arg) || t.isUnaryExpression(arg)) {
|
||||
hasSpace = true;
|
||||
needsSpace = true;
|
||||
}
|
||||
|
||||
if (t.isUnaryExpression(arg) && arg.operator === "!") {
|
||||
hasSpace = false;
|
||||
needsSpace = false;
|
||||
}
|
||||
|
||||
this.push(node.operator);
|
||||
if (hasSpace) this.push(" ");
|
||||
if (needsSpace) this.push(" ");
|
||||
print.plain(node.argument);
|
||||
}
|
||||
|
||||
@@ -25,6 +24,12 @@ export function DoExpression(node, print) {
|
||||
print.plain(node.body);
|
||||
}
|
||||
|
||||
export function ParenthesizedExpression(node, print) {
|
||||
this.push("(");
|
||||
print.plain(node.expression);
|
||||
this.push(")");
|
||||
}
|
||||
|
||||
export function UpdateExpression(node, print) {
|
||||
if (node.prefix) {
|
||||
this.push(node.operator);
|
||||
@@ -70,6 +75,7 @@ export function Super() {
|
||||
export function Decorator(node, print) {
|
||||
this.push("@");
|
||||
print.plain(node.expression);
|
||||
this.newline();
|
||||
}
|
||||
|
||||
export function CallExpression(node, print) {
|
||||
@@ -77,19 +83,16 @@ export function CallExpression(node, print) {
|
||||
|
||||
this.push("(");
|
||||
|
||||
var separator = ",";
|
||||
|
||||
var isPrettyCall = node._prettyCall && !this.format.retainLines;
|
||||
var isPrettyCall = node._prettyCall && !this.format.retainLines && !this.format.compact;
|
||||
|
||||
var separator;
|
||||
if (isPrettyCall) {
|
||||
separator += "\n";
|
||||
separator = ",\n";
|
||||
this.newline();
|
||||
this.indent();
|
||||
} else {
|
||||
separator += " ";
|
||||
}
|
||||
|
||||
print.list(node.arguments, { separator: separator });
|
||||
print.list(node.arguments, { separator });
|
||||
|
||||
if (isPrettyCall) {
|
||||
this.newline();
|
||||
@@ -126,12 +129,32 @@ export function ExpressionStatement(node, print) {
|
||||
this.semicolon();
|
||||
}
|
||||
|
||||
export function AssignmentPattern(node, print) {
|
||||
print.plain(node.left);
|
||||
this.push(" = ");
|
||||
print.plain(node.right);
|
||||
}
|
||||
|
||||
export function AssignmentExpression(node, print) {
|
||||
// todo: add cases where the spaces can be dropped when in compact mode
|
||||
print.plain(node.left);
|
||||
this.push(" ");
|
||||
|
||||
var spaces = node.operator === "in" || node.operator === "instanceof";
|
||||
spaces = true; // todo: https://github.com/babel/babel/issues/1835
|
||||
this.space(spaces);
|
||||
|
||||
this.push(node.operator);
|
||||
this.push(" ");
|
||||
|
||||
if (!spaces) {
|
||||
// space is mandatory to avoid outputting <!--
|
||||
// http://javascript.spec.whatwg.org/#comment-syntax
|
||||
spaces = node.operator === "<" &&
|
||||
t.isUnaryExpression(node.right, { prefix: true, operator: "!" }) &&
|
||||
t.isUnaryExpression(node.right.argument, { prefix: true, operator: "--" });
|
||||
}
|
||||
|
||||
this.space(spaces);
|
||||
|
||||
print.plain(node.right);
|
||||
}
|
||||
|
||||
@@ -143,12 +166,9 @@ export function BindExpression(node, print) {
|
||||
|
||||
export {
|
||||
AssignmentExpression as BinaryExpression,
|
||||
AssignmentExpression as LogicalExpression,
|
||||
AssignmentExpression as AssignmentPattern
|
||||
AssignmentExpression as LogicalExpression
|
||||
};
|
||||
|
||||
var SCIENTIFIC_NOTATION = /e/i;
|
||||
|
||||
export function MemberExpression(node, print) {
|
||||
var obj = node.object;
|
||||
print.plain(obj);
|
||||
@@ -167,11 +187,6 @@ export function MemberExpression(node, print) {
|
||||
print.plain(node.property);
|
||||
this.push("]");
|
||||
} else {
|
||||
// 5..toFixed(2);
|
||||
if (t.isLiteral(obj) && isInteger(obj.value) && !SCIENTIFIC_NOTATION.test(obj.value.toString())) {
|
||||
this.push(".");
|
||||
}
|
||||
|
||||
this.push(".");
|
||||
print.plain(node.property);
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ export function _method(node, print) {
|
||||
}
|
||||
|
||||
this._params(value, print);
|
||||
this.push(" ");
|
||||
this.space();
|
||||
print.plain(value.body);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,13 +33,13 @@ export function ForStatement(node, print) {
|
||||
this.push(";");
|
||||
|
||||
if (node.test) {
|
||||
this.push(" ");
|
||||
this.space();
|
||||
print.plain(node.test);
|
||||
}
|
||||
this.push(";");
|
||||
|
||||
if (node.update) {
|
||||
this.push(" ");
|
||||
this.space();
|
||||
print.plain(node.update);
|
||||
}
|
||||
|
||||
@@ -190,16 +190,29 @@ export function VariableDeclaration(node, print, parent) {
|
||||
}
|
||||
}
|
||||
|
||||
var sep = ",";
|
||||
//
|
||||
// use a pretty separator when we aren't in compact mode, have initializers and don't have retainLines on
|
||||
// this will format declarations like:
|
||||
//
|
||||
// var foo = "bar", bar = "foo";
|
||||
//
|
||||
// into
|
||||
//
|
||||
// var foo = "bar",
|
||||
// bar = "foo";
|
||||
//
|
||||
|
||||
var sep;
|
||||
if (!this.format.compact && !this.format.concise && hasInits && !this.format.retainLines) {
|
||||
sep += `\n${repeating(" ", node.kind.length + 1)}`;
|
||||
} else {
|
||||
sep += " ";
|
||||
sep = `,\n${repeating(" ", node.kind.length + 1)}`;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
print.list(node.declarations, { separator: sep });
|
||||
|
||||
if (t.isFor(parent)) {
|
||||
// don't give semicolons to these nodes since they'll be inserted in the parent generator
|
||||
if (parent.left === node || parent.init === node) return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint quotes: 0 */
|
||||
|
||||
import isInteger from "is-integer";
|
||||
import * as t from "../../types";
|
||||
|
||||
export function Identifier(node) {
|
||||
@@ -32,6 +33,8 @@ export function ObjectExpression(node, print) {
|
||||
export { ObjectExpression as ObjectPattern };
|
||||
|
||||
export function Property(node, print) {
|
||||
print.list(node.decorators, { separator: "" });
|
||||
|
||||
if (node.method || node.kind === "get" || node.kind === "set") {
|
||||
this._method(node, print);
|
||||
} else {
|
||||
@@ -79,7 +82,7 @@ export function ArrayExpression(node, print) {
|
||||
// both (all) of the holes.
|
||||
this.push(",");
|
||||
} else {
|
||||
if (i > 0) this.push(" ");
|
||||
if (i > 0) this.space();
|
||||
print.plain(elem);
|
||||
if (i < len - 1) this.push(",");
|
||||
}
|
||||
@@ -90,14 +93,29 @@ export function ArrayExpression(node, print) {
|
||||
|
||||
export { ArrayExpression as ArrayPattern };
|
||||
|
||||
export function Literal(node) {
|
||||
const SCIENTIFIC_NOTATION = /e/i;
|
||||
|
||||
export function Literal(node, print, parent) {
|
||||
var val = node.value;
|
||||
var type = typeof val;
|
||||
|
||||
if (type === "string") {
|
||||
this._stringLiteral(val);
|
||||
} else if (type === "number") {
|
||||
this.push(val + "");
|
||||
// check to see if this is the same number as the raw one in the original source as asm.js uses
|
||||
// numbers in the form 5.0 for type hinting
|
||||
var raw = node.raw;
|
||||
if (val === +raw && raw[raw.length - 1] !== "." && !/^0[bo]/i.test(raw)) {
|
||||
val = raw;
|
||||
}
|
||||
|
||||
val = val + "";
|
||||
|
||||
if (isInteger(+val) && t.isMemberExpression(parent, { object: node }) && !SCIENTIFIC_NOTATION.test(val)) {
|
||||
val += ".";
|
||||
}
|
||||
|
||||
this.push(val);
|
||||
} else if (type === "boolean") {
|
||||
this.push(val ? "true" : "false");
|
||||
} else if (node.regex) {
|
||||
@@ -116,9 +134,16 @@ export function _stringLiteral(val) {
|
||||
});
|
||||
|
||||
if (this.format.quotes === "single") {
|
||||
// remove double quotes
|
||||
val = val.slice(1, -1);
|
||||
|
||||
// unescape double quotes
|
||||
val = val.replace(/\\"/g, '"');
|
||||
|
||||
// escape single quotes
|
||||
val = val.replace(/'/g, "\\'");
|
||||
|
||||
// add single quotes
|
||||
val = `'${val}'`;
|
||||
}
|
||||
|
||||
|
||||
@@ -128,8 +128,7 @@ class CodeGenerator {
|
||||
// catch up to this nodes newline if we're behind
|
||||
if (node.loc && this.format.retainLines && this.buffer.buf) {
|
||||
var needsParens = false;
|
||||
if (!leftParenPrinted && parent &&
|
||||
this.position.line < node.loc.start.line && t.isTerminatorless(parent)) {
|
||||
if (!leftParenPrinted && parent && this.position.line < node.loc.start.line && t.isTerminatorless(parent)) {
|
||||
needsParens = true;
|
||||
this._push("(");
|
||||
}
|
||||
|
||||
@@ -18,7 +18,11 @@ export default class NodePrinter {
|
||||
}
|
||||
|
||||
list(items, opts = {}) {
|
||||
if (opts.separator == null) opts.separator = ", ";
|
||||
if (opts.separator == null) {
|
||||
opts.separator = ",";
|
||||
if (!this.generator.format.compact) opts.separator += " ";
|
||||
}
|
||||
|
||||
return this.join(items, opts);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,9 +79,11 @@ export default function (lines: number, lineNumber: number, colNumber: number, o
|
||||
if (params.number !== lineNumber) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (colNumber) {
|
||||
params.line += `\n${params.before}${repeating(" ", params.width)}${params.after}${repeating(" ", colNumber - 1)}^`;
|
||||
}
|
||||
|
||||
params.before = params.before.replace(/^./, ">");
|
||||
}
|
||||
}).join("\n");
|
||||
|
||||
@@ -5,15 +5,12 @@ export const MESSAGES = {
|
||||
JSXNamespacedTags: "Namespace tags are not supported. ReactJSX is not XML.",
|
||||
classesIllegalBareSuper: "Illegal use of bare super",
|
||||
classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead",
|
||||
classesIllegalConstructorKind: "Illegal kind for constructor method",
|
||||
scopeDuplicateDeclaration: "Duplicate declaration $1",
|
||||
settersInvalidParamLength: "Setters must have exactly one parameter",
|
||||
settersNoRest: "Setters aren't allowed to have a rest",
|
||||
noAssignmentsInForHead: "No assignments allowed in for-in/of head",
|
||||
expectedMemberExpressionOrIdentifier: "Expected type MemeberExpression or Identifier",
|
||||
expectedMemberExpressionOrIdentifier: "Expected type MemberExpression or Identifier",
|
||||
invalidParentForThisNode: "We don't know how to handle this node within the current parent - please open an issue",
|
||||
readOnly: "$1 is read-only",
|
||||
modulesIllegalExportName: "Illegal export $1",
|
||||
unknownForHead: "Unknown node type $1 in ForStatement",
|
||||
didYouMean: "Did you mean $1?",
|
||||
codeGeneratorDeopt: "Note: The code generator has deoptimised the styling of $1 as it exceeds the max of $2.",
|
||||
@@ -22,6 +19,9 @@ export const MESSAGES = {
|
||||
illegalMethodName: "Illegal method name $1",
|
||||
lostTrackNodePath: "We lost track of this nodes position, likely because the AST was directly manipulated",
|
||||
|
||||
modulesIllegalExportName: "Illegal export $1",
|
||||
modulesDuplicateDeclarations: "Duplicate module declarations with the same source but in different scopes",
|
||||
|
||||
undeclaredVariable: "Reference to undeclared variable $1",
|
||||
undeclaredVariableType: "Referencing a type alias outside of a type annotation",
|
||||
undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?",
|
||||
@@ -34,10 +34,10 @@ export const MESSAGES = {
|
||||
pluginIllegalKind: "Illegal kind $1 for plugin $2",
|
||||
pluginIllegalPosition: "Illegal position $1 for plugin $2",
|
||||
pluginKeyCollision: "The plugin $1 collides with another of the same name",
|
||||
pluginNotTransformer: "The plugin $1 didn't export a Transformer instance",
|
||||
pluginNotTransformer: "The plugin $1 didn't export a Plugin instance",
|
||||
pluginUnknown: "Unknown plugin $1",
|
||||
|
||||
transformerNotFile: "Transformer $1 is resolving to a different Babel version to what is doing the actual transformation..."
|
||||
pluginNotFile: "Plugin $1 is resolving to a different Babel version to what is doing the actual transformation..."
|
||||
};
|
||||
|
||||
export function get(key: String, ...args) {
|
||||
|
||||
9
src/babel/tools/protect.js
Normal file
9
src/babel/tools/protect.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import path from "path";
|
||||
|
||||
var root = path.resolve(__dirname, "../../../");
|
||||
|
||||
export default function (module) {
|
||||
if (module.parent && module.parent.filename.indexOf(root) !== 0) {
|
||||
throw new Error("Don't hotlink internal Babel files.");
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,26 @@
|
||||
import { validateOption, normaliseOptions, config as optionsConfig } from "./options";
|
||||
import convertSourceMap from "convert-source-map";
|
||||
import * as optionParsers from "./option-parsers";
|
||||
import moduleFormatters from "../modules";
|
||||
import PluginManager from "./plugin-manager";
|
||||
import shebangRegex from "shebang-regex";
|
||||
import NodePath from "../../traversal/path";
|
||||
import Transformer from "../transformer";
|
||||
import isFunction from "lodash/lang/isFunction";
|
||||
import isAbsolute from "path-is-absolute";
|
||||
import resolveRc from "../../tools/resolve-rc";
|
||||
import resolveRc from "./options/resolve-rc";
|
||||
import sourceMap from "source-map";
|
||||
import generate from "../../generation";
|
||||
import codeFrame from "../../helpers/code-frame";
|
||||
import defaults from "lodash/object/defaults";
|
||||
import includes from "lodash/collection/includes";
|
||||
import traverse from "../../traversal";
|
||||
import Hub from "../../traversal/hub";
|
||||
import assign from "lodash/object/assign";
|
||||
import Logger from "./logger";
|
||||
import Plugin from "../plugin";
|
||||
import parse from "../../helpers/parse";
|
||||
import merge from "../../helpers/merge";
|
||||
import slash from "slash";
|
||||
import clone from "lodash/lang/clone";
|
||||
import Hub from "../../traversal/hub";
|
||||
import * as util from "../../util";
|
||||
import path from "path";
|
||||
import * as t from "../../types";
|
||||
@@ -52,7 +52,7 @@ export default class File {
|
||||
this.log = new Logger(this, opts.filename || "unknown");
|
||||
this.ast = {};
|
||||
|
||||
this.normalizeOptions(opts);
|
||||
this.normaliseOptions(opts);
|
||||
|
||||
this.buildTransformers();
|
||||
|
||||
@@ -98,10 +98,10 @@ export default class File {
|
||||
|
||||
static soloHelpers = [];
|
||||
|
||||
static options = require("./options");
|
||||
static options = optionsConfig;
|
||||
|
||||
normalizeOptions(opts: Object) {
|
||||
opts = this.opts = assign({}, opts);
|
||||
normaliseOptions(opts: Object) {
|
||||
opts = this.opts = normaliseOptions(assign({}, opts));
|
||||
|
||||
// resolve babelrc
|
||||
if (opts.filename) {
|
||||
@@ -120,26 +120,28 @@ export default class File {
|
||||
|
||||
// merge in environment options
|
||||
var envKey = process.env.BABEL_ENV || process.env.NODE_ENV || "development";
|
||||
if (opts.env) merge(opts, opts.env[envKey]);
|
||||
if (opts.env) merge(opts, normaliseOptions(opts.env[envKey]));
|
||||
|
||||
// normalise options
|
||||
for (let key in File.options) {
|
||||
let option = File.options[key];
|
||||
var val = opts[key];
|
||||
|
||||
var val = opts[key];
|
||||
// optional
|
||||
if (!val && option.optional) continue;
|
||||
|
||||
// deprecated
|
||||
if (val && option.deprecated) {
|
||||
this.log.deprecate("Deprecated option " + key + ": " + option.deprecated);
|
||||
}
|
||||
|
||||
if (val == null) {
|
||||
val = clone(option.default);
|
||||
}
|
||||
// default
|
||||
if (val == null) val = clone(option.default);
|
||||
|
||||
var optionParser = optionParsers[option.type];
|
||||
if (optionParser) val = optionParser(key, val, this.pipeline);
|
||||
// validate
|
||||
if (val) val = validateOption(key, val, this.pipeline);
|
||||
|
||||
// aaliases
|
||||
if (option.alias) {
|
||||
opts[option.alias] = opts[option.alias] || val;
|
||||
} else {
|
||||
@@ -164,7 +166,10 @@ export default class File {
|
||||
opts.basename = path.basename(opts.filename, path.extname(opts.filename));
|
||||
|
||||
opts.ignore = util.arrayify(opts.ignore, util.regexify);
|
||||
opts.only = util.arrayify(opts.only, util.regexify);
|
||||
|
||||
if (opts.only) {
|
||||
opts.only = util.arrayify(opts.only, util.regexify);
|
||||
}
|
||||
|
||||
defaults(opts, {
|
||||
moduleRoot: opts.sourceRoot
|
||||
@@ -241,7 +246,7 @@ export default class File {
|
||||
|
||||
// build dependency graph
|
||||
for (let pass of (stack: Array)) {
|
||||
for (var dep of (pass.transformer.dependencies: Array)) {
|
||||
for (var dep of (pass.plugin.dependencies: Array)) {
|
||||
this.transformerDependencies[dep] = pass.key;
|
||||
}
|
||||
}
|
||||
@@ -258,7 +263,7 @@ export default class File {
|
||||
// been merged
|
||||
if (ignore.indexOf(pass) >= 0) continue;
|
||||
|
||||
var group = pass.transformer.metadata.group;
|
||||
var group = pass.plugin.metadata.group;
|
||||
|
||||
// can't merge
|
||||
if (!pass.canTransform() || !group) {
|
||||
@@ -268,7 +273,7 @@ export default class File {
|
||||
|
||||
var mergeStack = [];
|
||||
for (let pass of (_stack: Array)) {
|
||||
if (pass.transformer.metadata.group === group) {
|
||||
if (pass.plugin.metadata.group === group) {
|
||||
mergeStack.push(pass);
|
||||
ignore.push(pass);
|
||||
}
|
||||
@@ -276,11 +281,11 @@ export default class File {
|
||||
|
||||
var visitors = [];
|
||||
for (let pass of (mergeStack: Array)) {
|
||||
visitors.push(pass.handlers);
|
||||
visitors.push(pass.plugin.visitor);
|
||||
}
|
||||
var visitor = traverse.visitors.merge(visitors);
|
||||
var mergeTransformer = new Transformer(group, visitor);
|
||||
stack.push(mergeTransformer.buildPass(this));
|
||||
var mergePlugin = new Plugin(group, { visitor });
|
||||
stack.push(mergePlugin.buildPass(this));
|
||||
}
|
||||
|
||||
return stack;
|
||||
@@ -330,7 +335,7 @@ export default class File {
|
||||
}
|
||||
|
||||
if (this.transformers["es6.modules"].canTransform()) {
|
||||
this.moduleFormatter.importSpecifier(specifiers[0], declar, this.dynamicImports);
|
||||
this.moduleFormatter.importSpecifier(specifiers[0], declar, this.dynamicImports, this.scope);
|
||||
this.moduleFormatter.hasLocalImports = true;
|
||||
} else {
|
||||
this.dynamicImports.push(declar);
|
||||
@@ -341,14 +346,24 @@ export default class File {
|
||||
}
|
||||
|
||||
attachAuxiliaryComment(node: Object): Object {
|
||||
var comment = this.opts.auxiliaryComment;
|
||||
if (comment) {
|
||||
var beforeComment = this.opts.auxiliaryCommentBefore;
|
||||
if (beforeComment) {
|
||||
node.leadingComments = node.leadingComments || [];
|
||||
node.leadingComments.push({
|
||||
type: "CommentLine",
|
||||
value: " " + comment
|
||||
value: " " + beforeComment
|
||||
});
|
||||
}
|
||||
|
||||
var afterComment = this.opts.auxiliaryCommentAfter;
|
||||
if (afterComment) {
|
||||
node.trailingComments = node.trailingComments || [];
|
||||
node.trailingComments.push({
|
||||
type: "CommentLine",
|
||||
value: " " + afterComment
|
||||
});
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -400,11 +415,12 @@ export default class File {
|
||||
|
||||
errorWithNode(node, msg, Error = SyntaxError) {
|
||||
var err;
|
||||
if (node.loc) {
|
||||
if (node && node.loc) {
|
||||
var loc = node.loc.start;
|
||||
err = new Error(`Line ${loc.line}: ${msg}`);
|
||||
err.loc = loc;
|
||||
} else {
|
||||
// todo: find errors with nodes inside to at least point to something
|
||||
err = new Error("There's been an error on a dynamic node. This is almost certainly an internal error. Please report it.");
|
||||
}
|
||||
return err;
|
||||
@@ -570,7 +586,7 @@ export default class File {
|
||||
|
||||
call(key: string) {
|
||||
for (var pass of (this.uncollapsedTransformerStack: Array)) {
|
||||
var fn = pass.transformer[key];
|
||||
var fn = pass.plugin[key];
|
||||
if (fn) fn(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import buildDebug from "debug/node";
|
||||
var verboseDebug = buildDebug("babel:verbose");
|
||||
var generalDebug = buildDebug("babel");
|
||||
|
||||
var seenDeprecatedMessages = [];
|
||||
|
||||
export default class Logger {
|
||||
constructor(file: File, filename: string) {
|
||||
this.filename = filename;
|
||||
@@ -25,9 +27,17 @@ export default class Logger {
|
||||
}
|
||||
|
||||
deprecate(msg) {
|
||||
if (!this.file.opts.suppressDeprecationMessages) {
|
||||
console.error(this._buildMessage(msg));
|
||||
}
|
||||
if (this.file.opts.suppressDeprecationMessages) return;
|
||||
|
||||
msg = this._buildMessage(msg);
|
||||
|
||||
// already seen this message
|
||||
if (seenDeprecatedMessages.indexOf(msg) >= 0) return;
|
||||
|
||||
// make sure we don't see it again
|
||||
seenDeprecatedMessages.push(msg);
|
||||
|
||||
console.error(msg);
|
||||
}
|
||||
|
||||
verbose(msg: string) {
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import * as util from "../../util";
|
||||
|
||||
export function transformerList(key, val, pipeline) {
|
||||
val = util.arrayify(val);
|
||||
|
||||
if (val.indexOf("all") >= 0 || val.indexOf(true) >= 0) {
|
||||
val = Object.keys(pipeline.transformers);
|
||||
}
|
||||
|
||||
return pipeline._ensureTransformerNames(key, val);
|
||||
}
|
||||
|
||||
export function number(key, val) {
|
||||
return +val;
|
||||
}
|
||||
|
||||
export function boolean(key, val) {
|
||||
return !!val;
|
||||
}
|
||||
|
||||
export function booleanString(key, val) {
|
||||
return util.booleanify(val);
|
||||
}
|
||||
|
||||
export function list(key, val) {
|
||||
return util.list(val);
|
||||
}
|
||||
@@ -78,7 +78,8 @@
|
||||
"blacklist": {
|
||||
"type": "transformerList",
|
||||
"description": "blacklist of transformers to NOT use",
|
||||
"shorthand": "b"
|
||||
"shorthand": "b",
|
||||
"default": []
|
||||
},
|
||||
|
||||
"whitelist": {
|
||||
@@ -90,7 +91,8 @@
|
||||
|
||||
"optional": {
|
||||
"type": "transformerList",
|
||||
"description": "list of optional transformers to enable"
|
||||
"description": "list of optional transformers to enable",
|
||||
"default": []
|
||||
},
|
||||
|
||||
"modules": {
|
||||
@@ -122,12 +124,14 @@
|
||||
|
||||
"plugins": {
|
||||
"type": "list",
|
||||
"description": ""
|
||||
"description": "",
|
||||
"default": []
|
||||
},
|
||||
|
||||
"ignore": {
|
||||
"type": "list",
|
||||
"description": "list of glob paths to **not** compile"
|
||||
"description": "list of glob paths to **not** compile",
|
||||
"default": []
|
||||
},
|
||||
|
||||
"only": {
|
||||
@@ -173,12 +177,23 @@
|
||||
},
|
||||
|
||||
"auxiliaryComment": {
|
||||
"deprecated": "renamed to auxiliaryCommentBefore",
|
||||
"shorthand": "a",
|
||||
"alias": "auxiliaryCommentBefore"
|
||||
},
|
||||
|
||||
"auxiliaryCommentBefore": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"shorthand": "a",
|
||||
"description": "attach a comment before all helper declarations and auxiliary code"
|
||||
},
|
||||
|
||||
"auxiliaryCommentAfter": {
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"description": "attach a comment after all helper declarations and auxiliary code"
|
||||
},
|
||||
|
||||
"externalHelpers": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
31
src/babel/transformation/file/options/index.js
Normal file
31
src/babel/transformation/file/options/index.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import * as parsers from "./parsers";
|
||||
import config from "./config";
|
||||
|
||||
export { config };
|
||||
|
||||
export function validateOption(key, val, pipeline) {
|
||||
var opt = config[key];
|
||||
var parser = opt && parsers[opt.type];
|
||||
if (parser && parser.validate) {
|
||||
return parser.validate(key, val, pipeline);
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
export function normaliseOptions(options = {}) {
|
||||
for (var key in options) {
|
||||
var val = options[key];
|
||||
if (val == null) continue;
|
||||
|
||||
var opt = config[key];
|
||||
if (!opt) continue;
|
||||
|
||||
var parser = parsers[opt.type];
|
||||
if (parser) val = parser(val);
|
||||
|
||||
options[key] = val;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
29
src/babel/transformation/file/options/parsers.js
Normal file
29
src/babel/transformation/file/options/parsers.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import * as util from "../../../util";
|
||||
|
||||
export function transformerList(val) {
|
||||
return util.arrayify(val);
|
||||
}
|
||||
|
||||
transformerList.validate = function (key, val, pipeline) {
|
||||
if (val.indexOf("all") >= 0 || val.indexOf(true) >= 0) {
|
||||
val = Object.keys(pipeline.transformers);
|
||||
}
|
||||
|
||||
return pipeline._ensureTransformerNames(key, val);
|
||||
};
|
||||
|
||||
export function number(val) {
|
||||
return +val;
|
||||
}
|
||||
|
||||
export function boolean(val) {
|
||||
return !!val;
|
||||
}
|
||||
|
||||
export function booleanString(val) {
|
||||
return util.booleanify(val);
|
||||
}
|
||||
|
||||
export function list(val) {
|
||||
return util.list(val);
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
import stripJsonComments from "strip-json-comments";
|
||||
import merge from "../helpers/merge";
|
||||
import { normaliseOptions } from "./index";
|
||||
import merge from "../../../helpers/merge";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import pathExists from "path-exists";
|
||||
|
||||
var cache = {};
|
||||
var jsons = {};
|
||||
|
||||
function exists(filename) {
|
||||
if (!fs.existsSync) return false;
|
||||
|
||||
var cached = cache[filename];
|
||||
if (cached != null) return cached;
|
||||
return cache[filename] = fs.existsSync(filename);
|
||||
return cache[filename] = pathExists.sync(filename);
|
||||
}
|
||||
|
||||
export default function (loc, opts = {}) {
|
||||
@@ -34,6 +34,7 @@ export default function (loc, opts = {}) {
|
||||
|
||||
try {
|
||||
json = jsons[content] = jsons[content] || JSON.parse(stripJsonComments(content));
|
||||
normaliseOptions(json);
|
||||
} catch (err) {
|
||||
err.message = `${file}: ${err.message}`;
|
||||
throw err;
|
||||
@@ -42,6 +43,7 @@ export default function (loc, opts = {}) {
|
||||
opts.babelrc.push(file);
|
||||
|
||||
if (json.breakConfig) return;
|
||||
|
||||
merge(opts, json);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
import * as node from "../../api/node";
|
||||
import Transformer from "../transformer";
|
||||
import Plugin from "../plugin";
|
||||
import * as types from "../../types";
|
||||
import * as messages from "../../messages";
|
||||
import traverse from "../../types";
|
||||
import parse from "../../helpers/parse";
|
||||
|
||||
var context = {
|
||||
messages,
|
||||
Transformer,
|
||||
Plugin,
|
||||
types,
|
||||
parse,
|
||||
traverse
|
||||
};
|
||||
|
||||
import * as util from "../../util";
|
||||
|
||||
export default class PluginManager {
|
||||
@@ -11,7 +25,7 @@ export default class PluginManager {
|
||||
if (plugin.container === fn) return plugin.transformer;
|
||||
}
|
||||
|
||||
var transformer = fn(node);
|
||||
var transformer = fn(context);
|
||||
PluginManager.memoisedPlugins.push({
|
||||
container: fn,
|
||||
transformer: transformer
|
||||
@@ -55,7 +69,7 @@ export default class PluginManager {
|
||||
}
|
||||
|
||||
// validate Transformer instance
|
||||
if (!plugin.buildPass || plugin.constructor.name !== "Transformer") {
|
||||
if (!plugin.buildPass || plugin.constructor.name !== "Plugin") {
|
||||
throw new TypeError(messages.get("pluginNotTransformer", name));
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,10 @@ import esutils from "esutils";
|
||||
import * as react from "./react";
|
||||
import * as t from "../../types";
|
||||
|
||||
export default function (exports, opts) {
|
||||
exports.JSXIdentifier = function (node) {
|
||||
export default function (opts) {
|
||||
var visitor = {};
|
||||
|
||||
visitor.JSXIdentifier = function (node) {
|
||||
if (node.name === "this" && this.isReferenced()) {
|
||||
return t.thisExpression();
|
||||
} else if (esutils.keyword.isIdentifierNameES6(node.name)) {
|
||||
@@ -20,22 +22,22 @@ export default function (exports, opts) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.JSXNamespacedName = function () {
|
||||
visitor.JSXNamespacedName = function () {
|
||||
throw this.errorWithNode(messages.get("JSXNamespacedTags"));
|
||||
};
|
||||
|
||||
exports.JSXMemberExpression = {
|
||||
visitor.JSXMemberExpression = {
|
||||
exit(node) {
|
||||
node.computed = t.isLiteral(node.property);
|
||||
node.type = "MemberExpression";
|
||||
}
|
||||
};
|
||||
|
||||
exports.JSXExpressionContainer = function (node) {
|
||||
visitor.JSXExpressionContainer = function (node) {
|
||||
return node.expression;
|
||||
};
|
||||
|
||||
exports.JSXAttribute = {
|
||||
visitor.JSXAttribute = {
|
||||
enter(node) {
|
||||
var value = node.value;
|
||||
if (t.isLiteral(value) && isString(value.value)) {
|
||||
@@ -49,7 +51,7 @@ export default function (exports, opts) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.JSXOpeningElement = {
|
||||
visitor.JSXOpeningElement = {
|
||||
exit(node, parent, scope, file) {
|
||||
parent.children = react.buildChildren(parent);
|
||||
|
||||
@@ -139,7 +141,7 @@ export default function (exports, opts) {
|
||||
return attribs;
|
||||
};
|
||||
|
||||
exports.JSXElement = {
|
||||
visitor.JSXElement = {
|
||||
exit(node) {
|
||||
var callExpr = node.openingElement;
|
||||
|
||||
@@ -153,54 +155,5 @@ export default function (exports, opts) {
|
||||
}
|
||||
};
|
||||
|
||||
// display names
|
||||
|
||||
var addDisplayName = function (id, call) {
|
||||
var props = call.arguments[0].properties;
|
||||
var safe = true;
|
||||
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
var prop = props[i];
|
||||
var key = t.toComputedKey(prop);
|
||||
if (t.isLiteral(key, { value: "displayName" })) {
|
||||
safe = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (safe) {
|
||||
props.unshift(t.property("init", t.identifier("displayName"), t.literal(id)));
|
||||
}
|
||||
};
|
||||
|
||||
exports.ExportDefaultDeclaration = function (node, parent, scope, file) {
|
||||
if (react.isCreateClass(node.declaration)) {
|
||||
addDisplayName(file.opts.basename, node.declaration);
|
||||
}
|
||||
};
|
||||
|
||||
exports.AssignmentExpression =
|
||||
exports.Property =
|
||||
exports.VariableDeclarator = function (node) {
|
||||
var left, right;
|
||||
|
||||
if (t.isAssignmentExpression(node)) {
|
||||
left = node.left;
|
||||
right = node.right;
|
||||
} else if (t.isProperty(node)) {
|
||||
left = node.key;
|
||||
right = node.value;
|
||||
} else if (t.isVariableDeclarator(node)) {
|
||||
left = node.id;
|
||||
right = node.init;
|
||||
}
|
||||
|
||||
if (t.isMemberExpression(left)) {
|
||||
left = left.property;
|
||||
}
|
||||
|
||||
if (t.isIdentifier(left) && react.isCreateClass(right)) {
|
||||
addDisplayName(left.name, right);
|
||||
}
|
||||
};
|
||||
return visitor;
|
||||
}
|
||||
|
||||
@@ -20,11 +20,8 @@ var visitor = {
|
||||
visitIdentifier(this, node, scope, state);
|
||||
},
|
||||
|
||||
AssignmentExpression(node, parent, scope, state) {
|
||||
var ids = this.getBindingIdentifiers();
|
||||
for (var name in ids) {
|
||||
visitIdentifier(this, ids[name], scope, state);
|
||||
}
|
||||
BindingIdentifier(node, parent, scope, state) {
|
||||
visitIdentifier(this, node, scope, state);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -71,10 +68,10 @@ var visit = function (node, name, scope) {
|
||||
// check to see if we have a local binding of the id we're setting inside of
|
||||
// the function, this is important as there are caveats associated
|
||||
|
||||
var bindingInfo = scope.getOwnBindingInfo(name);
|
||||
var binding = scope.getOwnBinding(name);
|
||||
|
||||
if (bindingInfo) {
|
||||
if (bindingInfo.kind === "param") {
|
||||
if (binding) {
|
||||
if (binding.kind === "param") {
|
||||
// safari will blow up in strict mode with code like:
|
||||
//
|
||||
// var t = function t(t) {};
|
||||
@@ -114,8 +111,7 @@ export function property(node, file, scope) {
|
||||
var key = t.toComputedKey(node, node.key);
|
||||
if (!t.isLiteral(key)) return; // we can't set a function id with this
|
||||
|
||||
var name = t.toIdentifier(key.value);
|
||||
if (name === "eval" || name === "arguments") name = "_" + name;
|
||||
var name = t.toBindingIdentifierName(key.value);
|
||||
var id = t.identifier(name);
|
||||
|
||||
var method = node.value;
|
||||
@@ -136,8 +132,8 @@ export function bare(node, parent, scope) {
|
||||
id = parent.id;
|
||||
|
||||
if (t.isIdentifier(id)) {
|
||||
var bindingInfo = scope.parent.getBinding(id.name);
|
||||
if (bindingInfo && bindingInfo.constant && scope.getBinding(id.name) === bindingInfo) {
|
||||
var binding = scope.parent.getBinding(id.name);
|
||||
if (binding && binding.constant && scope.getBinding(id.name) === binding) {
|
||||
// always going to reference this method
|
||||
node.id = id;
|
||||
return;
|
||||
@@ -156,7 +152,7 @@ export function bare(node, parent, scope) {
|
||||
return;
|
||||
}
|
||||
|
||||
name = t.toIdentifier(name);
|
||||
name = t.toBindingIdentifierName(name);
|
||||
id = t.identifier(name);
|
||||
|
||||
var state = visit(node, name, scope);
|
||||
|
||||
19
src/babel/transformation/helpers/react.js
vendored
19
src/babel/transformation/helpers/react.js
vendored
@@ -1,24 +1,5 @@
|
||||
import * as t from "../../types";
|
||||
|
||||
var isCreateClassCallExpression = t.buildMatchMemberExpression("React.createClass");
|
||||
|
||||
export function isCreateClass(node) {
|
||||
if (!node || !t.isCallExpression(node)) return false;
|
||||
|
||||
// not React.createClass call member object
|
||||
if (!isCreateClassCallExpression(node.callee)) return false;
|
||||
|
||||
// no call arguments
|
||||
var args = node.arguments;
|
||||
if (args.length !== 1) return false;
|
||||
|
||||
// first node arg is not an object
|
||||
var first = args[0];
|
||||
if (!t.isObjectExpression(first)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export var isReactComponent = t.buildMatchMemberExpression("React.Component");
|
||||
|
||||
export function isCompatTag(tagName) {
|
||||
|
||||
@@ -169,7 +169,13 @@ export default class ReplaceSupers {
|
||||
|
||||
if (methodName.name === "constructor") {
|
||||
// constructor() { super(); }
|
||||
return t.memberExpression(superRef, t.identifier("call"));
|
||||
if (parent.arguments.length === 2 && t.isSpreadElement(parent.arguments[1]) && t.isIdentifier(parent.arguments[1].argument, { name: "arguments" })) {
|
||||
// special case single arguments spread
|
||||
parent.arguments[1] = parent.arguments[1].argument;
|
||||
return t.memberExpression(superRef, t.identifier("apply"));
|
||||
} else {
|
||||
return t.memberExpression(superRef, t.identifier("call"));
|
||||
}
|
||||
} else {
|
||||
id = superRef;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import Pipeline from "./transformer-pipeline";
|
||||
import Pipeline from "./pipeline";
|
||||
|
||||
var pipeline = new Pipeline;
|
||||
|
||||
@@ -8,8 +8,11 @@ import transformers from "./transformers";
|
||||
|
||||
for (var key in transformers) {
|
||||
var transformer = transformers[key];
|
||||
var metadata = transformer.metadata = transformer.metadata || {};
|
||||
metadata.group = metadata.group || "builtin-basic";
|
||||
|
||||
if (typeof transformer === "object") {
|
||||
var metadata = transformer.metadata = transformer.metadata || {};
|
||||
metadata.group = metadata.group || "builtin-basic";
|
||||
}
|
||||
}
|
||||
|
||||
pipeline.addTransformers(transformers);
|
||||
|
||||
@@ -1,122 +1,64 @@
|
||||
import * as messages from "../../messages";
|
||||
import Remaps from "./lib/remaps";
|
||||
import extend from "lodash/object/extend";
|
||||
import object from "../../helpers/object";
|
||||
import * as util from "../../util";
|
||||
import * as t from "../../types";
|
||||
|
||||
var remapVisitor = {
|
||||
enter(node) {
|
||||
if (node._skipModulesRemap) {
|
||||
return this.skip();
|
||||
}
|
||||
},
|
||||
|
||||
ReferencedIdentifier(node, parent, scope, formatter) {
|
||||
var remap = formatter.internalRemap[node.name];
|
||||
|
||||
if (remap && node !== remap) {
|
||||
if (!scope.hasBinding(node.name) || scope.bindingIdentifierEquals(node.name, formatter.localImports[node.name])) {
|
||||
if (this.key === "callee" && this.parentPath.isCallExpression()) {
|
||||
return t.sequenceExpression([t.literal(0), remap]);
|
||||
} else {
|
||||
return remap;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
AssignmentExpression: {
|
||||
exit(node, parent, scope, formatter) {
|
||||
if (!node._ignoreModulesRemap) {
|
||||
var exported = formatter.getExport(node.left, scope);
|
||||
if (exported) {
|
||||
return formatter.remapExportAssignment(node, exported);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
UpdateExpression(node, parent, scope, formatter) {
|
||||
var exported = formatter.getExport(node.argument, scope);
|
||||
if (!exported) return;
|
||||
|
||||
this.skip();
|
||||
|
||||
// expand to long file assignment expression
|
||||
var assign = t.assignmentExpression(node.operator[0] + "=", node.argument, t.literal(1));
|
||||
|
||||
// remap this assignment expression
|
||||
var remapped = formatter.remapExportAssignment(assign, exported);
|
||||
|
||||
// we don't need to change the result
|
||||
if (t.isExpressionStatement(parent) || node.prefix) {
|
||||
return remapped;
|
||||
}
|
||||
|
||||
var nodes = [];
|
||||
nodes.push(remapped);
|
||||
|
||||
var operator;
|
||||
if (node.operator === "--") {
|
||||
operator = "+";
|
||||
} else { // "++"
|
||||
operator = "-";
|
||||
}
|
||||
nodes.push(t.binaryExpression(operator, node.argument, t.literal(1)));
|
||||
|
||||
return t.sequenceExpression(nodes);
|
||||
}
|
||||
};
|
||||
|
||||
var metadataVisitor = {
|
||||
ModuleDeclaration(node, parent, scope, formatter) {
|
||||
if (node.source) {
|
||||
node.source.value = formatter.file.resolveModuleSource(node.source.value);
|
||||
ModuleDeclaration: {
|
||||
enter(node, parent, scope, formatter) {
|
||||
if (node.source) {
|
||||
node.source.value = formatter.file.resolveModuleSource(node.source.value);
|
||||
formatter.addScope(this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ImportDeclaration(node, parent, scope, formatter) {
|
||||
formatter.hasLocalImports = true;
|
||||
ImportDeclaration: {
|
||||
exit(node, parent, scope, formatter) {
|
||||
formatter.hasLocalImports = true;
|
||||
|
||||
var specifiers = [];
|
||||
var imported = [];
|
||||
formatter.metadata.imports.push({
|
||||
source: node.source.value,
|
||||
imported,
|
||||
specifiers
|
||||
});
|
||||
var specifiers = [];
|
||||
var imported = [];
|
||||
formatter.metadata.imports.push({
|
||||
source: node.source.value,
|
||||
imported,
|
||||
specifiers
|
||||
});
|
||||
|
||||
for (var specifier of (this.get("specifiers"): Array)) {
|
||||
var ids = specifier.getBindingIdentifiers();
|
||||
extend(formatter.localImports, ids);
|
||||
for (var specifier of (this.get("specifiers"): Array)) {
|
||||
var ids = specifier.getBindingIdentifiers();
|
||||
extend(formatter.localImports, ids);
|
||||
|
||||
var local = specifier.node.local.name;
|
||||
var local = specifier.node.local.name;
|
||||
|
||||
if (specifier.isImportDefaultSpecifier()) {
|
||||
imported.push("default");
|
||||
specifiers.push({
|
||||
kind: "named",
|
||||
imported: "default",
|
||||
local
|
||||
});
|
||||
}
|
||||
if (specifier.isImportDefaultSpecifier()) {
|
||||
imported.push("default");
|
||||
specifiers.push({
|
||||
kind: "named",
|
||||
imported: "default",
|
||||
local
|
||||
});
|
||||
}
|
||||
|
||||
if (specifier.isImportSpecifier()) {
|
||||
var importedName = specifier.node.imported.name;
|
||||
imported.push(importedName);
|
||||
specifiers.push({
|
||||
kind: "named",
|
||||
imported: importedName,
|
||||
local
|
||||
});
|
||||
}
|
||||
if (specifier.isImportSpecifier()) {
|
||||
var importedName = specifier.node.imported.name;
|
||||
imported.push(importedName);
|
||||
specifiers.push({
|
||||
kind: "named",
|
||||
imported: importedName,
|
||||
local
|
||||
});
|
||||
}
|
||||
|
||||
if (specifier.isImportNamespaceSpecifier()) {
|
||||
imported.push("*");
|
||||
specifiers.push({
|
||||
kind: "namespace",
|
||||
local
|
||||
});
|
||||
if (specifier.isImportNamespaceSpecifier()) {
|
||||
imported.push("*");
|
||||
specifiers.push({
|
||||
kind: "namespace",
|
||||
local
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -214,18 +156,27 @@ var metadataVisitor = {
|
||||
}
|
||||
},
|
||||
|
||||
Scope() {
|
||||
this.skip();
|
||||
Scope(node, parent, scope, formatter) {
|
||||
if (!formatter.isLoose()) {
|
||||
this.skip();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default class DefaultFormatter {
|
||||
constructor(file) {
|
||||
this.internalRemap = object();
|
||||
this.defaultIds = object();
|
||||
this.scope = file.scope;
|
||||
this.file = file;
|
||||
this.ids = object();
|
||||
// object containg all module sources with the scope that they're contained in
|
||||
this.sourceScopes = object();
|
||||
|
||||
// ids for use in module ids
|
||||
this.defaultIds = object();
|
||||
this.ids = object();
|
||||
|
||||
// contains reference aliases for live bindings
|
||||
this.remaps = new Remaps(file, this);
|
||||
|
||||
this.scope = file.scope;
|
||||
this.file = file;
|
||||
|
||||
this.hasNonDefaultExports = false;
|
||||
|
||||
@@ -239,6 +190,18 @@ export default class DefaultFormatter {
|
||||
this.getMetadata();
|
||||
}
|
||||
|
||||
addScope(path) {
|
||||
var source = path.node.source && path.node.source.value;
|
||||
if (!source) return;
|
||||
|
||||
var existingScope = this.sourceScopes[source];
|
||||
if (existingScope && existingScope !== path.scope) {
|
||||
throw path.errorWithNode(messages.get("modulesDuplicateDeclarations"));
|
||||
}
|
||||
|
||||
this.sourceScopes[source] = path.scope;
|
||||
}
|
||||
|
||||
isModuleType(node, type) {
|
||||
var modules = this.file.dynamicImportTypes[type];
|
||||
return modules && modules.indexOf(node) >= 0;
|
||||
@@ -260,12 +223,14 @@ export default class DefaultFormatter {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has) this.file.path.traverse(metadataVisitor, this);
|
||||
if (has || this.isLoose()) {
|
||||
this.file.path.traverse(metadataVisitor, this);
|
||||
}
|
||||
}
|
||||
|
||||
remapAssignments() {
|
||||
if (this.hasLocalExports || this.hasLocalImports) {
|
||||
this.file.path.traverse(remapVisitor, this);
|
||||
this.remaps.run();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ export default class AMDFormatter extends DefaultFormatter {
|
||||
this.getExternalReference(node);
|
||||
}
|
||||
|
||||
importSpecifier(specifier, node, nodes) {
|
||||
importSpecifier(specifier, node, nodes, scope) {
|
||||
var key = node.source.value;
|
||||
var ref = this.getExternalReference(node);
|
||||
|
||||
@@ -90,7 +90,7 @@ export default class AMDFormatter extends DefaultFormatter {
|
||||
// import * as bar from "foo";
|
||||
} else if (!includes(this.file.dynamicImported, node) && t.isSpecifierDefault(specifier) && !this.noInteropRequireImport) {
|
||||
// import foo from "foo";
|
||||
var uid = this.scope.generateUidIdentifier(specifier.local.name);
|
||||
var uid = scope.generateUidIdentifier(specifier.local.name);
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(uid, t.callExpression(this.file.addHelper("interop-require-default"), [ref]))
|
||||
]));
|
||||
@@ -102,7 +102,7 @@ export default class AMDFormatter extends DefaultFormatter {
|
||||
ref = t.memberExpression(ref, imported);
|
||||
}
|
||||
|
||||
this.internalRemap[specifier.local.name] = ref;
|
||||
this.remaps.add(scope, specifier.local.name, ref);
|
||||
}
|
||||
|
||||
exportSpecifier(specifier, node, nodes) {
|
||||
|
||||
@@ -37,7 +37,7 @@ export default class CommonJSFormatter extends DefaultFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
importSpecifier(specifier, node, nodes) {
|
||||
importSpecifier(specifier, node, nodes, scope) {
|
||||
var variableName = specifier.local;
|
||||
|
||||
var ref = this.getExternalReference(node, nodes);
|
||||
@@ -47,9 +47,9 @@ export default class CommonJSFormatter extends DefaultFormatter {
|
||||
if (this.isModuleType(node, "absolute")) {
|
||||
// absolute module reference
|
||||
} else if (this.isModuleType(node, "absoluteDefault")) {
|
||||
this.internalRemap[variableName.name] = ref;
|
||||
this.remaps.add(scope, variableName.name, ref);
|
||||
} else if (this.noInteropRequireImport) {
|
||||
this.internalRemap[variableName.name] = t.memberExpression(ref, t.identifier("default"));
|
||||
this.remaps.add(scope, variableName.name, t.memberExpression(ref, t.identifier("default")));
|
||||
} else {
|
||||
var uid = this.scope.generateUidIdentifierBasedOnNode(node, "import");
|
||||
|
||||
@@ -57,7 +57,7 @@ export default class CommonJSFormatter extends DefaultFormatter {
|
||||
t.variableDeclarator(uid, t.callExpression(this.file.addHelper("interop-require-default"), [ref]))
|
||||
]));
|
||||
|
||||
this.internalRemap[variableName.name] = t.memberExpression(uid, t.identifier("default"));
|
||||
this.remaps.add(scope, variableName.name, t.memberExpression(uid, t.identifier("default")));
|
||||
}
|
||||
} else {
|
||||
if (t.isImportNamespaceSpecifier(specifier)) {
|
||||
@@ -71,7 +71,7 @@ export default class CommonJSFormatter extends DefaultFormatter {
|
||||
]));
|
||||
} else {
|
||||
// import { foo } from "foo";
|
||||
this.internalRemap[variableName.name] = t.memberExpression(ref, specifier.imported);
|
||||
this.remaps.add(scope, variableName.name, t.memberExpression(ref, specifier.imported));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import DefaultFormatter from "./_default";
|
||||
import * as t from "../../types";
|
||||
|
||||
export default class IgnoreFormatter {
|
||||
export default class IgnoreFormatter extends DefaultFormatter {
|
||||
exportDeclaration(node, nodes) {
|
||||
var declar = t.toStatement(node.declaration, true);
|
||||
if (declar) nodes.push(t.inherits(declar, node));
|
||||
@@ -10,4 +11,5 @@ export default class IgnoreFormatter {
|
||||
importDeclaration() {}
|
||||
importSpecifier() {}
|
||||
exportSpecifier() {}
|
||||
transform() {}
|
||||
}
|
||||
|
||||
121
src/babel/transformation/modules/lib/remaps.js
Normal file
121
src/babel/transformation/modules/lib/remaps.js
Normal file
@@ -0,0 +1,121 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
var remapVisitor = {
|
||||
enter(node) {
|
||||
if (node._skipModulesRemap) {
|
||||
return this.skip();
|
||||
}
|
||||
},
|
||||
|
||||
ReferencedIdentifier(node, parent, scope, remaps) {
|
||||
var { formatter } = remaps;
|
||||
|
||||
var remap = remaps.get(scope, node.name);
|
||||
if (!remap || node === remap) return;
|
||||
|
||||
if (!scope.hasBinding(node.name) ||
|
||||
scope.bindingIdentifierEquals(node.name, formatter.localImports[node.name])) {
|
||||
if (!formatter.isLoose() && this.key === "callee" && this.parentPath.isCallExpression()) {
|
||||
return t.sequenceExpression([t.literal(0), remap]);
|
||||
} else {
|
||||
return remap;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
AssignmentExpression: {
|
||||
exit(node, parent, scope, { formatter }) {
|
||||
if (!node._ignoreModulesRemap) {
|
||||
var exported = formatter.getExport(node.left, scope);
|
||||
if (exported) {
|
||||
return formatter.remapExportAssignment(node, exported);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
UpdateExpression(node, parent, scope, { formatter }) {
|
||||
var exported = formatter.getExport(node.argument, scope);
|
||||
if (!exported) return;
|
||||
|
||||
this.skip();
|
||||
|
||||
// expand to long file assignment expression
|
||||
var assign = t.assignmentExpression(node.operator[0] + "=", node.argument, t.literal(1));
|
||||
|
||||
// remap this assignment expression
|
||||
var remapped = formatter.remapExportAssignment(assign, exported);
|
||||
|
||||
// we don't need to change the result
|
||||
if (t.isExpressionStatement(parent) || node.prefix) {
|
||||
return remapped;
|
||||
}
|
||||
|
||||
var nodes = [];
|
||||
nodes.push(remapped);
|
||||
|
||||
var operator;
|
||||
if (node.operator === "--") {
|
||||
operator = "+";
|
||||
} else { // "++"
|
||||
operator = "-";
|
||||
}
|
||||
nodes.push(t.binaryExpression(operator, node.argument, t.literal(1)));
|
||||
|
||||
return t.sequenceExpression(nodes);
|
||||
}
|
||||
};
|
||||
export default class Remaps {
|
||||
constructor(file, formatter) {
|
||||
this.formatter = formatter;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
run() {
|
||||
this.file.path.traverse(remapVisitor, this);
|
||||
}
|
||||
|
||||
_getKey(name) {
|
||||
return `${name}:moduleRemap`;
|
||||
}
|
||||
|
||||
get(scope, name) {
|
||||
return scope.getData(this._getKey(name));
|
||||
}
|
||||
|
||||
add(scope, name, val) {
|
||||
if (this.all) {
|
||||
this.all.push({
|
||||
name,
|
||||
scope,
|
||||
node: val
|
||||
});
|
||||
}
|
||||
|
||||
return scope.setData(this._getKey(name), val);
|
||||
}
|
||||
|
||||
remove(scope, name) {
|
||||
return scope.removeData(this._getKey(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* These methods are used by the system module formatter who needs access to all the remaps
|
||||
* so it can process them into it's specific setter method. We don't do this by default since
|
||||
* no other module formatters need access to this.
|
||||
*/
|
||||
|
||||
getAll() {
|
||||
return this.all;
|
||||
}
|
||||
|
||||
clearAll() {
|
||||
if (this.all) {
|
||||
for (var remap of (this.all: Array)) {
|
||||
remap.scope.removeData(this._getKey(remap.name));
|
||||
}
|
||||
}
|
||||
|
||||
this.all = [];
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import DefaultFormatter from "./_default";
|
||||
import AMDFormatter from "./amd";
|
||||
import object from "../../helpers/object";
|
||||
import * as util from "../../util";
|
||||
import last from "lodash/array/last";
|
||||
import map from "lodash/collection/map";
|
||||
@@ -82,6 +81,8 @@ export default class SystemFormatter extends AMDFormatter {
|
||||
this.exportIdentifier = file.scope.generateUidIdentifier("export");
|
||||
this.noInteropRequireExport = true;
|
||||
this.noInteropRequireImport = true;
|
||||
|
||||
this.remaps.clearAll();
|
||||
}
|
||||
|
||||
_addImportSource(node, exportNode) {
|
||||
@@ -137,13 +138,13 @@ export default class SystemFormatter extends AMDFormatter {
|
||||
importSpecifier(specifier, node, nodes) {
|
||||
AMDFormatter.prototype.importSpecifier.apply(this, arguments);
|
||||
|
||||
for (var name in this.internalRemap) {
|
||||
for (var remap of (this.remaps.getAll(): Array)) {
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(t.identifier(name), this.internalRemap[name])
|
||||
t.variableDeclarator(t.identifier(remap.name), remap.node)
|
||||
]));
|
||||
}
|
||||
|
||||
this.internalRemap = object();
|
||||
this.remaps.clearAll();
|
||||
|
||||
this._addImportSource(last(nodes), node);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import Transformer from "./transformer";
|
||||
import PluginManager from "./file/plugin-manager";
|
||||
import normalizeAst from "../helpers/normalize-ast";
|
||||
import Plugin from "./plugin";
|
||||
import assign from "lodash/object/assign";
|
||||
import object from "../helpers/object";
|
||||
import File from "./file";
|
||||
|
||||
export default class TransformerPipeline {
|
||||
export default class Pipeline {
|
||||
constructor() {
|
||||
this.transformers = object();
|
||||
this.namespaces = object();
|
||||
@@ -20,7 +21,7 @@ export default class TransformerPipeline {
|
||||
return this;
|
||||
}
|
||||
|
||||
addTransformer(key, transformer) {
|
||||
addTransformer(key, plugin) {
|
||||
if (this.transformers[key]) throw new Error(); // todo: error
|
||||
|
||||
var namespace = key.split(".")[0];
|
||||
@@ -28,7 +29,19 @@ export default class TransformerPipeline {
|
||||
this.namespaces[namespace].push(key);
|
||||
this.namespaces[key] = namespace;
|
||||
|
||||
this.transformers[key] = new Transformer(key, transformer);
|
||||
if (typeof plugin === "function") {
|
||||
plugin = PluginManager.memoisePluginContainer(plugin);
|
||||
plugin.key = key;
|
||||
plugin.metadata.optional = true;
|
||||
|
||||
if (key === "react.displayName") {
|
||||
plugin.metadata.optional = false;
|
||||
}
|
||||
} else {
|
||||
plugin = new Plugin(key, plugin);
|
||||
}
|
||||
|
||||
this.transformers[key] = plugin;
|
||||
}
|
||||
|
||||
addAliases(names) {
|
||||
@@ -46,17 +59,24 @@ export default class TransformerPipeline {
|
||||
return this;
|
||||
}
|
||||
|
||||
canTransform(transformer, fileOpts) {
|
||||
if (transformer.metadata.plugin) return true;
|
||||
canTransform(plugin, fileOpts) {
|
||||
if (plugin.metadata.plugin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (var filter of (this.filters: Array)) {
|
||||
var result = filter(transformer, fileOpts);
|
||||
var result = filter(plugin, fileOpts);
|
||||
if (result != null) return result;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
analyze(code: string, opts?: Object = {}) {
|
||||
opts.code = false;
|
||||
return this.transform(code, opts);
|
||||
}
|
||||
|
||||
pretransform(code: string, opts?: Object) {
|
||||
var file = new File(opts, this);
|
||||
return file.wrap(code, function () {
|
||||
@@ -7,14 +7,13 @@ import type File from "./file";
|
||||
* AST and running it's parent transformers handlers over it.
|
||||
*/
|
||||
|
||||
export default class TransformerPass {
|
||||
constructor(file: File, transformer: Transformer) {
|
||||
this.transformer = transformer;
|
||||
this.handlers = transformer.handlers;
|
||||
this.file = file;
|
||||
this.key = transformer.key;
|
||||
export default class PluginPass {
|
||||
constructor(file: File, plugin: Transformer) {
|
||||
this.plugin = plugin;
|
||||
this.file = file;
|
||||
this.key = plugin.key;
|
||||
|
||||
if (this.canTransform() && transformer.metadata.experimental && !file.opts.experimental) {
|
||||
if (this.canTransform() && plugin.metadata.experimental && !file.opts.experimental) {
|
||||
file.log.warn(`THE TRANSFORMER ${this.key} HAS BEEN MARKED AS EXPERIMENTAL AND IS WIP. USE AT YOUR OWN RISK. ` +
|
||||
"THIS WILL HIGHLY LIKELY BREAK YOUR CODE SO USE WITH **EXTREME** CAUTION. ENABLE THE " +
|
||||
"`experimental` OPTION TO IGNORE THIS WARNING.");
|
||||
@@ -23,13 +22,13 @@ export default class TransformerPass {
|
||||
|
||||
canTransform(): boolean {
|
||||
return this.file.transformerDependencies[this.key] ||
|
||||
this.file.pipeline.canTransform(this.transformer, this.file.opts);
|
||||
this.file.pipeline.canTransform(this.plugin, this.file.opts);
|
||||
}
|
||||
|
||||
transform() {
|
||||
var file = this.file;
|
||||
file.log.debug(`Start transformer ${this.key}`);
|
||||
traverse(file.ast, this.handlers, file.scope, file);
|
||||
traverse(file.ast, this.plugin.visitor, file.scope, file);
|
||||
file.log.debug(`Finish transformer ${this.key}`);
|
||||
}
|
||||
}
|
||||
55
src/babel/transformation/plugin.js
Normal file
55
src/babel/transformation/plugin.js
Normal file
@@ -0,0 +1,55 @@
|
||||
import PluginPass from "./plugin-pass";
|
||||
import * as messages from "../messages";
|
||||
import isFunction from "lodash/lang/isFunction";
|
||||
import traverse from "../traversal";
|
||||
import assign from "lodash/object/assign";
|
||||
import clone from "lodash/lang/clone";
|
||||
import File from "./file";
|
||||
|
||||
export default class Plugin {
|
||||
constructor(key: string, plugin: Object) {
|
||||
plugin = assign({}, plugin);
|
||||
|
||||
var take = function (key) {
|
||||
var val = plugin[key];
|
||||
delete plugin[key];
|
||||
return val;
|
||||
};
|
||||
|
||||
this.manipulateOptions = take("manipulateOptions");
|
||||
this.metadata = take("metadata") || {};
|
||||
this.dependencies = this.metadata.dependencies || [];
|
||||
this.post = take("post");
|
||||
this.pre = take("pre");
|
||||
|
||||
//
|
||||
|
||||
if (this.metadata.stage != null) {
|
||||
this.metadata.optional = true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
this.visitor = this.normalize(clone(take("visitor")) || {});
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
normalize(visitor: Object): Object {
|
||||
if (isFunction(visitor)) {
|
||||
visitor = { ast: visitor };
|
||||
}
|
||||
|
||||
traverse.explode(visitor);
|
||||
|
||||
return visitor;
|
||||
}
|
||||
|
||||
buildPass(file: File): PluginPass {
|
||||
// validate Transformer instance
|
||||
if (!(file instanceof File)) {
|
||||
throw new TypeError(messages.get("pluginNotFile", this.key));
|
||||
}
|
||||
|
||||
return new PluginPass(file, this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
(function () {
|
||||
super(...arguments);
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
if (SUPER_NAME != null) {
|
||||
SUPER_NAME.apply(this, arguments);
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
if (SUPER_NAME != null) {
|
||||
SUPER_NAME.apply(this, arguments);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
if (SUPER_NAME != null) {
|
||||
var NATIVE_REF = new SUPER_NAME(...arguments);
|
||||
NATIVE_REF.__proto__ = CLASS_NAME.prototype;
|
||||
return NATIVE_REF;
|
||||
}
|
||||
@@ -1,8 +1,18 @@
|
||||
(function (obj, key, value) {
|
||||
return Object.defineProperty(obj, key, {
|
||||
value: value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
// Shortcircuit the slow defineProperty path when possible.
|
||||
// We are trying to avoid issues where setters defined on the
|
||||
// prototype cause side effects under the fast path of simple
|
||||
// assignment. By checking for existence of the property with
|
||||
// the in operator, we can optimize most of this overhead away.
|
||||
if (key in obj) {
|
||||
Object.defineProperty(obj, key, {
|
||||
value: value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true
|
||||
});
|
||||
} else {
|
||||
obj[key] = value;
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
(function get(object, property, receiver) {
|
||||
if (object === null) object = Function.prototype;
|
||||
|
||||
var desc = Object.getOwnPropertyDescriptor(object, property);
|
||||
|
||||
if (desc === undefined) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function (arr, i) {
|
||||
if (Array.isArray(arr)) {
|
||||
return arr;
|
||||
} else if (Symbol.iterator in Object(arr)) {
|
||||
(function () {
|
||||
// Broken out into a separate function to avoid deoptimizations due to the try/catch for the
|
||||
// array iterator case.
|
||||
function sliceIterator(arr, i) {
|
||||
// this is an expanded form of `for...of` that properly supports abrupt completions of
|
||||
// iterators etc. variable names have been minimised to reduce the size of this massive
|
||||
// helper. sometimes spec compliancy is annoying :(
|
||||
@@ -32,7 +32,15 @@
|
||||
}
|
||||
}
|
||||
return _arr;
|
||||
} else {
|
||||
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
||||
}
|
||||
});
|
||||
|
||||
return function (arr, i) {
|
||||
if (Array.isArray(arr)) {
|
||||
return arr;
|
||||
} else if (Symbol.iterator in Object(arr)) {
|
||||
return sliceIterator(arr, i);
|
||||
} else {
|
||||
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -1,82 +1,14 @@
|
||||
import TransformerPass from "./transformer-pass";
|
||||
import * as messages from "../messages";
|
||||
import isFunction from "lodash/lang/isFunction";
|
||||
import traverse from "../traversal";
|
||||
import isObject from "lodash/lang/isObject";
|
||||
import assign from "lodash/object/assign";
|
||||
import File from "./file";
|
||||
import each from "lodash/collection/each";
|
||||
|
||||
/**
|
||||
* This is the class responsible for normalising a transformers handlers
|
||||
* as well as constructing a `TransformerPass` that is responsible for
|
||||
* actually running the transformer over the provided `File`.
|
||||
*/
|
||||
import Plugin from "./plugin";
|
||||
|
||||
export default class Transformer {
|
||||
constructor(transformerKey: string, transformer: Object) {
|
||||
transformer = assign({}, transformer);
|
||||
constructor(key, obj) {
|
||||
var plugin = {};
|
||||
|
||||
var take = function (key) {
|
||||
var val = transformer[key];
|
||||
delete transformer[key];
|
||||
return val;
|
||||
};
|
||||
plugin.metadata = obj.metadata;
|
||||
delete obj.metadata;
|
||||
|
||||
this.manipulateOptions = take("manipulateOptions");
|
||||
this.metadata = take("metadata") || {};
|
||||
this.dependencies = this.metadata.dependencies || [];
|
||||
this.parser = take("parser");
|
||||
this.post = take("post");
|
||||
this.pre = take("pre");
|
||||
plugin.visitor = obj;
|
||||
|
||||
//
|
||||
|
||||
if (this.metadata.stage != null) {
|
||||
this.metadata.optional = true;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
this.handlers = this.normalize(transformer);
|
||||
this.key = transformerKey;
|
||||
}
|
||||
|
||||
normalize(transformer: Object): Object {
|
||||
if (isFunction(transformer)) {
|
||||
transformer = { ast: transformer };
|
||||
}
|
||||
|
||||
traverse.explode(transformer);
|
||||
|
||||
each(transformer, (fns, type) => {
|
||||
// hidden property
|
||||
if (type[0] === "_") {
|
||||
this[type] = fns;
|
||||
return;
|
||||
}
|
||||
|
||||
if (type === "enter" || type === "exit") return;
|
||||
|
||||
if (isFunction(fns)) fns = { enter: fns };
|
||||
|
||||
if (!isObject(fns)) return;
|
||||
|
||||
if (!fns.enter) fns.enter = function () { };
|
||||
if (!fns.exit) fns.exit = function () { };
|
||||
|
||||
transformer[type] = fns;
|
||||
});
|
||||
|
||||
return transformer;
|
||||
}
|
||||
|
||||
buildPass(file: File): TransformerPass {
|
||||
// validate Transformer instance
|
||||
if (!(file instanceof File)) {
|
||||
throw new TypeError(messages.get("transformerNotFile", this.key));
|
||||
}
|
||||
|
||||
return new TransformerPass(file, this);
|
||||
return new Plugin(key, plugin);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,8 @@
|
||||
"utility.inlineExpressions": "minification.constantFolding",
|
||||
"utility.deadCodeElimination": "minification.deadCodeElimination",
|
||||
"utility.removeConsoleCalls": "minification.removeConsole",
|
||||
"utility.removeDebugger": "minification.removeDebugger"
|
||||
"utility.removeDebugger": "minification.removeDebugger",
|
||||
|
||||
"es6.parameters.rest": "es6.parameters",
|
||||
"es6.parameters.default": "es6.parameters"
|
||||
}
|
||||
|
||||
@@ -4,13 +4,15 @@ export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export var MemberExpression = {
|
||||
exit(node) {
|
||||
var prop = node.property;
|
||||
if (!node.computed && t.isIdentifier(prop) && !t.isValidIdentifier(prop.name)) {
|
||||
// foo.default -> foo["default"]
|
||||
node.property = t.literal(prop.name);
|
||||
node.computed = true;
|
||||
export var visitor = {
|
||||
MemberExpression: {
|
||||
exit(node) {
|
||||
var prop = node.property;
|
||||
if (!node.computed && t.isIdentifier(prop) && !t.isValidIdentifier(prop.name)) {
|
||||
// foo.default -> foo["default"]
|
||||
node.property = t.literal(prop.name);
|
||||
node.computed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,12 +4,14 @@ export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export var Property = {
|
||||
exit(node) {
|
||||
var key = node.key;
|
||||
if (!node.computed && t.isIdentifier(key) && !t.isValidIdentifier(key.name)) {
|
||||
// default: "bar" -> "default": "bar"
|
||||
node.key = t.literal(key.name);
|
||||
export var visitor = {
|
||||
Property: {
|
||||
exit(node) {
|
||||
var key = node.key;
|
||||
if (!node.computed && t.isIdentifier(key) && !t.isValidIdentifier(key.name)) {
|
||||
// default: "bar" -> "default": "bar"
|
||||
node.key = t.literal(key.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,29 +1,31 @@
|
||||
import * as defineMap from "../../helpers/define-map";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export function ObjectExpression(node, parent, scope, file) {
|
||||
var hasAny = false;
|
||||
for (var prop of (node.properties: Array)) {
|
||||
if (prop.kind === "get" || prop.kind === "set") {
|
||||
hasAny = true;
|
||||
break;
|
||||
export var visitor = {
|
||||
ObjectExpression(node, parent, scope, file) {
|
||||
var hasAny = false;
|
||||
for (var prop of (node.properties: Array)) {
|
||||
if (prop.kind === "get" || prop.kind === "set") {
|
||||
hasAny = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasAny) return;
|
||||
|
||||
var mutatorMap = {};
|
||||
|
||||
node.properties = node.properties.filter(function (prop) {
|
||||
if (prop.kind === "get" || prop.kind === "set") {
|
||||
defineMap.push(mutatorMap, prop, prop.kind, file);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return t.callExpression(
|
||||
t.memberExpression(t.identifier("Object"), t.identifier("defineProperties")),
|
||||
[node, defineMap.toDefineObject(mutatorMap)]
|
||||
);
|
||||
}
|
||||
if (!hasAny) return;
|
||||
|
||||
var mutatorMap = {};
|
||||
|
||||
node.properties = node.properties.filter(function (prop) {
|
||||
if (prop.kind === "get" || prop.kind === "set") {
|
||||
defineMap.push(mutatorMap, prop, prop.kind, file);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return t.callExpression(
|
||||
t.memberExpression(t.identifier("Object"), t.identifier("defineProperties")),
|
||||
[node, defineMap.toDefineObject(mutatorMap)]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
export function ArrowFunctionExpression(node) {
|
||||
t.ensureBlock(node);
|
||||
|
||||
node.expression = false;
|
||||
node.type = "FunctionExpression";
|
||||
node.shadow = true;
|
||||
}
|
||||
export var visitor = {
|
||||
ArrowFunctionExpression(node) {
|
||||
this.ensureBlock();
|
||||
node.expression = false;
|
||||
node.type = "FunctionExpression";
|
||||
node.shadow = true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -44,47 +44,47 @@ export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
export function VariableDeclaration(node, parent, scope, file) {
|
||||
if (!isLet(node, parent)) return;
|
||||
export var visitor = {
|
||||
VariableDeclaration(node, parent, scope, file) {
|
||||
if (!isLet(node, parent)) return;
|
||||
|
||||
if (isLetInitable(node) && file.transformers["es6.spec.blockScoping"].canTransform()) {
|
||||
var nodes = [node];
|
||||
if (isLetInitable(node) && file.transformers["es6.spec.blockScoping"].canTransform()) {
|
||||
var nodes = [node];
|
||||
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
var decl = node.declarations[i];
|
||||
if (decl.init) {
|
||||
var assign = t.assignmentExpression("=", decl.id, decl.init);
|
||||
assign._ignoreBlockScopingTDZ = true;
|
||||
nodes.push(t.expressionStatement(assign));
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
var decl = node.declarations[i];
|
||||
if (decl.init) {
|
||||
var assign = t.assignmentExpression("=", decl.id, decl.init);
|
||||
assign._ignoreBlockScopingTDZ = true;
|
||||
nodes.push(t.expressionStatement(assign));
|
||||
}
|
||||
decl.init = file.addHelper("temporal-undefined");
|
||||
}
|
||||
decl.init = file.addHelper("temporal-undefined");
|
||||
|
||||
node._blockHoist = 2;
|
||||
|
||||
return nodes;
|
||||
}
|
||||
},
|
||||
|
||||
Loop(node, parent, scope, file) {
|
||||
var init = node.left || node.init;
|
||||
if (isLet(init, node)) {
|
||||
t.ensureBlock(node);
|
||||
node.body._letDeclarators = [init];
|
||||
}
|
||||
|
||||
node._blockHoist = 2;
|
||||
var blockScoping = new BlockScoping(this, this.get("body"), parent, scope, file);
|
||||
return blockScoping.run();
|
||||
},
|
||||
|
||||
return nodes;
|
||||
"BlockStatement|Program"(block, parent, scope, file) {
|
||||
if (!t.isLoop(parent)) {
|
||||
var blockScoping = new BlockScoping(null, this, parent, scope, file);
|
||||
blockScoping.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function Loop(node, parent, scope, file) {
|
||||
var init = node.left || node.init;
|
||||
if (isLet(init, node)) {
|
||||
t.ensureBlock(node);
|
||||
node.body._letDeclarators = [init];
|
||||
}
|
||||
|
||||
var blockScoping = new BlockScoping(this, this.get("body"), parent, scope, file);
|
||||
return blockScoping.run();
|
||||
}
|
||||
|
||||
export function BlockStatement(block, parent, scope, file) {
|
||||
if (!t.isLoop(parent)) {
|
||||
var blockScoping = new BlockScoping(null, this, parent, scope, file);
|
||||
blockScoping.run();
|
||||
}
|
||||
}
|
||||
|
||||
export { BlockStatement as Program };
|
||||
};
|
||||
|
||||
function replace(node, parent, scope, remaps) {
|
||||
var remap = remaps[node.name];
|
||||
@@ -162,6 +162,7 @@ var hoistVarDeclarationsVisitor = {
|
||||
} else if (this.isFor()) {
|
||||
if (isVar(node.left, node)) {
|
||||
node.left = node.left.declarations[0].id;
|
||||
self.pushDeclar(node.left);
|
||||
}
|
||||
} else if (isVar(node, parent)) {
|
||||
return self.pushDeclar(node).map(t.expressionStatement);
|
||||
@@ -337,6 +338,7 @@ class BlockScoping {
|
||||
// this is the defining identifier of a declaration
|
||||
var ref = letRefs[key];
|
||||
|
||||
// todo: could skip this if the colliding binding is in another function
|
||||
if (scope.parentHasBinding(key) || scope.hasGlobal(key)) {
|
||||
var uid = scope.generateUidIdentifier(ref.name).name;
|
||||
ref.name = uid;
|
||||
|
||||
@@ -10,15 +10,17 @@ import * as t from "../../../types";
|
||||
|
||||
const PROPERTY_COLLISION_METHOD_NAME = "__initializeProperties";
|
||||
|
||||
export function ClassDeclaration(node, parent, scope, file) {
|
||||
return t.variableDeclaration("let", [
|
||||
t.variableDeclarator(node.id, t.toExpression(node))
|
||||
]);
|
||||
}
|
||||
export var visitor = {
|
||||
ClassDeclaration(node) {
|
||||
return t.variableDeclaration("let", [
|
||||
t.variableDeclarator(node.id, t.toExpression(node))
|
||||
]);
|
||||
},
|
||||
|
||||
export function ClassExpression(node, parent, scope, file) {
|
||||
return new ClassTransformer(this, file).run();
|
||||
}
|
||||
ClassExpression(node, parent, scope, file) {
|
||||
return new ClassTransformer(this, file).run();
|
||||
}
|
||||
};
|
||||
|
||||
var collectPropertyReferencesVisitor = {
|
||||
Identifier: {
|
||||
@@ -251,20 +253,43 @@ class ClassTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* https://www.youtube.com/watch?v=fWNaR-rxAic
|
||||
*/
|
||||
|
||||
constructorMeMaybe() {
|
||||
if (!this.hasSuper) return;
|
||||
|
||||
var hasConstructor = false;
|
||||
var paths = this.path.get("body.body");
|
||||
|
||||
for (var path of (paths: Array)) {
|
||||
hasConstructor = path.equals("kind", "constructor");
|
||||
if (hasConstructor) break;
|
||||
}
|
||||
|
||||
if (!hasConstructor) {
|
||||
this.path.get("body").unshiftContainer("body", t.methodDefinition(
|
||||
t.identifier("constructor"),
|
||||
util.template("class-derived-default-constructor"),
|
||||
"constructor"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
buildBody() {
|
||||
this.constructorMeMaybe();
|
||||
|
||||
var constructorBody = this.constructorBody;
|
||||
var classBody = this.node.body.body;
|
||||
var classBodyPaths = this.path.get("body.body");
|
||||
var body = this.body;
|
||||
|
||||
var classBodyPaths = this.path.get("body").get("body");
|
||||
|
||||
for (var i = 0; i < classBody.length; i++) {
|
||||
var node = classBody[i];
|
||||
var path = classBodyPaths[i];
|
||||
for (var path of (classBodyPaths: Array)) {
|
||||
var node = path.node;
|
||||
|
||||
if (node.decorators) {
|
||||
memoiseDecorators(node.decorators, this.scope);
|
||||
@@ -297,16 +322,6 @@ class ClassTransformer {
|
||||
}
|
||||
}
|
||||
|
||||
// we have no constructor, but we're a derived class
|
||||
if (!this.hasConstructor && this.hasSuper) {
|
||||
var helperName = "class-super-constructor-call";
|
||||
if (this.isLoose) helperName += "-loose";
|
||||
constructorBody.body.push(util.template(helperName, {
|
||||
CLASS_NAME: this.classRef,
|
||||
SUPER_NAME: this.superName
|
||||
}, true));
|
||||
}
|
||||
|
||||
//
|
||||
this.placePropertyInitializers();
|
||||
|
||||
@@ -462,7 +477,7 @@ class ClassTransformer {
|
||||
|
||||
var classRef = this.classRef;
|
||||
if (!node.static) classRef = t.memberExpression(classRef, t.identifier("prototype"));
|
||||
var methodName = t.memberExpression(classRef, node.key, node.computed);
|
||||
var methodName = t.memberExpression(classRef, node.key, node.computed || t.isLiteral(node.key));
|
||||
|
||||
var expr = t.expressionStatement(t.assignmentExpression("=", methodName, node.value));
|
||||
t.inheritsComments(expr, node);
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import * as messages from "../../../messages";
|
||||
|
||||
export function Scope(node, parent, scope) {
|
||||
for (var name in scope.bindings) {
|
||||
var binding = scope.bindings[name];
|
||||
export var visitor = {
|
||||
Scope(node, parent, scope) {
|
||||
for (var name in scope.bindings) {
|
||||
var binding = scope.bindings[name];
|
||||
|
||||
// not a constant
|
||||
if (binding.kind !== "const" && binding.kind !== "module") continue;
|
||||
// not a constant
|
||||
if (binding.kind !== "const" && binding.kind !== "module") continue;
|
||||
|
||||
for (var violation of (binding.constantViolations: Array)) {
|
||||
throw violation.errorWithNode(messages.get("readOnly", name));
|
||||
for (var violation of (binding.constantViolations: Array)) {
|
||||
throw violation.errorWithNode(messages.get("readOnly", name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
export function VariableDeclaration(node) {
|
||||
if (node.kind === "const") node.kind = "let";
|
||||
}
|
||||
VariableDeclaration(node) {
|
||||
if (node.kind === "const") node.kind = "let";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5,145 +5,209 @@ export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
var left = node.left;
|
||||
export var visitor = {
|
||||
ForXStatement(node, parent, scope, file) {
|
||||
var left = node.left;
|
||||
|
||||
if (t.isPattern(left)) {
|
||||
// for ({ length: k } in { abc: 3 });
|
||||
if (t.isPattern(left)) {
|
||||
// for ({ length: k } in { abc: 3 });
|
||||
|
||||
var temp = scope.generateUidIdentifier("ref");
|
||||
var temp = scope.generateUidIdentifier("ref");
|
||||
|
||||
node.left = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp)
|
||||
node.left = t.variableDeclaration("var", [
|
||||
t.variableDeclarator(temp)
|
||||
]);
|
||||
|
||||
this.ensureBlock();
|
||||
|
||||
node.body.body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(left, temp)
|
||||
]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t.isVariableDeclaration(left)) return;
|
||||
|
||||
var pattern = left.declarations[0].id;
|
||||
if (!t.isPattern(pattern)) return;
|
||||
|
||||
var key = scope.generateUidIdentifier("ref");
|
||||
node.left = t.variableDeclaration(left.kind, [
|
||||
t.variableDeclarator(key, null)
|
||||
]);
|
||||
|
||||
t.ensureBlock(node);
|
||||
|
||||
node.body.body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(left, temp)
|
||||
]));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t.isVariableDeclaration(left)) return;
|
||||
|
||||
var pattern = left.declarations[0].id;
|
||||
if (!t.isPattern(pattern)) return;
|
||||
|
||||
var key = scope.generateUidIdentifier("ref");
|
||||
node.left = t.variableDeclaration(left.kind, [
|
||||
t.variableDeclarator(key, null)
|
||||
]);
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
kind: left.kind,
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
|
||||
destructuring.init(pattern, key);
|
||||
|
||||
t.ensureBlock(node);
|
||||
|
||||
var block = node.body;
|
||||
block.body = nodes.concat(block.body);
|
||||
}
|
||||
|
||||
export { ForOfStatement as ForInStatement };
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
var hasDestructuring = false;
|
||||
for (let pattern of (node.params: Array)) {
|
||||
if (t.isPattern(pattern)) {
|
||||
hasDestructuring = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasDestructuring) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
let pattern = node.params[i];
|
||||
if (!t.isPattern(pattern)) continue;
|
||||
|
||||
var ref = node.params[i] = scope.generateUidIdentifier("ref");
|
||||
t.inherits(ref, pattern);
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
blockHoist: node.params.length - i,
|
||||
nodes: nodes,
|
||||
scope: scope,
|
||||
file: file,
|
||||
kind: "let"
|
||||
kind: left.kind,
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
|
||||
destructuring.init(pattern, ref);
|
||||
}
|
||||
destructuring.init(pattern, key);
|
||||
|
||||
t.ensureBlock(node);
|
||||
this.ensureBlock();
|
||||
|
||||
var block = node.body;
|
||||
block.body = nodes.concat(block.body);
|
||||
}
|
||||
var block = node.body;
|
||||
block.body = nodes.concat(block.body);
|
||||
},
|
||||
|
||||
export function CatchClause(node, parent, scope, file) {
|
||||
var pattern = node.param;
|
||||
if (!t.isPattern(pattern)) return;
|
||||
|
||||
var ref = scope.generateUidIdentifier("ref");
|
||||
node.param = ref;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
kind: "let",
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
destructuring.init(pattern, ref);
|
||||
|
||||
node.body.body = nodes.concat(node.body.body);
|
||||
}
|
||||
|
||||
export function AssignmentExpression(node, parent, scope, file) {
|
||||
if (!t.isPattern(node.left)) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
operator: node.operator,
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
|
||||
var ref;
|
||||
if (this.isCompletionRecord() || !this.parentPath.isExpressionStatement()) {
|
||||
ref = scope.generateUidIdentifierBasedOnNode(node.right, "ref");
|
||||
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(ref, node.right)
|
||||
]));
|
||||
|
||||
if (t.isArrayExpression(node.right)) {
|
||||
destructuring.arrays[ref.name] = true;
|
||||
Function(node, parent, scope, file) {
|
||||
var hasDestructuring = false;
|
||||
for (let pattern of (node.params: Array)) {
|
||||
if (t.isPattern(pattern)) {
|
||||
hasDestructuring = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasDestructuring) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
let pattern = node.params[i];
|
||||
if (!t.isPattern(pattern)) continue;
|
||||
|
||||
var ref = scope.generateUidIdentifier("ref");
|
||||
if (t.isAssignmentPattern(pattern)) {
|
||||
var _pattern = pattern;
|
||||
pattern = pattern.left;
|
||||
_pattern.left = ref;
|
||||
} else {
|
||||
node.params[i] = ref;
|
||||
}
|
||||
|
||||
t.inherits(ref, pattern);
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
blockHoist: node.params.length - i,
|
||||
nodes: nodes,
|
||||
scope: scope,
|
||||
file: file,
|
||||
kind: "let"
|
||||
});
|
||||
|
||||
destructuring.init(pattern, ref);
|
||||
}
|
||||
|
||||
this.ensureBlock();
|
||||
|
||||
var block = node.body;
|
||||
block.body = nodes.concat(block.body);
|
||||
},
|
||||
|
||||
CatchClause(node, parent, scope, file) {
|
||||
var pattern = node.param;
|
||||
if (!t.isPattern(pattern)) return;
|
||||
|
||||
var ref = scope.generateUidIdentifier("ref");
|
||||
node.param = ref;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
kind: "let",
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
destructuring.init(pattern, ref);
|
||||
|
||||
node.body.body = nodes.concat(node.body.body);
|
||||
},
|
||||
|
||||
AssignmentExpression(node, parent, scope, file) {
|
||||
if (!t.isPattern(node.left)) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
operator: node.operator,
|
||||
file: file,
|
||||
scope: scope,
|
||||
nodes: nodes
|
||||
});
|
||||
|
||||
var ref;
|
||||
if (this.isCompletionRecord() || !this.parentPath.isExpressionStatement()) {
|
||||
ref = scope.generateUidIdentifierBasedOnNode(node.right, "ref");
|
||||
|
||||
nodes.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(ref, node.right)
|
||||
]));
|
||||
|
||||
if (t.isArrayExpression(node.right)) {
|
||||
destructuring.arrays[ref.name] = true;
|
||||
}
|
||||
}
|
||||
|
||||
destructuring.init(node.left, ref || node.right);
|
||||
|
||||
if (ref) {
|
||||
nodes.push(t.expressionStatement(ref));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
},
|
||||
|
||||
VariableDeclaration(node, parent, scope, file) {
|
||||
if (t.isForXStatement(parent)) return;
|
||||
if (!variableDeclarationHasPattern(node)) return;
|
||||
|
||||
var nodes = [];
|
||||
var declar;
|
||||
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
declar = node.declarations[i];
|
||||
|
||||
var patternId = declar.init;
|
||||
var pattern = declar.id;
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
nodes: nodes,
|
||||
scope: scope,
|
||||
kind: node.kind,
|
||||
file: file
|
||||
});
|
||||
|
||||
if (t.isPattern(pattern)) {
|
||||
destructuring.init(pattern, patternId);
|
||||
|
||||
if (+i !== node.declarations.length - 1) {
|
||||
// we aren't the last declarator so let's just make the
|
||||
// last transformed node inherit from us
|
||||
t.inherits(nodes[nodes.length - 1], declar);
|
||||
}
|
||||
} else {
|
||||
nodes.push(t.inherits(destructuring.buildVariableAssignment(declar.id, declar.init), declar));
|
||||
}
|
||||
}
|
||||
|
||||
if (!t.isProgram(parent) && !t.isBlockStatement(parent)) {
|
||||
// https://github.com/babel/babel/issues/113
|
||||
// for (let [x] = [0]; false;) {}
|
||||
|
||||
declar = null;
|
||||
|
||||
for (i = 0; i < nodes.length; i++) {
|
||||
node = nodes[i];
|
||||
declar = declar || t.variableDeclaration(node.kind, []);
|
||||
|
||||
if (!t.isVariableDeclaration(node) && declar.kind !== node.kind) {
|
||||
throw file.errorWithNode(node, messages.get("invalidParentForThisNode"));
|
||||
}
|
||||
|
||||
declar.declarations = declar.declarations.concat(node.declarations);
|
||||
}
|
||||
|
||||
return declar;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
destructuring.init(node.left, ref || node.right);
|
||||
|
||||
if (ref) {
|
||||
nodes.push(t.expressionStatement(ref));
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
};
|
||||
|
||||
function variableDeclarationHasPattern(node) {
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
@@ -154,62 +218,6 @@ function variableDeclarationHasPattern(node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
export function VariableDeclaration(node, parent, scope, file) {
|
||||
if (t.isForXStatement(parent)) return;
|
||||
if (!variableDeclarationHasPattern(node)) return;
|
||||
|
||||
var nodes = [];
|
||||
var declar;
|
||||
|
||||
for (var i = 0; i < node.declarations.length; i++) {
|
||||
declar = node.declarations[i];
|
||||
|
||||
var patternId = declar.init;
|
||||
var pattern = declar.id;
|
||||
|
||||
var destructuring = new DestructuringTransformer({
|
||||
nodes: nodes,
|
||||
scope: scope,
|
||||
kind: node.kind,
|
||||
file: file
|
||||
});
|
||||
|
||||
if (t.isPattern(pattern)) {
|
||||
destructuring.init(pattern, patternId);
|
||||
|
||||
if (+i !== node.declarations.length - 1) {
|
||||
// we aren't the last declarator so let's just make the
|
||||
// last transformed node inherit from us
|
||||
t.inherits(nodes[nodes.length - 1], declar);
|
||||
}
|
||||
} else {
|
||||
nodes.push(t.inherits(destructuring.buildVariableAssignment(declar.id, declar.init), declar));
|
||||
}
|
||||
}
|
||||
|
||||
if (!t.isProgram(parent) && !t.isBlockStatement(parent)) {
|
||||
// https://github.com/babel/babel/issues/113
|
||||
// for (let [x] = [0]; false;) {}
|
||||
|
||||
declar = null;
|
||||
|
||||
for (i = 0; i < nodes.length; i++) {
|
||||
node = nodes[i];
|
||||
declar = declar || t.variableDeclaration(node.kind, []);
|
||||
|
||||
if (!t.isVariableDeclaration(node) && declar.kind !== node.kind) {
|
||||
throw file.errorWithNode(node, messages.get("invalidParentForThisNode"));
|
||||
}
|
||||
|
||||
declar.declarations = declar.declarations.concat(node.declarations);
|
||||
}
|
||||
|
||||
return declar;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
function hasRest(pattern) {
|
||||
for (var i = 0; i < pattern.elements.length; i++) {
|
||||
if (t.isRestElement(pattern.elements[i])) {
|
||||
|
||||
@@ -2,40 +2,42 @@ import * as messages from "../../../messages";
|
||||
import * as util from "../../../util";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export function ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isArrayExpression()) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
export var visitor = {
|
||||
ForOfStatement(node, parent, scope, file) {
|
||||
if (this.get("right").isArrayExpression()) {
|
||||
return _ForOfStatementArray.call(this, node, scope, file);
|
||||
}
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.forOf")) callback = loose;
|
||||
|
||||
var build = callback(node, parent, scope, file);
|
||||
var declar = build.declar;
|
||||
var loop = build.loop;
|
||||
var block = loop.body;
|
||||
|
||||
// ensure that it's a block so we can take all its statements
|
||||
this.ensureBlock();
|
||||
|
||||
// add the value declaration to the new loop body
|
||||
if (declar) {
|
||||
block.body.push(declar);
|
||||
}
|
||||
|
||||
// push the rest of the original loop body onto our new body
|
||||
block.body = block.body.concat(node.body.body);
|
||||
|
||||
t.inherits(loop, node);
|
||||
t.inherits(loop.body, node.body);
|
||||
|
||||
if (build.replaceParent) {
|
||||
this.parentPath.replaceWithMultiple(build.node);
|
||||
this.dangerouslyRemove();
|
||||
} else {
|
||||
return build.node;
|
||||
}
|
||||
}
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.forOf")) callback = loose;
|
||||
|
||||
var build = callback(node, parent, scope, file);
|
||||
var declar = build.declar;
|
||||
var loop = build.loop;
|
||||
var block = loop.body;
|
||||
|
||||
// ensure that it's a block so we can take all its statements
|
||||
t.ensureBlock(node);
|
||||
|
||||
// add the value declaration to the new loop body
|
||||
if (declar) {
|
||||
block.body.push(declar);
|
||||
}
|
||||
|
||||
// push the rest of the original loop body onto our new body
|
||||
block.body = block.body.concat(node.body.body);
|
||||
|
||||
t.inherits(loop, node);
|
||||
t.inherits(loop.body, node.body);
|
||||
|
||||
if (build.replaceParent) {
|
||||
this.parentPath.replaceWithMultiple(build.node);
|
||||
this.dangerouslyRemove();
|
||||
} else {
|
||||
return build.node;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export function _ForOfStatementArray(node, scope, file) {
|
||||
var nodes = [];
|
||||
|
||||
@@ -12,64 +12,66 @@ export var metadata = {
|
||||
group: "builtin-modules"
|
||||
};
|
||||
|
||||
export function ImportDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (node.isType) return;
|
||||
export var visitor = {
|
||||
ImportDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (node.isType) return;
|
||||
|
||||
var nodes = [];
|
||||
var nodes = [];
|
||||
|
||||
if (node.specifiers.length) {
|
||||
for (var specifier of (node.specifiers: Array)) {
|
||||
file.moduleFormatter.importSpecifier(specifier, node, nodes, parent);
|
||||
}
|
||||
} else {
|
||||
file.moduleFormatter.importDeclaration(node, nodes, parent);
|
||||
}
|
||||
|
||||
if (nodes.length === 1) {
|
||||
// inherit `_blockHoist` - this is for `_blockHoist` in File.prototype.addImport
|
||||
nodes[0]._blockHoist = node._blockHoist;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function ExportAllDeclaration(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
file.moduleFormatter.exportAllDeclaration(node, nodes, parent);
|
||||
keepBlockHoist(node, nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function ExportDefaultDeclaration(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
file.moduleFormatter.exportDeclaration(node, nodes, parent);
|
||||
keepBlockHoist(node, nodes);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function ExportNamedDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (this.get("declaration").isTypeAlias()) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
if (node.declaration) {
|
||||
// make sure variable exports have an initializer
|
||||
// this is done here to avoid duplicating it in the module formatters
|
||||
if (t.isVariableDeclaration(node.declaration)) {
|
||||
var declar = node.declaration.declarations[0];
|
||||
declar.init = declar.init || t.identifier("undefined");
|
||||
if (node.specifiers.length) {
|
||||
for (var specifier of (node.specifiers: Array)) {
|
||||
file.moduleFormatter.importSpecifier(specifier, node, nodes, scope);
|
||||
}
|
||||
} else {
|
||||
file.moduleFormatter.importDeclaration(node, nodes, scope);
|
||||
}
|
||||
|
||||
file.moduleFormatter.exportDeclaration(node, nodes, parent);
|
||||
} else if (node.specifiers) {
|
||||
for (let i = 0; i < node.specifiers.length; i++) {
|
||||
file.moduleFormatter.exportSpecifier(node.specifiers[i], node, nodes, parent);
|
||||
if (nodes.length === 1) {
|
||||
// inherit `_blockHoist` - this is for `_blockHoist` in File.prototype.addImport
|
||||
nodes[0]._blockHoist = node._blockHoist;
|
||||
}
|
||||
|
||||
return nodes;
|
||||
},
|
||||
|
||||
ExportAllDeclaration(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
file.moduleFormatter.exportAllDeclaration(node, nodes, scope);
|
||||
keepBlockHoist(node, nodes);
|
||||
return nodes;
|
||||
},
|
||||
|
||||
ExportDefaultDeclaration(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
file.moduleFormatter.exportDeclaration(node, nodes, scope);
|
||||
keepBlockHoist(node, nodes);
|
||||
return nodes;
|
||||
},
|
||||
|
||||
ExportNamedDeclaration(node, parent, scope, file) {
|
||||
// flow type
|
||||
if (this.get("declaration").isTypeAlias()) return;
|
||||
|
||||
var nodes = [];
|
||||
|
||||
if (node.declaration) {
|
||||
// make sure variable exports have an initializer
|
||||
// this is done here to avoid duplicating it in the module formatters
|
||||
if (t.isVariableDeclaration(node.declaration)) {
|
||||
var declar = node.declaration.declarations[0];
|
||||
declar.init = declar.init || t.identifier("undefined");
|
||||
}
|
||||
|
||||
file.moduleFormatter.exportDeclaration(node, nodes, scope);
|
||||
} else if (node.specifiers) {
|
||||
for (let i = 0; i < node.specifiers.length; i++) {
|
||||
file.moduleFormatter.exportSpecifier(node.specifiers[i], node, nodes, scope);
|
||||
}
|
||||
}
|
||||
|
||||
keepBlockHoist(node, nodes);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
keepBlockHoist(node, nodes);
|
||||
|
||||
return nodes;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,17 +17,19 @@ function Property(path, node, scope, getObjectRef, file) {
|
||||
replaceSupers.replace();
|
||||
}
|
||||
|
||||
export function ObjectExpression(node, parent, scope, file) {
|
||||
var objectRef;
|
||||
var getObjectRef = () => objectRef = objectRef || scope.generateUidIdentifier("obj");
|
||||
export var visitor = {
|
||||
ObjectExpression(node, parent, scope, file) {
|
||||
var objectRef;
|
||||
var getObjectRef = () => objectRef = objectRef || scope.generateUidIdentifier("obj");
|
||||
|
||||
var propPaths = this.get("properties");
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
Property(propPaths[i], node.properties[i], scope, getObjectRef, file);
|
||||
}
|
||||
var propPaths = this.get("properties");
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
Property(propPaths[i], node.properties[i], scope, getObjectRef, file);
|
||||
}
|
||||
|
||||
if (objectRef) {
|
||||
scope.push({ id: objectRef });
|
||||
return t.assignmentExpression("=", objectRef, node);
|
||||
if (objectRef) {
|
||||
scope.push({ id: objectRef });
|
||||
return t.assignmentExpression("=", objectRef, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
import callDelegate from "../../helpers/call-delegate";
|
||||
import getFunctionArity from "../../helpers/get-function-arity";
|
||||
import * as util from "../../../util";
|
||||
import * as t from "../../../types";
|
||||
|
||||
var hasDefaults = function (node) {
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
if (!t.isIdentifier(node.params[i])) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var iifeVisitor = {
|
||||
ReferencedIdentifier(node, parent, scope, state) {
|
||||
if (node.name !== "eval") {
|
||||
if (!state.scope.hasOwnBinding(node.name)) return;
|
||||
if (state.scope.bindingIdentifierEquals(node.name, node)) return;
|
||||
}
|
||||
|
||||
state.iife = true;
|
||||
this.stop();
|
||||
}
|
||||
};
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
if (!hasDefaults(node)) return;
|
||||
|
||||
// ensure it's a block, useful for arrow functions
|
||||
t.ensureBlock(node);
|
||||
|
||||
var state = {
|
||||
iife: false,
|
||||
scope: scope
|
||||
};
|
||||
|
||||
var body = [];
|
||||
|
||||
//
|
||||
var argsIdentifier = t.identifier("arguments");
|
||||
argsIdentifier._shadowedFunctionLiteral = true;
|
||||
|
||||
// push a default parameter definition
|
||||
function pushDefNode(left, right, i) {
|
||||
var defNode;
|
||||
if (exceedsLastNonDefault(i) || t.isPattern(left) || file.transformers["es6.spec.blockScoping"].canTransform()) {
|
||||
defNode = util.template("default-parameter", {
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right,
|
||||
ARGUMENT_KEY: t.literal(i),
|
||||
ARGUMENTS: argsIdentifier
|
||||
}, true);
|
||||
} else {
|
||||
defNode = util.template("default-parameter-assign", {
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right
|
||||
}, true);
|
||||
}
|
||||
defNode._blockHoist = node.params.length - i;
|
||||
body.push(defNode);
|
||||
}
|
||||
|
||||
// check if an index exceeds the functions arity
|
||||
function exceedsLastNonDefault(i) {
|
||||
return i + 1 > lastNonDefaultParam;
|
||||
}
|
||||
|
||||
//
|
||||
var lastNonDefaultParam = getFunctionArity(node);
|
||||
|
||||
//
|
||||
var params = this.get("params");
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var param = params[i];
|
||||
|
||||
if (!param.isAssignmentPattern()) {
|
||||
if (!param.isIdentifier()) {
|
||||
param.traverse(iifeVisitor, state);
|
||||
}
|
||||
|
||||
if (file.transformers["es6.spec.blockScoping"].canTransform() && param.isIdentifier()) {
|
||||
pushDefNode(param.node, t.identifier("undefined"), i);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var left = param.get("left");
|
||||
var right = param.get("right");
|
||||
|
||||
if (exceedsLastNonDefault(i) || left.isPattern()) {
|
||||
var placeholder = scope.generateUidIdentifier("x");
|
||||
placeholder._isDefaultPlaceholder = true;
|
||||
node.params[i] = placeholder;
|
||||
} else {
|
||||
node.params[i] = left.node;
|
||||
}
|
||||
|
||||
if (!state.iife) {
|
||||
if (right.isIdentifier() && scope.hasOwnBinding(right.node.name)) {
|
||||
state.iife = true;
|
||||
} else {
|
||||
right.traverse(iifeVisitor, state);
|
||||
}
|
||||
}
|
||||
|
||||
pushDefNode(left.node, right.node, i);
|
||||
}
|
||||
|
||||
// we need to cut off all trailing default parameters
|
||||
node.params = node.params.slice(0, lastNonDefaultParam);
|
||||
|
||||
if (state.iife) {
|
||||
body.push(callDelegate(node, scope));
|
||||
node.body = t.blockStatement(body);
|
||||
} else {
|
||||
node.body.body = body.concat(node.body.body);
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
import * as util from "../../../util";
|
||||
import * as t from "../../../types";
|
||||
|
||||
var memberExpressionOptimisationVisitor = {
|
||||
Scope(node, parent, scope, state) {
|
||||
// check if this scope has a local binding that will shadow the rest parameter
|
||||
if (!scope.bindingIdentifierEquals(state.name, state.outerBinding)) {
|
||||
this.skip();
|
||||
}
|
||||
},
|
||||
|
||||
enter(node, parent, scope, state) {
|
||||
var stop = () => {
|
||||
state.canOptimise = false;
|
||||
this.stop();
|
||||
};
|
||||
|
||||
if (this.isArrowFunctionExpression()) return stop();
|
||||
|
||||
// skip over functions as whatever `arguments` we reference inside will refer
|
||||
// to the wrong function
|
||||
if (this.isFunctionDeclaration() || this.isFunctionExpression()) {
|
||||
state.noOptimise = true;
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
state.noOptimise = false;
|
||||
return this.skip();
|
||||
}
|
||||
|
||||
// is this a referenced identifier and is it referencing the rest parameter?
|
||||
if (!this.isReferencedIdentifier({ name: state.name })) return;
|
||||
|
||||
if (!state.noOptimise && t.isMemberExpression(parent) && parent.computed) {
|
||||
// if we know that this member expression is referencing a number then we can safely
|
||||
// optimise it
|
||||
var prop = this.parentPath.get("property");
|
||||
if (prop.isGenericType("Number")) {
|
||||
state.candidates.push(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
stop();
|
||||
}
|
||||
};
|
||||
|
||||
function optimizeMemberExpression(parent, offset) {
|
||||
if (offset === 0) return;
|
||||
|
||||
var newExpr;
|
||||
var prop = parent.property;
|
||||
|
||||
if (t.isLiteral(prop)) {
|
||||
prop.value += offset;
|
||||
prop.raw = String(prop.value);
|
||||
} else { // // UnaryExpression, BinaryExpression
|
||||
newExpr = t.binaryExpression("+", prop, t.literal(offset));
|
||||
parent.property = newExpr;
|
||||
}
|
||||
}
|
||||
|
||||
var hasRest = function (node) {
|
||||
return t.isRestElement(node.params[node.params.length - 1]);
|
||||
};
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
if (!hasRest(node)) return;
|
||||
|
||||
var restParam = node.params.pop();
|
||||
var rest = restParam.argument;
|
||||
|
||||
var argsId = t.identifier("arguments");
|
||||
|
||||
// otherwise `arguments` will be remapped in arrow functions
|
||||
argsId._shadowedFunctionLiteral = true;
|
||||
|
||||
// support patterns
|
||||
if (t.isPattern(rest)) {
|
||||
var pattern = rest;
|
||||
rest = scope.generateUidIdentifier("ref");
|
||||
|
||||
var declar = t.variableDeclaration("let", pattern.elements.map(function (elem, index) {
|
||||
var accessExpr = t.memberExpression(rest, t.literal(index), true);
|
||||
return t.variableDeclarator(elem, accessExpr);
|
||||
}));
|
||||
node.body.body.unshift(declar);
|
||||
}
|
||||
|
||||
// check if rest is used in member expressions and optimise for those cases
|
||||
|
||||
var state = {
|
||||
outerBinding: scope.getBindingIdentifier(rest.name),
|
||||
canOptimise: true,
|
||||
candidates: [],
|
||||
method: node,
|
||||
name: rest.name
|
||||
};
|
||||
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
|
||||
// we only have shorthands and there's no other references
|
||||
if (state.canOptimise && state.candidates.length) {
|
||||
for (var candidate of (state.candidates: Array)) {
|
||||
candidate.replaceWith(argsId);
|
||||
optimizeMemberExpression(candidate.parent, node.params.length);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
var start = t.literal(node.params.length);
|
||||
var key = scope.generateUidIdentifier("key");
|
||||
var len = scope.generateUidIdentifier("len");
|
||||
|
||||
var arrKey = key;
|
||||
var arrLen = len;
|
||||
if (node.params.length) {
|
||||
// this method has additional params, so we need to subtract
|
||||
// the index of the current argument position from the
|
||||
// position in the array that we want to populate
|
||||
arrKey = t.binaryExpression("-", key, start);
|
||||
|
||||
// we need to work out the size of the array that we're
|
||||
// going to store all the rest parameters
|
||||
//
|
||||
// we need to add a check to avoid constructing the array
|
||||
// with <0 if there are less arguments than params as it'll
|
||||
// cause an error
|
||||
arrLen = t.conditionalExpression(
|
||||
t.binaryExpression(">", len, start),
|
||||
t.binaryExpression("-", len, start),
|
||||
t.literal(0)
|
||||
);
|
||||
}
|
||||
|
||||
var loop = util.template("rest", {
|
||||
ARRAY_TYPE: restParam.typeAnnotation,
|
||||
ARGUMENTS: argsId,
|
||||
ARRAY_KEY: arrKey,
|
||||
ARRAY_LEN: arrLen,
|
||||
START: start,
|
||||
ARRAY: rest,
|
||||
KEY: key,
|
||||
LEN: len
|
||||
});
|
||||
loop._blockHoist = node.params.length + 1;
|
||||
node.body.body.unshift(loop);
|
||||
}
|
||||
120
src/babel/transformation/transformers/es6/parameters/default.js
Normal file
120
src/babel/transformation/transformers/es6/parameters/default.js
Normal file
@@ -0,0 +1,120 @@
|
||||
import callDelegate from "../../../helpers/call-delegate";
|
||||
import getFunctionArity from "../../../helpers/get-function-arity";
|
||||
import * as util from "../../../../util";
|
||||
import * as t from "../../../../types";
|
||||
|
||||
var hasDefaults = function (node) {
|
||||
for (var i = 0; i < node.params.length; i++) {
|
||||
if (!t.isIdentifier(node.params[i])) return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var iifeVisitor = {
|
||||
ReferencedIdentifier(node, parent, scope, state) {
|
||||
if (node.name !== "eval") {
|
||||
if (!state.scope.hasOwnBinding(node.name)) return;
|
||||
if (state.scope.bindingIdentifierEquals(node.name, node)) return;
|
||||
}
|
||||
|
||||
state.iife = true;
|
||||
this.stop();
|
||||
}
|
||||
};
|
||||
|
||||
export var visitor = {
|
||||
Function(node, parent, scope, file) {
|
||||
if (!hasDefaults(node)) return;
|
||||
|
||||
// ensure it's a block, useful for arrow functions
|
||||
this.ensureBlock();
|
||||
|
||||
var state = {
|
||||
iife: false,
|
||||
scope: scope
|
||||
};
|
||||
|
||||
var body = [];
|
||||
|
||||
//
|
||||
var argsIdentifier = t.identifier("arguments");
|
||||
argsIdentifier._shadowedFunctionLiteral = this;
|
||||
|
||||
// push a default parameter definition
|
||||
function pushDefNode(left, right, i) {
|
||||
var defNode;
|
||||
if (exceedsLastNonDefault(i) || t.isPattern(left) || file.transformers["es6.spec.blockScoping"].canTransform()) {
|
||||
defNode = util.template("default-parameter", {
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right,
|
||||
ARGUMENT_KEY: t.literal(i),
|
||||
ARGUMENTS: argsIdentifier
|
||||
}, true);
|
||||
} else {
|
||||
defNode = util.template("default-parameter-assign", {
|
||||
VARIABLE_NAME: left,
|
||||
DEFAULT_VALUE: right
|
||||
}, true);
|
||||
}
|
||||
defNode._blockHoist = node.params.length - i;
|
||||
body.push(defNode);
|
||||
}
|
||||
|
||||
// check if an index exceeds the functions arity
|
||||
function exceedsLastNonDefault(i) {
|
||||
return i + 1 > lastNonDefaultParam;
|
||||
}
|
||||
|
||||
//
|
||||
var lastNonDefaultParam = getFunctionArity(node);
|
||||
|
||||
//
|
||||
var params = this.get("params");
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var param = params[i];
|
||||
|
||||
if (!param.isAssignmentPattern()) {
|
||||
if (!param.isIdentifier()) {
|
||||
param.traverse(iifeVisitor, state);
|
||||
}
|
||||
|
||||
if (file.transformers["es6.spec.blockScoping"].canTransform() && param.isIdentifier()) {
|
||||
pushDefNode(param.node, t.identifier("undefined"), i);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
var left = param.get("left");
|
||||
var right = param.get("right");
|
||||
|
||||
if (exceedsLastNonDefault(i) || left.isPattern()) {
|
||||
var placeholder = scope.generateUidIdentifier("x");
|
||||
placeholder._isDefaultPlaceholder = true;
|
||||
node.params[i] = placeholder;
|
||||
} else {
|
||||
node.params[i] = left.node;
|
||||
}
|
||||
|
||||
if (!state.iife) {
|
||||
if (right.isIdentifier() && scope.hasOwnBinding(right.node.name)) {
|
||||
state.iife = true;
|
||||
} else {
|
||||
right.traverse(iifeVisitor, state);
|
||||
}
|
||||
}
|
||||
|
||||
pushDefNode(left.node, right.node, i);
|
||||
}
|
||||
|
||||
// we need to cut off all trailing default parameters
|
||||
node.params = node.params.slice(0, lastNonDefaultParam);
|
||||
|
||||
if (state.iife) {
|
||||
body.push(callDelegate(node, scope));
|
||||
node.body = t.blockStatement(body);
|
||||
} else {
|
||||
node.body.body = body.concat(node.body.body);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
import * as visitors from "../../../../traversal/visitors";
|
||||
|
||||
import * as def from "./default";
|
||||
import * as rest from "./rest";
|
||||
|
||||
export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
export var visitor = visitors.merge([rest.visitor, def.visitor]);
|
||||
186
src/babel/transformation/transformers/es6/parameters/rest.js
Normal file
186
src/babel/transformation/transformers/es6/parameters/rest.js
Normal file
@@ -0,0 +1,186 @@
|
||||
import * as util from "../../../../util";
|
||||
import * as t from "../../../../types";
|
||||
|
||||
var memberExpressionOptimisationVisitor = {
|
||||
Scope(node, parent, scope, state) {
|
||||
// check if this scope has a local binding that will shadow the rest parameter
|
||||
if (!scope.bindingIdentifierEquals(state.name, state.outerBinding)) {
|
||||
this.skip();
|
||||
}
|
||||
},
|
||||
|
||||
Function(node, parent, scope, state) {
|
||||
// skip over functions as whatever `arguments` we reference inside will refer
|
||||
// to the wrong function
|
||||
var oldNoOptimise = state.noOptimise;
|
||||
state.noOptimise = true;
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
state.noOptimise = oldNoOptimise;
|
||||
this.skip();
|
||||
},
|
||||
|
||||
ReferencedIdentifier(node, parent, scope, state) {
|
||||
// we can't guarantee the purity of arguments
|
||||
if (node.name === "arguments") {
|
||||
state.deopted = true;
|
||||
}
|
||||
|
||||
// is this a referenced identifier and is it referencing the rest parameter?
|
||||
if (node.name !== state.name) return;
|
||||
|
||||
if (state.noOptimise) {
|
||||
state.deopted = true;
|
||||
} else {
|
||||
if (this.parentPath.isMemberExpression({ computed: true, object: node })) {
|
||||
// if we know that this member expression is referencing a number then we can safely
|
||||
// optimise it
|
||||
var prop = this.parentPath.get("property");
|
||||
if (prop.isBaseType("number")) {
|
||||
state.candidates.push(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// optimise single spread args in calls
|
||||
if (this.parentPath.isSpreadElement() && state.offset === 0) {
|
||||
var call = this.parentPath.parentPath;
|
||||
if (call.isCallExpression() && call.node.arguments.length === 1) {
|
||||
state.candidates.push(this);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
state.references.push(this);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function optimiseMemberExpression(parent, offset) {
|
||||
if (offset === 0) return;
|
||||
|
||||
var newExpr;
|
||||
var prop = parent.property;
|
||||
|
||||
if (t.isLiteral(prop)) {
|
||||
prop.value += offset;
|
||||
prop.raw = String(prop.value);
|
||||
} else { // // UnaryExpression, BinaryExpression
|
||||
newExpr = t.binaryExpression("+", prop, t.literal(offset));
|
||||
parent.property = newExpr;
|
||||
}
|
||||
}
|
||||
|
||||
function hasRest(node) {
|
||||
return t.isRestElement(node.params[node.params.length - 1]);
|
||||
}
|
||||
|
||||
export var visitor = {
|
||||
Function(node, parent, scope) {
|
||||
if (!hasRest(node)) return;
|
||||
|
||||
var restParam = node.params.pop();
|
||||
var rest = restParam.argument;
|
||||
|
||||
var argsId = t.identifier("arguments");
|
||||
|
||||
// otherwise `arguments` will be remapped in arrow functions
|
||||
argsId._shadowedFunctionLiteral = this;
|
||||
|
||||
// support patterns
|
||||
if (t.isPattern(rest)) {
|
||||
var pattern = rest;
|
||||
rest = scope.generateUidIdentifier("ref");
|
||||
|
||||
var declar = t.variableDeclaration("let", pattern.elements.map(function (elem, index) {
|
||||
var accessExpr = t.memberExpression(rest, t.literal(index), true);
|
||||
return t.variableDeclarator(elem, accessExpr);
|
||||
}));
|
||||
node.body.body.unshift(declar);
|
||||
}
|
||||
|
||||
// check and optimise for extremely common cases
|
||||
var state = {
|
||||
references: [],
|
||||
offset: node.params.length,
|
||||
|
||||
argumentsNode: argsId,
|
||||
outerBinding: scope.getBindingIdentifier(rest.name),
|
||||
|
||||
// candidate member expressions we could optimise if there are no other references
|
||||
candidates: [],
|
||||
|
||||
// local rest binding name
|
||||
name: rest.name,
|
||||
|
||||
// whether any references to the rest parameter were made in a function
|
||||
deopted: false
|
||||
};
|
||||
|
||||
this.traverse(memberExpressionOptimisationVisitor, state);
|
||||
|
||||
if (!state.deopted && !state.references.length) {
|
||||
// we only have shorthands and there are no other references
|
||||
if (state.candidates.length) {
|
||||
for (var candidate of (state.candidates: Array)) {
|
||||
candidate.replaceWith(argsId);
|
||||
if (candidate.parentPath.isMemberExpression()) {
|
||||
optimiseMemberExpression(candidate.parent, state.offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
state.references = state.references.concat(state.candidates);
|
||||
}
|
||||
|
||||
// deopt shadowed functions as transforms like regenerator may try touch the allocation loop
|
||||
state.deopted = state.deopted || !!node.shadow;
|
||||
|
||||
//
|
||||
|
||||
var start = t.literal(node.params.length);
|
||||
var key = scope.generateUidIdentifier("key");
|
||||
var len = scope.generateUidIdentifier("len");
|
||||
|
||||
var arrKey = key;
|
||||
var arrLen = len;
|
||||
if (node.params.length) {
|
||||
// this method has additional params, so we need to subtract
|
||||
// the index of the current argument position from the
|
||||
// position in the array that we want to populate
|
||||
arrKey = t.binaryExpression("-", key, start);
|
||||
|
||||
// we need to work out the size of the array that we're
|
||||
// going to store all the rest parameters
|
||||
//
|
||||
// we need to add a check to avoid constructing the array
|
||||
// with <0 if there are less arguments than params as it'll
|
||||
// cause an error
|
||||
arrLen = t.conditionalExpression(
|
||||
t.binaryExpression(">", len, start),
|
||||
t.binaryExpression("-", len, start),
|
||||
t.literal(0)
|
||||
);
|
||||
}
|
||||
|
||||
var loop = util.template("rest", {
|
||||
ARRAY_TYPE: restParam.typeAnnotation,
|
||||
ARGUMENTS: argsId,
|
||||
ARRAY_KEY: arrKey,
|
||||
ARRAY_LEN: arrLen,
|
||||
START: start,
|
||||
ARRAY: rest,
|
||||
KEY: key,
|
||||
LEN: len
|
||||
});
|
||||
|
||||
if (state.deopted) {
|
||||
loop._blockHoist = node.params.length + 1;
|
||||
node.body.body.unshift(loop);
|
||||
} else {
|
||||
// perform allocation at the lowest common denominator of all references
|
||||
loop._blockHoist = 1;
|
||||
this.getEarliestCommonAncestorFrom(state.references).getStatementParent().insertBefore(loop);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,9 +1,7 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
function loose(node, body, objId) {
|
||||
for (var i = 0; i < node.properties.length; i++) {
|
||||
var prop = node.properties[i];
|
||||
|
||||
for (var prop of (node.properties: Array)) {
|
||||
body.push(t.expressionStatement(
|
||||
t.assignmentExpression(
|
||||
"=",
|
||||
@@ -15,31 +13,15 @@ function loose(node, body, objId) {
|
||||
}
|
||||
|
||||
function spec(node, body, objId, initProps, file) {
|
||||
var props = node.properties;
|
||||
|
||||
// add all non-computed properties and `__proto__` properties to the initializer
|
||||
|
||||
var broken = false;
|
||||
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
let prop = props[i];
|
||||
|
||||
if (prop.computed) {
|
||||
broken = true;
|
||||
}
|
||||
|
||||
if (prop.kind !== "init" || !broken || t.isLiteral(t.toComputedKey(prop, prop.key), { value: "__proto__" })) {
|
||||
initProps.push(prop);
|
||||
props[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// add a simple assignment for all Symbol member expressions due to symbol polyfill limitations
|
||||
// otherwise use Object.defineProperty
|
||||
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
let prop = props[i];
|
||||
if (!prop) continue;
|
||||
for (let prop of (node.properties: Array)) {
|
||||
// this wont work with Object.defineProperty
|
||||
if (t.isLiteral(t.toComputedKey(prop), { value: "__proto__" })) {
|
||||
initProps.push(prop);
|
||||
continue;
|
||||
}
|
||||
|
||||
let key = prop.key;
|
||||
if (t.isIdentifier(key) && !prop.computed) {
|
||||
@@ -63,40 +45,62 @@ function spec(node, body, objId, initProps, file) {
|
||||
}
|
||||
}
|
||||
|
||||
export var ObjectExpression = {
|
||||
exit(node, parent, scope, file) {
|
||||
var hasComputed = false;
|
||||
export var visitor = {
|
||||
ObjectExpression: {
|
||||
exit(node, parent, scope, file) {
|
||||
var hasComputed = false;
|
||||
|
||||
for (var prop of (node.properties: Array)) {
|
||||
hasComputed = t.isProperty(prop, { computed: true, kind: "init" });
|
||||
if (hasComputed) break;
|
||||
for (let prop of (node.properties: Array)) {
|
||||
hasComputed = t.isProperty(prop, { computed: true, kind: "init" });
|
||||
if (hasComputed) break;
|
||||
}
|
||||
|
||||
if (!hasComputed) return;
|
||||
|
||||
// put all getters/setters into the first object expression as well as all initialisers up
|
||||
// to the first computed property
|
||||
|
||||
var initProps = [];
|
||||
var stopInits = false;
|
||||
|
||||
node.properties = node.properties.filter(function (prop) {
|
||||
if (prop.computed) {
|
||||
stopInits = true;
|
||||
}
|
||||
|
||||
if (prop.kind !== "init" || !stopInits) {
|
||||
initProps.push(prop);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
var objId = scope.generateUidIdentifierBasedOnNode(parent);
|
||||
|
||||
//
|
||||
|
||||
var body = [];
|
||||
|
||||
//
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.properties.computed")) callback = loose;
|
||||
|
||||
var result = callback(node, body, objId, initProps, file);
|
||||
if (result) return result;
|
||||
|
||||
//
|
||||
|
||||
body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(objId, t.objectExpression(initProps))
|
||||
]));
|
||||
|
||||
body.push(t.expressionStatement(objId));
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
if (!hasComputed) return;
|
||||
|
||||
var initProps = [];
|
||||
var objId = scope.generateUidIdentifierBasedOnNode(parent);
|
||||
|
||||
//
|
||||
|
||||
var body = [];
|
||||
|
||||
//
|
||||
|
||||
var callback = spec;
|
||||
if (file.isLoose("es6.properties.computed")) callback = loose;
|
||||
|
||||
var result = callback(node, body, objId, initProps, file);
|
||||
if (result) return result;
|
||||
|
||||
//
|
||||
|
||||
body.unshift(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(objId, t.objectExpression(initProps))
|
||||
]));
|
||||
|
||||
body.push(t.expressionStatement(objId));
|
||||
|
||||
return body;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
export function Property(node) {
|
||||
if (node.method) {
|
||||
node.method = false;
|
||||
}
|
||||
export var visitor = {
|
||||
Property(node) {
|
||||
if (node.method) {
|
||||
node.method = false;
|
||||
}
|
||||
|
||||
if (node.shorthand) {
|
||||
node.shorthand = false;
|
||||
if (node.shorthand) {
|
||||
node.shorthand = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import * as regex from "../../helpers/regex";
|
||||
import * as t from "../../../types";
|
||||
|
||||
export function Literal(node) {
|
||||
if (!regex.is(node, "y")) return;
|
||||
return t.newExpression(t.identifier("RegExp"), [
|
||||
t.literal(node.regex.pattern),
|
||||
t.literal(node.regex.flags)
|
||||
]);
|
||||
}
|
||||
export var visitor = {
|
||||
Literal(node) {
|
||||
if (!regex.is(node, "y")) return;
|
||||
return t.newExpression(t.identifier("RegExp"), [
|
||||
t.literal(node.regex.pattern),
|
||||
t.literal(node.regex.flags)
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import rewritePattern from "regexpu/rewrite-pattern";
|
||||
import * as regex from "../../helpers/regex";
|
||||
|
||||
export function Literal(node) {
|
||||
if (!regex.is(node, "u")) return;
|
||||
node.regex.pattern = rewritePattern(node.regex.pattern, node.regex.flags);
|
||||
regex.pullFlag(node, "u");
|
||||
}
|
||||
export var visitor = {
|
||||
Literal(node) {
|
||||
if (!regex.is(node, "u")) return;
|
||||
node.regex.pattern = rewritePattern(node.regex.pattern, node.regex.flags);
|
||||
regex.pullFlag(node, "u");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ function references(node, scope, state) {
|
||||
return scope.getBindingIdentifier(node.name) === declared;
|
||||
}
|
||||
|
||||
var visitor = {
|
||||
var refVisitor = {
|
||||
ReferencedIdentifier(node, parent, scope, state) {
|
||||
if (t.isFor(parent) && parent.left === node) return;
|
||||
|
||||
@@ -62,16 +62,16 @@ export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
export var BlockStatement = {
|
||||
exit(node, parent, scope, file) {
|
||||
var letRefs = node._letReferences;
|
||||
if (!letRefs) return;
|
||||
export var visitor = {
|
||||
"Program|Loop|BlockStatement": {
|
||||
exit(node, parent, scope, file) {
|
||||
var letRefs = node._letReferences;
|
||||
if (!letRefs) return;
|
||||
|
||||
this.traverse(visitor, {
|
||||
letRefs: letRefs,
|
||||
file: file
|
||||
});
|
||||
this.traverse(refVisitor, {
|
||||
letRefs: letRefs,
|
||||
file: file
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export { BlockStatement as Program, BlockStatement as Loop };
|
||||
|
||||
@@ -4,34 +4,34 @@ export var metadata = {
|
||||
optional: true
|
||||
};
|
||||
|
||||
export function UnaryExpression(node, parent, scope, file) {
|
||||
if (node._ignoreSpecSymbols) return;
|
||||
export var visitor = {
|
||||
UnaryExpression(node, parent, scope, file) {
|
||||
if (node._ignoreSpecSymbols) return;
|
||||
|
||||
if (node.operator === "typeof") {
|
||||
var call = t.callExpression(file.addHelper("typeof"), [node.argument]);
|
||||
if (this.get("argument").isIdentifier()) {
|
||||
var undefLiteral = t.literal("undefined");
|
||||
var unary = t.unaryExpression("typeof", node.argument);
|
||||
unary._ignoreSpecSymbols = true;
|
||||
return t.conditionalExpression(
|
||||
t.binaryExpression("===", unary, undefLiteral),
|
||||
undefLiteral,
|
||||
call
|
||||
);
|
||||
} else {
|
||||
return call;
|
||||
if (node.operator === "typeof") {
|
||||
var call = t.callExpression(file.addHelper("typeof"), [node.argument]);
|
||||
if (this.get("argument").isIdentifier()) {
|
||||
var undefLiteral = t.literal("undefined");
|
||||
var unary = t.unaryExpression("typeof", node.argument);
|
||||
unary._ignoreSpecSymbols = true;
|
||||
return t.conditionalExpression(
|
||||
t.binaryExpression("===", unary, undefLiteral),
|
||||
undefLiteral,
|
||||
call
|
||||
);
|
||||
} else {
|
||||
return call;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
BinaryExpression(node, parent, scope, file) {
|
||||
if (node.operator === "instanceof") {
|
||||
return t.callExpression(file.addHelper("instanceof"), [node.left, node.right]);
|
||||
}
|
||||
},
|
||||
|
||||
"VariableDeclaration|FunctionDeclaration"(node) {
|
||||
if (node._generated) this.skip();
|
||||
}
|
||||
}
|
||||
|
||||
export function BinaryExpression(node, parent, scope, file) {
|
||||
if (node.operator === "instanceof") {
|
||||
return t.callExpression(file.addHelper("instanceof"), [node.left, node.right]);
|
||||
}
|
||||
}
|
||||
|
||||
export function VariableDeclaration(node) {
|
||||
if (node._generated) this.skip();
|
||||
}
|
||||
|
||||
export { VariableDeclaration as FunctionDeclaration };
|
||||
};
|
||||
|
||||
@@ -5,10 +5,12 @@ export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
export function TemplateLiteral(node, parent, scope, file) {
|
||||
if (t.isTaggedTemplateExpression(parent)) return;
|
||||
export var visitor = {
|
||||
TemplateLiteral(node, parent) {
|
||||
if (t.isTaggedTemplateExpression(parent)) return;
|
||||
|
||||
for (var i = 0; i < node.expressions.length; i++) {
|
||||
node.expressions[i] = t.callExpression(t.identifier("String"), [node.expressions[i]]);
|
||||
for (var i = 0; i < node.expressions.length; i++) {
|
||||
node.expressions[i] = t.callExpression(t.identifier("String"), [node.expressions[i]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as t from "../../../types";
|
||||
|
||||
function getSpreadLiteral(spread, scope) {
|
||||
if (scope.hub.file.isLoose("es6.spread")) {
|
||||
if (scope.hub.file.isLoose("es6.spread") && !t.isIdentifier(spread.argument, { name: "arguments" })) {
|
||||
return spread.argument;
|
||||
} else {
|
||||
return scope.toArray(spread.argument, true);
|
||||
@@ -43,76 +43,82 @@ function build(props, scope) {
|
||||
return nodes;
|
||||
}
|
||||
|
||||
export function ArrayExpression(node, parent, scope) {
|
||||
var elements = node.elements;
|
||||
if (!hasSpread(elements)) return;
|
||||
export var metadata = {
|
||||
group: "builtin-advanced"
|
||||
};
|
||||
|
||||
var nodes = build(elements, scope);
|
||||
var first = nodes.shift();
|
||||
export var visitor = {
|
||||
ArrayExpression(node, parent, scope) {
|
||||
var elements = node.elements;
|
||||
if (!hasSpread(elements)) return;
|
||||
|
||||
if (!t.isArrayExpression(first)) {
|
||||
nodes.unshift(first);
|
||||
first = t.arrayExpression([]);
|
||||
}
|
||||
var nodes = build(elements, scope);
|
||||
var first = nodes.shift();
|
||||
|
||||
return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
|
||||
}
|
||||
|
||||
export function CallExpression(node, parent, scope) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var contextLiteral = t.identifier("undefined");
|
||||
|
||||
node.arguments = [];
|
||||
|
||||
var nodes;
|
||||
if (args.length === 1 && args[0].argument.name === "arguments") {
|
||||
nodes = [args[0].argument];
|
||||
} else {
|
||||
nodes = build(args, scope);
|
||||
}
|
||||
|
||||
var first = nodes.shift();
|
||||
if (nodes.length) {
|
||||
node.arguments.push(t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes));
|
||||
} else {
|
||||
node.arguments.push(first);
|
||||
}
|
||||
|
||||
var callee = node.callee;
|
||||
|
||||
if (this.get("callee").isMemberExpression()) {
|
||||
var temp = scope.maybeGenerateMemoised(callee.object);
|
||||
if (temp) {
|
||||
callee.object = t.assignmentExpression("=", temp, callee.object);
|
||||
contextLiteral = temp;
|
||||
} else {
|
||||
contextLiteral = callee.object;
|
||||
if (!t.isArrayExpression(first)) {
|
||||
nodes.unshift(first);
|
||||
first = t.arrayExpression([]);
|
||||
}
|
||||
t.appendToMemberExpression(callee, t.identifier("apply"));
|
||||
} else {
|
||||
node.callee = t.memberExpression(node.callee, t.identifier("apply"));
|
||||
|
||||
return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
|
||||
},
|
||||
|
||||
CallExpression(node, parent, scope) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var contextLiteral = t.identifier("undefined");
|
||||
|
||||
node.arguments = [];
|
||||
|
||||
var nodes;
|
||||
if (args.length === 1 && args[0].argument.name === "arguments") {
|
||||
nodes = [args[0].argument];
|
||||
} else {
|
||||
nodes = build(args, scope);
|
||||
}
|
||||
|
||||
var first = nodes.shift();
|
||||
if (nodes.length) {
|
||||
node.arguments.push(t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes));
|
||||
} else {
|
||||
node.arguments.push(first);
|
||||
}
|
||||
|
||||
var callee = node.callee;
|
||||
|
||||
if (this.get("callee").isMemberExpression()) {
|
||||
var temp = scope.maybeGenerateMemoised(callee.object);
|
||||
if (temp) {
|
||||
callee.object = t.assignmentExpression("=", temp, callee.object);
|
||||
contextLiteral = temp;
|
||||
} else {
|
||||
contextLiteral = callee.object;
|
||||
}
|
||||
t.appendToMemberExpression(callee, t.identifier("apply"));
|
||||
} else {
|
||||
node.callee = t.memberExpression(node.callee, t.identifier("apply"));
|
||||
}
|
||||
|
||||
node.arguments.unshift(contextLiteral);
|
||||
},
|
||||
|
||||
NewExpression(node, parent, scope, file) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var nodes = build(args, scope);
|
||||
|
||||
var context = t.arrayExpression([t.literal(null)]);
|
||||
|
||||
args = t.callExpression(t.memberExpression(context, t.identifier("concat")), nodes);
|
||||
|
||||
return t.newExpression(
|
||||
t.callExpression(
|
||||
t.memberExpression(file.addHelper("bind"), t.identifier("apply")),
|
||||
[node.callee, args]
|
||||
),
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
node.arguments.unshift(contextLiteral);
|
||||
}
|
||||
|
||||
export function NewExpression(node, parent, scope, file) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var nodes = build(args, scope);
|
||||
|
||||
var context = t.arrayExpression([t.literal(null)]);
|
||||
|
||||
args = t.callExpression(t.memberExpression(context, t.identifier("concat")), nodes);
|
||||
|
||||
return t.newExpression(
|
||||
t.callExpression(
|
||||
t.memberExpression(file.addHelper("bind"), t.identifier("apply")),
|
||||
[node.callee, args]
|
||||
),
|
||||
[]
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,11 +9,13 @@ export var metadata = {
|
||||
group: "builtin-trailing"
|
||||
};
|
||||
|
||||
export function Func/*tion*/(node, parent, scope, file) {
|
||||
if (node.generator || node.async) return;
|
||||
var tailCall = new TailCallTransformer(this, scope, file);
|
||||
tailCall.run();
|
||||
}
|
||||
export var visitor = {
|
||||
Function(node, parent, scope, file) {
|
||||
if (node.generator || node.async) return;
|
||||
var tailCall = new TailCallTransformer(this, scope, file);
|
||||
tailCall.run();
|
||||
}
|
||||
};
|
||||
|
||||
function returnBlock(expr) {
|
||||
return t.blockStatement([t.returnStatement(expr)]);
|
||||
@@ -148,7 +150,7 @@ class TailCallTransformer {
|
||||
|
||||
//
|
||||
|
||||
var body = t.ensureBlock(node).body;
|
||||
var body = this.path.ensureBlock().body;
|
||||
|
||||
for (var i = 0; i < body.length; i++) {
|
||||
var bodyNode = body[i];
|
||||
@@ -209,7 +211,7 @@ class TailCallTransformer {
|
||||
var decl = t.variableDeclarator(this.argumentsId);
|
||||
if (this.argumentsId) {
|
||||
decl.init = t.identifier("arguments");
|
||||
decl.init._shadowedFunctionLiteral = true;
|
||||
decl.init._shadowedFunctionLiteral = this.path;
|
||||
}
|
||||
topVars.push(decl);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,10 @@ export var metadata = {
|
||||
group: "builtin-pre"
|
||||
};
|
||||
|
||||
function isString(node) {
|
||||
return t.isLiteral(node) && typeof node.value === "string";
|
||||
}
|
||||
|
||||
function buildBinaryExpression(left, right) {
|
||||
var node = t.binaryExpression("+", left, right);
|
||||
node._templateLiteralProduced = true;
|
||||
@@ -16,59 +20,70 @@ function crawl(path) {
|
||||
if (path.is("_templateLiteralProduced")) {
|
||||
crawl(path.get("left"));
|
||||
crawl(path.get("right"));
|
||||
} else if (!path.isGenericType("String") && !path.isGenericType("Number")) {
|
||||
} else if (!path.isBaseType("string") && !path.isBaseType("number")) {
|
||||
path.replaceWith(t.callExpression(t.identifier("String"), [path.node]));
|
||||
}
|
||||
}
|
||||
|
||||
export function TaggedTemplateExpression(node, parent, scope, file) {
|
||||
var quasi = node.quasi;
|
||||
var args = [];
|
||||
export var visitor = {
|
||||
TaggedTemplateExpression(node, parent, scope, file) {
|
||||
var quasi = node.quasi;
|
||||
var args = [];
|
||||
|
||||
var strings = [];
|
||||
var raw = [];
|
||||
var strings = [];
|
||||
var raw = [];
|
||||
|
||||
for (var elem of (quasi.quasis: Array)) {
|
||||
strings.push(t.literal(elem.value.cooked));
|
||||
raw.push(t.literal(elem.value.raw));
|
||||
}
|
||||
|
||||
strings = t.arrayExpression(strings);
|
||||
raw = t.arrayExpression(raw);
|
||||
|
||||
var templateName = "tagged-template-literal";
|
||||
if (file.isLoose("es6.templateLiterals")) templateName += "-loose";
|
||||
args.push(t.callExpression(file.addHelper(templateName), [strings, raw]));
|
||||
|
||||
args = args.concat(quasi.expressions);
|
||||
|
||||
return t.callExpression(node.tag, args);
|
||||
}
|
||||
|
||||
export function TemplateLiteral(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
|
||||
for (let elem of (node.quasis: Array)) {
|
||||
nodes.push(t.literal(elem.value.cooked));
|
||||
|
||||
var expr = node.expressions.shift();
|
||||
if (expr) nodes.push(expr);
|
||||
}
|
||||
|
||||
if (nodes.length > 1) {
|
||||
// remove redundant '' at the end of the expression
|
||||
var last = nodes[nodes.length - 1];
|
||||
if (t.isLiteral(last, { value: "" })) nodes.pop();
|
||||
|
||||
var root = buildBinaryExpression(nodes.shift(), nodes.shift());
|
||||
|
||||
for (let node of (nodes: Array)) {
|
||||
root = buildBinaryExpression(root, node);
|
||||
for (var elem of (quasi.quasis: Array)) {
|
||||
strings.push(t.literal(elem.value.cooked));
|
||||
raw.push(t.literal(elem.value.raw));
|
||||
}
|
||||
|
||||
this.replaceWith(root);
|
||||
//crawl(this);
|
||||
} else {
|
||||
return nodes[0];
|
||||
strings = t.arrayExpression(strings);
|
||||
raw = t.arrayExpression(raw);
|
||||
|
||||
var templateName = "tagged-template-literal";
|
||||
if (file.isLoose("es6.templateLiterals")) templateName += "-loose";
|
||||
args.push(t.callExpression(file.addHelper(templateName), [strings, raw]));
|
||||
|
||||
args = args.concat(quasi.expressions);
|
||||
|
||||
return t.callExpression(node.tag, args);
|
||||
},
|
||||
|
||||
TemplateLiteral(node, parent, scope, file) {
|
||||
var nodes = [];
|
||||
|
||||
for (let elem of (node.quasis: Array)) {
|
||||
nodes.push(t.literal(elem.value.cooked));
|
||||
|
||||
var expr = node.expressions.shift();
|
||||
if (expr) nodes.push(expr);
|
||||
}
|
||||
|
||||
if (nodes.length > 1) {
|
||||
// filter out empty string literals
|
||||
nodes = nodes.filter(n => !t.isLiteral(n, { value: "" }));
|
||||
|
||||
if (nodes.length === 1 && isString(nodes[0])) {
|
||||
return nodes[0];
|
||||
}
|
||||
|
||||
// since `+` is left-to-right associative
|
||||
// ensure the first node is a string if first/second isn't
|
||||
if (!isString(nodes[0]) && !isString(nodes[1])) {
|
||||
nodes.unshift(t.literal(""));
|
||||
}
|
||||
|
||||
var root = buildBinaryExpression(nodes.shift(), nodes.shift());
|
||||
|
||||
for (let node of (nodes: Array)) {
|
||||
root = buildBinaryExpression(root, node);
|
||||
}
|
||||
|
||||
this.replaceWith(root);
|
||||
//crawl(this);
|
||||
} else {
|
||||
return nodes[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user