UNPKG

ember-material-icons

Version:

Google Material icons for your ember-cli app

405 lines (322 loc) 11 kB
import { Meta, InnerReferenceFactory, PropertyReference } from '@glimmer/object-reference'; import { Dict, dict, assign, initializeGuid } from '@glimmer/util'; import { Mixin, extend as extendClass, toMixin, relinkSubclasses, wrapMethod } from './mixin'; const { isArray } = Array; import { ROOT } from './utils'; export const EMPTY_CACHE = function EMPTY_CACHE() {}; const CLASS_META = "df8be4c8-4e89-44e2-a8f9-550c8dacdca7"; export interface ObjectWithMixins { "df8be4c8-4e89-44e2-a8f9-550c8dacdca7": ClassMeta; _meta: Meta; } export interface InstanceWithMixins { constructor: ObjectWithMixins; } export interface GlimmerObjectFactory<T> { new<U>(attrs?: U): T & U; extend(): GlimmerObjectFactory<Object>; extend<T>(extension: T): GlimmerObjectFactory<T>; extend(...extensions: Object[]): GlimmerObjectFactory<Object>; create<U>(attrs?: U): GlimmerObject & T & U; reopen<U>(extensions: U); reopenClass<U>(extensions: U); metaForProperty(property: string): Object; eachComputedProperty(callback: (string, Object) => void); "df8be4c8-4e89-44e2-a8f9-550c8dacdca7": InstanceMeta; } export function turbocharge(obj) { // function Dummy() {} // Dummy.prototype = obj; return obj; } abstract class SealedMeta extends Meta { addReferenceTypeFor(...args): InnerReferenceFactory<any> { throw new Error("Cannot modify reference types on a sealed meta"); } } export class ClassMeta { private referenceTypes = dict<InnerReferenceFactory<any>>(); private propertyMetadata = dict<any>(); private concatenatedProperties = dict<any[]>(); private hasConcatenatedProperties = false; private mergedProperties = dict<Object>(); private hasMergedProperties = false; private mixins: Mixin[] = []; private appliedMixins: Mixin[] = []; private staticMixins: Mixin[] = []; private subclasses: GlimmerObjectFactory<any>[] = []; private slots: string[] = []; public InstanceMetaConstructor: typeof Meta = null; static fromParent(parent: ClassMeta) { let meta = new this(); meta.reset(parent); return meta; } static for(object: ObjectWithMixins | InstanceWithMixins): ClassMeta { if (CLASS_META in object) return (<ObjectWithMixins>object)[CLASS_META]; else if (object.constructor) return (<InstanceWithMixins>object).constructor[CLASS_META] || null; else return null; } init(object: GlimmerObject, attrs: Object) { if (typeof attrs !== 'object' || attrs === null) return; if (this.hasConcatenatedProperties) { let concatProps = this.concatenatedProperties; for (let prop in concatProps) { if (prop in attrs) { let concat = concatProps[prop].slice(); object[prop] = concat.concat(attrs[prop]); } } } if (this.hasMergedProperties) { let mergedProps = this.mergedProperties; for (let prop in mergedProps) { if (prop in attrs) { let merged = assign({}, mergedProps[prop]); object[prop] = assign(merged, attrs[prop]); } } } } addStaticMixin(mixin: Mixin) { this.staticMixins.push(mixin); } addMixin(mixin: Mixin) { this.mixins.push(mixin); } getStaticMixins(): Mixin[] { return this.staticMixins; } getMixins(): Mixin[] { return this.mixins; } addAppliedMixin(mixin: Mixin) { this.appliedMixins.push(mixin); } hasAppliedMixin(mixin: Mixin): boolean { return this.appliedMixins.indexOf(mixin) !== -1; } getAppliedMixins(): Mixin[] { return this.appliedMixins; } hasStaticMixin(mixin: Mixin): boolean { return this.staticMixins.indexOf(mixin) !== -1; } static applyAllMixins(Subclass: GlimmerObjectFactory<any>, Parent: GlimmerObjectFactory<any>) { Subclass[CLASS_META].getMixins().forEach(m => m.extendPrototypeOnto(Subclass, Parent)); Subclass[CLASS_META].getStaticMixins().forEach(m => m.extendStatic(Subclass)); Subclass[CLASS_META].seal(); } addSubclass(constructor: GlimmerObjectFactory<any>) { this.subclasses.push(constructor); } getSubclasses(): Function[] { return this.subclasses; } addPropertyMetadata(property: string, value: any) { this.propertyMetadata[property] = value; } metadataForProperty(property: string): Object { return this.propertyMetadata[property]; } addReferenceTypeFor(property: string, type: InnerReferenceFactory<any>) { this.referenceTypes[property] = type; } addSlotFor(property: string) { this.slots.push(property); } hasConcatenatedProperty(property: string): boolean { if (!this.hasConcatenatedProperties) return false; return <string>property in this.concatenatedProperties; } getConcatenatedProperty(property: string): any[] { return this.concatenatedProperties[property]; } getConcatenatedProperties(): string[] { return <string[]>Object.keys(this.concatenatedProperties); } addConcatenatedProperty(property: string, value: any) { this.hasConcatenatedProperties = true; if (<string>property in this.concatenatedProperties) { let val = this.concatenatedProperties[property].concat(value); this.concatenatedProperties[property] = val; } else { this.concatenatedProperties[property] = value; } } hasMergedProperty(property: string): boolean { if (!this.hasMergedProperties) return false; return <string>property in this.mergedProperties; } getMergedProperty(property: string): Object { return this.mergedProperties[property]; } getMergedProperties(): string[] { return <string[]>Object.keys(this.mergedProperties); } addMergedProperty(property: string, value: Object) { this.hasMergedProperties = true; if (isArray(value)) { throw new Error(`You passed in \`${JSON.stringify(value)}\` as the value for \`foo\` but \`foo\` cannot be an Array`); } if (<string>property in this.mergedProperties && this.mergedProperties[property] && value) { this.mergedProperties[property] = mergeMergedProperties(value, this.mergedProperties[property]); } else { value = value === null ? value : value || {}; this.mergedProperties[property] = value; } } getReferenceTypes(): Dict<InnerReferenceFactory<any>> { return this.referenceTypes; } getPropertyMetadata(): Dict<any> { return this.propertyMetadata; } reset(parent: ClassMeta) { this.referenceTypes = dict<InnerReferenceFactory<any>>(); this.propertyMetadata = dict(); this.concatenatedProperties = dict<any[]>(); this.mergedProperties = dict<Object>(); if (parent) { this.hasConcatenatedProperties = parent.hasConcatenatedProperties; for (let prop in parent.concatenatedProperties) { this.concatenatedProperties[prop] = parent.concatenatedProperties[prop].slice(); } this.hasMergedProperties = parent.hasMergedProperties; for (let prop in parent.mergedProperties) { this.mergedProperties[prop] = assign({}, parent.mergedProperties[prop]); } assign(this.referenceTypes, parent.referenceTypes); assign(this.propertyMetadata, parent.propertyMetadata); } } reseal(obj: Object) { let meta = Meta.for(obj); let fresh = new this.InstanceMetaConstructor(obj, {}); let referenceTypes = meta.getReferenceTypes(); let slots = meta.getSlots(); turbocharge(assign(referenceTypes, this.referenceTypes)); turbocharge(assign(slots, fresh.getSlots())); } seal() { let referenceTypes: Dict<InnerReferenceFactory<any>> = turbocharge(assign({}, this.referenceTypes)); turbocharge(this.concatenatedProperties); turbocharge(this.mergedProperties); if (!this.hasMergedProperties && !this.hasConcatenatedProperties) { this.init = function() {}; } let slots = this.slots; class Slots { constructor() { slots.forEach(name => { this[name] = EMPTY_CACHE; }); } } this.InstanceMetaConstructor = class extends SealedMeta { protected slots: Slots = new Slots(); public referenceTypes: Dict<InnerReferenceFactory<any>> = referenceTypes; getReferenceTypes() { return this.referenceTypes; } referenceTypeFor(property: string): InnerReferenceFactory<any> { return this.referenceTypes[property] || PropertyReference; } getSlots() { return this.slots; } }; turbocharge(this); } } function mergeMergedProperties(attrs: Object, parent: Object) { let merged = assign({}, parent); for (let prop in attrs) { if (prop in parent && typeof parent[prop] === 'function' && typeof attrs[prop] === 'function') { let wrapped = wrapMethod(parent, prop, attrs[prop]); merged[prop] = wrapped; } else { merged[prop] = attrs[prop]; } } return merged; } export class InstanceMeta extends ClassMeta { public "df8be4c8-4e89-44e2-a8f9-550c8dacdca7": ClassMeta = ClassMeta.fromParent(null); static fromParent(parent: InstanceMeta): InstanceMeta { return <InstanceMeta>super.fromParent(parent); } reset(parent: InstanceMeta) { super.reset(parent); if (parent) this[CLASS_META].reset(parent[CLASS_META]); } seal() { super.seal(); this[CLASS_META].seal(); } } export default class GlimmerObject { static "df8be4c8-4e89-44e2-a8f9-550c8dacdca7": InstanceMeta = InstanceMeta.fromParent(null); static isClass = true; static extend(): typeof GlimmerObject; static extend<T>(extension: T): typeof GlimmerObject; static extend(...extensions: Object[]): typeof GlimmerObject; static extend(...extensions) { return extendClass(this, ...extensions); } static create(attrs?: Object): GlimmerObject { return new this(attrs); } static reopen<U>(extensions: U) { toMixin(extensions).extendPrototype(this); this[CLASS_META].seal(); relinkSubclasses(this); } static reopenClass(extensions: Object) { toMixin(extensions).extendStatic(this); this[CLASS_META].seal(); } static metaForProperty(property: string): Object { let value = this[CLASS_META].metadataForProperty(property); if (!value) throw new Error(`metaForProperty() could not find a computed property with key '${property}'.`); return value; } static eachComputedProperty(callback: (string, Object) => void) { let metadata = this[CLASS_META].getPropertyMetadata(); if (!metadata) return; for (let prop in metadata) { callback(prop, metadata[prop]); } } _super = ROOT; _meta = null; _guid: number; init() {} constructor(attrs?: Object) { if (attrs) assign(this, attrs); (<typeof GlimmerObject>this.constructor)[CLASS_META].init(this, attrs); this._super = ROOT; initializeGuid(this); this.init(); } get(key: string): any { return this[key]; } set(key: string, value: any) { this[key] = value; } setProperties(attrs: Object) { assign(this, attrs); } destroy() {} }