text: 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.keys(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('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('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;
              }
          };
      }
  }
  if (!global.NativeScriptHasInitGlobal) {
      initGlobal();
  }
  //# sourceMappingURL=index.js.map