@glint/template 0.9.6 → 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,23 @@
1
1
  import { AttrValue, ContentValue } from '..';
2
2
  import {
3
- AcceptsBlocks,
3
+ ComponentReturn,
4
4
  AnyContext,
5
5
  AnyFunction,
6
- BoundModifier,
7
- EmptyObject,
6
+ ModifierReturn,
8
7
  HasContext,
9
- Invokable,
8
+ InvokableInstance,
10
9
  TemplateContext,
10
+ NamedArgs,
11
11
  } from '../integration';
12
12
  import { ElementForTagName } from './types';
13
13
 
14
+ /**
15
+ * Used during emit to denote an object literal that corresponds
16
+ * to the use of named args rather than passing an object value
17
+ * directly.
18
+ */
19
+ export declare const NamedArgsMarker: NamedArgs<unknown>;
20
+
14
21
  /*
15
22
  * Emits the given value as top-level content to the DOM. This:
16
23
  *
@@ -57,11 +64,11 @@ export declare function emitElement<Name extends string>(
57
64
  * applyModifier(𝛄.element, resolve(baz)({}));
58
65
  * });
59
66
  */
60
- export declare function emitComponent<T extends AcceptsBlocks<any, any>>(
67
+ export declare function emitComponent<T extends ComponentReturn<any, any>>(
61
68
  component: T
62
69
  ): {
63
- element: T extends AcceptsBlocks<any, infer El> ? El : any;
64
- blockParams: T extends AcceptsBlocks<infer Yields, any> ? Required<Yields> : any;
70
+ element: T extends ComponentReturn<any, infer El> ? El : any;
71
+ blockParams: T extends ComponentReturn<infer Yields, any> ? Required<Yields> : any;
65
72
  };
66
73
 
67
74
  /*
@@ -72,9 +79,9 @@ export declare function emitComponent<T extends AcceptsBlocks<any, any>>(
72
79
  * environment's DSL export.
73
80
  */
74
81
  export declare function templateExpression<
75
- Signature extends AnyFunction = (args: EmptyObject) => AcceptsBlocks<EmptyObject>,
76
- Context extends AnyContext = TemplateContext<void, EmptyObject, EmptyObject, void>
77
- >(f: (𝚪: Context, χ: never) => void): new () => Invokable<Signature> & HasContext<Context>;
82
+ Signature extends AnyFunction = () => ComponentReturn<{}>,
83
+ Context extends AnyContext = TemplateContext<void, {}, {}, void>
84
+ >(f: (𝚪: Context, χ: never) => void): new () => InvokableInstance<Signature> & HasContext<Context>;
78
85
 
79
86
  /*
80
87
  * Wraps a template body that's backed by a known value (typically a class), either
@@ -101,13 +108,12 @@ export declare function templateForBackingValue<Args extends unknown[], Context
101
108
  *
102
109
  * Is equivalent to:
103
110
  *
104
- * yieldToBlock(𝚪, 'name', foo, bar);
111
+ * yieldToBlock(𝚪, 'name')(foo, bar);
105
112
  */
106
113
  export declare function yieldToBlock<Context extends AnyContext, K extends keyof Context['blocks']>(
107
114
  𝚪: Context,
108
- to: K,
109
- ...values: NonNullable<Context['blocks'][K]>
110
- ): void;
115
+ to: K
116
+ ): (...values: NonNullable<Context['blocks'][K]>) => void;
111
117
 
112
118
  /*
113
119
  * Applies `...attributes` that were passed to a component down
@@ -135,7 +141,11 @@ export declare function applyAttributes(element: Element, attrs: Record<string,
135
141
  * <div {{someModifier}}></div>
136
142
  * <AnotherComponent {{someModifier}} />
137
143
  */
138
- export declare function applyModifier<TargetElement extends Element>(
139
- element: TargetElement,
140
- modifier: BoundModifier<TargetElement>
141
- ): void;
144
+ export declare function applyModifier(boundModifier: ModifierReturn): void;
145
+
146
+ /*
147
+ * Used to consume imported identifiers like `hash` or `array` when
148
+ * we treat them as a special form to be translated into native
149
+ * syntax.
150
+ */
151
+ export declare function noop(value: unknown): void;
@@ -1,4 +1,4 @@
1
- import { DirectInvokable, Invokable, Invoke, InvokeDirect } from '../integration';
1
+ import { DirectInvokable, InvokableInstance, Invoke, InvokeDirect } from '../integration';
2
2
  import { ResolveOrReturn } from './types';
