UNPKG

ember-app-scheduler

Version:

Ember addon to schedule work at different phases of app life cycle.

239 lines 6.73 kB
import { dict, EMPTY_ARRAY } from '@glimmer/util'; import { combineTagged } from '@glimmer/reference'; import { PrimitiveReference, UNDEFINED_REFERENCE } from '../references'; export class Arguments { constructor() { this.stack = null; this.positional = new PositionalArguments(); this.named = new NamedArguments(); } empty() { this.setup(null, true); return this; } setup(stack, synthetic) { this.stack = stack; let names = stack.fromTop(0); let namedCount = names.length; let positionalCount = stack.fromTop(namedCount + 1); let start = positionalCount + namedCount + 2; let positional = this.positional; positional.setup(stack, start, positionalCount); let named = this.named; named.setup(stack, namedCount, names, synthetic); } get tag() { return combineTagged([this.positional, this.named]); } get length() { return this.positional.length + this.named.length; } at(pos) { return this.positional.at(pos); } get(name) { return this.named.get(name); } capture() { return { tag: this.tag, length: this.length, positional: this.positional.capture(), named: this.named.capture() }; } clear() { let { stack, length } = this; stack.pop(length + 2); } } class PositionalArguments { constructor() { this.length = 0; this.stack = null; this.start = 0; this._tag = null; this._references = null; } setup(stack, start, length) { this.stack = stack; this.start = start; this.length = length; this._tag = null; this._references = null; } get tag() { let tag = this._tag; if (!tag) { tag = this._tag = combineTagged(this.references); } return tag; } at(position) { let { start, length } = this; if (position < 0 || position >= length) { return UNDEFINED_REFERENCE; } // stack: pos1, pos2, pos3, named1, named2 // start: 4 (top - 4) // // at(0) === pos1 === top - start // at(1) === pos2 === top - (start - 1) // at(2) === pos3 === top - (start - 2) let fromTop = start - position - 1; return this.stack.fromTop(fromTop); } capture() { return new CapturedPositionalArguments(this.tag, this.references); } get references() { let references = this._references; if (!references) { let { length } = this; references = this._references = new Array(length); for (let i = 0; i < length; i++) { references[i] = this.at(i); } } return references; } } class CapturedPositionalArguments { constructor(tag, references, length = references.length) { this.tag = tag; this.references = references; this.length = length; } at(position) { return this.references[position]; } value() { return this.references.map(this.valueOf); } get(name) { let { references, length } = this; if (name === 'length') { return PrimitiveReference.create(length); } else { let idx = parseInt(name, 10); if (idx < 0 || idx >= length) { return UNDEFINED_REFERENCE; } else { return references[idx]; } } } valueOf(reference) { return reference.value(); } } class NamedArguments { constructor() { this.length = 0; this._tag = null; this._references = null; this._names = null; this._realNames = EMPTY_ARRAY; } setup(stack, length, names, synthetic) { this.stack = stack; this.length = length; this._tag = null; this._references = null; if (synthetic) { this._names = names; this._realNames = EMPTY_ARRAY; } else { this._names = null; this._realNames = names; } } get tag() { return combineTagged(this.references); } get names() { let names = this._names; if (!names) { names = this._names = this._realNames.map(this.sliceName); } return names; } has(name) { return this.names.indexOf(name) !== -1; } get(name) { let { names, length } = this; let idx = names.indexOf(name); if (idx === -1) { return UNDEFINED_REFERENCE; } // stack: pos1, pos2, pos3, named1, named2 // start: 4 (top - 4) // namedDict: { named1: 1, named2: 0 }; // // get('named1') === named1 === top - (start - 1) // get('named2') === named2 === top - start let fromTop = length - idx; return this.stack.fromTop(fromTop); } capture() { return new CapturedNamedArguments(this.tag, this.names, this.references); } get references() { let references = this._references; if (!references) { let { names, length } = this; references = this._references = []; for (let i = 0; i < length; i++) { references[i] = this.get(names[i]); } } return references; } sliceName(name) { return name.slice(1); } } class CapturedNamedArguments { constructor(tag, names, references) { this.tag = tag; this.names = names; this.references = references; this.length = names.length; this._map = null; } get map() { let map = this._map; if (!map) { let { names, references } = this; map = this._map = dict(); for (let i = 0; i < names.length; i++) { let name = names[i]; map[name] = references[i]; } } return map; } has(name) { return this.names.indexOf(name) !== -1; } get(name) { let { names, references } = this; let idx = names.indexOf(name); if (idx === -1) { return UNDEFINED_REFERENCE; } else { return references[idx]; } } value() { let { names, references } = this; let out = dict(); for (let i = 0; i < names.length; i++) { let name = names[i]; out[name] = references[i].value(); } return out; } } export default new Arguments();