[Pkg-javascript-commits] [es-module-loader-0.17.js] 01/05: Import Upstream version 0.17.11+dfsg
Tim Potter
tpot at hpe.com
Thu Oct 13 00:27:46 UTC 2016
This is an automated email from the git hooks/post-receive script.
tpot-guest pushed a commit to branch master
in repository es-module-loader-0.17.js.
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/es-module-loader-0.17.js.git
More information about the Pkg-javascript-commits
mailing list