Compare commits
198 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a88e05362 | ||
|
|
e3bd2dff8d | ||
|
|
ef82171254 | ||
|
|
00d94fd810 | ||
|
|
d929d3c5eb | ||
|
|
5c1ee86b97 | ||
|
|
5409691a3a | ||
|
|
24964ac454 | ||
|
|
faa81ab85b | ||
|
|
d4bc082bb9 | ||
|
|
3777af6bbd | ||
|
|
1f258e9e9c | ||
|
|
50333c879c | ||
|
|
105e6ac379 | ||
|
|
dadab64e39 | ||
|
|
2b82f2bcc2 | ||
|
|
f1183505b1 | ||
|
|
fa3b24e5b4 | ||
|
|
5789447068 | ||
|
|
f1f7321590 | ||
|
|
9ff4df6dae | ||
|
|
0dbb24c922 | ||
|
|
a027d2b9cf | ||
|
|
e290990371 | ||
|
|
d0a2bd170e | ||
|
|
69db46f96b | ||
|
|
27ba4b2bba | ||
|
|
b337c1ab06 | ||
|
|
a1895b4bb4 | ||
|
|
00483917f0 | ||
|
|
d09bafaf8c | ||
|
|
a7ef02c781 | ||
|
|
94cd45c269 | ||
|
|
424bab97d0 | ||
|
|
a1bdd804e2 | ||
|
|
10c051890b | ||
|
|
ac49d0a335 | ||
|
|
b56f1800e5 | ||
|
|
49ef92c586 | ||
|
|
542fe89123 | ||
|
|
5b118c0c3f | ||
|
|
8503916799 | ||
|
|
206c828a56 | ||
|
|
7a261a1db1 | ||
|
|
c9d9a085f1 | ||
|
|
6d1953d9c3 | ||
|
|
92621d71c7 | ||
|
|
dc01731c25 | ||
|
|
9fb8a80f60 | ||
|
|
85c2de57e4 | ||
|
|
58fac2e2be | ||
|
|
682806f1ca | ||
|
|
47c6f74251 | ||
|
|
37f360c72d | ||
|
|
e5a8c95b62 | ||
|
|
921d459f13 | ||
|
|
58898932e6 | ||
|
|
c7b45116c4 | ||
|
|
32ddd638ba | ||
|
|
0eb3cda2d4 | ||
|
|
2acb24d43d | ||
|
|
fdd1451d53 | ||
|
|
43e2f121a6 | ||
|
|
297e55ba63 | ||
|
|
38396dadd5 | ||
|
|
f75f045026 | ||
|
|
740193b1e2 | ||
|
|
b9fe1475c2 | ||
|
|
6065220f9b | ||
|
|
715884662e | ||
|
|
11780c28ff | ||
|
|
215c2da7cb | ||
|
|
c7c41d6548 | ||
|
|
695571b435 | ||
|
|
f845633cc1 | ||
|
|
72c9b1d6c9 | ||
|
|
edd3363e48 | ||
|
|
114b5ef9ec | ||
|
|
2f4e0c3361 | ||
|
|
3ee51dae1a | ||
|
|
20263c1151 | ||
|
|
eaac564f11 | ||
|
|
63a47ef7bb | ||
|
|
6963cc1e40 | ||
|
|
5eb2462e29 | ||
|
|
9e285cdc20 | ||
|
|
01ade47af9 | ||
|
|
b1fe449b0d | ||
|
|
2b458ec2d4 | ||
|
|
d5f47f4f4d | ||
|
|
d4deb18975 | ||
|
|
5a794db73b | ||
|
|
dc131f05a8 | ||
|
|
1d4f79790a | ||
|
|
6bcbaf6df1 | ||
|
|
bc199ef0c9 | ||
|
|
f5fed99c81 | ||
|
|
66a6d3cffe | ||
|
|
39227486a6 | ||
|
|
caafa31df1 | ||
|
|
4c41c904f5 | ||
|
|
0917a6a5b1 | ||
|
|
349eba33ce | ||
|
|
8ff21b407d | ||
|
|
751ea7a12c | ||
|
|
b30cd227cc | ||
|
|
18dc7b8143 | ||
|
|
1c628bbec1 | ||
|
|
d4c3dde02a | ||
|
|
a587106a6b | ||
|
|
9c1b60e451 | ||
|
|
0c7e0b65b9 | ||
|
|
5c17091db4 | ||
|
|
7fa5ba88df | ||
|
|
2fae245cd5 | ||
|
|
297f103ddb | ||
|
|
fd63650d6a | ||
|
|
e13ed39567 | ||
|
|
bb00f641b7 | ||
|
|
25b466a627 | ||
|
|
ac231f2987 | ||
|
|
458e3d48f6 | ||
|
|
c235780611 | ||
|
|
56b858ccb1 | ||
|
|
d42351bb02 | ||
|
|
ed7378cc2d | ||
|
|
a47a7dc347 | ||
|
|
2c82b5a4b0 | ||
|
|
3578135b90 | ||
|
|
5f3408b2a2 | ||
|
|
9e3f9fda6b | ||
|
|
7f425d2c6e | ||
|
|
311a8e042b | ||
|
|
27d30329fd | ||
|
|
12c5a3e73b | ||
|
|
2a166a6ed1 | ||
|
|
896929378e | ||
|
|
ae439d27b9 | ||
|
|
e22798261a | ||
|
|
d0af8b8d0a | ||
|
|
beaa2fa540 | ||
|
|
b8cac9787e | ||
|
|
64f6e4a0c5 | ||
|
|
c4a7ac5a8b | ||
|
|
1ed682fa76 | ||
|
|
9987e7fe0e | ||
|
|
e74c7cb0b7 | ||
|
|
2f01e5c3af | ||
|
|
6847211971 | ||
|
|
965e246259 | ||
|
|
af59eb7d6a | ||
|
|
def4319058 | ||
|
|
d90383b1ba | ||
|
|
1ac40ee834 | ||
|
|
3d5d170eff | ||
|
|
b5bdba46f1 | ||
|
|
c4e162b8e5 | ||
|
|
98bc750b05 | ||
|
|
84002ed1ce | ||
|
|
aaab2db0ec | ||
|
|
7f3959444c | ||
|
|
0ba9216d6f | ||
|
|
6dfe66bce3 | ||
|
|
9e08a6f084 | ||
|
|
b9f3f1e2a9 | ||
|
|
4f18ed406c | ||
|
|
4d8e5f728a | ||
|
|
54857ceac7 | ||
|
|
5b961ea3e7 | ||
|
|
35b28cf722 | ||
|
|
c5bfbf37f0 | ||
|
|
cfee68aa67 | ||
|
|
7d0dae129c | ||
|
|
f9d14fa2ed | ||
|
|
11d55e661e | ||
|
|
0544e98fb1 | ||
|
|
59d918ea67 | ||
|
|
b4232699d2 | ||
|
|
6bd67ca660 | ||
|
|
4722c0ce56 | ||
|
|
25a5caa0fc | ||
|
|
6f05466cf5 | ||
|
|
1ad9edb57c | ||
|
|
c6ae33c5a2 | ||
|
|
e0d620b1d5 | ||
|
|
5588bf56eb | ||
|
|
a0e500de6c | ||
|
|
bf8d9801ce | ||
|
|
68b99a7004 | ||
|
|
5ae4f8eec7 | ||
|
|
d9a3eadad7 | ||
|
|
b1cc5419a4 | ||
|
|
c6a7a9c401 | ||
|
|
608df54b02 | ||
|
|
2ac83ec95b | ||
|
|
e4596f638d | ||
|
|
1425af9b2a | ||
|
|
9351c6470f |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -6,7 +6,7 @@ test/tmp
|
||||
/templates.json
|
||||
/tests.json
|
||||
/browser.js
|
||||
/polyfill.js
|
||||
/browser-polyfill.js
|
||||
/runtime.js
|
||||
coverage
|
||||
dist
|
||||
|
||||
3
.hound.yml
Normal file
3
.hound.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
java_script:
|
||||
enabled: true
|
||||
config_file: .jshintrc
|
||||
@@ -8,4 +8,4 @@ Makefile
|
||||
.*
|
||||
dist
|
||||
tests.json
|
||||
!README.md
|
||||
CHANGELOG.md
|
||||
|
||||
100
CHANGELOG.md
Normal file
100
CHANGELOG.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# 1.12.17
|
||||
|
||||
* Add `moduleName`, `sourceRoot` and `filenameRelative` options - thanks @darvelo!
|
||||
* Traversal optimisations.
|
||||
|
||||
# 1.12.16
|
||||
|
||||
* Fix comments not being retained from `MethodDefinition` in classes.
|
||||
* Add temporal dead zone in default parameters.
|
||||
|
||||
# 1.12.15
|
||||
|
||||
* Update `acorn-6to5`.
|
||||
|
||||
# 1.12.14
|
||||
|
||||
* Fix duplicate let scoping in functions.
|
||||
* Make JSX whitespace more React-compliant.
|
||||
* Add `_memberExpressionKeywords` transformer that turns keyword identifiers to computed literals.
|
||||
* Upgrade `regenerator-6to5`.
|
||||
|
||||
# 1.12.13
|
||||
|
||||
* Support duplicate constants within different block scopes.
|
||||
* Fix for-head duplication testing and replacement.
|
||||
* Support `raw` property on tagged template literals.
|
||||
|
||||
# 1.12.12
|
||||
|
||||
* Make scope tracker more reliable to handle all edgecases.
|
||||
|
||||
# 1.12.11
|
||||
|
||||
* Block scope classes.
|
||||
* Fix generation of integer `Literal`s in `MemberExpression`.
|
||||
|
||||
# 1.12.10
|
||||
|
||||
* Fix let scoping var hoisting.
|
||||
|
||||
# 1.12.9
|
||||
|
||||
* Escape unicode characters when generating string `Literal`s.
|
||||
* Fix semicolons being output for statements in `ExportDeclaration`.
|
||||
* Fix `WithStatement` missing parenthesis.
|
||||
|
||||
# 1.12.8
|
||||
|
||||
* Temporarily forbid `AssignmentExpression` destructuring outside of `ExpressionStatement`.
|
||||
|
||||
# 1.12.7
|
||||
|
||||
* Update to latest `acorn-6to5`.
|
||||
|
||||
# 1.12.6
|
||||
|
||||
* Update to latest `acorn-6to5`.
|
||||
|
||||
# 1.12.5
|
||||
|
||||
* Fix excessive whitespace trimming resulting in innaccurate sourcemap line.
|
||||
|
||||
# 1.12.4
|
||||
|
||||
* Add `doc` folder for documentation.
|
||||
|
||||
# 1.12.3
|
||||
|
||||
* Support generator comprehensions.
|
||||
* Use `Array.from` instead of `Array.prototype.slice` in spread transformer.
|
||||
* Support spread in `NewExpression`s.
|
||||
|
||||
# 1.12.2
|
||||
|
||||
* Upgrade `matcha` to `0.6.0` and `browserify` to `6.3.2`.
|
||||
* Add own `trimRight` helper instead of relying on the string instance method.
|
||||
* Support JSX spreads that aren't the first.
|
||||
|
||||
# 1.12.1
|
||||
|
||||
* Fix `this` and `arguments` mapping in the `_aliasFunctions` transformer.
|
||||
|
||||
# 1.12.0
|
||||
|
||||
* Combine `jsx` and `react` transformers to `react`.
|
||||
* Update `react` syntax output to React v0.12.
|
||||
|
||||
# 1.11.15
|
||||
|
||||
* Fix JSX literal whitespace generation.
|
||||
|
||||
# 1.11.14
|
||||
|
||||
* Avoid using a switch for let-scoping continue and break statements and use an if statement instead.
|
||||
* Remove excess whitespace and newlines from JSX literals.
|
||||
|
||||
# 1.11.13
|
||||
|
||||
* Update regenerator-6to5
|
||||
* Add support for most escodegen formatting options
|
||||
31
CONTRIBUTING.md
Normal file
31
CONTRIBUTING.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Contributing
|
||||
|
||||
* **General**
|
||||
* No ES6 syntax features or methods, exclusively ES5.
|
||||
* Max of five arguments for functions
|
||||
* Max depth of four nested blocks
|
||||
* 2-spaced soft tabs
|
||||
* **Naming**
|
||||
* CamelCase all class names
|
||||
* camelBack all variable names
|
||||
* **Spacing**
|
||||
* 80 character line max
|
||||
* Spaces after all keywords
|
||||
* Spaces before all left curly braces
|
||||
* **Comments**
|
||||
* Use JSDoc-style comments for methods
|
||||
* Single-line comments for ambiguous code
|
||||
* **Quotes**
|
||||
* Always use double quotes
|
||||
* Only use single quotes when the string contains a double quote
|
||||
* **Declaration**
|
||||
* No unused variables
|
||||
* No pollution of global variables and prototypes
|
||||
|
||||
## Testing
|
||||
|
||||
$ make test
|
||||
|
||||
## Linting
|
||||
|
||||
$ make lint
|
||||
162
FEATURES.md
162
FEATURES.md
@@ -1,162 +0,0 @@
|
||||
# Features
|
||||
|
||||
## Array comprehension
|
||||
|
||||
```javascript
|
||||
[for (i of [1, 2, 3]) i * i]; // [1, 4, 9]
|
||||
```
|
||||
|
||||
## Arrow functions
|
||||
|
||||
```javascript
|
||||
arr.map(x => x * x);
|
||||
```
|
||||
|
||||
## Let scoping
|
||||
|
||||
```javascript
|
||||
for (let i in arr) {
|
||||
let v = arr[i];
|
||||
}
|
||||
```
|
||||
|
||||
## Classes
|
||||
|
||||
```javascript
|
||||
class Foo extends Bar {
|
||||
constructor() { }
|
||||
|
||||
foo() { }
|
||||
|
||||
get bar() { }
|
||||
|
||||
set bar() { }
|
||||
}
|
||||
```
|
||||
|
||||
## Computed property names
|
||||
|
||||
```javascript
|
||||
var foo = "foo";
|
||||
var bar = "bar";
|
||||
var obj = {
|
||||
["foo" + bar]: "heh",
|
||||
["bar" + foo]: "noo",
|
||||
foo: "foo",
|
||||
bar: "bar"
|
||||
};
|
||||
```
|
||||
|
||||
## Constants
|
||||
|
||||
```javascript
|
||||
const MULTIPLIER = 5;
|
||||
console.log(2 * MULTIPLIER);
|
||||
|
||||
MULTIPLIER = 6; // error
|
||||
var MULTIPLIER; // error
|
||||
```
|
||||
|
||||
## Default parameters
|
||||
|
||||
```javascript
|
||||
function foo(bar = "foo") {
|
||||
return bar + "bar";
|
||||
}
|
||||
```
|
||||
|
||||
## Destructuring
|
||||
|
||||
```javascript
|
||||
var [a, [b], c, d] = ["hello", [", ", "junk"], ["world"]];
|
||||
console.log(a + b + c); // hello, world
|
||||
```
|
||||
|
||||
## For-of
|
||||
|
||||
```javascript
|
||||
for (var i of [1, 2, 3]) {
|
||||
console.log(i * i);
|
||||
}
|
||||
```
|
||||
|
||||
## Generators
|
||||
|
||||
```javascript
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
```javascript
|
||||
```
|
||||
|
||||
## Numeric literals
|
||||
|
||||
```javascript
|
||||
0b111110111 === 503; // true
|
||||
0o767 === 503; // true
|
||||
```
|
||||
|
||||
## Property method assignment
|
||||
|
||||
```javascript
|
||||
var obj = {
|
||||
foo() {
|
||||
return "foobar";
|
||||
},
|
||||
|
||||
get bar() {
|
||||
return this._bar;
|
||||
},
|
||||
|
||||
set bar(val) {
|
||||
this._bar = val;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Property name shorthand
|
||||
|
||||
```javascript
|
||||
function f(x, y) {
|
||||
return { x, y };
|
||||
}
|
||||
```
|
||||
|
||||
## Rest parameters
|
||||
|
||||
```javascript
|
||||
function printList(name, ...items) {
|
||||
console.log("list %s has the following items", name);
|
||||
items.forEach(function (item) {
|
||||
console.log(item);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Spread
|
||||
|
||||
```javascript
|
||||
function add(x, y) {
|
||||
return x + y;
|
||||
}
|
||||
|
||||
var numbers = [5, 10];
|
||||
add(...numbers); // 15
|
||||
```
|
||||
|
||||
## Template literals
|
||||
|
||||
```javascript
|
||||
var x = 5;
|
||||
var y = 10;
|
||||
console.log(`${x} + ${y} = ${x + y}`); // "5 + 10 = 15"
|
||||
```
|
||||
|
||||
## Unicode regex
|
||||
|
||||
```javascript
|
||||
var string = 'foo💩bar';
|
||||
var match = string.match(/foo(.)bar/u);
|
||||
console.log(match[1]);
|
||||
```
|
||||
14
Makefile
14
Makefile
@@ -6,7 +6,7 @@ MOCHA_CMD = node_modules/mocha/bin/_mocha
|
||||
|
||||
export NODE_ENV = test
|
||||
|
||||
.PHONY: clean test test-cov tlint est-travis test-appveyor test-browser publish bench build
|
||||
.PHONY: clean test test-cov test-clean lint test-travis test-spec test-browser publish bench build
|
||||
|
||||
clean:
|
||||
rm -rf coverage templates.json test/tmp dist
|
||||
@@ -18,19 +18,23 @@ bench:
|
||||
lint:
|
||||
$(JSHINT_CMD) lib bin benchmark/index.js
|
||||
|
||||
test-clean:
|
||||
rm -rf test/tmp
|
||||
|
||||
test:
|
||||
make lint
|
||||
$(MOCHA_CMD)
|
||||
make test-clean
|
||||
|
||||
test-cov:
|
||||
rm -rf coverage
|
||||
node $(ISTANBUL_CMD) $(MOCHA_CMD) --
|
||||
|
||||
test-appveyor:
|
||||
test-spec:
|
||||
node $(ISTANBUL_CMD) $(MOCHA_CMD) -- --reporter spec
|
||||
|
||||
test-travis:
|
||||
make test-appveyor
|
||||
make test-spec
|
||||
if test -n "$$CODECLIMATE_REPO_TOKEN"; then codeclimate < coverage/lcov.info; fi
|
||||
|
||||
test-browser:
|
||||
@@ -66,7 +70,7 @@ publish:
|
||||
|
||||
make build
|
||||
cp dist/6to5.min.js browser.js
|
||||
cp dist/polyfill.min.js polyfill.js
|
||||
cp dist/polyfill.min.js browser-polyfill.js
|
||||
cp dist/runtime.min.js runtime.js
|
||||
|
||||
node bin/cache-templates
|
||||
@@ -78,4 +82,4 @@ publish:
|
||||
|
||||
git push --follow-tags
|
||||
|
||||
rm -rf templates.json browser.js runtime.js polyfill.js
|
||||
rm -rf templates.json browser.js runtime.js browser-polyfill.js
|
||||
|
||||
477
README.md
477
README.md
@@ -24,479 +24,6 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
**6to5** turns ES6 code into vanilla ES5, so you can use ES6 features **today.**
|
||||
**6to5** turns ES6+ code into vanilla ES5, so you can use next generation features **today.**
|
||||
|
||||
- **Readable** - formatting is retained if possible so your generated code is as similar as possible.
|
||||
- **Extensible** - with a large range of [plugins](#plugins) and **browser support**.
|
||||
- **Lossless** - **source map support** so you can debug your compiled code with ease.
|
||||
- **Compact** - maps directly to the equivalent ES5 with **no runtime**[\*](#generators).
|
||||
|
||||
## Installation
|
||||
|
||||
It's as easy as:
|
||||
|
||||
$ npm install -g 6to5
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Features](#features)
|
||||
- [Usage](#usage)
|
||||
- [Plugins](#plugins)
|
||||
- [CLI](#cli)
|
||||
- [Node](#node-1)
|
||||
- [Browser](#browser)
|
||||
- [Modules](#modules)
|
||||
- [Caveats](#caveats)
|
||||
- [Polyfill](#polyfill)
|
||||
- [Optional runtime](#optional-runtime)
|
||||
- [Differences](#differences)
|
||||
|
||||
## [Features](FEATURES.md)
|
||||
|
||||
- [Array comprehension](FEATURES.md#array-comprehension)
|
||||
- [Arrow functions](FEATURES.md#arrow-functions)
|
||||
- [Classes](FEATURES.md#classes)
|
||||
- [Computed property names](FEATURES.md#computed-property-names)
|
||||
- [Constants](FEATURES.md#constants)
|
||||
- [Default parameters](FEATURES.md#default-parameters)
|
||||
- [Destructuring](FEATURES.md#destructuring)
|
||||
- [For-of](FEATURES.md#for-of)
|
||||
- [Generators](FEATURES.md#generators) via [regenerator](https://github.com/facebook/regenerator)
|
||||
- [Let scoping](FEATURES.md#let-scoping)
|
||||
- [Modules](FEATURES.md#modules)
|
||||
- [Numeric literals](FEATURES.md#numeric-literals)
|
||||
- [Property method assignment](FEATURES.md#property-method-assignment)
|
||||
- [Property name shorthand](FEATURES.md#property-name-shorthand)
|
||||
- [Rest parameters](FEATURES.md#rest-parameters)
|
||||
- [Spread](FEATURES.md#spread)
|
||||
- [Template literals](FEATURES.md#template-literals)
|
||||
- [Unicode regex](FEATURES.md#unicode-regex)
|
||||
|
||||
## Usage
|
||||
|
||||
### Plugins
|
||||
|
||||
- [Broccoli](https://github.com/very-geek/broccoli-6to5-transpiler)
|
||||
- [Browserify](https://github.com/6to5/6to5-browserify)
|
||||
- [Brunch](https://github.com/es128/6to5-brunch)
|
||||
- [Duo](https://github.com/bdo-labs/duo6to5)
|
||||
- [Connect](https://github.com/6to5/6to5-connect)
|
||||
- [Gulp](https://github.com/sindresorhus/gulp-6to5)
|
||||
- [Grunt](https://github.com/sindresorhus/grunt-6to5)
|
||||
- [Jade](https://github.com/Apoxx/jade-6to5)
|
||||
- [Karma](https://github.com/shuhei/karma-6to5-preprocessor)
|
||||
- [webpack](https://github.com/Couto/6to5-loader)
|
||||
|
||||
### CLI
|
||||
|
||||
Compile the file `script.js` and output it to stdout.
|
||||
|
||||
$ 6to5 script.js
|
||||
|
||||
Compile the file `script.js` and output it to `script-compiled.js`.
|
||||
|
||||
$ 6to5 script.js --out-file script-compiled.js
|
||||
|
||||
Compile the file `script.js` and output it to `script-compiled.js` and save a
|
||||
source map to `script-compiled.js.map`.
|
||||
|
||||
$ 6to5 script.js --source-maps --out-file script-compiled.js
|
||||
|
||||
Compile the file `script.js` and output it to `script-compiled.js` with a source
|
||||
map embedded in a comment at the bottom.
|
||||
|
||||
$ 6to5 script.js --source-maps-inline --out-file script-compiled.js
|
||||
|
||||
Compile the entire `src` directory and output it to the `lib` directory.
|
||||
|
||||
$ 6to5 src --out-dir lib
|
||||
|
||||
Compile the entire `src` directory and output it to the one concatenated file.
|
||||
|
||||
$ 6to5 src --out-file script-compiled.js
|
||||
|
||||
Pipe a file in via stdin and output it to `script-compiled.js`
|
||||
|
||||
$ 6to5 --out-file script-compiled.js < script.js
|
||||
|
||||
#### Node
|
||||
|
||||
Launch a repl.
|
||||
|
||||
$ 6to5-node
|
||||
|
||||
Evaluate code.
|
||||
|
||||
$ 6to5-node -e "class Test { }"
|
||||
|
||||
Compile and run `test.js`.
|
||||
|
||||
$ 6to5-node test
|
||||
|
||||
### Node
|
||||
|
||||
```javascript
|
||||
var to5 = require("6to5");
|
||||
|
||||
var result = to5.transform("code();", options);
|
||||
result.code;
|
||||
result.map;
|
||||
result.ast;
|
||||
|
||||
to5.transformFileSync("filename.js", options).code;
|
||||
|
||||
to5.transformFile("filename.js", options, function (err, result) {
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
##### Options
|
||||
|
||||
```javascript
|
||||
{
|
||||
// Filename for use in errors etc.
|
||||
// Default: "unknown"
|
||||
filename: "filename",
|
||||
|
||||
// List of transformers to EXCLUDE.
|
||||
// Run `6to5 --help` to see a full list of transformers.
|
||||
blacklist: [],
|
||||
|
||||
// List of transformers to ONLY use.
|
||||
// Run `6to5 --help` to see a full list of transformers.
|
||||
whitelist: [],
|
||||
|
||||
// Module formatter to use
|
||||
// Run `6to5 --help` to see a full list of module formatters.
|
||||
// Default: "common"
|
||||
modules: "common",
|
||||
|
||||
// If truthy, adds a `map` property to returned output.
|
||||
// If set to "inline", a comment with a sourceMappingURL directive is added to
|
||||
// the bottom of the returned code.
|
||||
// Default: false
|
||||
sourceMap: true,
|
||||
|
||||
// Set `file` on returned source map.
|
||||
// Default: `filename` option.
|
||||
sourceMapName: "filename",
|
||||
|
||||
// Set `sources[0]` on returned source map.
|
||||
// Default: `filename` option.
|
||||
sourceFileName: "filename",
|
||||
|
||||
// Optionally replace all 6to5 helper declarations with a referenece to this
|
||||
// variable. If set to `true` then the default namespace is used "to5Runtime".
|
||||
// Default: false
|
||||
runtime: true
|
||||
}
|
||||
```
|
||||
|
||||
#### Require hook
|
||||
|
||||
All subsequent files required by node with the extensions `.es6` and `.js` will
|
||||
be transformed by 6to5. The polyfill specified in [Polyfill](#polyfill) is also
|
||||
required.
|
||||
|
||||
```javascript
|
||||
require("6to5/register");
|
||||
```
|
||||
|
||||
**NOTE:** By default all requires to `node_modules` will be ignored. You can
|
||||
override this by passing an ignore regex via:
|
||||
|
||||
```javascript
|
||||
require("6to5/register")({
|
||||
// This will override `node_modules` ignoring - you can alternatively pass
|
||||
// a regex
|
||||
ignore: false
|
||||
});
|
||||
```
|
||||
|
||||
##### Options
|
||||
|
||||
```javascript
|
||||
require("6to5/register")({
|
||||
// Optional ignore regex - if any filenames **do** match this regex then they
|
||||
// aren't compiled
|
||||
ignore: /regex/,
|
||||
|
||||
// Optional only regex - if any filenames **don't** match this regex then they
|
||||
// aren't compiled
|
||||
only: /my_es6_folder/,
|
||||
|
||||
// See options above for usage
|
||||
whitelist: [],
|
||||
blacklist: [],
|
||||
|
||||
// This will remove the currently hooked extensions of .es6 and .js so you'll
|
||||
// have to add them back if you want them to be used again.
|
||||
extensions: [".js", ".es6"]
|
||||
});
|
||||
```
|
||||
|
||||
### Browser
|
||||
|
||||
A browser version of 6to5 is available from `browser.js` inside the 6to5
|
||||
directory in an npm release.
|
||||
|
||||
#### Scripts
|
||||
|
||||
While it's not recommended for serious use, when the browser version is included
|
||||
all scripts with the type `text/ecmascript-6` and `text/6to5` are automatically
|
||||
compiled and ran.
|
||||
|
||||
For example:
|
||||
|
||||
```html
|
||||
<script src="node_modules/6to5/browser.js"></script>
|
||||
<script type="text/6to5">
|
||||
class Test {
|
||||
test() {
|
||||
return "test";
|
||||
}
|
||||
}
|
||||
|
||||
var test = new Test;
|
||||
test.test();
|
||||
</script>
|
||||
```
|
||||
|
||||
#### Build
|
||||
|
||||
You can build a browser version of the compiler by running the following in the
|
||||
6to5 directory:
|
||||
|
||||
$ make build
|
||||
|
||||
This will output the files `dist/6to5.js` and `dist/6to5.min.js`.
|
||||
|
||||
#### API
|
||||
|
||||
```javascript
|
||||
to5.transform("class Test {}").code;
|
||||
```
|
||||
|
||||
#### Test
|
||||
|
||||
To test 6to5 in your browser run:
|
||||
|
||||
$ make test-browser
|
||||
|
||||
And open `test/browser.html` in your browser if it doesn't open automatically.
|
||||
|
||||
## [Modules](MODULES.md)
|
||||
|
||||
See [Modules - Common](MODULES.md#common-default) for documentation on the
|
||||
default module formatting.
|
||||
|
||||
Alternatively see [Modules](MODULES.md) for all other supported module formatting types.
|
||||
|
||||
## Caveats
|
||||
|
||||
### For-of
|
||||
|
||||
A polyfill is required for for-of functionality that implements `Symbol` and
|
||||
adds `prototype[Symbol.iterator]` behaviour to built-ins. Using the polyfills
|
||||
specified in [polyfill](#polyfill) suffices.
|
||||
|
||||
### Classes
|
||||
|
||||
Built-in classes such as `Date`, `Array` and `DOM` cannot be subclassed due to
|
||||
limitations in ES5 implementations.
|
||||
|
||||
If you're inheriting from a class then static properties are inherited from it
|
||||
via [\_\_proto\_\_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto),
|
||||
this is widely supported but you may run into problems with much older browsers.
|
||||
|
||||
**NOTE:** `__proto__` is not supported on IE <= 9 so static properties
|
||||
**will not** be inherited. A possible workaround is to use `super();`:
|
||||
|
||||
```javascript
|
||||
class Foo {
|
||||
static foo() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
static foo() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Generators
|
||||
|
||||
The [regenerator runtime](https://github.com/facebook/regenerator/blob/master/runtime.js)
|
||||
and an [ES6 polyfill](#polyfill) are required in order for generators to work.
|
||||
|
||||
## Polyfill
|
||||
|
||||
6to5 includes a polyfill that includes the
|
||||
[regenerator runtime](https://github.com/facebook/regenerator/blob/master/runtime.js) and the
|
||||
[es6-shim](https://github.com/paulmillr/es6-shim) and
|
||||
[es6-symbol](https://github.com/medikoo/es6-symbol) polyfills.
|
||||
|
||||
### Node
|
||||
|
||||
```javascript
|
||||
require("6to5/polyfill");
|
||||
```
|
||||
|
||||
### Browser
|
||||
|
||||
Available from the `polyfill.js` file within the 6to5 directory of an npm
|
||||
release.
|
||||
|
||||
## Optional runtime
|
||||
|
||||
6to5 has a few helper functions that'll be placed at the top of the generated
|
||||
code if needed so it's not inlined multiple times throughout that file. This may
|
||||
become an issue if you have multiple files, especially when you're sending them
|
||||
to the browser. gzip alleviates most of this concern but it's still not ideal.
|
||||
|
||||
You can tell 6to5 to not place any declarations at the top of your files and
|
||||
instead just point them to a reference contained within the runtime.
|
||||
|
||||
Simply use the following option if you're using the [Node API](#node-1):
|
||||
|
||||
```javascript
|
||||
{
|
||||
runtime: true
|
||||
}
|
||||
```
|
||||
|
||||
or the following flag if you're using the [CLI](#cli):
|
||||
|
||||
$ 6to5 --runtime
|
||||
|
||||
Then just include the runtime before your generated code.
|
||||
|
||||
### Getting the runtime
|
||||
|
||||
You can get the runtime via either:
|
||||
|
||||
$ 6to5-runtime
|
||||
|
||||
or
|
||||
|
||||
```javascript
|
||||
require("6to5").runtime();
|
||||
```
|
||||
|
||||
or from an npm release in `runtime.js` from the 6to5 directory.
|
||||
|
||||
### Customising namespace
|
||||
|
||||
You can also customise the runtime namespace by passing an optional namespace
|
||||
argument:
|
||||
|
||||
```javascript
|
||||
require("6to5").runtime("myCustomNamespace");
|
||||
```
|
||||
|
||||
$ 6to5-runtime myCustomNamespace
|
||||
|
||||
See [Options - runtime](#options) for documentation on changing the reference in
|
||||
generated code.
|
||||
|
||||
## Differences
|
||||
|
||||
### Philosophy
|
||||
|
||||
The fundamental concept behind 6to5 is that the generated code must be close as
|
||||
possible to the original, retaining all the same formatting and readability.
|
||||
|
||||
Many other transpilers are just concerned with making the code work while 6to5
|
||||
is concerned with making sure it works **and** is readable at the same time.
|
||||
|
||||
For example, given the following array comprehension:
|
||||
|
||||
```javascript
|
||||
var seattlers = [for (c of customers) if (c.city == "Seattle") { name: c.name, age: c.age }];
|
||||
```
|
||||
|
||||
is generated to the following with 6to5:
|
||||
|
||||
```javascript
|
||||
var seattlers = customers.filter(function (c) {
|
||||
return c.city == "Seattle";
|
||||
}).map(function (c) {
|
||||
return {
|
||||
name: c.name,
|
||||
age: c.age
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
The following is what Traceur generates:
|
||||
|
||||
```javascript
|
||||
var seattlers = (function() {
|
||||
var c;
|
||||
var $__20 = 0,
|
||||
$__21 = [];
|
||||
for (var $__22 = customers[$traceurRuntime.toProperty(Symbol.iterator)](),
|
||||
$__23; !($__23 = $__22.next()).done; ) {
|
||||
c = $__23.value;
|
||||
if (c.city == "Seattle")
|
||||
$traceurRuntime.setProperty($__21, $__20++, {
|
||||
name: c.name,
|
||||
age: c.age
|
||||
});
|
||||
}
|
||||
return $__21;
|
||||
}());
|
||||
```
|
||||
|
||||
As you can tell, it's not very pretty, unreadable even. Instead of mapping
|
||||
directly to a runtime, like other transpilers, 6to5 maps directly to the
|
||||
equivalent ES5.
|
||||
|
||||
I'm not saying 6to5 is for everyone or even suited for everything. Traceur is
|
||||
better suited if you'd like a full ES6 environment with polyfills and all.
|
||||
|
||||
### Comparison to other transpilers
|
||||
|
||||
| | 6to5 | Traceur | esnext | es6now | es6-transpiler | jstransform |
|
||||
| ---------------------------- | ---- | ------- | ------ | ------ | -------------- | ----------- |
|
||||
| No runtime | ✓ | | | | ✓ | ✓ |
|
||||
| Source maps | ✓ | ✓ | ✓ | | ✓ | ✓ |
|
||||
| No compiler global pollution | ✓ | | ✓ | | ✓ | ✓ |
|
||||
| Arrow functions | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Classes | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Computed property names | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| Constants | ✓ | ✓ | | | ✓ | |
|
||||
| Default parameters | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| Destructuring | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| For-of | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| Generators | ✓ | ✓ | ✓ | | | |
|
||||
| Let scoping | ✓ | ✓ | | | ✓ | |
|
||||
| Modules | ✓ | ✓ | | ✓ | | |
|
||||
| Property method assignment | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Property name shorthand | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Rest parameters | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Spread | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| Template literals | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Unicode regex | ✓ | ✓ | | | ✓ | |
|
||||
|
||||
#### [Traceur](https://github.com/google/traceur-compiler)
|
||||
|
||||
Traceur requires quite a bulky runtime (~75KB) and produces quite verbose code.
|
||||
While this can be trimmed down by selectively building the runtime, it's an
|
||||
unneccesary step when a runtime can be eliminated entirely.
|
||||
|
||||
#### [es6now](https://github.com/zenparsing/es6now)
|
||||
|
||||
es6now doesn't output sourcemaps. This is cited as a positive as line-to-line
|
||||
mapping is the goal. This however obviously doesn't retain column mapping
|
||||
resulting in the output code not being very pleasant.
|
||||
|
||||
#### [es6-transpiler](https://github.com/termi/es6-transpiler)
|
||||
|
||||
The es6-transpiler compiler requires shims to operate which pollutes the global
|
||||
scope resulting in possible collisions.
|
||||
|
||||
es6-transpiler maps line-by-line, just like es6now, this results in the same
|
||||
issues such as lack of column information and unpleasant code output.
|
||||
For more information view the [documentation](https://6to5.github.io).
|
||||
|
||||
@@ -10,7 +10,7 @@ install:
|
||||
test_script:
|
||||
- "node --version"
|
||||
- "npm --version"
|
||||
- "make test-appveyor"
|
||||
- "make test-spec"
|
||||
|
||||
build: "off"
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var commander = require("commander");
|
||||
var util = require("../lib/6to5/util");
|
||||
var path = require("path");
|
||||
var repl = require("repl");
|
||||
var to5 = require("../lib/6to5");
|
||||
var util = require("../lib/6to5/util");
|
||||
var vm = require("vm");
|
||||
var _ = require("lodash");
|
||||
|
||||
|
||||
61
doc/browser.md
Normal file
61
doc/browser.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Browser
|
||||
|
||||
A browser version of 6to5 is available from `browser.js` inside the 6to5
|
||||
directory in an npm release.
|
||||
|
||||
## Scripts
|
||||
|
||||
While it's not recommended for serious use, when the browser version is included
|
||||
all scripts with the type `text/ecmascript-6` and `text/6to5` are automatically
|
||||
compiled and ran.
|
||||
|
||||
For example:
|
||||
|
||||
```html
|
||||
<script src="node_modules/6to5/browser.js"></script>
|
||||
<script type="text/6to5">
|
||||
class Test {
|
||||
test() {
|
||||
return "test";
|
||||
}
|
||||
}
|
||||
|
||||
var test = new Test;
|
||||
test.test();
|
||||
</script>
|
||||
```
|
||||
|
||||
## Build
|
||||
|
||||
You can build a browser version of the compiler by running the following in the
|
||||
6to5 directory:
|
||||
|
||||
$ make build
|
||||
|
||||
This will output the files `dist/6to5.js` and `dist/6to5.min.js`.
|
||||
|
||||
## Test
|
||||
|
||||
To test 6to5 in your browser run:
|
||||
|
||||
$ make test-browser
|
||||
|
||||
And open `test/browser.html` in your browser if it doesn't open automatically.
|
||||
|
||||
## API
|
||||
|
||||
### to5.transform(code, [opts])
|
||||
|
||||
See [options](usage.md#options) for additional documentation.
|
||||
|
||||
```javascript
|
||||
to5.transform("class Test {}").code;
|
||||
```
|
||||
|
||||
### to5.run(code, [opts])
|
||||
|
||||
See [options](usage.md#options) for additional documentation.
|
||||
|
||||
```javascript
|
||||
to5.run("class Test {}");
|
||||
```
|
||||
43
doc/caveats.md
Normal file
43
doc/caveats.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Caveats
|
||||
|
||||
## Async/Generators
|
||||
|
||||
The [regenerator runtime](https://github.com/facebook/regenerator/blob/master/runtime.js)
|
||||
and an [ES6 polyfill](polyfill.md) are required in order for generators to work.
|
||||
|
||||
## Classes
|
||||
|
||||
Built-in classes such as `Date`, `Array` and `DOM` cannot be subclassed due to
|
||||
limitations in ES5 implementations.
|
||||
|
||||
If you're inheriting from a class then static properties are inherited from it
|
||||
via [\_\_proto\_\_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto),
|
||||
this is widely supported but you may run into problems with much older browsers.
|
||||
|
||||
**NOTE:** `__proto__` is not supported on IE <= 9 so static properties
|
||||
**will not** be inherited. A possible workaround is to use `super();`:
|
||||
|
||||
```javascript
|
||||
class Foo {
|
||||
static foo() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class Bar extends Foo {
|
||||
static foo() {
|
||||
super();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## For-of
|
||||
|
||||
A polyfill is required for for-of functionality that implements `Symbol` and
|
||||
adds `prototype[Symbol.iterator]` behaviour to built-ins. Using the polyfills
|
||||
specified in [polyfill](polyfill.md) suffices.
|
||||
|
||||
## Spread
|
||||
|
||||
An [ES6 polyfill](polyfill.md) is required in order for spread to work. More
|
||||
specifically a polyfill for `Array.from`.
|
||||
103
doc/differences.md
Normal file
103
doc/differences.md
Normal file
@@ -0,0 +1,103 @@
|
||||
# Differences
|
||||
|
||||
## Philosophy
|
||||
|
||||
The fundamental concept behind 6to5 is that the generated code must be close as
|
||||
possible to the original, retaining all the same formatting and readability.
|
||||
|
||||
Many other transpilers are just concerned with making the code work while 6to5
|
||||
is concerned with making sure it works **and** is readable at the same time.
|
||||
|
||||
For example, given the following array comprehension:
|
||||
|
||||
```javascript
|
||||
var seattlers = [for (c of customers) if (c.city == "Seattle") { name: c.name, age: c.age }];
|
||||
```
|
||||
|
||||
is generated to the following with 6to5:
|
||||
|
||||
```javascript
|
||||
var seattlers = customers.filter(function (c) {
|
||||
return c.city == "Seattle";
|
||||
}).map(function (c) {
|
||||
return {
|
||||
name: c.name,
|
||||
age: c.age
|
||||
};
|
||||
});
|
||||
```
|
||||
|
||||
The following is what Traceur generates:
|
||||
|
||||
```javascript
|
||||
var seattlers = (function() {
|
||||
var c;
|
||||
var $__20 = 0,
|
||||
$__21 = [];
|
||||
for (var $__22 = customers[$traceurRuntime.toProperty(Symbol.iterator)](),
|
||||
$__23; !($__23 = $__22.next()).done; ) {
|
||||
c = $__23.value;
|
||||
if (c.city == "Seattle")
|
||||
$traceurRuntime.setProperty($__21, $__20++, {
|
||||
name: c.name,
|
||||
age: c.age
|
||||
});
|
||||
}
|
||||
return $__21;
|
||||
}());
|
||||
```
|
||||
|
||||
As you can tell, it's not very pretty, unreadable even. Instead of mapping
|
||||
directly to a runtime, like other transpilers, 6to5 maps directly to the
|
||||
equivalent ES5.
|
||||
|
||||
I'm not saying 6to5 is for everyone or even suited for everything. Traceur is
|
||||
better suited if you'd like a full ES6 environment with polyfills and all.
|
||||
|
||||
## Comparison to other transpilers
|
||||
|
||||
| | 6to5 | Traceur | esnext | es6now | es6-transpiler | jstransform |
|
||||
| ---------------------------- | ---- | ------- | ------ | ------ | -------------- | ----------- |
|
||||
| No runtime | ✓ | | | | ✓ | ✓ |
|
||||
| Source maps | ✓ | ✓ | ✓ | | ✓ | ✓ |
|
||||
| No compiler global pollution | ✓ | | ✓ | | ✓ | ✓ |
|
||||
| Browser support | ✓ | ✓ | ✓ | | | |
|
||||
| Array comprehension | ✓ | ✓ | | | ✓ | |
|
||||
| Arrow functions | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Async functions | ✓ | ✓ | ✓ | | | |
|
||||
| Classes | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Computed property names | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| Constants | ✓ | ✓ | | | ✓ | |
|
||||
| Default parameters | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| Destructuring | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| For-of | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| Generators | ✓ | ✓ | ✓ | | | |
|
||||
| Generator comprehension | ✓ | ✓ | | | | |
|
||||
| Let scoping | ✓ | ✓ | | | ✓ | |
|
||||
| Modules | ✓ | ✓ | | ✓ | | |
|
||||
| Property method assignment | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Property name shorthand | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Rest parameters | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Spread | ✓ | ✓ | ✓ | ✓ | ✓ | |
|
||||
| Template literals | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
|
||||
| Unicode regex | ✓ | ✓ | | | ✓ | |
|
||||
|
||||
### [Traceur](https://github.com/google/traceur-compiler)
|
||||
|
||||
Traceur requires quite a bulky runtime (~75KB) and produces quite verbose code.
|
||||
While this can be trimmed down by selectively building the runtime, it's an
|
||||
unneccesary step when a runtime can be eliminated entirely.
|
||||
|
||||
### [es6now](https://github.com/zenparsing/es6now)
|
||||
|
||||
es6now doesn't output sourcemaps. This is cited as a positive as line-to-line
|
||||
mapping is the goal. This however obviously doesn't retain column mapping
|
||||
resulting in the output code not being very pleasant.
|
||||
|
||||
### [es6-transpiler](https://github.com/termi/es6-transpiler)
|
||||
|
||||
The es6-transpiler compiler requires shims to operate which pollutes the global
|
||||
scope resulting in possible collisions.
|
||||
|
||||
es6-transpiler maps line-by-line, just like es6now, this results in the same
|
||||
issues such as lack of column information and unpleasant code output.
|
||||
226
doc/features.md
Normal file
226
doc/features.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# Features
|
||||
|
||||
## Array comprehension
|
||||
|
||||
```javascript
|
||||
var results = [for (c of customers) if (c.city == "Seattle") { name: c.name, age: c.age }]
|
||||
```
|
||||
|
||||
## Arrow functions
|
||||
|
||||
```javascript
|
||||
// Expression bodies
|
||||
var odds = evens.map(v => v + 1);
|
||||
var nums = evens.map((v, i) => v + i);
|
||||
|
||||
// Statement bodies
|
||||
nums.forEach(v => {
|
||||
if (v % 5 === 0)
|
||||
fives.push(v);
|
||||
});
|
||||
|
||||
// Lexical this
|
||||
var bob = {
|
||||
_name: "Bob",
|
||||
_friends: [],
|
||||
printFriends() {
|
||||
this._friends.forEach(f => {
|
||||
console.log(this._name + " knows " + f);
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Async functions
|
||||
|
||||
```javascript
|
||||
async function chainAnimationsAsync(elem, animations) {
|
||||
for (var anim of animations) {
|
||||
await anim(elem);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Classes
|
||||
|
||||
```javascript
|
||||
class SkinnedMesh extends THREE.Mesh {
|
||||
constructor(geometry, materials) {
|
||||
super(geometry, materials);
|
||||
|
||||
this.idMatrix = SkinnedMesh.defaultMatrix();
|
||||
this.bones = [];
|
||||
this.boneMatrices = [];
|
||||
//...
|
||||
}
|
||||
|
||||
update(camera) {
|
||||
//...
|
||||
super.update();
|
||||
}
|
||||
|
||||
static defaultMatrix() {
|
||||
return new THREE.Matrix4();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Computed property names
|
||||
|
||||
```javascript
|
||||
var foo = "foo";
|
||||
var bar = "bar";
|
||||
var obj = {
|
||||
["foo" + bar]: "heh",
|
||||
["bar" + foo]: "noo",
|
||||
foo: "foo",
|
||||
bar: "bar"
|
||||
};
|
||||
```
|
||||
|
||||
## Constants
|
||||
|
||||
```javascript
|
||||
const MULTIPLIER = 5;
|
||||
console.log(2 * MULTIPLIER);
|
||||
|
||||
MULTIPLIER = 6; // error
|
||||
var MULTIPLIER; // error
|
||||
```
|
||||
|
||||
## Default parameters
|
||||
|
||||
```javascript
|
||||
function f(x, y = 12) {
|
||||
// y is 12 if not passed (or passed as undefined)
|
||||
return x + y;
|
||||
}
|
||||
f(3) == 15
|
||||
```
|
||||
|
||||
## Destructuring
|
||||
|
||||
```javascript
|
||||
// list matching
|
||||
var [a, , b] = [1,2,3];
|
||||
|
||||
// object matching
|
||||
var { op: a, lhs: { op: b }, rhs: c } = getASTNode();
|
||||
|
||||
// object matching shorthand
|
||||
// binds `op`, `lhs` and `rhs` in scope
|
||||
var { op, lhs, rhs } = getASTNode();
|
||||
|
||||
// Can be used in parameter position
|
||||
function g({ name: x }) {
|
||||
console.log(x);
|
||||
}
|
||||
g({ name: 5 });
|
||||
|
||||
// Fail-soft destructuring
|
||||
var [a] = [];
|
||||
a === undefined;
|
||||
```
|
||||
|
||||
## For-of
|
||||
|
||||
```javascript
|
||||
for (var i of [1, 2, 3]) {
|
||||
console.log(i * i);
|
||||
}
|
||||
```
|
||||
|
||||
## Generators
|
||||
|
||||
```javascript
|
||||
|
||||
```
|
||||
|
||||
## Generator comprehension
|
||||
|
||||
```javascript
|
||||
|
||||
```
|
||||
|
||||
## Let scoping
|
||||
|
||||
```javascript
|
||||
for (let i in arr) {
|
||||
let v = arr[i];
|
||||
}
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
```javascript
|
||||
|
||||
```
|
||||
|
||||
## Numeric literals
|
||||
|
||||
```javascript
|
||||
0b111110111 === 503; // true
|
||||
0o767 === 503; // true
|
||||
```
|
||||
|
||||
## Property method assignment
|
||||
|
||||
```javascript
|
||||
var obj = {
|
||||
foo() {
|
||||
return "foobar";
|
||||
},
|
||||
|
||||
get bar() {
|
||||
return this._bar;
|
||||
},
|
||||
|
||||
set bar(val) {
|
||||
this._bar = val;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Property name shorthand
|
||||
|
||||
```javascript
|
||||
function f(x, y) {
|
||||
return { x, y };
|
||||
}
|
||||
```
|
||||
|
||||
## Rest parameters
|
||||
|
||||
```javascript
|
||||
function f(x, ...y) {
|
||||
// y is an Array
|
||||
return x * y.length;
|
||||
}
|
||||
f(3, "hello", true) == 6
|
||||
```
|
||||
|
||||
## Spread
|
||||
|
||||
```javascript
|
||||
function f(x, y, z) {
|
||||
return x + y + z;
|
||||
}
|
||||
// Pass each elem of array as argument
|
||||
f(...[1,2,3]) == 6
|
||||
```
|
||||
|
||||
## Template literals
|
||||
|
||||
```javascript
|
||||
var x = 5;
|
||||
var y = 10;
|
||||
console.log(`${x} + ${y} = ${x + y}`); // "5 + 10 = 15"
|
||||
```
|
||||
|
||||
## Unicode regex
|
||||
|
||||
```javascript
|
||||
var string = 'foo💩bar';
|
||||
var match = string.match(/foo(.)bar/u);
|
||||
console.log(match[1]);
|
||||
```
|
||||
54
doc/index.md
Normal file
54
doc/index.md
Normal file
@@ -0,0 +1,54 @@
|
||||
**6to5** turns ES6+ code into vanilla ES5, so you can use next generation features **today.**
|
||||
|
||||
- **Readable** - formatting is retained if possible so your generated code is as similar as possible.
|
||||
- **Extensible** - with a large range of [plugins](plugins.md) and **browser support**.
|
||||
- **Lossless** - **source map support** so you can debug your compiled code with ease.
|
||||
- **Compact** - maps directly to the equivalent ES5 with **no runtime**[\*](caveats.md#generators).
|
||||
|
||||
## Installation
|
||||
|
||||
It's as easy as:
|
||||
|
||||
$ npm install -g 6to5
|
||||
|
||||
## Usage
|
||||
|
||||
Once you've installed 6to5, there are multiple paths you can take depending on
|
||||
how you want to use it.
|
||||
|
||||
6to5 will simply compile your ES6+ script to ES5 if you pass it as an argument
|
||||
to the command-line tool `6to5`:
|
||||
|
||||
$ 6to5 script.js
|
||||
|
||||
If you have a file written using ES6+ and you just want to run it, `6to5-node`
|
||||
has you covered:
|
||||
|
||||
$ 6to5-node script.js
|
||||
|
||||
And it doesn't end here! To see all the ways you can use 6to5, check out the
|
||||
[Usage](http://6to5.github.io/usage.html) page.
|
||||
|
||||
## [Features](features.md)
|
||||
|
||||
- [Array comprehension](features.md#array-comprehension)
|
||||
- [Async functions](features.md#async-functions) via [regenerator](https://github.com/facebook/regenerator)
|
||||
- [Arrow functions](features.md#arrow-functions)
|
||||
- [Classes](features.md#classes)
|
||||
- [Computed property names](features.md#computed-property-names)
|
||||
- [Constants](features.md#constants)
|
||||
- [Default parameters](features.md#default-parameters)
|
||||
- [Destructuring](features.md#destructuring)
|
||||
- [For-of](features.md#for-of)
|
||||
- [Generators](features.md#generators) via [regenerator](https://github.com/facebook/regenerator)
|
||||
- [Generator comprehension](features.md#generator-comprehension)
|
||||
- [Let scoping](features.md#let-scoping)
|
||||
- [Modules](features.md#modules)
|
||||
- [Numeric literals](features.md#numeric-literals)
|
||||
- [Property method assignment](features.md#property-method-assignment)
|
||||
- [Property name shorthand](features.md#property-name-shorthand)
|
||||
- [React/JSX](react.md)
|
||||
- [Rest parameters](features.md#rest-parameters)
|
||||
- [Spread](features.md#spread)
|
||||
- [Template literals](features.md#template-literals)
|
||||
- [Unicode regex](features.md#unicode-regex)
|
||||
@@ -66,7 +66,7 @@ export function bar() {
|
||||
**Out**
|
||||
|
||||
```javascript
|
||||
define(["exports", "foo"], function (exports, _foo) {
|
||||
define("filename", ["exports", "foo"], function (exports, _foo) {
|
||||
exports.bar = bar;
|
||||
|
||||
var foo = _foo.default;
|
||||
@@ -94,7 +94,7 @@ export function bar() {
|
||||
```javascript
|
||||
(function (factory) {
|
||||
if (typeof define === "function" && define.amd) {
|
||||
define(["exports", "foo"], factory);
|
||||
define("filename", ["exports", "foo"], factory);
|
||||
} else if (typeof exports !== "undefined") {
|
||||
factory(exports, require("foo"));
|
||||
}
|
||||
@@ -111,7 +111,6 @@ export function bar() {
|
||||
|
||||
### Ignore
|
||||
|
||||
|
||||
**In**
|
||||
|
||||
```javascript
|
||||
51
doc/optional-runtime.md
Normal file
51
doc/optional-runtime.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# Optional runtime
|
||||
|
||||
6to5 has a few helper functions that'll be placed at the top of the generated
|
||||
code if needed so it's not inlined multiple times throughout that file. This may
|
||||
become an issue if you have multiple files, especially when you're sending them
|
||||
to the browser. gzip alleviates most of this concern but it's still not ideal.
|
||||
|
||||
You can tell 6to5 to not place any declarations at the top of your files and
|
||||
instead just point them to a reference contained within the runtime.
|
||||
|
||||
Simply use the following option if you're using the [Node API](usage.md#node):
|
||||
|
||||
```javascript
|
||||
{
|
||||
runtime: true
|
||||
}
|
||||
```
|
||||
|
||||
or the following flag if you're using the [CLI](usage.md#cli):
|
||||
|
||||
$ 6to5 --runtime
|
||||
|
||||
Then just include the runtime before your generated code.
|
||||
|
||||
## Getting the runtime
|
||||
|
||||
You can get the runtime via either:
|
||||
|
||||
$ 6to5-runtime
|
||||
|
||||
or
|
||||
|
||||
```javascript
|
||||
require("6to5").runtime();
|
||||
```
|
||||
|
||||
or from an npm release in `runtime.js` from the 6to5 directory.
|
||||
|
||||
## Customising namespace
|
||||
|
||||
You can also customise the runtime namespace by passing an optional namespace
|
||||
argument:
|
||||
|
||||
```javascript
|
||||
require("6to5").runtime("myCustomNamespace");
|
||||
```
|
||||
|
||||
$ 6to5-runtime myCustomNamespace
|
||||
|
||||
See [Options - runtime](usage.md#options) for documentation on changing the
|
||||
reference in generated code.
|
||||
15
doc/plugins.md
Normal file
15
doc/plugins.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Plugins
|
||||
|
||||
- [Broccoli](https://github.com/very-geek/broccoli-6to5-transpiler)
|
||||
- [Browserify](https://github.com/6to5/6to5-browserify)
|
||||
- [Brunch](https://github.com/es128/6to5-brunch)
|
||||
- [Duo](https://github.com/bdo-labs/duo6to5)
|
||||
- [Connect](https://github.com/6to5/6to5-connect)
|
||||
- [Gulp](https://github.com/sindresorhus/gulp-6to5)
|
||||
- [Grunt](https://github.com/sindresorhus/grunt-6to5)
|
||||
- [Jade](https://github.com/Apoxx/jade-6to5)
|
||||
- [Jest](https://github.com/6to5/6to5-jest)
|
||||
- [Karma](https://github.com/shuhei/karma-6to5-preprocessor)
|
||||
- [Mocha](https://github.com/6to5/6to5-mocha)
|
||||
- [Rails](https://github.com/6to5/6to5-rails)
|
||||
- [webpack](https://github.com/Couto/6to5-loader)
|
||||
17
doc/polyfill.md
Normal file
17
doc/polyfill.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Polyfill
|
||||
|
||||
6to5 includes a polyfill that includes the
|
||||
[regenerator runtime](https://github.com/facebook/regenerator/blob/master/runtime.js) and the
|
||||
[es6-shim](https://github.com/paulmillr/es6-shim) and
|
||||
[es6-symbol](https://github.com/medikoo/es6-symbol) polyfills.
|
||||
|
||||
## Node
|
||||
|
||||
```javascript
|
||||
require("6to5/polyfill");
|
||||
```
|
||||
|
||||
## Browser
|
||||
|
||||
Available from the `browser-polyfill.js` file within the 6to5 directory of an
|
||||
npm release.
|
||||
16
doc/react.md
Normal file
16
doc/react.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# React/JSX
|
||||
|
||||
6to5 has built-in support for React v0.12. Tags are automatically transformed to
|
||||
their equivalent `React.createElement(...)` and `displayName` is automatically
|
||||
inferred and added to all `React.createClass` calls.
|
||||
|
||||
## Blacklist
|
||||
|
||||
To disable this behaviour add `react` to your blacklist:
|
||||
|
||||
```javascript
|
||||
to5.transform("code", { blacklist: ["react"] });
|
||||
```
|
||||
|
||||
|
||||
$ 6to5 --blacklist react
|
||||
172
doc/usage.md
Normal file
172
doc/usage.md
Normal file
@@ -0,0 +1,172 @@
|
||||
# Usage
|
||||
|
||||
## CLI
|
||||
|
||||
Compile the file `script.js` and output it to stdout.
|
||||
|
||||
$ 6to5 script.js
|
||||
|
||||
Compile the file `script.js` and output it to `script-compiled.js`.
|
||||
|
||||
$ 6to5 script.js --out-file script-compiled.js
|
||||
|
||||
Compile the file `script.js` and output it to `script-compiled.js` and save a
|
||||
source map to `script-compiled.js.map`.
|
||||
|
||||
$ 6to5 script.js --source-maps --out-file script-compiled.js
|
||||
|
||||
Compile the file `script.js` and output it to `script-compiled.js` with a source
|
||||
map embedded in a comment at the bottom.
|
||||
|
||||
$ 6to5 script.js --source-maps-inline --out-file script-compiled.js
|
||||
|
||||
Compile the entire `src` directory and output it to the `lib` directory.
|
||||
|
||||
$ 6to5 src --out-dir lib
|
||||
|
||||
Compile the entire `src` directory and output it to the one concatenated file.
|
||||
|
||||
$ 6to5 src --out-file script-compiled.js
|
||||
|
||||
Pipe a file in via stdin and output it to `script-compiled.js`
|
||||
|
||||
$ 6to5 --out-file script-compiled.js < script.js
|
||||
|
||||
### Node
|
||||
|
||||
Launch a repl.
|
||||
|
||||
$ 6to5-node
|
||||
|
||||
Evaluate code.
|
||||
|
||||
$ 6to5-node -e "class Test { }"
|
||||
|
||||
Compile and run `test.js`.
|
||||
|
||||
$ 6to5-node test
|
||||
|
||||
## Node
|
||||
|
||||
```javascript
|
||||
var to5 = require("6to5");
|
||||
```
|
||||
|
||||
### to5.transform(code, [opts]);
|
||||
|
||||
```javascript
|
||||
var result = to5.transform("code();", options);
|
||||
result.code;
|
||||
result.map;
|
||||
result.ast;
|
||||
```
|
||||
|
||||
### to5.transformFileSync(filename, [opts])
|
||||
|
||||
```javascript
|
||||
to5.transformFileSync("filename.js", options).code;
|
||||
```
|
||||
|
||||
### to5.transformFile(filename, [opts], callback)
|
||||
|
||||
```javascript
|
||||
to5.transformFile("filename.js", options, function (err, result) {
|
||||
result.code;
|
||||
});
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
```javascript
|
||||
{
|
||||
// Filename for use in errors etc.
|
||||
// Default: "unknown"
|
||||
filename: "filename",
|
||||
|
||||
// Filename relative to `sourceRoot`
|
||||
// Default: `filename` option.
|
||||
filenameRelative: "",
|
||||
|
||||
// List of transformers to EXCLUDE.
|
||||
// Run `6to5 --help` to see a full list of transformers.
|
||||
blacklist: [],
|
||||
|
||||
// List of transformers to ONLY use.
|
||||
// Run `6to5 --help` to see a full list of transformers.
|
||||
whitelist: [],
|
||||
|
||||
// Module formatter to use
|
||||
// Run `6to5 --help` to see a full list of module formatters.
|
||||
// Default: "common"
|
||||
modules: "common",
|
||||
|
||||
// If truthy, adds a `map` property to returned output.
|
||||
// If set to "inline", a comment with a sourceMappingURL directive is added to
|
||||
// the bottom of the returned code.
|
||||
// Default: false
|
||||
sourceMap: true,
|
||||
|
||||
// Set `file` on returned source map.
|
||||
// Default: `filenameRelative` option.
|
||||
sourceMapName: "filename",
|
||||
|
||||
// Set `sources[0]` on returned source map.
|
||||
// Default: `filenameRelative` option.
|
||||
sourceFileName: "filename",
|
||||
|
||||
// The root from which all sources are relative
|
||||
sourceRoot: "assets/scripts",
|
||||
|
||||
// Optional prefix for the AMD module formatter that will be prepend to the
|
||||
// filename on module definitions
|
||||
moduleRoot: "my-app",
|
||||
|
||||
// Optionally replace all 6to5 helper declarations with a referenece to this
|
||||
// variable. If set to `true` then the default namespace is used "to5Runtime".
|
||||
// Default: false
|
||||
runtime: true
|
||||
}
|
||||
```
|
||||
|
||||
### Require hook
|
||||
|
||||
All subsequent files required by node with the extensions `.es6` and `.js` will
|
||||
be transformed by 6to5. The polyfill specified in [Polyfill](polyfill.md) is
|
||||
also required.
|
||||
|
||||
```javascript
|
||||
require("6to5/register");
|
||||
```
|
||||
|
||||
**NOTE:** By default all requires to `node_modules` will be ignored. You can
|
||||
override this by passing an ignore regex via:
|
||||
|
||||
```javascript
|
||||
require("6to5/register")({
|
||||
// This will override `node_modules` ignoring - you can alternatively pass
|
||||
// a regex
|
||||
ignore: false
|
||||
});
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
```javascript
|
||||
require("6to5/register")({
|
||||
// Optional ignore regex - if any filenames **do** match this regex then they
|
||||
// aren't compiled
|
||||
ignore: /regex/,
|
||||
|
||||
// Optional only regex - if any filenames **don't** match this regex then they
|
||||
// aren't compiled
|
||||
only: /my_es6_folder/,
|
||||
|
||||
// See options above for usage
|
||||
whitelist: [],
|
||||
blacklist: [],
|
||||
|
||||
// This will remove the currently hooked extensions of .es6 and .js so you'll
|
||||
// have to add them back if you want them to be used again.
|
||||
extensions: [".js", ".es6"]
|
||||
});
|
||||
```
|
||||
@@ -2,13 +2,6 @@ var transform = module.exports = require("./transformation/transform");
|
||||
|
||||
transform.transform = transform;
|
||||
|
||||
transform.eval = function (code, opts) {
|
||||
opts = opts || {};
|
||||
opts.filename = opts.filename || "eval";
|
||||
opts.sourceMap = "inline";
|
||||
return eval(transform(code, opts).code);
|
||||
};
|
||||
|
||||
transform.run = function (code, opts) {
|
||||
opts = opts || {};
|
||||
opts.sourceMap = "inline";
|
||||
|
||||
@@ -18,7 +18,8 @@ function File(opts) {
|
||||
this.ast = {};
|
||||
}
|
||||
|
||||
File.declarations = ["extends", "class-props", "slice"];
|
||||
File.declarations = ["extends", "class-props", "slice", "apply-constructor",
|
||||
"tagged-template-literal"];
|
||||
|
||||
File.normaliseOptions = function (opts) {
|
||||
opts = _.cloneDeep(opts || {});
|
||||
@@ -30,12 +31,20 @@ File.normaliseOptions = function (opts) {
|
||||
sourceMap: false,
|
||||
filename: "unknown",
|
||||
modules: "common",
|
||||
runtime: false
|
||||
runtime: false,
|
||||
code: true
|
||||
});
|
||||
|
||||
// normalise windows path separators to unix
|
||||
opts.filename = opts.filename.replace(/\\/g, "/");
|
||||
|
||||
_.defaults(opts, {
|
||||
filenameRelative: opts.filename
|
||||
});
|
||||
|
||||
_.defaults(opts, {
|
||||
sourceFileName: opts.filename,
|
||||
sourceMapName: opts.filename
|
||||
sourceFileName: opts.filenameRelative,
|
||||
sourceMapName: opts.filenameRelative
|
||||
});
|
||||
|
||||
if (opts.runtime === true) {
|
||||
@@ -139,17 +148,27 @@ File.prototype.generate = function () {
|
||||
var opts = this.opts;
|
||||
var ast = this.ast;
|
||||
|
||||
if (!opts.code) {
|
||||
return {
|
||||
code: "",
|
||||
map: null,
|
||||
ast: ast
|
||||
};
|
||||
}
|
||||
|
||||
var result = generate(ast, opts, this.code);
|
||||
|
||||
if (this.shebang) {
|
||||
// add back shebang
|
||||
result.code = this.shebang + result.code;
|
||||
result.code = this.shebang + "\n" + result.code;
|
||||
}
|
||||
|
||||
if (opts.sourceMap === "inline") {
|
||||
result.code += "\n" + util.sourceMapToComment(result.map);
|
||||
}
|
||||
|
||||
result.ast = result;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
||||
125
lib/6to5/generation/buffer.js
Normal file
125
lib/6to5/generation/buffer.js
Normal file
@@ -0,0 +1,125 @@
|
||||
module.exports = Buffer;
|
||||
|
||||
var util = require("../util");
|
||||
var _ = require("lodash");
|
||||
|
||||
function Buffer(position, format) {
|
||||
this.position = position;
|
||||
this._indent = format.indent.base;
|
||||
this.format = format;
|
||||
this.buf = "";
|
||||
}
|
||||
|
||||
Buffer.prototype.get = function () {
|
||||
return util.trimRight(this.buf);
|
||||
};
|
||||
|
||||
Buffer.prototype.getIndent = function () {
|
||||
if (this.format.compact) {
|
||||
return "";
|
||||
} else {
|
||||
return util.repeat(this._indent, this.format.indent.style);
|
||||
}
|
||||
};
|
||||
|
||||
Buffer.prototype.indentSize = function () {
|
||||
return this.getIndent().length;
|
||||
};
|
||||
|
||||
Buffer.prototype.indent = function () {
|
||||
this._indent++;
|
||||
};
|
||||
|
||||
Buffer.prototype.dedent = function () {
|
||||
this._indent--;
|
||||
};
|
||||
|
||||
Buffer.prototype.semicolon = function () {
|
||||
if (this.format.semicolons) this.push(";");
|
||||
};
|
||||
|
||||
Buffer.prototype.ensureSemicolon = function () {
|
||||
if (!this.isLast(";")) this.semicolon();
|
||||
};
|
||||
|
||||
Buffer.prototype.rightBrace = function () {
|
||||
this.newline(true);
|
||||
this.push("}");
|
||||
};
|
||||
|
||||
Buffer.prototype.keyword = function (name) {
|
||||
this.push(name);
|
||||
this.push(" ");
|
||||
};
|
||||
|
||||
Buffer.prototype.space = function () {
|
||||
if (this.buf && !this.isLast([" ", "\n"])) {
|
||||
this.push(" ");
|
||||
}
|
||||
};
|
||||
|
||||
Buffer.prototype.removeLast = function (cha) {
|
||||
if (!this.isLast(cha)) return;
|
||||
|
||||
this.buf = this.buf.slice(0, -1);
|
||||
this.position.unshift(cha);
|
||||
};
|
||||
|
||||
Buffer.prototype.newline = function (i, removeLast) {
|
||||
if (!this.buf) return;
|
||||
if (this.format.compact) return;
|
||||
if (this.endsWith("{\n")) return;
|
||||
|
||||
if (_.isBoolean(i)) {
|
||||
removeLast = i;
|
||||
i = null;
|
||||
}
|
||||
|
||||
if (_.isNumber(i)) {
|
||||
if (this.endsWith(util.repeat(i, "\n"))) return;
|
||||
|
||||
var self = this;
|
||||
_.times(i, function () {
|
||||
self.newline(null, removeLast);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (removeLast && this.isLast("\n")) this.removeLast("\n");
|
||||
|
||||
this.removeLast(" ");
|
||||
this.buf = this.buf.replace(/\n +$/, "\n");
|
||||
this._push("\n");
|
||||
};
|
||||
|
||||
Buffer.prototype.push = function (str, noIndent) {
|
||||
if (this._indent && !noIndent && str !== "\n") {
|
||||
// we have an indent level and we aren't pushing a newline
|
||||
var indent = this.getIndent();
|
||||
|
||||
// replace all newlines with newlines with the indentation
|
||||
str = str.replace(/\n/g, "\n" + indent);
|
||||
|
||||
// we've got a newline before us so prepend on the indentation
|
||||
if (this.isLast("\n")) str = indent + str;
|
||||
}
|
||||
|
||||
this._push(str);
|
||||
};
|
||||
|
||||
Buffer.prototype._push = function (str) {
|
||||
this.position.push(str);
|
||||
this.buf += str;
|
||||
};
|
||||
|
||||
Buffer.prototype.endsWith = function (str) {
|
||||
return this.buf.slice(-str.length) === str;
|
||||
};
|
||||
|
||||
Buffer.prototype.isLast = function (cha, trimRight) {
|
||||
var buf = this.buf;
|
||||
if (trimRight) buf = util.trimRight(buf);
|
||||
|
||||
var chars = [].concat(cha);
|
||||
return _.contains(chars, _.last(buf));
|
||||
};
|
||||
@@ -8,6 +8,7 @@ module.exports.CodeGenerator = CodeGenerator;
|
||||
var Whitespace = require("./whitespace");
|
||||
var SourceMap = require("./source-map");
|
||||
var Position = require("./position");
|
||||
var Buffer = require("./buffer");
|
||||
var util = require("../util");
|
||||
var n = require("./node");
|
||||
var t = require("../types");
|
||||
@@ -16,165 +17,66 @@ var _ = require("lodash");
|
||||
function CodeGenerator(ast, opts, code) {
|
||||
opts = opts || {};
|
||||
|
||||
this.style = {
|
||||
semicolons: true,
|
||||
comments: true,
|
||||
compact: false,
|
||||
indent: {
|
||||
char: " ",
|
||||
width: 2
|
||||
}
|
||||
};
|
||||
|
||||
this.comments = ast.comments || [];
|
||||
this.tokens = ast.tokens || [];
|
||||
this.opts = opts;
|
||||
this.format = CodeGenerator.normaliseOptions(opts);
|
||||
this.ast = ast;
|
||||
this.buf = "";
|
||||
|
||||
this._indent = 0;
|
||||
|
||||
this.whitespace = new Whitespace(this.tokens, this.comments);
|
||||
this.position = new Position;
|
||||
this.map = new SourceMap(this.position, opts, code);
|
||||
this.buffer = new Buffer(this.position, this.format);
|
||||
}
|
||||
|
||||
_.each(Buffer.prototype, function (fn, key) {
|
||||
CodeGenerator.prototype[key] = function () {
|
||||
return fn.apply(this.buffer, arguments);
|
||||
};
|
||||
});
|
||||
|
||||
CodeGenerator.normaliseOptions = function (opts) {
|
||||
opts = opts.format || {};
|
||||
|
||||
opts = _.merge({
|
||||
parentheses: true,
|
||||
semicolons: true,
|
||||
comments: true,
|
||||
compact: false,
|
||||
indent: {
|
||||
adjustMultilineComment: true,
|
||||
style: " ",
|
||||
base: 0
|
||||
}
|
||||
}, opts);
|
||||
|
||||
return opts;
|
||||
};
|
||||
|
||||
CodeGenerator.generators = {
|
||||
arrayComprehensions: require("./generators/array-comprehensions"),
|
||||
templateLiterals: require("./generators/template-literals"),
|
||||
expressions: require("./generators/expressions"),
|
||||
statements: require("./generators/statements"),
|
||||
classes: require("./generators/classes"),
|
||||
methods: require("./generators/methods"),
|
||||
modules: require("./generators/modules"),
|
||||
types: require("./generators/types"),
|
||||
base: require("./generators/base"),
|
||||
jsx: require("./generators/jsx")
|
||||
templateLiterals: require("./generators/template-literals"),
|
||||
comprehensions: require("./generators/comprehensions"),
|
||||
expressions: require("./generators/expressions"),
|
||||
statements: require("./generators/statements"),
|
||||
classes: require("./generators/classes"),
|
||||
methods: require("./generators/methods"),
|
||||
modules: require("./generators/modules"),
|
||||
types: require("./generators/types"),
|
||||
base: require("./generators/base"),
|
||||
jsx: require("./generators/jsx")
|
||||
};
|
||||
|
||||
_.each(CodeGenerator.generators, function (generator) {
|
||||
_.extend(CodeGenerator.prototype, generator);
|
||||
});
|
||||
|
||||
CodeGenerator.prototype.newline = function (i, removeLast) {
|
||||
if (!this.buf) return;
|
||||
if (this.style.compact) return;
|
||||
if (this.endsWith("{\n")) return;
|
||||
|
||||
if (_.isBoolean(i)) {
|
||||
removeLast = i;
|
||||
i = null;
|
||||
}
|
||||
|
||||
if (_.isNumber(i)) {
|
||||
var self = this;
|
||||
_.times(i, function () {
|
||||
self.newline(null, removeLast);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (removeLast && this.isLast("\n")) this.removeLast("\n");
|
||||
|
||||
this.removeLast(" ");
|
||||
this.buf = this.buf.replace(/\n(\s+)$/, "\n");
|
||||
this._push("\n");
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.removeLast = function (cha) {
|
||||
if (!this.isLast(cha)) return;
|
||||
|
||||
this.buf = this.buf.slice(0, -1);
|
||||
this.position.unshift(cha);
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.semicolon = function () {
|
||||
if (this.style.semicolons) this.push(";");
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.ensureSemicolon = function () {
|
||||
if (!this.isLast(";")) this.semicolon();
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.rightBrace = function () {
|
||||
this.newline(true);
|
||||
this.push("}");
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.keyword = function (name) {
|
||||
this.push(name);
|
||||
this.push(" ");
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.space = function () {
|
||||
if (this.buf && !this.isLast([" ", "\n"])) {
|
||||
this.push(" ");
|
||||
}
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.push = function (str, noIndent) {
|
||||
if (this._indent && !noIndent && str !== "\n") {
|
||||
// we have an indent level and we aren't pushing a newline
|
||||
var indent = this.getIndent();
|
||||
|
||||
// replace all newlines with newlines with the indentation
|
||||
str = str.replace(/\n/g, "\n" + indent);
|
||||
|
||||
// we've got a newline before us so prepend on the indentation
|
||||
if (this.isLast("\n")) str = indent + str;
|
||||
}
|
||||
|
||||
this._push(str);
|
||||
};
|
||||
|
||||
CodeGenerator.prototype._push = function (str) {
|
||||
this.position.push(str);
|
||||
this.buf += str;
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.endsWith = function (str) {
|
||||
return this.buf.slice(-str.length) === str;
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.isLast = function (cha, trimRight) {
|
||||
var buf = this.buf;
|
||||
if (trimRight) buf = buf.trimRight();
|
||||
|
||||
var chars = [].concat(cha);
|
||||
return _.contains(chars, _.last(buf));
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.getIndent = function () {
|
||||
if (this.style.compact) {
|
||||
return "";
|
||||
} else {
|
||||
return util.repeat(this.indentSize(), this.style.indent.char);
|
||||
}
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.indentSize = function () {
|
||||
return this._indent * this.style.indent.width;
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.indent = function () {
|
||||
this._indent++;
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.dedent = function () {
|
||||
this._indent--;
|
||||
};
|
||||
|
||||
CodeGenerator.prototype.generate = function () {
|
||||
var ast = this.ast;
|
||||
|
||||
this.print(ast);
|
||||
|
||||
this.buf = this.buf.trimRight();
|
||||
|
||||
return {
|
||||
map: this.map.get(),
|
||||
ast: ast,
|
||||
code: this.buf
|
||||
code: this.buffer.get()
|
||||
};
|
||||
};
|
||||
|
||||
@@ -213,8 +115,6 @@ CodeGenerator.prototype.print = function (node, parent, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
var newline = function (leading) {
|
||||
var ignoreDuplicates = false;
|
||||
|
||||
if (!opts.statement && !n.isUserWhitespacable(node, parent)) {
|
||||
return;
|
||||
}
|
||||
@@ -237,7 +137,7 @@ CodeGenerator.prototype.print = function (node, parent, opts) {
|
||||
lines += needs(node, parent);
|
||||
}
|
||||
|
||||
self.newline(lines, ignoreDuplicates);
|
||||
self.newline(lines);
|
||||
};
|
||||
|
||||
if (this[node.type]) {
|
||||
@@ -353,8 +253,8 @@ CodeGenerator.prototype._getComments = function (key, node) {
|
||||
};
|
||||
|
||||
CodeGenerator.prototype._printComments = function (comments) {
|
||||
if (this.style.compact) return;
|
||||
if (!this.style.comments) return;
|
||||
if (this.format.compact) return;
|
||||
if (!this.format.comments) return;
|
||||
if (!comments || !comments.length) return;
|
||||
|
||||
var self = this;
|
||||
@@ -373,14 +273,16 @@ CodeGenerator.prototype._printComments = function (comments) {
|
||||
|
||||
//
|
||||
|
||||
var offset = comment.loc.start.column;
|
||||
if (offset) {
|
||||
var newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
|
||||
val = val.replace(newlineRegex, "\n");
|
||||
}
|
||||
if (comment.type === "Block" && self.format.indent.adjustMultilineComment) {
|
||||
var offset = comment.loc.start.column;
|
||||
if (offset) {
|
||||
var newlineRegex = new RegExp("\\n\\s{1," + offset + "}", "g");
|
||||
val = val.replace(newlineRegex, "\n");
|
||||
}
|
||||
|
||||
var indent = Math.max(self.indentSize(), column);
|
||||
val = val.replace(/\n/g, "\n" + util.repeat(indent));
|
||||
var indent = Math.max(self.indentSize(), column);
|
||||
val = val.replace(/\n/g, "\n" + util.repeat(indent));
|
||||
}
|
||||
|
||||
if (column === 0) {
|
||||
val = self.getIndent() + val;
|
||||
|
||||
@@ -30,3 +30,11 @@ exports.ClassBody = function (node, print) {
|
||||
this.rightBrace();
|
||||
}
|
||||
};
|
||||
|
||||
exports.MethodDefinition = function (node, print) {
|
||||
if (node.static) {
|
||||
this.push("static ");
|
||||
}
|
||||
|
||||
this._method(node, print);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,8 @@ exports.ComprehensionBlock = function (node, print) {
|
||||
};
|
||||
|
||||
exports.ComprehensionExpression = function (node, print) {
|
||||
this.push("[");
|
||||
this.push(node.generator ? "(" : "[");
|
||||
|
||||
print.join(node.blocks, { separator: " " });
|
||||
this.space();
|
||||
|
||||
@@ -21,5 +22,6 @@ exports.ComprehensionExpression = function (node, print) {
|
||||
}
|
||||
|
||||
print(node.body);
|
||||
this.push("]");
|
||||
|
||||
this.push(node.generator ? ")" : "]");
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
var t = require("../../types");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.UnaryExpression = function (node, print) {
|
||||
var hasSpace = /[a-z]$/.test(node.operator);
|
||||
@@ -44,9 +45,11 @@ exports.ConditionalExpression = function (node, print) {
|
||||
exports.NewExpression = function (node, print) {
|
||||
this.push("new ");
|
||||
print(node.callee);
|
||||
this.push("(");
|
||||
print.join(node.arguments, { separator: ", " });
|
||||
this.push(")");
|
||||
if (node.arguments.length || this.format.parentheses) {
|
||||
this.push("(");
|
||||
print.join(node.arguments, { separator: ", " });
|
||||
this.push(")");
|
||||
}
|
||||
};
|
||||
|
||||
exports.SequenceExpression = function (node, print) {
|
||||
@@ -64,15 +67,20 @@ exports.CallExpression = function (node, print) {
|
||||
this.push(")");
|
||||
};
|
||||
|
||||
exports.YieldExpression = function (node, print) {
|
||||
this.push("yield");
|
||||
if (node.delegate) this.push("*");
|
||||
if (node.argument) {
|
||||
this.space();
|
||||
print(node.argument);
|
||||
}
|
||||
var buildYieldAwait = function (keyword) {
|
||||
return function (node, print) {
|
||||
this.push(keyword);
|
||||
if (node.delegate) this.push("*");
|
||||
if (node.argument) {
|
||||
this.space();
|
||||
print(node.argument);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
exports.YieldExpression = buildYieldAwait("yield");
|
||||
exports.AwaitExpression = buildYieldAwait("await");
|
||||
|
||||
exports.EmptyStatement = function () {
|
||||
this.semicolon();
|
||||
};
|
||||
@@ -98,6 +106,11 @@ exports.MemberExpression = function (node, print) {
|
||||
print(node.property);
|
||||
this.push("]");
|
||||
} else {
|
||||
// 5..toFixed(2);
|
||||
if (t.isLiteral(node.object) && util.isInteger(node.object.value)) {
|
||||
this.push(".");
|
||||
}
|
||||
|
||||
this.push(".");
|
||||
print(node.property);
|
||||
}
|
||||
|
||||
@@ -46,15 +46,11 @@ exports.XJSElement = function (node, print) {
|
||||
|
||||
this.indent();
|
||||
_.each(node.children, function (child) {
|
||||
if (t.isLiteral(child) && typeof child.value === "string") {
|
||||
if (/\S/.test(child.value)) {
|
||||
return self.push(child.value.replace(/^\s+|\s+$/g, ""));
|
||||
} else if (/\n/.test(child.value)) {
|
||||
return self.newline();
|
||||
}
|
||||
if (t.isLiteral(child)) {
|
||||
self.push(child.value);
|
||||
} else {
|
||||
print(child);
|
||||
}
|
||||
|
||||
print(child);
|
||||
});
|
||||
this.dedent();
|
||||
|
||||
@@ -78,5 +74,5 @@ exports.XJSClosingElement = function (node, print) {
|
||||
};
|
||||
|
||||
exports.XJSEmptyExpression = function () {
|
||||
this.push("null");
|
||||
|
||||
};
|
||||
|
||||
@@ -41,6 +41,8 @@ exports._method = function (node, print) {
|
||||
this.push(kind + " ");
|
||||
}
|
||||
|
||||
if (value.async) this.push("async ");
|
||||
|
||||
if (node.computed) {
|
||||
this.push("[");
|
||||
print(key);
|
||||
@@ -54,16 +56,9 @@ exports._method = function (node, print) {
|
||||
print(value.body);
|
||||
};
|
||||
|
||||
exports.MethodDefinition = function (node, print) {
|
||||
if (node.static) {
|
||||
this.push("static ");
|
||||
}
|
||||
|
||||
this._method(node, print);
|
||||
};
|
||||
|
||||
exports.FunctionDeclaration =
|
||||
exports.FunctionExpression = function (node, print) {
|
||||
if (node.async) this.push("async ");
|
||||
this.push("function");
|
||||
if (node.generator) this.push("*");
|
||||
this.space();
|
||||
@@ -74,6 +69,8 @@ exports.FunctionExpression = function (node, print) {
|
||||
};
|
||||
|
||||
exports.ArrowFunctionExpression = function (node, print) {
|
||||
if (node.async) this.push("async ");
|
||||
|
||||
if (node.params.length === 1 && !node.defaults.length && !node.rest && t.isIdentifier(node.params[0])) {
|
||||
print(node.params[0]);
|
||||
} else {
|
||||
|
||||
@@ -25,9 +25,10 @@ exports.ExportDeclaration = function (node, print) {
|
||||
|
||||
if (node.declaration) {
|
||||
print(node.declaration);
|
||||
if (t.isStatement(node.declaration)) return;
|
||||
} else {
|
||||
if (specifiers.length === 1 && t.isExportBatchSpecifier(specifiers[0])) {
|
||||
this.push("*");
|
||||
print(specifiers[0]);
|
||||
} else {
|
||||
this.push("{");
|
||||
if (specifiers.length) {
|
||||
|
||||
@@ -4,6 +4,7 @@ exports.WithStatement = function (node, print) {
|
||||
this.keyword("with");
|
||||
this.push("(");
|
||||
print(node.object);
|
||||
this.push(")");
|
||||
print.block(node.body);
|
||||
};
|
||||
|
||||
@@ -134,15 +135,6 @@ exports.SwitchStatement = function (node, print) {
|
||||
this.push(") {");
|
||||
print.sequence(node.cases, { indent: true });
|
||||
this.push("}");
|
||||
|
||||
//if (node.cases.length) {
|
||||
// this.newline();
|
||||
// print.sequence(node.cases, { indent: true });
|
||||
// this.newline();
|
||||
// this.rightBrace();
|
||||
//} else {
|
||||
// this.push("}");
|
||||
//}
|
||||
};
|
||||
|
||||
exports.SwitchCase = function (node, print) {
|
||||
@@ -154,13 +146,8 @@ exports.SwitchCase = function (node, print) {
|
||||
this.push("default:");
|
||||
}
|
||||
|
||||
if (node.consequent.length === 1) {
|
||||
this.space();
|
||||
print(node.consequent[0]);
|
||||
} else if (node.consequent.length > 1) {
|
||||
this.newline();
|
||||
print.sequence(node.consequent, { indent: true });
|
||||
}
|
||||
this.space();
|
||||
print.sequence(node.consequent, { indent: true });
|
||||
};
|
||||
|
||||
exports.DebuggerStatement = function () {
|
||||
|
||||
@@ -74,13 +74,20 @@ exports.Literal = function (node) {
|
||||
var val = node.value;
|
||||
var type = typeof val;
|
||||
|
||||
if (type === "boolean" || type === "number" || type === "string") {
|
||||
if (type === "string") {
|
||||
val = JSON.stringify(val);
|
||||
|
||||
// escape unicode characters
|
||||
val = val.replace(/[\u007f-\uffff]/g, function(c) {
|
||||
return "\\u" + ("0000" + c.charCodeAt(0).toString(16)).slice(-4);
|
||||
});
|
||||
|
||||
this.push(val);
|
||||
} else if (type === "boolean" || type === "number") {
|
||||
this.push(JSON.stringify(val));
|
||||
} else if (node.regex) {
|
||||
this.push("/" + node.regex.pattern + "/" + node.regex.flags);
|
||||
} else if (val === null) {
|
||||
this.push("null");
|
||||
} else if (node.raw) {
|
||||
this.push(node.raw);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
module.exports = Node;
|
||||
|
||||
var t = require("../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
function Node(node, parent) {
|
||||
this.parent = parent;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
Node.whitespace = {
|
||||
FunctionExpression: 1,
|
||||
FunctionStatement: 1,
|
||||
ClassExpression: 1,
|
||||
ClassStatement: 1,
|
||||
ForOfStatement: 1,
|
||||
ForInStatement: 1,
|
||||
ForStatement: 1,
|
||||
SwitchStatement: 1,
|
||||
IfStatement: { before: 1 },
|
||||
//Property: { before: 1 },
|
||||
Literal: { after: 1 }
|
||||
};
|
||||
|
||||
_.each(Node.whitespace, function (amounts, type) {
|
||||
if (_.isNumber(amounts)) amounts = { after: amounts, before: amounts };
|
||||
Node.whitespace[type] = amounts;
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
Node.PRECEDENCE = {};
|
||||
|
||||
_.each([
|
||||
["||"],
|
||||
["&&"],
|
||||
["|"],
|
||||
["^"],
|
||||
["&"],
|
||||
["==", "===", "!=", "!=="],
|
||||
["<", ">", "<=", ">=", "in", "instanceof"],
|
||||
[">>", "<<", ">>>"],
|
||||
["+", "-"],
|
||||
["*", "/", "%"]
|
||||
], function (tier, i) {
|
||||
_.each(tier, function (op) {
|
||||
Node.PRECEDENCE[op] = i;
|
||||
});
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
Node.prototype.isUserWhitespacable = function () {
|
||||
//var parent = this.parent;
|
||||
var node = this.node;
|
||||
|
||||
if (t.isUserWhitespacable(node)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//if (t.isArrayExpression(parent)) {
|
||||
// return true;
|
||||
//}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Node.prototype.needsWhitespace = function (type) {
|
||||
var parent = this.parent;
|
||||
var node = this.node;
|
||||
if (!node) return 0;
|
||||
|
||||
if (t.isExpressionStatement(node)) {
|
||||
node = node.expression;
|
||||
}
|
||||
|
||||
if (type === "before") {
|
||||
if (t.isProperty(node) && parent.properties[0] === node) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (type === "after") {
|
||||
if (t.isCallExpression(node)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
var exprs = [];
|
||||
|
||||
if (t.isVariableDeclaration(node)) {
|
||||
exprs = _.map(node.declarations, "init");
|
||||
}
|
||||
|
||||
if (t.isArrayExpression(node)) {
|
||||
exprs = node.elements;
|
||||
}
|
||||
|
||||
if (t.isObjectExpression(node)) {
|
||||
exprs = node.properties;
|
||||
}
|
||||
|
||||
var lines = 0;
|
||||
|
||||
_.each(exprs, function (expr) {
|
||||
lines = Node.needsWhitespace(expr, node, type);
|
||||
if (lines) return false;
|
||||
});
|
||||
|
||||
if (lines) return lines;
|
||||
}
|
||||
|
||||
if (t.isCallExpression(node) && t.isFunction(node.callee)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
var opts = Node.whitespace[node.type];
|
||||
return (opts && opts[type]) || 0;
|
||||
};
|
||||
|
||||
Node.prototype.needsWhitespaceBefore = function () {
|
||||
return this.needsWhitespace("before");
|
||||
};
|
||||
|
||||
Node.prototype.needsWhitespaceAfter = function () {
|
||||
return this.needsWhitespace("after");
|
||||
};
|
||||
|
||||
Node.prototype.needsParens = function () {
|
||||
var parent = this.parent;
|
||||
var node = this.node;
|
||||
|
||||
if (!parent) return false;
|
||||
|
||||
//
|
||||
if (t.isUnaryLike(node)) {
|
||||
return t.isMemberExpression(parent) && parent.object === node;
|
||||
}
|
||||
|
||||
if (t.isBinary(node)) {
|
||||
//
|
||||
if (t.isCallExpression(parent) && parent.callee === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
if (t.isUnaryLike(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isBinary(parent)) {
|
||||
var parentOp = parent.operator;
|
||||
var parentPos = Node.PRECEDENCE[parentOp];
|
||||
|
||||
var nodeOp = node.operator;
|
||||
var nodePos = Node.PRECEDENCE[nodeOp];
|
||||
|
||||
if (parentPos > nodePos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parentPos === nodePos && parent.right === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isBinaryExpression(node) && node.operator === "in") {
|
||||
// var i = (1 in []);
|
||||
if (t.isVariableDeclarator(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// for ((1 in []);;);
|
||||
if (t.isFor(parent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// (class {});
|
||||
if (t.isClassExpression(node) && t.isExpressionStatement(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isSequenceExpression(node)) {
|
||||
if (t.isForStatement(parent)) {
|
||||
// Although parentheses wouldn't hurt around sequence
|
||||
// expressions in the head of for loops, traditional style
|
||||
// dictates that e.g. i++, j++ should not be wrapped with
|
||||
// parentheses.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t.isExpressionStatement(parent) && parent.expression === node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise err on the side of overparenthesization, adding
|
||||
// explicit exceptions above if this proves overzealous.
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
if (t.isYieldExpression(node)) {
|
||||
return t.isBinary(parent) ||
|
||||
t.isUnaryLike(parent) ||
|
||||
t.isCallExpression(parent) ||
|
||||
t.isMemberExpression(parent) ||
|
||||
t.isNewExpression(parent) ||
|
||||
t.isConditionalExpression(parent) ||
|
||||
t.isYieldExpression(parent);
|
||||
}
|
||||
|
||||
if (t.isNewExpression(parent) && parent.callee === node) {
|
||||
return t.isCallExpression(node) || _.some(node, function (val) {
|
||||
return t.isCallExpression(val);
|
||||
});
|
||||
}
|
||||
|
||||
// (1).valueOf()
|
||||
if (t.isLiteral(node) && _.isNumber(node.value) && t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isAssignmentExpression(node) || t.isConditionalExpression(node)) {
|
||||
//
|
||||
if (t.isUnaryLike(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
if (t.isBinary(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
if (t.isCallExpression(parent) && parent.callee === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
if (t.isConditionalExpression(parent) && parent.test === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (t.isFunctionExpression(node)) {
|
||||
// function () {};
|
||||
if (t.isExpressionStatement(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// (function test() {}).name;
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// (function () {})();
|
||||
if (t.isCallExpression(parent) && parent.callee === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// ({ x, y }) = { x: 5, y: 6 };
|
||||
if (t.isObjectPattern(node) && t.isAssignmentExpression(parent) && parent.left == node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
_.each(Node.prototype, function (fn, key) {
|
||||
Node[key] = function (node, parent) {
|
||||
var n = new Node(node, parent);
|
||||
|
||||
var args = _.toArray(arguments).slice(2);
|
||||
return n[key].apply(n, args);
|
||||
};
|
||||
});
|
||||
87
lib/6to5/generation/node/index.js
Normal file
87
lib/6to5/generation/node/index.js
Normal file
@@ -0,0 +1,87 @@
|
||||
module.exports = Node;
|
||||
|
||||
var whitespace = require("./whitespace");
|
||||
var parens = require("./parentheses");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var find = function (obj, node, parent) {
|
||||
var result;
|
||||
|
||||
_.each(obj, function (fn, type) {
|
||||
if (t["is" + type](node)) {
|
||||
result = fn(node, parent);
|
||||
if (result != null) return false;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
function Node(node, parent) {
|
||||
this.parent = parent;
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
Node.prototype.isUserWhitespacable = function () {
|
||||
var parent = this.parent;
|
||||
var node = this.node;
|
||||
|
||||
if (t.isUserWhitespacable(node) ||
|
||||
t.isSequenceExpression(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Node.prototype.needsWhitespace = function (type) {
|
||||
var parent = this.parent;
|
||||
var node = this.node;
|
||||
if (!node) return 0;
|
||||
|
||||
if (t.isExpressionStatement(node)) {
|
||||
node = node.expression;
|
||||
}
|
||||
|
||||
var lines = find(whitespace[type].nodes, node, parent);
|
||||
if (lines) return lines;
|
||||
|
||||
_.each(find(whitespace[type].list, node, parent), function (expr) {
|
||||
lines = Node.needsWhitespace(expr, node, type);
|
||||
if (lines) return false;
|
||||
});
|
||||
return lines || 0;
|
||||
};
|
||||
|
||||
Node.prototype.needsWhitespaceBefore = function () {
|
||||
return this.needsWhitespace("before");
|
||||
};
|
||||
|
||||
Node.prototype.needsWhitespaceAfter = function () {
|
||||
return this.needsWhitespace("after");
|
||||
};
|
||||
|
||||
Node.prototype.needsParens = function () {
|
||||
var parent = this.parent;
|
||||
var node = this.node;
|
||||
|
||||
if (!parent) return false;
|
||||
|
||||
if (t.isNewExpression(parent) && parent.callee === node) {
|
||||
return t.isCallExpression(node) || _.some(node, function (val) {
|
||||
return t.isCallExpression(val);
|
||||
});
|
||||
}
|
||||
|
||||
return find(parens, node, parent);
|
||||
};
|
||||
|
||||
_.each(Node.prototype, function (fn, key) {
|
||||
Node[key] = function (node, parent) {
|
||||
var n = new Node(node, parent);
|
||||
|
||||
var args = _.toArray(arguments).slice(2);
|
||||
return n[key].apply(n, args);
|
||||
};
|
||||
});
|
||||
150
lib/6to5/generation/node/parentheses.js
Normal file
150
lib/6to5/generation/node/parentheses.js
Normal file
@@ -0,0 +1,150 @@
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var PRECEDENCE = {};
|
||||
|
||||
_.each([
|
||||
["||"],
|
||||
["&&"],
|
||||
["|"],
|
||||
["^"],
|
||||
["&"],
|
||||
["==", "===", "!=", "!=="],
|
||||
["<", ">", "<=", ">=", "in", "instanceof"],
|
||||
[">>", "<<", ">>>"],
|
||||
["+", "-"],
|
||||
["*", "/", "%"]
|
||||
], function (tier, i) {
|
||||
_.each(tier, function (op) {
|
||||
PRECEDENCE[op] = i;
|
||||
});
|
||||
});
|
||||
|
||||
exports.Binary = function (node, parent) {
|
||||
if (t.isCallExpression(parent) && parent.callee === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isUnaryLike(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isBinary(parent)) {
|
||||
var parentOp = parent.operator;
|
||||
var parentPos = PRECEDENCE[parentOp];
|
||||
|
||||
var nodeOp = node.operator;
|
||||
var nodePos = PRECEDENCE[nodeOp];
|
||||
|
||||
if (parentPos > nodePos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (parentPos === nodePos && parent.right === node) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.BinaryExpression = function (node, parent) {
|
||||
if (node.operator === "in") {
|
||||
// var i = (1 in []);
|
||||
if (t.isVariableDeclarator(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// for ((1 in []);;);
|
||||
if (t.isFor(parent)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.SequenceExpression = function (node, parent) {
|
||||
if (t.isForStatement(parent)) {
|
||||
// Although parentheses wouldn't hurt around sequence
|
||||
// expressions in the head of for loops, traditional style
|
||||
// dictates that e.g. i++, j++ should not be wrapped with
|
||||
// parentheses.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (t.isExpressionStatement(parent) && parent.expression === node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise err on the side of overparenthesization, adding
|
||||
// explicit exceptions above if this proves overzealous.
|
||||
return true;
|
||||
};
|
||||
|
||||
exports.YieldExpression = function (node, parent) {
|
||||
return t.isBinary(parent) ||
|
||||
t.isUnaryLike(parent) ||
|
||||
t.isCallExpression(parent) ||
|
||||
t.isMemberExpression(parent) ||
|
||||
t.isNewExpression(parent) ||
|
||||
t.isConditionalExpression(parent) ||
|
||||
t.isYieldExpression(parent);
|
||||
};
|
||||
|
||||
exports.Literal = function (node, parent) {
|
||||
// (1).valueOf()
|
||||
if (_.isNumber(node.value) && t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
exports.ClassExpression = function (node, parent) {
|
||||
return t.isExpressionStatement(parent);
|
||||
};
|
||||
|
||||
exports.UnaryLike = function (node, parent) {
|
||||
return t.isMemberExpression(parent) && parent.object === node;
|
||||
};
|
||||
|
||||
exports.FunctionExpression = function (node, parent) {
|
||||
// function () {};
|
||||
if (t.isExpressionStatement(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// (function test() {}).name;
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// (function () {})();
|
||||
if (t.isCallExpression(parent) && parent.callee === node) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
exports.AssignmentExpression =
|
||||
exports.ConditionalExpression = function (node, parent) {
|
||||
if (t.isUnaryLike(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isBinary(parent)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isCallExpression(parent) && parent.callee === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isConditionalExpression(parent) && parent.test === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (t.isMemberExpression(parent) && parent.object === node) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
60
lib/6to5/generation/node/whitespace.js
Normal file
60
lib/6to5/generation/node/whitespace.js
Normal file
@@ -0,0 +1,60 @@
|
||||
var _ = require("lodash");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.before = {
|
||||
nodes: {
|
||||
Property: function (node, parent) {
|
||||
if (parent.properties[0] === node) {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
|
||||
SwitchCase: function (node, parent) {
|
||||
if (parent.cases[0] === node) {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
|
||||
CallExpression: function (node) {
|
||||
if (t.isFunction(node.callee)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
exports.after = {
|
||||
nodes: {},
|
||||
|
||||
list: {
|
||||
VariableDeclaration: function (node) {
|
||||
return _.map(node.declarations, "init");
|
||||
},
|
||||
|
||||
ArrayExpression: function (node) {
|
||||
return node.elements;
|
||||
},
|
||||
|
||||
ObjectExpression: function (node) {
|
||||
return node.properties;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_.each({
|
||||
Function: 1,
|
||||
Class: 1,
|
||||
For: 1,
|
||||
SwitchStatement: 1,
|
||||
IfStatement: { before: 1 },
|
||||
CallExpression: { after: 1 },
|
||||
Literal: { after: 1 }
|
||||
}, function (amounts, type) {
|
||||
if (_.isNumber(amounts)) amounts = { after: amounts, before: amounts };
|
||||
|
||||
_.each(amounts, function (amount, key) {
|
||||
exports[key].nodes[type] = function () {
|
||||
return amount;
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -9,7 +9,8 @@ function SourceMap(position, opts, code) {
|
||||
|
||||
if (opts.sourceMap) {
|
||||
this.map = new sourceMap.SourceMapGenerator({
|
||||
file: opts.sourceMapName
|
||||
file: opts.sourceMapName,
|
||||
sourceRoot: opts.sourceRoot
|
||||
});
|
||||
|
||||
this.map.setSourceContent(opts.sourceFileName, code);
|
||||
|
||||
@@ -36,6 +36,7 @@ var blacklistTest = function (transformer, code) {
|
||||
};
|
||||
|
||||
blacklistTest("arrayComprehension", "var foo = [for (foo of bar) foo * foo];");
|
||||
//blacklistTest("generatorComprehension", "");
|
||||
blacklistTest("arrowFunctions", "var foo = x => x * x;");
|
||||
blacklistTest("classes", "class Foo {}");
|
||||
blacklistTest("computedPropertyNames", "var foo = { [foo]: bar };");
|
||||
|
||||
@@ -5,7 +5,7 @@ var t = require("./types");
|
||||
var _ = require("lodash");
|
||||
|
||||
module.exports = function (namespace) {
|
||||
namespace = t.identifier(namespace || "to5Runtime");
|
||||
namespace = t.identifier(t.toIdentifier(namespace || "to5Runtime"));
|
||||
|
||||
var body = [];
|
||||
var container = t.functionExpression(null, [], t.blockStatement(body));
|
||||
|
||||
5
lib/6to5/templates/apply-constructor.js
Normal file
5
lib/6to5/templates/apply-constructor.js
Normal file
@@ -0,0 +1,5 @@
|
||||
(function (Constructor, args) {
|
||||
var bindArgs = [null].concat(args);
|
||||
var Factory = Constructor.bind.apply(Constructor, bindArgs);
|
||||
return new Factory;
|
||||
});
|
||||
4
lib/6to5/templates/tagged-template-literal.js
Normal file
4
lib/6to5/templates/tagged-template-literal.js
Normal file
@@ -0,0 +1,4 @@
|
||||
(function (strings, raw) {
|
||||
return Object.defineProperties(strings, { raw: { value: raw } });
|
||||
});
|
||||
|
||||
@@ -29,12 +29,41 @@ AMDFormatter.prototype.transform = function (ast) {
|
||||
var params = _.values(this.ids);
|
||||
params.unshift(t.identifier("exports"));
|
||||
|
||||
var moduleName = this.getModuleName();
|
||||
|
||||
var container = t.functionExpression(null, params, t.blockStatement(body));
|
||||
var call = t.callExpression(t.identifier("define"), [names, container]);
|
||||
var call = t.callExpression(t.identifier("define"), [t.literal(moduleName), names, container]);
|
||||
|
||||
program.body = [t.expressionStatement(call)];
|
||||
};
|
||||
|
||||
AMDFormatter.prototype.getModuleName = function () {
|
||||
var opts = this.file.opts;
|
||||
var filenameRelative = opts.filenameRelative;
|
||||
var moduleName = "";
|
||||
|
||||
if (opts.moduleRoot) {
|
||||
moduleName = opts.moduleRoot + "/";
|
||||
}
|
||||
|
||||
if (!opts.filenameRelative) {
|
||||
return moduleName + opts.filename.replace(/^\//, "");
|
||||
}
|
||||
|
||||
if (opts.sourceRoot) {
|
||||
// remove sourceRoot from filename
|
||||
var sourceRootRegEx = new RegExp("^" + opts.sourceRoot + "\/?");
|
||||
filenameRelative = filenameRelative.replace(sourceRootRegEx, "");
|
||||
}
|
||||
|
||||
// remove extension
|
||||
filenameRelative = filenameRelative.replace(/\.(.*?)$/, "");
|
||||
|
||||
moduleName += filenameRelative;
|
||||
|
||||
return moduleName;
|
||||
};
|
||||
|
||||
AMDFormatter.prototype._push = function (node) {
|
||||
var id = node.source.value;
|
||||
var ids = this.ids;
|
||||
|
||||
@@ -32,8 +32,10 @@ UMDFormatter.prototype.transform = function (ast) {
|
||||
|
||||
// runner
|
||||
|
||||
var moduleName = this.getModuleName();
|
||||
|
||||
var runner = util.template("umd-runner-body", {
|
||||
AMD_ARGUMENTS: t.arrayExpression([t.literal("exports")].concat(names)),
|
||||
AMD_ARGUMENTS: [t.literal(moduleName), t.arrayExpression([t.literal("exports")].concat(names))],
|
||||
|
||||
COMMON_ARGUMENTS: names.map(function (name) {
|
||||
return t.callExpression(t.identifier("require"), [name]);
|
||||
|
||||
@@ -27,38 +27,39 @@ transform.moduleFormatters = {
|
||||
};
|
||||
|
||||
_.each({
|
||||
modules: require("./transformers/modules"),
|
||||
propertyNameShorthand: require("./transformers/property-name-shorthand"),
|
||||
constants: require("./transformers/constants"),
|
||||
arrayComprehension: require("./transformers/array-comprehension"),
|
||||
arrowFunctions: require("./transformers/arrow-functions"),
|
||||
classes: require("./transformers/classes"),
|
||||
modules: require("./transformers/modules"),
|
||||
propertyNameShorthand: require("./transformers/property-name-shorthand"),
|
||||
arrayComprehension: require("./transformers/array-comprehension"),
|
||||
generatorComprehension: require("./transformers/generator-comprehension"),
|
||||
arrowFunctions: require("./transformers/arrow-functions"),
|
||||
classes: require("./transformers/classes"),
|
||||
|
||||
_propertyLiterals: require("./transformers/_property-literals"),
|
||||
computedPropertyNames: require("./transformers/computed-property-names"),
|
||||
_propertyLiterals: require("./transformers/_property-literals"),
|
||||
computedPropertyNames: require("./transformers/computed-property-names"),
|
||||
|
||||
spread: require("./transformers/spread"),
|
||||
templateLiterals: require("./transformers/template-literals"),
|
||||
propertyMethodAssignment: require("./transformers/property-method-assignment"),
|
||||
defaultParameters: require("./transformers/default-parameters"),
|
||||
restParameters: require("./transformers/rest-parameters"),
|
||||
destructuring: require("./transformers/destructuring"),
|
||||
letScoping: require("./transformers/let-scoping"),
|
||||
forOf: require("./transformers/for-of"),
|
||||
unicodeRegex: require("./transformers/unicode-regex"),
|
||||
generators: require("./transformers/generators"),
|
||||
numericLiterals: require("./transformers/numeric-literals"),
|
||||
spread: require("./transformers/spread"),
|
||||
templateLiterals: require("./transformers/template-literals"),
|
||||
propertyMethodAssignment: require("./transformers/property-method-assignment"),
|
||||
defaultParameters: require("./transformers/default-parameters"),
|
||||
restParameters: require("./transformers/rest-parameters"),
|
||||
destructuring: require("./transformers/destructuring"),
|
||||
forOf: require("./transformers/for-of"),
|
||||
unicodeRegex: require("./transformers/unicode-regex"),
|
||||
|
||||
react: require("./transformers/react"),
|
||||
jsx: require("./transformers/jsx"),
|
||||
constants: require("./transformers/constants"),
|
||||
letScoping: require("./transformers/let-scoping"),
|
||||
|
||||
_aliasFunctions: require("./transformers/_alias-functions"),
|
||||
_blockHoist: require("./transformers/_block-hoist"),
|
||||
_declarations: require("./transformers/_declarations"),
|
||||
react: require("./transformers/react"),
|
||||
|
||||
useStrict: require("./transformers/use-strict"),
|
||||
_aliasFunctions: require("./transformers/_alias-functions"),
|
||||
_blockHoist: require("./transformers/_block-hoist"),
|
||||
_declarations: require("./transformers/_declarations"),
|
||||
|
||||
_moduleFormatter: require("./transformers/_module-formatter")
|
||||
generators: require("./transformers/generators"),
|
||||
useStrict: require("./transformers/use-strict"),
|
||||
|
||||
_memberExpressionKeywords: require("./transformers/_member-expression-keywords"),
|
||||
_moduleFormatter: require("./transformers/_module-formatter")
|
||||
}, function (transformer, key) {
|
||||
transform.transformers[key] = new Transformer(key, transformer);
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@ Transformer.normalise = function (transformer) {
|
||||
}
|
||||
|
||||
_.each(transformer, function (fns, type) {
|
||||
if (type[0] === "_") return;
|
||||
if (_.isFunction(fns)) fns = { enter: fns };
|
||||
transformer[type] = fns;
|
||||
});
|
||||
|
||||
@@ -14,10 +14,9 @@ var go = function (getBody, node, file, scope) {
|
||||
};
|
||||
|
||||
// traverse the function and find all alias functions so we can alias
|
||||
// arguments and this if necessary
|
||||
// `arguments` and `this` if necessary
|
||||
traverse(node, function (node) {
|
||||
var _aliasFunction = node._aliasFunction;
|
||||
if (!_aliasFunction) {
|
||||
if (!node._aliasFunction) {
|
||||
if (t.isFunction(node)) {
|
||||
// stop traversal of this node as it'll be hit again by this transformer
|
||||
return false;
|
||||
@@ -26,12 +25,10 @@ var go = function (getBody, node, file, scope) {
|
||||
}
|
||||
}
|
||||
|
||||
// traverse all child nodes of this function and find arguments and this
|
||||
// traverse all child nodes of this function and find `arguments` and `this`
|
||||
traverse(node, function (node, parent) {
|
||||
if (_aliasFunction === "arrows") {
|
||||
if (t.isFunction(node) && node._aliasFunction !== "arrows") {
|
||||
return false;
|
||||
}
|
||||
if (t.isFunction(node) && !node._aliasFunction) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node._ignoreAliasFunctions) return;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
var esutils = require("esutils");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.MemberExpression = function (node) {
|
||||
var prop = node.property;
|
||||
if (t.isIdentifier(prop) && esutils.keyword.isKeywordES6(prop.name, true)) {
|
||||
node.property = t.literal(prop.name);
|
||||
node.computed = true;
|
||||
}
|
||||
};
|
||||
@@ -1,10 +1,11 @@
|
||||
var esutils = require("esutils");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.Property = function (node) {
|
||||
// ignore key literals that are valid identifiers
|
||||
var key = node.key;
|
||||
if (t.isLiteral(key) && esutils.keyword.isIdentifierName(key.value)) {
|
||||
if (t.isLiteral(key) && _.isString(key.value) && esutils.keyword.isIdentifierName(key.value)) {
|
||||
key.type = "Identifier";
|
||||
key.name = key.value;
|
||||
delete key.value;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var singleArrayExpression = function (node) {
|
||||
var block = node.blocks[0];
|
||||
@@ -13,7 +14,13 @@ var singleArrayExpression = function (node) {
|
||||
ARRAY: block.right,
|
||||
KEY: block.left
|
||||
});
|
||||
result._aliasFunction = true;
|
||||
|
||||
_.each([result.callee.object, result], function (call) {
|
||||
if (t.isCallExpression(call)) {
|
||||
call.arguments[0]._aliasFunction = true;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -23,46 +30,49 @@ var multiple = function (node, file) {
|
||||
var container = util.template("array-comprehension-container", {
|
||||
KEY: uid
|
||||
});
|
||||
container._aliasFunction = true;
|
||||
container.callee.expression._aliasFunction = true;
|
||||
|
||||
var block = container.callee.expression.body;
|
||||
var body = block.body;
|
||||
|
||||
var returnStatement = body.pop();
|
||||
|
||||
var build = function () {
|
||||
var self = node.blocks.shift();
|
||||
if (!self) return;
|
||||
|
||||
var child = build();
|
||||
if (!child) {
|
||||
// last item
|
||||
|
||||
child = util.template("array-push", {
|
||||
STATEMENT: node.body,
|
||||
KEY: uid
|
||||
}, true);
|
||||
|
||||
// add a filter as this is our final stop
|
||||
if (node.filter) {
|
||||
child = t.ifStatement(node.filter, t.blockStatement([child]));
|
||||
}
|
||||
}
|
||||
|
||||
return t.forOfStatement(
|
||||
t.variableDeclaration("var", [t.variableDeclarator(self.left)]),
|
||||
self.right,
|
||||
t.blockStatement([child])
|
||||
);
|
||||
};
|
||||
|
||||
body.push(build());
|
||||
body.push(exports._build(node, function () {
|
||||
return util.template("array-push", {
|
||||
STATEMENT: node.body,
|
||||
KEY: uid
|
||||
}, true);
|
||||
}));
|
||||
body.push(returnStatement);
|
||||
|
||||
return container;
|
||||
};
|
||||
|
||||
exports._build = function (node, buildBody) {
|
||||
var self = node.blocks.shift();
|
||||
if (!self) return;
|
||||
|
||||
var child = exports._build(node, buildBody);
|
||||
if (!child) {
|
||||
// last item
|
||||
child = buildBody();
|
||||
|
||||
// add a filter as this is our final stop
|
||||
if (node.filter) {
|
||||
child = t.ifStatement(node.filter, t.blockStatement([child]));
|
||||
}
|
||||
}
|
||||
|
||||
return t.forOfStatement(
|
||||
t.variableDeclaration("var", [t.variableDeclarator(self.left)]),
|
||||
self.right,
|
||||
t.blockStatement([child])
|
||||
);
|
||||
};
|
||||
|
||||
exports.ComprehensionExpression = function (node, parent, file) {
|
||||
if (node.generator) return;
|
||||
|
||||
if (node.blocks.length === 1 && t.isArrayExpression(node.blocks[0].right)) {
|
||||
return singleArrayExpression(node);
|
||||
} else {
|
||||
|
||||
@@ -3,7 +3,7 @@ var t = require("../../types");
|
||||
exports.ArrowFunctionExpression = function (node) {
|
||||
t.ensureBlock(node);
|
||||
|
||||
node._aliasFunction = "arrows";
|
||||
node._aliasFunction = true;
|
||||
node.expression = false;
|
||||
node.type = "FunctionExpression";
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@ var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.ClassDeclaration = function (node, parent, file, scope) {
|
||||
return t.variableDeclaration("var", [
|
||||
t.variableDeclarator(node.id, buildClass(node, file, scope))
|
||||
return t.variableDeclaration("let", [
|
||||
t.variableDeclarator(node.id, new Class(node, file, scope).run())
|
||||
]);
|
||||
};
|
||||
|
||||
exports.ClassExpression = function (node, parent, file, scope) {
|
||||
return buildClass(node, file, scope);
|
||||
return new Class(node, file, scope).run();
|
||||
};
|
||||
|
||||
var getMemberExpressionObject = function (node) {
|
||||
@@ -20,31 +20,59 @@ var getMemberExpressionObject = function (node) {
|
||||
return node;
|
||||
};
|
||||
|
||||
var buildClass = function (node, file, scope) {
|
||||
var superName = node.superClass;
|
||||
var className = node.id || t.identifier(file.generateUid("class", scope));
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @param {Node} node
|
||||
* @param {File} file
|
||||
* @param {Scope} scope
|
||||
*/
|
||||
|
||||
var superClassArgument = node.superClass;
|
||||
var superClassCallee = node.superClass;
|
||||
function Class(node, file, scope) {
|
||||
this.scope = scope;
|
||||
this.node = node;
|
||||
this.file = file;
|
||||
|
||||
this.instanceMutatorMap = {};
|
||||
this.staticMutatorMap = {};
|
||||
this.hasConstructor = false;
|
||||
this.className = node.id || t.identifier(file.generateUid("class", scope));
|
||||
this.superName = node.superClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
|
||||
Class.prototype.run = function () {
|
||||
var superClassArgument = this.superName;
|
||||
var superClassCallee = this.superName;
|
||||
var superName = this.superName;
|
||||
var className = this.className;
|
||||
var file = this.file;
|
||||
|
||||
if (superName) {
|
||||
if (t.isMemberExpression(superName)) {
|
||||
superClassArgument = superClassCallee = getMemberExpressionObject(superName);
|
||||
} else if (!t.isIdentifier(superName)) {
|
||||
superClassArgument = superName;
|
||||
superClassCallee = superName = t.identifier(file.generateUid("ref", scope));
|
||||
superClassCallee = superName = t.identifier(file.generateUid("ref", this.scope));
|
||||
}
|
||||
}
|
||||
|
||||
this.superName = superName;
|
||||
|
||||
var container = util.template("class", {
|
||||
CLASS_NAME: className
|
||||
});
|
||||
|
||||
var block = container.callee.expression.body;
|
||||
var body = block.body;
|
||||
var constructor = body[0].declarations[0].init;
|
||||
var body = this.body = block.body;
|
||||
var constructor = this.constructor = body[0].declarations[0].init;
|
||||
|
||||
if (node.id) constructor.id = className;
|
||||
if (this.node.id) constructor.id = className;
|
||||
|
||||
var returnStatement = body.pop();
|
||||
|
||||
@@ -55,14 +83,7 @@ var buildClass = function (node, file, scope) {
|
||||
container.callee.expression.params.push(superClassCallee);
|
||||
}
|
||||
|
||||
buildClassBody({
|
||||
file: file,
|
||||
body: body,
|
||||
node: node,
|
||||
className: className,
|
||||
superName: superName,
|
||||
constructor: constructor,
|
||||
});
|
||||
this.buildBody();
|
||||
|
||||
if (body.length === 1) {
|
||||
// only a constructor so no need for a closure container
|
||||
@@ -73,49 +94,29 @@ var buildClass = function (node, file, scope) {
|
||||
}
|
||||
};
|
||||
|
||||
var buildClassBody = function (opts) {
|
||||
var file = opts.file;
|
||||
var body = opts.body;
|
||||
var node = opts.node;
|
||||
var constructor = opts.constructor;
|
||||
var className = opts.className;
|
||||
var superName = opts.superName;
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
|
||||
var instanceMutatorMap = {};
|
||||
var staticMutatorMap = {};
|
||||
var hasConstructor = false;
|
||||
|
||||
var classBody = node.body.body;
|
||||
Class.prototype.buildBody = function () {
|
||||
var constructor = this.constructor;
|
||||
var className = this.className;
|
||||
var superName = this.superName;
|
||||
var classBody = this.node.body.body;
|
||||
var body = this.body;
|
||||
var self = this;
|
||||
|
||||
_.each(classBody, function (node) {
|
||||
var methodName = node.key;
|
||||
var method = node.value;
|
||||
|
||||
replaceInstanceSuperReferences(superName, node);
|
||||
self.replaceInstanceSuperReferences(node);
|
||||
|
||||
if (node.key.name === "constructor") {
|
||||
if (node.kind === "") {
|
||||
hasConstructor = true;
|
||||
addConstructor(constructor, method);
|
||||
} else {
|
||||
throw file.errorWithNode(node, "illegal kind for constructor method");
|
||||
}
|
||||
self.pushConstructor(node);
|
||||
} else {
|
||||
var mutatorMap = instanceMutatorMap;
|
||||
if (node.static) mutatorMap = staticMutatorMap;
|
||||
|
||||
var kind = node.kind;
|
||||
|
||||
if (kind === "") {
|
||||
kind = "value";
|
||||
util.pushMutatorMap(mutatorMap, methodName, "writable", t.identifier("true"));
|
||||
}
|
||||
|
||||
util.pushMutatorMap(mutatorMap, methodName, kind, node);
|
||||
self.pushMethod(node);
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasConstructor && superName) {
|
||||
if (!this.hasConstructor && superName) {
|
||||
constructor.body.body.push(util.template("class-super-constructor-call", {
|
||||
SUPER_NAME: superName
|
||||
}, true));
|
||||
@@ -124,16 +125,16 @@ var buildClassBody = function (opts) {
|
||||
var instanceProps;
|
||||
var staticProps;
|
||||
|
||||
if (!_.isEmpty(instanceMutatorMap)) {
|
||||
if (!_.isEmpty(this.instanceMutatorMap)) {
|
||||
var protoId = util.template("prototype-identifier", {
|
||||
CLASS_NAME: className
|
||||
});
|
||||
|
||||
instanceProps = util.buildDefineProperties(instanceMutatorMap, protoId);
|
||||
instanceProps = util.buildDefineProperties(this.instanceMutatorMap, protoId);
|
||||
}
|
||||
|
||||
if (!_.isEmpty(staticMutatorMap)) {
|
||||
staticProps = util.buildDefineProperties(staticMutatorMap, className);
|
||||
if (!_.isEmpty(this.staticMutatorMap)) {
|
||||
staticProps = util.buildDefineProperties(this.staticMutatorMap, className);
|
||||
}
|
||||
|
||||
if (instanceProps || staticProps) {
|
||||
@@ -143,17 +144,50 @@ var buildClassBody = function (opts) {
|
||||
if (instanceProps) args.push(instanceProps);
|
||||
|
||||
body.push(t.expressionStatement(
|
||||
t.callExpression(file.addDeclaration("class-props"), args)
|
||||
t.callExpression(this.file.addDeclaration("class-props"), args)
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
var superIdentifier = function (superName, methodNode, node, parent) {
|
||||
var methodName = methodNode.key;
|
||||
/**
|
||||
* Push a method to it's respective mutatorMap.
|
||||
*
|
||||
* @param {Node} node MethodDefinition
|
||||
*/
|
||||
|
||||
if (parent.property === node) {
|
||||
Class.prototype.pushMethod = function (node) {
|
||||
var methodName = node.key;
|
||||
|
||||
var mutatorMap = this.instanceMutatorMap;
|
||||
if (node.static) mutatorMap = this.staticMutatorMap;
|
||||
|
||||
var kind = node.kind;
|
||||
|
||||
if (kind === "") {
|
||||
kind = "value";
|
||||
util.pushMutatorMap(mutatorMap, methodName, "writable", t.identifier("true"));
|
||||
}
|
||||
|
||||
util.pushMutatorMap(mutatorMap, methodName, kind, node);
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a `methodNode`, produce a `MemberExpression` super class reference.
|
||||
*
|
||||
* @param {Node} methodNode MethodDefinition
|
||||
* @param {Node} node Identifier
|
||||
* @param {Node} parent
|
||||
*
|
||||
* @returns {Node}
|
||||
*/
|
||||
|
||||
Class.prototype.superIdentifier = function (methodNode, id, parent) {
|
||||
var methodName = methodNode.key;
|
||||
var superName = this.superName || t.identifier("Function");
|
||||
|
||||
if (parent.property === id) {
|
||||
return;
|
||||
} else if (t.isCallExpression(parent, { callee: node })) {
|
||||
} else if (t.isCallExpression(parent, { callee: id })) {
|
||||
// super(); -> ClassName.prototype.MethodName.call(this);
|
||||
parent.arguments.unshift(t.thisExpression());
|
||||
|
||||
@@ -161,15 +195,15 @@ var superIdentifier = function (superName, methodNode, node, parent) {
|
||||
// constructor() { super(); }
|
||||
return t.memberExpression(superName, t.identifier("call"));
|
||||
} else {
|
||||
node = superName;
|
||||
id = superName;
|
||||
|
||||
// foo() { super(); }
|
||||
if (!methodNode.static) {
|
||||
node = t.memberExpression(node, t.identifier("prototype"));
|
||||
id = t.memberExpression(id, t.identifier("prototype"));
|
||||
}
|
||||
|
||||
node = t.memberExpression(node, methodName, methodNode.computed);
|
||||
return t.memberExpression(node, t.identifier("call"));
|
||||
id = t.memberExpression(id, methodName, methodNode.computed);
|
||||
return t.memberExpression(id, t.identifier("call"));
|
||||
}
|
||||
} else if (t.isMemberExpression(parent) && !methodNode.static) {
|
||||
// super.test -> ClassName.prototype.test
|
||||
@@ -179,31 +213,51 @@ var superIdentifier = function (superName, methodNode, node, parent) {
|
||||
}
|
||||
};
|
||||
|
||||
var replaceInstanceSuperReferences = function (superName, methodNode) {
|
||||
var method = methodNode.value;
|
||||
/**
|
||||
* Replace all `super` references with a reference to our `superClass`.
|
||||
*
|
||||
* @param {Node} methodNode MethodDefinition
|
||||
*/
|
||||
|
||||
superName = superName || t.identifier("Function");
|
||||
Class.prototype.replaceInstanceSuperReferences = function (methodNode) {
|
||||
var method = methodNode.value;
|
||||
var self = this;
|
||||
|
||||
traverse(method, function (node, parent) {
|
||||
if (t.isIdentifier(node, { name: "super" })) {
|
||||
return superIdentifier(superName, methodNode, node, parent);
|
||||
return self.superIdentifier(methodNode, node, parent);
|
||||
} else if (t.isCallExpression(node)) {
|
||||
var callee = node.callee;
|
||||
if (!t.isMemberExpression(callee)) return;
|
||||
if (callee.object.name !== "super") return;
|
||||
|
||||
// super.test(); -> ClassName.prototype.MethodName.call(this);
|
||||
callee.property.name = callee.property.name + ".call";
|
||||
// super.test(); -> ClassName.prototype.MethodName.call(this);
|
||||
callee.property = t.memberExpression(callee.property, t.identifier("call"));
|
||||
node.arguments.unshift(t.thisExpression());
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var addConstructor = function (construct, method) {
|
||||
construct.defaults = method.defaults;
|
||||
construct.params = method.params;
|
||||
construct.body = method.body;
|
||||
construct.rest = method.rest;
|
||||
/**
|
||||
* Replace the constructor body of our class.
|
||||
*
|
||||
* @param {Node} method MethodDefinition
|
||||
*/
|
||||
|
||||
t.inherits(construct, method);
|
||||
Class.prototype.pushConstructor = function (method) {
|
||||
if (method.kind !== "") {
|
||||
throw this.file.errorWithNode(method, "illegal kind for constructor method");
|
||||
}
|
||||
|
||||
var construct = this.constructor;
|
||||
var fn = method.value;
|
||||
|
||||
this.hasConstructor = true;
|
||||
t.inherits(construct, fn);
|
||||
t.inheritsComments(construct, method);
|
||||
|
||||
construct.defaults = fn.defaults;
|
||||
construct.params = fn.params;
|
||||
construct.body = fn.body;
|
||||
construct.rest = fn.rest;
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ exports.ObjectExpression = function (node, parent, file) {
|
||||
var containerCallee = container.callee.expression;
|
||||
var containerBody = containerCallee.body.body;
|
||||
|
||||
containerCallee._aliasFunction = "arrows";
|
||||
containerCallee._aliasFunction = true;
|
||||
|
||||
_.each(computed, function (prop) {
|
||||
containerBody.unshift(
|
||||
|
||||
@@ -7,26 +7,30 @@ exports.BlockStatement =
|
||||
exports.ForInStatement =
|
||||
exports.ForOfStatement =
|
||||
exports.ForStatement = function (node, parent, file) {
|
||||
var constants = [];
|
||||
var constants = {};
|
||||
|
||||
var check = function (node, names) {
|
||||
_.each(names, function (name) {
|
||||
if (constants.indexOf(name) >= 0) {
|
||||
throw file.errorWithNode(node, name + " is read-only");
|
||||
}
|
||||
var check = function (parent, names) {
|
||||
_.each(names, function (nameNode, name) {
|
||||
if (!_.has(constants, name)) return;
|
||||
if (parent && t.isBlockStatement(parent) && parent !== constants[name]) return;
|
||||
|
||||
throw file.errorWithNode(nameNode, name + " is read-only");
|
||||
});
|
||||
};
|
||||
|
||||
var getIds = function (node) {
|
||||
return t.getIds(node, false, ["MemberExpression"]);
|
||||
return t.getIds(node, true, ["MemberExpression"]);
|
||||
};
|
||||
|
||||
_.each(node.body, function (child) {
|
||||
_.each(node.body, function (child, parent) {
|
||||
if (child && t.isVariableDeclaration(child, { kind: "const" })) {
|
||||
_.each(child.declarations, function (declar) {
|
||||
_.each(getIds(declar), function (name) {
|
||||
check(declar, [name]);
|
||||
constants.push(name);
|
||||
_.each(getIds(declar), function (nameNode, name) {
|
||||
var names = {};
|
||||
names[name] = nameNode;
|
||||
check(parent, names);
|
||||
|
||||
constants[name] = parent;
|
||||
});
|
||||
|
||||
declar._ignoreConstant = true;
|
||||
@@ -37,13 +41,14 @@ exports.ForStatement = function (node, parent, file) {
|
||||
}
|
||||
});
|
||||
|
||||
if (!constants.length) return;
|
||||
if (_.isEmpty(constants)) return;
|
||||
|
||||
traverse(node, function (child) {
|
||||
traverse(node, function (child, parent) {
|
||||
if (child._ignoreConstant) return;
|
||||
if (t.isVariableDeclaration(child)) return;
|
||||
|
||||
if (t.isVariableDeclarator(child) || t.isDeclaration(child) || t.isAssignmentExpression(child)) {
|
||||
check(child, getIds(child));
|
||||
check(parent, getIds(child));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,21 +1,70 @@
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
var traverse = require("../../traverse");
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.Function = function (node) {
|
||||
if (!node.defaults.length) return;
|
||||
exports.Function = function (node, parent, file, scope) {
|
||||
if (!node.defaults || !node.defaults.length) return;
|
||||
t.ensureBlock(node);
|
||||
|
||||
var ids = node.params.map(function (param) {
|
||||
return t.getIds(param);
|
||||
});
|
||||
|
||||
var closure = false;
|
||||
|
||||
_.each(node.defaults, function (def, i) {
|
||||
if (!def) return;
|
||||
|
||||
var param = node.params[i];
|
||||
|
||||
node.body.body.unshift(util.template("if-undefined-set-to", {
|
||||
VARIABLE: param,
|
||||
DEFAULT: def
|
||||
// temporal dead zone check - here we prevent accessing of params that
|
||||
// are to the right - ie. uninitialized parameters
|
||||
_.each(ids.slice(i), function (ids) {
|
||||
var check = function (node, parent) {
|
||||
if (!t.isIdentifier(node) || !t.isReferenced(node, parent)) return;
|
||||
|
||||
if (_.contains(ids, node.name)) {
|
||||
throw file.errorWithNode(node, "Temporal dead zone - accessing a variable before it's initialized");
|
||||
}
|
||||
|
||||
if (scope.has(node.name)) {
|
||||
closure = true;
|
||||
}
|
||||
};
|
||||
|
||||
check(def, node);
|
||||
traverse(def, check);
|
||||
});
|
||||
|
||||
// we're accessing a variable that's already defined within this function
|
||||
var has = scope.get(param.name);
|
||||
if (has && !_.contains(node.params, has)) {
|
||||
closure = true;
|
||||
}
|
||||
});
|
||||
|
||||
var body = [];
|
||||
|
||||
_.each(node.defaults, function (def, i) {
|
||||
if (!def) return;
|
||||
|
||||
body.push(util.template("if-undefined-set-to", {
|
||||
VARIABLE: node.params[i],
|
||||
DEFAULT: def
|
||||
}, true));
|
||||
});
|
||||
|
||||
if (closure) {
|
||||
var container = t.functionExpression(null, [], node.body, node.generator);
|
||||
container._aliasFunction = true;
|
||||
|
||||
body.push(t.returnStatement(t.callExpression(container, [])));
|
||||
|
||||
node.body = t.blockStatement(body);
|
||||
} else {
|
||||
node.body.body = body.concat(node.body.body);
|
||||
}
|
||||
|
||||
node.defaults = [];
|
||||
};
|
||||
|
||||
@@ -146,6 +146,12 @@ exports.ExpressionStatement = function (node, parent, file, scope) {
|
||||
return nodes;
|
||||
};
|
||||
|
||||
exports.AssignmentExpression = function (node, parent, file) {
|
||||
if (parent.type === "ExpressionStatement") return;
|
||||
if (!t.isPattern(node.left)) return;
|
||||
throw file.errorWithNode(node, "AssignmentExpression destructuring outside of a ExpressionStatement is forbidden due to current 6to5 limitations");
|
||||
};
|
||||
|
||||
exports.VariableDeclaration = function (node, parent, file, scope) {
|
||||
if (t.isForInStatement(parent) || t.isForOfStatement(parent)) return;
|
||||
|
||||
|
||||
@@ -5,17 +5,17 @@ exports.ForOfStatement = function (node, parent, file, scope) {
|
||||
var left = node.left;
|
||||
var declar;
|
||||
|
||||
var stepKey = t.identifier(file.generateUid("step", scope));
|
||||
var stepValueId = t.memberExpression(stepKey, t.identifier("value"));
|
||||
var stepKey = t.identifier(file.generateUid("step", scope));
|
||||
var stepValue = t.memberExpression(stepKey, t.identifier("value"));
|
||||
|
||||
if (t.isIdentifier(left)) {
|
||||
declar = t.expressionStatement(t.assignmentExpression("=", left, stepValueId));
|
||||
declar = t.expressionStatement(t.assignmentExpression("=", left, stepValue));
|
||||
} else if (t.isVariableDeclaration(left)) {
|
||||
declar = t.variableDeclaration(left.kind, [
|
||||
t.variableDeclarator(left.declarations[0].id, stepValueId)
|
||||
t.variableDeclarator(left.declarations[0].id, stepValue)
|
||||
]);
|
||||
} else {
|
||||
return;
|
||||
throw file.errorWithNode(left, "Unknown node type " + left.type + " in ForOfStatement");
|
||||
}
|
||||
|
||||
var node2 = util.template("for-of", {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
var arrayComprehension = require("./array-comprehension");
|
||||
var t = require("../../types");
|
||||
|
||||
exports.ComprehensionExpression = function (node) {
|
||||
if (!node.generator) return;
|
||||
|
||||
var body = [];
|
||||
var container = t.functionExpression(null, [], t.blockStatement(body), true);
|
||||
|
||||
body.push(arrayComprehension._build(node, function () {
|
||||
return t.expressionStatement(t.yieldExpression(node.body));
|
||||
}));
|
||||
|
||||
return t.callExpression(container, []);
|
||||
};
|
||||
@@ -1,89 +0,0 @@
|
||||
// Based upon the excellent jsx-transpiler by Ingvar Stepanyan (RReverser)
|
||||
// https://github.com/RReverser/jsx-transpiler
|
||||
|
||||
var esutils = require("esutils");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var JSX_ANNOTATION_REGEX = /^\*\s*@jsx\s+([^\s]+)/;
|
||||
|
||||
exports.Program = function (node, parent, file) {
|
||||
var jsx = "React.DOM";
|
||||
|
||||
// looking for namespace annotation
|
||||
_.each(node.leadingComments, function (comment) {
|
||||
var matches = JSX_ANNOTATION_REGEX.exec(comment.value);
|
||||
if (matches) jsx = matches[1];
|
||||
});
|
||||
|
||||
// prebuilding AST node
|
||||
file.jsx = jsx.split(".").map(t.identifier).reduce(function (object, property) {
|
||||
return t.memberExpression(object, property);
|
||||
});
|
||||
};
|
||||
|
||||
exports.XJSIdentifier = function (node) {
|
||||
if (esutils.keyword.isIdentifierName(node.name)) {
|
||||
node.type = "Identifier";
|
||||
} else {
|
||||
return t.literal(node.name);
|
||||
}
|
||||
};
|
||||
|
||||
exports.XJSNamespacedName = function () {
|
||||
throw new Error("Namespace tags are not supported. ReactJSX is not XML.");
|
||||
};
|
||||
|
||||
exports.XJSMemberExpression = {
|
||||
exit: function (node) {
|
||||
node.computed = t.isLiteral(node.property);
|
||||
node.type = "MemberExpression";
|
||||
}
|
||||
};
|
||||
|
||||
exports.XJSExpressionContainer = function (node) {
|
||||
return node.expression;
|
||||
};
|
||||
|
||||
exports.XJSAttribute = {
|
||||
exit: function (node) {
|
||||
var value = node.value || t.literal(true);
|
||||
return t.property("init", node.name, value);
|
||||
}
|
||||
};
|
||||
|
||||
exports.XJSOpeningElement = {
|
||||
exit: function (node, parent, file) {
|
||||
var tagExpr = node.name;
|
||||
|
||||
if (t.isIdentifier(tagExpr)) {
|
||||
var tagName = tagExpr.name;
|
||||
|
||||
if (/[a-z]/.exec(tagName[0]) || _.contains(tagName, "-")) {
|
||||
tagExpr = t.memberExpression(file.jsx, tagExpr);
|
||||
}
|
||||
}
|
||||
|
||||
var props = node.attributes;
|
||||
if (props.length) {
|
||||
props = t.objectExpression(props);
|
||||
} else {
|
||||
props = t.literal(null);
|
||||
}
|
||||
|
||||
return t.callExpression(tagExpr, [props]);
|
||||
}
|
||||
};
|
||||
|
||||
exports.XJSElement = {
|
||||
exit: function (node) {
|
||||
var callExpr = node.openingElement;
|
||||
var children = node.children;
|
||||
|
||||
_.each(children, function (child) {
|
||||
callExpr.arguments.push(child);
|
||||
});
|
||||
|
||||
return t.inherits(callExpr, node);
|
||||
}
|
||||
};
|
||||
@@ -17,6 +17,12 @@ var isVar = function (node) {
|
||||
return t.isVariableDeclaration(node, { kind: "var" }) && !isLet(node);
|
||||
};
|
||||
|
||||
var standardiseLets = function (declars) {
|
||||
_.each(declars, function (declar) {
|
||||
delete declar._let;
|
||||
});
|
||||
};
|
||||
|
||||
exports.VariableDeclaration = function (node) {
|
||||
isLet(node);
|
||||
};
|
||||
@@ -33,7 +39,8 @@ exports.For = function (node, parent, file, scope) {
|
||||
node.label = parent.label;
|
||||
}
|
||||
|
||||
run(node, node.body, parent, file, scope);
|
||||
var letScoping = new LetScoping(node, node.body, parent, file, scope);
|
||||
letScoping.run();
|
||||
|
||||
if (node.label && !t.isLabeledStatement(parent)) {
|
||||
// we've been given a label so let's wrap ourselves
|
||||
@@ -43,29 +50,134 @@ exports.For = function (node, parent, file, scope) {
|
||||
|
||||
exports.BlockStatement = function (block, parent, file, scope) {
|
||||
if (!t.isFor(parent)) {
|
||||
run(false, block, parent, file, scope);
|
||||
var letScoping = new LetScoping(false, block, parent, file, scope);
|
||||
letScoping.run();
|
||||
}
|
||||
};
|
||||
|
||||
var noClosure = function (letDeclars, block, replacements) {
|
||||
standardiseLets(letDeclars);
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @param {Boolean|Node} forParent
|
||||
* @param {Node} block
|
||||
* @param {Node} parent
|
||||
* @param {File} file
|
||||
* @param {Scope} scope
|
||||
*/
|
||||
|
||||
function LetScoping(forParent, block, parent, file, scope) {
|
||||
this.forParent = forParent;
|
||||
this.parent = parent;
|
||||
this.scope = scope;
|
||||
this.block = block;
|
||||
this.file = file;
|
||||
|
||||
this.letReferences = {};
|
||||
this.body = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the ball rolling.
|
||||
*/
|
||||
|
||||
LetScoping.prototype.run = function () {
|
||||
var block = this.block;
|
||||
|
||||
if (block._letDone) return;
|
||||
block._letDone = true;
|
||||
|
||||
this.info = this.getInfo();
|
||||
|
||||
// this is a block within a `Function` so we can safely leave it be
|
||||
if (t.isFunction(this.parent)) return this.noClosure();
|
||||
|
||||
// this block has no let references so let's clean up
|
||||
if (!this.info.keys.length) return this.noClosure();
|
||||
|
||||
// returns whether or not there are any outside let references within any
|
||||
// functions
|
||||
var referencesInClosure = this.getLetReferences();
|
||||
|
||||
// no need for a closure so let's clean up
|
||||
if (!referencesInClosure) return this.noClosure();
|
||||
|
||||
// if we're inside of a for loop then we search to see if there are any
|
||||
// `break`s, `continue`s, `return`s etc
|
||||
this.has = this.checkFor();
|
||||
|
||||
// hoist var references to retain scope
|
||||
this.hoistVarDeclarations();
|
||||
|
||||
// set let references to plain var references
|
||||
standardiseLets(this.info.declarators);
|
||||
|
||||
// turn letReferences into an array
|
||||
var letReferences = _.values(this.letReferences);
|
||||
|
||||
// build the closure that we're going to wrap the block with
|
||||
var fn = t.functionExpression(null, letReferences, t.blockStatement(block.body));
|
||||
fn._aliasFunction = true;
|
||||
|
||||
// replace the current block body with the one we're going to build
|
||||
block.body = this.body;
|
||||
|
||||
// change upper scope references with their uid if they have one
|
||||
var params = this.getParams(letReferences);
|
||||
|
||||
// build a call and a unique id that we can assign the return value to
|
||||
var call = t.callExpression(fn, params);
|
||||
var ret = t.identifier(this.file.generateUid("ret", this.scope));
|
||||
|
||||
this.build(ret, call);
|
||||
};
|
||||
|
||||
/**
|
||||
* There are no let references accessed within a closure so we can just traverse
|
||||
* through this block and replace all references that exist in a higher scope to
|
||||
* their uids.
|
||||
*/
|
||||
|
||||
LetScoping.prototype.noClosure = function () {
|
||||
var replacements = this.info.duplicates;
|
||||
var declarators = this.info.declarators;
|
||||
var block = this.block;
|
||||
|
||||
standardiseLets(declarators);
|
||||
|
||||
if (_.isEmpty(replacements)) return;
|
||||
|
||||
traverse(block, function (node, parent) {
|
||||
var replace = function (node, parent) {
|
||||
if (!t.isIdentifier(node)) return;
|
||||
if (!t.isReferenced(node, parent)) return;
|
||||
node.name = replacements[node.name] || node.name;
|
||||
});
|
||||
};
|
||||
|
||||
var traverseReplace = function (node, parent) {
|
||||
replace(node, parent);
|
||||
traverse(node, replace);
|
||||
};
|
||||
|
||||
var forParent = this.forParent;
|
||||
if (forParent) {
|
||||
traverseReplace(forParent.right, forParent);
|
||||
traverseReplace(forParent.test, forParent);
|
||||
traverseReplace(forParent.update, forParent);
|
||||
}
|
||||
|
||||
traverse(block, replace);
|
||||
};
|
||||
|
||||
var standardiseLets = function (declars) {
|
||||
_.each(declars, function (declar) {
|
||||
delete declar._let;
|
||||
});
|
||||
};
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
LetScoping.prototype.getInfo = function () {
|
||||
var block = this.block;
|
||||
var scope = this.scope;
|
||||
var file = this.file;
|
||||
|
||||
var getInfo = function (block, file, scope) {
|
||||
var opts = {
|
||||
// array of `Identifier` names of let variables that appear lexically out of
|
||||
// this scope but should be accessible - eg. `ForOfStatement`.left
|
||||
@@ -84,10 +196,23 @@ var getInfo = function (block, file, scope) {
|
||||
keys: []
|
||||
};
|
||||
|
||||
var duplicates = function (id, key) {
|
||||
var has = scope.parentGet(key);
|
||||
|
||||
if (has && has !== id) {
|
||||
// there's a variable with this exact name in an upper scope so we need
|
||||
// to generate a new name
|
||||
opts.duplicates[key] = id.name = file.generateUid(key, scope);
|
||||
}
|
||||
};
|
||||
|
||||
_.each(opts.declarators, function (declar) {
|
||||
opts.declarators.push(declar);
|
||||
|
||||
var keys = t.getIds(declar);
|
||||
var keys = t.getIds(declar, true);
|
||||
_.each(keys, duplicates);
|
||||
keys = _.keys(keys);
|
||||
|
||||
opts.outsideKeys = opts.outsideKeys.concat(keys);
|
||||
opts.keys = opts.keys.concat(keys);
|
||||
});
|
||||
@@ -96,14 +221,7 @@ var getInfo = function (block, file, scope) {
|
||||
if (!isLet(declar)) return;
|
||||
|
||||
_.each(t.getIds(declar, true), function (id, key) {
|
||||
var has = scope.parentGet(key);
|
||||
|
||||
if (has && has !== id) {
|
||||
// there's a variable with this exact name in an upper scope so we need
|
||||
// to generate a new name
|
||||
opts.duplicates[key] = id.name = file.generateUid(key, scope);
|
||||
}
|
||||
|
||||
duplicates(id, key);
|
||||
opts.keys.push(key);
|
||||
});
|
||||
});
|
||||
@@ -111,15 +229,24 @@ var getInfo = function (block, file, scope) {
|
||||
return opts;
|
||||
};
|
||||
|
||||
var checkFor = function (forParent, block) {
|
||||
/**
|
||||
* If we're inside of a `For*Statement` then traverse it and check if it has one
|
||||
* of the following node types `ReturnStatement`, `BreakStatement`,
|
||||
* `ContinueStatement` and replace it with a return value that we can track
|
||||
* later on.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
|
||||
LetScoping.prototype.checkFor = function () {
|
||||
var has = {
|
||||
hasContinue: false,
|
||||
hasReturn: false,
|
||||
hasBreak: false,
|
||||
};
|
||||
|
||||
if (forParent) {
|
||||
traverse(block, function (node) {
|
||||
if (this.forParent) {
|
||||
traverse(this.block, function (node) {
|
||||
var replace;
|
||||
|
||||
if (t.isFunction(node) || t.isFor(node)) {
|
||||
@@ -133,7 +260,7 @@ var checkFor = function (forParent, block) {
|
||||
} else if (t.isReturnStatement(node)) {
|
||||
has.hasReturn = true;
|
||||
replace = t.returnStatement(t.objectExpression([
|
||||
t.property("init", t.identifier("v"), node.argument)
|
||||
t.property("init", t.identifier("v"), node.argument || t.identifier("undefined"))
|
||||
]));
|
||||
}
|
||||
|
||||
@@ -144,38 +271,59 @@ var checkFor = function (forParent, block) {
|
||||
return has;
|
||||
};
|
||||
|
||||
var hoistVarDeclarations = function (block, pushDeclar) {
|
||||
traverse(block, function (node) {
|
||||
/**
|
||||
* Hoist all var declarations in this block to before it so they retain scope
|
||||
* once we wrap everything in a closure.
|
||||
*/
|
||||
|
||||
LetScoping.prototype.hoistVarDeclarations = function () {
|
||||
var self = this;
|
||||
traverse(this.block, function (node) {
|
||||
if (t.isForStatement(node)) {
|
||||
if (isVar(node.init)) {
|
||||
node.init = t.sequenceExpression(pushDeclar(node.init));
|
||||
node.init = t.sequenceExpression(self.pushDeclar(node.init));
|
||||
}
|
||||
} else if (t.isFor(node)) {
|
||||
if (isVar(node.left)) {
|
||||
node.left = node.left.declarations[0].id;
|
||||
}
|
||||
} else if (isVar(node)) {
|
||||
return pushDeclar(node).map(t.expressionStatement);
|
||||
return self.pushDeclar(node).map(t.expressionStatement);
|
||||
} else if (t.isFunction(node)) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var getParams = function (info, letReferences) {
|
||||
var params = _.cloneDeep(letReferences);
|
||||
/**
|
||||
* Build up a parameter list that we'll call our closure wrapper with, replacing
|
||||
* all duplicate ids with their uid.
|
||||
*
|
||||
* @param {Array} params
|
||||
* @returns {Array}
|
||||
*/
|
||||
|
||||
LetScoping.prototype.getParams = function (params) {
|
||||
var info = this.info;
|
||||
params = _.cloneDeep(params);
|
||||
_.each(params, function (param) {
|
||||
param.name = info.duplicates[param.name] || param.name;
|
||||
});
|
||||
return params;
|
||||
};
|
||||
|
||||
var getLetReferences = function (block, info, letReferences) {
|
||||
/**
|
||||
* Get all let references within this block. Stopping whenever we reach another
|
||||
* block.
|
||||
*/
|
||||
|
||||
LetScoping.prototype.getLetReferences = function () {
|
||||
var closurify = false;
|
||||
var self = this;
|
||||
|
||||
// traverse through this block, stopping on functions and checking if they
|
||||
// contain any outside let references
|
||||
traverse(block, function (node, parent, scope) {
|
||||
traverse(this.block, function (node, parent, scope) {
|
||||
if (t.isFunction(node)) {
|
||||
traverse(node, function (node, parent) {
|
||||
// not an identifier so we have no use
|
||||
@@ -191,10 +339,10 @@ var getLetReferences = function (block, info, letReferences) {
|
||||
closurify = true;
|
||||
|
||||
// this key doesn't appear just outside our scope
|
||||
if (!_.contains(info.outsideKeys, node.name)) return;
|
||||
if (!_.contains(self.info.outsideKeys, node.name)) return;
|
||||
|
||||
// push this badboy
|
||||
letReferences[node.name] = node;
|
||||
self.letReferences[node.name] = node;
|
||||
});
|
||||
|
||||
return false;
|
||||
@@ -206,120 +354,100 @@ var getLetReferences = function (block, info, letReferences) {
|
||||
return closurify;
|
||||
};
|
||||
|
||||
var buildPushDeclar = function (body) {
|
||||
return function (node) {
|
||||
body.push(t.variableDeclaration(node.kind, node.declarations.map(function (declar) {
|
||||
return t.variableDeclarator(declar.id);
|
||||
})));
|
||||
/**
|
||||
* Turn a `VariableDeclaration` into an array of `AssignmentExpressions` with
|
||||
* their declarations hoisted to before the closure wrapper.
|
||||
*
|
||||
* @param {Node} node VariableDeclaration
|
||||
* @returns {Array}
|
||||
*/
|
||||
|
||||
var replace = [];
|
||||
LetScoping.prototype.pushDeclar = function (node) {
|
||||
this.body.push(t.variableDeclaration(node.kind, node.declarations.map(function (declar) {
|
||||
return t.variableDeclarator(declar.id);
|
||||
})));
|
||||
|
||||
_.each(node.declarations, function (declar) {
|
||||
if (!declar.init) return;
|
||||
var replace = [];
|
||||
|
||||
var expr = t.assignmentExpression("=", declar.id, declar.init);
|
||||
replace.push(t.inherits(expr, declar));
|
||||
});
|
||||
_.each(node.declarations, function (declar) {
|
||||
if (!declar.init) return;
|
||||
|
||||
return replace;
|
||||
};
|
||||
var expr = t.assignmentExpression("=", declar.id, declar.init);
|
||||
replace.push(t.inherits(expr, declar));
|
||||
});
|
||||
|
||||
return replace;
|
||||
};
|
||||
|
||||
var run = function (forParent, block, parent, file, scope) {
|
||||
if (block._letDone) return;
|
||||
block._letDone = true;
|
||||
|
||||
var info = getInfo(block, file, scope);
|
||||
var declarators = info.declarators;
|
||||
var letKeys = info.keys;
|
||||
|
||||
// this is a block within a `Function` so we can safely leave it be
|
||||
if (t.isFunction(parent)) return;
|
||||
|
||||
// this block has no let references so let's clean up
|
||||
if (!letKeys.length) return noClosure(declarators, block, info.duplicates);
|
||||
|
||||
// outside let references that we need to wrap
|
||||
var letReferences = {};
|
||||
|
||||
// returns whether or not there are any outside let references within any
|
||||
// functions
|
||||
var closurify = getLetReferences(block, info, letReferences);
|
||||
|
||||
letReferences = _.values(letReferences);
|
||||
|
||||
// no need for a closure so let's clean up
|
||||
if (!closurify) return noClosure(declarators, block, info.duplicates);
|
||||
|
||||
// if we're inside of a for loop then we search to see if there are any
|
||||
// `break`s, `continue`s, `return`s etc
|
||||
var has = checkFor(forParent, block);
|
||||
|
||||
var body = [];
|
||||
|
||||
// hoist a `VariableDeclaration` and add `AssignmentExpression`s in it's place
|
||||
var pushDeclar = buildPushDeclar(body);
|
||||
|
||||
// hoist var references to retain scope
|
||||
hoistVarDeclarations(block, pushDeclar);
|
||||
|
||||
// set let references to plain var references
|
||||
standardiseLets(declarators);
|
||||
|
||||
// build the closure that we're going to wrap the block with
|
||||
var fn = t.functionExpression(null, letReferences, t.blockStatement(block.body));
|
||||
fn._aliasFunction = true;
|
||||
|
||||
// replace the current block body with the one we've built
|
||||
block.body = body;
|
||||
|
||||
// change duplicate let references to their uid if they have one
|
||||
var params = getParams(info, letReferences);
|
||||
|
||||
var call = t.callExpression(fn, params);
|
||||
var ret = t.identifier(file.generateUid("ret", scope));
|
||||
/**
|
||||
* Push the closure to the body.
|
||||
*
|
||||
* @param {Node} ret Identifier
|
||||
* @param {Node} call CallExpression
|
||||
*/
|
||||
|
||||
LetScoping.prototype.build = function (ret, call) {
|
||||
var has = this.has;
|
||||
if (has.hasReturn || has.hasBreak || has.hasContinue) {
|
||||
body.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(ret, call)
|
||||
]));
|
||||
this.buildHas(ret, call);
|
||||
} else {
|
||||
this.body.push(t.expressionStatement(call));
|
||||
}
|
||||
};
|
||||
|
||||
var retCheck;
|
||||
/**
|
||||
* Description
|
||||
*
|
||||
* @param {Node} ret Identifier
|
||||
* @param {Node} call CallExpression
|
||||
*/
|
||||
|
||||
if (has.hasReturn) {
|
||||
// typeof ret === "object"
|
||||
retCheck = util.template("let-scoping-return", {
|
||||
RETURN: ret,
|
||||
});
|
||||
LetScoping.prototype.buildHas = function (ret, call) {
|
||||
var body = this.body;
|
||||
|
||||
// there's no `break` or `continue` so we can just push in the `if`
|
||||
if (!has.hasBreak && !has.hasContinue) {
|
||||
body.push(retCheck);
|
||||
}
|
||||
body.push(t.variableDeclaration("var", [
|
||||
t.variableDeclarator(ret, call)
|
||||
]));
|
||||
|
||||
var forParent = this.forParent;
|
||||
var retCheck;
|
||||
var has = this.has;
|
||||
var cases = [];
|
||||
|
||||
if (has.hasReturn) {
|
||||
// typeof ret === "object"
|
||||
retCheck = util.template("let-scoping-return", {
|
||||
RETURN: ret
|
||||
});
|
||||
}
|
||||
|
||||
if (has.hasBreak || has.hasContinue) {
|
||||
// ensure that the parent has a label as we're building a switch and we
|
||||
// need to be able to access it
|
||||
var label = forParent.label = forParent.label || t.identifier(this.file.generateUid("loop", this.scope));
|
||||
|
||||
if (has.hasBreak) {
|
||||
cases.push(t.switchCase(t.literal("break"), [t.breakStatement(label)]));
|
||||
}
|
||||
|
||||
if (has.hasBreak || has.hasContinue) {
|
||||
// ensure that the parent has a label as we're building a switch and we
|
||||
// need to be able to access it
|
||||
var label = forParent.label = forParent.label || t.identifier(file.generateUid("loop", scope));
|
||||
if (has.hasContinue) {
|
||||
cases.push(t.switchCase(t.literal("continue"), [t.continueStatement(label)]));
|
||||
}
|
||||
|
||||
var cases = [];
|
||||
|
||||
if (has.hasBreak) {
|
||||
cases.push(t.switchCase(t.literal("break"), [t.breakStatement(label)]));
|
||||
}
|
||||
|
||||
if (has.hasContinue) {
|
||||
cases.push(t.switchCase(t.literal("continue"), [t.continueStatement(label)]));
|
||||
}
|
||||
|
||||
if (has.hasReturn) {
|
||||
cases.push(t.switchCase(null, [retCheck]));
|
||||
}
|
||||
if (has.hasReturn) {
|
||||
cases.push(t.switchCase(null, [retCheck]));
|
||||
}
|
||||
|
||||
if (cases.length === 1) {
|
||||
var single = cases[0];
|
||||
body.push(t.ifStatement(
|
||||
t.binaryExpression("===", ret, single.test),
|
||||
single.consequent[0]
|
||||
));
|
||||
} else {
|
||||
body.push(t.switchStatement(ret, cases));
|
||||
}
|
||||
} else {
|
||||
body.push(t.expressionStatement(call));
|
||||
if (has.hasReturn) body.push(retCheck);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.Literal = function (node) {
|
||||
// TODO: remove this when the new code generator is released
|
||||
if (_.isNumber(node.value)) delete node.raw;
|
||||
};
|
||||
147
lib/6to5/transformation/transformers/react.js
vendored
147
lib/6to5/transformation/transformers/react.js
vendored
@@ -1,5 +1,148 @@
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
// Based upon the excellent jsx-transpiler by Ingvar Stepanyan (RReverser)
|
||||
// https://github.com/RReverser/jsx-transpiler
|
||||
|
||||
// jsx
|
||||
|
||||
var esutils = require("esutils");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
exports.XJSIdentifier = function (node) {
|
||||
if (esutils.keyword.isIdentifierName(node.name)) {
|
||||
node.type = "Identifier";
|
||||
} else {
|
||||
return t.literal(node.name);
|
||||
}
|
||||
};
|
||||
|
||||
exports.XJSNamespacedName = function (node, parent, file) {
|
||||
throw file.errorWithNode(node, "Namespace tags are not supported. ReactJSX is not XML.");
|
||||
};
|
||||
|
||||
exports.XJSMemberExpression = {
|
||||
exit: function (node) {
|
||||
node.computed = t.isLiteral(node.property);
|
||||
node.type = "MemberExpression";
|
||||
}
|
||||
};
|
||||
|
||||
exports.XJSExpressionContainer = function (node) {
|
||||
return node.expression;
|
||||
};
|
||||
|
||||
exports.XJSAttribute = {
|
||||
exit: function (node) {
|
||||
var value = node.value || t.literal(true);
|
||||
return t.property("init", node.name, value);
|
||||
}
|
||||
};
|
||||
|
||||
exports.XJSOpeningElement = {
|
||||
exit: function (node) {
|
||||
var tagExpr = node.name;
|
||||
var args = [];
|
||||
|
||||
var tagName;
|
||||
if (t.isIdentifier(tagExpr)) {
|
||||
tagName = tagExpr.name;
|
||||
} else if (t.isLiteral(tagExpr)) {
|
||||
tagName = tagExpr.value;
|
||||
}
|
||||
|
||||
if (tagName && (/[a-z]/.exec(tagName[0]) || _.contains(tagName, "-"))) {
|
||||
args.push(t.literal(tagName));
|
||||
} else {
|
||||
args.push(tagExpr);
|
||||
}
|
||||
|
||||
var props = node.attributes;
|
||||
if (props.length) {
|
||||
var _props = [];
|
||||
var objs = [];
|
||||
|
||||
var pushProps = function () {
|
||||
if (!_props.length) return;
|
||||
|
||||
objs.push(t.objectExpression(_props));
|
||||
_props = [];
|
||||
};
|
||||
|
||||
while (props.length) {
|
||||
var prop = props.shift();
|
||||
if (t.isXJSSpreadAttribute(prop)) {
|
||||
pushProps();
|
||||
objs.push(prop.argument);
|
||||
} else {
|
||||
_props.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
pushProps();
|
||||
|
||||
if (objs.length === 1) {
|
||||
props = objs[0];
|
||||
} else {
|
||||
if (!t.isObjectExpression(objs[0])) {
|
||||
objs.unshift(t.objectExpression([]));
|
||||
}
|
||||
|
||||
props = t.callExpression(
|
||||
t.memberExpression(t.identifier("React"), t.identifier("__spread")),
|
||||
objs
|
||||
);
|
||||
}
|
||||
} else {
|
||||
props = t.literal(null);
|
||||
}
|
||||
|
||||
args.push(props);
|
||||
|
||||
tagExpr = t.memberExpression(t.identifier("React"), t.identifier("createElement"));
|
||||
return t.callExpression(tagExpr, args);
|
||||
}
|
||||
};
|
||||
|
||||
exports.XJSElement = {
|
||||
exit: function (node) {
|
||||
var callExpr = node.openingElement;
|
||||
|
||||
_.each(node.children, function (child) {
|
||||
if (t.isLiteral(child)) {
|
||||
var lines = child.value.split(/\r\n|\n|\r/);
|
||||
|
||||
_.each(lines, function (line, i) {
|
||||
var isFirstLine = i === 0;
|
||||
var isLastLine = i === lines.length - 1;
|
||||
|
||||
// replace rendered whitespace tabs with spaces
|
||||
var trimmedLine = line.replace(/\t/g, ' ');
|
||||
|
||||
// trim whitespace touching a newline
|
||||
if (!isFirstLine) {
|
||||
trimmedLine = trimmedLine.replace(/^[ ]+/, '');
|
||||
}
|
||||
|
||||
// trim whitespace touching an endline
|
||||
if (!isLastLine) {
|
||||
trimmedLine = trimmedLine.replace(/[ ]+$/, '');
|
||||
}
|
||||
|
||||
if (trimmedLine) {
|
||||
callExpr.arguments.push(t.literal(trimmedLine));
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
callExpr.arguments.push(child);
|
||||
});
|
||||
|
||||
return t.inherits(callExpr, node);
|
||||
}
|
||||
};
|
||||
|
||||
// display names
|
||||
|
||||
var addDisplayName = function (id, call) {
|
||||
if (!call || !t.isCallExpression(call)) return;
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
var util = require("../../util");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
var t = require("../../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var getSpreadLiteral = function (spread, file) {
|
||||
var getSpreadLiteral = function (spread) {
|
||||
var literal = spread.argument;
|
||||
if (!t.isArrayExpression(literal)) {
|
||||
literal = util.template("call", {
|
||||
OBJECT: file.addDeclaration("slice"),
|
||||
CONTEXT: literal
|
||||
});
|
||||
literal = t.callExpression(
|
||||
t.memberExpression(t.identifier("Array"), t.identifier("from")),
|
||||
[literal]
|
||||
);
|
||||
}
|
||||
return literal;
|
||||
};
|
||||
@@ -24,7 +23,7 @@ var hasSpread = function (nodes) {
|
||||
return has;
|
||||
};
|
||||
|
||||
var build = function (props, file) {
|
||||
var build = function (props) {
|
||||
var nodes = [];
|
||||
|
||||
var _props = [];
|
||||
@@ -38,7 +37,7 @@ var build = function (props, file) {
|
||||
_.each(props, function (prop) {
|
||||
if (t.isSpreadElement(prop)) {
|
||||
push();
|
||||
nodes.push(getSpreadLiteral(prop, file));
|
||||
nodes.push(getSpreadLiteral(prop));
|
||||
} else {
|
||||
_props.push(prop);
|
||||
}
|
||||
@@ -49,11 +48,11 @@ var build = function (props, file) {
|
||||
return nodes;
|
||||
};
|
||||
|
||||
exports.ArrayExpression = function (node, parent, file) {
|
||||
exports.ArrayExpression = function (node) {
|
||||
var elements = node.elements;
|
||||
if (!hasSpread(elements)) return;
|
||||
|
||||
var nodes = build(elements, file);
|
||||
var nodes = build(elements);
|
||||
var first = nodes.shift();
|
||||
|
||||
if (!nodes.length) return first;
|
||||
@@ -61,7 +60,7 @@ exports.ArrayExpression = function (node, parent, file) {
|
||||
return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
|
||||
};
|
||||
|
||||
exports.CallExpression = function (node, parent, file) {
|
||||
exports.CallExpression = function (node) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
@@ -69,7 +68,7 @@ exports.CallExpression = function (node, parent, file) {
|
||||
|
||||
node.arguments = [];
|
||||
|
||||
var nodes = build(args, file);
|
||||
var nodes = build(args);
|
||||
var first = nodes.shift();
|
||||
|
||||
if (nodes.length) {
|
||||
@@ -96,3 +95,19 @@ exports.CallExpression = function (node, parent, file) {
|
||||
|
||||
node.arguments.unshift(contextLiteral);
|
||||
};
|
||||
|
||||
exports.NewExpression = function (node, parent, file) {
|
||||
var args = node.arguments;
|
||||
if (!hasSpread(args)) return;
|
||||
|
||||
var nodes = build(args);
|
||||
var first = nodes.shift();
|
||||
|
||||
if (nodes.length) {
|
||||
args = t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
|
||||
} else {
|
||||
args = first;
|
||||
}
|
||||
|
||||
return t.callExpression(file.addDeclaration("apply-constructor"), [node.callee, args]);
|
||||
};
|
||||
|
||||
@@ -5,14 +5,22 @@ var buildBinaryExpression = function (left, right) {
|
||||
return t.binaryExpression("+", left, right);
|
||||
};
|
||||
|
||||
exports.TaggedTemplateExpression = function (node) {
|
||||
exports.TaggedTemplateExpression = function (node, parent, file) {
|
||||
var args = [];
|
||||
var quasi = node.quasi;
|
||||
|
||||
var strings = quasi.quasis.map(function (elem) {
|
||||
return t.literal(elem.value.raw);
|
||||
var strings = [];
|
||||
var raw = [];
|
||||
|
||||
_.each(quasi.quasis, function (elem) {
|
||||
strings.push(t.literal(elem.value.cooked));
|
||||
raw.push(t.literal(elem.value.raw));
|
||||
});
|
||||
args.push(t.arrayExpression(strings));
|
||||
|
||||
args.push(t.callExpression(file.addDeclaration("tagged-template-literal"), [
|
||||
t.arrayExpression(strings),
|
||||
t.arrayExpression(raw)
|
||||
]));
|
||||
|
||||
_.each(quasi.expressions, function (expr) {
|
||||
args.push(expr);
|
||||
|
||||
@@ -29,37 +29,41 @@ function traverse(parent, callbacks, opts) {
|
||||
// normalise callbacks
|
||||
if (_.isFunction(callbacks)) callbacks = { enter: callbacks };
|
||||
|
||||
_.each(keys, function (key) {
|
||||
for (var i in keys) {
|
||||
var key = keys[i];
|
||||
var nodes = parent[key];
|
||||
if (!nodes) return;
|
||||
if (!nodes) continue;
|
||||
|
||||
var updated = false;
|
||||
|
||||
var handle = function (obj, key) {
|
||||
var node = obj[key];
|
||||
if (!node) return;
|
||||
|
||||
// type is blacklisted
|
||||
if (_.contains(blacklistTypes, node.type)) return;
|
||||
|
||||
var result;
|
||||
if (blacklistTypes.indexOf(node.type) > -1) return;
|
||||
|
||||
// replace node
|
||||
var maybeReplace = function (result) {
|
||||
if (result === false) return;
|
||||
if (result != null) node = obj[key] = result;
|
||||
|
||||
if (result != null) {
|
||||
updated = true;
|
||||
node = obj[key] = result;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
var opts2 = _.clone(opts);
|
||||
var opts2 = { scope: opts.scope, blacklist: opts.blacklist };
|
||||
if (t.isScope(node)) opts2.scope = new Scope(opts.scope, node);
|
||||
|
||||
// enter
|
||||
if (callbacks.enter) {
|
||||
result = callbacks.enter(node, parent, opts2.scope);
|
||||
var result = callbacks.enter(node, parent, opts2.scope);
|
||||
maybeReplace(result);
|
||||
|
||||
// stop iteration
|
||||
if (result === false) return;
|
||||
|
||||
maybeReplace(result);
|
||||
}
|
||||
|
||||
// traverse node
|
||||
@@ -72,15 +76,15 @@ function traverse(parent, callbacks, opts) {
|
||||
};
|
||||
|
||||
if (_.isArray(nodes)) {
|
||||
_.each(nodes, function (node, i) {
|
||||
for (i in nodes) {
|
||||
handle(nodes, i);
|
||||
});
|
||||
}
|
||||
|
||||
parent[key] = _.flatten(parent[key]);
|
||||
if (updated) parent[key] = _.flatten(parent[key]);
|
||||
} else {
|
||||
handle(parent, key);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
traverse.removeProperties = function (tree) {
|
||||
@@ -114,25 +118,18 @@ traverse.hasType = function (tree, type, blacklistTypes) {
|
||||
|
||||
var has = false;
|
||||
|
||||
if (_.isArray(tree)) {
|
||||
// array of nodes, find the first
|
||||
return tree.some(function (node) {
|
||||
return traverse.hasType(node, type, blacklistTypes);
|
||||
});
|
||||
} else {
|
||||
// the node we're searching in is blacklisted
|
||||
if (_.contains(blacklistTypes, tree.type)) return false;
|
||||
// the node we're searching in is blacklisted
|
||||
if (_.contains(blacklistTypes, tree.type)) return false;
|
||||
|
||||
// the type we're looking for is the same as the passed node
|
||||
if (tree.type === type) return true;
|
||||
// the type we're looking for is the same as the passed node
|
||||
if (tree.type === type) return true;
|
||||
|
||||
traverse(tree, function (node) {
|
||||
if (node.type === type) {
|
||||
has = true;
|
||||
return false;
|
||||
}
|
||||
}, { blacklist: blacklistTypes });
|
||||
}
|
||||
traverse(tree, function (node) {
|
||||
if (node.type === type) {
|
||||
has = true;
|
||||
return false;
|
||||
}
|
||||
}, { blacklist: blacklistTypes });
|
||||
|
||||
return has;
|
||||
};
|
||||
|
||||
@@ -4,54 +4,93 @@ var traverse = require("./index");
|
||||
var t = require("../types");
|
||||
var _ = require("lodash");
|
||||
|
||||
var FOR_KEYS = ["left", "init"];
|
||||
|
||||
function Scope(parent, block) {
|
||||
this.parent = parent;
|
||||
this.block = block;
|
||||
this.ids = this.getIds();
|
||||
|
||||
this.getIds();
|
||||
this.info = this.getInfo();
|
||||
this.declarations = this.info.declarations;
|
||||
}
|
||||
|
||||
Scope.prototype.getIds = function () {
|
||||
Scope.prototype.getInfo = function () {
|
||||
var block = this.block;
|
||||
if (block._scopeIds) return block._scopeIds;
|
||||
if (block._scope) return block._scope;
|
||||
|
||||
var self = this;
|
||||
var ids = block._scopeIds = {};
|
||||
var info = block._scope = {
|
||||
declarations: {}
|
||||
};
|
||||
|
||||
if (t.isBlockStatement(block)) {
|
||||
_.each(block.body, function (node) {
|
||||
if (t.isVariableDeclaration(node) && node.kind !== "var") {
|
||||
self.add(node, ids);
|
||||
}
|
||||
});
|
||||
} else if (t.isProgram(block) || t.isFunction(block)) {
|
||||
traverse(block, function (node, parent) {
|
||||
if (parent !== block && t.isVariableDeclaration(node) && node.kind !== "var") {
|
||||
return;
|
||||
}
|
||||
var add = function (node) {
|
||||
self.addDeclaration(node, info.declarations);
|
||||
};
|
||||
|
||||
if (t.isDeclaration(node)) {
|
||||
self.add(node, ids);
|
||||
} else if (t.isFunction(node)) {
|
||||
return false;
|
||||
}
|
||||
// ForStatement - left, init
|
||||
|
||||
if (t.isFor(block)) {
|
||||
_.each(FOR_KEYS, function (key) {
|
||||
var node = block[key];
|
||||
if (t.isLet(node)) add(node);
|
||||
});
|
||||
} else if (t.isCatchClause(block)) {
|
||||
self.add(block.param, ids);
|
||||
|
||||
block = block.body;
|
||||
}
|
||||
|
||||
// Program, BlockStatement - let variables
|
||||
|
||||
if (t.isBlockStatement(block) || t.isProgram(block)) {
|
||||
_.each(block.body, function (node) {
|
||||
// check for non-var `VariableDeclaration`s
|
||||
if (t.isLet(node)) add(node);
|
||||
});
|
||||
}
|
||||
|
||||
// CatchClause - param
|
||||
|
||||
if (t.isCatchClause(block)) {
|
||||
add(block.param);
|
||||
}
|
||||
|
||||
// Program, Function - var variables
|
||||
|
||||
if (t.isProgram(block) || t.isFunction(block)) {
|
||||
traverse(block, function (node) {
|
||||
if (t.isFor(node)) {
|
||||
_.each(FOR_KEYS, function (key) {
|
||||
var declar = node[key];
|
||||
if (t.isVar(declar)) add(declar);
|
||||
});
|
||||
}
|
||||
|
||||
// this block is a function so we'll stop since none of the variables
|
||||
// declared within are accessible
|
||||
if (t.isFunction(node)) return false;
|
||||
|
||||
// we've ran into a declaration!
|
||||
// we'll let the BlockStatement scope deal with `let` declarations
|
||||
if (t.isDeclaration(node) && !t.isLet(node)) {
|
||||
add(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Function - params, rest
|
||||
|
||||
if (t.isFunction(block)) {
|
||||
add(block.rest);
|
||||
_.each(block.params, function (param) {
|
||||
self.add(param, ids);
|
||||
add(param);
|
||||
});
|
||||
}
|
||||
|
||||
return ids;
|
||||
return info;
|
||||
};
|
||||
|
||||
Scope.prototype.add = function (node, ids) {
|
||||
_.merge(ids || this.ids, t.getIds(node, true));
|
||||
Scope.prototype.addDeclaration = function (node, declarations) {
|
||||
if (!node) return;
|
||||
_.merge(declarations || this.declarations, t.getIds(node, true));
|
||||
};
|
||||
|
||||
Scope.prototype.get = function (id) {
|
||||
@@ -59,7 +98,7 @@ Scope.prototype.get = function (id) {
|
||||
};
|
||||
|
||||
Scope.prototype.getOwn = function (id) {
|
||||
return _.has(this.ids, id) && this.ids[id];
|
||||
return _.has(this.declarations, id) && this.declarations[id];
|
||||
};
|
||||
|
||||
Scope.prototype.parentGet = function (id) {
|
||||
|
||||
@@ -35,12 +35,13 @@
|
||||
"ClassDeclaration": ["Statement", "Declaration", "Class"],
|
||||
"ClassExpression": ["Class"],
|
||||
|
||||
"ForOfStatement": ["Statement", "For"],
|
||||
"ForInStatement": ["Statement", "For"],
|
||||
"ForStatement": ["Statement", "For"],
|
||||
"ForOfStatement": ["Statement", "For", "Scope"],
|
||||
"ForInStatement": ["Statement", "For", "Scope"],
|
||||
"ForStatement": ["Statement", "For", "Scope"],
|
||||
|
||||
"ObjectPattern": ["Pattern"],
|
||||
"ArrayPattern": ["Pattern"],
|
||||
|
||||
"Property": ["UserWhitespacable"]
|
||||
"Property": ["UserWhitespacable"],
|
||||
"XJSElement": ["UserWhitespacable"]
|
||||
}
|
||||
|
||||
@@ -7,11 +7,12 @@
|
||||
"ConditionalExpression": ["test", "consequent", "alternate"],
|
||||
"ExpressionStatement": ["expression"],
|
||||
"File": ["program", "comments", "tokens"],
|
||||
"FunctionExpression": ["id", "params", "body"],
|
||||
"FunctionExpression": ["id", "params", "body", "generator"],
|
||||
"Identifier": ["name"],
|
||||
"IfStatement": ["test", "consequent", "alternate"],
|
||||
"Literal": ["value"],
|
||||
"MemberExpression": ["object", "property", "computed"],
|
||||
"NewExpression": ["callee", "arguments"],
|
||||
"ObjectExpression": ["properties"],
|
||||
"ParenthesizedExpression": ["expression"],
|
||||
"Program": ["body"],
|
||||
|
||||
@@ -70,6 +70,9 @@ t.isReferenced = function (node, parent) {
|
||||
// we're a property key so we aren't referenced
|
||||
if (t.isProperty(parent) && parent.key === node) return false;
|
||||
|
||||
// we're a variable declarator id so we aren't referenced
|
||||
if (t.isVariableDeclarator(parent) && parent.id === node) return false;
|
||||
|
||||
var isMemberExpression = t.isMemberExpression(parent);
|
||||
|
||||
// we're in a member expression and we're the computed property so we're referenced
|
||||
@@ -106,6 +109,10 @@ t.ensureBlock = function (node) {
|
||||
};
|
||||
|
||||
t.toStatement = function (node, ignore) {
|
||||
if (t.isStatement(node)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
var mustHaveId = false;
|
||||
var newType;
|
||||
|
||||
@@ -115,8 +122,6 @@ t.toStatement = function (node, ignore) {
|
||||
} else if (t.isFunction(node)) {
|
||||
mustHaveId = true;
|
||||
newType = "FunctionDeclaration";
|
||||
} else if (t.isStatement(node)) {
|
||||
newType = node.type;
|
||||
}
|
||||
|
||||
if (mustHaveId && !node.id) {
|
||||
@@ -159,7 +164,7 @@ t.toBlock = function (node, parent) {
|
||||
t.getIds = function (node, map, ignoreTypes) {
|
||||
ignoreTypes = ignoreTypes || [];
|
||||
|
||||
var search = [node];
|
||||
var search = [].concat(node);
|
||||
var ids = {};
|
||||
|
||||
while (search.length) {
|
||||
@@ -204,11 +209,32 @@ t.getIds.arrays = {
|
||||
ObjectPattern: "properties"
|
||||
};
|
||||
|
||||
t.isLet = function (node) {
|
||||
return t.isVariableDeclaration(node) && (node.kind !== "var" || node._let);
|
||||
};
|
||||
|
||||
t.isVar = function (node) {
|
||||
return t.isVariableDeclaration(node, { kind: "var" }) && !node._let;
|
||||
};
|
||||
|
||||
t.removeComments = function (child) {
|
||||
delete child.leadingComments;
|
||||
delete child.trailingComments;
|
||||
return child;
|
||||
};
|
||||
|
||||
t.inheritsComments = function (child, parent) {
|
||||
child.leadingComments = _.compact([].concat(child.leadingComments, parent.leadingComments));
|
||||
child.trailingComments = _.compact([].concat(child.trailingComments, parent.trailingComments));
|
||||
return child;
|
||||
};
|
||||
|
||||
t.inherits = function (child, parent) {
|
||||
child.loc = parent.loc;
|
||||
child.end = parent.end;
|
||||
child.range = parent.range;
|
||||
child.start = parent.start;
|
||||
t.inheritsComments(child, parent);
|
||||
return child;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"ArrayPattern": ["elements"],
|
||||
"ArrowFunctionExpression": ["params", "defaults", "rest", "body"],
|
||||
"AssignmentExpression": ["left", "right"],
|
||||
"AwaitExpression": ["argument"],
|
||||
"BinaryExpression": ["left", "right"],
|
||||
"BlockStatement": ["body"],
|
||||
"BreakStatement": ["label"],
|
||||
@@ -70,6 +71,6 @@
|
||||
"XJSMemberExpression": ["object", "property"],
|
||||
"XJSNamespacedName": ["namespace", "name"],
|
||||
"XJSOpeningElement": ["name", "attributes"],
|
||||
"XJSSpreadAttribute": [],
|
||||
"XJSSpreadAttribute": ["argument"],
|
||||
"YieldExpression": ["argument"]
|
||||
}
|
||||
|
||||
@@ -17,6 +17,10 @@ exports.canCompile = function (filename, altExts) {
|
||||
return _.contains(exts, ext);
|
||||
};
|
||||
|
||||
exports.isInteger = function (i) {
|
||||
return _.isNumber(i) && i % 1 === 0;
|
||||
};
|
||||
|
||||
exports.resolve = function (loc) {
|
||||
try {
|
||||
return require.resolve(loc);
|
||||
@@ -25,6 +29,10 @@ exports.resolve = function (loc) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.trimRight = function (str) {
|
||||
return str.replace(/[\n\s]+$/g, "");
|
||||
};
|
||||
|
||||
exports.list = function (val) {
|
||||
return val ? val.split(",") : [];
|
||||
};
|
||||
@@ -98,8 +106,13 @@ exports.buildDefineProperties = function (mutatorMap) {
|
||||
if (key[0] === "_") return;
|
||||
|
||||
node = _.clone(node);
|
||||
var inheritNode = node;
|
||||
if (t.isMethodDefinition(node)) node = node.value;
|
||||
mapNode.properties.push(t.property("init", t.identifier(key), node));
|
||||
|
||||
var prop = t.property("init", t.identifier(key), node);
|
||||
t.inheritsComments(prop, inheritNode);
|
||||
t.removeComments(inheritNode);
|
||||
mapNode.properties.push(prop);
|
||||
});
|
||||
|
||||
objExpr.properties.push(propNode);
|
||||
@@ -119,23 +132,17 @@ exports.template = function (name, nodes, keepExpression) {
|
||||
|
||||
template = _.cloneDeep(template);
|
||||
|
||||
var inherits = false;
|
||||
if (nodes) {
|
||||
inherits = nodes.inherits;
|
||||
delete nodes.inherits;
|
||||
|
||||
if (!_.isEmpty(nodes)) {
|
||||
traverse(template, function (node) {
|
||||
if (t.isIdentifier(node) && _.has(nodes, node.name)) {
|
||||
var newNode = nodes[node.name];
|
||||
if (_.isString(newNode)) {
|
||||
node.name = newNode;
|
||||
} else {
|
||||
return newNode;
|
||||
}
|
||||
if (!_.isEmpty(nodes)) {
|
||||
traverse(template, function (node) {
|
||||
if (t.isIdentifier(node) && _.has(nodes, node.name)) {
|
||||
var newNode = nodes[node.name];
|
||||
if (_.isString(newNode)) {
|
||||
node.name = newNode;
|
||||
} else {
|
||||
return newNode;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var node = template.body[0];
|
||||
@@ -146,10 +153,6 @@ exports.template = function (name, nodes, keepExpression) {
|
||||
if (t.isParenthesizedExpression(node)) node = node.expression;
|
||||
}
|
||||
|
||||
if (inherits) {
|
||||
node = t.inherits(node, inherits);
|
||||
}
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
@@ -240,7 +243,7 @@ exports.parse = function (opts, code, callback) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.parseNoProperties = function (loc, code) {
|
||||
exports.parseTemplate = function (loc, code) {
|
||||
var ast = exports.parse({ filename: loc }, code).program;
|
||||
return traverse.removeProperties(ast);
|
||||
};
|
||||
@@ -262,7 +265,7 @@ var loadTemplates = function () {
|
||||
var loc = templatesLoc + "/" + name;
|
||||
var code = fs.readFileSync(loc, "utf8");
|
||||
|
||||
templates[key] = exports.parseNoProperties(loc, code);
|
||||
templates[key] = exports.parseTemplate(loc, code);
|
||||
});
|
||||
|
||||
return templates;
|
||||
@@ -273,9 +276,5 @@ try {
|
||||
} catch (err) {
|
||||
if (err.code !== "MODULE_NOT_FOUND") throw err;
|
||||
|
||||
Object.defineProperty(exports, "templates", {
|
||||
get: function () {
|
||||
return exports.templates = loadTemplates();
|
||||
}
|
||||
});
|
||||
exports.templates = loadTemplates();
|
||||
}
|
||||
|
||||
10
package.json
10
package.json
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "6to5",
|
||||
"description": "Turn ES6 code into readable vanilla ES5 with source maps",
|
||||
"version": "1.11.7",
|
||||
"version": "1.12.17",
|
||||
"author": "Sebastian McKenzie <sebmck@gmail.com>",
|
||||
"homepage": "https://github.com/6to5/6to5",
|
||||
"repository": {
|
||||
@@ -44,19 +44,19 @@
|
||||
"es6-symbol": "0.1.1",
|
||||
"regexpu": "0.3.0",
|
||||
"source-map": "0.1.40",
|
||||
"regenerator-6to5": "https://github.com/6to5/regenerator-6to5/archive/b7bc53e1a655879974aad53a8ceb93a70efaa08d.tar.gz",
|
||||
"regenerator-6to5": "https://github.com/6to5/regenerator-6to5/archive/a9c53518af063ffef410f826225f8ee250131932.tar.gz",
|
||||
"chokidar": "0.10.5",
|
||||
"source-map-support": "0.2.8",
|
||||
"esutils": "1.1.4",
|
||||
"acorn-6to5": "https://github.com/6to5/acorn-6to5/archive/49e421660af161af0e75c2fa066ea356d6650e69.tar.gz",
|
||||
"acorn-6to5": "https://github.com/6to5/acorn-6to5/archive/74d8e9bed20ba302d3504f53d0b1c649968959e1.tar.gz",
|
||||
"estraverse": "^1.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"istanbul": "0.3.2",
|
||||
"matcha": "0.5.0",
|
||||
"matcha": "0.6.0",
|
||||
"mocha": "2.0.1",
|
||||
"uglify-js": "2.4.15",
|
||||
"browserify": "6.2.0",
|
||||
"browserify": "6.3.2",
|
||||
"rimraf": "2.2.8",
|
||||
"jshint": "2.5.10",
|
||||
"chai": "^1.9.2"
|
||||
|
||||
1
polyfill.js
Normal file
1
polyfill.js
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require("./lib/6to5/polyfill");
|
||||
@@ -5,9 +5,11 @@ var humanise = function (val) {
|
||||
return val.replace(/-/g, " ");
|
||||
};
|
||||
|
||||
var readFile = function (filename) {
|
||||
var readFile = exports.readFile = function (filename) {
|
||||
if (fs.existsSync(filename)) {
|
||||
return fs.readFileSync(filename, "utf8").trim();
|
||||
var file = fs.readFileSync(filename, "utf8").trim();
|
||||
file = file.replace(/\r\n/g, "\n");
|
||||
return file;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
@@ -34,8 +36,6 @@ exports.get = function (entryName) {
|
||||
if (fs.existsSync(suiteOptsLoc)) suite.options = require(suiteOptsLoc);
|
||||
|
||||
_.each(fs.readdirSync(suite.filename), function (taskName) {
|
||||
if (taskName[0] === ".") return;
|
||||
|
||||
var taskDir = suite.filename + "/" + taskName;
|
||||
if (fs.statSync(taskDir).isFile()) return;
|
||||
|
||||
@@ -48,8 +48,9 @@ exports.get = function (entryName) {
|
||||
var execLoc = taskDir + "/exec.js";
|
||||
|
||||
var taskOpts = _.merge({
|
||||
filename: actualLocAlias,
|
||||
sourceMapName: expectLocAlias
|
||||
filenameRelative: expectLocAlias,
|
||||
sourceFileName: actualLocAlias,
|
||||
sourceMapName: expectLocAlias
|
||||
}, _.cloneDeep(suite.options));
|
||||
|
||||
var taskOptsLoc = taskDir + "/options.json";
|
||||
@@ -57,8 +58,10 @@ exports.get = function (entryName) {
|
||||
|
||||
var test = {
|
||||
title: humanise(taskName),
|
||||
disabled: taskName[0] === ".",
|
||||
options: taskOpts,
|
||||
exec: {
|
||||
loc: execLoc,
|
||||
code: readFile(execLoc),
|
||||
filename: execLocAlias,
|
||||
},
|
||||
|
||||
17
test/api.js
Normal file
17
test/api.js
Normal file
@@ -0,0 +1,17 @@
|
||||
var transform = require("../lib/6to5/transformation/transform");
|
||||
var assert = require("assert");
|
||||
var File = require("../lib/6to5/file");
|
||||
|
||||
suite("api", function () {
|
||||
test("{ code: false }", function () {
|
||||
var result = transform("foo('bar');", { code: false });
|
||||
assert.ok(!result.code);
|
||||
});
|
||||
|
||||
test("addDeclaration unknown", function () {
|
||||
var file = new File;
|
||||
assert.throws(function () {
|
||||
file.addDeclaration("foob");
|
||||
}, /unknown declaration foob/);
|
||||
});
|
||||
});
|
||||
16
test/bin.js
16
test/bin.js
@@ -1,4 +1,5 @@
|
||||
var readdir = require("fs-readdir-recursive");
|
||||
var helper = require("./_helper");
|
||||
var assert = require("assert");
|
||||
var rimraf = require("rimraf");
|
||||
var mkdirp = require("mkdirp");
|
||||
@@ -11,15 +12,11 @@ var _ = require("lodash");
|
||||
var fixtureLoc = __dirname + "/fixtures/bin";
|
||||
var tmpLoc = __dirname + "/tmp";
|
||||
|
||||
var readFile = function (filename) {
|
||||
return fs.readFileSync(filename, "utf8").trim();
|
||||
};
|
||||
|
||||
var readDir = function (loc) {
|
||||
var files = {};
|
||||
if (fs.existsSync(loc)) {
|
||||
_.each(readdir(loc), function (filename) {
|
||||
var contents = readFile(loc + "/" + filename);
|
||||
var contents = helper.readFile(loc + "/" + filename);
|
||||
files[filename] = contents;
|
||||
});
|
||||
}
|
||||
@@ -51,6 +48,7 @@ var assertTest = function (stdout, stderr, opts) {
|
||||
|
||||
var expectStdout = opts.stdout.trim();
|
||||
stdout = stdout.trim();
|
||||
stdout = stdout.replace(/\\/g, "/");
|
||||
|
||||
if (opts.stdout) {
|
||||
if (opts.stdoutContains) {
|
||||
@@ -63,7 +61,7 @@ var assertTest = function (stdout, stderr, opts) {
|
||||
}
|
||||
|
||||
_.each(opts.outFiles, function (expect, filename) {
|
||||
var actual = readFile(filename);
|
||||
var actual = helper.readFile(filename);
|
||||
chai.expect(actual).to.equal(expect, "out-file " + filename);
|
||||
});
|
||||
};
|
||||
@@ -138,7 +136,7 @@ _.each(fs.readdirSync(fixtureLoc), function (binName) {
|
||||
_.each(["stdout", "stdin", "stderr"], function (key) {
|
||||
var loc = testLoc + "/" + key + ".txt";
|
||||
if (fs.existsSync(loc)) {
|
||||
opts[key] = readFile(loc);
|
||||
opts[key] = helper.readFile(loc);
|
||||
} else {
|
||||
opts[key] = opts[key] || "";
|
||||
}
|
||||
@@ -151,7 +149,3 @@ _.each(fs.readdirSync(fixtureLoc), function (binName) {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
after(function () {
|
||||
rimraf.sync(tmpLoc);
|
||||
});
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
var multiples = [for (num of nums) num * num];
|
||||
var multiples = [for (num of nums) for (num2 of nums) num * num];
|
||||
var multiples = [for (num of nums) if (num > 5) num * num];
|
||||
@@ -1,3 +0,0 @@
|
||||
var multiples = [for (num of nums) num * num];
|
||||
var multiples = [for (num of nums) for (num2 of nums) num * num];
|
||||
var multiples = [for (num of nums) if (num > 5) num * num];
|
||||
@@ -1 +0,0 @@
|
||||
var foo = [1, 2, 3];
|
||||
@@ -1 +0,0 @@
|
||||
var foo = [1, 2, 3];
|
||||
@@ -1,17 +0,0 @@
|
||||
var foo = `i
|
||||
am a multiline string`;
|
||||
|
||||
var foo = `i am also
|
||||
a multiline string
|
||||
foobar`;
|
||||
|
||||
var foo = `im a single line string`;
|
||||
|
||||
var foo = tagit`i
|
||||
am a multiline string`;
|
||||
|
||||
var foo = tagit`i am also
|
||||
a multiline string
|
||||
foobar`;
|
||||
|
||||
var foo = tagit`im a single line string`;
|
||||
@@ -1,17 +0,0 @@
|
||||
var foo = `i
|
||||
am a multiline string`;
|
||||
|
||||
var foo = `i am also
|
||||
a multiline string
|
||||
foobar`;
|
||||
|
||||
var foo = `im a single line string`;
|
||||
|
||||
var foo = tagit`i
|
||||
am a multiline string`;
|
||||
|
||||
var foo = tagit`i am also
|
||||
a multiline string
|
||||
foobar`;
|
||||
|
||||
var foo = tagit`im a single line string`;
|
||||
@@ -2,3 +2,5 @@
|
||||
/**/
|
||||
/*
|
||||
*/
|
||||
|
||||
test
|
||||
@@ -20,8 +20,11 @@
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
function test() {}
|
||||
|
||||
|
||||
|
||||
// Copyright (C) 2012 Yusuke Suzuki <utatane.tea@gmail.com>
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -4,6 +4,6 @@ export { a as b, c as d } from "hello";
|
||||
export { a as b, c as d };
|
||||
export {};
|
||||
export default i = 20;
|
||||
export function test() {};
|
||||
export function test() {}
|
||||
export var i = 20;
|
||||
export let i = 42;
|
||||
|
||||
5
test/fixtures/generation/types/ArrayExpression-ArrayPattern/actual.js
vendored
Normal file
5
test/fixtures/generation/types/ArrayExpression-ArrayPattern/actual.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
[a, b, c];
|
||||
[[], [b, c], []];
|
||||
[a,, b,];
|
||||
[a,,,, b];
|
||||
[a, b,, c];
|
||||
5
test/fixtures/generation/types/ArrayExpression-ArrayPattern/expected.js
vendored
Normal file
5
test/fixtures/generation/types/ArrayExpression-ArrayPattern/expected.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
[a, b, c];
|
||||
[[], [b, c], []];
|
||||
[a,, b];
|
||||
[a,,,, b];
|
||||
[a, b,, c];
|
||||
4
test/fixtures/generation/types/ArrowFunctionExpression/actual.js
vendored
Normal file
4
test/fixtures/generation/types/ArrowFunctionExpression/actual.js
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
var foo = x => x * x;
|
||||
var foo = (a, b) => a * b;
|
||||
var foo = async x => x * x;
|
||||
var foo = async (a, b) => a * b;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user