@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
JavaScript
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