[Pkg-javascript-commits] [node-es-module-loader-0.17] 01/03: Import Upstream version 0.17.11+dfsg

Tim Potter tpot at hpe.com
Tue Oct 11 05:46:58 UTC 2016


This is an automated email from the git hooks/post-receive script.

tpot-guest pushed a commit to branch master
in repository node-es-module-loader-0.17.

commit cdc2f3224402a5878224a92d99194256f2728ba8
Author: Tim Potter <tpot at hpe.com>
Date:   Thu Sep 29 17:07:44 2016 +1000

    Import Upstream version 0.17.11+dfsg
---
 .agignore                            |   1 +
 .gitignore                           |   6 +
 .jshintrc                            |  12 +
 .travis.yml                          |  39 ++
 Gruntfile.js                         |  80 ++++
 LICENSE-MIT                          |  22 +
 README.md                            | 193 +++++++++
 demo/index.html                      |  68 +++
 demo/test1.js                        |   1 +
 demo/test2.js                        |   5 +
 docs/circular-references-bindings.md |  53 +++
 docs/loader-config.md                |  66 +++
 docs/loader-extensions.md            | 127 ++++++
 docs/production-workflows.md         |  54 +++
 docs/system-register.md              | 106 +++++
 docs/tracing-api.md                  |  36 ++
 index.js                             |  28 ++
 karma-benchmark.conf.js              |  31 ++
 karma.conf.js                        | 181 ++++++++
 package.json                         |  69 +++
 src/declarative.js                   | 297 +++++++++++++
 src/dynamic-only.js                  |  39 ++
 src/loader.js                        | 806 +++++++++++++++++++++++++++++++++++
 src/module-tag.js                    |  37 ++
 src/system-fetch.js                  | 131 ++++++
 src/system-resolve.js                |  45 ++
 src/system.js                        |  63 +++
 src/transpiler.js                    |  86 ++++
 src/url-polyfill.js                  |  65 +++
 src/wrapper-end.js                   |  21 +
 src/wrapper-start.js                 |  82 ++++
 test/_browser.js                     |   9 +
 test/_helper.js                      |  59 +++
 test/_node-babel.js                  |  16 +
 test/_node-traceur.js                |  13 +
 test/_node-typescript.js             |  14 +
 test/browser-script-type-module.js   |  13 +
 test/custom-loader.js                | 148 +++++++
 test/custom-loader.spec.js           | 102 +++++
 test/loader/amd-dep.js               |   5 +
 test/loader/amd.js                   |   5 +
 test/loader/anon.js                  |   1 +
 test/loader/async-norm.js            |   3 +
 test/loader/custom-folder/path.js    |   1 +
 test/loader/custom-path.js           |   1 +
 test/loader/custom.js                |   1 +
 test/loader/error1-parent.js         |   1 +
 test/loader/master.js                |   1 +
 test/loader/module.js                |   7 +
 test/loader/moduleName.js            |   1 +
 test/loader/named.js                 |   1 +
 test/loader/specific-path.js         |   1 +
 test/loader/test.js                  |   1 +
 test/loads/_a.js                     |   4 +
 test/loads/_b.js                     |   2 +
 test/loads/_c.js                     |   2 +
 test/loads/_d.js                     |   1 +
 test/loads/_e.js                     |   2 +
 test/loads/_f.js                     |   2 +
 test/loads/_g.js                     |   1 +
 test/loads/_h.js                     |   3 +
 test/loads/_i.js                     |   2 +
 test/loads/a.js                      |   2 +
 test/loads/b.js                      |   1 +
 test/loads/c.js                      |   3 +
 test/loads/deperror.js               |   1 +
 test/loads/load-non-existent.js      |   1 +
 test/loads/main.js                   |   1 +
 test/loads/s.js                      |   3 +
 test/manual/source-maps/test.html    |  13 +
 test/manual/source-maps/test.js      |   4 +
 test/perf.html                       |  89 ++++
 test/perf.js                         | 137 ++++++
 test/syntax/circular1.js             |  13 +
 test/syntax/circular2.js             |  13 +
 test/syntax/direct.js                |   1 +
 test/syntax/es6-dep.js               |   2 +
 test/syntax/es6-file.js              |  14 +
 test/syntax/es6-generator.js         |   3 +
 test/syntax/es6-withdep.js           |   2 +
 test/syntax/es6.js                   |   1 +
 test/syntax/even.js                  |  10 +
 test/syntax/export-default.js        |   3 +
 test/syntax/export-star.js           |   2 +
 test/syntax/export-star2.js          |   4 +
 test/syntax/export.js                |  10 +
 test/syntax/import.js                |  11 +
 test/syntax/odd.js                   |   5 +
 test/syntax/rebinding.js             |   1 +
 test/syntax/reexport-binding.js      |   1 +
 test/syntax/reexport1.js             |   1 +
 test/syntax/reexport2.js             |   2 +
 test/syntax/script.js                |   1 +
 test/syntax/star-dep.js              |   1 +
 test/syntax/test-file.js             |   5 +
 test/system.normalize.spec.js        |  69 +++
 test/system.spec.js                  | 452 ++++++++++++++++++++
 test/worker/es6.js                   |   1 +
 test/worker/worker-babel.js          |  12 +
 test/worker/worker-traceur.js        |   8 +
 test/worker/worker-typescript.js     |   9 +
 101 files changed, 4185 insertions(+)