3
3
 
4
4
  /*
@@ -9,12 +9,12 @@ import { ResolveOrReturn } from './types';
9
9
  * (args: Named, ...positional: Positional) => Result
10
10
  *
11
11
  * `Named` and `Positional` represent the respective types of the named and positional
12
- * args accepted, and `Result` is either `CreatesModifier`, `AcceptsBlocks<...>`, or any
12
+ * args accepted, and `Result` is either `CreatesModifier`, `ComponentReturn<...>`, or any
13
13
  * other type to simply indicate that the invokable returns a value.
14
14
  *
15
15
  * In the core, invokables can take one of two forms:
16
16
  *
17
- * - `new (...) => Invokable<T>`: this is the typical signature for items such as a
17
+ * - `new (...) => InvokableInstance<T>`: this is the typical signature for items such as a
18
18
  * component subclass. In resolving this form, we need to break apart the construct
19
19
  * signature and reconstruct it as a regular function, which has the implicit effect
20
20
  * of preserving type parameters for polymorphic components in the resulting function
@@ -32,7 +32,7 @@ import { ResolveOrReturn } from './types';
32
32
  */
33
33
 
34
34
  export declare function resolve<T extends DirectInvokable>(item: T): T[typeof InvokeDirect];
35
- export declare function resolve<Args extends unknown[], Instance extends Invokable>(
35
+ export declare function resolve<Args extends unknown[], Instance extends InvokableInstance>(
36
36
  item: (abstract new (...args: Args) => Instance) | null | undefined
37
37
  ): (...args: Parameters<Instance[typeof Invoke]>) => ReturnType<Instance[typeof Invoke]>;
38
38
 
@@ -1,12 +1,8 @@
1
- import { EmptyObject } from '@glint/template/-private/integration';
2
-
3
- type Constructor<T> = abstract new (...args: never[]) => T;
4
-
5
1
  /**
6
2
  * A utility for constructing the type of an environment's `resolveOrReturn` from
7
3
  * the type of its `resolve` function.
8
4
  */
9
- export type ResolveOrReturn<T> = T & (<U>(item: U) => (args: EmptyObject) => U);
5
+ export type ResolveOrReturn<T> = T & (<U>(item: U) => () => U);
10
6
 
11
7
  /**
12
8
  * Given a tag name, returns an appropriate `Element` subtype.
package/-private/dsl.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // This module exports functions and types directly referenced by
2
- // the output of `@glint/transform`. It comprises the basis from
3
- // which environments construct their exports.
2
+ // the output of `@glint/core`'s transform layer. It comprises the
3
+ // basis from which environments construct their exports.
4
4
 
5
5
  export * from './dsl/resolve';
6
6
  export * from './dsl/emit';
@@ -1,12 +1,21 @@
1
1
  import {
2
- AcceptsBlocks,
2
+ ComponentReturn,
3
3
  AnyFunction,
4
- BoundModifier,
5
- GuardEmpty,
4
+ ModifierReturn,
6
5
  FlattenBlockParams,
7
6
  Invokable,
7
+ NamedArgNames,
8
+ UnwrapNamedArgs,
8
9
  } from './integration';
9
- import { ExpandSignature } from '@glimmer/component/-private/component';
10
+ import {
11
+ ComponentSignatureArgs,
12
+ ComponentSignatureBlocks,
13
+ ComponentSignatureElement,
14
+ Get,
15
+ InvokableArgs,
16
+ MaybeNamed,
17
+ PrebindArgs,
18
+ } from './signature';
10
19
 
11
20
  /**
12
21
  * Any value that can be safely emitted into the DOM as top-level content,
@@ -27,6 +36,14 @@ export type ContentValue =
27
36
  | Node
28
37
  | ArglessCurlyComponent;
29
38
 
39
+ // This encompasses both @glimmer/runtime and @ember/template's notion of `SafeString`s,
40
+ // and this coverage is tested in `emit-content.test.ts`.
41
+ type SafeString = { toHTML(): string };
42
+
43
+ // `{{foo}}` becomes `emitContent(resolveOrReturn(foo)({})`, which means if `foo`
44
+ // is a component that accepts no args, then this is a valid invocation.
45
+ type ArglessCurlyComponent = ComponentReturn<{}, any>;
46
+
30
47
  /**
31
48
  * Any value that can be safely set as an HTML attribute on a DOM node.
32
49
  * This includes strings, numbers, booleans and `null`/`undefined`.
@@ -47,13 +64,12 @@ export type AttrValue = string | number | boolean | null | undefined | SafeStrin
47
64
  * The `S` signature parameter here is of the same form as the one
48
65
  * accepted by both the Ember and Glimmer `Component` base classes.
49
66
  */
50
- export type ComponentLike<S = unknown> = InvokableConstructor<
67
+ export type ComponentLike<S = unknown> = Invokable<
51
68
  (
52
- named: GuardEmpty<ExpandSignature<S>['Args']['Named']>,
53
- ...positional: ExpandSignature<S>['Args']['Positional']
54
- ) => AcceptsBlocks<
55
- FlattenBlockParams<ExpandSignature<S>['Blocks']>,
56
- ExpandSignature<S>['Element']
69
+ ...args: InvokableArgs<ComponentSignatureArgs<S>>
70
+ ) => ComponentReturn<
71
+ FlattenBlockParams<ComponentSignatureBlocks<S>>,
72
+ ComponentSignatureElement<S>
57
73
  >
