UNPKG

12.9 kBJavaScriptView Raw
1const tslib = require('tslib');
2import { Observable } from '../data/observable';
3import { trace as profilingTrace, time, uptime, level as profilingLevel } from '../profiling';
4function registerOnGlobalContext(moduleName, exportName) {
5 Object.defineProperty(global, exportName, {
6 get: function () {
7 // We do not need to cache require() call since it is already cached in the runtime.
8 const m = global.loadModule(moduleName);
9 // Redefine the property to make sure the above code is executed only once.
10 const resolvedValue = m[exportName];
11 Object.defineProperty(global, exportName, {
12 value: resolvedValue,
13 configurable: true,
14 writable: true,
15 });
16 return resolvedValue;
17 },
18 configurable: true,
19 });
20}
21/**
22 * Manages internal framework global state
23 */
24export class NativeScriptGlobalState {
25 constructor() {
26 this.launched = false;
27 this._appInstanceReady = false;
28 // console.log('creating NativeScriptGlobals...')
29 this.events = new Observable();
30 this._setLaunched = this._setLaunchedFn.bind(this);
31 this.events.on('launch', this._setLaunched);
32 if (profilingLevel() > 0) {
33 this.events.on('displayed', () => {
34 const duration = uptime();
35 const end = time();
36 const start = end - duration;
37 profilingTrace(`Displayed in ${duration.toFixed(2)}ms`, start, end);
38 });
39 }
40 }
41 get appInstanceReady() {
42 return this._appInstanceReady;
43 }
44 set appInstanceReady(value) {
45 this._appInstanceReady = value;
46 // app instance ready, wire up any app events waiting in startup queue
47 if (this.appEventWiring && this.appEventWiring.length) {
48 for (const callback of this.appEventWiring) {
49 callback();
50 }
51 // cleanup
52 this.appEventWiring = null;
53 }
54 }
55 /**
56 * Ability for classes to initialize app event handling early even before the app instance is ready during boot cycle avoiding boot race conditions
57 * @param callback wire up any global event handling inside the callback
58 */
59 addEventWiring(callback) {
60 if (this._appInstanceReady) {
61 callback();
62 }
63 else {
64 if (!this.appEventWiring) {
65 this.appEventWiring = [];
66 }
67 this.appEventWiring.push(callback);
68 }
69 }
70 _setLaunchedFn() {
71 // console.log('NativeScriptGlobals launch fired!');
72 this.launched = true;
73 this.events.off('launch', this._setLaunched);
74 this._setLaunched = null;
75 }
76}
77export function installPolyfills(moduleName, exportNames) {
78 if (global.__snapshot) {
79 const loadedModule = global.loadModule(moduleName);
80 exportNames.forEach((exportName) => (global[exportName] = loadedModule[exportName]));
81 }
82 else {
83 exportNames.forEach((exportName) => registerOnGlobalContext(moduleName, exportName));
84 }
85}
86export function initGlobal() {
87 if (!global.NativeScriptHasInitGlobal) {
88 global.NativeScriptHasInitGlobal = true;
89 // init global state handler
90 global.NativeScriptGlobals = new NativeScriptGlobalState();
91 // ts-helpers
92 // Required by V8 snapshot generator
93 if (!global.__extends) {
94 global.__extends = function (d, b) {
95 for (const p in b) {
96 if (b.hasOwnProperty(p)) {
97 d[p] = b[p];
98 }
99 }
100 function __() {
101 this.constructor = d;
102 }
103 d.prototype = b === null ? Object.create(b) : ((__.prototype = b.prototype), new __());
104 };
105 }
106 // Bind the tslib helpers to global scope.
107 // This is needed when we don't use importHelpers, which
108 // breaks extending native-classes
109 for (const fnName of Object.getOwnPropertyNames(tslib)) {
110 if (typeof tslib[fnName] !== 'function') {
111 continue;
112 }
113 if (fnName in global) {
114 // Don't override globals that are already defined (ex. __extends)
115 continue;
116 }
117 global[fnName] = tslib[fnName];
118 }
119 // module helpers
120 const modules = new Map();
121 const modulesLoadedForUI = new Set();
122 const defaultExtensionMap = {
123 '.js': '.js',
124 '.ts': '.js',
125 '.kt': '.js',
126 '.css': '.css',
127 '.scss': '.css',
128 '.less': '.css',
129 '.sass': '.css',
130 '.xml': '.xml',
131 };
132 // Cast to <any> because moduleResolvers is read-only in definitions
133 global.moduleResolvers = [global.require];
134 global.registerModule = function (name, loader) {
135 modules.set(name, { loader, moduleId: name });
136 };
137 global._unregisterModule = function _unregisterModule(name) {
138 modules.delete(name);
139 };
140 global._isModuleLoadedForUI = function _isModuleLoadedForUI(moduleName) {
141 return modulesLoadedForUI.has(moduleName);
142 };
143 global.registerWebpackModules = function registerWebpackModules(context, extensionMap = {}) {
144 context.keys().forEach((moduleId) => {
145 const extDotIndex = moduleId.lastIndexOf('.');
146 const base = moduleId.substr(0, extDotIndex);
147 const originalExt = moduleId.substr(extDotIndex);
148 const registerExt = extensionMap[originalExt] || defaultExtensionMap[originalExt] || originalExt;
149 // We prefer source files for webpack scenarios before compilation leftovers,
150 // e. g. if we get a .js and .ts for the same module, the .js is probably the compiled version of the .ts file,
151 // so we register the .ts with higher priority, similar is the case with us preferring the .scss to .css
152 const isSourceFile = originalExt !== registerExt;
153 const registerName = base + registerExt;
154 const registerWithName = (nickName) => {
155 modules.set(nickName, {
156 moduleId,
157 loader: () => {
158 return context(moduleId);
159 },
160 });
161 };
162 if (registerName.startsWith('./') && registerName.endsWith('.js')) {
163 const jsNickNames = [
164 // This is extremely short version like "main-page" that was promoted to be used with global.registerModule("module-name", loaderFunc);
165 registerName.substr(2, registerName.length - 5),
166 // This is for supporting module names like "./main/main-page"
167 registerName.substr(0, registerName.length - 3),
168 // This is for supporting module names like "main/main-page.js"
169 registerName.substr(2),
170 ];
171 jsNickNames.forEach((jsNickName) => {
172 if (isSourceFile || !global.moduleExists(jsNickName)) {
173 registerWithName(jsNickName);
174 }
175 });
176 }
177 else if (registerName.startsWith('./')) {
178 const moduleNickNames = [
179 // This is for supporting module names like "main/main-page.xml"
180 registerName.substr(2),
181 ];
182 moduleNickNames.forEach((moduleNickName) => {
183 if (!global.moduleExists(moduleNickName)) {
184 registerWithName(moduleNickName);
185 }
186 });
187 }
188 if (isSourceFile || !global.moduleExists(registerName)) {
189 registerWithName(registerName);
190 }
191 });
192 };
193 global.moduleExists = function moduleExists(name) {
194 return modules.has(name);
195 };
196 global.loadModule = function loadModule(name, isUIModule = false) {
197 const moduleInfo = modules.get(name);
198 if (moduleInfo) {
199 if (isUIModule) {
200 modulesLoadedForUI.add(moduleInfo.moduleId);
201 }
202 const result = moduleInfo.loader(name);
203 if (result.enableAutoAccept) {
204 result.enableAutoAccept();
205 }
206 return result;
207 }
208 for (const resolver of global.moduleResolvers) {
209 const result = resolver(name);
210 if (result) {
211 modules.set(name, { moduleId: name, loader: () => result });
212 return result;
213 }
214 }
215 };
216 global.getRegisteredModules = function getRegisteredModules() {
217 return Array.from(modules.keys());
218 };
219 /**
220 * Polyfills
221 */
222 // This method iterates all the keys in the source exports object and copies them to the destination exports one.
223 // Note: the method will not check for naming collisions and will override any already existing entries in the destination exports.
224 global.moduleMerge = function (sourceExports, destExports) {
225 for (const key in sourceExports) {
226 destExports[key] = sourceExports[key];
227 }
228 };
229 global.zonedCallback = function (callback) {
230 if (global.zone) {
231 // Zone v0.5.* style callback wrapping
232 return global.zone.bind(callback);
233 }
234 if (global.Zone) {
235 // Zone v0.6.* style callback wrapping
236 return global.Zone.current.wrap(callback);
237 }
238 else {
239 return callback;
240 }
241 };
242 global.System = {
243 import(path) {
244 return new Promise((resolve, reject) => {
245 try {
246 resolve(global.require(path));
247 }
248 catch (e) {
249 reject(e);
250 }
251 });
252 },
253 };
254 // DOM api polyfills
255 global.registerModule('timer', () => require('../timer'));
256 installPolyfills('timer', ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval']);
257 global.registerModule('animation', () => require('../animation-frame'));
258 installPolyfills('animation', ['requestAnimationFrame', 'cancelAnimationFrame']);
259 global.registerModule('ui-dialogs', () => require('../ui/dialogs'));
260 installPolyfills('ui-dialogs', ['alert', 'confirm', 'prompt', 'login', 'action']);
261 global.registerModule('text', () => require('../text'));
262 installPolyfills('text', ['TextDecoder', 'TextEncoder']);
263 global.registerModule('xhr', () => require('../xhr'));
264 installPolyfills('xhr', ['XMLHttpRequest', 'FormData', 'Blob', 'File', 'FileReader']);
265 global.registerModule('fetch', () => require('../fetch'));
266 installPolyfills('fetch', ['fetch', 'Headers', 'Request', 'Response']);
267 // global.registerModule('abortcontroller', () => require('../abortcontroller'));
268 // installPolyfills('abortcontroller', ['AbortController', 'AbortSignal']);
269 // Custom decorators
270 global.Deprecated = function (target, key, descriptor) {
271 if (descriptor) {
272 const originalMethod = descriptor.value;
273 descriptor.value = function (...args) {
274 console.log(`${key.toString()} is deprecated`);
275 return originalMethod.apply(this, args);
276 };
277 return descriptor;
278 }
279 else {
280 console.log(`${(target && target.name) || target} is deprecated`);
281 return target;
282 }
283 };
284 global.Experimental = function (target, key, descriptor) {
285 if (descriptor) {
286 const originalMethod = descriptor.value;
287 descriptor.value = function (...args) {
288 console.log(`${key.toString()} is experimental`);
289 return originalMethod.apply(this, args);
290 };
291 return descriptor;
292 }
293 else {
294 console.log(`${(target && target.name) || target} is experimental`);
295 return target;
296 }
297 };
298 }
299}
300if (!global.NativeScriptHasInitGlobal) {
301 initGlobal();
302}
303//# sourceMappingURL=index.js.map
\No newline at end of file