diff --git a/.agignore b/.agignore
new file mode 100644
index 0000000..849ddff
--- /dev/null
+++ b/.agignore
@@ -0,0 +1 @@
+dist/
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..98754ac
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+node_modules
+bower_components
+tmp
+coverage
+.DS_Store
+*.sw?
diff --git a/.jshintrc b/.jshintrc
new file mode 100644
index 0000000..55e9674
--- /dev/null
+++ b/.jshintrc
@@ -0,0 +1,12 @@
+{
+  "curly": true,
+  "eqeqeq": true,
+  "immed": true,
+  "latedef": true,
+  "newcap": true,
+  "noarg": true,
+  "sub": true,
+  "undef": true,
+  "boss": true,
+  "eqnull": true
+}
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..c12ed0c
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,39 @@
+---
+git:
+  depth: 1
+language: node_js
+node_js:
+  - '0.10'
+  - '0.11'
+  - '0.12'
+  - 'iojs'
+  - 'stable'
+env:
+  global:
+    - SAUCE_LABS=false PARSER=false OPTIONS=""
+  matrix:
+    - PARSER="traceur"
+    - PARSER="babel"
+    - PARSER="typescript"
+matrix:
+  include:
+    - node_js: "0.10"
+      env: SAUCE_LABS=true PARSER="traceur"
+    - node_js: "0.10"
+      env: SAUCE_LABS=true PARSER="babel"
+    - node_js: "0.10"
+      env: SAUCE_LABS=true PARSER="typescript"
+    #- node_js: "0.10"
+   #   env: SAUCE_LABS=true PARSER="traceur" OPTIONS="--ie8"
+before_install:
+  - export CHROME_BIN=chromium-browser
+  - export DISPLAY=:99.0
+  - sh -e /etc/init.d/xvfb start
+  - npm update -g
+  - npm install -g karma-cli grunt-cli
+before_script:
+  - grunt
+script:
+  - npm run test:node
+  - npm run test:browser-$PARSER
+  - "[ $SAUCE_LABS == false ] || npm run test:browser-$PARSER -- --saucelabs $OPTIONS"
diff --git a/Gruntfile.js b/Gruntfile.js
new file mode 100644
index 0000000..0a75687
--- /dev/null
+++ b/Gruntfile.js
@@ -0,0 +1,80 @@
+'use strict';
+
+module.exports = function (grunt) {
+  grunt.initConfig({
+    pkg: grunt.file.readJSON('package.json'),
+    meta: {
+      banner: '/*\n *  <%= pkg.name %> v<%= pkg.version %>\n' +
+        '<%= pkg.homepage ? " *  " + pkg.homepage + "\\n" : "" %>' +
+        ' *  Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
+        ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n */'
+    },
+    jshint: {
+      options: {
+        jshintrc: '.jshintrc'
+      },
+      dist: [
+        'lib/index.js'
+      ]
+    },
+    concat: {
+      dist: {
+        files: {
+          'dist/<%= pkg.name %>.src.js': [
+            'src/url-polyfill.js',
+            'src/wrapper-start.js',
+            'src/loader.js',
+            'src/dynamic-only.js',
+            'src/system.js',
+            'src/system-resolve.js',
+            'src/system-fetch.js',
+            'src/wrapper-end.js'
+          ],
+          'dist/<%= pkg.name %>-dev.src.js': [
+            'src/url-polyfill.js',
+            'src/wrapper-start.js',
+            'src/loader.js',
+            'src/declarative.js',
+            'src/transpiler.js',
+            'src/system.js',
+            'src/system-resolve.js',
+            'src/system-fetch.js',
+            'src/module-tag.js',
+            'src/wrapper-end.js'
+          ]
+        }
+      }
+    },
+    uglify: {
+      options: {
+        banner: '<%= meta.banner %>\n',
+        compress: {
+          drop_console: true
+        },
+        sourceMap: true
+      },
+      dist: {
+        options: {
+          banner: '<%= meta.banner %>\n'
+        },
+        src: 'dist/<%= pkg.name %>.src.js',
+        dest: 'dist/<%= pkg.name %>.js'
+      },
+      devDist: {
+        options: {
+          banner: '<%= meta.banner %>\n'
+        },
+        src: 'dist/<%= pkg.name %>-dev.src.js',
+        dest: 'dist/<%= pkg.name %>-dev.js'
+      }
+    }
+  });
+
+  grunt.loadNpmTasks('grunt-contrib-jshint');
+  grunt.loadNpmTasks('grunt-contrib-uglify');
+  grunt.loadNpmTasks('grunt-contrib-concat');
+
+  grunt.registerTask('lint', ['jshint']);
+  grunt.registerTask('compile', ['concat']);
+  grunt.registerTask('default', [/*'jshint', */'concat', 'uglify']);
+};
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..be26339
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,22 @@
+Copyright (c) 2013-2016 Guy Bedford, Luke Hoban, Addy Osmani
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..69cdd23
--- /dev/null
+++ b/README.md
@@ -0,0 +1,193 @@
+# ES6 Module Loader Polyfill [![Build Status][travis-image]][travis-url]
+
+_For upgrading to ES6 Module Loader 0.17, [read the release notes here](https://github.com/ModuleLoader/es6-module-loader/releases/tag/v0.17.0)._
+
+Dynamically loads ES6 modules in browsers and [NodeJS](#nodejs-use) with support for loading existing and custom module formats through loader hooks.
+
+This project implements dynamic module loading through `System` exactly to the previous ES6-specified loader API at [2014-08-24 ES6 Specification Draft Rev 27, Section 15](http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts#august_24_2014_draft_rev_27). The specification for the module loader was removed from the ES6/ES2015 specification in 2014, and a new loader implementing the new draft [WhatWG loader spec](https://github.com/whatwg/loader) is pending alpha release on  [...]
+
+* Provides an asynchronous loader (`System.import`) to [dynamically load ES6 modules](#getting-started).
+* Supports [Traceur](https://github.com/google/traceur-compiler), [Babel](http://babeljs.io/) and [TypeScript](https://github.com/Microsoft/TypeScript/) for compiling ES6 modules and syntax into ES5 in the browser with source map support.
+* Fully supports [ES6 circular references and live bindings](docs/circular-references-bindings.md).
+* Includes [`paths` implementation](docs/loader-config.md).
+* Can be used as a [tracing tool](docs/tracing-api.md) for static analysis of modules.
+* Supports IE8+, with IE9+ support for ES6 development without pre-compilation.
+* The minified production loader is under 5KB minified and gzipped, making it suitable for production use, provided that modules are [built into ES5 making them independent of Traceur](docs/production-workflows.md).
+* Supports declaring modules with `<script type="module">`, the precursor of the proposed [`<module>` tag](https://github.com/dherman/module-tag/).
+
+For an overview of build workflows, [see the production guide](docs/production-workflows.md).
+
+For an example of a universal module loader based on this polyfill for loading AMD, CommonJS and globals, see [SystemJS](https://github.com/systemjs/systemjs).
+
+### Documentation
+
+* [Configuring the loader](docs/loader-config.md)
+* [Production workflows](docs/production-workflows.md)
+* [Circular References & Bindings](docs/circular-references-bindings.md)
+* [Extending the loader through loader hooks](docs/loader-extensions.md)
+* [Tracing API](docs/tracing-api.md)
+
+### Getting Started
+
+If using ES6 syntax (optional), include `traceur.js`, `babel.js` or `typescript.js` in the page first then include `es6-module-loader-dev.js`:
+
+```html
+  <script src="traceur.js"></script>
+  <script src="es6-module-loader-dev.js"></script>
+```
+
+To use Babel, load Babel's `browser.js` instead and set the transpiler to `babel` with the loader configuration:
+
+```html
+<script>
+  System.transpiler = 'babel';
+</script>
+```
+
+To use TypeScript, set the transpiler to `typescript` in the loader configuration:
+
+```html
+<script>
+  System.transpiler = 'typescript';
+</script>
+```
+
+Then we can write any ES6 module:
+
+mymodule.js:
+```javascript
+  export class q {
+    constructor() {
+      console.log('this is an es6 class!');
+    }
+  }
+```
+
+and load the module dynamically in the browser
+
+```html
+<script>
+  System.import('mymodule').then(function(m) {
+    new m.q();
+  });
+</script>
+```
+
+The dynamic loader returns a `Module` object, which contains getters for the named exports (in this case, `q`).
+
+See the [demo folder](https://github.com/ModuleLoader/es6-module-loader/blob/master/demo/index.html) in this repo for a working example demonstrating module loading in the browser both with `System.import` and with the module-type script tag.
+
+Although `System.import()` does not support the import of multiple modules defined in an array, because `System.import()` returns a Promise, this can be achieved by creating an array of `System.import`s and using `Promise.all()`.
+
+#### Setting transpilation options
+
+If using Traceur, these can be set with:
+
+```javascript
+System.traceurOptions = {...};
+```
+
+With Babel:
+
+```javascript
+System.babelOptions = {...};
+```
+
+With TypeScript:
+
+```javascript
+System.typescriptOptions = {...};
+```
+
+#### Module Tag
+
+The module tag is specified to provide a new entry point for using module syntax in browsers. This is because normal `<script>` tags must remain backwards-compatible so won't support this new mechanism.
+
+This polyfill provides simple support for the `<script type="module">` tag via:
+
+```html
+<script type="module">
+  // loads the 'q' export from 'mymodule.js' in the same path as the page
+  import { q } from 'mymodule';
+
+  new q(); // -> 'this is an es6 class!'
+</script>
+```
+
+Because it is only possible to load ES6 modules with this tag, it is not suitable for production use in this way.
+
+#### NodeJS Use
+
+```
+  npm install es6-module-loader babel traceur typescript
+```
+
+It is important that Babel, Traceur or TypeScript is installed into the path in order to be found, since these are no longer project dependencies.
+
+For use in NodeJS, the `Loader` and `System` globals are provided as exports:
+
+index.js:
+```javascript
+  var System = require('es6-module-loader').System;
+  /*  
+   *  Include:
+   *    System.transpiler = 'babel'; 
+   *  to use Babel instead of Traceur or
+   *    System.transpiler = 'typescript';
+   *  to use TypeScript
+   */
+
+  System.import('some-module').then(function(m) {
+    console.log(m.p);
+  });
+```
+
+some-module.js:
+```javascript
+  export var p = 'NodeJS test';
+```
+
+Running the application:
+```
+> node index.js
+NodeJS test
+```
+
+## Contributing
+In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [grunt](https://github.com/cowboy/grunt).
+
+_Also, please don't edit files in the "dist" subdirectory as they are generated via grunt. You'll find source code in the "lib" subdirectory!_
+
+## Testing
+
+- `npm run test:node` will use node to  to run the tests
+- `npm run test:browser` will run `npm run test:browser-babel`, `npm run test:browser-traceur` and `npm run test:browser-typescript`
+- `npm run test:browser-[transpiler]` use karma to run the tests with Traceur, Babel or TypeScript.
+- `npm run test:browser:perf` will use karma to run benchmarks
+
+`npm run test:browser-[transpiler]` supports options after a double dash (`--`) :
+
+- You can use the `--polyfill` option to test the code with polyfill.
+
+- You can use the `--coverage` option to test and extract coverage info.
+
+- You can use the `--ie8` option to test the code in the ie8 scope only.
+
+- You can use the `--saucelabs` option to use karma and saucelabs to run the tests in various browsers.
+Note: you will need to export your username and key to launch it.
+
+  ```sh
+  export SAUCE_USERNAME={your user name} && export SAUCE_ACCESS_KEY={the access key that you see once logged in}
+  npm run test:browsers -- --saucelabs
+  ```
+
+## Credit
+Copyright (c) 2015 Luke Hoban, Addy Osmani, Guy Bedford
+
+## License
+Licensed under the MIT license.
+
+[travis-url]: https://travis-ci.org/ModuleLoader/es6-module-loader
+[travis-image]: https://travis-ci.org/ModuleLoader/es6-module-loader.svg?branch=master
+[saucelabs-url]: https://saucelabs.com/u/guybedford
+[saucelabs-image]: https://saucelabs.com/buildstatus/guybedford
diff --git a/demo/index.html b/demo/index.html
new file mode 100644
index 0000000..611ad20
--- /dev/null
+++ b/demo/index.html
@@ -0,0 +1,68 @@
+<!doctype html>
+<head>
+  <style>
+    body {
+      background: blue;
+      color: #fff;
+    }
+    pre {
+      color: black;
+      background: white;
+    }
+  </style>
+</head>
+<body>
+  <div role="main">
+    <h1>Module Loader Polyfill</h1>
+    <p>Check the console in your browser developer tools! This code is currently loaded in the page:</p>
+    <pre>
+  <script src="../node_modules/traceur/bin/traceur.js"></script>
+  <script src="../dist/es6-module-loader-dev.js"></script>
+  <script type="module">
+    import { hello } from 'test1.js';
+    console.log(hello); // -> world
+
+    // es6 syntax
+    var a, b;
+    [a, b] = [1, 2];
+    console.log(a); // 1
+  </script>
+    </pre>
+    <p>Click on the button below and this function will be run:</p>
+    <pre>
+  <script>
+    function buttonClick() {
+      // dynamic loading API
+      System.import('test2.js').then(function(module) {
+        new module.Foo();
+      });
+    }
+  </script>
+    </pre>
+    <button onclick="buttonClick()">Load test2</button>
+    <p>Note that if you click on the button again, a new Foo module will be created, but 'test2' will not be reloaded.</p>
+  </div>
+  <footer>
+  </footer>
+
+  <script src="../node_modules/traceur/bin/traceur.js"></script>
+  <script src="../dist/es6-module-loader-dev.js"></script>
+  <script type="module">
+    import { hello } from 'test1.js';
+    console.log(hello); // -> world
+
+    // es6 syntax
+    var a, b;
+    [a, b] = [1, 2];
+    console.log(a); // -> 1
+  </script>
+  <script>
+    function buttonClick() {
+      // dynamic loading API
+      System.import('test2.js').then(function(module) {
+        new module.Foo();
+      });
+    }
+  </script>
+</body>
+</html>
diff --git a/demo/test1.js b/demo/test1.js
new file mode 100644
index 0000000..fd916c8
--- /dev/null
+++ b/demo/test1.js
@@ -0,0 +1 @@
+export var hello = 'world';
\ No newline at end of file
diff --git a/demo/test2.js b/demo/test2.js
new file mode 100644
index 0000000..3063f50
--- /dev/null
+++ b/demo/test2.js
@@ -0,0 +1,5 @@
+export class Foo {
+  constructor() {
+    console.log('Created the ES6 class foo!');
+  }
+}
\ No newline at end of file
diff --git a/docs/circular-references-bindings.md b/docs/circular-references-bindings.md
new file mode 100644
index 0000000..a8f57d7
--- /dev/null
+++ b/docs/circular-references-bindings.md
@@ -0,0 +1,53 @@
+### Circular References & Bindings
+
+#### Zebra-Striping
+
+All [AMD](http://requirejs.org/docs/api.html#circular), [CommonJS](http://nodejs.org/api/modules.html#modules_cycles), 
+and [ES6](https://github.com/ModuleLoader/es6-module-loader#circular-references--bindings) treat circular dependencies differently. 
+Handling this problem is one of the innovations of the loader spec, using a technique called **zebra-striping**. 
+This involves analyzing the dependency tree and forming alternate layers of ES6 / non-ES6 modules with circular 
+references in each layer for linking. The layers are then individually linked, with the appropriate circular reference 
+handling being done within each layer. This allows CommonJS circular references to interact with ES6 circular references. 
+Inter-format circular references are not supported as they would be across layers.
+
+This loader implementation handles zebra-striping automatically, allowing a loader like [SystemJS](https://github.com/systemjs/systemjs)
+to support all module formats with exact circular reference support.
+
+#### ES6 Circular References & Bindings
+
+ES6 circular references and bindings behave in the following way:
+
+* Bindings are set up before module execution.
+* Execution is run from depth-first left to right on the module tree stopping at circular references.
+* Bindings are live - an adjustment to an export of one module affects all modules importing it, but it can 
+only be modified in the defining module.
+
+even.js
+```javascript
+  import { odd } from './odd'
+
+  export var counter = 0;
+
+  export function even(n) {
+    counter++;
+    return n == 0 || odd(n - 1);
+  }
+```
+
+odd.js
+```javascript
+  import { even } from './even';
+
+  export function odd(n) {
+    return n != 0 && even(n - 1);
+  }
+```
+
+```javascript
+  System.import('even').then(function(m) {
+    m.even(10);
+    m.counter;
+    m.even(20);
+    m.counter;
+  });
+```
\ No newline at end of file
diff --git a/docs/loader-config.md b/docs/loader-config.md
new file mode 100644
index 0000000..a2039b9
--- /dev/null
+++ b/docs/loader-config.md
@@ -0,0 +1,66 @@
+### Paths Implementation
+
+The System loader provides paths rules used by the standard `locate` function.
+
+For example, we might want to load `jquery` from a CDN location. For this we can provide a paths rule:
+
+```javascript
+  System.paths['jquery'] = '//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js';
+  System.import('jquery').then(function($) {
+    // ...
+  });
+```
+
+Any reference to `jquery` in other modules will also use this same version.
+
+It is also possible to define wildcard paths rules. The most specific rule will be used:
+
+```javascript
+  System.paths['lodash/*'] = '/js/lodash/*.js'
+  System.import('lodash/map').then(function(map) {
+    // ...
+  });
+```
+
+Rule specificity is determined by an exact paths match first, followed by the last deepest wildcard match.
+
+### Custom Compilation Options
+
+Custom [Traceur compilation options](https://github.com/google/traceur-compiler/wiki/Options-for-Compiling) can be set through `System.traceurOptions`, eg:
+
+```javascript
+System.traceurOptions = { annotations = true };
+```
+
+or if using Babel:
+
+```javascript
+System.babelOptions = { experimental: true };
+```
+
+or TypeScript:
+
+```javascript
+System.typescriptOptions = {};
+```
+
+### Finding the Transpiler
+
+For Babel use the `browser.js` file contained in the `babel-core` npm module. For Traceur use the `traceur.js` file contained in the `traceur` npm module bin folder.
+
+The transpiler is loaded as a module itself, so will follow normal paths rules.
+> 
+To set custom paths to Babel or Traceur use paths configuration:
+
+```javascript
+System.paths['traceur'] = 'path/to/traceur.js';
+```
+
+Alternatively if you know that the transpiler will be needed, it will be detected from the global (`window[System.transpiler]`) when the first module is loaded, so can be loaded before ES6 Module Loader:
+
+```html
+<script src="traceur.js"></script>
+<script src="es6-module-loader.js"></script>
+```
+
+> TypeScript can be loaded in the browser, but in Node, must already be defined as a global before loading an ES6 file.
\ No newline at end of file
diff --git a/docs/loader-extensions.md b/docs/loader-extensions.md
new file mode 100644
index 0000000..ed19800
--- /dev/null
+++ b/docs/loader-extensions.md
@@ -0,0 +1,127 @@
+### Extending the ES6 Loader
+
+The loader pipeline is based on the following hooks:
+
+* Normalize: Given the import name, provide the normalized name for the resource.
+* Locate: Given a normalized module name, provide the URL for the resource.
+* Fetch: Given a URL for a resource, fetch its content.
+* Translate: Given module source, make any source modifications.
+* Instantiate: Given module source, determine its dependencies, and how to execute it.
+
+Variations of these hooks can allow creating many different styles of loader.
+
+Each hook can either return a result directly, or a promise for the result.
+
+To use custom loader hooks, one would typically override the System loader hooks on the `System` global directly:
+
+```javascript
+  // store the old normalization function
+  var systemNormalize = System.normalize;
+  // override the normalization function
+  System.normalize = function(name, parentName, parentAddress) {
+    if (name == 'my/custom/rule')
+      return 'custom/name';
+    else
+      return systemNormalize.call(this, name, parentName, parentAddress);
+  }
+```
+
+### Custom Extension Example - Cache Busting Extension
+
+```javascript
+var systemLocate = System.locate;
+System.locate = function(load) {
+  var System = this; // its good to ensure exact instance-binding
+  return Promise.resolve(systemLocate.call(this, load)).then(function(address) {
+    return address + System.cacheBust;
+  });
+}
+System.cacheBust = '?bust=' + Date.now();
+```
+
+The above will add a customizable cache-busting query parameter to all requests. Custom filtering could even be added as well to only do this for certain requests.
+
+### Creating a Custom Loader
+
+A custom loader can be created with:
+
+```javascript
+  var myLoader = new LoaderPolyfill({
+    normalize: ...,
+    locate: ...,
+    fetch: ...,
+    translate: ...,
+    instantiate: ...
+  });
+```
+
+### Loader Hooks
+
+The signatures for all the loader hooks is provided below:
+
+```javascript
+
+/*
+ * name: the unnormalized module name
+ * parentName: the canonical module name for the requesting module
+ * parentAddress: the address of the requesting module
+ */
+function normalize(name, parentName, parentAddress) {
+  return resolvedName;
+}
+
+/*
+ * load.name the canonical module name
+ * load.metadata a metadata object that can be used to store
+ *   derived metadata for reference in other hooks
+ */
+function locate(load) {
+  return this.baseURL + '/' + load.name + '.js';
+}
+
+/*
+ * load.name: the canonical module name
+ * load.address: the URL returned from locate
+ * load.metadata: the same metadata object by reference, which
+ *   can be modified
+ */
+function fetch(load) {
+  return new Promise(function(resolve, reject) {
+    myFetchMethod.get(load.address, resolve, reject);
+  });
+}
+
+/*
+ * load.name
+ * load.address
+ * load.metadata
+ * load.source: the fetched source
+ */
+function translate(load) {
+  return load.source;
+}
+
+/*
+ * load identical to previous hooks, but load.source
+ * is now the translated source
+ */
+function instantiate(load) {
+  // an empty return indicates standard ES6 linking and execution
+  return;
+
+  // a return value creates a "dynamic" module linking
+  return {
+    deps: ['some', 'dependencies'],
+    execute: function() {
+      return loader.newModule({
+        some: 'export'
+      });
+    }
+  };
+}
+```
+
+For a more in-depth overview of creating with custom loaders, some resources are provided below:
+
+* [ES6 Loader API guide](https://gist.github.com/dherman/7568080)
+* [Yehuda Katz's essay](https://gist.github.com/wycats/51c96e3adcdb3a68cbc3) (outdated)
\ No newline at end of file
diff --git a/docs/production-workflows.md b/docs/production-workflows.md
new file mode 100644
index 0000000..c4ffe95
--- /dev/null
+++ b/docs/production-workflows.md
@@ -0,0 +1,54 @@
+### Moving to Production
+
+When in production, it is not suitable to load ES6 modules and syntax in the browser.
+
+#### System.register Output
+
+There is a `modules=instantiate` build output in Traceur and `modules=system` output in Babel and TypeScript that can be used with the ES6 Module Loader, 
+provided it has been extended with support for the System.register format.
+
+This is available from the [system-register-only](https://github.com/systemjs/systemjs/tree/0.17.0/dist) SystemJS build of the loader.
+
+The benefit of the [System.register output format](system-register.md) is that it provides [full support for circular references and live module bindings](circular-references-bindings.md).
+
+A basic example of using this extension with a Traceur build would be the following (although the related similar workflow would apply for Babel):
+
+1. Build all ES6 modules into ES5 System.register form:
+
+  ```
+    traceur --out app-build.js app/app.js --modules=instantiate
+  ```
+
+2. If using additional ES6 features apart from modules syntax, load [`traceur-runtime.js`](https://raw.githubusercontent.com/jmcriffey/bower-traceur-runtime/0.0.79/traceur-runtime.js) (also included in the `bin` folder when installing Traceur through Bower or npm). Then include `es6-module-loader.js` and then apply the register extension before doing the import or loading the bundle as a script:
+
+  ```html
+    <script src="traceur-runtime.js"></script>
+    <script src="system-register-only.js"></script>
+
+    <!-- now include the bundle -->
+    <script src="app-build.js"></script>
+
+    <!-- now we can import and get modules from the bundle -->
+    <script>
+      System.import('app/app');
+    </script>
+  ```
+
+* Note that `app-build.js` must be at the base-level for this to work.
+* Also, the name we import, `app/app` must be the same name given to Traceur's compiler.
+
+#### Building into separate files
+
+We can also build separate files with:
+
+```
+  traceur --dir app app-build --modules=instantiate
+```
+
+With the above, we can load from the separate files identical to loading ES6, but with full CSP compatibility.
+
+#### Building across module formats
+
+If using a loader like [SystemJS](https://github.com/systemjs/systemjs) to load different module formats, then a build can also be performed across module formats as well.
+
+See [SystemJS builder](https://github.com/systemjs/builder) for a combined approach.
diff --git a/docs/system-register.md b/docs/system-register.md
new file mode 100644
index 0000000..948b68f
--- /dev/null
+++ b/docs/system-register.md
@@ -0,0 +1,106 @@
+### What it is
+
+System.register can be considered as a new module format designed to support the exact semantics of ES6 modules within ES5. 
+It is a format that was developed out of collaboration and is supported as a module output in Traceur (as _instantiate_), 
+Babel and TypeScript (as _system_). All dynamic binding and circular reference behaviors supported by ES6 modules are supported 
+by this format. In this way it acts as a safe and comprehensive target format for the polyfill path into ES6 modules.
+
+To run the format, a suitable loader implementation needs to be used that understands how to execute it. Currently these include 
+[SystemJS](https://github.com/systemjs/systemjs), [SystemJS Self-Executing Bundles](https://github.com/systemjs/builder#sfx-bundles) 
+and [ES6 Micro Loader](https://github.com/caridy/es6-micro-loader). The ES6 Module Loader polyfill also uses this format 
+internally when transpiling and executing ES6.
+
+#### Bundled vs On-Demand
+
+Just like AMD define, System.register can be both named and anonymous.
+
+When a module name string is provided as the first argument in the `System.register` call, the format is suitable for 
+naming multiple modules in the same JS file creating a bundle format.
+
+When files are separately compiled, with only one `System.register` call per module, the name should not be set. 
+This allows the importing environment to name the module into whatever namespace it likes without imposing a specific 
+schema for maximum portability.
+
+### How it works
+
+When compiling ES6 modules to ES5, the Traceur `instantiate` output and Babel `system` output generates something like the following:
+
+```javascript
+  import { p as q } from './dep';
+ 
+  var s = 'local';
+  
+  export function func() {
+    return q;
+  }
+
+  export class C {
+  }
+```
+
+->
+
+```javascript
+  System.register(['./dep'], function($__export) {
+    var s, C, q;
+    function func() {
+      return q;
+    }
+    $__export('func', func);
+    return {
+      setters: [
+      // every time a dependency updates an export, 
+      // this function is called to update the local binding
+      // the setter array matches up with the dependency array above
+      function(m) {
+        q = m.p;
+      }
+      ],
+      execute: function() {
+        // use the export function to update the exports of this module
+        s = 'local';
+        $__export('C', C = $traceurRuntime.createClass(...));
+      }
+    };
+  });
+```
+
+Initial exports and changes to exports are pushed through the setter function, `$__export`. Values of dependencies and 
+changes to dependency bindings are set through the dependency setters, `setters`, corresponding to the `$__export` calls of dependencies.
+
+Functions and variables get hoisted into the declaration scope. This outer function sets up all the bindings, 
+and the execution is entirely separated from this process. Hoisted functions are immediately exported. 
+All of the modules in the tree first run this first function setting up all the bindings. 
+Then we separately run all the execution functions left to right from the bottom of the tree ending at circular references.
+
+In this way we get the live binding and circular reference support exactly as expected by the spec, 
+while supporting ES3 environments for the module syntax conversion.
+
+#### Bulk exports
+
+The `$__export` function above can also be used to export multiple exports at the same time:
+
+```javascript
+$__export({ key: 'value', another: 'value' });
+```
+
+This is useful for performance of deep re-exports where unnecessary setter operations can be avoided.
+
+#### Metadata
+
+The next iteration of this format will include support for ES6 module meta information through a new 
+System.register argument as soon as the specification for this is proposed.
+
+### Limitations
+
+The main limitation with authoring in this format and transitioning to ES6 is if unresolved exports exist such as:
+
+```javascript
+import {p} from 'q';
+```
+
+Where module `q` does not export a `p` at all.
+
+This code will run in the System.register output but not in ES6 environments.
+
+While this format can be adjusted to handle the SyntaxErrors that get thrown when an imported name does not exist, for performance and code-size constraints this is not provided. Ideally static checking via tooling should catch these issues rather.
\ No newline at end of file
diff --git a/docs/tracing-api.md b/docs/tracing-api.md
new file mode 100644
index 0000000..ba2677d
--- /dev/null
+++ b/docs/tracing-api.md
@@ -0,0 +1,36 @@
+This is not in the specification, but is provided since it is such a natural extension of loading 
+and not much code at all.
+
+Enable tracing and start importing modules:
+
+```javascript
+  loader.trace = true;
+  loader.execute = false; // optional, disables execution of module contents
+
+  loader.import('some/module').then(function() {
+    /*
+      Now we have:
+      
+        loader.loads['some/module'] == {
+          name: 'some/module',
+          deps: ['./unnormalized', 'deps'],
+          depMap: {
+            './unnormalized': 'normalized',
+            'deps': 'deps'
+          },
+          address: '/resolvedURL',
+          metadata: { metadata object from load },
+          source: 'translated source code string',
+          kind: 'dynamic' (instantiated) or 'declarative' (ES6 module pipeline)
+        }
+
+      With the dependency load records
+        loader.loads['normalized']
+        loader.loads['deps']
+      also set.
+    */
+  });
+```
+
+So tracing can be done by importing a module, then reading its normalized name off of `loader.loads` 
+(it is probably advisable to separately call `loader.normalize` to determine this).
\ No newline at end of file
diff --git a/index.js b/index.js
new file mode 100644
index 0000000..821cf8f
--- /dev/null
+++ b/index.js
@@ -0,0 +1,28 @@
+if (typeof Promise === 'undefined')
+  require('when/es6-shim/Promise');
+
+var System = require('./dist/es6-module-loader-dev.src');
+
+var filePrefix = 'file:' + (process.platform.match(/^win/) ? '/' : '') + '//';
+
+try {
+  System.paths.traceur = filePrefix + require.resolve('traceur/bin/traceur.js');
+}
+catch(e) {}
+try {
+  System.paths.babel = filePrefix + require.resolve('babel-core/browser.js');
+}
+catch(e) {}
+try {
+  System.paths.babel = System.paths.babel || filePrefix + require.resolve('babel/browser.js');
+}
+catch(e) {}
+try {
+  System.paths.typescript = filePrefix + require.resolve('typescript/bin/typescript.js');
+}
+catch(e) { }
+
+module.exports = {
+  Loader: global.LoaderPolyfill,
+  System: System
+};
diff --git a/karma-benchmark.conf.js b/karma-benchmark.conf.js
new file mode 100644
index 0000000..7bd2138
--- /dev/null
+++ b/karma-benchmark.conf.js
@@ -0,0 +1,31 @@
+module.exports = function (config) {
+
+  config.set({
+    basePath: '',
+    frameworks: ['benchmark'],
+    files: [
+      'dist/es6-module-loader.src.js',
+      'test/perf.js'
+    ],
+    reporters: ['benchmark'],
+    browsers: ['Chrome', 'Firefox'],
+
+    browserDisconnectTimeout: 10000,
+    browserDisconnectTolerance: 2,
+    browserNoActivityTimeout: 30000,
+    captureTimeout: 120000
+  });
+
+  if(process.env.TRAVIS){
+    config.set({
+      customLaunchers: {
+        'TR_Chrome': {
+          base: 'Chrome',
+          flags: ['--no-sandbox']
+        }
+      },
+      browsers: ['TR_Chrome', 'Firefox']
+    });
+  }
+
+};
diff --git a/karma.conf.js b/karma.conf.js
new file mode 100644
index 0000000..a07dde2
--- /dev/null
+++ b/karma.conf.js
@@ -0,0 +1,181 @@
+'use strict';
+
+var util = require('util');
+var pkg = require('./package.json');
+var extend = util._extend;
+var geSaLaKaCuLa = require('gesalakacula');
+
+// No Karma options are passed after the double dash option (`--`)
+// Example : karma start --single-run -- --polyfill
+//        >> { _: [], polyfill: true }
+
+var _argv = process.argv;
+var argv = require('minimist')(_argv.slice(_argv.indexOf('--') + 1));
+
+
+var options = extend({
+  travis: process.env.TRAVIS,
+  polyfill: false,
+  saucelabs: false,
+  ie8: false,
+  coverage: false
+}, argv);
+
+if (options.ie8) {
+  console.log('IE8 Mode !\n - polyfill required\n');
+  options.polyfill = true;
+}
+if (options.saucelabs) {
+  options.polyfill = true;
+}
+
+////
+module.exports = function(config) {
+
+  var files = [
+    'test/_helper.js',
+    [options['babel'] ? 'node_modules/regenerator/runtime.js' : ''],
+
+    [!options.ie8 
+        ? (options['babel'] 
+            ? 'node_modules/babel-core/browser.js' 
+            : options['typescript']  
+                ? 'node_modules/typescript/lib/typescript.js' 
+                : 'node_modules/traceur/bin/traceur.js') 
+        : ''],
+
+    [options.polyfill ? 'node_modules/when/es6-shim/Promise.js' : ''],
+    [options.polyfill ? 'dist/es6-module-loader-dev.js' : 'dist/es6-module-loader-dev.src.js'],
+
+    'test/_browser.js',
+    'test/browser-script-type-module.js',
+    'test/custom-loader.js',
+
+    [!options.ie8 ? 'test/*.spec.js' : ['test/system.normalize.spec.js', 'test/custom-loader.spec.js']],
+
+    {pattern: 'test/{loader,loads,syntax,worker}/**/*', included: false},
+    {pattern: 'node_modules/traceur/bin/traceur.js', included: false},
+    {pattern: 'node_modules/babel-core/browser.js', included: false},
+    {pattern: 'node_modules/typescript/lib/typescript.js', included: false},
+    {pattern: 'node_modules/when/es6-shim/Promise.js', included: false},
+    {pattern: 'dist/es6-module-loader*.js', included: false}
+  ];
+  // Default Config
+  config.set({
+    basePath: '',
+    frameworks: ['mocha', 'expect'],
+    files: flatten(files),
+    reporters: ['mocha'],
+    browsers: ['Chrome', 'Firefox'],
+    client: {
+      mocha: {
+        reporter: 'html',
+        timeout: 8000
+      },
+      system: {
+        ie8: options.ie8,
+        transpiler: options.babel
+            ? 'babel'
+            : options.typescript
+                ? 'typescript'
+                : 'traceur'
+      }
+    }
+  });
+
+  if (options.coverage) {
+    config.set({
+      reporters: ['mocha', 'coverage'],
+      preprocessors: {
+        'dist/es6-module-loader*.src.js': ['coverage']
+      },
+      coverageReporter: {
+        type : 'html',
+        dir : 'coverage/'
+      },
+      browsers: ['Chrome']
+    });
+  }
+
+  if (options.travis) {
+    // TRAVIS config overwrite
+    config.set({
+      singleRun: true,
+      reporters: ['dots'],
+      customLaunchers: {
+        'TR_Chrome': {
+          base: 'Chrome',
+          flags: ['--no-sandbox']
+        }
+      },
+      browsers: ['TR_Chrome', 'Firefox']
+    });
+  }
+
+  if (options.saucelabs) {
+
+    var customLaunchers = geSaLaKaCuLa({
+      'Windows 7': {
+        'internet explorer': '9..11'
+      }
+    });
+
+    if (options.ie8) {
+      customLaunchers = geSaLaKaCuLa({
+        'Windows 7': {
+          'internet explorer': '8'
+        }
+      });
+    }
+
+    // saucelabs still fail sporadically
+    customLaunchers = undefined;
+
+    var now = new Date();
+    var buildData = options.travis ?
+    {
+      location: 'TRAVIS',
+      name: process.env.TRAVIS_JOB_NUMBER,
+      id: process.env.TRAVIS_BUILD_ID
+    }
+      :
+    {
+      location: 'LOCAL',
+      name: now.toString(),
+      id: +now
+    };
+    var build = util.format('%s #%s (%s)',
+      buildData.location, buildData.name, buildData.id);
+
+    console.log('SauceLabs Run\n- Build : ' + build + '\n');
+
+    config.set({
+      reporters: ['dots', 'saucelabs'],
+
+      browserDisconnectTimeout: 10000,
+      browserDisconnectTolerance: 2,
+      browserNoActivityTimeout: 30000,
+      captureTimeout: 120000,
+
+      sauceLabs: {
+        testName: pkg.name,
+        recordScreenshots: false,
+        build: build,
+        tunnelIdentifier: options.travis ?
+          process.env.TRAVIS_JOB_NUMBER : Math.floor(Math.random() * 1000)
+      }
+    });
+
+    if (customLaunchers)
+      config.set({
+        browsers: Object.keys(customLaunchers),
+        customLaunchers: customLaunchers
+      });
+  }
+};
+
+function flatten(arr) {
+  return arr.reduce(function(memo, val) {
+    return memo.concat(util.isArray(val) ? flatten(val) : val ? [val] : []);
+  }, []);
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..2364a25
--- /dev/null
+++ b/package.json
@@ -0,0 +1,69 @@
+{
+  "name": "es6-module-loader",
+  "description": "An ES6 Module Loader shim",
+  "version": "0.17.11",
+  "homepage": "https://github.com/ModuleLoader/es6-module-loader",
+  "author": {
+    "name": "Guy Bedford, Luke Hoban, Addy Osmani",
+    "email": "addyosmani at gmail.com",
+    "url": "https://github.com/ModuleLoader"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/ModuleLoader/es6-module-loader"
+  },
+  "bugs": {
+    "url": "https://github.com/ModuleLoader/es6-module-loader/issues"
+  },
+  "licenses": [
+    {
+      "type": "MIT",
+      "url": "https://github.com/ModuleLoader/es6-module-loader/blob/master/LICENSE-MIT"
+    }
+  ],
+  "devDependencies": {
+    "babel-core": "^5.8.20",
+    "expect.js": "^0.3.1",
+    "gesalakacula": "^1.0.0",
+    "grunt": "~0.4.1",
+    "grunt-contrib-concat": "^0.5.0",
+    "grunt-contrib-jshint": "~0.6.0",
+    "grunt-contrib-uglify": "~0.6.0",
+    "karma": "^0.12.35",
+    "karma-benchmark": "^0.4.0",
+    "karma-benchmark-reporter": "^0.1.1",
+    "karma-chrome-launcher": "^0.1.7",
+    "karma-coverage": "^0.2.7",
+    "karma-expect": "^1.1.0",
+    "karma-firefox-launcher": "^0.1.3",
+    "karma-mocha": "^0.1.10",
+    "karma-mocha-reporter": "^0.3.1",
+    "karma-sauce-launcher": "^0.2.10",
+    "minimist": "^1.1.0",
+    "mocha": "^2.0.1",
+    "regenerator": "^0.8.9",
+    "traceur": "0.0.93",
+    "typescript": "^1.6.2"
+  },
+  "keywords": [
+    "script",
+    "loader",
+    "es6",
+    "harmony"
+  ],
+  "engines": {
+    "node": ">=0.8.0"
+  },
+  "scripts": {
+    "test": "npm run test:node && npm run test:browser",
+    "test:node": "mocha test/_node-traceur.js && mocha test/_node-babel.js && mocha test/_node-typescript.js",
+    "test:browser": "npm run test:browser-traceur && npm run test:browser-babel && npm run test:browser-typescript",
+    "test:browser-traceur": "karma start --single-run",
+    "test:browser-babel": "karma start --single-run --babel",
+    "test:browser-typescript": "karma start --single-run --typescript",
+    "test:browser:perf": "karma start karma-benchmark.conf.js --single-run"
+  },
+  "dependencies": {
+    "when": "^3.7.2"
+  }
+}
diff --git a/src/declarative.js b/src/declarative.js
new file mode 100644
index 0000000..73f2306
--- /dev/null
+++ b/src/declarative.js
@@ -0,0 +1,297 @@
+/*
+ * ES6 Module Declarative Linking Code - Dev Build Only
+ */
+
+  // 15.2.5.3 Module Linking Groups
+
+  // 15.2.5.3.2 BuildLinkageGroups alternative implementation
+  // Adjustments (also see https://bugs.ecmascript.org/show_bug.cgi?id=2755)
+  // 1. groups is an already-interleaved array of group kinds
+  // 2. load.groupIndex is set when this function runs
+  // 3. load.groupIndex is the interleaved index ie 0 declarative, 1 dynamic, 2 declarative, ... (or starting with dynamic)
+  function buildLinkageGroups(load, loads, groups) {
+    groups[load.groupIndex] = groups[load.groupIndex] || [];
+
+    // if the load already has a group index and its in its group, its already been done
+    // this logic naturally handles cycles
+    if (indexOf.call(groups[load.groupIndex], load) != -1)
+      return;
+
+    // now add it to the group to indicate its been seen
+    groups[load.groupIndex].push(load);
+
+    for (var i = 0, l = loads.length; i < l; i++) {
+      var loadDep = loads[i];
+
+      // dependencies not found are already linked
+      for (var j = 0; j < load.dependencies.length; j++) {
+        if (loadDep.name == load.dependencies[j].value) {
+          // by definition all loads in linkset are loaded, not linked
+          console.assert(loadDep.status == 'loaded', 'Load in linkSet not loaded!');
+
+          // if it is a group transition, the index of the dependency has gone up
+          // otherwise it is the same as the parent
+          var loadDepGroupIndex = load.groupIndex + (loadDep.isDeclarative != load.isDeclarative);
+
+          // the group index of an entry is always the maximum
+          if (loadDep.groupIndex === undefined || loadDep.groupIndex < loadDepGroupIndex) {
+
+            // if already in a group, remove from the old group
+            if (loadDep.groupIndex !== undefined) {
+              groups[loadDep.groupIndex].splice(indexOf.call(groups[loadDep.groupIndex], loadDep), 1);
+
+              // if the old group is empty, then we have a mixed depndency cycle
+              if (groups[loadDep.groupIndex].length == 0)
+                throw new TypeError("Mixed dependency cycle detected");
+            }
+
+            loadDep.groupIndex = loadDepGroupIndex;
+          }
+
+          buildLinkageGroups(loadDep, loads, groups);
+        }
+      }
+    }
+  }
+
+  // 15.2.5.4
+  // declarative linking implementation
+  function link(linkSet, linkError) {
+
+    var loader = linkSet.loader;
+
+    if (!linkSet.loads.length)
+      return;
+
+    // console.log('linking {' + logloads(linkSet.loads) + '}');
+    // snapshot(loader);
+
+    // 15.2.5.3.1 LinkageGroups alternative implementation
+
+    // build all the groups
+    // because the first load represents the top of the tree
+    // for a given linkset, we can work down from there
+    var groups = [];
+    var startingLoad = linkSet.loads[0];
+    startingLoad.groupIndex = 0;
+    buildLinkageGroups(startingLoad, linkSet.loads, groups);
+
+    // determine the kind of the bottom group
+    var curGroupDeclarative = startingLoad.isDeclarative == groups.length % 2;
+
+    // run through the groups from bottom to top
+    for (var i = groups.length - 1; i >= 0; i--) {
+      var group = groups[i];
+      for (var j = 0; j < group.length; j++) {
+        var load = group[j];
+
+        // 15.2.5.5 LinkDeclarativeModules adjusted
+        if (curGroupDeclarative) {
+          linkDeclarativeModule(load, linkSet.loads, loader);
+        }
+        // 15.2.5.6 LinkDynamicModules adjusted
+        else {
+          var module = doDynamicExecute(linkSet, load, linkError);
+          if (!module)
+            return;
+          load.module = {
+            name: load.name,
+            module: module
+          };
+          load.status = 'linked';
+        }
+        finishLoad(loader, load);
+      }
+
+      // alternative current kind for next loop
+      curGroupDeclarative = !curGroupDeclarative;
+    }
+  }
+
+
+  // custom module records for binding graph
+  // store linking module records in a separate table
+  function getOrCreateModuleRecord(name, loader) {
+    var moduleRecords = loader.moduleRecords;
+    return moduleRecords[name] || (moduleRecords[name] = {
+      name: name,
+      dependencies: [],
+      module: new Module(), // start from an empty module and extend
+      importers: []
+    });
+  }
+
+  // custom declarative linking function
+  function linkDeclarativeModule(load, loads, loader) {
+    if (load.module)
+      return;
+
+    var module = load.module = getOrCreateModuleRecord(load.name, loader);
+    var moduleObj = load.module.module;
+
+    var registryEntry = load.declare.call(__global, function(name, value) {
+      // NB This should be an Object.defineProperty, but that is very slow.
+      //    By disaling this module write-protection we gain performance.
+      //    It could be useful to allow an option to enable or disable this.
+      module.locked = true;
+
+      // export({name: value})
+      if (typeof name == 'object') {
+        for (var p in name)
+          moduleObj[p] = name[p];
+      }
+      // export(name, value)
+      else {
+        moduleObj[name] = value;
+      }
+
+      for (var i = 0, l = module.importers.length; i < l; i++) {
+        var importerModule = module.importers[i];
+        if (!importerModule.locked) {
+          for (var j = 0; j < importerModule.dependencies.length; ++j) {
+            if (importerModule.dependencies[j] === module) {
+              importerModule.setters[j](moduleObj);
+            }
+          }
+        }
+      }
+
+      module.locked = false;
+      return value;
+    }, { id: load.name });
+
+    // setup our setters and execution function
+    module.setters = registryEntry.setters;
+    module.execute = registryEntry.execute;
+
+    // now link all the module dependencies
+    // amending the depMap as we go
+    for (var i = 0, l = load.dependencies.length; i < l; i++) {
+      var depName = load.dependencies[i].value;
+      var depModule = loader.modules[depName];
+
+      // if dependency not already in the module registry
+      // then try and link it now
+      if (!depModule) {
+        // get the dependency load record
+        for (var j = 0; j < loads.length; j++) {
+          if (loads[j].name != depName)
+            continue;
+
+          // only link if already not already started linking (stops at circular / dynamic)
+          if (!loads[j].module) {
+            linkDeclarativeModule(loads[j], loads, loader);
+            depModule = loads[j].module;
+          }
+          // if circular, create the module record
+          else {
+            depModule = getOrCreateModuleRecord(depName, loader);
+          }
+        }
+      }
+
+      // only declarative modules have dynamic bindings
+      if (depModule.importers) {
+        module.dependencies.push(depModule);
+        depModule.importers.push(module);
+      }
+      else {
+        // track dynamic records as null module records as already linked
+        module.dependencies.push(null);
+      }
+
+      // run the setter for this dependency
+      if (module.setters[i])
+        module.setters[i](depModule.module);
+    }
+
+    load.status = 'linked';
+  }
+
+  /*
+   * Module Object non-exotic for ES5:
+   *
+   * module.module        bound module object
+   * module.execute       execution function for module
+   * module.dependencies  list of module objects for dependencies
+   * See getOrCreateModuleRecord for all properties
+   *
+   */
+  function doExecute(module) {
+    try {
+      module.execute.call(__global);
+    }
+    catch(e) {
+      return e;
+    }
+  }
+
+  // 15.2.5.5.1 LinkImports not implemented
+  // 15.2.5.7 ResolveExportEntries not implemented
+  // 15.2.5.8 ResolveExports not implemented
+  // 15.2.5.9 ResolveExport not implemented
+  // 15.2.5.10 ResolveImportEntries not implemented
+
+  // 15.2.6.1
+  function evaluateLoadedModule(loader, load) {
+    console.assert(load.status == 'linked', 'is linked ' + load.name);
+
+    doEnsureEvaluated(load.module, [], loader);
+    return load.module.module;
+  }
+
+  // propogate execution errors
+  // see https://bugs.ecmascript.org/show_bug.cgi?id=2993
+  function doEnsureEvaluated(module, seen, loader) {
+    var err = ensureEvaluated(module, seen, loader);
+    if (err)
+      throw err;
+  }
+  // 15.2.6.2 EnsureEvaluated adjusted
+  function ensureEvaluated(module, seen, loader) {
+    if (module.evaluated || !module.dependencies)
+      return;
+
+    seen.push(module);
+
+    var deps = module.dependencies;
+    var err;
+
+    for (var i = 0, l = deps.length; i < l; i++) {
+      var dep = deps[i];
+      // dynamic dependencies are empty in module.dependencies
+      // as they are already linked
+      if (!dep)
+        continue;
+      if (indexOf.call(seen, dep) == -1) {
+        err = ensureEvaluated(dep, seen, loader);
+        // stop on error, see https://bugs.ecmascript.org/show_bug.cgi?id=2996
+        if (err) {
+          err = addToError(err, 'Error evaluating ' + dep.name);
+          return err;
+        }
+      }
+    }
+
+    if (module.failed)
+      return new Error('Module failed execution.');
+
+    if (module.evaluated)
+      return;
+
+    module.evaluated = true;
+    err = doExecute(module);
+    if (err) {
+      module.failed = true;
+    }
+    else if (Object.preventExtensions) {
+      // spec variation
+      // we don't create a new module here because it was created and ammended
+      // we just disable further extensions instead
+      Object.preventExtensions(module.module);
+    }
+
+    module.execute = undefined;
+    return err;
+  }
+})();
diff --git a/src/dynamic-only.js b/src/dynamic-only.js
new file mode 100644
index 0000000..3f57248
--- /dev/null
+++ b/src/dynamic-only.js
@@ -0,0 +1,39 @@
+/*
+ * ES6 Module Declarative Linking Code - Dev Build Only
+ */
+  function link(linkSet, linkError) {
+
+    var loader = linkSet.loader;
+
+    if (!linkSet.loads.length)
+      return;
+
+    var loads = linkSet.loads.concat([]);
+
+    for (var i = 0; i < loads.length; i++) {
+      var load = loads[i];
+
+      var module = doDynamicExecute(linkSet, load, linkError);
+      if (!module)
+        return;
+      load.module = {
+        name: load.name,
+        module: module
+      };
+      load.status = 'linked';
+
+      finishLoad(loader, load);
+    }
+  }
+
+  function evaluateLoadedModule(loader, load) {
+    console.assert(load.status == 'linked', 'is linked ' + load.name);
+    return load.module.module;
+  }
+
+  function doEnsureEvaluated() {}
+
+  function transpile() {
+    throw new TypeError('ES6 transpilation is only provided in the dev module loader build.');
+  }
+})();
\ No newline at end of file
diff --git a/src/loader.js b/src/loader.js
new file mode 100644
index 0000000..b645285
--- /dev/null
+++ b/src/loader.js
@@ -0,0 +1,806 @@
+/*
+*********************************************************************************************
+
+  Dynamic Module Loader Polyfill
+
+    - Implemented exactly to the former 2014-08-24 ES6 Specification Draft Rev 27, Section 15
+      http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts#august_24_2014_draft_rev_27
+
+    - Functions are commented with their spec numbers, with spec differences commented.
+
+    - Spec bugs are commented in this code with links.
+
+    - Abstract functions have been combined where possible, and their associated functions
+      commented.
+
+    - Realm implementation is entirely omitted.
+
+*********************************************************************************************
+*/
+
+function Module() {}
+// http://www.ecma-international.org/ecma-262/6.0/#sec-@@tostringtag
+defineProperty(Module.prototype, 'toString', {
+  value: function() {
+    return 'Module';
+  }
+});
+function Loader(options) {
+  this._loader = {
+    loaderObj: this,
+    loads: [],
+    modules: {},
+    importPromises: {},
+    moduleRecords: {}
+  };
+
+  // 26.3.3.6
+  defineProperty(this, 'global', {
+    get: function() {
+      return __global;
+    }
+  });
+
+  // 26.3.3.13 realm not implemented
+}
+
+(function() {
+
+// Some Helpers
+
+// logs a linkset snapshot for debugging
+/* function snapshot(loader) {
+  console.log('---Snapshot---');
+  for (var i = 0; i < loader.loads.length; i++) {
+    var load = loader.loads[i];
+    var linkSetLog = '  ' + load.name + ' (' + load.status + '): ';
+
+    for (var j = 0; j < load.linkSets.length; j++) {
+      linkSetLog += '{' + logloads(load.linkSets[j].loads) + '} ';
+    }
+    console.log(linkSetLog);
+  }
+  console.log('');
+}
+function logloads(loads) {
+  var log = '';
+  for (var k = 0; k < loads.length; k++)
+    log += loads[k].name + (k != loads.length - 1 ? ' ' : '');
+  return log;
+} */
+
+
+/* function checkInvariants() {
+  // see https://bugs.ecmascript.org/show_bug.cgi?id=2603#c1
+
+  var loads = System._loader.loads;
+  var linkSets = [];
+
+  for (var i = 0; i < loads.length; i++) {
+    var load = loads[i];
+    console.assert(load.status == 'loading' || load.status == 'loaded', 'Each load is loading or loaded');
+
+    for (var j = 0; j < load.linkSets.length; j++) {
+      var linkSet = load.linkSets[j];
+
+      for (var k = 0; k < linkSet.loads.length; k++)
+        console.assert(loads.indexOf(linkSet.loads[k]) != -1, 'linkSet loads are a subset of loader loads');
+
+      if (linkSets.indexOf(linkSet) == -1)
+        linkSets.push(linkSet);
+    }
+  }
+
+  for (var i = 0; i < loads.length; i++) {
+    var load = loads[i];
+    for (var j = 0; j < linkSets.length; j++) {
+      var linkSet = linkSets[j];
+
+      if (linkSet.loads.indexOf(load) != -1)
+        console.assert(load.linkSets.indexOf(linkSet) != -1, 'linkSet contains load -> load contains linkSet');
+
+      if (load.linkSets.indexOf(linkSet) != -1)
+        console.assert(linkSet.loads.indexOf(load) != -1, 'load contains linkSet -> linkSet contains load');
+    }
+  }
+
+  for (var i = 0; i < linkSets.length; i++) {
+    var linkSet = linkSets[i];
+    for (var j = 0; j < linkSet.loads.length; j++) {
+      var load = linkSet.loads[j];
+
+      for (var k = 0; k < load.dependencies.length; k++) {
+        var depName = load.dependencies[k].value;
+        var depLoad;
+        for (var l = 0; l < loads.length; l++) {
+          if (loads[l].name != depName)
+            continue;
+          depLoad = loads[l];
+          break;
+        }
+
+        // loading records are allowed not to have their dependencies yet
+        // if (load.status != 'loading')
+        //  console.assert(depLoad, 'depLoad found');
+
+        // console.assert(linkSet.loads.indexOf(depLoad) != -1, 'linkset contains all dependencies');
+      }
+    }
+  }
+} */
+
+  // 15.2.3 - Runtime Semantics: Loader State
+
+  // 15.2.3.11
+  function createLoaderLoad(object) {
+    return {
+      // modules is an object for ES5 implementation
+      modules: {},
+      loads: [],
+      loaderObj: object
+    };
+  }
+
+  // 15.2.3.2 Load Records and LoadRequest Objects
+
+  // 15.2.3.2.1
+  function createLoad(name) {
+    return {
+      status: 'loading',
+      name: name,
+      linkSets: [],
+      dependencies: [],
+      metadata: {}
+    };
+  }
+
+  // 15.2.3.2.2 createLoadRequestObject, absorbed into calling functions
+
+  // 15.2.4
+
+  // 15.2.4.1
+  function loadModule(loader, name, options) {
+    return new Promise(asyncStartLoadPartwayThrough({
+      step: options.address ? 'fetch' : 'locate',
+      loader: loader,
+      moduleName: name,
+      // allow metadata for import https://bugs.ecmascript.org/show_bug.cgi?id=3091
+      moduleMetadata: options && options.metadata || {},
+      moduleSource: options.source,
+      moduleAddress: options.address
+    }));
+  }
+
+  // 15.2.4.2
+  function requestLoad(loader, request, refererName, refererAddress) {
+    // 15.2.4.2.1 CallNormalize
+    return new Promise(function(resolve, reject) {
+      resolve(loader.loaderObj.normalize(request, refererName, refererAddress));
+    })
+    // 15.2.4.2.2 GetOrCreateLoad
+    .then(function(name) {
+      var load;
+      if (loader.modules[name]) {
+        load = createLoad(name);
+        load.status = 'linked';
+        // https://bugs.ecmascript.org/show_bug.cgi?id=2795
+        load.module = loader.modules[name];
+        return load;
+      }
+
+      for (var i = 0, l = loader.loads.length; i < l; i++) {
+        load = loader.loads[i];
+        if (load.name != name)
+          continue;
+        console.assert(load.status == 'loading' || load.status == 'loaded', 'loading or loaded');
+        return load;
+      }
+
+      load = createLoad(name);
+      loader.loads.push(load);
+
+      proceedToLocate(loader, load);
+
+      return load;
+    });
+  }
+
+  // 15.2.4.3
+  function proceedToLocate(loader, load) {
+    proceedToFetch(loader, load,
+      Promise.resolve()
+      // 15.2.4.3.1 CallLocate
+      .then(function() {
+        return loader.loaderObj.locate({ name: load.name, metadata: load.metadata });
+      })
+    );
+  }
+
+  // 15.2.4.4
+  function proceedToFetch(loader, load, p) {
+    proceedToTranslate(loader, load,
+      p
+      // 15.2.4.4.1 CallFetch
+      .then(function(address) {
+        // adjusted, see https://bugs.ecmascript.org/show_bug.cgi?id=2602
+        if (load.status != 'loading')
+          return;
+        load.address = address;
+
+        return loader.loaderObj.fetch({ name: load.name, metadata: load.metadata, address: address });
+      })
+    );
+  }
+
+  var anonCnt = 0;
+
+  // 15.2.4.5
+  function proceedToTranslate(loader, load, p) {
+    p
+    // 15.2.4.5.1 CallTranslate
+    .then(function(source) {
+      if (load.status != 'loading')
+        return;
+
+      return Promise.resolve(loader.loaderObj.translate({ name: load.name, metadata: load.metadata, address: load.address, source: source }))
+
+      // 15.2.4.5.2 CallInstantiate
+      .then(function(source) {
+        load.source = source;
+        return loader.loaderObj.instantiate({ name: load.name, metadata: load.metadata, address: load.address, source: source });
+      })
+
+      // 15.2.4.5.3 InstantiateSucceeded
+      .then(function(instantiateResult) {
+        if (instantiateResult === undefined) {
+          load.address = load.address || '<Anonymous Module ' + ++anonCnt + '>';
+
+          // instead of load.kind, use load.isDeclarative
+          load.isDeclarative = true;
+          return transpile.call(loader.loaderObj, load)
+          .then(function(transpiled) {
+            // Hijack System.register to set declare function
+            var curSystem = __global.System;
+            var curRegister = curSystem.register;
+            curSystem.register = function(name, deps, declare) {
+              if (typeof name != 'string') {
+                declare = deps;
+                deps = name;
+              }
+              // store the registered declaration as load.declare
+              // store the deps as load.deps
+              load.declare = declare;
+              load.depsList = deps;
+            }
+            // empty {} context is closest to undefined 'this' we can get
+            __eval(transpiled, load.address, {});
+            curSystem.register = curRegister;
+          });
+        }
+        else if (typeof instantiateResult == 'object') {
+          load.depsList = instantiateResult.deps || [];
+          load.execute = instantiateResult.execute;
+          load.isDeclarative = false;
+        }
+        else
+          throw TypeError('Invalid instantiate return value');
+      })
+      // 15.2.4.6 ProcessLoadDependencies
+      .then(function() {
+        load.dependencies = [];
+        var depsList = load.depsList;
+
+        var loadPromises = [];
+        for (var i = 0, l = depsList.length; i < l; i++) (function(request, index) {
+          loadPromises.push(
+            requestLoad(loader, request, load.name, load.address)
+
+            // 15.2.4.6.1 AddDependencyLoad (load is parentLoad)
+            .then(function(depLoad) {
+
+              // adjusted from spec to maintain dependency order
+              // this is due to the System.register internal implementation needs
+              load.dependencies[index] = {
+                key: request,
+                value: depLoad.name
+              };
+
+              if (depLoad.status != 'linked') {
+                var linkSets = load.linkSets.concat([]);
+                for (var i = 0, l = linkSets.length; i < l; i++)
+                  addLoadToLinkSet(linkSets[i], depLoad);
+              }
+
+              // console.log('AddDependencyLoad ' + depLoad.name + ' for ' + load.name);
+              // snapshot(loader);
+            })
+          );
+        })(depsList[i], i);
+
+        return Promise.all(loadPromises);
+      })
+
+      // 15.2.4.6.2 LoadSucceeded
+      .then(function() {
+        // console.log('LoadSucceeded ' + load.name);
+        // snapshot(loader);
+
+        console.assert(load.status == 'loading', 'is loading');
+
+        load.status = 'loaded';
+
+        var linkSets = load.linkSets.concat([]);
+        for (var i = 0, l = linkSets.length; i < l; i++)
+          updateLinkSetOnLoad(linkSets[i], load);
+      });
+    })
+    // 15.2.4.5.4 LoadFailed
+    ['catch'](function(exc) {
+      load.status = 'failed';
+      load.exception = exc;
+
+      var linkSets = load.linkSets.concat([]);
+      for (var i = 0, l = linkSets.length; i < l; i++) {
+        linkSetFailed(linkSets[i], load, exc);
+      }
+
+      console.assert(load.linkSets.length == 0, 'linkSets not removed');
+    });
+  }
+
+  // 15.2.4.7 PromiseOfStartLoadPartwayThrough absorbed into calling functions
+
+  // 15.2.4.7.1
+  function asyncStartLoadPartwayThrough(stepState) {
+    return function(resolve, reject) {
+      var loader = stepState.loader;
+      var name = stepState.moduleName;
+      var step = stepState.step;
+
+      if (loader.modules[name])
+        throw new TypeError('"' + name + '" already exists in the module table');
+
+      // adjusted to pick up existing loads
+      var existingLoad;
+      for (var i = 0, l = loader.loads.length; i < l; i++) {
+        if (loader.loads[i].name == name) {
+          existingLoad = loader.loads[i];
+
+          if (step == 'translate' && !existingLoad.source) {
+            existingLoad.address = stepState.moduleAddress;
+            proceedToTranslate(loader, existingLoad, Promise.resolve(stepState.moduleSource));
+          }
+
+          // a primary load -> use that existing linkset if it is for the direct load here
+          // otherwise create a new linkset unit
+          if (existingLoad.linkSets.length && existingLoad.linkSets[0].loads[0].name == existingLoad.name)
+            return existingLoad.linkSets[0].done.then(function() {
+              resolve(existingLoad);
+            });
+        }
+      }
+
+      var load = existingLoad || createLoad(name);
+
+      load.metadata = stepState.moduleMetadata;
+
+      var linkSet = createLinkSet(loader, load);
+
+      loader.loads.push(load);
+
+      resolve(linkSet.done);
+
+      if (step == 'locate')
+        proceedToLocate(loader, load);
+
+      else if (step == 'fetch')
+        proceedToFetch(loader, load, Promise.resolve(stepState.moduleAddress));
+
+      else {
+        console.assert(step == 'translate', 'translate step');
+        load.address = stepState.moduleAddress;
+        proceedToTranslate(loader, load, Promise.resolve(stepState.moduleSource));
+      }
+    }
+  }
+
+  // Declarative linking functions run through alternative implementation:
+  // 15.2.5.1.1 CreateModuleLinkageRecord not implemented
+  // 15.2.5.1.2 LookupExport not implemented
+  // 15.2.5.1.3 LookupModuleDependency not implemented
+
+  // 15.2.5.2.1
+  function createLinkSet(loader, startingLoad) {
+    var linkSet = {
+      loader: loader,
+      loads: [],
+      startingLoad: startingLoad, // added see spec bug https://bugs.ecmascript.org/show_bug.cgi?id=2995
+      loadingCount: 0
+    };
+    linkSet.done = new Promise(function(resolve, reject) {
+      linkSet.resolve = resolve;
+      linkSet.reject = reject;
+    });
+    addLoadToLinkSet(linkSet, startingLoad);
+    return linkSet;
+  }
+  // 15.2.5.2.2
+  function addLoadToLinkSet(linkSet, load) {
+    if (load.status == 'failed')
+      return;
+
+    console.assert(load.status == 'loading' || load.status == 'loaded', 'loading or loaded on link set');
+
+    for (var i = 0, l = linkSet.loads.length; i < l; i++)
+      if (linkSet.loads[i] == load)
+        return;
+
+    linkSet.loads.push(load);
+    load.linkSets.push(linkSet);
+
+    // adjustment, see https://bugs.ecmascript.org/show_bug.cgi?id=2603
+    if (load.status != 'loaded') {
+      linkSet.loadingCount++;
+    }
+
+    var loader = linkSet.loader;
+
+    for (var i = 0, l = load.dependencies.length; i < l; i++) {
+      if (!load.dependencies[i])
+        continue;
+
+      var name = load.dependencies[i].value;
+
+      if (loader.modules[name])
+        continue;
+
+      for (var j = 0, d = loader.loads.length; j < d; j++) {
+        if (loader.loads[j].name != name)
+          continue;
+
+        addLoadToLinkSet(linkSet, loader.loads[j]);
+        break;
+      }
+    }
+    // console.log('add to linkset ' + load.name);
+    // snapshot(linkSet.loader);
+  }
+
+  // linking errors can be generic or load-specific
+  // this is necessary for debugging info
+  function doLink(linkSet) {
+    var error = false;
+    try {
+      link(linkSet, function(load, exc) {
+        linkSetFailed(linkSet, load, exc);
+        error = true;
+      });
+    }
+    catch(e) {
+      linkSetFailed(linkSet, null, e);
+      error = true;
+    }
+    return error;
+  }
+
+  // 15.2.5.2.3
+  function updateLinkSetOnLoad(linkSet, load) {
+    // console.log('update linkset on load ' + load.name);
+    // snapshot(linkSet.loader);
+
+    console.assert(load.status == 'loaded' || load.status == 'linked', 'loaded or linked');
+
+    linkSet.loadingCount--;
+
+    if (linkSet.loadingCount > 0)
+      return;
+
+    // adjusted for spec bug https://bugs.ecmascript.org/show_bug.cgi?id=2995
+    var startingLoad = linkSet.startingLoad;
+
+    // non-executing link variation for loader tracing
+    // on the server. Not in spec.
+    /***/
+    if (linkSet.loader.loaderObj.execute === false) {
+      var loads = [].concat(linkSet.loads);
+      for (var i = 0, l = loads.length; i < l; i++) {
+        var load = loads[i];
+        load.module = !load.isDeclarative ? {
+          module: _newModule({})
+        } : {
+          name: load.name,
+          module: _newModule({}),
+          evaluated: true
+        };
+        load.status = 'linked';
+        finishLoad(linkSet.loader, load);
+      }
+      return linkSet.resolve(startingLoad);
+    }
+    /***/
+
+    var abrupt = doLink(linkSet);
+
+    if (abrupt)
+      return;
+
+    console.assert(linkSet.loads.length == 0, 'loads cleared');
+
+    linkSet.resolve(startingLoad);
+  }
+
+  // 15.2.5.2.4
+  function linkSetFailed(linkSet, load, exc) {
+    var loader = linkSet.loader;
+    var requests;
+
+    checkError: 
+    if (load) {
+      if (linkSet.loads[0].name == load.name) {
+        exc = addToError(exc, 'Error loading ' + load.name);
+      }
+      else {
+        for (var i = 0; i < linkSet.loads.length; i++) {
+          var pLoad = linkSet.loads[i];
+          for (var j = 0; j < pLoad.dependencies.length; j++) {
+            var dep = pLoad.dependencies[j];
+            if (dep.value == load.name) {
+              exc = addToError(exc, 'Error loading ' + load.name + ' as "' + dep.key + '" from ' + pLoad.name);
+              break checkError;
+            }
+          }
+        }
+        exc = addToError(exc, 'Error loading ' + load.name + ' from ' + linkSet.loads[0].name);
+      }
+    }
+    else {
+      exc = addToError(exc, 'Error linking ' + linkSet.loads[0].name);
+    }
+
+
+    var loads = linkSet.loads.concat([]);
+    for (var i = 0, l = loads.length; i < l; i++) {
+      var load = loads[i];
+
+      // store all failed load records
+      loader.loaderObj.failed = loader.loaderObj.failed || [];
+      if (indexOf.call(loader.loaderObj.failed, load) == -1)
+        loader.loaderObj.failed.push(load);
+
+      var linkIndex = indexOf.call(load.linkSets, linkSet);
+      console.assert(linkIndex != -1, 'link not present');
+      load.linkSets.splice(linkIndex, 1);
+      if (load.linkSets.length == 0) {
+        var globalLoadsIndex = indexOf.call(linkSet.loader.loads, load);
+        if (globalLoadsIndex != -1)
+          linkSet.loader.loads.splice(globalLoadsIndex, 1);
+      }
+    }
+    linkSet.reject(exc);
+  }
+
+  // 15.2.5.2.5
+  function finishLoad(loader, load) {
+    // add to global trace if tracing
+    if (loader.loaderObj.trace) {
+      if (!loader.loaderObj.loads)
+        loader.loaderObj.loads = {};
+      var depMap = {};
+      load.dependencies.forEach(function(dep) {
+        depMap[dep.key] = dep.value;
+      });
+      loader.loaderObj.loads[load.name] = {
+        name: load.name,
+        deps: load.dependencies.map(function(dep){ return dep.key }),
+        depMap: depMap,
+        address: load.address,
+        metadata: load.metadata,
+        source: load.source,
+        kind: load.isDeclarative ? 'declarative' : 'dynamic'
+      };
+    }
+    // if not anonymous, add to the module table
+    if (load.name) {
+      console.assert(!loader.modules[load.name], 'load not in module table');
+      loader.modules[load.name] = load.module;
+    }
+    var loadIndex = indexOf.call(loader.loads, load);
+    if (loadIndex != -1)
+      loader.loads.splice(loadIndex, 1);
+    for (var i = 0, l = load.linkSets.length; i < l; i++) {
+      loadIndex = indexOf.call(load.linkSets[i].loads, load);
+      if (loadIndex != -1)
+        load.linkSets[i].loads.splice(loadIndex, 1);
+    }
+    load.linkSets.splice(0, load.linkSets.length);
+  }
+
+  function doDynamicExecute(linkSet, load, linkError) {
+    try {
+      var module = load.execute();
+    }
+    catch(e) {
+      linkError(load, e);
+      return;
+    }
+    if (!module || !(module instanceof Module))
+      linkError(load, new TypeError('Execution must define a Module instance'));
+    else
+      return module;
+  }
+
+  // 26.3 Loader
+
+  // 26.3.1.1
+  // defined at top
+
+  // importPromises adds ability to import a module twice without error - https://bugs.ecmascript.org/show_bug.cgi?id=2601
+  function createImportPromise(loader, name, promise) {
+    var importPromises = loader._loader.importPromises;
+    return importPromises[name] = promise.then(function(m) {
+      importPromises[name] = undefined;
+      return m;
+    }, function(e) {
+      importPromises[name] = undefined;
+      throw e;
+    });
+  }
+
+  Loader.prototype = {
+    // 26.3.3.1
+    constructor: Loader,
+    // 26.3.3.2
+    define: function(name, source, options) {
+      // check if already defined
+      if (this._loader.importPromises[name])
+        throw new TypeError('Module is already loading.');
+      return createImportPromise(this, name, new Promise(asyncStartLoadPartwayThrough({
+        step: 'translate',
+        loader: this._loader,
+        moduleName: name,
+        moduleMetadata: options && options.metadata || {},
+        moduleSource: source,
+        moduleAddress: options && options.address
+      })));
+    },
+    // 26.3.3.3
+    'delete': function(name) {
+      var loader = this._loader;
+      delete loader.importPromises[name];
+      delete loader.moduleRecords[name];
+      return loader.modules[name] ? delete loader.modules[name] : false;
+    },
+    // 26.3.3.4 entries not implemented
+    // 26.3.3.5
+    get: function(key) {
+      if (!this._loader.modules[key])
+        return;
+      doEnsureEvaluated(this._loader.modules[key], [], this);
+      return this._loader.modules[key].module;
+    },
+    // 26.3.3.7
+    has: function(name) {
+      return !!this._loader.modules[name];
+    },
+    // 26.3.3.8
+    'import': function(name, parentName, parentAddress) {
+      if (typeof parentName == 'object')
+        parentName = parentName.name;
+
+      // run normalize first
+      var loaderObj = this;
+
+      // added, see https://bugs.ecmascript.org/show_bug.cgi?id=2659
+      return Promise.resolve(loaderObj.normalize(name, parentName))
+      .then(function(name) {
+        var loader = loaderObj._loader;
+
+        if (loader.modules[name]) {
+          doEnsureEvaluated(loader.modules[name], [], loader._loader);
+          return loader.modules[name].module;
+        }
+
+        return loader.importPromises[name] || createImportPromise(loaderObj, name,
+          loadModule(loader, name, {})
+          .then(function(load) {
+            delete loader.importPromises[name];
+            return evaluateLoadedModule(loader, load);
+          }));
+      });
+    },
+    // 26.3.3.9 keys not implemented
+    // 26.3.3.10
+    load: function(name) {
+      var loader = this._loader;
+      if (loader.modules[name])
+        return Promise.resolve();
+      return loader.importPromises[name] || createImportPromise(this, name, new Promise(asyncStartLoadPartwayThrough({
+        step: 'locate',
+        loader: loader,
+        moduleName: name,
+        moduleMetadata: {},
+        moduleSource: undefined,
+        moduleAddress: undefined
+      }))
+      .then(function() {
+        delete loader.importPromises[name];
+      }));
+    },
+    // 26.3.3.11
+    module: function(source, options) {
+      var load = createLoad();
+      load.address = options && options.address;
+      var linkSet = createLinkSet(this._loader, load);
+      var sourcePromise = Promise.resolve(source);
+      var loader = this._loader;
+      var p = linkSet.done.then(function() {
+        return evaluateLoadedModule(loader, load);
+      });
+      proceedToTranslate(loader, load, sourcePromise);
+      return p;
+    },
+    // 26.3.3.12
+    newModule: function (obj) {
+      if (typeof obj != 'object')
+        throw new TypeError('Expected object');
+
+      var m = new Module();
+
+      var pNames = [];
+      if (Object.getOwnPropertyNames && obj != null)
+        pNames = Object.getOwnPropertyNames(obj);
+      else
+        for (var key in obj)
+          pNames.push(key);
+
+      for (var i = 0; i < pNames.length; i++) (function(key) {
+        defineProperty(m, key, {
+          configurable: false,
+          enumerable: true,
+          get: function () {
+            return obj[key];
+          },
+          set: function() {
+            throw new Error('Module exports cannot be changed externally.');
+          }
+        });
+      })(pNames[i]);
+
+      if (Object.freeze)
+        Object.freeze(m);
+
+      return m;
+    },
+    // 26.3.3.14
+    set: function(name, module) {
+      if (!(module instanceof Module))
+        throw new TypeError('Loader.set(' + name + ', module) must be a module');
+      this._loader.modules[name] = {
+        module: module
+      };
+    },
+    // 26.3.3.15 values not implemented
+    // 26.3.3.16 @@iterator not implemented
+    // 26.3.3.17 @@toStringTag not implemented
+
+    // 26.3.3.18.1
+    normalize: function(name, referrerName, referrerAddress) {
+      return name;
+    },
+    // 26.3.3.18.2
+    locate: function(load) {
+      return load.name;
+    },
+    // 26.3.3.18.3
+    fetch: function(load) {
+    },
+    // 26.3.3.18.4
+    translate: function(load) {
+      return load.source;
+    },
+    // 26.3.3.18.5
+    instantiate: function(load) {
+    }
+  };
+
+  var _newModule = Loader.prototype.newModule;
diff --git a/src/module-tag.js b/src/module-tag.js
new file mode 100644
index 0000000..ff79fc0
--- /dev/null
+++ b/src/module-tag.js
@@ -0,0 +1,37 @@
+(function() {
+  // <script type="module"> support
+  // allow a data-init function callback once loaded
+  if (isBrowser && typeof document.getElementsByTagName != 'undefined') {
+    var curScript = document.getElementsByTagName('script');
+    curScript = curScript[curScript.length - 1];
+
+    function completed() {
+      document.removeEventListener( "DOMContentLoaded", completed, false );
+      window.removeEventListener( "load", completed, false );
+      ready();
+    }
+
+    function ready() {
+      var scripts = document.getElementsByTagName('script');
+      for (var i = 0; i < scripts.length; i++) {
+        var script = scripts[i];
+        if (script.type == 'module') {
+          var source = script.innerHTML.substr(1);
+          // It is important to reference the global System, rather than the one
+          // in our closure. We want to ensure that downstream users/libraries
+          // can override System w/ custom behavior.
+          System.module(source)['catch'](function(err) { setTimeout(function() { throw err; }); });
+        }
+      }
+    }
+
+    // DOM ready, taken from https://github.com/jquery/jquery/blob/master/src/core/ready.js#L63
+    if (document.readyState === 'complete') {
+      setTimeout(ready);
+    }
+    else if (document.addEventListener) {
+      document.addEventListener('DOMContentLoaded', completed, false);
+      window.addEventListener('load', completed, false);
+    }
+  }
+})();
\ No newline at end of file
diff --git a/src/system-fetch.js b/src/system-fetch.js
new file mode 100644
index 0000000..a688f0b
--- /dev/null
+++ b/src/system-fetch.js
@@ -0,0 +1,131 @@
+  var fetchTextFromURL;
+  if (typeof XMLHttpRequest != 'undefined') {
+    fetchTextFromURL = function(url, authorization, fulfill, reject) {
+      var xhr = new XMLHttpRequest();
+      var sameDomain = true;
+      var doTimeout = false;
+      if (!('withCredentials' in xhr)) {
+        // check if same domain
+        var domainCheck = /^(\w+:)?\/\/([^\/]+)/.exec(url);
+        if (domainCheck) {
+          sameDomain = domainCheck[2] === window.location.host;
+          if (domainCheck[1])
+            sameDomain &= domainCheck[1] === window.location.protocol;
+        }
+      }
+      if (!sameDomain && typeof XDomainRequest != 'undefined') {
+        xhr = new XDomainRequest();
+        xhr.onload = load;
+        xhr.onerror = error;
+        xhr.ontimeout = error;
+        xhr.onprogress = function() {};
+        xhr.timeout = 0;
+        doTimeout = true;
+      }
+      function load() {
+        fulfill(xhr.responseText);
+      }
+      function error() {
+        reject(new Error('XHR error' + (xhr.status ? ' (' + xhr.status + (xhr.statusText ? ' ' + xhr.statusText  : '') + ')' : '') + ' loading ' + url));
+      }
+
+      xhr.onreadystatechange = function () {
+        if (xhr.readyState === 4) {
+          // in Chrome on file:/// URLs, status is 0
+          if (xhr.status == 0) {
+            if (xhr.responseText) {
+              load();
+            }
+            else {
+              // when responseText is empty, wait for load or error event
+              // to inform if it is a 404 or empty file
+              xhr.addEventListener('error', error);
+              xhr.addEventListener('load', load);
+            }
+          }
+          else if (xhr.status === 200) {
+            load();
+          }
+          else {
+            error();
+          }
+        }
+      };
+      xhr.open("GET", url, true);
+
+      if (xhr.setRequestHeader) {
+        xhr.setRequestHeader('Accept', 'application/x-es-module, */*');
+        // can set "authorization: true" to enable withCredentials only
+        if (authorization) {
+          if (typeof authorization == 'string')
+            xhr.setRequestHeader('Authorization', authorization);
+          xhr.withCredentials = true;
+        }
+      }
+
+      if (doTimeout) {
+        setTimeout(function() {
+          xhr.send();
+        }, 0);
+      } else {
+        xhr.send(null);
+      }
+    };
+  }
+  else if (typeof require != 'undefined' && typeof process != 'undefined') {
+    var fs;
+    fetchTextFromURL = function(url, authorization, fulfill, reject) {
+      if (url.substr(0, 8) != 'file:///')
+        throw new Error('Unable to fetch "' + url + '". Only file URLs of the form file:/// allowed running in Node.');
+      fs = fs || require('fs');
+      if (isWindows)
+        url = url.replace(/\//g, '\\').substr(8);
+      else
+        url = url.substr(7);
+      return fs.readFile(url, function(err, data) {
+        if (err) {
+          return reject(err);
+        }
+        else {
+          // Strip Byte Order Mark out if it's the leading char
+          var dataString = data + '';
+          if (dataString[0] === '\ufeff')
+            dataString = dataString.substr(1);
+
+          fulfill(dataString);
+        }
+      });
+    };
+  }
+  else if (typeof self != 'undefined' && typeof self.fetch != 'undefined') {
+    fetchTextFromURL = function(url, authorization, fulfill, reject) {
+      var opts = {
+        headers: {'Accept': 'application/x-es-module, */*'}
+      };
+
+      if (authorization) {
+        if (typeof authorization == 'string')
+          opts.headers['Authorization'] = authorization;
+        opts.credentials = 'include';
+      }
+
+      fetch(url, opts)
+        .then(function (r) {
+          if (r.ok) {
+            return r.text();
+          } else {
+            throw new Error('Fetch error: ' + r.status + ' ' + r.statusText);
+          }
+        })
+        .then(fulfill, reject);
+    }
+  }
+  else {
+    throw new TypeError('No environment fetch API available.');
+  }
+
+  SystemLoader.prototype.fetch = function(load) {
+    return new Promise(function(resolve, reject) {
+      fetchTextFromURL(load.address, undefined, resolve, reject);
+    });
+  };
diff --git a/src/system-resolve.js b/src/system-resolve.js
new file mode 100644
index 0000000..691fe03
--- /dev/null
+++ b/src/system-resolve.js
@@ -0,0 +1,45 @@
+var absURLRegEx = /^([^\/]+:\/\/|\/)/;
+
+// Normalization with module names as absolute URLs
+SystemLoader.prototype.normalize = function(name, parentName, parentAddress) {
+  // NB does `import 'file.js'` import relative to the parent name or baseURL?
+  //    have assumed that it is baseURL-relative here, but spec may well align with URLs to be the latter
+  //    safe option for users is to always use "./file.js" for relative
+
+  // not absolute or relative -> apply paths (what will be sites)
+  if (!name.match(absURLRegEx) && name[0] != '.')
+    name = new URL(applyPaths(this.paths, name) || name, baseURI).href;
+  // apply parent-relative normalization, parentAddress is already normalized
+  else
+    name = new URL(name, parentName || baseURI).href;
+
+  return name;
+};
+
+SystemLoader.prototype.locate = function(load) {
+  return load.name;
+};
+
+
+// ensure the transpiler is loaded correctly
+SystemLoader.prototype.instantiate = function(load) {
+  var self = this;
+  return Promise.resolve(self.normalize(self.transpiler))
+  .then(function(transpilerNormalized) {
+    // load transpiler as a global (avoiding System clobbering)
+    if (load.address === transpilerNormalized) {
+      return {
+        deps: [],
+        execute: function() {
+          var curSystem = __global.System;
+          var curLoader = __global.Reflect.Loader;
+          // ensure not detected as CommonJS
+          __eval('(function(require,exports,module){' + load.source + '})();', load.address, __global);
+          __global.System = curSystem;
+          __global.Reflect.Loader = curLoader;
+          return self.newModule({ 'default': __global[self.transpiler], __useDefault: true });
+        }
+      };
+    }
+  });
+};
\ No newline at end of file
diff --git a/src/system.js b/src/system.js
new file mode 100644
index 0000000..4b787ec
--- /dev/null
+++ b/src/system.js
@@ -0,0 +1,63 @@
+/*
+*********************************************************************************************
+
+  System Loader Implementation
+
+    - Implemented to https://github.com/jorendorff/js-loaders/blob/master/browser-loader.js
+
+    - <script type="module"> supported
+
+*********************************************************************************************
+*/
+
+var System;
+
+function SystemLoader() {
+  Loader.call(this);
+  this.paths = {};
+}
+
+// NB no specification provided for System.paths, used ideas discussed in https://github.com/jorendorff/js-loaders/issues/25
+function applyPaths(paths, name) {
+  // most specific (most number of slashes in path) match wins
+  var pathMatch = '', wildcard, maxWildcardPrefixLen = 0;
+
+  // check to see if we have a paths entry
+  for (var p in paths) {
+    var pathParts = p.split('*');
+    if (pathParts.length > 2)
+      throw new TypeError('Only one wildcard in a path is permitted');
+
+    // exact path match
+    if (pathParts.length == 1) {
+      if (name == p)
+        return paths[p];
+      
+      // support trailing / in paths rules
+      else if (name.substr(0, p.length - 1) == p.substr(0, p.length - 1) && (name.length < p.length || name[p.length - 1] == p[p.length - 1]) && paths[p][paths[p].length - 1] == '/')
+        return paths[p].substr(0, paths[p].length - 1) + (name.length > p.length ? '/' + name.substr(p.length) : '');
+    }
+    // wildcard path match
+    else {
+      var wildcardPrefixLen = pathParts[0].length;
+      if (wildcardPrefixLen >= maxWildcardPrefixLen &&
+          name.substr(0, pathParts[0].length) == pathParts[0] &&
+          name.substr(name.length - pathParts[1].length) == pathParts[1]) {
+            maxWildcardPrefixLen = wildcardPrefixLen;
+            pathMatch = p;
+            wildcard = name.substr(pathParts[0].length, name.length - pathParts[1].length - pathParts[0].length);
+          }
+    }
+  }
+
+  var outPath = paths[pathMatch];
+  if (typeof wildcard == 'string')
+    outPath = outPath.replace('*', wildcard);
+
+  return outPath;
+}
+
+// inline Object.create-style class extension
+function LoaderProto() {}
+LoaderProto.prototype = Loader.prototype;
+SystemLoader.prototype = new LoaderProto();
diff --git a/src/transpiler.js b/src/transpiler.js
new file mode 100644
index 0000000..79c3d96
--- /dev/null
+++ b/src/transpiler.js
@@ -0,0 +1,86 @@
+/*
+ * Traceur, Babel and TypeScript transpile hook for Loader
+ */
+var transpile = (function() {
+
+  // use Traceur by default
+  Loader.prototype.transpiler = 'traceur';
+
+  function transpile(load) {
+    var self = this;
+
+    return Promise.resolve(__global[self.transpiler == 'typescript' ? 'ts' : self.transpiler]
+        || (self.pluginLoader || self)['import'](self.transpiler))
+    .then(function(transpiler) {
+      if (transpiler.__useDefault)
+        transpiler = transpiler['default'];
+
+      var transpileFunction;
+      if (transpiler.Compiler)
+        transpileFunction = traceurTranspile;
+      else if (transpiler.createLanguageService)
+        transpileFunction = typescriptTranspile;
+      else
+        transpileFunction = babelTranspile;
+
+      // note __moduleName will be part of the transformer meta in future when we have the spec for this
+      return '(function(__moduleName){' + transpileFunction.call(self, load, transpiler) + '\n})("' + load.name + '");\n//# sourceURL=' + load.address + '!transpiled';
+    });
+  };
+
+  function traceurTranspile(load, traceur) {
+    var options = this.traceurOptions || {};
+    options.modules = 'instantiate';
+    options.script = false;
+    if (options.sourceMaps === undefined)
+      options.sourceMaps = 'inline';
+    options.filename = load.address;
+    options.inputSourceMap = load.metadata.sourceMap;
+    options.moduleName = false;
+
+    var compiler = new traceur.Compiler(options);
+
+    return doTraceurCompile(load.source, compiler, options.filename);
+  }
+  function doTraceurCompile(source, compiler, filename) {
+    try {
+      return compiler.compile(source, filename);
+    }
+    catch(e) {
+      // on older versions of traceur (<0.9.3), an array of errors is thrown
+      // rather than a single error.
+      if (e.length) {
+        throw e[0];
+      }
+      throw e;
+    }
+  }
+
+  function babelTranspile(load, babel) {
+    var options = this.babelOptions || {};
+    options.modules = 'system';
+    if (options.sourceMap === undefined)
+      options.sourceMap = 'inline';
+    options.inputSourceMap = load.metadata.sourceMap;
+    options.filename = load.address;
+    options.code = true;
+    options.ast = false;
+
+    return babel.transform(load.source, options).code;
+  }
+
+  function typescriptTranspile(load, ts) {
+    var options = this.typescriptOptions || {};
+    options.target = options.target || ts.ScriptTarget.ES5;
+    if (options.sourceMap === undefined)
+      options.sourceMap = true;
+    if (options.sourceMap && options.inlineSourceMap !== false)
+      options.inlineSourceMap = true;
+
+    options.module = ts.ModuleKind.System;
+
+    return ts.transpile(load.source, options, load.address);
+  }
+
+  return transpile;
+})();
diff --git a/src/url-polyfill.js b/src/url-polyfill.js
new file mode 100644
index 0000000..0f3766c
--- /dev/null
+++ b/src/url-polyfill.js
@@ -0,0 +1,65 @@
+// from https://gist.github.com/Yaffle/1088850
+(function(global) {
+function URLPolyfill(url, baseURL) {
+  if (typeof url != 'string')
+    throw new TypeError('URL must be a string');
+  var m = String(url).replace(/^\s+|\s+$/g, "").match(/^([^:\/?#]+:)?(?:\/\/(?:([^:@\/?#]*)(?::([^:@\/?#]*))?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
+  if (!m)
+    throw new RangeError('Invalid URL format');
+  var protocol = m[1] || "";
+  var username = m[2] || "";
+  var password = m[3] || "";
+  var host = m[4] || "";
+  var hostname = m[5] || "";
+  var port = m[6] || "";
+  var pathname = m[7] || "";
+  var search = m[8] || "";
+  var hash = m[9] || "";
+  if (baseURL !== undefined) {
+    var base = baseURL instanceof URLPolyfill ? baseURL : new URLPolyfill(baseURL);
+    var flag = !protocol && !host && !username;
+    if (flag && !pathname && !search)
+      search = base.search;
+    if (flag && pathname[0] !== "/")
+      pathname = (pathname ? (((base.host || base.username) && !base.pathname ? "/" : "") + base.pathname.slice(0, base.pathname.lastIndexOf("/") + 1) + pathname) : base.pathname);
+    // dot segments removal
+    var output = [];
+    pathname.replace(/^(\.\.?(\/|$))+/, "")
+      .replace(/\/(\.(\/|$))+/g, "/")
+      .replace(/\/\.\.$/, "/../")
+      .replace(/\/?[^\/]*/g, function (p) {
+        if (p === "/..")
+          output.pop();
+        else
+          output.push(p);
+      });
+    pathname = output.join("").replace(/^\//, pathname[0] === "/" ? "/" : "");
+    if (flag) {
+      port = base.port;
+      hostname = base.hostname;
+      host = base.host;
+      password = base.password;
+      username = base.username;
+    }
+    if (!protocol)
+      protocol = base.protocol;
+  }
+
+  // convert windows file URLs to use /
+  if (protocol == 'file:')
+    pathname = pathname.replace(/\\/g, '/');
+
+  this.origin = host ? protocol + (protocol !== "" || host !== "" ? "//" : "") + host : "";
+  this.href = protocol + (protocol && host || protocol == "file:" ? "//" : "") + (username !== "" ? username + (password !== "" ? ":" + password : "") + "@" : "") + host + pathname + search + hash;
+  this.protocol = protocol;
+  this.username = username;
+  this.password = password;
+  this.host = host;
+  this.hostname = hostname;
+  this.port = port;
+  this.pathname = pathname;
+  this.search = search;
+  this.hash = hash;
+}
+global.URLPolyfill = URLPolyfill;
+})(typeof self != 'undefined' ? self : global);
\ No newline at end of file
diff --git a/src/wrapper-end.js b/src/wrapper-end.js
new file mode 100644
index 0000000..b4d01a6
--- /dev/null
+++ b/src/wrapper-end.js
@@ -0,0 +1,21 @@
+  // -- exporting --
+
+  if (typeof exports === 'object')
+    module.exports = Loader;
+
+  __global.Reflect = __global.Reflect || {};
+  __global.Reflect.Loader = __global.Reflect.Loader || Loader;
+  __global.Reflect.global = __global.Reflect.global || __global;
+  __global.LoaderPolyfill = Loader;
+
+  if (!System) {
+    System = new SystemLoader();
+    System.constructor = SystemLoader;
+  }
+
+  if (typeof exports === 'object')
+    module.exports = System;
+
+  __global.System = System;
+
+})(typeof self != 'undefined' ? self : global);
\ No newline at end of file
diff --git a/src/wrapper-start.js b/src/wrapper-start.js
new file mode 100644
index 0000000..1998bb4
--- /dev/null
+++ b/src/wrapper-start.js
@@ -0,0 +1,82 @@
+(function(__global) {
+
+  var isWorker = typeof window == 'undefined' && typeof self != 'undefined' && typeof importScripts != 'undefined';
+  var isBrowser = typeof window != 'undefined' && typeof document != 'undefined';
+  var isWindows = typeof process != 'undefined' && typeof process.platform != 'undefined' && !!process.platform.match(/^win/);
+
+  if (!__global.console)
+    __global.console = { assert: function() {} };
+
+  // IE8 support
+  var indexOf = Array.prototype.indexOf || function(item) {
+    for (var i = 0, thisLen = this.length; i < thisLen; i++) {
+      if (this[i] === item) {
+        return i;
+      }
+    }
+    return -1;
+  };
+  
+  var defineProperty;
+  (function () {
+    try {
+      if (!!Object.defineProperty({}, 'a', {}))
+        defineProperty = Object.defineProperty;
+    }
+    catch (e) {
+      defineProperty = function(obj, prop, opt) {
+        try {
+          obj[prop] = opt.value || opt.get.call(obj);
+        }
+        catch(e) {}
+      }
+    }
+  })();
+
+  function addToError(err, msg) {
+    if (err instanceof Error) {
+      err.message = msg + '\n\t' + err.message;
+      Error.call(err, err.message);
+    }
+    else {
+      err = msg + '\n\t' + err;
+    }
+    return err;
+  }
+
+  function __eval(source, debugName, context) {
+    try {
+      new Function(source).call(context);
+    }
+    catch(e) {
+      throw addToError(e, 'Evaluating ' + debugName);
+    }
+  }
+
+  var baseURI;
+  // environent baseURI detection
+  if (typeof document != 'undefined' && document.getElementsByTagName) {
+    baseURI = document.baseURI;
+
+    if (!baseURI) {
+      var bases = document.getElementsByTagName('base');
+      baseURI = bases[0] && bases[0].href || window.location.href;
+    }
+
+    // sanitize out the hash and querystring
+    baseURI = baseURI.split('#')[0].split('?')[0];
+    baseURI = baseURI.substr(0, baseURI.lastIndexOf('/') + 1);
+  }
+  else if (typeof process != 'undefined' && process.cwd) {
+    baseURI = 'file://' + (isWindows ? '/' : '') + process.cwd() + '/';
+    if (isWindows)
+      baseURI = baseURI.replace(/\\/g, '/');
+  }
+  else if (typeof location != 'undefined') {
+    baseURI = __global.location.href;
+  }
+  else {
+    throw new TypeError('No environment baseURI');
+  }
+
+  var URL = __global.URLPolyfill || __global.URL;
diff --git a/test/_browser.js b/test/_browser.js
new file mode 100644
index 0000000..83600b7
--- /dev/null
+++ b/test/_browser.js
@@ -0,0 +1,9 @@
+
+System.paths['*'] = 'base/*';
+baseURL += 'base/';
+
+System.paths.traceur = 'node_modules/traceur/bin/traceur.js';
+System.paths.babel = 'node_modules/babel-core/browser.js';
+System.paths.typescript = 'node_modules/typescript/bin/typescript.js';
+
+System.transpiler = __karma__.config.system.transpiler;
diff --git a/test/_helper.js b/test/_helper.js
new file mode 100644
index 0000000..eac26ee
--- /dev/null
+++ b/test/_helper.js
@@ -0,0 +1,59 @@
+
+
+(function (__global){
+  'use strict';
+
+  if(!__global.console){
+    __global.console = { log : __global.dump || function (){} };
+  }
+
+  var isWindows = typeof process != 'undefined' && process.platform.match(/^win/);
+
+  var baseURI;
+  // environent baseURI detection
+  if (typeof document != 'undefined' && document.getElementsByTagName) {
+    baseURI = document.baseURI;
+
+    if (!baseURI) {
+      var bases = document.getElementsByTagName('base');
+      baseURI = bases[0] && bases[0].href || window.location.href;
+    }
+
+    // sanitize out the hash and querystring
+    baseURI = baseURI.split('#')[0].split('?')[0];
+    baseURI = baseURI.substr(0, baseURI.lastIndexOf('/') + 1);
+  }
+  else if (typeof process != 'undefined' && process.cwd) {
+    baseURI = 'file://' + (isWindows ? '/' : '') + process.cwd() + '/';
+    if (isWindows)
+      baseURI = baseURI.replace(/\\/g, '/');
+  }
+  else if (typeof location != 'undefined') {
+    baseURI = __global.location.href;
+  }
+  else {
+    throw new TypeError('No environment baseURI');
+  }
+
+  // baseURI - the current path, for standard relative normalization (./x)
+  __global.baseURI = baseURI;
+
+  // baseURL - the base path, for plain relative normalization (x)
+  __global.baseURL = baseURI;
+
+  /**
+   * Describe a block if the bool is true.
+   * Will skip it otherwise.
+   * @param bool
+   * @returns {Function} describe or describe.skip
+   */
+  function describeIf(bool) {
+    return (bool ? describe : describe.skip)
+      .apply(null, Array.prototype.slice.call(arguments, 1));
+  }
+
+  __global.describeIf = describeIf;
+
+}(typeof window != 'undefined' ? window : global));
+
+
diff --git a/test/_node-babel.js b/test/_node-babel.js
new file mode 100644
index 0000000..3048744
--- /dev/null
+++ b/test/_node-babel.js
@@ -0,0 +1,16 @@
+'use strict';
+
+global.expect = require('expect.js');
+
+require('./_helper');
+
+require('regenerator/runtime');
+
+global.System = require('../index').System;
+global.System.transpiler = 'babel';
+
+require('./system.normalize.spec');
+require('./system.spec');
+
+require('./custom-loader');
+require('./custom-loader.spec');
diff --git a/test/_node-traceur.js b/test/_node-traceur.js
new file mode 100644
index 0000000..09a2a69
--- /dev/null
+++ b/test/_node-traceur.js
@@ -0,0 +1,13 @@
+'use strict';
+
+global.expect = require('expect.js');
+
+require('./_helper');
+
+global.System = require('../index').System;
+
+require('./system.normalize.spec');
+require('./system.spec');
+
+require('./custom-loader');
+require('./custom-loader.spec');
diff --git a/test/_node-typescript.js b/test/_node-typescript.js
new file mode 100644
index 0000000..e0d535c
--- /dev/null
+++ b/test/_node-typescript.js
@@ -0,0 +1,14 @@
+'use strict';
+
+global.expect = require('expect.js');
+
+require('./_helper');
+
+global.System = require('../index').System;
+global.ts = require('typescript');
+global.System.transpiler = 'typescript';
+
+require('./system.spec');
+
+require('./custom-loader');
+require('./custom-loader.spec');
diff --git a/test/browser-script-type-module.js b/test/browser-script-type-module.js
new file mode 100644
index 0000000..b0c572c
--- /dev/null
+++ b/test/browser-script-type-module.js
@@ -0,0 +1,13 @@
+
+(function (__global){
+  'use strict';
+
+  if (!__global){
+    return;
+  }
+
+  document.write('<script type="module"> window.anon = class { constructor() {  } } </script>');
+
+}(typeof window != 'undefined' && window ));
+
+
diff --git a/test/custom-loader.js b/test/custom-loader.js
new file mode 100644
index 0000000..04734d4
--- /dev/null
+++ b/test/custom-loader.js
@@ -0,0 +1,148 @@
+//
+
+(function (__global) {
+
+
+  var customModules = {};
+  var customFactories = {};
+
+  var executeModule = function (name) {
+    if (!customFactories[name]) {
+      return;
+    }
+    var module = customFactories[name].apply(null, []);
+    customModules[name] = module;
+    return module;
+  };
+
+  function CustomLoader(baseURL) {
+    System.constructor.call(this, baseURL);
+  }
+
+  // inline Object.create-style class extension
+  function CustomLoaderProto() {}
+  CustomLoaderProto.prototype = System.constructor.prototype;
+  CustomLoader.prototype = new CustomLoaderProto();
+
+
+  
+  CustomLoader.prototype.normalize = function (name, parentName, parentAddress) {
+    return new Promise(function(resolve, reject) {
+      if (name == 'asdfasdf') {
+        return setTimeout(function () {
+          resolve('test/loader/async-norm.js');
+        }, 500);
+      }
+
+      if (name == 'error1') {
+        return setTimeout(function () { reject('error1'); }, 100);
+      }
+
+      var normalized = System.normalize(name, parentName, parentAddress);
+      resolve(normalized);
+    });
+  };
+
+  CustomLoader.prototype.locate = function (load) {
+    if (load.name == 'error2') {
+      return new Promise(function (resolve, reject) {
+        setTimeout(function () { reject('error2'); }, 100);
+      });
+    }
+
+    if (load.name.match(/path\//))
+      load.name = load.name.replace(/path\//, 'test/loader/');
+
+    return System.locate(load);
+  };
+
+  
+  CustomLoader.prototype.fetch = function (load) {
+    if (load.name == 'error3') {
+      throw 'error3';
+    }
+    if (load.name == 'error4' || load.name == 'error5') {
+      return 'asdf';
+    }
+    return System.fetch.apply(this, arguments);
+  };
+
+  CustomLoader.prototype.translate = function (load) {
+    if (load.name == 'error4') {
+      return new Promise(function (resolve, reject) {
+        setTimeout(function () { reject('error4'); }, 100);
+      });
+    }
+    return System.translate.apply(this, arguments);
+  };
+
+  CustomLoader.prototype.instantiate = function (load) {
+    if (load.name.match(/(traceur|babel.+\/browser).js$/)) {
+      var transpiler = this.transpiler;
+      return System['import'](transpiler).then(function() {
+        return {
+          deps: [],
+          execute: function() {
+            return System.get(System.normalize(transpiler));
+          }
+        };
+      });
+    }
+
+    if (load.name == 'error5') {
+      return new Promise(function (resolve, reject) {
+        setTimeout(function () { reject('error5'); }, 100);
+      });
+    }
+    // very bad AMD support
+    if (load.source.indexOf('define') == -1) {
+      return System.instantiate(load);
+    }
+
+    var factory, deps;
+    var define = function (_deps, _factory) {
+      deps = _deps;
+      factory = _factory;
+    };
+    eval(load.source);
+
+    customFactories[load.name] = factory;
+
+    // normalize all dependencies now
+    var normalizePromises = [];
+    for (var i = 0; i < deps.length; i++) {
+      normalizePromises.push(Promise.resolve(System.normalize(deps[i], load.name, load.address)));
+    }
+
+    return Promise.all(normalizePromises).then(function (resolvedDeps) {
+
+      return {
+        deps: deps,
+        execute: function () {
+          if (customModules[load.name]) {
+            return System.newModule(customModules[load.name]);
+          }
+
+          // first ensure all dependencies have been executed
+          for (var i = 0; i < resolvedDeps.length; i++) {
+            resolvedDeps[i] = executeModule(resolvedDeps[i]);
+          }
+
+          var module = factory.apply(null, resolvedDeps);
+
+          customModules[load.name] = module;
+          return System.newModule(module);
+        }
+      };
+    });
+  };
+
+  var customLoader = new CustomLoader(System.baseURL);
+  customLoader.transpiler = System.transpiler;
+
+
+  if (typeof exports === 'object')
+    module.exports = customLoader;
+
+  __global.customLoader = customLoader;
+}(typeof window != 'undefined' ? window : global));
diff --git a/test/custom-loader.spec.js b/test/custom-loader.spec.js
new file mode 100644
index 0000000..f1e188d
--- /dev/null
+++ b/test/custom-loader.spec.js
@@ -0,0 +1,102 @@
+//
+
+describe('Custom Loader', function () {
+
+  describe('#import', function () {
+
+    describe('scripts', function () {
+      if (typeof __karma__ == 'undefined' || !__karma__.config.system.ie8)
+        it('should support ES6 scripts', function(done) {
+        customLoader['import']('test/loader/test.js')
+          .then(function (m) {
+            expect(m.loader).to.be.equal('custom');
+          })
+          .then(done, done)
+        });
+
+      it('should support AMD scripts', function(done) {
+        customLoader['import']('test/loader/amd.js')
+        .then(function (m) {
+          expect(m.format).to.be.equal('amd');
+        })
+        .then(done, done);
+      });
+    });
+
+    describe('special #locate path rule', function a() {
+
+      if (typeof __karma__ == 'undefined' || !__karma__.config.system.ie8)
+        it('should support special loading rules', function(done) {
+          customLoader['import']('path/custom.js')
+          .then(function (m) {
+            expect(m.path).to.be.ok();
+          })
+          .then(done, done);
+        });
+
+    });
+
+    describe('errors', function () {
+
+      function supposeToFail() {
+        expect(false, 'should not be successful').to.be.ok();
+      }
+      var base = baseURL + 'test/loader/';
+
+      it('should make the normalize throw', function(done) {
+        customLoader['import']('test/loader/error1-parent.js')
+        .then(supposeToFail, function(e) {
+          expect(e.toString()).to.contain('Error loading ' + base + 'error1-parent.js');
+        })
+        .then(done, done);
+      });
+
+      it('should make the locate throw', function(done) {
+        customLoader['import']('test/loader/error2')
+        .then(supposeToFail, function(e) {
+          expect(typeof window != 'undefined' ? e.toString() : e.stack).to.be.contain('Error loading ' + base + 'error2');
+        })
+        .then(done, done);
+      });
+
+      it('should make the fetch throw', function(done) {
+        customLoader['import']('test/loader/error3')
+        .then(supposeToFail, function(e) {
+          expect(typeof window != 'undefined' ? e.toString() : e.stack).to.be.contain('Error loading ' + base + 'error3');
+        })
+        .then(done, done);
+      });
+
+      it('should make the translate throw', function(done) {
+        customLoader['import']('test/loader/error4')
+        .then(supposeToFail, function(e) {
+          expect(typeof window != 'undefined' ? e.toString() : e.stack).to.be.contain('Error loading ' + base + 'error4');
+        })
+        .then(done, done);
+      });
+
+      it('should make the instantiate throw', function(done) {
+        customLoader['import']('test/loader/error5')
+        .then(supposeToFail, function(e) {
+          expect(typeof window != 'undefined' ? e.toString() : e.stack).to.be.contain('Error loading ' + base + 'error5');
+        })
+        .then(done, done);
+      });
+
+    });
+
+  });
+
+  describe('#normalize', function () {
+    it('should support async normalization', function(done) {
+      customLoader.normalize('asdfasdf')
+      .then(function (normalized) {
+        return customLoader['import'](normalized);
+      })
+      .then(function (m) {
+        expect(m.n).to.be.equal('n');
+      })
+      .then(done, done);
+    });
+  });
+});
diff --git a/test/loader/amd-dep.js b/test/loader/amd-dep.js
new file mode 100644
index 0000000..12bbc65
--- /dev/null
+++ b/test/loader/amd-dep.js
@@ -0,0 +1,5 @@
+define([], function() {
+  return {
+    name: 'amd'
+  };
+});
diff --git a/test/loader/amd.js b/test/loader/amd.js
new file mode 100644
index 0000000..3b5a6ae
--- /dev/null
+++ b/test/loader/amd.js
@@ -0,0 +1,5 @@
+define(['./amd-dep.js'], function(dep) {
+  return {
+    format: dep.name
+  };
+});
diff --git a/test/loader/anon.js b/test/loader/anon.js
new file mode 100644
index 0000000..7a29aca
--- /dev/null
+++ b/test/loader/anon.js
@@ -0,0 +1 @@
+window.anon2 = class {}
diff --git a/test/loader/async-norm.js b/test/loader/async-norm.js
new file mode 100644
index 0000000..ceef94d
--- /dev/null
+++ b/test/loader/async-norm.js
@@ -0,0 +1,3 @@
+define([], function() {
+  return { n: 'n' };
+});
diff --git a/test/loader/custom-folder/path.js b/test/loader/custom-folder/path.js
new file mode 100644
index 0000000..0e7f339
--- /dev/null
+++ b/test/loader/custom-folder/path.js
@@ -0,0 +1 @@
+export var bar = 'baa';
diff --git a/test/loader/custom-path.js b/test/loader/custom-path.js
new file mode 100644
index 0000000..c5ebeb9
--- /dev/null
+++ b/test/loader/custom-path.js
@@ -0,0 +1 @@
+export var bar = 'bar';
diff --git a/test/loader/custom.js b/test/loader/custom.js
new file mode 100644
index 0000000..6369843
--- /dev/null
+++ b/test/loader/custom.js
@@ -0,0 +1 @@
+export var path = true;
\ No newline at end of file
diff --git a/test/loader/error1-parent.js b/test/loader/error1-parent.js
new file mode 100644
index 0000000..3f4cf9a
--- /dev/null
+++ b/test/loader/error1-parent.js
@@ -0,0 +1 @@
+import 'error1';
diff --git a/test/loader/master.js b/test/loader/master.js
new file mode 100644
index 0000000..ec0c73a
--- /dev/null
+++ b/test/loader/master.js
@@ -0,0 +1 @@
+import 'slave';
diff --git a/test/loader/module.js b/test/loader/module.js
new file mode 100644
index 0000000..c04c425
--- /dev/null
+++ b/test/loader/module.js
@@ -0,0 +1,7 @@
+export var run;
+
+(function(global) {
+  run = global.run ? 'second' : 'first';
+
+  global.run = true;
+})(typeof window == 'undefined' ? global : window);
\ No newline at end of file
diff --git a/test/loader/moduleName.js b/test/loader/moduleName.js
new file mode 100644
index 0000000..f022135
--- /dev/null
+++ b/test/loader/moduleName.js
@@ -0,0 +1 @@
+export var name = __moduleName;
\ No newline at end of file
diff --git a/test/loader/named.js b/test/loader/named.js
new file mode 100644
index 0000000..09761e2
--- /dev/null
+++ b/test/loader/named.js
@@ -0,0 +1 @@
+export var q = 'test';
diff --git a/test/loader/specific-path.js b/test/loader/specific-path.js
new file mode 100644
index 0000000..d1a69ef
--- /dev/null
+++ b/test/loader/specific-path.js
@@ -0,0 +1 @@
+export var path = true;
diff --git a/test/loader/test.js b/test/loader/test.js
new file mode 100644
index 0000000..2e0dd77
--- /dev/null
+++ b/test/loader/test.js
@@ -0,0 +1 @@
+export var loader = 'custom';
diff --git a/test/loads/_a.js b/test/loads/_a.js
new file mode 100644
index 0000000..eeaa5a6
--- /dev/null
+++ b/test/loads/_a.js
@@ -0,0 +1,4 @@
+export { b } from './_b.js';
+export { d } from './_d.js';
+export { g } from './_g.js';
+export var a = 'a';
diff --git a/test/loads/_b.js b/test/loads/_b.js
new file mode 100644
index 0000000..c405088
--- /dev/null
+++ b/test/loads/_b.js
@@ -0,0 +1,2 @@
+export { c } from './_c.js';
+export var b = 'b';
diff --git a/test/loads/_c.js b/test/loads/_c.js
new file mode 100644
index 0000000..16770af
--- /dev/null
+++ b/test/loads/_c.js
@@ -0,0 +1,2 @@
+export { d } from './_d.js';
+export var c = 'c';
diff --git a/test/loads/_d.js b/test/loads/_d.js
new file mode 100644
index 0000000..91f12c0
--- /dev/null
+++ b/test/loads/_d.js
@@ -0,0 +1 @@
+export var d = 'd';
diff --git a/test/loads/_e.js b/test/loads/_e.js
new file mode 100644
index 0000000..92c711c
--- /dev/null
+++ b/test/loads/_e.js
@@ -0,0 +1,2 @@
+export { c } from './_c.js';
+export var e = 'e';
diff --git a/test/loads/_f.js b/test/loads/_f.js
new file mode 100644
index 0000000..5da67dd
--- /dev/null
+++ b/test/loads/_f.js
@@ -0,0 +1,2 @@
+export { g } from './_g.js';
+export var f = 'f';
diff --git a/test/loads/_g.js b/test/loads/_g.js
new file mode 100644
index 0000000..d57ef0b
--- /dev/null
+++ b/test/loads/_g.js
@@ -0,0 +1 @@
+export var g = 'g';
diff --git a/test/loads/_h.js b/test/loads/_h.js
new file mode 100644
index 0000000..a0c6228
--- /dev/null
+++ b/test/loads/_h.js
@@ -0,0 +1,3 @@
+export { a } from './_a.js';
+export { i } from './_i.js';
+export var h = 'h';
diff --git a/test/loads/_i.js b/test/loads/_i.js
new file mode 100644
index 0000000..de29b56
--- /dev/null
+++ b/test/loads/_i.js
@@ -0,0 +1,2 @@
+export { b } from './_b.js';
+export var i = 'i';
diff --git a/test/loads/a.js b/test/loads/a.js
new file mode 100644
index 0000000..c9615a4
--- /dev/null
+++ b/test/loads/a.js
@@ -0,0 +1,2 @@
+export { b } from './b.js';
+export var a = 'a';
diff --git a/test/loads/b.js b/test/loads/b.js
new file mode 100644
index 0000000..6db04b4
--- /dev/null
+++ b/test/loads/b.js
@@ -0,0 +1 @@
+export var b = 'b';
diff --git a/test/loads/c.js b/test/loads/c.js
new file mode 100644
index 0000000..3dc16b3
--- /dev/null
+++ b/test/loads/c.js
@@ -0,0 +1,3 @@
+export { a } from './a.js';
+export { b } from './a.js';
+export var c = 'c';
diff --git a/test/loads/deperror.js b/test/loads/deperror.js
new file mode 100644
index 0000000..f2776f7
--- /dev/null
+++ b/test/loads/deperror.js
@@ -0,0 +1 @@
+throw 'dep error';
diff --git a/test/loads/load-non-existent.js b/test/loads/load-non-existent.js
new file mode 100644
index 0000000..63d9541
--- /dev/null
+++ b/test/loads/load-non-existent.js
@@ -0,0 +1 @@
+import 'non-existent';
\ No newline at end of file
diff --git a/test/loads/main.js b/test/loads/main.js
new file mode 100644
index 0000000..6ba10d8
--- /dev/null
+++ b/test/loads/main.js
@@ -0,0 +1 @@
+import "./deperror.js";
diff --git a/test/loads/s.js b/test/loads/s.js
new file mode 100644
index 0000000..a20f19e
--- /dev/null
+++ b/test/loads/s.js
@@ -0,0 +1,3 @@
+export { b, c } from './c.js';
+export { a } from './a.js';
+export var s = 's';
diff --git a/test/manual/source-maps/test.html b/test/manual/source-maps/test.html
new file mode 100644
index 0000000..5de35a0
--- /dev/null
+++ b/test/manual/source-maps/test.html
@@ -0,0 +1,13 @@
+<!doctype html>
+  <html>
+
+  <body>
+    <h1>Source Map Stack Trace Test</h1>
+    <script src="../../../node_modules/traceur/bin/traceur.js"></script>
+    <script src="../../../dist/es6-module-loader.src.js"></script>
+    <script>
+      System.import('test').then(function(module) {
+        console.log(module.make().stack)
+      })
+    </script>
+  </body>
diff --git a/test/manual/source-maps/test.js b/test/manual/source-maps/test.js
new file mode 100644
index 0000000..1e88e56
--- /dev/null
+++ b/test/manual/source-maps/test.js
@@ -0,0 +1,4 @@
+export function make() {
+  return new Error('Hello')
+}
+
diff --git a/test/perf.html b/test/perf.html
new file mode 100644
index 0000000..d599e8e
--- /dev/null
+++ b/test/perf.html
@@ -0,0 +1,89 @@
+<!doctype html>
+  <script>
+    // delete window.Promise;
+  </script>
+  <script src="../dist/es6-module-loader.js"></script>
+  <script>
+    /* PARAMETERS */
+    var TREE_DEPTH = 10;
+    var NUM_MODULES = 1000;
+
+    /*
+      TREE LOOKS LIKE - 
+
+                           MODULE NUM_MODULES
+                                   |
+                                   |
+      -------------------------------------  ... -----
+      |                            |                 |
+    MODULE 0              MODULE TREE_DEPTH         ...
+      |                            |
+    MODULE 1              MODULE TREE_DEPTH + 1
+     ...                         ...
+ MODULE TREE_DEPTH - 1   MODULE TREE_DEPTH * 2 - 1
+
+THAT IS -
+  DEPTH   =  TREE_DEPTH
+  BREADTH =  FLOOR(NUM_MODULES / TREE_DEPTH)
+
+    */
+
+    /*
+      
+      PERF RESULTS
+      ------------
+
+      WITH 1000 modules,
+
+      TREE_DEPTH    FULL LOAD TIME PER MODULE (including evaluation and defining)
+          1          0.25ms
+          10         0.27ms
+          50         0.30ms
+         100         0.35ms
+         500         0.90ms
+        1000         1.90ms
+
+    */
+
+
+    System.set('module0', System.newModule({}));
+    System.instantiate = function(load) {
+      var num = parseInt(load.name.substr(6));
+
+      var deps = [];
+
+      // the last module depends on all of them
+      if (num == NUM_MODULES) {
+        for (var i = 0; i < NUM_MODULES; i += TREE_DEPTH)
+          deps.push('module' + i);
+      }
+      else if (num % TREE_DEPTH != TREE_DEPTH - 1)
+        deps = ['module' + (num + 1)];
+
+      return {
+        deps: deps,
+        execute: function() {
+          eval(load.source);
+          return System.newModule({});
+        }
+      };
+    }
+
+    function start() {
+      document.body.innerHTML = '';
+      var startTime = +Date.now();
+
+      for (var i = 1; i <= NUM_MODULES; i++)
+        System.define('module' + i, "function q() {} var p = 5;\n // non-trivial code");
+      
+      System.import('module' + NUM_MODULES).then(function() {
+        document.body.innerHTML = ((Date.now() - startTime) / NUM_MODULES) + 'ms per module';
+      }).catch(function(e) {
+        setTimeout(function() {
+          throw e;
+        })
+      });
+    }
+  </script>
+  <body onclick="start()" style="height:100%">
+    <p>Click to start</p>
\ No newline at end of file
diff --git a/test/perf.js b/test/perf.js
new file mode 100644
index 0000000..261b38a
--- /dev/null
+++ b/test/perf.js
@@ -0,0 +1,137 @@
+'use strict';
+
+/* PARAMETERS */
+var NUM_MODULES = 1000;
+
+
+    /*
+      TREE LOOKS LIKE -
+
+                           MODULE NUM_MODULES
+                                   |
+                                   |
+      -------------------------------------  ... -----
+      |                            |                 |
+    MODULE 0              MODULE TREE_DEPTH         ...
+      |                            |
+    MODULE 1              MODULE TREE_DEPTH + 1
+     ...                         ...
+ MODULE TREE_DEPTH - 1   MODULE TREE_DEPTH * 2 - 1
+
+THAT IS -
+  DEPTH   =  TREE_DEPTH
+  BREADTH =  FLOOR(NUM_MODULES / TREE_DEPTH)
+
+    */
+
+    /*
+
+      PERF RESULTS
+      ------------
+
+      WITH 1000 modules,
+
+      TREE_DEPTH    FULL LOAD TIME PER MODULE (including evaluation and defining)
+          1          0.25ms
+          10         0.27ms
+          50         0.30ms
+         100         0.35ms
+         500         0.90ms
+        1000         1.90ms
+
+    */
+
+////
+
+System.set('module0', System.newModule({}));
+
+function instantiateAtDepth(treeDepth) {
+  return function (load) {
+    var num = parseInt(load.name.substr(6));
+
+    var deps = [];
+
+    // the last module depends on all of them
+    if (num == NUM_MODULES) {
+      for (var i = 0; i < NUM_MODULES; i += treeDepth)
+        deps.push('module' + i);
+    }
+    else if (num % treeDepth != treeDepth - 1)
+      deps = ['module' + (num + 1)];
+
+    return {
+      deps: deps,
+      execute: function () {
+        eval(load.source);
+        return System.newModule({});
+      }
+    };
+  };
+}
+
+////
+
+function hundredModulesBench(treeDepth) {
+
+  benchmark('hundred modules depth ' + treeDepth, function (deferred) {
+
+    // Generate range 0 to NUM_MODULES
+    var range = Array.apply(null, { length: NUM_MODULES });
+
+    Promise
+      // Define all the modules
+      .all(range.map(function (_, i) {
+        if (!i) return;
+        return System.define('module' + i, "function q() {} var p = 5;\n // non-trivial code");
+      }))
+
+      .then(function () {
+        // Import the last one
+        return System.import('module' + (NUM_MODULES - 1));
+      })
+
+      .then(function () {
+        return Promise
+          // Remove all the modules
+          .all(range.map(function (_, i) {
+            if (!i) return;
+            return System.delete('module' + i);
+          })
+        );
+      })
+
+      // End of the bench
+      .then(function () {
+        deferred.resolve();
+      })
+      .catch(function (e) {
+        setTimeout(function () {
+          throw e;
+        })
+      })
+    ;
+
+  }, {
+    defer: true,
+    timeout: false,
+    setup: function(){
+
+      System.instantiate = instantiateAtDepth(treeDepth);
+
+    }
+  });
+
+}
+
+////
+
+suite('System', function () {
+
+  hundredModulesBench(1);
+  hundredModulesBench(10);
+  hundredModulesBench(50);
+  hundredModulesBench(100);
+  hundredModulesBench(500);
+  hundredModulesBench(1000);
+
+});
diff --git a/test/syntax/circular1.js b/test/syntax/circular1.js
new file mode 100644
index 0000000..0401544
--- /dev/null
+++ b/test/syntax/circular1.js
@@ -0,0 +1,13 @@
+import {fn2, variable2} from './circular2.js';
+
+export var variable1 = 'test circular 1';
+
+export { output as output2 } from './circular2.js';
+
+fn2();
+
+export var output;
+
+export function fn1() {
+  output = variable2;
+}
\ No newline at end of file
diff --git a/test/syntax/circular2.js b/test/syntax/circular2.js
new file mode 100644
index 0000000..695b1dc
--- /dev/null
+++ b/test/syntax/circular2.js
@@ -0,0 +1,13 @@
+import {fn1, variable1} from './circular1.js';
+
+export var variable2 = 'test circular 2';
+
+export { output as output1 } from './circular1.js';
+
+fn1();
+
+export var output;
+
+export function fn2() {
+  output = variable1;
+}
\ No newline at end of file
diff --git a/test/syntax/direct.js b/test/syntax/direct.js
new file mode 100644
index 0000000..b826544
--- /dev/null
+++ b/test/syntax/direct.js
@@ -0,0 +1 @@
+import { p } from './es6-dep.js';
diff --git a/test/syntax/es6-dep.js b/test/syntax/es6-dep.js
new file mode 100644
index 0000000..41890af
--- /dev/null
+++ b/test/syntax/es6-dep.js
@@ -0,0 +1,2 @@
+export var p = 'p';
+console.log('dep');
diff --git a/test/syntax/es6-file.js b/test/syntax/es6-file.js
new file mode 100644
index 0000000..ccd3fca
--- /dev/null
+++ b/test/syntax/es6-file.js
@@ -0,0 +1,14 @@
+export class q {
+  foo() {
+    throw 'g';
+    console.log('class method');
+  }
+}
+
+export default 4;
+
+// export const ii = 'sdf';
+
+var p = 5;
+
+import * as Q from './test-file.js';
diff --git a/test/syntax/es6-generator.js b/test/syntax/es6-generator.js
new file mode 100644
index 0000000..2ad064e
--- /dev/null
+++ b/test/syntax/es6-generator.js
@@ -0,0 +1,3 @@
+export function* generator() {
+  yield 1;
+}
diff --git a/test/syntax/es6-withdep.js b/test/syntax/es6-withdep.js
new file mode 100644
index 0000000..15774ca
--- /dev/null
+++ b/test/syntax/es6-withdep.js
@@ -0,0 +1,2 @@
+export { p } from './es6-dep.js';
+console.log('withdep');
\ No newline at end of file
diff --git a/test/syntax/es6.js b/test/syntax/es6.js
new file mode 100644
index 0000000..edcd3c7
--- /dev/null
+++ b/test/syntax/es6.js
@@ -0,0 +1 @@
+export var p = 'p';
diff --git a/test/syntax/even.js b/test/syntax/even.js
new file mode 100644
index 0000000..91cf85b
--- /dev/null
+++ b/test/syntax/even.js
@@ -0,0 +1,10 @@
+import { odd } from './odd.js'
+
+export var counter = 0;
+
+export function even(n) {
+  counter++;
+  return n == 0 || odd(n - 1);
+}
+
+odd(1);
\ No newline at end of file
diff --git a/test/syntax/export-default.js b/test/syntax/export-default.js
new file mode 100644
index 0000000..0365b4b
--- /dev/null
+++ b/test/syntax/export-default.js
@@ -0,0 +1,3 @@
+export default function() {
+  return 'test';
+}
diff --git a/test/syntax/export-star.js b/test/syntax/export-star.js
new file mode 100644
index 0000000..31cd2eb
--- /dev/null
+++ b/test/syntax/export-star.js
@@ -0,0 +1,2 @@
+export * from './star-dep.js';
+export var bar = 'bar';
\ No newline at end of file
diff --git a/test/syntax/export-star2.js b/test/syntax/export-star2.js
new file mode 100644
index 0000000..b1c56fa
--- /dev/null
+++ b/test/syntax/export-star2.js
@@ -0,0 +1,4 @@
+export * from './export-star.js';
+export function foo() {
+  
+}
\ No newline at end of file
diff --git a/test/syntax/export.js b/test/syntax/export.js
new file mode 100644
index 0000000..2f02154
--- /dev/null
+++ b/test/syntax/export.js
@@ -0,0 +1,10 @@
+export var p = 5;
+export function foo() {};
+export var q = {};
+
+export default function bar() {};
+
+var s = 4;
+
+export { s };
+export { s as t, q as m };
\ No newline at end of file
diff --git a/test/syntax/import.js b/test/syntax/import.js
new file mode 100644
index 0000000..38b0be8
--- /dev/null
+++ b/test/syntax/import.js
@@ -0,0 +1,11 @@
+import './export.js';
+
+import d from './export.js';
+
+import { s as p } from './reexport1.js';
+
+import { z, q as r } from './reexport2.js';
+
+import * as q from './reexport1.js';
+
+export { d as a, p as b, z as c, r as d, q }
\ No newline at end of file
diff --git a/test/syntax/odd.js b/test/syntax/odd.js
new file mode 100644
index 0000000..c9222d2
--- /dev/null
+++ b/test/syntax/odd.js
@@ -0,0 +1,5 @@
+import { even } from './even.js';
+
+export function odd(n) {
+  return n != 0 && even(n - 1);
+}
\ No newline at end of file
diff --git a/test/syntax/rebinding.js b/test/syntax/rebinding.js
new file mode 100644
index 0000000..ce43dbb
--- /dev/null
+++ b/test/syntax/rebinding.js
@@ -0,0 +1 @@
+export var p = 4;
\ No newline at end of file
diff --git a/test/syntax/reexport-binding.js b/test/syntax/reexport-binding.js
new file mode 100644
index 0000000..3fcf5f8
--- /dev/null
+++ b/test/syntax/reexport-binding.js
@@ -0,0 +1 @@
+import { p } from './rebinding.js';
\ No newline at end of file
diff --git a/test/syntax/reexport1.js b/test/syntax/reexport1.js
new file mode 100644
index 0000000..f16ebf7
--- /dev/null
+++ b/test/syntax/reexport1.js
@@ -0,0 +1 @@
+export * from './export.js';
\ No newline at end of file
diff --git a/test/syntax/reexport2.js b/test/syntax/reexport2.js
new file mode 100644
index 0000000..42b4715
--- /dev/null
+++ b/test/syntax/reexport2.js
@@ -0,0 +1,2 @@
+export { t as q, p as z } from './export.js';
+export default 4;
diff --git a/test/syntax/script.js b/test/syntax/script.js
new file mode 100644
index 0000000..a6a223c
--- /dev/null
+++ b/test/syntax/script.js
@@ -0,0 +1 @@
+console.log('script');
diff --git a/test/syntax/star-dep.js b/test/syntax/star-dep.js
new file mode 100644
index 0000000..0b7981c
--- /dev/null
+++ b/test/syntax/star-dep.js
@@ -0,0 +1 @@
+export var foo = 'foo';
\ No newline at end of file
diff --git a/test/syntax/test-file.js b/test/syntax/test-file.js
new file mode 100644
index 0000000..dea37df
--- /dev/null
+++ b/test/syntax/test-file.js
@@ -0,0 +1,5 @@
+export var s = 4;
+
+export default function q() {
+
+}
\ No newline at end of file
diff --git a/test/system.normalize.spec.js b/test/system.normalize.spec.js
new file mode 100644
index 0000000..3775ccc
--- /dev/null
+++ b/test/system.normalize.spec.js
@@ -0,0 +1,69 @@
+//
+
+describe('System', function () {
+
+  describe('#toString', function() {
+    it('Module toString is "Module"', function() {
+      expect(System.newModule({}).toString()).to.equal('Module');
+    });
+  });
+
+  describe('#normalize', function () {
+
+    describe('when having no argument', function () {
+
+      it('should throw with no specified name', function () {
+        expect(function () { System.normalize(); }).to.throwException();
+      });
+
+    });
+
+    describe('when having one argument', function () {
+
+      it('should allow no referer', function () {
+        expect(System.normalize('d/e/f')).to.equal(baseURL + 'd/e/f');
+      });
+
+      var backTrack
+      // in the browser, double backtracking goes below the hostname -> just keep at hostname
+      if (typeof window != 'undefined')
+        backTrack = baseURI.substr(0, baseURI.length - 1);
+      else
+        backTrack = baseURI.split('/').splice(0, baseURI.split('/').length - 2).join('/')
+      
+      if (typeof window != 'undefined')
+
+      it('should backtracking below baseURL', function () {
+        expect(System.normalize('../e/f')).to.equal(backTrack + '/e/f');
+      });
+
+      it('should double dotted backtracking', function () {
+        expect(System.normalize('./../a.js')).to.equal(backTrack + '/a.js');
+      });
+
+      it('should normalize ./ and plain names to the same base', function () {
+        expect(System.normalize('./a.js')).to.equal(baseURI + 'a.js');
+      });
+
+    });
+
+    describe('when having two arguments', function () {
+
+      var refererAddress = 'http://parent.com/dir/file';
+
+      it('should normalize relative paths against the parent name', function () {
+        expect(System.normalize('./d/e/f', refererAddress)).to.equal('http://parent.com/dir/d/e/f');
+        expect(System.normalize('../e/f', refererAddress)).to.equal('http://parent.com/e/f');
+      });
+
+    });
+  });
+
+  describe('#locate', function () {
+
+    it('should be the identity function', function () {
+      expect(System.locate({name: '@some/name'})).to.equal('@some/name');
+    });
+
+  });
+});
diff --git a/test/system.spec.js b/test/system.spec.js
new file mode 100644
index 0000000..9d05fca
--- /dev/null
+++ b/test/system.spec.js
@@ -0,0 +1,452 @@
+//
+
+if (typeof babel != 'undefined')
+  System.transpiler = 'babel';
+
+var ie = typeof window != 'undefined' && window.navigator.userAgent.match(/Trident/);
+
+describe('System', function () {
+
+  describe('prerequisite', function () {
+
+    it('should be a instance of Loader', function () {
+      expect(System).to.be.a(Reflect.Loader);
+    });
+
+  });
+
+  describe('#import', function () {
+
+    describe('an ES5 script', function () {
+
+      it('should import a ES5 script', function (done) {
+        System.import('test/syntax/script.js')
+          .then(function (m) {
+            expect(!!m).to.be.ok();
+          })
+          .then(done, done);
+      });
+
+      it('should import a ES5 script once loaded', function (done) {
+        System.import('test/syntax/script.js')
+          .then(function () {
+            return System.import('test/syntax/script.js').
+              then(function (m) {
+                expect(!!m).to.be.ok();
+              });
+          })
+          .then(done, done);
+      });
+
+    });
+
+    describe('System registry methods', function() {
+
+      it('should support set, get and delete', function(done) {
+
+        var testPath = baseURL + 'test/loader/module.js';
+
+        System.import(testPath).then(function(m) {
+          expect(m.run).to.equal('first');
+          System.delete(testPath);
+          return System.import(testPath);
+        })
+        .then(function(m) {
+          expect(m.run).to.equal('second');
+          System.delete('loader.module');
+          System.set(testPath, System.newModule({ custom: 'module' }));
+          return System.import(testPath);
+        })
+        .then(function(m) {
+          expect(m.custom).to.equal('module');
+        })
+        .then(done, done);
+      });
+    });
+
+    describe('an ES6 script', function () {
+
+      it('should import an ES6 script', function (done) {
+        System.import('test/syntax/es6.js')
+          .then(function (m) {
+            expect(m.p).to.equal('p');
+          })
+          .then(done, done);
+      });
+
+      it('should import an ES6 script with its dependencies', function (done) {
+        System.import('test/syntax/es6-withdep.js')
+          .then(function (m) {
+            expect(m.p).to.equal('p');
+          })
+          .then(done, done);
+      });
+
+      // typescript does not support generators yet
+      (ie || System.transpiler === 'typescript' ? it.skip : it)('should import an ES6 script with a generator', function (done) {
+        System.import('test/syntax/es6-generator.js')
+          .then(function (m) {
+            expect(!!m.generator).to.be.ok();
+          })
+          .then(done, done);
+      });
+
+      it('should import without bindings', function (done) {
+        System.import('test/syntax/direct.js')
+          .then(function (m) {
+            expect(!!m).to.be.ok();
+          })
+          .then(done, done);
+      });
+
+      it('should support es6 various syntax', function (done) {
+        System.import('test/syntax/es6-file.js')
+          .then(function (m) {
+
+            expect(m.q).to.be.a('function');
+
+            expect(function () { (new m.q()).foo(); })
+              .to.throwException(function (e) {
+                expect(e).to.equal('g');
+              });
+
+          })
+          .then(done, done);
+      });
+
+    });
+
+    describe('with circular dependencies', function () {
+
+      (System.transpiler == 'traceur' ? it : it.skip)('should resolve circular dependencies', function (done) {
+        System.import('test/syntax/circular1.js')
+          .then(function (m1) {
+            return System.import('test/syntax/circular2.js').then(function (m2) {
+              expect(m1.variable1).to.equal('test circular 1');
+              expect(m2.variable2).to.equal('test circular 2');
+
+              expect(m2.output, 'The module 2 output is the module 1 variable')
+                .to.equal('test circular 1');
+              expect(m1.output, 'The module 1 output is the module 2 variable')
+                .to.equal('test circular 2');
+              expect(m2.output1, 'The module 2 output1 is the module 1 output')
+                .to.equal('test circular 2');
+              expect(m1.output2, 'The module 1 output2 is the module 2 output')
+                .to.equal('test circular 1');
+            });
+          })
+          .then(done, done);
+      });
+
+
+      it('should update circular dependencies', function (done) {
+        System.import('test/syntax/even.js')
+          .then(function (m) {
+            expect(m.counter, 'Counter initially at 1').to.be.equal(1);
+            expect(m.even(10), 'Must be an even number').to.be.ok();
+            expect(m.counter, 'Counter sould now be at 7').to.be.equal(7);
+            expect(m.even(15), 'Must be an odd number').to.not.be.ok();
+            expect(m.counter, 'Counter sould now be at 15').to.be.equal(15);
+          })
+          .then(done, done);
+
+      });
+
+    });
+
+    describe('loading order', function () {
+
+      function expectedOrder(file, order, done) {
+        System.import('test/loads/' + file)
+          .then(function (m) {
+            order.forEach(function (letter) {
+              expect(m[letter], 'The "' + letter + '" file wasn\'t loaded')
+                .to.equal(letter);
+            });
+
+          })
+          .then(done, done);
+      }
+
+      it('should load in order (a)', function (done) {
+        expectedOrder('a.js', ['a', 'b'], done)
+      });
+
+      it('should load in order (c)', function (done) {
+        expectedOrder('c.js', ['c', 'a', 'b'], done)
+      });
+
+      it('should load in order (s)', function (done) {
+        expectedOrder('s.js', ['s', 'c', 'a', 'b'], done)
+      });
+
+      it('should load in order (_a)', function (done) {
+        expectedOrder('_a.js', ['b', 'd', 'g', 'a'], done)
+      });
+
+      it('should load in order (_e)', function (done) {
+        expectedOrder('_e.js', ['c', 'e'], done)
+      });
+
+      it('should load in order (_f)', function (done) {
+        expectedOrder('_f.js', ['g', 'f'], done)
+      });
+
+      it('should load in order (_h)', function (done) {
+        expectedOrder('_h.js', ['i', 'a', 'h'], done)
+      });
+
+    });
+
+    //
+
+    describe('errors', function () {
+
+      function supposedToFail() {
+        expect(false, 'should not be successful').to.be.ok();
+      }
+
+      it('should throw if on syntax error', function (done) {
+        System.import('test/loads/main.js')
+          .then(supposedToFail)
+          .catch(function (e) {
+            expect(e)
+              .to.be.equal('Error evaluating ' + baseURL + 'test/loads/deperror.js\n\tdep error');
+          })
+          .then(done, done);
+      });
+
+      it('should throw what the script throws', function (done) {
+        System.import('test/loads/deperror.js')
+          .then(supposedToFail)
+          .catch(function(e) {
+            expect(e == 'dep error');
+          })
+          .then(done, done);
+      });
+
+
+      it('Unhandled rejection test', function (done) {
+        System.import('test/loads/load-non-existent.js')
+          .then(supposedToFail)
+          .catch(function (e) {
+            expect(typeof window != 'undefined' ? e.toString() : e.stack).to.be.match(/Error loading \S+/);
+          })
+          .then(done, done);
+      });
+
+    });
+
+    //
+
+    describe('es6 export syntax overview', function () {
+      it('should resolve different export syntax', function (done) {
+        System.import('test/syntax/export.js')
+          .then(function (m) {
+            expect(m.p, 'should export a number').to.be.equal(5);
+            expect(m.foo, 'should export a function').to.be.a('function');
+            expect(m.q, 'should export an object').to.be.an('object');
+            expect(m.default, 'should export a default function')
+              .to.be.a('function');
+            expect(m.s, 'should export a set of variable').to.be.equal(4);
+            expect(m.t, 'should export a specifier number').to.be.equal(4);
+            expect(m.m, 'should export a specifier object ').to.be.an('object');
+          })
+          .then(done, done);
+      });
+    });
+
+    describe('es6 export default syntax', function () {
+      it('should resolve "export default"', function (done) {
+        System.import('test/syntax/export-default.js')
+          .then(function (m) {
+            expect(m.default()).to.be.equal('test');
+          })
+          .then(done, done);
+      });
+    });
+
+    describe('es6 export re-exporting', function () {
+      it('should support simple re-exporting', function (done) {
+        System.import('test/syntax/reexport1.js')
+          .then(function (m) {
+            expect(m.p, 'should export 5 from the "./export"').to.be.equal(5);
+          })
+          .then(done, done);
+      });
+
+      it('should support re-exporting binding', function (done) {
+        System.import('test/syntax/reexport-binding.js')
+          .then(function () {
+            return System.import('test/syntax/rebinding.js').then(function (m) {
+              expect(m.p, 'should export "p" from the "./rebinding"')
+                .to.be.equal(4);
+            });
+          })
+          .then(done, done);
+      });
+
+      it('should support re-exporting with a new name', function (done) {
+        System.import('test/syntax/reexport2.js')
+          .then(function (m) {
+            expect(m.q, 'should export "t" as "q" from the "./export"')
+              .to.be.equal(4);
+            expect(m.z, 'should export "q" as "z" from the "./export"')
+              .to.be.equal(5);
+          })
+          .then(done, done);
+      });
+
+      it('should support re-exporting', function (done) {
+        System.import('test/syntax/export-star.js')
+          .then(function (m) {
+            expect(m.foo, 'should export a function').to.be.equal('foo');
+            expect(m.bar, 'should re-export export-star bar variable')
+              .to.be.equal('bar');
+          })
+          .then(done, done);
+      });
+
+      (System.transpiler != 'traceur' ? it.skip : it)('should support re-exporting overwriting', function (done) {
+        System.import('test/syntax/export-star2.js')
+          .then(function (m) {
+            expect(m.bar, 'should re-export "./export-star" bar variable')
+              .to.be.equal('bar');
+            expect(m.foo, 'should overwrite "./star-dep" foo variable with a function')
+              .to.be.a('function');
+          })
+          .then(done, done);
+      });
+    });
+
+    //
+
+    describe('es6 import syntax overview', function () {
+      it('should resolve different import syntax', function (done) {
+        System.import('test/syntax/import.js')
+          .then(function (m) {
+            expect(m.a, 'should export "d" as "a" from the "./export"')
+              .to.be.a('function');
+            expect(m.b, 'should export "p" as "b" for "s" as "p" from "./reexport1"')
+              .to.be.equal(4);
+            expect(m.c, 'should export "z" as "c" with "z" from "./reexport2"')
+              .to.be.equal(5);
+            expect(m.d, 'should export "r" as "d" for "q" as "r" from the "./reexport2"')
+              .to.be.equal(4);
+            expect(m.q, 'should export "q" as "*" from the "./reexport1"')
+              .to.be.an('object');
+            expect(m.q.foo, 'should access the "foo" function of "./reexport1" through "q" ad "*" ')
+              .to.be.a('function');
+          })
+          .then(done, done);
+      });
+    });
+
+    //
+
+    describe('a script with metas', function () {
+      it('should support module name meta', function (done) {
+        System.import('test/loader/moduleName.js')
+          .then(function (m) {
+            expect(m.name).to.be.equal(m.name);
+          })
+          .then(done, done);
+      });
+    });
+
+  });
+
+  describe('#paths', function () {
+
+    it('should support custom paths', function (done) {
+      System.paths['bar'] = baseURL + 'test/loader/custom-path.js';
+      System.import('bar')
+        .then(function (m) {
+          expect(m.bar).to.be.equal('bar');
+          delete System.paths['bar'];
+        })
+        .then(done, done);
+    });
+
+
+    it('should support path wildcard', function (done) {
+      System.paths['bar/*'] = baseURL + 'test/loader/custom-folder/*.js';
+      System.import('bar/path')
+        .then(function (m) {
+          expect(m.bar).to.be.equal('baa');
+          delete System.paths['bar/*'];
+        })
+        .then(done, done);
+    });
+
+    it('should support most specific paths', function (done) {
+      System.paths['bar/bar'] = baseURL + 'test/loader/specific-path.js';
+      System.paths['bar/*'] = baseURL + 'test/loader/custom-folder/*.js';
+      System.import('bar/bar')
+        .then(function (m) {
+          expect(m.path).to.be.ok();
+          delete System.paths['bar/bar'];
+          delete System.paths['bar/*'];
+        })
+        .then(done, done);
+    });
+
+  });
+
+  describe('#System.define', function () {
+
+    it.skip('should load System.define', function(done) {
+      var oldLocate = System.locate;
+      var slaveLocatePromise = new Promise(function(resolve, reject) {
+
+        System.locate = function(load) {
+          if(load.name === 'slave') {
+            setTimeout(function() {
+              System.define('slave', 'var double = [1,2,3].map(i => i * 2);');
+              resolve('slave.js');
+            }, 1);
+            return slaveLocatePromise;
+          }
+          return oldLocate.apply(this, arguments);
+        };
+
+      });
+
+      System.import('test/loader/master.js').then(function(m) {
+        done()
+      }, done).then(reset, reset);
+
+      function reset() {
+        System.locate = oldLocate;
+      }
+    });
+
+  });
+
+  describeIf(
+    typeof window != 'undefined' && window.Worker,
+    'with Web Worker', function () {
+      (ie ? it.skip : it)('should loading inside of a Web Worker', function (done) {
+        var worker = new Worker(baseURL + 'test/worker/worker-' + System.transpiler + '.js');
+
+        worker.onmessage = function (e) {
+          expect(e.data).to.be.equal('p');
+          done();
+        };
+
+      });
+
+    });
+
+  describeIf(
+    typeof window != 'undefined',
+    'with script type "module"', function () {
+      it('should load the module on the document "load" event', function (done) {
+        setTimeout(function(){ // wait for script processing first
+          expect(window.anon).to.be.a('function');
+          done();
+        }, 0);
+      });
+
+    });
+});
diff --git a/test/worker/es6.js b/test/worker/es6.js
new file mode 100644
index 0000000..edcd3c7
--- /dev/null
+++ b/test/worker/es6.js
@@ -0,0 +1 @@
+export var p = 'p';
diff --git a/test/worker/worker-babel.js b/test/worker/worker-babel.js
new file mode 100644
index 0000000..ae6c930
--- /dev/null
+++ b/test/worker/worker-babel.js
@@ -0,0 +1,12 @@
+importScripts("../../node_modules/when/es6-shim/Promise.js",
+             "../../dist/es6-module-loader-dev.src.js"
+             );
+
+System.transpiler = 'babel';
+System.paths['babel'] = '../../node_modules/babel-core/browser.js';
+
+System['import']('es6.js').then(function(m) {
+  postMessage(m.p);
+}, function(err) {
+  console.error(err, err.stack);
+});
\ No newline at end of file
diff --git a/test/worker/worker-traceur.js b/test/worker/worker-traceur.js
new file mode 100644
index 0000000..d8ff14b
--- /dev/null
+++ b/test/worker/worker-traceur.js
@@ -0,0 +1,8 @@
+importScripts("../../node_modules/when/es6-shim/Promise.js",
+             "../../dist/es6-module-loader-dev.src.js");
+System.paths['traceur'] = '../../node_modules/traceur/bin/traceur.js';
+System['import']('es6.js').then(function(m) {
+  postMessage(m.p);
+}, function(err) {
+  console.error(err, err.stack);
+});
diff --git a/test/worker/worker-typescript.js b/test/worker/worker-typescript.js
new file mode 100644
index 0000000..8a087b9
--- /dev/null
+++ b/test/worker/worker-typescript.js
@@ -0,0 +1,9 @@
+importScripts("../../node_modules/when/es6-shim/Promise.js",
+             "../../dist/es6-module-loader-dev.src.js",
+             "../../node_modules/typescript/lib/typescript.js");
+System.transpiler = 'typescript';
+System['import']('es6.js').then(function(m) {
+  postMessage(m.p);
+}, function(err) {
+  console.error(err, err.stack);
+});
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-es-module-loader-0.17.git



More information about the Pkg-javascript-commits mailing list