58
74
  >;
59
75
 
@@ -66,8 +82,8 @@ export type ComponentLike<S = unknown> = InvokableConstructor<
66
82
  * The `S` signature parameter here is of the same form as the one
67
83
  * accepted by `Helper` and `helper`.
68
84
  */
69
- export type HelperLike<S = unknown> = InvokableConstructor<
70
- (...args: InvokableArgs<S>) => Get<S, 'Return', unknown>
85
+ export type HelperLike<S = unknown> = Invokable<
86
+ (...args: InvokableArgs<Get<S, 'Args'>>) => Get<S, 'Return', unknown>
71
87
  >;
72
88
 
73
89
  /**
@@ -79,8 +95,8 @@ export type HelperLike<S = unknown> = InvokableConstructor<
79
95
  * The `S` signature parameter here is of the same form as the ones
80
96
  * accepted by `Modifier` and `modifier`.
81
97
  */
82
- export type ModifierLike<S = unknown> = InvokableConstructor<
83
- (...args: InvokableArgs<S>) => BoundModifier<Constrain<Get<S, 'Element'>, Element>>
98
+ export type ModifierLike<S = unknown> = Invokable<
99
+ (element: Get<S, 'Element'>, ...args: InvokableArgs<Get<S, 'Args'>>) => ModifierReturn
84
100
  >;
85
101
 
86
102
  /**
@@ -112,43 +128,17 @@ export type ModifierLike<S = unknown> = InvokableConstructor<
112
128
  * arg when invoking the yielded component.
113
129
  */
114
130
  export type WithBoundArgs<
115
- T extends InvokableConstructor<AnyFunction>,
131
+ T extends Invokable<AnyFunction>,
116
132
  BoundArgs extends NamedArgNames<T>
117
- > = T extends InvokableConstructor<
118
- (named: infer Named, ...positional: infer Positional) => infer Result
119
- >
120
- ? InvokableConstructor<
133
+ > = T extends Invokable<(...args: [...positional: infer P, named: infer N]) => infer R>
134
+ ? Invokable<
121
135
  (
122
- named: GuardEmpty<Omit<Named, BoundArgs> & Partial<Pick<Named, BoundArgs & keyof Named>>>,
123
- ...positional: Positional
124
- ) => Result
136
+ ...args: [
137
+ ...positional: P,
138
+ ...named: MaybeNamed<PrebindArgs<UnwrapNamedArgs<NonNullable<N>>, BoundArgs>>
139
+ ]
140
+ ) => R
125
141
  >
