Skip to content

Commit

Permalink
[WIP] Modifier Manager
Browse files Browse the repository at this point in the history
  • Loading branch information
chadhietala committed Oct 22, 2018
1 parent 6d57f74 commit 64eadfe
Show file tree
Hide file tree
Showing 7 changed files with 363 additions and 5 deletions.
1 change: 1 addition & 0 deletions packages/@ember/-internals/glimmer/index.ts
Expand Up @@ -306,4 +306,5 @@ export { default as DebugStack } from './lib/utils/debug-stack';
export { default as OutletView } from './lib/views/outlet';
export { capabilities } from './lib/component-managers/custom';
export { setComponentManager, getComponentManager } from './lib/utils/custom-component-manager';
export { setModifierManager, getModifierManager } from './lib/utils/custom-modifier-manager';
export { isSerializationFirstNode } from './lib/utils/serialization-first-node-helpers';
109 changes: 109 additions & 0 deletions packages/@ember/-internals/glimmer/lib/modifiers/custom.ts
@@ -0,0 +1,109 @@
import { Factory } from '@ember/-internals/owner';
import { Dict, Opaque } from '@glimmer/interfaces';
import { Tag } from '@glimmer/reference';
import { Arguments, CapturedArguments, ModifierManager } from '@glimmer/runtime';

export interface CustomModifierDefinitionState<ModifierInstance> {
ModifierClass: Factory<ModifierInstance>;
name: string;
delegate: ModifierManagerDelegate<ModifierInstance>;
}

// Currently there are no capabilities for modifiers
export function capabilities() {
return {};
}

export class CustomModifierDefinition<ModifierInstance> {
public state: CustomModifierDefinitionState<ModifierInstance>;
public manager = CUSTOM_MODIFIER_MANAGER;
constructor(
public name: string,
ModifierClass: Factory<ModifierInstance>,
public delegate: ModifierManagerDelegate<ModifierInstance>
) {
this.state = {
ModifierClass,
name,
delegate,
};
}
}

export class CustomModifierState<ModifierInstance> {
constructor(
public element: Element,
public delegate: ModifierManagerDelegate<ModifierInstance>,
public modifier: ModifierInstance,
public args: CapturedArguments
) {}

destroy() {
const { delegate, modifier, args } = this;
let modifierArgs = valueForCapturedArgs(args);
delegate.destroyModifier(modifier, modifierArgs);
}
}

export interface CustomModifierManagerArgs {
named: Dict<Opaque>;
positional: Opaque[];
}

export interface ModifierManagerDelegate<ModifierInstance> {
createModifier(factory: Opaque, args: CustomModifierManagerArgs): ModifierInstance;
installModifier(
instance: ModifierInstance,
element: Element,
args: CustomModifierManagerArgs
): void;
updateModifier(instance: ModifierInstance, args: CustomModifierManagerArgs): void;
destroyModifier(instance: ModifierInstance, args: CustomModifierManagerArgs): void;
}

function valueForCapturedArgs(args: CapturedArguments): CustomModifierManagerArgs {
return {
named: args.named.value(),
positional: args.positional.value(),
};
}

class CustomModifierManager<ModifierInstance>
implements
ModifierManager<
CustomModifierState<ModifierInstance>,
CustomModifierDefinitionState<ModifierInstance>
> {
create(
element: Element,
definition: CustomModifierDefinitionState<ModifierInstance>,
args: Arguments
) {
const capturedArgs = args.capture();
let modifierArgs = valueForCapturedArgs(capturedArgs);
let instance = definition.delegate.createModifier(definition.ModifierClass, modifierArgs);
return new CustomModifierState(element, definition.delegate, instance, capturedArgs);
}

getTag({ args }: CustomModifierState<ModifierInstance>): Tag {
return args.tag;
}

install(state: CustomModifierState<ModifierInstance>) {
let { element, args, delegate, modifier } = state;
let modifierArgs = valueForCapturedArgs(args);
delegate.installModifier(modifier, element, modifierArgs);
}

update(state: CustomModifierState<ModifierInstance>) {
let { args, delegate, modifier } = state;
let modifierArgs = valueForCapturedArgs(args);
delegate.updateModifier(modifier, modifierArgs);
}

getDestructor(state: CustomModifierState<ModifierInstance>) {
return state;
}
}

