├── .gitignore ├── Gruntfile.js ├── LICENSE ├── Makefile ├── README.md ├── index.js ├── macros ├── class.sjs ├── destructure.sjs ├── fat-arrow.sjs └── util.sjs ├── package.json └── tests ├── class.sjs ├── destructure.sjs └── fat-arrow.sjs /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | tests/*.js -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = function(grunt) { 3 | grunt.initConfig({ 4 | concat: { 5 | dist: { 6 | src: ['macros/util.sjs', 7 | 'macros/class.sjs', 8 | 'macros/fat-arrow.sjs', 9 | // destructure must come last, so that `var` in 10 | // any case macros is not overriden (those have 11 | // special syntax) 12 | 'macros/destructure.sjs'], 13 | dest: 'index.js' 14 | } 15 | }, 16 | sweetjs: { 17 | options: { 18 | modules: ['./index.js'] 19 | }, 20 | tests: { 21 | src: 'tests/**/*.sjs' 22 | } 23 | } 24 | }); 25 | 26 | grunt.loadNpmTasks('grunt-contrib-concat'); 27 | grunt.loadNpmTasks('grunt-sweet.js'); 28 | grunt.registerTask('default', ['concat']); 29 | }; 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, James Long 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in 13 | the documentation and/or other materials provided with the 14 | distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: 3 | grunt 4 | grunt sweetjs 5 | mocha --harmony -b -R tap tests 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # es6-macros 2 | 3 | This is a collection of [sweet.js](http://sweetjs.org/) macros that 4 | implement syntactic ES6 features that can be easily compiled out to 5 | ES5 JavaScript, which can be used today everywhere. 6 | 7 | **Warning**: This is still in development and most of these features are not completely compliant with ES6 yet. I wouldn't recommend using it for production code yet. 8 | 9 | Currently implemented: 10 | 11 | * destructuring (including elision and rest) 12 | * classes 13 | * fat arrow functions 14 | 15 | TODO: 16 | 17 | * rest and default arguments 18 | * spread operator for applying arguments 19 | * possibly limited `for of` support 20 | * possibly limited module support 21 | 22 | ## Using 23 | 24 | ``` 25 | $ npm install sweet.js es6-macros 26 | ``` 27 | 28 | Write your improved ES6 JavaScript, and compile it: 29 | 30 | ``` 31 | $ sjs -m es6-macros file.js 32 | ``` 33 | 34 | If you pass `-c` to sjs along with `-o output.js`, it will generate a 35 | sourcemap so you get good debugging too! 36 | 37 | ## Contributing 38 | 39 | To run the tests: 40 | 41 | ```bash 42 | npm install 43 | make 44 | ``` 45 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | macro _debug { 3 | case { $expr ... } => { 4 | function collapse(stx) { 5 | return stx.map(function(s) { 6 | if(s.token.inner) { 7 | return s.token.value[0] + 8 | collapse(s.token.inner) + 9 | s.token.value[1]; 10 | } 11 | 12 | return s.token.value; 13 | }).join(' '); 14 | } 15 | 16 | var stx = #{ $expr ... }; 17 | var val = makeValue(collapse(stx), #{ctx}); 18 | 19 | return withSyntax($val = [val]) { 20 | return #{$val} 21 | } 22 | } 23 | } 24 | 25 | 26 | 27 | // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-class-definitions 28 | 29 | macro install_super { 30 | case { $ctx $cls { $body ... } } => { 31 | var stx = #{ $body ... }; 32 | var saveThis = false; 33 | var res = search(stx); 34 | 35 | if(saveThis) { 36 | res = [makeKeyword('var', #{$ctx}), 37 | makeIdent('self', stx[0]), 38 | makePunc('=', #{$ctx}), 39 | makeIdent('this', #{$ctx})].concat(res); 40 | } 41 | 42 | return res; 43 | 44 | function search(stx, inFunction) { 45 | var res = []; 46 | var insideFunc = false; 47 | 48 | for(var i=0; i { 159 | function $typename $cparams { install_super $typename $cbody } 160 | 161 | $typename.prototype = Object.create($parent.prototype); 162 | $($typename.prototype.$mname = function $mname $mparams 163 | { install_super $typename $mbody };) ... 164 | } 165 | 166 | rule { 167 | $typename { 168 | constructor $cparams $cbody 169 | $($mname $mparams $mbody) ... 170 | } 171 | } => { 172 | function $typename $cparams $cbody 173 | 174 | $($typename.prototype.$mname = function $mname $mparams $mbody;) ... 175 | } 176 | 177 | rule { 178 | $typename $extends ... { 179 | $methods ... 180 | } 181 | } => { 182 | class_constructor $typename $extends ... { 183 | constructor() { 184 | Object.getPrototypeOf($typename.prototype).constructor.apply(this, arguments); 185 | } 186 | $methods ... 187 | } 188 | } 189 | } 190 | 191 | // hack to recurse down into `class` (which needs to be a let macro 192 | // because we don't have proper modules yet) 193 | macro class_constructor { 194 | rule { 195 | $typedef ... { 196 | $methods ... 197 | } 198 | } => { 199 | class $typedef ... { 200 | $methods ... 201 | } 202 | } 203 | } 204 | export class 205 | 206 | macro bind_args { 207 | case { $ctx $args $body ... } => { 208 | var stx = #{ $body ... }; 209 | var args = #{ $args }; 210 | 211 | function walk(stx) { 212 | for(var i=0; i { 236 | case infix { ($arg (,) ...) | $ctx {$body ...} } => { 237 | letstx $args = [makeIdent('__fa_args', #{$ctx})]; 238 | return #{ 239 | function($args, $arg (,) ...) { 240 | bind_args $args $body ... 241 | }.bind(this, typeof arguments !== "undefined" ? arguments : undefined) 242 | } 243 | } 244 | case infix { $arg:ident | $ctx {$body ...} } => { 245 | letstx $args = [makeIdent('__fa_args', #{$ctx})]; 246 | return #{ 247 | function($args, $arg) { 248 | bind_args $args $body ... 249 | }.bind(this, typeof arguments !== "undefined" ? arguments : undefined) 250 | } 251 | } 252 | case infix { ($arg (,) ...) | $ctx $guard:expr } => { 253 | letstx $args = [makeIdent('__fa_args', #{$ctx})]; 254 | return #{ 255 | function ($args, $arg (,) ...) { 256 | return bind_args $args $guard; 257 | }.bind(this, typeof arguments !== "undefined" ? arguments : undefined) 258 | } 259 | } 260 | case infix { $arg:ident | $ctx $guard:expr } => { 261 | letstx $args = [makeIdent('__fa_args', #{$ctx})]; 262 | return #{ 263 | function($args, $arg) { 264 | return bind_args $args $guard; 265 | }.bind(this, typeof arguments !== "undefined" ? arguments : undefined) 266 | } 267 | } 268 | } 269 | 270 | export => 271 | 272 | macro destructor { 273 | rule { [ $arr:arr_destructor (,) ... ] } => { (arr $arr ...) } 274 | rule { { $obj:obj_destructor (,) ... } } => { (obj $obj ...) } 275 | rule { $id:ident } => { (id $id) } 276 | } 277 | 278 | macro arr_destructor { 279 | rule { $id:ident = $default:expr } => { (arr_id $id $default) } 280 | rule { $id:ident } => { (arr_id $id) } 281 | rule { $[...] $id:ident } => { (arr_slice $id) } 282 | rule { $p:destructor } => { (arr_sub $p) } 283 | rule { } => { (elide) } 284 | } 285 | 286 | macro obj_destructor { 287 | rule { $key:ident $[:] $id:ident = $default:expr } => { 288 | (obj_id $key $id $default) 289 | } 290 | rule { $key:ident $[:] $id:ident } => { (obj_id $key $id) } 291 | rule { $key:ident $[:] $p:destructor } => { (obj_sub $key $p) } 292 | rule { $key:ident = $default:expr } => { (obj_id $key $key $default) } 293 | rule { $key:ident } => { (obj_id $key $key) } 294 | } 295 | 296 | macroclass succ { 297 | pattern { 298 | rule { $cur:lit } 299 | with $next = [makeValue(unwrapSyntax(#{$cur}) + 1, #{$cur})]; 300 | } 301 | } 302 | 303 | macro count_array { 304 | rule { () $i $k $o } => { 305 | } 306 | 307 | rule { ($item $arr ...) $i:succ $k $o } => { 308 | destruct $item $i$cur $k $o 309 | count_array ($arr ...) $i$next $k $o 310 | } 311 | } 312 | 313 | macro destruct { 314 | rule { (id $id) $k $o } => { $k $id = $o; } 315 | rule { (obj $obj ...) $k $o } => { $(destruct $obj $k $o) ... } 316 | rule { (obj_id $key $id $default) $k $o } => { $k $id = $o.$key != null ? $o.$key : $default; } 317 | rule { (obj_id $key $id) $k $o } => { $k $id = $o.$key; } 318 | rule { (obj_sub $key $p) $k $o } => { $k __o = $o.$key; destruct $p $k __o } 319 | rule { (arr $arr ...) $k $o } => { count_array ($arr ...) 0 $k $o } 320 | rule { (arr_id $id $default) $i $k $o } => { $k $id = $o[$i] != null ? $o[$i] : $default; } 321 | rule { (arr_id $id) $i $k $o } => { $k $id = $o[$i]; } 322 | rule { (arr_sub $p) $i $k $o } => { $k __a = $o[$i]; destruct $p $k __a } 323 | rule { (arr_slice $id) $i $k $o } => { $k $id = $o.slice($i); } 324 | rule { (elide) $i $k $o } => { } 325 | } 326 | 327 | let var = macro { 328 | rule { $id:ident } => { 329 | var $id 330 | } 331 | 332 | rule { $pattern:destructor = $rhs:expr ;... } => { 333 | var __ref = $rhs; 334 | destruct $pattern var __ref 335 | } 336 | } 337 | export var; 338 | 339 | let const = macro { 340 | rule { $id:ident } => { 341 | var $id 342 | } 343 | 344 | rule { $pattern:destructor = $rhs:expr ;... } => { 345 | var __ref = $rhs; 346 | destruct $pattern const __ref 347 | } 348 | } 349 | export const; 350 | 351 | let let = macro { 352 | rule { $id:ident } => { 353 | var $id 354 | } 355 | 356 | rule { $pattern:destructor = $rhs:expr ;... } => { 357 | var __ref = $rhs; 358 | destruct $pattern let __ref 359 | } 360 | } 361 | export let; 362 | -------------------------------------------------------------------------------- /macros/class.sjs: -------------------------------------------------------------------------------- 1 | 2 | // http://people.mozilla.org/~jorendorff/es6-draft.html#sec-class-definitions 3 | 4 | macro install_super { 5 | case { $ctx $cls { $body ... } } => { 6 | var stx = #{ $body ... }; 7 | var saveThis = false; 8 | var res = search(stx); 9 | 10 | if(saveThis) { 11 | res = [makeKeyword('var', #{$ctx}), 12 | makeIdent('self', stx[0]), 13 | makePunc('=', #{$ctx}), 14 | makeIdent('this', #{$ctx})].concat(res); 15 | } 16 | 17 | return res; 18 | 19 | function search(stx, inFunction) { 20 | var res = []; 21 | var insideFunc = false; 22 | 23 | for(var i=0; i { 134 | function $typename $cparams { install_super $typename $cbody } 135 | 136 | $typename.prototype = Object.create($parent.prototype); 137 | $($typename.prototype.$mname = function $mname $mparams 138 | { install_super $typename $mbody };) ... 139 | } 140 | 141 | rule { 142 | $typename { 143 | constructor $cparams $cbody 144 | $($mname $mparams $mbody) ... 145 | } 146 | } => { 147 | function $typename $cparams $cbody 148 | 149 | $($typename.prototype.$mname = function $mname $mparams $mbody;) ... 150 | } 151 | 152 | rule { 153 | $typename $extends ... { 154 | $methods ... 155 | } 156 | } => { 157 | class_constructor $typename $extends ... { 158 | constructor() { 159 | Object.getPrototypeOf($typename.prototype).constructor.apply(this, arguments); 160 | } 161 | $methods ... 162 | } 163 | } 164 | } 165 | 166 | // hack to recurse down into `class` (which needs to be a let macro 167 | // because we don't have proper modules yet) 168 | macro class_constructor { 169 | rule { 170 | $typedef ... { 171 | $methods ... 172 | } 173 | } => { 174 | class $typedef ... { 175 | $methods ... 176 | } 177 | } 178 | } 179 | export class 180 | -------------------------------------------------------------------------------- /macros/destructure.sjs: -------------------------------------------------------------------------------- 1 | macro destructor { 2 | rule { [ $arr:arr_destructor (,) ... ] } => { (arr $arr ...) } 3 | rule { { $obj:obj_destructor (,) ... } } => { (obj $obj ...) } 4 | rule { $id:ident } => { (id $id) } 5 | } 6 | 7 | macro arr_destructor { 8 | rule { $id:ident = $default:expr } => { (arr_id $id $default) } 9 | rule { $id:ident } => { (arr_id $id) } 10 | rule { $[...] $id:ident } => { (arr_slice $id) } 11 | rule { $p:destructor } => { (arr_sub $p) } 12 | rule { } => { (elide) } 13 | } 14 | 15 | macro obj_destructor { 16 | rule { $key:ident $[:] $id:ident = $default:expr } => { 17 | (obj_id $key $id $default) 18 | } 19 | rule { $key:ident $[:] $id:ident } => { (obj_id $key $id) } 20 | rule { $key:ident $[:] $p:destructor } => { (obj_sub $key $p) } 21 | rule { $key:ident = $default:expr } => { (obj_id $key $key $default) } 22 | rule { $key:ident } => { (obj_id $key $key) } 23 | } 24 | 25 | macroclass succ { 26 | pattern { 27 | rule { $cur:lit } 28 | with $next = [makeValue(unwrapSyntax(#{$cur}) + 1, #{$cur})]; 29 | } 30 | } 31 | 32 | macro count_array { 33 | rule { () $i $k $o } => { 34 | } 35 | 36 | rule { ($item $arr ...) $i:succ $k $o } => { 37 | destruct $item $i$cur $k $o 38 | count_array ($arr ...) $i$next $k $o 39 | } 40 | } 41 | 42 | macro destruct { 43 | rule { (id $id) $k $o } => { $k $id = $o; } 44 | rule { (obj $obj ...) $k $o } => { $(destruct $obj $k $o) ... } 45 | rule { (obj_id $key $id $default) $k $o } => { $k $id = $o.$key != null ? $o.$key : $default; } 46 | rule { (obj_id $key $id) $k $o } => { $k $id = $o.$key; } 47 | rule { (obj_sub $key $p) $k $o } => { $k __o = $o.$key; destruct $p $k __o } 48 | rule { (arr $arr ...) $k $o } => { count_array ($arr ...) 0 $k $o } 49 | rule { (arr_id $id $default) $i $k $o } => { $k $id = $o[$i] != null ? $o[$i] : $default; } 50 | rule { (arr_id $id) $i $k $o } => { $k $id = $o[$i]; } 51 | rule { (arr_sub $p) $i $k $o } => { $k __a = $o[$i]; destruct $p $k __a } 52 | rule { (arr_slice $id) $i $k $o } => { $k $id = $o.slice($i); } 53 | rule { (elide) $i $k $o } => { } 54 | } 55 | 56 | let var = macro { 57 | rule { $id:ident } => { 58 | var $id 59 | } 60 | 61 | rule { $pattern:destructor = $rhs:expr ;... } => { 62 | var __ref = $rhs; 63 | destruct $pattern var __ref 64 | } 65 | } 66 | export var; 67 | 68 | let const = macro { 69 | rule { $id:ident } => { 70 | const $id 71 | } 72 | 73 | rule { $pattern:destructor = $rhs:expr ;... } => { 74 | var __ref = $rhs; 75 | destruct $pattern const __ref 76 | } 77 | } 78 | export const; 79 | 80 | let let = macro { 81 | rule { $id:ident } => { 82 | let $id 83 | } 84 | 85 | rule { $pattern:destructor = $rhs:expr ;... } => { 86 | var __ref = $rhs; 87 | destruct $pattern let __ref 88 | } 89 | } 90 | export let; 91 | -------------------------------------------------------------------------------- /macros/fat-arrow.sjs: -------------------------------------------------------------------------------- 1 | macro bind_args { 2 | case { $ctx $args $body ... } => { 3 | var stx = #{ $body ... }; 4 | var args = #{ $args }; 5 | 6 | function walk(stx) { 7 | for(var i=0; i { 31 | case infix { ($arg (,) ...) | $ctx {$body ...} } => { 32 | letstx $args = [makeIdent('__fa_args', #{$ctx})]; 33 | return #{ 34 | function($args, $arg (,) ...) { 35 | bind_args $args $body ... 36 | }.bind(this, typeof arguments !== "undefined" ? arguments : undefined) 37 | } 38 | } 39 | case infix { $arg:ident | $ctx {$body ...} } => { 40 | letstx $args = [makeIdent('__fa_args', #{$ctx})]; 41 | return #{ 42 | function($args, $arg) { 43 | bind_args $args $body ... 44 | }.bind(this, typeof arguments !== "undefined" ? arguments : undefined) 45 | } 46 | } 47 | case infix { ($arg (,) ...) | $ctx $guard:expr } => { 48 | letstx $args = [makeIdent('__fa_args', #{$ctx})]; 49 | return #{ 50 | function ($args, $arg (,) ...) { 51 | return bind_args $args $guard; 52 | }.bind(this, typeof arguments !== "undefined" ? arguments : undefined) 53 | } 54 | } 55 | case infix { $arg:ident | $ctx $guard:expr } => { 56 | letstx $args = [makeIdent('__fa_args', #{$ctx})]; 57 | return #{ 58 | function($args, $arg) { 59 | return bind_args $args $guard; 60 | }.bind(this, typeof arguments !== "undefined" ? arguments : undefined) 61 | } 62 | } 63 | } 64 | 65 | export => 66 | -------------------------------------------------------------------------------- /macros/util.sjs: -------------------------------------------------------------------------------- 1 | 2 | macro _debug { 3 | case { $expr ... } => { 4 | function collapse(stx) { 5 | return stx.map(function(s) { 6 | if(s.token.inner) { 7 | return s.token.value[0] + 8 | collapse(s.token.inner) + 9 | s.token.value[1]; 10 | } 11 | 12 | return s.token.value; 13 | }).join(' '); 14 | } 15 | 16 | var stx = #{ $expr ... }; 17 | var val = makeValue(collapse(stx), #{ctx}); 18 | 19 | return withSyntax($val = [val]) { 20 | return #{$val} 21 | } 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-macros", 3 | "description": "A collection of sweet.js macros that implement ES6 features for ES5", 4 | "version": "0.0.7", 5 | "author": "James Long ", 6 | "engines": { 7 | "node": "*" 8 | }, 9 | "main": "index", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/jlongster/es6-macros.git" 13 | }, 14 | "license": [ 15 | { 16 | "type": "BSD", 17 | "url": "https://github.com/jlongster/es6-macros/blob/master/LICENSE" 18 | } 19 | ], 20 | "bugs": { 21 | "url": "https://github.com/jlongster/es6-macros/issues" 22 | }, 23 | "devDependencies": { 24 | "grunt": "~0.4.2", 25 | "grunt-contrib-concat": "~0.3.0", 26 | "sweet.js": "~0.5.0", 27 | "grunt-sweet.js": "~0.1.4", 28 | "expect.js": "~0.3.1" 29 | }, 30 | "tags": [ 31 | "sweet-macros" 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /tests/class.sjs: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var expect = require('expect.js'); 3 | 4 | describe('class', function() { 5 | it('should create a class', function() { 6 | class FooEmpty { 7 | } 8 | 9 | class FooSimple { 10 | constructor(x, y) { 11 | this.x = x; 12 | this.y = y; 13 | } 14 | } 15 | 16 | class FooWithMethod { 17 | length() { 18 | var x = this.x; 19 | var y = this.y; 20 | return x * x + y * y; 21 | } 22 | } 23 | 24 | class Foo { 25 | constructor(x, y) { 26 | this.x = x; 27 | this.y = y; 28 | } 29 | 30 | length() { 31 | var x = this.x; 32 | var y = this.y; 33 | return x * x + y * y; 34 | } 35 | 36 | getX() { 37 | return this.x; 38 | } 39 | 40 | getY() { 41 | return this.y; 42 | } 43 | } 44 | 45 | var f = new Foo(1, 2); 46 | expect(f.x).to.be(1); 47 | }); 48 | 49 | it('should support super', function() { 50 | class Foo { 51 | constructor(x) { 52 | this.fooX = x + 5; 53 | } 54 | 55 | getX() { 56 | return this.fooX; 57 | } 58 | } 59 | 60 | class Bar extends Foo { 61 | constructor(x) { 62 | super(x); 63 | this.barX = x; 64 | } 65 | 66 | getX() { 67 | return this.barX; 68 | } 69 | 70 | getFooX() { 71 | return super.getX(); 72 | } 73 | 74 | nested() { 75 | if(true) { 76 | if(this.barX > 2) { 77 | return super.getX(); 78 | } 79 | } 80 | 81 | return 1; 82 | } 83 | 84 | nestedFunction() { 85 | function run() { 86 | if(true) { 87 | return super.getX(); 88 | } 89 | } 90 | 91 | return run(); 92 | } 93 | 94 | getMethod() { 95 | return super.getX; 96 | } 97 | 98 | getMethod2() { 99 | return super['getX']; 100 | } 101 | 102 | } 103 | 104 | var b = new Bar(5); 105 | expect(b.fooX).to.be(10); 106 | expect(b.barX).to.be(5); 107 | expect(b.getX()).to.be(5); 108 | expect(b.getFooX()).to.be(10); 109 | expect(b.nested()).to.be(10); 110 | expect(b.nestedFunction()).to.be(10); 111 | expect(expect(b.getMethod().call(b)).to.be(10)); 112 | expect(expect(b.getMethod2().call(b)).to.be(10)); 113 | }); 114 | }); 115 | -------------------------------------------------------------------------------- /tests/destructure.sjs: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | var expect = require('expect.js'); 3 | 4 | macro testWithDecl { 5 | rule { $var $name } => { 6 | describe('destructuring ' + $name + ' keyword', function() { 7 | it('should handle normal declarations', function() { 8 | $var y = 5; 9 | $var w = function(){}; 10 | 11 | // for($var i=0; i<5; i++) { 12 | // } 13 | }); 14 | 15 | it('should basically work', function() { 16 | // basic destructuring 17 | $var {one, two} = { one: 1, two: 2 }; 18 | expect(one).to.be(1); 19 | expect(two).to.be(2); 20 | 21 | $var [foo, bar] = [1, 2]; 22 | expect(foo).to.be(1); 23 | expect(bar).to.be(2); 24 | 25 | // $var i = 0; 26 | // $var arr = [0, 5]; 27 | // for($var [i, n] = arr; i < 10; i++) { 28 | // expect(n).to.be(5); 29 | // } 30 | }); 31 | 32 | it('should rename', function() { 33 | // renaming 34 | $var { one: val1 } = { one: 1, two: 2 }; 35 | expect(val1).to.be(1); 36 | }); 37 | 38 | it('should set default values', function() { 39 | // default values 40 | $var {one = 1, two} = { two: 2 }; 41 | expect(one).to.be(1); 42 | expect(two).to.be(2); 43 | 44 | $var [foo, bar = 2] = [1]; 45 | expect(foo).to.be(1); 46 | expect(bar).to.be(2); 47 | }); 48 | 49 | it('should handle multiple levels', function() { 50 | // multiple levels of destructuring 51 | $var [foo, {bar, baz}] = [1, { bar: 2, baz: 3 }]; 52 | expect(foo).to.be(1); 53 | expect(bar).to.be(2); 54 | expect(baz).to.be(3); 55 | 56 | $var [one, {two, nums: [three, four]}] = [1, { two: 2, nums: [3, 4] }]; 57 | expect(one).to.be(1); 58 | expect(two).to.be(2); 59 | expect(three).to.be(3); 60 | expect(four).to.be(4); 61 | 62 | $var { fiz, biz: [mum, dum] } = { biz: [8, 9], fiz: 5 }; 63 | expect(fiz).to.be(5); 64 | expect(mum).to.be(8); 65 | expect(dum).to.be(9); 66 | 67 | // default values deep down 68 | $var [one_, {two_, three_ = 3000}] = [1, { two_: 2, three_: 3 }]; 69 | expect(one_).to.be(1); 70 | expect(two_).to.be(2); 71 | expect(three_).to.be(3); 72 | }); 73 | 74 | it('should handle elision', function() { 75 | $var [,,,four] = [1, 2, 3, 4]; 76 | expect(four).to.be(4); 77 | 78 | $var [,,three,,,six] = [1, 2, 3, 4, 5, 6]; 79 | expect(three).to.be(3); 80 | expect(six).to.be(6); 81 | }); 82 | 83 | it('should handle rest', function() { 84 | // 2 dots instead of 3 until this bug is fixed: 85 | // https://github.com/mozilla/sweet.js/issues/142 86 | 87 | $var [one, two, $[...] rest] = [1, 2, 3, 4]; 88 | expect(rest.length).to.be(2); 89 | expect(rest[0]).to.be(3); 90 | expect(rest[1]).to.be(4); 91 | 92 | $var [,, $[...] rest2] = [1, 2, 3, 4]; 93 | expect(rest2.length).to.be(2); 94 | expect(rest2[0]).to.be(3); 95 | expect(rest2[1]).to.be(4); 96 | }); 97 | }); 98 | } 99 | } 100 | 101 | testWithDecl var "var" 102 | testWithDecl let "let" 103 | testWithDecl const "const" 104 | 105 | // describe('destructuring', function() { 106 | // it('should handle function args', function() { 107 | // function foo(x, y, [z, w]) { 108 | // expect(z).to.be(5); 109 | // expect(w).to.be(6); 110 | // } 111 | // foo(1, 2, [5, 6]); 112 | 113 | // function bar(x, y, {z, w}) { 114 | // expect(z).to.be(5); 115 | // expect(w).to.be(6); 116 | // } 117 | // bar(1, 2, { z: 5, w: 6 }); 118 | 119 | // (function({ x, y, z }, callback) { 120 | // expect(x).to.be(3); 121 | // expect(y).to.be(4); 122 | // expect(z).to.be(5); 123 | // })({ x: 3, y: 4, z: 5 }); 124 | 125 | // function baz(x, y, { apple = true, 126 | // pear = false, 127 | // peach = 'default' }) { 128 | // expect(apple).to.be(true); 129 | // expect(pear).to.be(true); 130 | // expect(peach).to.be('default'); 131 | // } 132 | // baz(1, 2, { pear: true }); 133 | // }); 134 | // }); 135 | -------------------------------------------------------------------------------- /tests/fat-arrow.sjs: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var expect = require('expect.js'); 3 | 4 | describe('fat arrow', function() { 5 | it('should square array items', function() { 6 | var squared = [1,2,3].map(x => x * x) 7 | expect(squared[0]).to.be(1); 8 | expect(squared[1]).to.be(4); 9 | expect(squared[2]).to.be(9); 10 | }); 11 | 12 | it('should square array items with explicit return', function() { 13 | var squared = [1,2,3].map((x) => { 14 | return x * x 15 | }); 16 | expect(squared[0]).to.be(1); 17 | expect(squared[1]).to.be(4); 18 | expect(squared[2]).to.be(9); 19 | }); 20 | 21 | it('should not square array items', function() { 22 | var squared = [1,2,3].map((x) => { 23 | x * x 24 | }); 25 | expect(squared[0]).to.be(undefined); 26 | expect(squared[1]).to.be(undefined); 27 | expect(squared[2]).to.be(undefined); 28 | }); 29 | 30 | it('should bind this for infix 0 arguments', function() { 31 | var obj = { 32 | id: 1, 33 | getter: function() { 34 | var f = () => this.id; 35 | return f(); 36 | } 37 | }; 38 | expect(obj.getter()).to.be(1); 39 | }); 40 | 41 | it('should bind this for infix 1 arguments', function() { 42 | var obj = { 43 | id: 1, 44 | adder: function(x) { 45 | var f = x => this.id + x; 46 | return f(x) 47 | } 48 | }; 49 | expect(obj.adder(5)).to.be(6); 50 | }); 51 | 52 | it('should bind this for block syntax', function() { 53 | var obj = { 54 | id: 1, 55 | subtractor: function(x) { 56 | var f = (x, y, z) => { 57 | return this.id - x - y - z; 58 | } 59 | return f(x, 1, 2) 60 | } 61 | }; 62 | expect(obj.subtractor(5)).to.be(-7); 63 | }); 64 | 65 | it('should bind this for single-param block syntax', function() { 66 | var obj = { 67 | id: 1, 68 | subtractor: function(x) { 69 | var f = x => { 70 | return this.id - x; 71 | } 72 | return f(x) 73 | } 74 | }; 75 | expect(obj.subtractor(5)).to.be(-4); 76 | }); 77 | 78 | it('should implicitly return object', function() { 79 | var obj = id => ({ id: id }); 80 | expect(obj(1)).to.eql({id: 1}); 81 | }); 82 | 83 | it('should implicitly return object', function() { 84 | var obj = id => ({ id: id }); 85 | expect(obj(1)).to.eql({id: 1}); 86 | }); 87 | 88 | it('should interpret `arguments` as belonging to containing function', function() { 89 | var obj = { 90 | id: 1, 91 | subtractor: function() { 92 | var f = () => this.id - arguments[0]; 93 | return f(); 94 | } 95 | }; 96 | expect(obj.subtractor(5)).to.be(-4); 97 | 98 | function func() { 99 | var f = () => function(x) { 100 | return arguments[0]; 101 | } 102 | return f()(1); 103 | } 104 | expect(func()).to.be(1); 105 | 106 | var foo = () => function() { 107 | var bar = { arguments: 5 }; 108 | return bar.arguments; 109 | } 110 | expect(foo()()).to.be(5); 111 | }); 112 | }); 113 | --------------------------------------------------------------------------------