126
142
  : never;
127
143
 
128
- type InvokableConstructor<F extends AnyFunction> = abstract new (...args: any) => Invokable<F>;
129
- type NamedArgNames<T extends InvokableConstructor<AnyFunction>> = T extends InvokableConstructor<
130
- (named: infer Named, ...positional: any) => any
131
- >
132
- ? keyof Named
133
- : never;
134
-
135
- type Get<T, K, Otherwise = unknown> = K extends keyof T ? T[K] : Otherwise;
136
- type Constrain<T, Constraint, Otherwise = Constraint> = T extends Constraint ? T : Otherwise;
137
-
138
- // We use the imported `ExpandSignature` for component signatures, as they have
139
- // different layers of possible shorthand, but modifiers and helpers only have
140
- // one structure they can specify their args in, so this utility is sufficient.
141
- type InvokableArgs<S> = [
142
- named: GuardEmpty<Get<Get<S, 'Args'>, 'Named'>>,
143
- ...positional: Constrain<Get<Get<S, 'Args'>, 'Positional'>, Array<unknown>, []>
144
- ];
145
-
146
- // This encompasses both @glimmer/runtime and @ember/template's notion of `SafeString`s,
147
- // and this coverage is tested in `emit-content.test.ts`.
148
- type SafeString = { toHTML(): string };
149
-
150
- // `{{foo}}` becomes `emitContent(resolveOrReturn(foo)({})`, which means if `foo`
151
- // is a component that accepts no args, then this is a valid invocation.
152
- type ArglessCurlyComponent = AcceptsBlocks<{}, any>;
153
-
154
144
  export {};
@@ -1,9 +1,10 @@
1
- // While the entire `@glint/template` package is currently private, this
2
- // module exports the symbols and types necessary to declare a class or
3
- // other entity as integrating with Glint's template system.
4
-
5
- import { EmptyObject } from '@glimmer/component/-private/component';
6
- export { EmptyObject };
1
+ // While everything in the `@glint/template` package other than its main
2
+ // entrypoint is "private", this module exports the symbols and types
3
+ // necessary to declare a class or other entity as integrating with Glint's
4
+ // template system.
5
+ // In most cases it should be possible to declare integrations in terms of
6
+ // `ComponentLike`/`HelperLike`/`ModifierLike`, but these declarations are
7
+ // the primitives on which those types are built.
7
8
 
8
9
  /** Any function, which is the tighest bound we can put on an object's `[Invoke]` field. */
9
10
  export type AnyFunction = (...params: any) => any;
@@ -18,31 +19,26 @@ export declare const InvokeDirect: unique symbol;
18
19
  export type DirectInvokable<T extends AnyFunction = AnyFunction> = { [InvokeDirect]: T };
19
20
 
20
21
  export declare const Invoke: unique symbol;
21
- export type Invokable<T extends AnyFunction = AnyFunction> = { [Invoke]: T };
22
+ export type InvokableInstance<T extends AnyFunction = AnyFunction> = { [Invoke]: T };
23
+ export type Invokable<F extends AnyFunction> = abstract new (...args: any) => InvokableInstance<F>;
22
24
 
23
25
  export declare const Context: unique symbol;
24
26
  export type HasContext<T extends AnyContext = AnyContext> = { [Context]: T };
25
27
 
26
- // These shenanigans are necessary to get TS to report when named args
27
- // are passed to a signature that doesn't expect any, because `{}` is
28
- // special-cased in the type system not to trigger EPC.
29
-
30
- export type GuardEmpty<T> = T extends any ? (keyof T extends never ? EmptyObject : T) : never;
31
-
32
28
  declare const Element: unique symbol;
33
29
  declare const Modifier: unique symbol;
34
30
  declare const Blocks: unique symbol;
35
31
 
36
32
  /** Denotes a modifier whose arguments have been bound and is ready to be attached to an element. */
37
- export type BoundModifier<El extends Element> = { [Modifier]: (el: El) => void };
33
+ export type ModifierReturn = { [Modifier]: true };
38
34
 
39
35
  /**
40
36
  * Denotes that the associated entity may be invoked with the given
41
37
  * blocks, yielding params of the appropriate type.
42
38
  */
