UNPKG

ng1-shift

Version:

Angular 1.5+ decorators for writing Angular2 like.

395 lines (374 loc) 14.9 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["ng1-shift"] = {})); })(this, (function (exports) { 'use strict'; const Metakeys = { type: "ng1-shift:type", componentOptions: "ng1-shift:componentOptions" }; class ComponentMetadataService { constructor(target) { this.target = target; } addInput(componentProp, inputName) { const options = this.metadata; options.inputs.push({ componentProp, inputName }); this.metadata = options; } addOutput(componentProp, outputName) { const options = this.metadata; options.outputs.push({ componentProp, outputName }); this.metadata = options; } getInputs() { return this.metadata.inputs; } getOutputs() { return this.metadata.outputs; } get hasMetadata() { return Reflect.hasMetadata(Metakeys.componentOptions, this.target); } get metadata() { if (this.hasMetadata) { return Reflect.getMetadata(Metakeys.componentOptions, this.target); } return { inputs: [], outputs: [] }; } set metadata(value) { Reflect.defineMetadata(Metakeys.componentOptions, value, this.target); } } function findFirst(array, expression) { // @ts-ignore if (!angular.isFunction(expression)) { const first = array[0]; if (!first) { return null; } return first; } for (let i = 0; i < array.length; i++) { if (expression(array[i])) { return array[i]; } } return null; } // Solution from: https://stackoverflow.com/questions/30758961/how-to-check-if-a-variable-is-an-es6-class-declaration#answer-68708710 function isClass(value) { return typeof value === "function" && (/^\s*class[^\w]+/.test(value.toString()) || // 1. native classes don't have `class` in their name // 2. However, they are globals and start with a capital letter. (window[value.name] === value && /^[A-Z]/.test(value.name))); } function wrapRouterConfig(routerConfig) { if (isClass(routerConfig)) { const wrapperFunction = (...args) => { // @ts-ignore return new routerConfig(...args); }; wrapperFunction.$inject = routerConfig.$inject; return wrapperFunction; } return routerConfig; } function importHandler(imports) { let ng1ModuleIds = []; const modules = imports.filter((mdl) => { return !(mdl.$inject && findFirst(mdl.$inject, (i) => i === "$stateProvider")); }); const ng1RouterConfig = findFirst(imports, (mdl) => { return mdl.$inject && findFirst(mdl.$inject, (i) => i === "$stateProvider"); }); if (modules.length) { ng1ModuleIds = modules.map((mdl) => { if (mdl.ng1ShiftModuleName) { return mdl.ng1ShiftModuleName; } return mdl; }); } return { ng1ModuleIds, ng1RouterConfig: wrapRouterConfig(ng1RouterConfig), }; } function kebabCaseToCamelCase(str) { if (str.indexOf("-") !== -1) { const newArr = str.toLowerCase().split("-"); // We are starting from 1 because the first letter in camelCase word is in lowercase for (let i = 1; i < newArr.length; i++) { newArr[i] = newArr[i].charAt(0).toUpperCase() + newArr[i].substr(1); } return newArr.join(""); } return str; } const DeclarationType = { component: "component", directive: "directive" }; function removeBracketsAndDot(str) { return str .replace(/^\[|\]$/ig, "") .replace(/^\./i, ""); } function getRestrictFromSelector(selector) { const firstSign = selector.substr(0, 1); let restrict = "E"; switch (firstSign) { case "[": restrict = "A"; break; case ".": restrict = "C"; break; } return restrict; } function DirectiveFactory(type) { return () => Object(Object.assign({}, type)); } function daclarationHandler(ng1Module, declarations) { declarations.forEach((declaration) => { const hasNg1Meta = Reflect.hasMetadata(Metakeys.type, declaration); if (hasNg1Meta) { const declarationType = Reflect.getMetadata(Metakeys.type, declaration); const selectorNg2 = declaration.selector; let selectorNg1; switch (declarationType) { case DeclarationType.component: selectorNg1 = kebabCaseToCamelCase(selectorNg2); ng1Module.component(selectorNg1, declaration); break; case DeclarationType.directive: selectorNg1 = removeBracketsAndDot(selectorNg2); ng1Module.directive(selectorNg1, DirectiveFactory(declaration)); break; } } }); } function providerHandler(ng1Module, providers, declarations) { declarations.forEach((declaration) => { const injections = Reflect.getMetadata("design:paramtypes", declaration); if (injections) { const injectedServices = injections.map(({ name }) => name); if (!declaration.$inject) { declaration.$inject = []; } providers.forEach((provider) => { const serviceToken = provider.name; const injectIndex = injectedServices.indexOf(serviceToken); declaration.$inject[injectIndex] = serviceToken; ng1Module.service(serviceToken, provider); }); } }); } const entityCounters = {}; function counter(entity) { const registeredEntity = entity in entityCounters; if (!registeredEntity) { entityCounters[entity] = 0; } return entityCounters[entity]++; } function NgModule({ id, imports, declarations, providers, directRegister }) { return function (target) { let ng1ModuleIds = []; let ng1RouterConfig; const hasImports = imports && imports.length; if (hasImports) { const handledImports = importHandler(imports); ng1ModuleIds = handledImports.ng1ModuleIds; ng1RouterConfig = handledImports.ng1RouterConfig; } target.ng1ShiftModuleName = `${target.name}-${counter("moduleName")}`; if (id === "app-module") { target.ng1ShiftModuleName = id; } // @ts-ignore const ng1Module = angular.module(target.ng1ShiftModuleName, ng1ModuleIds); if (ng1RouterConfig) { ng1Module.config(ng1RouterConfig); } if (declarations && declarations.length) { daclarationHandler(ng1Module, declarations); } if (providers && providers.length) { providerHandler(ng1Module, providers, declarations); } if (directRegister) { directRegister(ng1Module); } }; } function replaceTwoWayBindings(target) { const componentMetadata = new ComponentMetadataService(target), inputs = componentMetadata.getInputs(), outputs = componentMetadata.getOutputs(); if (inputs.length > 0 && outputs.length > 0) { inputs.forEach(input => { const requiredOutput = `${input.inputName}Change`; const hasOutput = outputs.some(output => output.outputName === requiredOutput); if (hasOutput && target.bindings) { target.bindings[input.componentProp] = target.bindings[input.componentProp].replace(/^</, "="); } }); } } function Component(config) { return function (target) { if (config) { if (config.template) { target.template = config.template; } if (config.selector) { target.selector = config.selector; } } // Lifecycle hooks aliases if (target.prototype.ngOnInit) { target.prototype.$onInit = target.prototype.ngOnInit; } if (target.prototype.ngAfterViewInit) { target.prototype.$postLink = target.prototype.ngAfterViewInit; } if (target.prototype.ngOnChanges) { target.prototype.$onChanges = target.prototype.ngOnChanges; } if (target.prototype.ngOnDestroy) { target.prototype.$onDestroy = target.prototype.ngOnDestroy; } // Controller linking target.controller = target; replaceTwoWayBindings(target); Reflect.defineMetadata(Metakeys.type, DeclarationType.component, target); return target; }; } function Directive({ selector }) { return (target) => { if (selector) { target.selector = kebabCaseToCamelCase(selector); } // Lifecycle hooks aliases if (target.prototype.ngOnInit) { target.prototype.$onInit = target.prototype.ngOnInit; } if (target.prototype.ngAfterViewInit) { target.prototype.$postLink = target.prototype.ngAfterViewInit; } if (target.prototype.ngOnChanges) { target.prototype.$onChanges = target.prototype.ngOnChanges; } if (target.prototype.ngOnDestroy) { target.prototype.$onDestroy = target.prototype.ngOnDestroy; } // Controller linking target.restrict = getRestrictFromSelector(target.selector); target.controller = target; // IE11 doesn't support function.name target.controllerAs = target.controllerAs || target.name || target.selector; target.bindToController = target.bindings ? target.bindings : {}; // always isolated scope, unless set other target.scope = target.scope !== void 0 ? target.scope : false; Reflect.defineMetadata(Metakeys.type, DeclarationType.directive, target); return target; }; } function Input(alias) { return function (target, property) { const componentMetadata = new ComponentMetadataService(target.constructor); if (!target.constructor.bindings) { target.constructor.bindings = {}; } const propName = String(property); const attrBinding = alias ? alias : propName; target.constructor.bindings[propName] = "<" + attrBinding; componentMetadata.addInput(propName, attrBinding); }; } function Output(alias) { return function (target, property) { const componentMetadata = new ComponentMetadataService(target.constructor); if (!target.constructor.bindings) { target.constructor.bindings = {}; } const propName = String(property); const privateCallbackName = `__${propName}`; const attrBinding = alias ? alias : propName; target.constructor.bindings[privateCallbackName] = `&${attrBinding}`; componentMetadata.addOutput(propName, attrBinding); Object.defineProperty(target, privateCallbackName, { set: function (callback) { if (!this.__callbackCache) { this.__callbackCache = {}; } if (typeof callback === "function") { this.__callbackCache[propName] = callback; } }, enumerable: false, configurable: true }); Object.defineProperty(target, propName, { set: function (eventEmitterInstance) { if (!this.__eventEmitterCache) { this.__eventEmitterCache = {}; } if (eventEmitterInstance && eventEmitterInstance.subscribe) { eventEmitterInstance.subscribe((eventData) => { if (typeof this.__callbackCache[propName] === "function") { this.__callbackCache[propName]({ $event: eventData }); } }); this.__eventEmitterCache[propName] = eventEmitterInstance; } }, get: function () { return this.__eventEmitterCache[propName]; }, enumerable: true, configurable: true }); }; } function Inject(dependencyName) { return function (target, property, parameterIndex) { if (!target.$inject) { target.$inject = []; } const injectionToken = typeof dependencyName === "string" ? dependencyName : dependencyName.$injectionToken; target.$inject[parameterIndex] = injectionToken; }; } class EventEmitter { constructor() { this.listeners = []; } emit(event) { this.listeners.forEach(callback => callback.call(null, event)); } subscribe(callback) { this.listeners.push(callback); } } exports.Component = Component; exports.Directive = Directive; exports.EventEmitter = EventEmitter; exports.Inject = Inject; exports.Input = Input; exports.NgModule = NgModule; exports.Output = Output; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=index.js.map