const CUSTOM_MODIFIER_MANAGER = new CustomModifierManager();
36 changes: 31 additions & 5 deletions packages/@ember/-internals/glimmer/lib/resolver.ts
Expand Up @@ -2,7 +2,11 @@ import { privatize as P } from '@ember/-internals/container';
import { ENV } from '@ember/-internals/environment';
import { LookupOptions, Owner, setOwner } from '@ember/-internals/owner';
import { lookupComponent, lookupPartial, OwnedTemplateMeta } from '@ember/-internals/views';
import { EMBER_MODULE_UNIFICATION, GLIMMER_CUSTOM_COMPONENT_MANAGER } from '@ember/canary-features';
import {
EMBER_MODULE_UNIFICATION,
GLIMMER_CUSTOM_COMPONENT_MANAGER,
GLIMMER_MODIFIER_MANAGER,
} from '@ember/canary-features';
import { assert } from '@ember/debug';
import { _instrumentStart } from '@ember/instrumentation';
import { DEBUG } from '@glimmer/env';
Expand Down Expand Up @@ -37,11 +41,13 @@ import { default as queryParams } from './helpers/query-param';
import { default as readonly } from './helpers/readonly';
import { default as unbound } from './helpers/unbound';
import ActionModifierManager from './modifiers/action';
import { CustomModifierDefinition } from './modifiers/custom';
import { populateMacros } from './syntax';
import { mountHelper } from './syntax/mount';
import { outletHelper } from './syntax/outlet';
import { Factory as TemplateFactory, Injections, OwnedTemplate } from './template';
import { getComponentManager } from './utils/custom-component-manager';
import { getModifierManager } from './utils/custom-modifier-manager';
import { ClassBasedHelperReference, SimpleHelperReference } from './utils/references';

function instrumentationPayload(name: string) {
Expand Down Expand Up @@ -175,8 +181,8 @@ export default class RuntimeResolver implements IRuntimeResolver<OwnedTemplateMe
/**
* Called by CompileTimeLookup compiling the
*/
lookupModifier(name: string, _meta: OwnedTemplateMeta): Option<number> {
return this.handle(this._lookupModifier(name));
lookupModifier(name: string, meta: OwnedTemplateMeta): Option<number> {
return this.handle(this._lookupModifier(name, meta));
}

/**
Expand Down Expand Up @@ -272,8 +278,28 @@ export default class RuntimeResolver implements IRuntimeResolver<OwnedTemplateMe
}
}

private _lookupModifier(name: string) {
return this.builtInModifiers[name];
private _lookupModifier(name: string, meta: OwnedTemplateMeta) {
let builtin = this.builtInModifiers[name];

if (GLIMMER_MODIFIER_MANAGER && builtin === undefined) {
let { owner } = meta;
let modifier = owner.factoryFor(`modifier:${name}`);
if (modifier !== undefined) {
let managerFactory = getModifierManager(modifier.class);
assert(
`Could not find custom modifier manager for '${name}' which was specified by ${
modifier.class
}`,
!!managerFactory
);

let manager = managerFactory!(owner);

return new CustomModifierDefinition(name, modifier, manager);
}
}

return builtin;
}

private _parseNameForNamespace(_name: string) {
Expand Down
@@ -0,0 +1,32 @@
import { Owner } from '@ember/-internals/owner';
import { GLIMMER_MODIFIER_MANAGER } from '@ember/canary-features';
import { Opaque } from '@glimmer/util';
import { ModifierManagerDelegate } from '../modifiers/custom';

const getPrototypeOf = Object.getPrototypeOf;

export type ModifierManagerFactory = (owner: Owner) => ModifierManagerDelegate<Opaque>;

const MANAGERS: WeakMap<any, ModifierManagerFactory> = new WeakMap();

export function setModifierManager(factory: ModifierManagerFactory, obj: any) {
MANAGERS.set(obj, factory);
return obj;
}

export function getModifierManager(obj: any): undefined | ModifierManagerFactory {
if (!GLIMMER_MODIFIER_MANAGER) {
return;
}

let pointer = obj;
while (pointer !== undefined && pointer !== null) {
if (MANAGERS.has(pointer)) {
return MANAGERS.get(pointer);
}

pointer = getPrototypeOf(pointer);
}

return;
}

0 comments on commit 64eadfe

Please sign in to comment.