43
- export type AcceptsBlocks<BlockImpls, El = null> = {
39
+ export type ComponentReturn<BlockDefs, El = null> = {
40
+ [Blocks]: BlockDefs;
44
41
  [Element]: El extends Element ? El : null;
45
- (blocks: BlockImpls): { [Blocks]: true };
46
42
  };
47
43
 
48
44
  /**
@@ -63,3 +59,22 @@ export type TemplateContext<This, Args, Blocks, Element> = {
63
59
  export type FlattenBlockParams<T> = {
64
60
  [K in keyof T]: T[K] extends { Params: { Positional: infer U } } ? U : T[K];
65
61
  };
62
+
63
+ // This trio of declarations allows us to distinguish explicit named
64
+ // argument invocation from "final positional argument is a hash"
65
+ // situations.
66
+ export declare const NamedArgs: unique symbol;
67
+ export type NamedArgs<T> = T & NamedArgsMarker;
68
+ export interface NamedArgsMarker {
69
+ [NamedArgs]: true;
70
+ }
71
+
72
+ export type NamedArgNames<T extends Invokable<AnyFunction>> = T extends Invokable<
73
+ (...args: infer A) => any
74
+ >
75
+ ? A extends [...positional: infer _, named?: infer N]
76
+ ? Exclude<keyof NonNullable<N>, typeof NamedArgs>
77
+ : never
78
+ : never;
79
+
80
+ export type UnwrapNamedArgs<T> = T extends NamedArgs<infer U> ? U : T;
@@ -1,17 +1,58 @@
1
- import { AcceptsBlocks, AnyBlocks, DirectInvokable, Invokable } from '../integration';
1
+ import { WithBoundArgs } from '../index';
2
+ import {
3
+ ComponentReturn,
4
+ DirectInvokable,
5
+ InvokableInstance,
6
+ NamedArgs,
7
+ Invokable,
8
+ NamedArgNames,
9
+ AnyFunction,
10
+ UnwrapNamedArgs,
11
+ } from '../integration';
12
+
13
+ type PartiallyAppliedComponent<Component, Args> = Component extends Invokable<AnyFunction>
14
+ ? WithBoundArgs<
15
+ Component,
16
+ Exclude<Args extends NamedArgNames<Component> ? Args : never, typeof NamedArgs>
17
+ >
18
+ : never;
2
19
 
3
20
  export type ComponentKeyword = DirectInvokable<{
4
21
  <
5
- Args,
6
- GivenArgs extends Partial<Args>,
7
- Blocks extends AnyBlocks,
8
- ConstructorArgs extends unknown[]
22
+ Named,
23
+ Positional extends unknown[],
24
+ Return extends ComponentReturn<any, any>,
25
+ ConstructorArgs extends unknown[],
26
+ GivenArgs extends Partial<Named> = {}
27
+ >(
28
+ component: abstract new (...args: ConstructorArgs) => InvokableInstance<
29
+ (...args: [...positional: Positional, named: Named]) => Return
30
+ >,
31
+ args?: NamedArgs<GivenArgs>
32
+ ): PartiallyAppliedComponent<
33
+ abstract new (...args: ConstructorArgs) => InvokableInstance<
34
+ (...args: [...positional: Positional, named: Named]) => Return
35
+ >,
36
+ keyof UnwrapNamedArgs<GivenArgs>
37
+ >;
38
+ <
39
+ Named,
40
+ Positional extends unknown[],
41
+ Return extends ComponentReturn<any, any>,
42
+ ConstructorArgs extends unknown[],
43
+ GivenArgs extends Partial<Named> = {}
9
44
  >(
10
- args: GivenArgs,
11
- component: new (...args: ConstructorArgs) => Invokable<(args: Args) => AcceptsBlocks<Blocks>>
12
- ): new () => Invokable<
13
- (
14
- args: Omit<Args, keyof GivenArgs> & Partial<Pick<Args, keyof GivenArgs & keyof Args>>
15
- ) => AcceptsBlocks<Blocks>
45
+ component:
46
+ | null
47
+ | undefined
48
+ | (abstract new (...args: ConstructorArgs) => InvokableInstance<
49
+ (...args: [...positional: Positional, named: Named]) => Return
50
+ >),
51
+ args?: NamedArgs<GivenArgs>
52
+ ): null | PartiallyAppliedComponent<
53
+ abstract new (...args: ConstructorArgs) => InvokableInstance<
54
+ (...args: [...positional: Positional, named: Named]) => Return
55
+ >,
56
+ keyof UnwrapNamedArgs<GivenArgs>
16
57
  >;
17
58
  }>;
@@ -1,5 +1,3 @@
1
- import { DirectInvokable, EmptyObject } from '../integration';
1
+ import { HelperLike } from '../index';
2
2
 
3
- export type DebuggerKeyword = DirectInvokable<{
4
- (args: EmptyObject): void;
5
- }>;
3
+ export interface DebuggerKeyword extends HelperLike<{ Return: void }> {}
@@ -1,8 +1,16 @@
1
- import { AcceptsBlocks, DirectInvokable } from '../integration';
1
+ import { ComponentLike } from '../index';
2
2
 
3
- export type EachKeyword = DirectInvokable<{
4
- <T>(args: { key?: string }, items: readonly T[]): AcceptsBlocks<{
5
- default: [T, number];
6
- else?: [];
7
- }>;
8
- }>;
3
+ type ArrayLike<T> = ReadonlyArray<T> | Iterable<T>;
4
+
5
+ export type EachKeyword = abstract new <T = any>() => InstanceType<
6
+ ComponentLike<{
7
+ Args: {
8
+ Positional: [items: Iterable<T> | null | undefined];
9
+ Named: { key?: string };
10
+ };
11
+ Blocks: {
12
+ default: [T, number];
13
+ else: [];
14
+ };
15
+ }>
16
+ >;
@@ -1,5 +1,6 @@
1
- import { DirectInvokable, EmptyObject } from '../integration';
1
+ import { HelperLike } from '../index';
2
2
 
3
- export type HasBlockParamsKeyword = DirectInvokable<{
4
- (args: EmptyObject, blockName?: string): boolean;
3
+ export type HasBlockParamsKeyword = HelperLike<{
4
+ Args: { Positional: [blockName?: string] };
5
+ Return: boolean;
5
6
  }>;
@@ -1,5 +1,6 @@
1
- import { DirectInvokable, EmptyObject } from '../integration';
1
+ import { HelperLike } from '../index';
2
2
 
3
- export type HasBlockKeyword = DirectInvokable<{
4
- (args: EmptyObject, blockName?: string): boolean;
3
+ export type HasBlockKeyword = HelperLike<{
4
+ Args: { Positional: [blockName?: string] };
5
+ Return: boolean;
5
6
  }>;
@@ -1,10 +1,13 @@
1
- import { AcceptsBlocks, DirectInvokable } from '../integration';
1
+ import { ComponentLike } from '../index';
2
2
 
3
- export type InElementKeyword = DirectInvokable<{
4
- (
5
- args: {
3
+ export type InElementKeyword = ComponentLike<{
4
+ Args: {
5
+ Positional: [element: ShadowRoot | Element];
6
+ Named: {
6
7
  insertBefore?: null | undefined;
7
- },
8
- element: ShadowRoot | Element
9
- ): AcceptsBlocks<{ default: [] }>;
8
+ };
9
+ };
10
+ Blocks: {
11
+ default: [];
12
+ };
10
13
  }>;
@@ -1,7 +1,7 @@
1
- import { AcceptsBlocks, DirectInvokable, EmptyObject } from '../integration';
1
+ import { ComponentReturn, DirectInvokable } from '../integration';
2
2
 
3
3
  export type LetKeyword = DirectInvokable<{
4
- <T extends unknown[]>(args: EmptyObject, ...values: T): AcceptsBlocks<{
4
+ <T extends unknown[]>(...values: T): ComponentReturn<{
5
5
  default: T;
6
6
  }>;
7
7
  }>;
@@ -1,8 +1,13 @@
1
- import { AcceptsBlocks, DirectInvokable, EmptyObject } from '../integration';
1
+ import { ComponentLike } from '../index';
2
2
 
3
- export type WithKeyword = DirectInvokable<{
4
- <T>(args: EmptyObject, value: T): AcceptsBlocks<{
5
- default: [T];
6
- else?: [];
7
- }>;
8
- }>;
3
+ export type WithKeyword = abstract new <T>() => InstanceType<
4
+ ComponentLike<{
5
+ Args: {
6
+ Positional: [value: T];
7
+ };
8
+ Blocks: {
9
+ default: [value: T];
10
+ else: [];
11
+ };
12
+ }>
13
+ >;
@@ -0,0 +1,64 @@
1
+ // This module contains utilities for converting signature types defined
2
+ // in userspace into our internal representation of an invokable's
3
+ // function type signature.
4
+
5
+ import { NamedArgs, UnwrapNamedArgs } from './integration';
6
+
7
+ /**
8
+ * Given an "args hash" (e.g. `{ Named: {...}; Positional: [...] }`),
9
+ * returns a tuple type representing the parameters
10
+ */
11
+ export type InvokableArgs<Args> = [
12
+ ...positional: Constrain<Get<Args, 'Positional'>, Array<unknown>, []>,
13
+ ...named: MaybeNamed<NamedArgs<Get<Args, 'Named'>>>
14
+ ];
15
+
16
+ /** Given a signature `S`, get back the normalized `Args` type. */
17
+ export type ComponentSignatureArgs<S> = S extends {
18
+ Args: infer Args;
19
+ }
20
+ ? Args extends {
21
+ Named?: object;
22
+ Positional?: unknown[];
23
+ }
24
+ ? {
25
+ Named: Get<S['Args'], 'Named', {}>;
26
+ Positional: Get<S['Args'], 'Positional', []>;
27
+ }
28
+ : {
29
+ Named: S['Args'];
30
+ Positional: [];
31
+ }
32
+ : {
33
+ Named: keyof S extends 'Args' | 'Blocks' | 'Element' ? {} : S;
34
+ Positional: [];
35
+ };
36
+
37
+ /** Given a signature `S`, get back the normalized `Blocks` type. */
38
+ export type ComponentSignatureBlocks<S> = S extends { Blocks: infer Blocks }
39
+ ? {
40
+ [Block in keyof Blocks]: Blocks[Block] extends unknown[]
41
+ ? { Params: { Positional: Blocks[Block] } }
42
+ : Blocks[Block];
43
+ }
44
+ : {};
45
+
46
+ /** Given a component signature `S`, get back the `Element` type. */
47
+ export type ComponentSignatureElement<S> = S extends { Element: infer Element }
48
+ ? NonNullable<Element> extends never
49
+ ? unknown
50
+ : Element
51
+ : unknown;
52
+
53
+ export type PrebindArgs<T, Args extends keyof UnwrapNamedArgs<T>> = NamedArgs<
54
+ Omit<UnwrapNamedArgs<T>, Args> & Partial<Pick<UnwrapNamedArgs<T>, Args>>
55
+ >;
56
+
57
+ export type MaybeNamed<T> = {} extends UnwrapNamedArgs<T>
58
+ ? keyof UnwrapNamedArgs<T> extends never
59
+ ? []
60
+ : [named?: T]
61
+ : [named: T];
62
+
63
+ export type Get<T, K, Otherwise = unknown> = K extends keyof T ? T[K] : Otherwise;
64
+ export type Constrain<T, Constraint, Otherwise = Constraint> = T extends Constraint ? T : Otherwise;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glint/template",
3
- "version": "0.9.6",
3
+ "version": "1.0.0-beta.1",
4
4
  "repository": "typed-ember/glint",
5
5
  "description": "Type definitions to back typechecking for Glimmer templates",
6
6
  "license": "MIT",
@@ -14,9 +14,6 @@
14
14
  "-private",
15
15
  "*.d.ts"
16
16
  ],
17
- "peerDependencies": {
18
- "@glimmer/component": "^1.1.2"
19
- },
20
17
  "devDependencies": {
21
18
  "@glimmer/component": "^1.1.2",
22
19
  "@glimmerx/component": "^0.6.7",