From 3df5de2449f14dad41d0fdf0ee281d176b0b141c Mon Sep 17 00:00:00 2001 From: guybedford Date: Wed, 1 Apr 2015 01:38:23 +0200 Subject: [PATCH 01/30] minimal loader build, first attempt --- Gruntfile.js | 73 ++--- package.json | 2 - src/declarative.js | 284 +++++++++++++++++ src/dynamic-only.js | 30 ++ src/loader.js | 306 +----------------- src/module-tag.js | 39 +++ src/polyfill-wrapper-end.js | 2 + src/polyfill-wrapper-start.js | 35 +-- src/register.js | 566 ++++++++++++++++++++++++++++++++++ src/system.js | 259 +++++++--------- src/transpiler.js | 14 +- 11 files changed, 1090 insertions(+), 520 deletions(-) create mode 100644 src/declarative.js create mode 100644 src/dynamic-only.js create mode 100644 src/module-tag.js create mode 100644 src/register.js diff --git a/Gruntfile.js b/Gruntfile.js index 3259e20..0d0b950 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -20,48 +20,43 @@ module.exports = function (grunt) { concat: { dist: { files: { + 'dist/<%= pkg.name %>-prod.src.js': [ + 'node_modules/when/es6-shim/Promise.js', + 'src/polyfill-wrapper-start.js', + 'src/loader.js', + 'src/dynamic-only.js', + 'src/system.js', + 'src/polyfill-wrapper-end.js' + ], + 'dist/<%= pkg.name %>-prod-sans-promises.src.js': [ + 'src/polyfill-wrapper-start.js', + 'src/loader.js', + 'src/dynamic-only.js', + 'src/system.js', + 'src/polyfill-wrapper-end.js' + ], 'dist/<%= pkg.name %>.src.js': [ 'node_modules/when/es6-shim/Promise.js', 'src/polyfill-wrapper-start.js', - 'dist/<%= pkg.name %>.js', + 'src/loader.js', + 'src/declarative.js', + 'src/transpiler.js', + 'src/system.js', + 'src/module-tag.js', 'src/polyfill-wrapper-end.js' ], 'dist/<%= pkg.name %>-sans-promises.src.js': [ 'src/polyfill-wrapper-start.js', - 'dist/<%= pkg.name %>.js', + 'src/loader.js', + 'src/declarative.js', + 'src/transpiler.js', + 'src/system.js', + 'src/module-tag.js', 'src/polyfill-wrapper-end.js' ] } } }, - esnext: { - dist: { - src: [ - 'src/loader.js', - 'src/transpiler.js', - 'src/system.js' - ], - dest: 'dist/<%= pkg.name %>.js' - } - }, - 'string-replace': { - dist: { - files: { - 'dist/<%= pkg.name %>.js': 'dist/<%= pkg.name %>.js' - }, - options: { - replacements:[{ - pattern: 'var $__Object$getPrototypeOf = Object.getPrototypeOf;\n' + - 'var $__Object$defineProperty = Object.defineProperty;\n' + - 'var $__Object$create = Object.create;', - replacement: '' - }, { - pattern: '$__Object$getPrototypeOf(SystemLoader.prototype).constructor', - replacement: '$__super' - }] - } - } - }, uglify: { options: { banner: '<%= meta.banner %>\n', @@ -80,18 +75,26 @@ module.exports = function (grunt) { distSansPromises: { src: 'dist/<%= pkg.name %>-sans-promises.src.js', dest: 'dist/<%= pkg.name %>-sans-promises.js' + }, + prodDist: { + options: { + banner: '<%= meta.banner %>\n' + }, + src: 'dist/<%= pkg.name %>-prod.src.js', + dest: 'dist/<%= pkg.name %>-prod.js' + }, + prodDistSansPromises: { + src: 'dist/<%= pkg.name %>-prod-sans-promises.src.js', + dest: 'dist/<%= pkg.name %>-prod-sans-promises.js' } } }); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-esnext'); grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-string-replace'); grunt.registerTask('lint', ['jshint']); - grunt.registerTask('compile', ['esnext', 'string-replace', 'concat']); - grunt.registerTask('default', [/*'jshint', */'esnext', 'string-replace', - 'concat', 'uglify']); + grunt.registerTask('compile', ['concat']); + grunt.registerTask('default', [/*'jshint', */'concat', 'uglify']); }; diff --git a/package.json b/package.json index 044e09c..5c047e2 100644 --- a/package.json +++ b/package.json @@ -29,8 +29,6 @@ "grunt-contrib-concat": "^0.5.0", "grunt-contrib-jshint": "~0.6.0", "grunt-contrib-uglify": "~0.6.0", - "grunt-esnext": "0.0.3", - "grunt-string-replace": "^0.2.7", "karma": "^0.12.28", "karma-benchmark": "^0.4.0", "karma-benchmark-reporter": "^0.1.1", diff --git a/src/declarative.js b/src/declarative.js new file mode 100644 index 0000000..c4d3025 --- /dev/null +++ b/src/declarative.js @@ -0,0 +1,284 @@ +/* + * 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; + moduleObj[name] = value; + + for (var i = 0, l = module.importers.length; i < l; i++) { + var importerModule = module.importers[i]; + if (!importerModule.locked) { + var importerIndex = indexOf.call(importerModule.dependencies, module); + importerModule.setters[importerIndex](moduleObj); + } + } + + module.locked = false; + return value; + }); + + // 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 + '\n'); + 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; + } \ No newline at end of file diff --git a/src/dynamic-only.js b/src/dynamic-only.js new file mode 100644 index 0000000..2945df8 --- /dev/null +++ b/src/dynamic-only.js @@ -0,0 +1,30 @@ +/* + * Dynamic-only Linking Code + */ + + // 15.2.5.4 + // dynamic-only linking implementation + function link(linkSet, linkError) { + + var loader = linkSet.loader; + + if (!linkSet.loads.length) + return; + + for (var i = 0; i < linkSet.loads.length; i++) { + var load = linkSet.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) { + return load.module.module; + } \ No newline at end of file diff --git a/src/loader.js b/src/loader.js index 11ee8dc..922c3ad 100644 --- a/src/loader.js +++ b/src/loader.js @@ -100,9 +100,6 @@ function logloads(loads) { } } } */ - - -(function() { var Promise = __global.Promise || require('when/es6-shim/Promise'); if (__global.console) console.assert = console.assert || function() {}; @@ -116,7 +113,22 @@ function logloads(loads) { } return -1; }; - var defineProperty = $__Object$defineProperty; + + 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) {} + } + } + })(); // 15.2.3 - Runtime Semantics: Loader State @@ -246,7 +258,7 @@ function logloads(loads) { // instead of load.kind, use load.isDeclarative load.isDeclarative = true; - return loader.loaderObj.transpile(load) + return transpile.call(loader.loaderObj, load) .then(function(transpiled) { // Hijack System.register to set declare function var curSystem = __global.System; @@ -575,58 +587,6 @@ function logloads(loads) { load.linkSets.splice(0, load.linkSets.length); } - // 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); - } - } - } - } - function doDynamicExecute(linkSet, load, linkError) { try { var module = load.execute(); @@ -641,236 +601,6 @@ function logloads(loads) { return module; } - // 15.2.5.4 - 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; - moduleObj[name] = value; - - for (var i = 0, l = module.importers.length; i < l; i++) { - var importerModule = module.importers[i]; - if (!importerModule.locked) { - var importerIndex = indexOf.call(importerModule.dependencies, module); - importerModule.setters[importerIndex](moduleObj); - } - } - - module.locked = false; - return value; - }); - - // 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'; - } - - - - // 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; - } - - /* - * 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; - } - } - - // 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 + '\n'); - 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; - } - function addToError(err, msg) { if (err instanceof Error) err.message = msg + err.message; @@ -1087,5 +817,3 @@ function logloads(loads) { __global.Reflect.global = __global.Reflect.global || __global; __global.LoaderPolyfill = Loader; -})(); - diff --git a/src/module-tag.js b/src/module-tag.js new file mode 100644 index 0000000..a5a4013 --- /dev/null +++ b/src/module-tag.js @@ -0,0 +1,39 @@ + // - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/test/test-traceur.html b/test/test-traceur.html deleted file mode 100644 index ba51137..0000000 --- a/test/test-traceur.html +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/test.js b/test/test.js deleted file mode 100644 index b477cee..0000000 --- a/test/test.js +++ /dev/null @@ -1,647 +0,0 @@ - -var System, Loader, Module, tests, test; - -var testCnt = 0, passed = 0, failed = 0; -var test = function(name, initialize) { - if (typeof initialize != 'function') { - var val = initialize; - var exp = arguments[2]; - initialize = function(assert) { - assert(val, exp); - } - } - var testId = testCnt++; - tests.addTest(testId, name); - function assert(value, expected) { - if (value != expected) - return 'Got "' + value + '" instead of "' + expected + '"'; - } - initialize(function(value, expected) { - var failure; - if (value instanceof Array) { - for (var i = 0; i < arguments.length; i++) - failure = failure || assert(arguments[i][0], arguments[i][1]); - } - else - failure = assert(value, expected); - if (failure) - failed++; - else - passed++; - tests.completeTest(testId, name, failure, { passed: passed, failed: failed, total: testCnt }); - }, function(err) { - setTimeout(function() { - throw err; - }); - }); -} - -if (typeof window != 'undefined') { - // browser - document.body.innerHTML = "
Summary
"; - tests = { - addTest: function(id, name) { - var p = document.createElement('tr'); - var td = document.createElement('td'); - td.innerHTML = name; - p.appendChild(td); - td = document.createElement('td'); - td.className = 'result-' + id; - p.appendChild(td); - document.querySelector('.test tbody').appendChild(p); - }, - completeTest: function(id, name, failure, summary) { - document.querySelector('.test .result-' + id).innerHTML = !failure ? 'Passed' : 'Failed: ' + failure; - document.querySelector('.summary').innerHTML = summary.passed + '/' + summary.total + ' tests passed'; - } - } - window.test = test; - window.runTests = runTests; -} -else { - // nodejs - var ml = require('../lib/index-' + process.env.es6compiler); - - if (process.env.es6compiler == '6to5') - require('regenerator/runtime'); - - process.on('uncaughtException', function(err) { - console.log('Caught: ' + err); - }); - - System = ml.System; - Loader = ml.Loader; - Module = ml.Module; - - tests = { - addTest: function(id, name) {}, - completeTest: function(id, name, failure, summary) { - console.log(name + ': ' + (!failure ? 'Passed' : 'Failed: ' + failure)); - console.log(summary.passed + '/' + summary.total + ' passed. '); - if (failure) - process.exit(1); - }, - }; - - runTests(); -} - -function runTests() { - - // Normalize tests - identical to https://github.com/google/traceur-compiler/blob/master/test/unit/runtime/System.js - - var oldBaseURL = System.baseURL; - System.baseURL = 'http://example.org/a/b.html'; - - test('Normalize - No Referer', System.normalize('d/e/f'), 'd/e/f'); - // test('Normalize - Below baseURL', System.normalize('../e/f'), '../e/f'); - - var refererName = 'dir/file'; - test('Normalize - Relative paths', System.normalize('./d/e/f', refererName), 'dir/d/e/f'); - test('Normalize - Relative paths', System.normalize('../e/f', refererName), 'e/f'); - - test('Normalize - name undefined', function(assert) { - try { - System.normalize(undefined, refererName); - } - catch(e) { - assert(e.message, 'Module name must be a string'); - } - }); - - // test('Normalize - below referer', System.normalize('../../e/f', refererName), '../e/f'); - - test('Normalize - backwards compat', System.normalize('./a.js'), 'a.js'); - - test('Normalize - URL', function(assert) { - assert(System.normalize('http://example.org/a/b.html'), 'http://example.org/a/b.html'); - }); - - System.baseURL = 'http://example.org/a/'; - - test('Locate', System.locate({ name: '@abc/def' }), 'http://example.org/a/@abc/def'); - test('Locate', System.locate({ name: 'abc/def' }), 'http://example.org/a/abc/def'); - - // paths - System.paths['path/*'] = '/test/*.js'; - test('Locate paths', System.locate({ name: 'path/test' }), 'http://example.org/test/test.js'); - - - System.baseURL = oldBaseURL; - - - - // More Normalize tests - - test('Normalize test 1', function(assert) { - assert(System.normalize('./a/b', 'c'), 'a/b'); - }); - test('Normalize test 2', function(assert) { - assert(System.normalize('./a/b', 'c/d'), 'c/a/b'); - }); - test('Normalize test 3', function(assert) { - assert(System.normalize('./a/b', '../c/d'), '../c/a/b'); - }); - test('Normalize test 4', function(assert) { - assert(System.normalize('./a/b', '../c/d'), '../c/a/b'); - }); - test('Normalize test 5', function(assert) { - assert(System.normalize('../a/b', '../../c/d'), '../../a/b'); - }); - - test('Setting & deleting modules', function(assert, err) { - System['import']('loader/module.js').then(function(m1) { - System['delete']('loader/module.js'); - System['import']('loader/module.js').then(function(m2) { - System['delete']('loader/module.js'); - System.set('loader/module.js', System.newModule({custom: 'module'})); - System['import']('loader/module.js').then(function(m3) { - assert( - [m1.run, 'first'], - [m2.run, 'second'], - [m3.custom, 'module'] - ); - }, err); - }, err); - }, err); - }); - - test('Import a script', function(assert, err) { - System['import']('syntax/script.js').then(function(m) { - assert(!!m, true); - }, err); - }); - - test('Import a script once loaded', function(assert, err) { - System['import']('syntax/script.js').then(function(m) { - System['import']('syntax/script.js').then(function(m) { - assert(!!m, true); - }, err); - }); - }); - - test('Import ES6', function(assert, err) { - System['import']('syntax/es6.js').then(function(m) { - assert(m.p, 'p'); - }, err); - }); - - test('Import ES6 with dep', function(assert, err) { - System['import']('syntax/es6-withdep.js').then(function(m) { - assert(m.p, 'p'); - }, err); - }); - - test('Import ES6 Generator', function(assert, err) { - System['import']('syntax/es6-generator.js').then(function(m) { - assert(!!m.generator, true); - }, err); - }); - - test('Direct import without bindings', function(assert, err) { - System['import']('syntax/direct.js').then(function(m) { - assert(!!m, true); - }, err); - }); - - test('Circular Dependencies', function(assert, err) { - System['import']('syntax/circular1.js').then(function(m1) { - System['import']('syntax/circular2.js').then(function(m2) { - assert( - [m2.output, 'test circular 1'], - [m1.output, 'test circular 2'], - [m2.output1, 'test circular 2'], - [m1.output2, 'test circular 1'] - ); - }, err); - }, err); - }); - - test('Circular Test', function(assert, err) { - System['import']('syntax/even.js').then(function(m) { - assert( - [m.even(10), true], - [m.counter, 7], - [m.even(15), false], - [m.counter, 15] - ); - }, err); - }); - - test('Load order test: A', function(assert, err) { - System['import']('loads/a.js').then(function(m) { - assert( - [m.a, 'a'], - [m.b, 'b'] - ); - }, err); - }); - - test('Load order test: C', function(assert, err) { - System['import']('loads/c.js').then(function(m) { - assert( - [m.c, 'c'], - [m.a, 'a'], - [m.b, 'b'] - ); - }, err); - }); - - test('Load order test: S', function(assert, err) { - System['import']('loads/s.js').then(function(m) { - assert( - [m.s, 's'], - [m.c, 'c'], - [m.a, 'a'], - [m.b, 'b'] - ); - }, err); - }); - - test('Load order test: _a', function(assert) { - System['import']('loads/_a.js').then(function(m) { - assert( - [m.b, 'b'], - [m.d, 'd'], - [m.g, 'g'], - [m.a, 'a'] - ); - }) - }); - - test('Load order test: _e', function(assert) { - System['import']('loads/_e.js').then(function(m) { - assert( - [m.c, 'c'], - [m.e, 'e'] - ); - }) - }); - - test('Load order test: _f', function(assert) { - System['import']('loads/_f.js').then(function(m) { - assert( - [m.g, 'g'], - [m.f, 'f'] - ); - }) - }); - test('Load order test: _h', function(assert) { - System['import']('loads/_h.js').then(function(m) { - assert( - [m.i, 'i'], - [m.a, 'a'], - [m.h, 'h'] - ); - }) - }); - - test('Error check 1', function(assert) { - System['import']('loads/main.js').then(function(m) { - assert(false, true); - }, function(e) { - assert(e, 'dep error\n\tError evaluating loads/deperror.js'); - }); - // System['import']('loads/deperror'); - }); - - test('Unhandled rejection test', function(assert) { - System['import']('loads/load-non-existent') - assert(); - }); - - - test('Export Syntax', function(assert) { - System['import']('syntax/export.js').then(function(m) { - assert( - [m.p, 5], - [typeof m.foo, 'function'], - [typeof m.q, 'object'], - [typeof m['default'], 'function'], - [m.s, 4], - [m.t, 4], - [typeof m.m, 'object'] - ); - }); - }); - - // test not enabled for Babel - if (System.transpiler != 'babel') - test('Export Star 2', function(assert) { - System['import']('syntax/export-star2.js').then(function(m) { - assert( - [typeof m.foo, 'function'], - [m.bar, 'bar'] - ); - }); - }); - - test('Export Star', function(assert) { - System['import']('syntax/export-star.js').then(function(m) { - assert( - [m.foo, 'foo'], - [m.bar, 'bar'] - ); - }); - }); - - test('Export default 1', function(assert, err) { - System['import']('syntax/export-default.js').then(function(m) { - assert(m['default'](), 'test'); - }, err); - }); - - test('Re-export', function(assert, err) { - System['import']('syntax/reexport1.js').then(function(m) { - assert(m.p, 5); - }, err); - }); - - test('Re-export with new name', function(assert, err) { - System['import']('syntax/reexport2.js').then(function(m) { - assert( - [m.q, 4], - [m.z, 5] - ); - }, err); - }); - - test('Re-export binding', function(assert, err) { - System['import']('syntax/reexport-binding.js').then(function(m) { - System['import']('syntax/rebinding.js').then(function(m) { - assert(m.p, 4); - }); - }, err); - }); - - test('Import Syntax', function(assert, err) { - System['import']('syntax/import.js').then(function(m) { - assert( - [typeof m.a, 'function'], - [m.b, 4], - [m.c, 5], - [m.d, 4], - [typeof m.q.foo, 'function'] - ); - }, err); - }); - - test('ES6 Syntax', function(assert, err) { - System['import']('syntax/es6-file.js').then(function(m) { - setTimeout(function() { - (new m.q()).foo(); - }); - assert( - [typeof m.q, 'function'] - ); - }, err); - }); - - test('Module Name meta', function(assert) { - System['import']('loader/moduleName.js').then(function(m) { - assert( - [m.name, 'loader/moduleName.js'], - [m.address, System.baseURL + 'loader/moduleName.js'] - ); - }); - }); - - test('Custom path', function(assert) { - System.paths['bar'] = 'loader/custom-path.js'; - System['import']('bar').then(function(m) { - assert(m.bar, 'bar'); - }) - }); - - test('Custom path wildcard', function(assert) { - System.paths['bar/*'] = 'loader/custom-folder/*.js'; - System['import']('bar/path').then(function(m) { - assert(m.bar, 'baa'); - }); - }); - - test('Custom path most specific', function(assert) { - delete System.paths['bar/*']; - System.paths['bar/bar'] = 'loader/specific-path.js'; - System.paths['bar/*'] = 'loader/custom-folder/*.js'; - System['import']('bar/bar').then(function(m) { - assert(m.path, true); - }); - }); - - test('should load System.define', function(assert) { - 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('loader/master.js').then(function() { - assert(true, true, 'Able to load'); - }, function(err) { - assert('Did not resolve'); - }).then(reset, reset); - - function reset() { - System.locate = oldLocate; - } - }); - - var customModules = {}; - var customFactories = {}; - - var executeModule = function(name) { - if (!customFactories[name]) - return; - var module = customFactories[name].apply(null, []); - customModules[name] = module; - return module; - } - - var customLoader = new Reflect.Loader({ - normalize: function(name, parentName, parentAddress) { - return new Promise(function(resolve, reject) { - if (name == 'asdfasdf') { - return setTimeout(function() { - resolve('loader/async-norm.js'); - }, 500); - } - - if (name == 'error1') - return setTimeout(function(){ reject('error1'); }, 100); - - var normalized = System.normalize(name, parentName, parentAddress); - resolve(normalized); - }); - }, - locate: function(load) { - if (load.name == 'error2') - return new Promise(function(resolve, reject) { - setTimeout(function(){ reject('error2'); }, 100); - }); - - if (load.name.substr(0, 5) == 'path/') - load.name = 'loader/' + load.name.substr(5); - return System.locate(load); - }, - fetch: function(load) { - if (load.name == 'error3') - throw 'error3'; - if (load.name == 'error4' || load.name == 'error5') - return 'asdf'; - return System.fetch.apply(this, arguments); - }, - translate: function(load) { - if (load.name == 'error4') - return new Promise(function(resolve, reject) { - setTimeout(function(){ reject('error4'); }, 100); - }); - return System.translate.apply(this, arguments); - }, - instantiate: function(load) { - if (load.name == this.transpiler) { - var transpiler = this.transpiler; - return System.import(transpiler).then(function() { - return { - deps: [], - execute: function() { - return System.get(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; - } - //console.log(load.source); - 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))); - - 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); - } - }; - }); - } - }); - customLoader.transpiler = System.transpiler; - - test('Custom loader standard load', function(assert) { - var p = customLoader['import']('loader/test.js').then(function(m) { - assert(m.loader, 'custom'); - }); - if (p['catch']) - p['catch'](function(e) { - assert(!e, 'standard load failed: ' + e); - }); - }); - - test('Custom loader special rules', function(assert) { - var p = customLoader['import']('path/custom.js').then(function(m) { - assert(m.path, true); - }); - if (p['catch']) - p['catch'](function(e) { - assert(!e, 'special rules failed: ' + e); - }); - }); - - test('Custom loader AMD support', function(assert) { - customLoader['import']('loader/amd.js').then(function(m) { - assert(m.format, 'amd'); - })['catch'](function(e) { - setTimeout(function() { - throw e; - }, 1); - }); - }); - - test('Custom loader hook - normalize error', function(assert) { - customLoader['import']('loader/error1-parent.js').then(function(m) { - })['catch'](function(e) { - assert(e.toString(), 'error1\n\tError loading "loader/error1-parent.js" at ' + System.baseURL + 'loader/error1-parent.js'); - }); - }); - test('Custom loader hook - locate error', function(assert) { - customLoader['import']('error2').then(function(m) {}, function(e) { - assert(e.toString(), 'error2\n\tError loading "error2" at '); - }); - }); - test('Custom loader hook - fetch error', function(assert) { - customLoader['import']('error3').then(function(m) {}, function(e) { - assert(e.toString(), 'error3\n\tError loading "error3" at ' + System.baseURL + 'error3'); - }); - }); - test('Custom loader hook - translate error', function(assert) { - customLoader['import']('error4').then(function(m) {}, function(e) { - assert(e.toString(), 'error4\n\tError loading "error4" at ' + System.baseURL + 'error4'); - }); - }); - test('Custom loader hook - instantiate error', function(assert) { - customLoader['import']('error5').then(function(m) {}, function(e) { - assert(e.toString(), 'error5\n\tError loading "error5" at ' + System.baseURL + 'error5'); - }); - }); - - test('Async Normalize', function(assert) { - customLoader.normalize('asdfasdf').then(function(normalized) { - return customLoader['import'](normalized); - }).then(function(m) { - assert(m.n, 'n'); - }); - }); - - test('System instanceof Loader', function(assert) { - assert(System instanceof Reflect.Loader, true); - }); - - if (typeof Worker != 'undefined') - test('Loading inside of a Web Worker', function(assert) { - var worker = new Worker('worker/worker-' + System.transpiler + '.js'); - - worker.onmessage = function(e) { - assert(e.data, 'p'); - }; - }); -} From 58c50ea223e5cead8f849b32767e9bc5f8d2d327 Mon Sep 17 00:00:00 2001 From: guybedford Date: Wed, 6 May 2015 23:42:38 +0200 Subject: [PATCH 27/30] separate fetch implementation --- Gruntfile.js | 2 + src/system-fetch.js | 77 +++++++++++++++++++++++++++++++++++++++ src/system.js | 89 ++------------------------------------------- 3 files changed, 83 insertions(+), 85 deletions(-) create mode 100644 src/system-fetch.js diff --git a/Gruntfile.js b/Gruntfile.js index f0652cd..d95f402 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -28,6 +28,7 @@ module.exports = function (grunt) { 'src/url-polyfill.js', 'src/system.js', 'src/system-resolve.js', + 'src/system-fetch.js', 'src/wrapper-end.js' ], 'dist/<%= pkg.name %>-dev.src.js': [ @@ -39,6 +40,7 @@ module.exports = function (grunt) { 'src/url-polyfill.js', 'src/system.js', 'src/system-resolve.js', + 'src/system-fetch.js', 'src/module-tag.js', 'src/wrapper-end.js' ] diff --git a/src/system-fetch.js b/src/system-fetch.js new file mode 100644 index 0000000..ea70b34 --- /dev/null +++ b/src/system-fetch.js @@ -0,0 +1,77 @@ + var fetchTextFromURL; + if (typeof XMLHttpRequest != 'undefined') { + fetchTextFromURL = function(url, 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(xhr.statusText + ': ' + url || 'XHR error'); + } + + xhr.onreadystatechange = function () { + if (xhr.readyState === 4) { + if (xhr.status === 200 || (xhr.status == 0 && xhr.responseText)) { + load(); + } else { + error(); + } + } + }; + xhr.open("GET", url, true); + + if (doTimeout) + setTimeout(function() { + xhr.send(); + }, 0); + + xhr.send(null); + }; + } + else if (typeof require != 'undefined') { + var fs; + fetchTextFromURL = function(url, fulfill, reject) { + if (url.substr(0, 8) != 'file:///') + throw '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 + fulfill(data + ''); + }); + }; + } + else { + throw new TypeError('No environment fetch API available.'); + } + + SystemLoader.prototype.fetch = function(load) { + return new Promise(function(resolve, reject) { + fetchTextFromURL(load.address, resolve, reject); + }); + }; \ No newline at end of file diff --git a/src/system.js b/src/system.js index 3611eae..76a3ce5 100644 --- a/src/system.js +++ b/src/system.js @@ -83,88 +83,7 @@ function applyPaths(loader, name) { return outPath; } -(function() { - var fetchTextFromURL; - if (typeof XMLHttpRequest != 'undefined') { - fetchTextFromURL = function(url, 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(xhr.statusText + ': ' + url || 'XHR error'); - } - - xhr.onreadystatechange = function () { - if (xhr.readyState === 4) { - if (xhr.status === 200 || (xhr.status == 0 && xhr.responseText)) { - load(); - } else { - error(); - } - } - }; - xhr.open("GET", url, true); - - if (doTimeout) - setTimeout(function() { - xhr.send(); - }, 0); - - xhr.send(null); - }; - } - else if (typeof require != 'undefined') { - var fs; - fetchTextFromURL = function(url, fulfill, reject) { - if (url.substr(0, 8) != 'file:///') - throw '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 - fulfill(data + ''); - }); - }; - } - else { - throw new TypeError('No environment fetch API available.'); - } - - // inline Object.create-style class extension - function LoaderProto() {} - LoaderProto.prototype = Loader.prototype; - SystemLoader.prototype = new LoaderProto(); - - SystemLoader.prototype.fetch = function(load) { - return new Promise(function(resolve, reject) { - fetchTextFromURL(load.address, resolve, reject); - }); - }; - -})(); +// inline Object.create-style class extension +function LoaderProto() {} +LoaderProto.prototype = Loader.prototype; +SystemLoader.prototype = new LoaderProto(); From a0ee0f4f8c7e50843a2fcabe0fc5e3a6508e0875 Mon Sep 17 00:00:00 2001 From: guybedford Date: Tue, 12 May 2015 01:19:14 +0200 Subject: [PATCH 28/30] Windows Node paths fix --- index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/index.js b/index.js index ff4ba3e..694c26a 100644 --- a/index.js +++ b/index.js @@ -3,16 +3,18 @@ if (typeof Promise === 'undefined') var System = require('./dist/es6-module-loader-dev.src'); +var filePrefix = 'file:' + (process.platform.match(/^win/) ? '/' : '') + '//'; + try { - System.paths.traceur = 'file:' + require.resolve('traceur/bin/traceur.js'); + System.paths.traceur = filePrefix + require.resolve('traceur/bin/traceur.js'); } catch(e) {} try { - System.paths.babel = 'file:' + require.resolve('babel-core/browser.js'); + System.paths.babel = filePrefix + require.resolve('babel-core/browser.js'); } catch(e) {} try { - System.paths.babel = System.paths.babel || 'file:' + require.resolve('babel/browser.js'); + System.paths.babel = System.paths.babel || filePrefix + require.resolve('babel/browser.js'); } catch(e) {} From 80c21191f8f3fb383abb86df0b72a658695e3cae Mon Sep 17 00:00:00 2001 From: guybedford Date: Fri, 15 May 2015 16:00:14 +0200 Subject: [PATCH 29/30] polyfill handling --- Gruntfile.js | 2 -- src/url-polyfill.js | 7 ++++--- src/wrapper-end.js | 2 +- src/wrapper-start.js | 2 ++ test/system.normalize.spec.js | 6 +++--- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index d95f402..df1d3bc 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -21,7 +21,6 @@ module.exports = function (grunt) { dist: { files: { 'dist/<%= pkg.name %>.src.js': [ - 'node_modules/when/es6-shim/Promise.js', 'src/wrapper-start.js', 'src/loader.js', 'src/dynamic-only.js', @@ -32,7 +31,6 @@ module.exports = function (grunt) { 'src/wrapper-end.js' ], 'dist/<%= pkg.name %>-dev.src.js': [ - 'node_modules/when/es6-shim/Promise.js', 'src/wrapper-start.js', 'src/loader.js', 'src/declarative.js', diff --git a/src/url-polyfill.js b/src/url-polyfill.js index 987b7c0..207f350 100644 --- a/src/url-polyfill.js +++ b/src/url-polyfill.js @@ -1,5 +1,5 @@ // from https://gist.github.com/Yaffle/1088850 -function URL(url, baseURL) { +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]*)?/); @@ -16,7 +16,7 @@ function URL(url, baseURL) { var search = m[8] || ""; var hash = m[9] || ""; if (baseURL !== undefined) { - var base = baseURL instanceof URL ? baseURL : new URL(baseURL); + var base = baseURL instanceof URLPolyfill ? baseURL : new URLPolyfill(baseURL); var flag = protocol === "" && host === "" && username === ""; if (flag && pathname === "" && search === "") { search = base.search; @@ -64,4 +64,5 @@ function URL(url, baseURL) { this.pathname = pathname; this.search = search; this.hash = hash; -} \ No newline at end of file +} +(typeof self != 'undefined' ? self : global).URLPolyfill = URLPolyfill; \ No newline at end of file diff --git a/src/wrapper-end.js b/src/wrapper-end.js index 4a0340a..b4d01a6 100644 --- a/src/wrapper-end.js +++ b/src/wrapper-end.js @@ -18,4 +18,4 @@ __global.System = System; -})(typeof window != 'undefined' ? window : (typeof global != 'undefined' ? global : self)); \ No newline at end of file +})(typeof self != 'undefined' ? self : global); \ No newline at end of file diff --git a/src/wrapper-start.js b/src/wrapper-start.js index 1bdae68..0ac6978 100644 --- a/src/wrapper-start.js +++ b/src/wrapper-start.js @@ -55,3 +55,5 @@ throw addToError(e, 'Evaluating ' + debugName); } } + + var URL = __global.URL || URLPolyfill; diff --git a/test/system.normalize.spec.js b/test/system.normalize.spec.js index 7707240..ebfebaa 100644 --- a/test/system.normalize.spec.js +++ b/test/system.normalize.spec.js @@ -47,11 +47,11 @@ describe('System', function () { describe('when having two arguments', function () { - var refererAddress = '/dir/file'; + var refererAddress = 'http://parent.com/dir/file'; it('should normalize relative paths against the parent address', function () { - expect(System.normalize('./d/e/f', null, refererAddress)).to.equal('/dir/d/e/f'); - expect(System.normalize('../e/f', null, refererAddress)).to.equal('/e/f'); + expect(System.normalize('./d/e/f', null, refererAddress)).to.equal('http://parent.com/dir/d/e/f'); + expect(System.normalize('../e/f', null, refererAddress)).to.equal('http://parent.com/e/f'); }); }); From 6524a6d0e227dfff4be17b93617663a26bb6cd3f Mon Sep 17 00:00:00 2001 From: guybedford Date: Sat, 16 May 2015 13:22:50 +0200 Subject: [PATCH 30/30] make baseURL a loader constructor option --- src/loader.js | 13 --- src/system.js | 30 +------ src/wrapper-start.js | 27 ++++++ test/custom-loader.js | 199 +++++++++++++++++++++++------------------- 4 files changed, 137 insertions(+), 132 deletions(-) diff --git a/src/loader.js b/src/loader.js index d5dee93..3600264 100644 --- a/src/loader.js +++ b/src/loader.js @@ -20,19 +20,6 @@ function Module() {} function Loader(options) { - options = options || {}; - - if (options.normalize) - this.normalize = options.normalize; - if (options.locate) - this.locate = options.locate; - if (options.fetch) - this.fetch = options.fetch; - if (options.translate) - this.translate = options.translate; - if (options.instantiate) - this.instantiate = options.instantiate; - this._loader = { loaderObj: this, loads: [], diff --git a/src/system.js b/src/system.js index 76a3ce5..caf0305 100644 --- a/src/system.js +++ b/src/system.js @@ -12,34 +12,10 @@ var System; -function SystemLoader(options) { - Loader.call(this, options || {}); +function SystemLoader(baseURL) { + Loader.call(this); - var baseURL; - // Set default baseURL and paths - if (typeof document != 'undefined' && document.getElementsByTagName) { - baseURL = document.baseURI; - - if (!baseURL) { - var bases = document.getElementsByTagName('base'); - baseURL = bases[0] && bases[0].href || window.location.href; - } - - // sanitize out the hash and querystring - baseURL = baseURL.split('#')[0].split('?')[0]; - baseURL = baseURL.substr(0, baseURL.lastIndexOf('/') + 1); - } - else if (typeof process != 'undefined' && process.cwd) { - baseURL = 'file://' + (isWindows ? '/' : '') + process.cwd() + '/'; - if (isWindows) - baseURL = baseURL.replace(/\\/g, '/'); - } - else if (typeof location != 'undefined') { - baseURL = __global.location.href; - } - else { - throw new TypeError('No environment baseURL'); - } + baseURL = baseURL || baseURI; this.baseURL = baseURL; this.paths = {}; diff --git a/src/wrapper-start.js b/src/wrapper-start.js index 0ac6978..6192471 100644 --- a/src/wrapper-start.js +++ b/src/wrapper-start.js @@ -57,3 +57,30 @@ } var URL = __global.URL || URLPolyfill; + + 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'); + } diff --git a/test/custom-loader.js b/test/custom-loader.js index 9121e05..c464a38 100644 --- a/test/custom-loader.js +++ b/test/custom-loader.js @@ -15,114 +15,129 @@ return module; }; - var customLoader = new Reflect.Loader({ - normalize: function (name, parentName, parentAddress) { - return new Promise(function(resolve, reject) { - if (name == 'asdfasdf') { - return setTimeout(function () { - resolve('test/loader/async-norm.js'); - }, 500); - } + 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); - } + if (name == 'error1') { + return setTimeout(function () { reject('error1'); }, 100); + } + + var normalized = System.normalize(name, parentName, parentAddress); + resolve(normalized); + }); + }; - 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); }); - }, - 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/'); + if (load.name.match(/path\//)) + load.name = load.name.replace(/path\//, 'test/loader/'); - return System.locate(load); - }, - fetch: function (load) { - if (load.name == 'error3') { - throw 'error3'; - } - if (load.name == 'error4' || load.name == 'error5') { - return 'asdf'; - } - return System.fetch.apply(this, arguments); - }, - translate: function (load) { - if (load.name == 'error4') { - return new Promise(function (resolve, reject) { - setTimeout(function () { reject('error4'); }, 100); - }); - } - return System.translate.apply(this, arguments); - }, - 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)); - } - }; - }); - } + return System.locate(load); + }; - 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); - } + + 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); + }; - var factory, deps; - var define = function (_deps, _factory) { - deps = _deps; - factory = _factory; - }; - eval(load.source); + 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); + }; - customFactories[load.name] = factory; + 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)); + } + }; + }); + } - // 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))); - } + 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); + } - return Promise.all(normalizePromises).then(function (resolvedDeps) { + var factory, deps; + var define = function (_deps, _factory) { + deps = _deps; + factory = _factory; + }; + eval(load.source); - return { - deps: deps, - execute: function () { - if (customModules[load.name]) { - return System.newModule(customModules[load.name]); - } + customFactories[load.name] = factory; - // first ensure all dependencies have been executed - for (var i = 0; i < resolvedDeps.length; i++) { - resolvedDeps[i] = executeModule(resolvedDeps[i]); - } + // 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))); + } - var module = factory.apply(null, resolvedDeps); + return Promise.all(normalizePromises).then(function (resolvedDeps) { - customModules[load.name] = module; - return System.newModule(module); + 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;