diff --git a/src/hooks.ts b/src/hooks.ts index 79e8f84f..c55b7dfc 100644 --- a/src/hooks.ts +++ b/src/hooks.ts @@ -38,7 +38,9 @@ export function useEnv(): E { */ export function useSubEnv(envExtension: Env) { const node = getCurrent()!; - node.childEnv = Object.freeze(Object.assign({}, node.childEnv, envExtension)); + const env = Object.create(node.childEnv); + const descrs = Object.getOwnPropertyDescriptors(envExtension); + node.childEnv = Object.freeze(Object.defineProperties(env, descrs)); } // ----------------------------------------------------------------------------- diff --git a/tests/components/__snapshots__/hooks.test.ts.snap b/tests/components/__snapshots__/hooks.test.ts.snap index 8d62944c..f9d7c06d 100644 --- a/tests/components/__snapshots__/hooks.test.ts.snap +++ b/tests/components/__snapshots__/hooks.test.ts.snap @@ -158,6 +158,32 @@ exports[`hooks use sub env does not pollute user env 1`] = ` }" `; +exports[`hooks use sub env supports arbitrary descriptor 1`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; + + let block1 = createBlock(\`
\`); + + return function template(ctx, node, key = \\"\\") { + let d1 = ctx['env'].someVal; + let d2 = ctx['env'].someVal2; + return block1([d1, d2]); + } +}" +`; + +exports[`hooks use sub env supports arbitrary descriptor 2`] = ` +"function anonymous(bdom, helpers +) { + let { text, createBlock, list, multi, html, toggler, component, comment } = bdom; + + return function template(ctx, node, key = \\"\\") { + return component(\`Child\`, {}, key + \`__1\`, node, ctx); + } +}" +`; + exports[`hooks useEffect hook dependencies prevent effects from rerunning when unchanged 1`] = ` "function anonymous(bdom, helpers ) { diff --git a/tests/components/hooks.test.ts b/tests/components/hooks.test.ts index c2acef96..1b09fcce 100644 --- a/tests/components/hooks.test.ts +++ b/tests/components/hooks.test.ts @@ -194,6 +194,40 @@ describe("hooks", () => { expect(component.env).toHaveProperty("val"); }); + test("use sub env supports arbitrary descriptor", async () => { + let someVal = "maggot"; + let someVal2 = "brain"; + + class Child extends Component { + static template = xml`
`; + } + + class Test extends Component { + static template = xml``; + static components = { Child }; + setup() { + useSubEnv({ + get someVal2() { + return someVal2; + }, + }); + } + } + someVal = "maggot"; + const env = { + get someVal() { + return someVal; + }, + }; + const component = await new App(Test).configure({ env }).mount(fixture); + expect(fixture.innerHTML).toBe("
maggot brain
"); + someVal = "brain"; + someVal2 = "maggot"; + component.render(); + await nextTick(); + expect(fixture.innerHTML).toBe("
brain maggot
"); + }); + test("can use useComponent", async () => { expect.assertions(2); class Test extends Component {