Skip to content

Commit

Permalink
refactor(children): make children observation a binding (#1732)
Browse files Browse the repository at this point in the history
* refactor(children): make children deco as a hook

* refactor(children): remove children observers from custom element def

* refactor(children): cleanup children observer related code, rename to binding

* chore: fix test

* refactor(observers): remove intermediate vars

* refactor: ignore dev message coverage
  • Loading branch information
bigopon committed Apr 7, 2023
1 parent 3f37f8d commit 5bde983
Show file tree
Hide file tree
Showing 35 changed files with 301 additions and 301 deletions.
2 changes: 1 addition & 1 deletion examples/helloworld/rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { nodeResolve } from '@rollup/plugin-node-resolve';
import { terser } from '@rollup/plugin-terser';
import terser from '@rollup/plugin-terser';

/** @type {import('rollup').RollupOptions} */
export default {
Expand Down
22 changes: 22 additions & 0 deletions packages/__tests__/3-runtime-html/children-observer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,28 @@ describe('3-runtime-html/children-observer.spec.ts', function () {

au.dispose();
});

it('updates subscribers', async function () {
@customElement({
name: 'e-l',
template: 'child count: ${nodes.length}',
shadowOptions: { mode: 'open' }
})
class El {
@children('div') nodes: any[];
}
const { assertText } = createFixture(
'<e-l ref=el><div repeat.for="i of items">',
class App {
items = 3;
},
[El]
);

await new Promise(r => setTimeout(r, 50));

assertText('child count: 3');
});
});

