diff --git a/packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts b/packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts index ad78b676ef..d46311166d 100644 --- a/packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts +++ b/packages/@glimmer-workspace/integration-tests/test/debug-render-tree-test.ts @@ -25,7 +25,7 @@ import { JitRenderDelegate, RenderTest, suite, - test, + test, tracked, } from '..'; interface CapturedBounds { @@ -90,7 +90,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.delegate.getInitialElement().firstChild), @@ -104,7 +104,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.delegate.getInitialElement().firstChild), @@ -113,7 +113,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'second' } }, + args: { positional: [], named: { arg: 'second' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.delegate.getInitialElement().lastChild), @@ -127,7 +127,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.delegate.getInitialElement().firstChild), @@ -138,19 +138,36 @@ class DebugRenderTreeTest extends RenderTest { @test 'emberish curly components'() { this.registerComponent('Curly', 'HelloWorld', 'Hello World'); + let error: Error|null = null; + class State { + @tracked doFail = false; + get getterWithError() { + if (!this.doFail) return; + error = new Error('error'); + throw error; + } + } + const obj = new State(); this.render( - `{{#if this.showSecond}}{{/if}}`, + `{{#if this.showSecond}}{{/if}}`, { showSecond: false, + obj, } ); + obj.doFail = true; + + this.delegate.getCapturedRenderTree(); + + this.assert.ok(error !== null, 'expecting an Error'); + this.assertRenderTree([ { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first', arg2: error }, errors: { arg2: error! } }, instance: (instance: EmberishCurlyComponent) => (instance as any).arg === 'first', template: '(unknown template module)', bounds: this.nodeBounds(this.delegate.getInitialElement().firstChild), @@ -158,13 +175,15 @@ class DebugRenderTreeTest extends RenderTest { }, ]); + obj.doFail = false; + this.rerender({ showSecond: true }); this.assertRenderTree([ { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first', arg2: undefined }, errors: {} }, instance: (instance: EmberishCurlyComponent) => (instance as any).arg === 'first', template: '(unknown template module)', bounds: this.nodeBounds(this.element.firstChild), @@ -173,7 +192,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'second' } }, + args: { positional: [], named: { arg: 'second' }, errors: {} }, instance: (instance: EmberishCurlyComponent) => (instance as any).arg === 'second', template: '(unknown template module)', bounds: this.nodeBounds(this.element.lastChild), @@ -187,7 +206,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first', arg2: undefined }, errors: {} }, instance: (instance: EmberishCurlyComponent) => (instance as any).arg === 'first', template: '(unknown template module)', bounds: this.nodeBounds(this.element.firstChild), @@ -210,7 +229,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: (instance: GlimmerishComponent) => instance.args['arg'] === 'first', template: '(unknown template module)', bounds: this.nodeBounds(this.delegate.getInitialElement().firstChild), @@ -224,7 +243,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: (instance: GlimmerishComponent) => instance.args['arg'] === 'first', template: '(unknown template module)', bounds: this.nodeBounds(this.element.firstChild), @@ -233,7 +252,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'second' } }, + args: { positional: [], named: { arg: 'second' }, errors: {} }, instance: (instance: GlimmerishComponent) => instance.args['arg'] === 'second', template: '(unknown template module)', bounds: this.nodeBounds(this.element.lastChild), @@ -247,7 +266,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: (instance: GlimmerishComponent) => instance.args['arg'] === 'first', template: '(unknown template module)', bounds: this.nodeBounds(this.element.firstChild), @@ -307,7 +326,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld2', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.delegate.getInitialElement().firstChild), @@ -321,7 +340,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld2', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.element.firstChild), @@ -330,7 +349,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'route-template', name: 'foo', - args: { positional: [], named: { arg: 'second' } }, + args: { positional: [], named: { arg: 'second' }, errors: {} }, instance: instance1, template: null, bounds: this.nodeBounds(this.element.lastChild), @@ -338,7 +357,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'engine', name: 'bar', - args: { positional: [], named: {} }, + args: { positional: [], named: {}, errors: {} }, instance: instance2, template: null, bounds: this.nodeBounds(this.element.lastChild), @@ -354,7 +373,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld2', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.element.firstChild), @@ -387,7 +406,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld2', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.delegate.getInitialElement().firstChild), @@ -401,7 +420,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld2', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.element.firstChild), @@ -415,7 +434,7 @@ class DebugRenderTreeTest extends RenderTest { { type: 'component', name: 'HelloWorld2', - args: { positional: [], named: { arg: 'first' } }, + args: { positional: [], named: { arg: 'first' }, errors: {} }, instance: null, template: '(unknown template module)', bounds: this.nodeBounds(this.element.firstChild), diff --git a/packages/@glimmer/interfaces/lib/runtime/arguments.d.ts b/packages/@glimmer/interfaces/lib/runtime/arguments.d.ts index 4b0f267082..db4bc9c215 100644 --- a/packages/@glimmer/interfaces/lib/runtime/arguments.d.ts +++ b/packages/@glimmer/interfaces/lib/runtime/arguments.d.ts @@ -60,3 +60,9 @@ export interface Arguments { positional: readonly unknown[]; named: Record; } + +export interface ArgumentsDebug { + positional: readonly unknown[]; + named: Record; + errors: Record; +} diff --git a/packages/@glimmer/interfaces/lib/runtime/debug-render-tree.d.ts b/packages/@glimmer/interfaces/lib/runtime/debug-render-tree.d.ts index f50bf99222..f56fbb85a2 100644 --- a/packages/@glimmer/interfaces/lib/runtime/debug-render-tree.d.ts +++ b/packages/@glimmer/interfaces/lib/runtime/debug-render-tree.d.ts @@ -1,7 +1,7 @@ import type { SimpleElement, SimpleNode } from '@simple-dom/interface'; import type { Bounds } from '../dom/bounds'; -import type { Arguments, CapturedArguments } from './arguments'; +import type { ArgumentsDebug, CapturedArguments } from './arguments'; export type RenderNodeType = 'outlet' | 'engine' | 'route-template' | 'component'; @@ -17,7 +17,7 @@ export interface CapturedRenderNode { id: string; type: RenderNodeType; name: string; - args: Arguments; + args: ArgumentsDebug; instance: unknown; template: string | null; bounds: null | { diff --git a/packages/@glimmer/runtime/lib/debug-render-tree.ts b/packages/@glimmer/runtime/lib/debug-render-tree.ts index bacb1fbff6..940a8cfea1 100644 --- a/packages/@glimmer/runtime/lib/debug-render-tree.ts +++ b/packages/@glimmer/runtime/lib/debug-render-tree.ts @@ -7,7 +7,7 @@ import type { } from "@glimmer/interfaces"; import { assign, expect, Stack } from '@glimmer/util'; -import { reifyArgs } from './vm/arguments'; +import { reifyArgsDebug } from './vm/arguments'; interface InternalRenderNode extends RenderNode { bounds: Nullable; @@ -181,7 +181,7 @@ export default class DebugRenderTreeImpl let template = this.captureTemplate(node); let bounds = this.captureBounds(node); let children = this.captureRefs(refs); - return { id, type, name, args: reifyArgs(args), instance, template, bounds, children }; + return { id, type, name, args: reifyArgsDebug(args), instance, template, bounds, children }; } private captureTemplate({ template }: InternalRenderNode): Nullable { diff --git a/packages/@glimmer/runtime/lib/vm/arguments.ts b/packages/@glimmer/runtime/lib/vm/arguments.ts index 2fb5eea71a..66d5ef1d43 100644 --- a/packages/@glimmer/runtime/lib/vm/arguments.ts +++ b/packages/@glimmer/runtime/lib/vm/arguments.ts @@ -500,6 +500,48 @@ export function reifyArgs(args: CapturedArguments) { }; } +export function reifyNamedDebug(named: CapturedNamedArguments) { + let reified = dict(); + let errors: Record = dict(); + + for (const [key, value] of Object.entries(named)) { + try { + reified[key] = valueForRef(value); + } catch (e) { + reified[key] = e; + errors[key] = e as Error; + } + } + + return { reified, errors }; +} + +export function reifyPositionalDebug(positional: CapturedPositionalArguments) { + let errors: Error[] = []; + let reified = positional.map((p) => { + try { + return valueForRef(p); + } catch(e) { + errors.push(e as Error); + return e; + } + }); + return { + reified, + errors + } +} + +export function reifyArgsDebug(args: CapturedArguments) { + let named = reifyNamedDebug(args.named); + let positional = reifyPositionalDebug(args.positional); + return { + named: named.reified, + positional: positional.reified, + errors: {...named.errors, ...positional.errors} as unknown as Record + }; +} + export const EMPTY_NAMED = Object.freeze(Object.create(null)) as CapturedNamedArguments; export const EMPTY_POSITIONAL = EMPTY_REFERENCES as CapturedPositionalArguments; export const EMPTY_ARGS = createCapturedArgs(EMPTY_NAMED, EMPTY_POSITIONAL); diff --git a/packages/@glimmer/vm-babel-plugins/index.ts b/packages/@glimmer/vm-babel-plugins/index.ts index 60b0c57664..fa1b8f2102 100644 --- a/packages/@glimmer/vm-babel-plugins/index.ts +++ b/packages/@glimmer/vm-babel-plugins/index.ts @@ -21,7 +21,7 @@ export default function generateVmPlugins( return [ [ __loadPlugins - ? + ? require('babel-plugin-debug-macros') : require.resolve('babel-plugin-debug-macros'), {