Skip to content

Commit

Permalink
[FEATURE dynamic-helper-and-modifier] Enable dynamic helper usage
Browse files Browse the repository at this point in the history
Enables dynamic helper usage based on either helper definitions
directly, or currying helpers with the (helper) keyword.
  • Loading branch information
Chris Garrett committed Dec 16, 2020
1 parent 9588535 commit f8339c3
Show file tree
Hide file tree
Showing 26 changed files with 384 additions and 1,228 deletions.
24 changes: 12 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,19 @@
},
"devDependencies": {
"@babel/preset-env": "^7.9.5",
"@glimmer/compiler": "0.70.0",
"@glimmer/compiler": "0.71.1",
"@glimmer/env": "^0.1.7",
"@glimmer/global-context": "0.70.0",
"@glimmer/interfaces": "0.70.0",
"@glimmer/manager": "0.70.0",
"@glimmer/destroyable": "0.70.0",
"@glimmer/owner": "0.70.0",
"@glimmer/node": "0.70.0",
"@glimmer/opcode-compiler": "0.70.0",
"@glimmer/program": "0.70.0",
"@glimmer/reference": "0.70.0",
"@glimmer/runtime": "0.70.0",
"@glimmer/validator": "0.70.0",
"@glimmer/global-context": "0.71.1",
"@glimmer/interfaces": "0.71.1",
"@glimmer/manager": "0.71.1",
"@glimmer/destroyable": "0.71.1",
"@glimmer/owner": "0.71.1",
"@glimmer/node": "0.71.1",
"@glimmer/opcode-compiler": "0.71.1",
"@glimmer/program": "0.71.1",
"@glimmer/reference": "0.71.1",
"@glimmer/runtime": "0.71.1",
"@glimmer/validator": "0.71.1",
"@simple-dom/document": "^1.4.0",
"@types/qunit": "^2.9.1",
"@types/rsvp": "^4.0.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ export default class InternalManager
implements
InternalComponentManager<InternalComponentState, EmberInternalComponentConstructor>,
WithCreateInstance {
static for(definition: EmberInternalComponentConstructor, name: string): () => InternalManager {
return () => new InternalManager(definition, name);
}

constructor(private ComponentClass: EmberInternalComponentConstructor, private name: string) {}

getCapabilities(): InternalComponentCapabilities {
Expand Down
2 changes: 1 addition & 1 deletion packages/@ember/-internals/glimmer/lib/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,6 @@ Component.reopenClass({
positionalParams: [],
});

setInternalComponentManager(() => CURLY_COMPONENT_MANAGER, Component);
setInternalComponentManager(CURLY_COMPONENT_MANAGER, Component);

export default Component;
2 changes: 1 addition & 1 deletion packages/@ember/-internals/glimmer/lib/components/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export const InputComponent = {
},
};

setInternalComponentManager(InternalManager.for(Input, 'input'), InputComponent);
setInternalComponentManager(new InternalManager(Input, 'input'), InputComponent);
setComponentTemplate(InputTemplate, InputComponent);

Input.toString = () => '@ember/component/input';
8 changes: 4 additions & 4 deletions packages/@ember/-internals/glimmer/lib/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { getDebugName, symbol } from '@ember/-internals/utils';
import { join } from '@ember/runloop';
import { DEBUG } from '@glimmer/env';
import { Arguments, Dict, HelperManager } from '@glimmer/interfaces';
import { helperCapabilities, setHelperManager } from '@glimmer/manager';
import { getInternalHelperManager, helperCapabilities, setHelperManager } from '@glimmer/manager';
import {
consumeTag,
createTag,
Expand Down Expand Up @@ -195,11 +195,11 @@ class ClassicHelperManager implements HelperManager<ClassicHelperStateBucket> {
}
}

export const CLASSIC_HELPER_MANAGER_FACTORY = (owner: Owner | undefined): ClassicHelperManager => {
setHelperManager((owner: Owner | undefined): ClassicHelperManager => {
return new ClassicHelperManager(owner);
};
}, Helper);

setHelperManager(CLASSIC_HELPER_MANAGER_FACTORY, Helper);
export const CLASSIC_HELPER_MANAGER = getInternalHelperManager(Helper);

///////////

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ import { Helper, HelperDefinitionState } from '@glimmer/interfaces';
import { setInternalHelperManager } from '@glimmer/manager';

export function internalHelper(helper: Helper): HelperDefinitionState {
return setInternalHelperManager(() => helper, {});
return setInternalHelperManager(helper, {});
}
4 changes: 3 additions & 1 deletion packages/@ember/-internals/glimmer/lib/modifiers/action.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Owner } from '@ember/-internals/owner';
import { uuid } from '@ember/-internals/utils';
import { ActionManager, isSimpleClick } from '@ember/-internals/views';
import { assert, deprecate } from '@ember/debug';
Expand Down Expand Up @@ -204,6 +205,7 @@ export class ActionState {

class ActionModifierManager implements InternalModifierManager<ActionState, object> {
create(
_owner: Owner,
element: SimpleElement,
_state: object,
args: VMArguments,
Expand Down Expand Up @@ -312,4 +314,4 @@ class ActionModifierManager implements InternalModifierManager<ActionState, obje

const ACTION_MODIFIER_MANAGER = new ActionModifierManager();

export default setInternalModifierManager(() => ACTION_MODIFIER_MANAGER, {});
export default setInternalModifierManager(ACTION_MODIFIER_MANAGER, {});
12 changes: 4 additions & 8 deletions packages/@ember/-internals/glimmer/lib/modifiers/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,23 +63,19 @@ class InternalModifierState implements Destroyable {

class InternalModifierManager
implements ModifierManager<InternalModifierState, typeof InternalModifier> {
constructor(private readonly owner: Owner) {}

create(
owner: Owner,
element: SimpleElement,
factory: typeof InternalModifier,
args: VMArguments
): InternalModifierState {
assert('element must be an HTMLElement', element instanceof HTMLElement);

let instance = new factory(this.owner, element, args.capture());
let instance = new factory(owner, element, args.capture());

registerDestructor(instance, (modifier) => modifier.remove());

return new InternalModifierState(
factory.name,
new factory(this.owner, element, args.capture())
);
return new InternalModifierState(factory.name, instance);
}

// not needed for now, but feel free to implement this
Expand All @@ -105,4 +101,4 @@ class InternalModifierManager
}
}

setInternalModifierManager((owner: Owner) => new InternalModifierManager(owner), InternalModifier);
setInternalModifierManager(new InternalModifierManager(), InternalModifier);
4 changes: 3 additions & 1 deletion packages/@ember/-internals/glimmer/lib/modifiers/on.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Owner } from '@ember/-internals/owner';
import { assert } from '@ember/debug';
import { registerDestructor } from '@glimmer/destroyable';
import { DEBUG } from '@glimmer/env';
Expand Down Expand Up @@ -322,6 +323,7 @@ class OnModifierManager implements InternalModifierManager<OnModifierState | nul
}

create(
_owner: Owner,
element: SimpleElement | Element,
_state: object,
args: VMArguments
Expand Down Expand Up @@ -387,6 +389,6 @@ const ON_MODIFIER_MANAGER = new OnModifierManager();

const on = {};

setInternalModifierManager(() => ON_MODIFIER_MANAGER, on);
setInternalModifierManager(ON_MODIFIER_MANAGER, on);

export default on;
12 changes: 5 additions & 7 deletions packages/@ember/-internals/glimmer/lib/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,12 @@ import {
import { _WeakSet } from '@glimmer/util';
import { isCurlyManager } from './component-managers/curly';
import {
CLASSIC_HELPER_MANAGER_FACTORY,
CLASSIC_HELPER_MANAGER,
HelperFactory,
HelperInstance,
isClassicHelper,
SimpleHelper,
} from './helper';
import { default as componentAssertionHelper } from './helpers/-assert-implicit-component-helper-argument';
import { default as inElementNullCheckHelper } from './helpers/-in-element-null-check';
import { default as normalizeClassHelper } from './helpers/-normalize-class';
import { default as trackArray } from './helpers/-track-array';
Expand Down Expand Up @@ -193,7 +192,6 @@ const BUILTIN_KEYWORD_HELPERS = {
'-get-dynamic-var': internalHelper(getDynamicVar),
'-mount': mountHelper,
'-outlet': outletHelper,
'-assert-implicit-component-helper-argument': componentAssertionHelper,
'-in-el-null': inElementNullCheckHelper,
};

Expand Down Expand Up @@ -267,10 +265,10 @@ export default class ResolverImpl implements RuntimeResolver<Owner>, CompileTime
// we'll trigger an assertion
if (!CLASSIC_HELPER_MANAGER_ASSOCIATED.has(factory)) {
CLASSIC_HELPER_MANAGER_ASSOCIATED.add(factory);
setInternalHelperManager(CLASSIC_HELPER_MANAGER_FACTORY, factory);
setInternalHelperManager(CLASSIC_HELPER_MANAGER, factory);
}
} else {
setInternalHelperManager(CLASSIC_HELPER_MANAGER_FACTORY, factory);
setInternalHelperManager(CLASSIC_HELPER_MANAGER, factory);
}

return factory;
Expand Down Expand Up @@ -345,7 +343,7 @@ export default class ResolverImpl implements RuntimeResolver<Owner>, CompileTime
};
} else {
let factory = owner.factoryFor(P`component:-default`)!;
let manager = getInternalComponentManager(owner, factory.class as object);
let manager = getInternalComponentManager(factory.class as object);

definition = {
state: factory,
Expand All @@ -358,7 +356,7 @@ export default class ResolverImpl implements RuntimeResolver<Owner>, CompileTime

let factory = pair.component;
let ComponentClass = factory.class!;
let manager = getInternalComponentManager(owner, ComponentClass);
let manager = getInternalComponentManager(ComponentClass);

definition = {
state: isCurlyManager(manager) ? factory : ComponentClass,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1319,20 +1319,6 @@ moduleFor(
this.assertStableRerender();
}

['@test GH#17121 implicit component invocations should not perform string lookup']() {
this.registerComponent('foo-bar', { template: 'foo-bar component' });

expectAssertion(
() =>
this.render(strip`
{{#let 'foo-bar' as |foo|}}
{{foo 1 2 3}}
{{/let}}
`),
"expected `foo` to be a contextual component but found a string. Did you mean `(component foo)`? ('-top-level' @ L1:C29) "
);
}

['@test RFC#311 invoking named args (without arguments)']() {
this.registerComponent('x-outer', { template: '{{@inner}}' });
this.registerComponent('x-inner', { template: 'inner' });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
on,
fn,
} from '@ember/-internals/glimmer';
import GlimmerishComponent from '../../utils/glimmerish-component';

if (EMBER_STRICT_MODE) {
moduleFor(
Expand Down Expand Up @@ -89,6 +90,69 @@ if (EMBER_STRICT_MODE) {
this.assertHTML('foobar');
this.assertStableRerender();
}

'@test Can use a dynamic component definition'() {
let Foo = defineComponent({}, 'Hello, world!');
let Bar = defineComponent(
{},
'<this.Foo/>',
class extends GlimmerishComponent {
Foo = Foo;
}
);

this.registerComponent('bar', { ComponentClass: Bar });

this.render('<Bar/>');
this.assertHTML('Hello, world!');
this.assertStableRerender();
}

'@test Can use a dynamic component definition (curly)'() {
let Foo = defineComponent({}, 'Hello, world!');
let Bar = defineComponent(
{},
'{{this.Foo}}',
class extends GlimmerishComponent {
Foo = Foo;
}
);

this.registerComponent('bar', { ComponentClass: Bar });

this.render('<Bar/>');
this.assertHTML('Hello, world!');
this.assertStableRerender();
}

'@test Can use a dynamic helper definition'() {
let foo = defineSimpleHelper(() => 'Hello, world!');
let Bar = defineComponent(
{},
'{{this.foo}}',
class extends GlimmerishComponent {
foo = foo;
}
);

this.registerComponent('bar', { ComponentClass: Bar });

this.render('<Bar/>');
this.assertHTML('Hello, world!');
this.assertStableRerender();
}

'@feature(EMBER_DYNAMIC_HELPERS_AND_MODIFIERS) Can use a curried dynamic helper'() {
let foo = defineSimpleHelper((value) => value);
let Foo = defineComponent({}, '{{@value}}');
let Bar = defineComponent({ Foo, foo }, '<Foo @value={{foo "Hello, world!"}}/>');

this.registerComponent('bar', { ComponentClass: Bar });

this.render('<Bar/>');
this.assertHTML('Hello, world!');
this.assertStableRerender();
}
}
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
import { DEBUG } from '@glimmer/env';

import { RenderingTestCase, moduleFor, runDestroy, runTask } from 'internal-test-helpers';
import { Helper } from '@ember/-internals/glimmer';
import {
RenderingTestCase,
moduleFor,
runDestroy,
runTask,
defineSimpleHelper,
} from 'internal-test-helpers';
import { Helper, Component } from '@ember/-internals/glimmer';
import { set, tracked } from '@ember/-internals/metal';
import { backtrackingMessageFor } from '../../utils/debug-stack';

Expand Down Expand Up @@ -769,6 +775,31 @@ moduleFor(
this.render('{{hello-world}}');
}, expectedMessage);
}

'@feature(EMBER_DYNAMIC_HELPERS_AND_MODIFIERS) Can use a curried dynamic helper'() {
let val = defineSimpleHelper((value) => value);

this.registerComponent('foo', {
template: '{{@value}}',
});

this.registerComponent('bar', {
template: '<Foo @value={{helper this.val "Hello, world!"}}/>',
ComponentClass: Component.extend({ val }),
});

this.render('<Bar/>');
this.assertText('Hello, world!');
this.assertStableRerender();
}

'@feature(!EMBER_DYNAMIC_HELPERS_AND_MODIFIERS) Can use a curried dynamic helper'() {
expectAssertion(() => {
this.registerComponent('bar', {
template: '<Foo @value={{helper this.val "Hello, world!"}}/>',
});
}, /Cannot use the \(helper\) keyword yet, as it has not been implemented/);
}
}
);

Expand Down
Loading

0 comments on commit f8339c3

Please sign in to comment.