UNPKG

@nativescript/core

Version:

A JavaScript library providing an easy to use api for interacting with iOS and Android platform APIs.

317 lines • 13.7 kB
const tslib = require('tslib'); import { Observable } from '../data/observable'; import { trace as profilingTrace, time, uptime, level as profilingLevel } from '../profiling'; function registerOnGlobalContext(moduleName, exportName) { Object.defineProperty(global, exportName, { get: function () { // We do not need to cache require() call since it is already cached in the runtime. const m = global.loadModule(moduleName); // Redefine the property to make sure the above code is executed only once. const resolvedValue = m[exportName]; Object.defineProperty(global, exportName, { value: resolvedValue, configurable: true, writable: true, }); return resolvedValue; }, configurable: true, }); } /** * Manages internal framework global state */ export class NativeScriptGlobalState { constructor() { this.launched = false; this._appInstanceReady = false; // console.log('creating NativeScriptGlobals...') this.events = new Observable(); this._setLaunched = this._setLaunchedFn.bind(this); this.events.on('launch', this._setLaunched); if (profilingLevel() > 0) { this.events.on('displayed', () => { const duration = uptime(); const end = time(); const start = end - duration; profilingTrace(`Displayed in ${duration.toFixed(2)}ms`, start, end); }); } } get appInstanceReady() { return this._appInstanceReady; } set appInstanceReady(value) { this._appInstanceReady = value; // app instance ready, wire up any app events waiting in startup queue if (this.appEventWiring && this.appEventWiring.length) { for (const callback of this.appEventWiring) { callback(); } // cleanup this.appEventWiring = null; } } /** * Ability for classes to initialize app event handling early even before the app instance is ready during boot cycle avoiding boot race conditions * @param callback wire up any global event handling inside the callback */ addEventWiring(callback) { if (this._appInstanceReady) { callback(); } else { if (!this.appEventWiring) { this.appEventWiring = []; } this.appEventWiring.push(callback); } } _setLaunchedFn() { // console.log('NativeScriptGlobals launch fired!'); this.launched = true; this.events.off('launch', this._setLaunched); this._setLaunched = null; } } export function installPolyfills(moduleName, exportNames) { if (global.__snapshot) { const loadedModule = global.loadModule(moduleName); exportNames.forEach((exportName) => (global[exportName] = loadedModule[exportName])); } else { exportNames.forEach((exportName) => registerOnGlobalContext(moduleName, exportName)); } } export function initGlobal() { if (!global.NativeScriptHasInitGlobal) { global.NativeScriptHasInitGlobal = true; // init global state handler global.NativeScriptGlobals = new NativeScriptGlobalState(); // ts-helpers // Required by V8 snapshot generator if (!global.__extends) { global.__extends = function (d, b) { for (const p in b) { if (b.hasOwnProperty(p)) { d[p] = b[p]; } } function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __()); }; } // Bind the tslib helpers to global scope. // This is needed when we don't use importHelpers, which // breaks extending native-classes for (const fnName of Object.getOwnPropertyNames(tslib)) { if (typeof tslib[fnName] !== 'function') { continue; } if (fnName in global) { // Don't override globals that are already defined (ex. __extends) continue; } global[fnName] = tslib[fnName]; } // module helpers const modules = new Map(); const modulesLoadedForUI = new Set(); const defaultExtensionMap = { '.js': '.js', '.ts': '.js', '.kt': '.js', '.css': '.css', '.scss': '.css', '.less': '.css', '.sass': '.css', '.xml': '.xml', }; // Cast to <any> because moduleResolvers is read-only in definitions global.moduleResolvers = [global.require]; global.registerModule = function (name, loader) { modules.set(name, { loader, moduleId: name }); }; global._unregisterModule = function _unregisterModule(name) { modules.delete(name); }; global._isModuleLoadedForUI = function _isModuleLoadedForUI(moduleName) { return modulesLoadedForUI.has(moduleName); }; global.registerWebpackModules = function registerWebpackModules(context, extensionMap = {}) { context.keys().forEach((moduleId) => { const extDotIndex = moduleId.lastIndexOf('.'); const base = moduleId.substr(0, extDotIndex); const originalExt = moduleId.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; const registerWithName = (nickName) => { modules.set(nickName, { moduleId, loader: () => { return context(moduleId); }, }); }; 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)) { registerWithName(jsNickName); } }); } else if (registerName.startsWith('./')) { const moduleNickNames = [ // This is for supporting module names like "main/main-page.xml" registerName.substr(2), ]; moduleNickNames.forEach((moduleNickName) => { if (!global.moduleExists(moduleNickName)) { registerWithName(moduleNickName); } }); } if (isSourceFile || !global.moduleExists(registerName)) { registerWithName(registerName); } }); }; global.moduleExists = function moduleExists(name) { return modules.has(name); }; global.loadModule = function loadModule(name, isUIModule = false) { const moduleInfo = modules.get(name); if (moduleInfo) { if (isUIModule) { modulesLoadedForUI.add(moduleInfo.moduleId); } const result = moduleInfo.loader(name); if (result.enableAutoAccept) { result.enableAutoAccept(); } return result; } for (const resolver of global.moduleResolvers) { const result = resolver(name); if (result) { modules.set(name, { moduleId: name, loader: () => result }); return result; } } }; global.getRegisteredModules = function getRegisteredModules() { return Array.from(modules.keys()); }; /** * Polyfills */ // 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, destExports) { for (const key in sourceExports) { destExports[key] = sourceExports[key]; } }; global.zonedCallback = function (callback) { if (global.zone) { // Zone v0.5.* style callback wrapping return global.zone.bind(callback); } if (global.Zone) { // Zone v0.6.* style callback wrapping return global.Zone.current.wrap(callback); } else { return callback; } }; global.System = { import(path) { return new Promise((resolve, reject) => { try { resolve(global.require(path)); } catch (e) { reject(e); } }); }, }; // DOM api polyfills global.registerModule('timer', () => require('../timer')); installPolyfills('timer', ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval']); global.registerModule('animation', () => require('../animation-frame')); installPolyfills('animation', ['requestAnimationFrame', 'cancelAnimationFrame']); global.registerModule('media-query-list', () => require('../media-query-list')); installPolyfills('media-query-list', ['matchMedia', 'MediaQueryList']); global.registerModule('ui-dialogs', () => require('../ui/dialogs')); installPolyfills('ui-dialogs', ['alert', 'confirm', 'prompt', 'login', 'action']); global.registerModule('text', () => require('../text')); installPolyfills('text', ['TextDecoder', 'TextEncoder']); global.registerModule('xhr', () => require('../xhr')); installPolyfills('xhr', ['XMLHttpRequest', 'FormData', 'Blob', 'File', 'FileReader']); global.registerModule('fetch', () => require('../fetch')); installPolyfills('fetch', ['fetch', 'Headers', 'Request', 'Response']); global.registerModule('wgc', () => require('../wgc')); installPolyfills('wgc', ['atob', 'btoa']); global.registerModule('crypto', () => require('../wgc/crypto')); installPolyfills('crypto', ['Crypto']); global.registerModule('subtle', () => require('../wgc/crypto/SubtleCrypto')); installPolyfills('subtle-crypto', ['Subtle']); global.crypto = new global.Crypto(); // global.registerModule('abortcontroller', () => require('../abortcontroller')); // installPolyfills('abortcontroller', ['AbortController', 'AbortSignal']); // Custom decorators global.Deprecated = function (target, key, descriptor) { if (descriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args) { console.log(`${key.toString()} is deprecated`); return originalMethod.apply(this, args); }; return descriptor; } else { console.log(`${(target && target.name) || target} is deprecated`); return target; } }; global.Experimental = function (target, key, descriptor) { if (descriptor) { const originalMethod = descriptor.value; descriptor.value = function (...args) { console.log(`${key.toString()} is experimental`); return originalMethod.apply(this, args); }; return descriptor; } else { console.log(`${(target && target.name) || target} is experimental`); return target; } }; } } function isTestingEnv() { return typeof jest !== 'undefined'; } if (!global.NativeScriptHasInitGlobal && !isTestingEnv()) { initGlobal(); } // ensure the Application instance is initialized before any other module imports it. require('@nativescript/core/application'); //# sourceMappingURL=index.js.map