@glint/ember-tsc 1.8.2 → 1.8.3
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.
- package/lib/config/environment.d.ts +7 -6
- package/lib/config/environment.d.ts.map +1 -1
- package/lib/config/environment.js +8 -23
- package/lib/config/environment.js.map +1 -1
- package/lib/config/types.d.cts +8 -7
- package/lib/config/types.d.cts.map +1 -1
- package/lib/environment-ember-template-imports/-private/environment/index.d.ts.map +1 -1
- package/lib/environment-ember-template-imports/-private/environment/index.js +33 -28
- package/lib/environment-ember-template-imports/-private/environment/index.js.map +1 -1
- package/lib/environment-ember-template-imports/-private/environment/preprocess.d.ts.map +1 -1
- package/lib/environment-ember-template-imports/-private/environment/preprocess.js +18 -4
- package/lib/environment-ember-template-imports/-private/environment/preprocess.js.map +1 -1
- package/lib/environment-ember-template-imports/-private/environment/transform.d.ts.map +1 -1
- package/lib/environment-ember-template-imports/-private/environment/transform.js +39 -34
- package/lib/environment-ember-template-imports/-private/environment/transform.js.map +1 -1
- package/lib/transform/template/inlining/tagged-strings.js +16 -10
- package/lib/transform/template/inlining/tagged-strings.js.map +1 -1
- package/lib/transform/template/rewrite-module.js +6 -6
- package/lib/transform/template/rewrite-module.js.map +1 -1
- package/lib/transform/template/template-to-typescript.d.ts.map +1 -1
- package/lib/transform/template/template-to-typescript.js +9 -1
- package/lib/transform/template/template-to-typescript.js.map +1 -1
- package/package.json +5 -1
- package/src/config/environment.ts +10 -29
- package/src/config/types.cts +8 -8
- package/src/environment-ember-template-imports/-private/environment/index.ts +33 -28
- package/src/environment-ember-template-imports/-private/environment/preprocess.ts +19 -4
- package/src/environment-ember-template-imports/-private/environment/transform.ts +39 -43
- package/src/transform/template/inlining/tagged-strings.ts +21 -15
- package/src/transform/template/rewrite-module.ts +6 -6
- package/src/transform/template/template-to-typescript.ts +11 -1
- package/types/-private/dsl/globals.d.ts +5 -10
- package/types/-private/intrinsics/comparison.d.ts +7 -14
- package/types/-private/intrinsics/element.d.ts +22 -2
- package/types/-private/intrinsics/get.d.ts +8 -4
- package/types/-private/intrinsics/truth-helpers.d.ts +26 -9
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
GlintEmitMetadata,
|
|
3
3
|
GlintSpecialForm,
|
|
4
4
|
GlintSpecialFormConfig,
|
|
5
|
-
|
|
5
|
+
GlintTemplateConfig,
|
|
6
6
|
} from '@glint/ember-tsc/config-types';
|
|
7
7
|
import type ts from 'typescript';
|
|
8
8
|
import { GlintEnvironment } from '../../../config/index.js';
|
|
@@ -66,10 +66,10 @@ export function calculateTaggedTemplateSpans(
|
|
|
66
66
|
suffix: script.contents.slice(templateLocation.contentEnd, templateLocation.end),
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
// The `<template>` form's backing import is always compiler-synthesized
|
|
70
|
+
// (see `resolveTagInfo`), so there is never a user-written tag binding to
|
|
71
|
+
// reference in a preamble.
|
|
72
|
+
let preamble: Array<string> = [];
|
|
73
73
|
|
|
74
74
|
let specialForms = collectSpecialForms(importedBindings, info.tagConfig.specialForms ?? {});
|
|
75
75
|
|
|
@@ -164,22 +164,28 @@ function resolveTagInfo(
|
|
|
164
164
|
importedBindings: ImportedBindings,
|
|
165
165
|
tag: ts.Identifier,
|
|
166
166
|
environment: GlintEnvironment,
|
|
167
|
-
): { importedBinding: ImportedBinding; tagConfig:
|
|
167
|
+
): { importedBinding: ImportedBinding; tagConfig: GlintTemplateConfig } | undefined {
|
|
168
168
|
let importedBinding = importedBindings[tag.text];
|
|
169
169
|
if (!importedBinding) {
|
|
170
170
|
return;
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
173
|
+
// Only the compiler-generated `<template>` form is processed. Its backing
|
|
174
|
+
// import is synthesized by the gts/gjs transform (see `addTagImport` in
|
|
175
|
+
// `environment-ember-template-imports/-private/environment/transform.ts`) and
|
|
176
|
+
// therefore has no position in the original source. User-authored tagged
|
|
177
|
+
// templates (`hbs`...``) have a real import and are deliberately ignored —
|
|
178
|
+
// Glint no longer supports tagged-string templates.
|
|
179
|
+
if (!importedBinding.synthetic) {
|
|
180
|
+
return;
|
|
182
181
|
}
|
|
182
|
+
|
|
183
|
+
let tagConfig = environment.getTemplateConfig();
|
|
184
|
+
if (!tagConfig) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return { importedBinding, tagConfig };
|
|
183
189
|
}
|
|
184
190
|
|
|
185
191
|
type ImportedBinding = { specifier: string; source: string; synthetic: boolean };
|
|
@@ -160,12 +160,12 @@ function calculateCorrelatedSpans(
|
|
|
160
160
|
ts.transform(ast, [
|
|
161
161
|
(context) =>
|
|
162
162
|
function visit<T extends ts.Node>(node: T): T {
|
|
163
|
-
//
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
//
|
|
167
|
-
//
|
|
168
|
-
//
|
|
163
|
+
// The gts/gjs preprocessor rewrites every `<template>` into a tagged
|
|
164
|
+
// template expression using a compiler-synthesized tag (see
|
|
165
|
+
// `environment-ember-template-imports/-private/environment/{preprocess,transform}.ts`).
|
|
166
|
+
// We look for those tagged templates here and hand them to
|
|
167
|
+
// `calculateTaggedTemplateSpans`, which only processes the synthesized
|
|
168
|
+
// tag — user-authored `hbs`...`` tagged strings are not supported.
|
|
169
169
|
if (ts.isTaggedTemplateExpression(node)) {
|
|
170
170
|
let meta = emitMetadata.get(node);
|
|
171
171
|
let result = calculateTaggedTemplateSpans(ts, node, meta, script, environment);
|
|
@@ -553,7 +553,17 @@ export function templateToTypescript(
|
|
|
553
553
|
let isGlobal = globals ? globals.includes(name) : true;
|
|
554
554
|
let form = specialForms[name];
|
|
555
555
|
|
|
556
|
-
|
|
556
|
+
// Operator special forms (`===`, `!==`, `&&`, `||`, `!`) emit only the
|
|
557
|
+
// operator expression — never a reference to the keyword itself. For a
|
|
558
|
+
// documented global keyword (e.g. `eq`/`neq`) that would drop hover
|
|
559
|
+
// docs and go-to-definition, so we still emit a discarded reference to
|
|
560
|
+
// it. Narrowing is preserved: the keyword is emitted as the throwaway
|
|
561
|
+
// first operand of a comma expression whose value is the operator
|
|
562
|
+
// expression (`(noop(eq), (a === b))`).
|
|
563
|
+
let isOperatorForm =
|
|
564
|
+
form === '===' || form === '!==' || form === '&&' || form === '||' || form === '!';
|
|
565
|
+
|
|
566
|
+
return { name, form, requiresConsumption: !isGlobal || isOperatorForm };
|
|
557
567
|
}
|
|
558
568
|
}
|
|
559
569
|
|
|
@@ -4,14 +4,7 @@ import * as VM from '@glint/template/-private/keywords';
|
|
|
4
4
|
|
|
5
5
|
import { ActionKeyword } from '../intrinsics/action';
|
|
6
6
|
import { ArrayHelper, HashHelper } from '../intrinsics/array-hash';
|
|
7
|
-
import {
|
|
8
|
-
EqHelper,
|
|
9
|
-
GtHelper,
|
|
10
|
-
GteHelper,
|
|
11
|
-
LtHelper,
|
|
12
|
-
LteHelper,
|
|
13
|
-
NeqHelper,
|
|
14
|
-
} from '../intrinsics/comparison';
|
|
7
|
+
import { GtHelper, GteHelper, LtHelper, LteHelper } from '../intrinsics/comparison';
|
|
15
8
|
import { EachKeyword } from '../intrinsics/each';
|
|
16
9
|
import { EachInKeyword } from '../intrinsics/each-in';
|
|
17
10
|
import { ElementHelper } from '../intrinsics/element';
|
|
@@ -331,7 +324,8 @@ interface KeywordsForEmber71Members {
|
|
|
331
324
|
*
|
|
332
325
|
* @see https://api.emberjs.com/ember/release/functions/@ember%2Fhelper/eq
|
|
333
326
|
*/
|
|
334
|
-
eq
|
|
327
|
+
// `{{eq}}` is emitted as the native `===` operator in `ember-tsc`.
|
|
328
|
+
eq: void;
|
|
335
329
|
|
|
336
330
|
/**
|
|
337
331
|
* `{{fn}}` is a helper that receives a function and some arguments, and
|
|
@@ -459,7 +453,8 @@ interface KeywordsForEmber71Members {
|
|
|
459
453
|
*
|
|
460
454
|
* @see https://api.emberjs.com/ember/release/functions/@ember%2Fhelper/neq
|
|
461
455
|
*/
|
|
462
|
-
neq
|
|
456
|
+
// `{{neq}}` is emitted as the native `!==` operator in `ember-tsc`.
|
|
457
|
+
neq: void;
|
|
463
458
|
|
|
464
459
|
/**
|
|
465
460
|
* The `{{not}}` helper returns the logical negation of its argument using
|
|
@@ -1,19 +1,12 @@
|
|
|
1
1
|
import { DirectInvokable } from '@glint/template/-private/integration';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<A, B>(a: A, b: B): [A] extends [B] ? ([B] extends [A] ? true : boolean) : boolean;
|
|
11
|
-
}>;
|
|
12
|
-
|
|
13
|
-
/** `(neq a b)` — strict inequality. Built-in keyword in ember-source >= 7.1. */
|
|
14
|
-
export type NeqHelper = DirectInvokable<{
|
|
15
|
-
<A, B>(a: A, b: B): [A] extends [B] ? ([B] extends [A] ? false : boolean) : boolean;
|
|
16
|
-
}>;
|
|
3
|
+
// NOTE: `eq`/`neq` (RFC 561) are not represented here. Because their runtime is
|
|
4
|
+
// exactly `left === right` / `left !== right`, they are emitted as the native
|
|
5
|
+
// `===`/`!==` operators (see the `ember-template-imports` environment's
|
|
6
|
+
// `specialForms`) — which, unlike a boolean-returning helper type, lets
|
|
7
|
+
// TypeScript narrow discriminated unions in `{{#if (eq foo.kind "a")}}`. The
|
|
8
|
+
// `lt`/`lte`/`gt`/`gte` keywords below have no narrowing benefit and remain
|
|
9
|
+
// ordinary helpers.
|
|
17
10
|
|
|
18
11
|
/** `(lt a b)` — numeric less-than. Built-in keyword in ember-source >= 7.1. */
|
|
19
12
|
export type LtHelper = DirectInvokable<{
|
|
@@ -6,8 +6,28 @@ import { DirectInvokable } from '@glint/template/-private/integration';
|
|
|
6
6
|
* name. Built-in keyword in ember-source >= 7.1 (RFC 389).
|
|
7
7
|
*/
|
|
8
8
|
export type ElementHelper = DirectInvokable<{
|
|
9
|
-
(
|
|
10
|
-
|
|
9
|
+
// `const K` preserves the literal tag name (e.g. `"video"`) through Glint's
|
|
10
|
+
// `resolve()` inference; without it TypeScript widens the argument to `string`
|
|
11
|
+
// and narrowing collapses to the base `Element`. The `string & {}` member lets
|
|
12
|
+
// a genuinely dynamic (non-literal) tag name still match and fall back to
|
|
13
|
+
// `Element`, covering both HTML and SVG.
|
|
14
|
+
<const K extends keyof HTMLElementTagNameMap | keyof SVGElementTagNameMap | (string & {})>(
|
|
15
|
+
tagName: K,
|
|
16
|
+
): ComponentLike<{
|
|
17
|
+
// A known HTML or SVG tag name narrows to the corresponding element type.
|
|
18
|
+
// When a name exists in both maps (e.g. `a`, `script`, `style`, `title`)
|
|
19
|
+
// the HTML element wins, matching the default (non-SVG) namespace at
|
|
20
|
+
// runtime. An empty string renders the block without a wrapping element, so
|
|
21
|
+
// there is no element to receive attributes (`null`, which makes applying
|
|
22
|
+
// any attribute a type error). Any other (dynamic) tag name falls back to
|
|
23
|
+
// the base `Element`, covering both HTML and SVG.
|
|
24
|
+
Element: K extends keyof HTMLElementTagNameMap
|
|
25
|
+
? HTMLElementTagNameMap[K]
|
|
26
|
+
: K extends keyof SVGElementTagNameMap
|
|
27
|
+
? SVGElementTagNameMap[K]
|
|
28
|
+
: K extends ''
|
|
29
|
+
? null
|
|
30
|
+
: Element;
|
|
11
31
|
Args: Record<string, unknown>;
|
|
12
32
|
Blocks: { default: [] };
|
|
13
33
|
}>;
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { DirectInvokable } from '@glint/template/-private/integration';
|
|
2
2
|
import ObjectProxy from '@ember/object/proxy';
|
|
3
|
-
import '@ember/object/-private/types';
|
|
4
3
|
|
|
5
4
|
// This hack lets us support both the stable/preview types from `ember-source`
|
|
6
5
|
// and the classic types still live on DefinitelyTyped. If using the DT types,
|
|
7
|
-
//
|
|
8
|
-
// the rest of the DT types. If using the stable/preview
|
|
9
|
-
// being a no-op.
|
|
6
|
+
// the `declare module` below acts as a declaration merge for a module which is
|
|
7
|
+
// then integrated via the rest of the DT types. If using the stable/preview
|
|
8
|
+
// types, the module does not exist and this ends up being a no-op.
|
|
9
|
+
//
|
|
10
|
+
// Note: we intentionally do *not* add a side-effect `import '@ember/object/-private/types'`
|
|
11
|
+
// here. TypeScript 6.0 errors (TS2882) on a side-effect import of a module that
|
|
12
|
+
// cannot be resolved, which is exactly the no-op (ember-source) case above. The
|
|
13
|
+
// `declare module` augmentation still merges into the DT module when it exists.
|
|
10
14
|
declare const GetSetMarker: unique symbol;
|
|
11
15
|
declare module '@ember/object/-private/types' {
|
|
12
16
|
interface ComputedPropertyMarker<Get, Set = Get> {
|
|
@@ -1,32 +1,49 @@
|
|
|
1
1
|
import { DirectInvokable } from '@glint/template/-private/integration';
|
|
2
2
|
|
|
3
|
-
import type { FirstFalsy, FirstTruthy, MaybeTruthy
|
|
3
|
+
import type { Falsy, FirstFalsy, FirstTruthy, MaybeTruthy } from './truth-convert';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* `(and a b ...)` — short-circuit logical AND. Returns the first falsy
|
|
7
7
|
* positional argument or the last argument. Available as a built-in keyword
|
|
8
8
|
* in ember-source >= 7.1 (RFC 560).
|
|
9
|
+
*
|
|
10
|
+
* The runtime requires **at least two** arguments (it throws otherwise), so the
|
|
11
|
+
* signature pins two leading positionals before the rest.
|
|
9
12
|
*/
|
|
10
13
|
export type AndHelper = DirectInvokable<{
|
|
11
|
-
<
|
|
14
|
+
<A extends MaybeTruthy, B extends MaybeTruthy, Rest extends MaybeTruthy[]>(
|
|
15
|
+
a: A,
|
|
16
|
+
b: B,
|
|
17
|
+
...rest: Rest
|
|
18
|
+
): FirstFalsy<[A, B, ...Rest]>;
|
|
12
19
|
}>;
|
|
13
20
|
|
|
14
21
|
/**
|
|
15
22
|
* `(or a b ...)` — short-circuit logical OR. Returns the first truthy
|
|
16
23
|
* positional argument or the last argument. Available as a built-in keyword
|
|
17
24
|
* in ember-source >= 7.1 (RFC 560).
|
|
25
|
+
*
|
|
26
|
+
* The runtime requires **at least two** arguments (it throws otherwise), so the
|
|
27
|
+
* signature pins two leading positionals before the rest.
|
|
18
28
|
*/
|
|
19
29
|
export type OrHelper = DirectInvokable<{
|
|
20
|
-
<
|
|
30
|
+
<A extends MaybeTruthy, B extends MaybeTruthy, Rest extends MaybeTruthy[]>(
|
|
31
|
+
a: A,
|
|
32
|
+
b: B,
|
|
33
|
+
...rest: Rest
|
|
34
|
+
): FirstTruthy<[A, B, ...Rest]>;
|
|
21
35
|
}>;
|
|
22
36
|
|
|
23
37
|
/**
|
|
24
|
-
* `(not value)` — boolean negation using
|
|
25
|
-
*
|
|
26
|
-
*
|
|
38
|
+
* `(not value)` — boolean negation using Handlebars truthiness semantics.
|
|
39
|
+
* Built-in keyword in ember-source >= 7.1 (RFC 560).
|
|
40
|
+
*
|
|
41
|
+
* Typed as a type predicate over Ember's `Falsy` type so that using it as a
|
|
42
|
+
* condition narrows the operand: in `{{#if (not value)}}` the operand is
|
|
43
|
+
* narrowed to its falsy members, and in the `{{else}}` branch to its truthy
|
|
44
|
+
* members. (As a predicate its *value* is `boolean` rather than a `true`/
|
|
45
|
+
* `false` literal — narrowing in conditions is the more useful guarantee.)
|
|
27
46
|
*/
|
|
28
47
|
export type NotHelper = DirectInvokable<{
|
|
29
|
-
<T>(
|
|
30
|
-
value: T,
|
|
31
|
-
): TruthConvert<T> extends true ? false : TruthConvert<T> extends false ? true : boolean;
|
|
48
|
+
<T>(value: T): value is Extract<T, Falsy>;
|
|
32
49
|
}>;
|