function createAppAndStart(childrenOptions?: PartialChildrenDefinition) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,6 @@ describe('3-runtime-html/template-compiler.spec.ts', function () {
cache: 0,
dependencies: [],
bindables: {},
childrenObservers: {},
containerless: false,
injectable: null,
isStrictBinding: false,
Expand Down
5 changes: 2 additions & 3 deletions packages/aurelia/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,8 +499,7 @@ export {
Bindable,
coercer,

// PartialChildrenDefinition,
// ChildrenDefinition,
PartialChildrenDefinition,
// Children,
children,

Expand Down Expand Up @@ -683,7 +682,7 @@ export {
// DefaultComponents as RuntimeHtmlDefaultComponents,

// CompiledTemplate,
// ChildrenObserver,
ChildrenBinding,
// IRenderer,
// IInstructionTypeClassifier,
// IRenderingEngine,
Expand Down
4 changes: 4 additions & 0 deletions packages/runtime-html/src/aurelia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export class Aurelia implements IDisposable {
if (this._root == null) {
if (this.next == null) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0767: root is not defined`);
else
throw createError(`AUR0767`);
Expand All @@ -58,6 +59,7 @@ export class Aurelia implements IDisposable {
) {
if (container.has(IAurelia, true)) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0768: An instance of Aurelia is already registered with the container or an ancestor of it.`);
else
throw createError(`AUR0768`);
Expand Down Expand Up @@ -129,6 +131,7 @@ export class Aurelia implements IDisposable {
if (!this.container.has(IPlatform, false)) {
if (host.ownerDocument.defaultView === null) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0769: Failed to initialize the platform object. The host element's ownerDocument does not have a defaultView`);
else
throw createError(`AUR0769`);
Expand Down Expand Up @@ -197,6 +200,7 @@ export class Aurelia implements IDisposable {
public dispose(): void {
if (this._isRunning || this._isStopping) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0771: The aurelia instance must be fully stopped before it can be disposed`);
else
throw createError(`AUR0771`);
Expand Down
4 changes: 2 additions & 2 deletions packages/runtime-html/src/binding/interpolation-binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import type {
IsExpression, Scope
} from '@aurelia/runtime';
import type { IPlatform } from '../platform';
import { isArray } from '../utilities';
import { isArray, safeString } from '../utilities';
import type { IBindingController } from './interfaces-bindings';

const queueTaskOptions: QueueTaskOptions = {
Expand Down Expand Up @@ -346,7 +346,7 @@ export class ContentBinding implements IBinding, ICollectionSubscriber {
target.textContent = '';
target.parentNode?.insertBefore(value, target);
} else {
target.textContent = String(value);
target.textContent = safeString(value);
}
}

Expand Down
4 changes: 1 addition & 3 deletions packages/runtime-html/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,10 +387,8 @@ export {

export {
type PartialChildrenDefinition,
ChildrenDefinition,
Children,
children,
ChildrenObserver,
ChildrenBinding,
} from './templating/children';

// These exports are temporary until we have a proper way to unit test them
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { subscriberCollection, AccessorType } from '@aurelia/runtime';
import { createError, isString } from '../utilities';
import { createError, isString, safeString } from '../utilities';

import type {
IObserver,
Expand Down Expand Up @@ -100,7 +100,7 @@ export class AttributeObserver implements AttributeObserver, ElementMutationSubs
if (this._value == null) {
this._obj.removeAttribute(this._attr);
} else {
this._obj.setAttribute(this._attr, String(this._value));
this._obj.setAttribute(this._attr, safeString(this._value));
}
}
}
Expand Down
12 changes: 7 additions & 5 deletions packages/runtime-html/src/observation/observer-locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { SelectValueObserver } from './select-value-observer';
import { StyleAttributeAccessor } from './style-attribute-accessor';
import { ISVGAnalyzer } from './svg-analyzer';
import { ValueAttributeObserver } from './value-attribute-observer';
import { createError, createLookup, isDataAttribute, isString, objectAssign } from '../utilities';
import { createError, createLookup, isDataAttribute, isString, objectAssign, safeString } from '../utilities';
import { aliasRegistration, singletonRegistration } from '../utilities-di';

import type { IIndexable, IContainer } from '@aurelia/kernel';
Expand Down Expand Up @@ -348,9 +348,10 @@ export class NodeObserverLocator implements INodeObserverLocator {
// consider:
// - maybe add a adapter API to handle unknown obj/key combo
if (__DEV__)
throw createError(`AUR0652: Unable to observe property ${String(key)}. Register observation mapping with .useConfig().`);
/* istanbul ignore next */
throw createError(`AUR0652: Unable to observe property ${safeString(key)}. Register observation mapping with .useConfig().`);
else
throw createError(`AUR0652:${String(key)}`);
throw createError(`AUR0652:${safeString(key)}`);
} else {
// todo: probably still needs to get the property descriptor via getOwnPropertyDescriptor
// but let's start with simplest scenario
Expand All @@ -373,7 +374,8 @@ export function getCollectionObserver(collection: unknown, observerLocator: IObs

function throwMappingExisted(nodeName: string, key: PropertyKey): never {
if (__DEV__)
throw createError(`AUR0653: Mapping for property ${String(key)} of <${nodeName} /> already exists`);
/* istanbul ignore next */
throw createError(`AUR0653: Mapping for property ${safeString(key)} of <${nodeName} /> already exists`);
else
throw createError(`AUR0653:${String(key)}@${nodeName}`);
throw createError(`AUR0653:${safeString(key)}@${nodeName}`);
}
6 changes: 6 additions & 0 deletions packages/runtime-html/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ function getRefTarget(refHost: INode, refTargetName: string): object {
case 'view':
// todo: returns node sequences for fun?
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0750: Not supported API`);
else
throw createError(`AUR0750`);
Expand All @@ -432,6 +433,7 @@ function getRefTarget(refHost: INode, refTargetName: string): object {
const ceController = findElementControllerFor(refHost, { name: refTargetName });
if (ceController === void 0) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0751: Attempted to reference "${refTargetName}", but it was not found amongst the target's API.`);
else
throw createError(`AUR0751:${refTargetName}`);
Expand Down Expand Up @@ -579,6 +581,7 @@ export class CustomAttributeRenderer implements IRenderer {
def = ctxContainer.find(CustomAttribute, instruction.res);
if (def == null) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0753: Attribute ${instruction.res} is not registered in ${(renderingCtrl as Controller)['name']}.`);
else
throw createError(`AUR0753:${instruction.res}@${(renderingCtrl as Controller)['name']}`);
Expand Down Expand Up @@ -657,6 +660,7 @@ export class TemplateControllerRenderer implements IRenderer {
def = ctxContainer.find(CustomAttribute, instruction.res);
if (def == null) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0754: Attribute ${instruction.res} is not registered in ${(renderingCtrl as Controller)['name']}.`);
else
throw createError(`AUR0754:${instruction.res}@${(renderingCtrl as Controller)['name']}`);
Expand Down Expand Up @@ -1253,12 +1257,14 @@ class ViewFactoryProvider implements IResolver {
const f = this.f;
if (f === null) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR7055: Cannot resolve ViewFactory before the provider was prepared.`);
else
throw createError(`AUR7055`);
}
if (!isString(f.name) || f.name.length === 0) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0756: Cannot resolve ViewFactory without a (valid) name.`);
else
throw createError(`AUR0756`);
Expand Down
1 change: 1 addition & 0 deletions packages/runtime-html/src/resources/binding-behavior.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export const BindingBehavior = objectFreeze<BindingBehaviorKind>({
const def = getOwnMetadata(bbBaseName, Type) as BindingBehaviorDefinition<T>;
if (def === void 0) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0151: No definition found for type ${Type.name}`);
else
throw createError(`AUR0151:${Type.name}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export class AttrBindingBehavior implements BindingBehaviorInstance {
public bind(_scope: Scope, binding: IBinding): void {
if (!(binding instanceof PropertyBinding)) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AURxxxx: & attr can be only used on property binding. It's used on ${binding.constructor.name}`);
else
throw createError(`AURxxxx`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export class SelfBindingBehavior implements BindingBehaviorInstance {
public bind(_scope: Scope, binding: ListenerBinding): void {
if (!(binding instanceof ListenerBinding)) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0801: Self binding behavior only supports listener binding via trigger/capture command.`);
else
throw createError(`AUR0801`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ export class SignalBindingBehavior implements BindingBehaviorInstance {
public bind(scope: Scope, binding: IConnectableBinding, ...names: string[]): void {
if (!('handleChange' in binding)) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0817: The signal behavior can only be used with bindings that have a "handleChange" method`);
else
throw createError(`AUR0817`);
}
if (names.length === 0) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`AUR0818: At least one signal name must be passed to the signal behavior, e.g. "expr & signal:'my-signal'"`);
else
throw createError(`AUR0818`);
Expand Down
14 changes: 0 additions & 14 deletions packages/runtime-html/src/resources/binding-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,20 +151,6 @@ export const BindingCommand = objectFreeze<BindingCommandKind>({

return definition.Type as BindingCommandType<T>;
},
// getDefinition<T extends Constructable>(Type: T): BindingCommandDefinition<T> {
// const def = getOwnMetadata(cmdBaseName, Type);
// if (def === void 0) {
// if (__DEV__)
// throw createError(`AUR0758: No definition found for type ${Type.name}`);
// else
// throw createError(`AUR0758:${Type.name}`);
// }

// return def;
// },
// annotate<K extends keyof PartialBindingCommandDefinition>(Type: Constructable, prop: K, value: PartialBindingCommandDefinition[K]): void {
// defineMetadata(getAnnotationKeyFor(prop), value, Type);
// },
getAnnotation: getCommandAnnotation,
});

Expand Down
1 change: 1 addition & 0 deletions packages/runtime-html/src/resources/custom-attribute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ export const getAttributeDefinition = <T extends Constructable>(Type: T | Functi
const def = getOwnMetadata(caBaseName, Type) as CustomAttributeDefinition<T>;
if (def === void 0) {
if (__DEV__)
/* istanbul ignore next */
throw createError(`No definition found for type ${Type.name}`);
else
throw createError(`AUR0759:${Type.name}`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class Focus implements ICustomAttributeViewModel {
/**
* Invoked when the attribute is afterDetachChildren from the DOM.
*/
public afterDetachChildren(): void {
public detaching(): void {
const el = this._element;
el.removeEventListener('focus', this);
el.removeEventListener('blur', this);
Expand Down Expand Up @@ -102,6 +102,8 @@ export class Focus implements ICustomAttributeViewModel {

/**
* Focus/blur based on current value
*
* @internal
*/
private _apply(): void {
const el = this._element;
Expand All @@ -116,7 +118,8 @@ export class Focus implements ICustomAttributeViewModel {
}
}

/** @internal */ private get _isElFocused(): boolean {
/** @internal */
private get _isElFocused(): boolean {
return this._element === this._platform.document.activeElement;
}
}
Expand Down

0 comments on commit 5bde983

Please sign in to comment.