Files
Morten Sjøgren 1232d1edfd feat(tslib): add tslib helpers to global (#6351)
* feat(tslib): add tslib helpers to global

* Adds tslib as a dependency to tns-core-modules
* Replaces globals/decorators with globals/tslib
* Adds support for async/await, rest and spread operators.

* refactor: rename tslib to ts-helpers to avoid confusion with npm package
2018-10-05 17:12:45 +03:00

228 lines
8.0 KiB
TypeScript

// Required by TypeScript compiler
require("./ts-helpers");
// This method iterates all the keys in the source exports object and copies them to the destination exports one.
// Note: the method will not check for naming collisions and will override any already existing entries in the destination exports.
global.moduleMerge = function (sourceExports: any, destExports: any) {
for (var key in sourceExports) {
destExports[key] = sourceExports[key];
}
}
import * as timerModule from "../timer";
import * as dialogsModule from "../ui/dialogs";
type ModuleLoader = (name?: string) => any;
const modules: Map<string, ModuleLoader> = new Map<string, ModuleLoader>();
(<any>global).moduleResolvers = [global.require];
global.registerModule = function (name: string, loader: ModuleLoader): void {
modules.set(name, loader);
}
interface Context {
keys(): string[];
(key: string): any;
}
interface ExtensionMap {
[originalFileExtension: string]: string;
}
const defaultExtensionMap = { ".js": ".js", ".ts": ".js", ".css": ".css", ".scss": ".css", ".xml": ".xml", ".less": ".css", ".sass": ".css" };
global.registerWebpackModules = function registerWebpackModules(context: Context, extensionMap: ExtensionMap = {}) {
context.keys().forEach(key => {
const extDotIndex = key.lastIndexOf(".");
const base = key.substr(0, extDotIndex);
const originalExt = key.substr(extDotIndex);
const registerExt = extensionMap[originalExt] || defaultExtensionMap[originalExt] || originalExt;
// We prefer source files for webpack scenarios before compilation leftovers,
// e. g. if we get a .js and .ts for the same module, the .js is probably the compiled version of the .ts file,
// so we register the .ts with higher priority, similar is the case with us preferring the .scss to .css
const isSourceFile = originalExt !== registerExt;
const registerName = base + registerExt;
if (registerName.startsWith("./") && registerName.endsWith(".js")) {
const jsNickNames = [
// This is extremely short version like "main-page" that was promoted to be used with global.registerModule("module-name", loaderFunc);
registerName.substr(2, registerName.length - 5),
// This is for supporting module names like "./main/main-page"
registerName.substr(0, registerName.length - 3),
// This is for supporting module names like "main/main-page.js"
registerName.substr(2),
];
jsNickNames.forEach(jsNickName => {
if (isSourceFile || !global.moduleExists(jsNickName)) {
global.registerModule(jsNickName, () => context(key));
}
});
}
if (isSourceFile || !global.moduleExists(registerName)) {
global.registerModule(registerName, () => context(key));
}
});
}
global.moduleExists = function (name: string): boolean {
return modules.has(name);
}
global.loadModule = function (name: string): any {
const loader = modules.get(name);
if (loader) {
return loader();
}
for (let resolver of (<any>global).moduleResolvers) {
const result = resolver(name);
if (result) {
modules.set(name, () => result);
return result;
}
}
}
global.zonedCallback = function (callback: Function): Function {
if ((<any>global).zone) {
// Zone v0.5.* style callback wrapping
return (<any>global).zone.bind(callback);
}
if ((<any>global).Zone) {
// Zone v0.6.* style callback wrapping
return (<any>global).Zone.current.wrap(callback);
} else {
return callback;
}
}
global.registerModule("timer", () => require("timer"));
global.registerModule("ui/dialogs", () => require("ui/dialogs"));
global.registerModule("xhr", () => require("xhr"));
global.registerModule("fetch", () => require("fetch"));
(<any>global).System = {
import(path) {
return new Promise((resolve, reject) => {
try {
resolve(global.require(path));
} catch (e) {
reject(e);
}
});
}
}
function registerOnGlobalContext(name: string, module: string): void {
Object.defineProperty(global, name, {
get: function () {
// We do not need to cache require() call since it is already cached in the runtime.
let m = global.loadModule(module);
// Redefine the property to make sure the above code is executed only once.
let resolvedValue = m[name];
Object.defineProperty(this, name, { value: resolvedValue, configurable: true, writable: true });
return resolvedValue;
},
configurable: true
});
}
let snapshotGlobals;
export function install() {
if ((<any>global).__snapshot || (<any>global).__snapshotEnabled) {
if (!snapshotGlobals) {
// require in snapshot mode is cheap
var timer: typeof timerModule = require("timer");
var dialogs: typeof dialogsModule = require("ui/dialogs");
var xhr = require("xhr");
var fetch = require("fetch");
snapshotGlobals = snapshotGlobals || {
setTimeout: timer.setTimeout,
clearTimeout: timer.clearTimeout,
setInterval: timer.setInterval,
clearInterval: timer.clearInterval,
alert: dialogs.alert,
confirm: dialogs.confirm,
prompt: dialogs.prompt,
login: dialogs.login,
action: dialogs.action,
XMLHttpRequest: xhr.XMLHttpRequest,
FormData: xhr.FormData,
fetch: fetch.fetch,
Headers: fetch.Headers,
Request: fetch.Request,
Response: fetch.Response,
}
}
var consoleModule = require("console").Console;
// Object.assign call will fire an error when trying to write to a read-only property of an object, such as 'console'
global.console = global.console || new consoleModule();
Object.assign(global, snapshotGlobals);
} else {
registerOnGlobalContext("setTimeout", "timer");
registerOnGlobalContext("clearTimeout", "timer");
registerOnGlobalContext("setInterval", "timer");
registerOnGlobalContext("clearInterval", "timer");
registerOnGlobalContext("alert", "ui/dialogs");
registerOnGlobalContext("confirm", "ui/dialogs");
registerOnGlobalContext("prompt", "ui/dialogs");
registerOnGlobalContext("login", "ui/dialogs");
registerOnGlobalContext("action", "ui/dialogs");
registerOnGlobalContext("XMLHttpRequest", "xhr");
registerOnGlobalContext("FormData", "xhr");
registerOnGlobalContext("fetch", "fetch");
registerOnGlobalContext("Headers", "fetch");
registerOnGlobalContext("Request", "fetch");
registerOnGlobalContext("Response", "fetch");
}
}
install();
export function Deprecated(target: Object, key?: string | symbol, descriptor?: any) {
if (descriptor) {
var originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`${key.toString()} is deprecated`);
return originalMethod.apply(this, args);
}
return descriptor;
} else {
console.log(`${(target && (<any>target).name || target)} is deprecated`);
return target;
}
}
global.Deprecated = Deprecated;
export function Experimental(target: Object, key?: string | symbol, descriptor?: any) {
if (descriptor) {
var originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`${key.toString()} is experimental`);
return originalMethod.apply(this, args);
}
return descriptor;
} else {
console.log(`${(target && (<any>target).name || target)} is experimental`);
return target;
}
}
global.Experimental = Experimental;