From 1926aff73d48ffb752fd0248cefdec48654e6217 Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Tue, 20 Apr 2021 13:03:33 -0700 Subject: [PATCH 1/2] Prefer `else` over `inverse`. Requires `Yields` to use `else`, but still allows for `{{yields to="inverse"}}` --- .../-private/intrinsics/each-in.d.ts | 2 +- .../-private/intrinsics/each.d.ts | 2 +- .../__tests__/component-like.test.ts | 4 +-- .../__tests__/ember-component.test.ts | 6 ++-- .../__tests__/glimmer-component.test.ts | 6 ++-- .../__tests__/intrinsics/each-in.test.ts | 10 +++---- .../__tests__/intrinsics/each.test.ts | 2 +- .../__tests__/component.test.ts | 6 ++-- packages/template/-private/keywords/each.d.ts | 2 +- packages/template/-private/keywords/with.d.ts | 2 +- .../__tests__/custom-invokable.test.ts | 4 +-- .../template/__tests__/keywords/with.test.ts | 2 +- .../__tests__/template-to-typescript.test.ts | 30 +++++++++++++++---- .../transform/src/template-to-typescript.ts | 7 ++++- 14 files changed, 55 insertions(+), 30 deletions(-) diff --git a/packages/environment-ember-loose/-private/intrinsics/each-in.d.ts b/packages/environment-ember-loose/-private/intrinsics/each-in.d.ts index 6320e0253..560e4dd8c 100644 --- a/packages/environment-ember-loose/-private/intrinsics/each-in.d.ts +++ b/packages/environment-ember-loose/-private/intrinsics/each-in.d.ts @@ -3,6 +3,6 @@ import { AcceptsBlocks, DirectInvokable, EmptyObject } from '@glint/template/-pr export type EachInKeyword = DirectInvokable<{ (args: EmptyObject, object: T): AcceptsBlocks<{ default: [key: keyof NonNullable, value: NonNullable[keyof NonNullable]]; - inverse?: []; + else?: []; }>; }>; diff --git a/packages/environment-ember-loose/-private/intrinsics/each.d.ts b/packages/environment-ember-loose/-private/intrinsics/each.d.ts index 199c4ecd0..3af933afd 100644 --- a/packages/environment-ember-loose/-private/intrinsics/each.d.ts +++ b/packages/environment-ember-loose/-private/intrinsics/each.d.ts @@ -6,6 +6,6 @@ type ArrayLike = ReadonlyArray | Iterable | EmberArray; export type EachKeyword = DirectInvokable<{ (args: { key?: string }, items: ArrayLike | null | undefined): AcceptsBlocks<{ default: [T, number]; - inverse: []; + else: []; }>; }>; diff --git a/packages/environment-ember-loose/__tests__/component-like.test.ts b/packages/environment-ember-loose/__tests__/component-like.test.ts index 963b962ea..455a20658 100644 --- a/packages/environment-ember-loose/__tests__/component-like.test.ts +++ b/packages/environment-ember-loose/__tests__/component-like.test.ts @@ -35,7 +35,7 @@ import { expectTypeOf } from 'expect-type'; }; Yields: { default: [number]; - inverse?: []; + else?: []; }; } @@ -79,7 +79,7 @@ import { expectTypeOf } from 'expect-type'; } { - const [...args] = component.blockParams.inverse; + const [...args] = component.blockParams.else; expectTypeOf(args).toEqualTypeOf<[]>(); } } diff --git a/packages/environment-ember-loose/__tests__/ember-component.test.ts b/packages/environment-ember-loose/__tests__/ember-component.test.ts index 8ef602ff9..010acef60 100644 --- a/packages/environment-ember-loose/__tests__/ember-component.test.ts +++ b/packages/environment-ember-loose/__tests__/ember-component.test.ts @@ -64,7 +64,7 @@ expectTypeOf(Component.extend).toEqualTypeOf(UpstreamEmberComponent.extend); }; Yields: { default: [T]; - inverse?: []; + else?: []; }; } @@ -79,7 +79,7 @@ expectTypeOf(Component.extend).toEqualTypeOf(UpstreamEmberComponent.extend); if (𝚪.args.values.length) { yieldToBlock(𝚪, 'default', 𝚪.args.values[0]); } else { - yieldToBlock(𝚪, 'inverse'); + yieldToBlock(𝚪, 'else'); } }); } @@ -116,7 +116,7 @@ expectTypeOf(Component.extend).toEqualTypeOf(UpstreamEmberComponent.extend); } { - const [...args] = component.blockParams.inverse; + const [...args] = component.blockParams.else; expectTypeOf(args).toEqualTypeOf<[]>(); } } diff --git a/packages/environment-ember-loose/__tests__/glimmer-component.test.ts b/packages/environment-ember-loose/__tests__/glimmer-component.test.ts index ca9dd49cc..0ec111723 100644 --- a/packages/environment-ember-loose/__tests__/glimmer-component.test.ts +++ b/packages/environment-ember-loose/__tests__/glimmer-component.test.ts @@ -57,7 +57,7 @@ import { expectTypeOf } from 'expect-type'; }; Yields: { default: [T]; - inverse?: []; + else?: []; }; } @@ -70,7 +70,7 @@ import { expectTypeOf } from 'expect-type'; if (𝚪.args.values.length) { yieldToBlock(𝚪, 'default', 𝚪.args.values[0]); } else { - yieldToBlock(𝚪, 'inverse'); + yieldToBlock(𝚪, 'else'); } }); } @@ -107,7 +107,7 @@ import { expectTypeOf } from 'expect-type'; } { - const [...args] = component.blockParams.inverse; + const [...args] = component.blockParams.else; expectTypeOf(args).toEqualTypeOf<[]>(); } } diff --git a/packages/environment-ember-loose/__tests__/intrinsics/each-in.test.ts b/packages/environment-ember-loose/__tests__/intrinsics/each-in.test.ts index cdc955795..2cab0dd3b 100644 --- a/packages/environment-ember-loose/__tests__/intrinsics/each-in.test.ts +++ b/packages/environment-ember-loose/__tests__/intrinsics/each-in.test.ts @@ -27,12 +27,12 @@ declare const maybeVal: { a: number; b: number } | undefined; } { - const [...args] = component.blockParams.inverse; + const [...args] = component.blockParams.else; expectTypeOf(args).toEqualTypeOf<[]>(); } } -// Can render inverse when undefined, null, or empty. +// Can render else when undefined, null, or empty. { const component = emitComponent(eachIn({}, undefined)); @@ -45,7 +45,7 @@ declare const maybeVal: { a: number; b: number } | undefined; } { - const [...args] = component.blockParams.inverse; + const [...args] = component.blockParams.else; expectTypeOf(args).toEqualTypeOf<[]>(); } } @@ -61,7 +61,7 @@ declare const maybeVal: { a: number; b: number } | undefined; } { - const [...args] = component.blockParams.inverse; + const [...args] = component.blockParams.else; expectTypeOf(args).toEqualTypeOf<[]>(); } } @@ -77,7 +77,7 @@ declare const maybeVal: { a: number; b: number } | undefined; } { - const [...args] = component.blockParams.inverse; + const [...args] = component.blockParams.else; expectTypeOf(args).toEqualTypeOf<[]>(); } } diff --git a/packages/environment-ember-loose/__tests__/intrinsics/each.test.ts b/packages/environment-ember-loose/__tests__/intrinsics/each.test.ts index e75a68b33..2ee01a342 100644 --- a/packages/environment-ember-loose/__tests__/intrinsics/each.test.ts +++ b/packages/environment-ember-loose/__tests__/intrinsics/each.test.ts @@ -16,7 +16,7 @@ let each = resolve(Globals['each']); } { - const [...args] = component.blockParams.inverse; + const [...args] = component.blockParams.else; expectTypeOf(args).toEqualTypeOf<[]>(); } } diff --git a/packages/environment-glimmerx/__tests__/component.test.ts b/packages/environment-glimmerx/__tests__/component.test.ts index 087415af5..e59b369bb 100644 --- a/packages/environment-glimmerx/__tests__/component.test.ts +++ b/packages/environment-glimmerx/__tests__/component.test.ts @@ -60,7 +60,7 @@ import { EmptyObject } from '@glint/template/-private/integration'; }; Yields: { default: [T]; - inverse?: []; + else?: []; }; } @@ -72,7 +72,7 @@ import { EmptyObject } from '@glint/template/-private/integration'; if (𝚪.args.values.length) { yieldToBlock(𝚪, 'default', 𝚪.args.values[0]); } else { - yieldToBlock(𝚪, 'inverse'); + yieldToBlock(𝚪, 'else'); } }); } @@ -125,7 +125,7 @@ import { EmptyObject } from '@glint/template/-private/integration'; } { - const [...args] = component.blockParams.inverse; + const [...args] = component.blockParams.else; expectTypeOf(args).toEqualTypeOf<[]>(); } } diff --git a/packages/template/-private/keywords/each.d.ts b/packages/template/-private/keywords/each.d.ts index 0e30b7787..ab21921f5 100644 --- a/packages/template/-private/keywords/each.d.ts +++ b/packages/template/-private/keywords/each.d.ts @@ -3,6 +3,6 @@ import { AcceptsBlocks, DirectInvokable } from '../integration'; export type EachKeyword = DirectInvokable<{ (args: { key?: string }, items: readonly T[]): AcceptsBlocks<{ default: [T, number]; - inverse?: []; + else?: []; }>; }>; diff --git a/packages/template/-private/keywords/with.d.ts b/packages/template/-private/keywords/with.d.ts index 3486e754f..01c340726 100644 --- a/packages/template/-private/keywords/with.d.ts +++ b/packages/template/-private/keywords/with.d.ts @@ -3,6 +3,6 @@ import { AcceptsBlocks, DirectInvokable, EmptyObject } from '../integration'; export type WithKeyword = DirectInvokable<{ (args: EmptyObject, value: T): AcceptsBlocks<{ default: [T]; - inverse?: []; + else?: []; }>; }>; diff --git a/packages/template/__tests__/custom-invokable.test.ts b/packages/template/__tests__/custom-invokable.test.ts index da42d0b7b..d959236cc 100644 --- a/packages/template/__tests__/custom-invokable.test.ts +++ b/packages/template/__tests__/custom-invokable.test.ts @@ -32,7 +32,7 @@ declare const caseOf: DirectInvokable< key: K ) => AcceptsBlocks<{ default: SumVariants[K]; - inverse?: []; + else?: []; }> > ]; @@ -62,7 +62,7 @@ declare const caseOf: DirectInvokable< emitValue(resolveOrReturn(n)({})); } { - component.blockParams.inverse; + component.blockParams.else; { const component = emitComponent(resolve(when)({}, 'Nothing')); expectTypeOf(component.blockParams.default).toEqualTypeOf<[]>(); diff --git a/packages/template/__tests__/keywords/with.test.ts b/packages/template/__tests__/keywords/with.test.ts index 8e0462f9a..756aeb373 100644 --- a/packages/template/__tests__/keywords/with.test.ts +++ b/packages/template/__tests__/keywords/with.test.ts @@ -14,7 +14,7 @@ const withKeyword = resolve({} as WithKeyword); } { - component.blockParams.inverse; + component.blockParams.else; } } diff --git a/packages/transform/__tests__/template-to-typescript.test.ts b/packages/transform/__tests__/template-to-typescript.test.ts index 15837b1f9..4b20ebdf3 100644 --- a/packages/transform/__tests__/template-to-typescript.test.ts +++ b/packages/transform/__tests__/template-to-typescript.test.ts @@ -291,7 +291,7 @@ describe('rewriteTemplate', () => { χ.emitValue(χ.resolveOrReturn(ok)({})); } { - const [] = 𝛄.blockParams.inverse; + const [] = 𝛄.blockParams.else; χ.emitValue(χ.resolveOrReturn(𝚪.args.nevermind)({})); } χ.Globals[\\"doAThing\\"]; @@ -355,6 +355,26 @@ describe('rewriteTemplate', () => { `"χ.yieldToBlock(𝚪, \\"body\\", 123);"` ); }); + + test('{{yield}} to else', () => { + let template = stripIndent` + {{yield 123 to="else"}} + `; + + expect(templateBody(template)).toMatchInlineSnapshot( + `"χ.yieldToBlock(𝚪, \\"else\\", 123);"` + ); + }); + + test('{{yield}} to inverse', () => { + let template = stripIndent` + {{yield 123 to="inverse"}} + `; + + expect(templateBody(template)).toMatchInlineSnapshot( + `"χ.yieldToBlock(𝚪, \\"else\\", 123);"` + ); + }); }); describe('{{array}}', () => { @@ -687,7 +707,7 @@ describe('rewriteTemplate', () => { `); }); - test('invocation with an inverse block', () => { + test('invocation with an else block', () => { let template = stripIndent` {{#foo as |bar baz|}} {{bar}}: {{baz}} @@ -705,7 +725,7 @@ describe('rewriteTemplate', () => { χ.emitValue(χ.resolveOrReturn(baz)({})); } { - const [] = 𝛄.blockParams.inverse; + const [] = 𝛄.blockParams.else; χ.emitValue(χ.resolveOrReturn(𝚪.args.oh)({})); } χ.Globals[\\"foo\\"]; @@ -713,7 +733,7 @@ describe('rewriteTemplate', () => { `); }); - test('chained inverse', () => { + test('chained else', () => { let template = stripIndent` {{#foo as |bar baz|}} {{bar}}: {{baz}} @@ -731,7 +751,7 @@ describe('rewriteTemplate', () => { χ.emitValue(χ.resolveOrReturn(baz)({})); } { - const [] = 𝛄.blockParams.inverse; + const [] = 𝛄.blockParams.else; χ.emitValue(χ.resolveOrReturn(𝚪.args.oh)({})); } χ.Globals[\\"foo\\"]; diff --git a/packages/transform/src/template-to-typescript.ts b/packages/transform/src/template-to-typescript.ts index 2caa0ce72..9ebf07f65 100644 --- a/packages/transform/src/template-to-typescript.ts +++ b/packages/transform/src/template-to-typescript.ts @@ -671,7 +671,12 @@ export function templateToTypescript( to = toPair.value.value; } + if (to === 'inverse') { + to = 'else'; + } + emit.text('χ.yieldToBlock(𝚪, '); + emit.text(JSON.stringify(to)); for (let param of node.params) { @@ -780,7 +785,7 @@ export function templateToTypescript( emitBlock('default', node.program); if (node.inverse) { - emitBlock('inverse', node.inverse); + emitBlock('else', node.inverse); } // TODO: emit something corresponding to `{{/foo}}` like we do From 3d1f0970c04498d5536da16221eb85d2b7d6e29e Mon Sep 17 00:00:00 2001 From: Peter Wagenet Date: Tue, 20 Apr 2021 14:06:59 -0700 Subject: [PATCH 2/2] Add note about Yields else to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 2478c1e16..5ae8d731d 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ While GlimmerX components accept `Args` as a type parameter, the Glint version a The `Element` field declares what type of element(s), if any, the component applies its passed `...attributes` to. This is often the component's root element. Tracking this type ensures any modifiers used on your component will be compatible with the DOM element(s) they're ultimately attached to. If no `Element` is specified, it will be a type error to set any HTML attributes when invoking your component. The `Yields` field specifies the names of any blocks the component yields to, as well as the type of any parameter(s) they'll receive. See the [Yieldable Named Blocks RFC] for further details. +(Note that the `inverse` block is an alias for `else`. These should be defined in `Yields` as `else`, though `{{yield to="inverse"}}` will continue to work.) ```ts import Component from '@glint/environment-glimmerx/component';