blob: 1902d3879fa78162703c9a756ae39d6b368d17aa [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
/* This file defines the module loader for the dart runtime.
*/
var dart_library;
if (!dart_library) {
dart_library =
typeof module != "undefined" && module.exports || {};
(function (dart_library) {
'use strict';
/** Note that we cannot use dart_utils.throwInternalError from here. */
function throwLibraryError(message) {
// Dispatch event to allow others to react to the load error without
// capturing the exception.
var errorEvent = new CustomEvent('dartLoadException', { detail: message });
window.dispatchEvent(errorEvent);
throw Error(message);
}
const libraryImports = Symbol('libraryImports');
dart_library.libraryImports = libraryImports;
// Module support. This is a simplified module system for Dart.
// Longer term, we can easily migrate to an existing JS module system:
// ES6, AMD, RequireJS, ....
// Returns a proxy that delegates to the underlying loader.
// This defers loading of a module until a library is actually used.
const loadedModule = Symbol('loadedModule');
dart_library.defer = function(module, name, patch) {
let done = false;
function loadDeferred() {
done = true;
var mod = module[loadedModule];
var lib = mod[name];
// Install unproxied module and library in caller's context.
patch(mod, lib);
}
// The deferred library object. Note, the only legal operations on a Dart
// library object should be get (to read a top-level variable, method, or
// Class) or set (to write a top-level variable).
return new Proxy({}, {
get: function(o, p) {
if (!done) loadDeferred();
return module[name][p];
},
set: function(o, p, value) {
if (!done) loadDeferred();
module[name][p] = value;
return true;
},
});
};
let _reverseImports = new Map();
class LibraryLoader {
constructor(name, defaultValue, imports, loader) {
imports.forEach(function(i) {
var deps = _reverseImports.get(i);
if (!deps) {
deps = new Set();
_reverseImports.set(i, deps);
}
deps.add(name);
});
this._name = name;
this._library = defaultValue ? defaultValue : {};
this._imports = imports;
this._loader = loader;
// Cyclic import detection
this._state = LibraryLoader.NOT_LOADED;
}
loadImports() {
let results = [];
for (let name of this._imports) {
results.push(import_(name));
}
return results;
}
load() {
// Check for cycles
if (this._state == LibraryLoader.LOADING) {
throwLibraryError('Circular dependence on library: '
+ this._name);
} else if (this._state >= LibraryLoader.READY) {
return this._library;
}
this._state = LibraryLoader.LOADING;
// Handle imports
let args = this.loadImports();
// Load the library
let loader = this;
let library = this._library;
library[libraryImports] = this._imports;
library[loadedModule] = library;
args.unshift(library);
if (this._name == 'dart_sdk') {
// Eagerly load the SDK.
this._loader.apply(null, args);
} else {
// Load / parse other modules on demand.
let done = false;
this._library = new Proxy(library, {
get: function(o, name) {
if (!done) {
done = true;
loader._loader.apply(null, args);
}
return o[name];
}
});
}
this._state = LibraryLoader.READY;
return this._library;
}
stub() {
return this._library;
}
}
LibraryLoader.NOT_LOADED = 0;
LibraryLoader.LOADING = 1;
LibraryLoader.READY = 2;
// Map from name to LibraryLoader
let _libraries = new Map();
dart_library.libraries = function() { return _libraries.keys(); };
dart_library.debuggerLibraries = function() {
var debuggerLibraries = [];
_libraries.forEach(function (value, key, map) {
debuggerLibraries.push(value.load());
});
debuggerLibraries.__proto__ = null;
return debuggerLibraries;
};
// Invalidate a library and all things that depend on it
function _invalidateLibrary(name) {
let lib = _libraries.get(name);
if (lib._state == LibraryLoader.NOT_LOADED) return;
lib._state = LibraryLoader.NOT_LOADED;
lib._library = {};
let deps = _reverseImports.get(name);
if (!deps) return;
deps.forEach(_invalidateLibrary);
}
function library(name, defaultValue, imports, loader) {
let result = _libraries.get(name);
if (result) {
console.log('Re-loading ' + name);
_invalidateLibrary(name);
}
result = new LibraryLoader(name, defaultValue, imports, loader);
_libraries.set(name, result);
return result;
}
dart_library.library = library;
// Maintain a stack of active imports. If a requested library/module is not
// available, print the stack to show where/how it was requested.
let _stack = [];
function import_(name) {
let lib = _libraries.get(name);
if (!lib) {
let message = 'Module ' + name + ' not loaded in the browser.';
if (_stack != []) {
message += '\nDependency via:';
let indent = '';
for (let last = _stack.length - 1; last >= 0; last--) {
indent += ' ';
message += '\n' + indent + '- ' + _stack[last];
}
}
throwLibraryError(message);
}
_stack.push(name);
let result = lib.load();
_stack.pop();
return result;
}
dart_library.import = import_;
var _currentIsolate = false;
function _restart() {
start(_lastModuleName, _lastLibraryName, true);
}
function reload() {
if (!window || !window.$dartWarmReload) {
console.warn('Warm reload not supported in this environment.');
return;
}
var result;
if (_lastLibrary && _lastLibrary.onReloadStart) {
result = _lastLibrary.onReloadStart();
}
if (result && result.then) {
let sdk = _libraries.get("dart_sdk");
result.then(sdk._library.dart.Dynamic)(function() {
window.$dartWarmReload(_restart);
});
} else {
window.$dartWarmReload(_restart);
}
}
dart_library.reload = reload;
var _lastModuleName;
var _lastLibraryName;
var _lastLibrary;
var _originalBody;
function start(moduleName, libraryName, isReload) {
if (libraryName == null) libraryName = moduleName;
_lastModuleName = moduleName;
_lastLibraryName = libraryName;
let library = import_(moduleName)[libraryName];
_lastLibrary = library;
let dart_sdk = import_('dart_sdk');
if (!_currentIsolate) {
// This import is only needed for chrome debugging. We should provide an
// option to compile without it.
dart_sdk._debugger.registerDevtoolsFormatter();
// Create isolate.
_currentIsolate = true;
dart_sdk._isolate_helper.startRootIsolate(() => {}, []);
}
if (isReload) {
if (library.onReloadEnd) {
library.onReloadEnd();
return;
} else {
document.body = _originalBody;
}
} else {
// If not a reload then store the initial html to reset it on reload.
_originalBody = document.body.cloneNode(true);
}
library.main();
}
dart_library.start = start;
})(dart_library);
}