1 | /**
|
2 | * @license
|
3 | * Copyright Google LLC All Rights Reserved.
|
4 | *
|
5 | * Use of this source code is governed by an MIT-style license that can be
|
6 | * found in the LICENSE file at https://angular.io/license
|
7 | */
|
8 | import { AbsoluteSourceSpan, BoundTarget, DirectiveMeta, ParseSourceSpan, SchemaMetadata } from '@angular/compiler';
|
9 | import ts from 'typescript';
|
10 | import { ErrorCode } from '../../diagnostics';
|
11 | import { Reference } from '../../imports';
|
12 | import { ClassPropertyMapping, DirectiveTypeCheckMeta, HostDirectiveMeta, InputMapping } from '../../metadata';
|
13 | import { ClassDeclaration } from '../../reflection';
|
14 | /**
|
15 | * Extension of `DirectiveMeta` that includes additional information required to type-check the
|
16 | * usage of a particular directive.
|
17 | */
|
18 | export interface TypeCheckableDirectiveMeta extends DirectiveMeta, DirectiveTypeCheckMeta {
|
19 | ref: Reference<ClassDeclaration>;
|
20 | queries: string[];
|
21 | inputs: ClassPropertyMapping<InputMapping>;
|
22 | outputs: ClassPropertyMapping;
|
23 | isStandalone: boolean;
|
24 | hostDirectives: HostDirectiveMeta[] | null;
|
25 | decorator: ts.Decorator | null;
|
26 | }
|
27 | export type TemplateId = string & {
|
28 | __brand: 'TemplateId';
|
29 | };
|
30 | /**
|
31 | * A `ts.Diagnostic` with additional information about the diagnostic related to template
|
32 | * type-checking.
|
33 | */
|
34 | export interface TemplateDiagnostic extends ts.Diagnostic {
|
35 | /**
|
36 | * The component with the template that resulted in this diagnostic.
|
37 | */
|
38 | componentFile: ts.SourceFile;
|
39 | /**
|
40 | * The template id of the component that resulted in this diagnostic.
|
41 | */
|
42 | templateId: TemplateId;
|
43 | }
|
44 | /**
|
45 | * A `TemplateDiagnostic` with a specific error code.
|
46 | */
|
47 | export type NgTemplateDiagnostic<T extends ErrorCode> = TemplateDiagnostic & {
|
48 | __ngCode: T;
|
49 | };
|
50 | /**
|
51 | * Metadata required in addition to a component class in order to generate a type check block (TCB)
|
52 | * for that component.
|
53 | */
|
54 | export interface TypeCheckBlockMetadata {
|
55 | /**
|
56 | * A unique identifier for the class which gave rise to this TCB.
|
57 | *
|
58 | * This can be used to map errors back to the `ts.ClassDeclaration` for the component.
|
59 | */
|
60 | id: TemplateId;
|
61 | /**
|
62 | * Semantic information about the template of the component.
|
63 | */
|
64 | boundTarget: BoundTarget<TypeCheckableDirectiveMeta>;
|
65 | pipes: Map<string, Reference<ClassDeclaration<ts.ClassDeclaration>>>;
|
66 | /**
|
67 | * Schemas that apply to this template.
|
68 | */
|
69 | schemas: SchemaMetadata[];
|
70 | isStandalone: boolean;
|
71 | }
|
72 | export interface TypeCtorMetadata {
|
73 | /**
|
74 | * The name of the requested type constructor function.
|
75 | */
|
76 | fnName: string;
|
77 | /**
|
78 | * Whether to generate a body for the function or not.
|
79 | */
|
80 | body: boolean;
|
81 | /**
|
82 | * Input, output, and query field names in the type which should be included as constructor input.
|
83 | */
|
84 | fields: {
|
85 | inputs: string[];
|
86 | outputs: string[];
|
87 | queries: string[];
|
88 | };
|
89 | /**
|
90 | * `Set` of field names which have type coercion enabled.
|
91 | */
|
92 | coercedInputFields: Set<string>;
|
93 | }
|
94 | export interface TypeCheckingConfig {
|
95 | /**
|
96 | * Whether to check the left-hand side type of binding operations.
|
97 | *
|
98 | * For example, if this is `false` then the expression `[input]="expr"` will have `expr` type-
|
99 | * checked, but not the assignment of the resulting type to the `input` property of whichever
|
100 | * directive or component is receiving the binding. If set to `true`, both sides of the assignment
|
101 | * are checked.
|
102 | *
|
103 | * This flag only affects bindings to components/directives. Bindings to the DOM are checked if
|
104 | * `checkTypeOfDomBindings` is set.
|
105 | */
|
106 | checkTypeOfInputBindings: boolean;
|
107 | /**
|
108 | * Whether to honor the access modifiers on input bindings for the component/directive.
|
109 | *
|
110 | * If a template binding attempts to assign to an input that is private/protected/readonly,
|
111 | * this will produce errors when enabled but will not when disabled.
|
112 | */
|
113 | honorAccessModifiersForInputBindings: boolean;
|
114 | /**
|
115 | * Whether to use strict null types for input bindings for directives.
|
116 | *
|
117 | * If this is `true`, applications that are compiled with TypeScript's `strictNullChecks` enabled
|
118 | * will produce type errors for bindings which can evaluate to `undefined` or `null` where the
|
119 | * inputs's type does not include `undefined` or `null` in its type. If set to `false`, all
|
120 | * binding expressions are wrapped in a non-null assertion operator to effectively disable strict
|
121 | * null checks. This may be particularly useful when the directive is from a library that is not
|
122 | * compiled with `strictNullChecks` enabled.
|
123 | *
|
124 | * If `checkTypeOfInputBindings` is set to `false`, this flag has no effect.
|
125 | */
|
126 | strictNullInputBindings: boolean;
|
127 | /**
|
128 | * Whether to check text attributes that happen to be consumed by a directive or component.
|
129 | *
|
130 | * For example, in a template containing `<input matInput disabled>` the `disabled` attribute ends
|
131 | * up being consumed as an input with type `boolean` by the `matInput` directive. At runtime, the
|
132 | * input will be set to the attribute's string value, which is an empty string for attributes
|
133 | * without a value, so with this flag set to `true`, an error would be reported. If set to
|
134 | * `false`, text attributes will never report an error.
|
135 | *
|
136 | * Note that if `checkTypeOfInputBindings` is set to `false`, this flag has no effect.
|
137 | */
|
138 | checkTypeOfAttributes: boolean;
|
139 | /**
|
140 | * Whether to check the left-hand side type of binding operations to DOM properties.
|
141 | *
|
142 | * As `checkTypeOfBindings`, but only applies to bindings to DOM properties.
|
143 | *
|
144 | * This does not affect the use of the `DomSchemaChecker` to validate the template against the DOM
|
145 | * schema. Rather, this flag is an experimental, not yet complete feature which uses the
|
146 | * lib.dom.d.ts DOM typings in TypeScript to validate that DOM bindings are of the correct type
|
147 | * for assignability to the underlying DOM element properties.
|
148 | */
|
149 | checkTypeOfDomBindings: boolean;
|
150 | /**
|
151 | * Whether to infer the type of the `$event` variable in event bindings for directive outputs or
|
152 | * animation events.
|
153 | *
|
154 | * If this is `true`, the type of `$event` will be inferred based on the generic type of
|
155 | * `EventEmitter`/`Subject` of the output. If set to `false`, the `$event` variable will be of
|
156 | * type `any`.
|
157 | */
|
158 | checkTypeOfOutputEvents: boolean;
|
159 | /**
|
160 | * Whether to infer the type of the `$event` variable in event bindings for animations.
|
161 | *
|
162 | * If this is `true`, the type of `$event` will be `AnimationEvent` from `@angular/animations`.
|
163 | * If set to `false`, the `$event` variable will be of type `any`.
|
164 | */
|
165 | checkTypeOfAnimationEvents: boolean;
|
166 | /**
|
167 | * Whether to infer the type of the `$event` variable in event bindings to DOM events.
|
168 | *
|
169 | * If this is `true`, the type of `$event` will be inferred based on TypeScript's
|
170 | * `HTMLElementEventMap`, with a fallback to the native `Event` type. If set to `false`, the
|
171 | * `$event` variable will be of type `any`.
|
172 | */
|
173 | checkTypeOfDomEvents: boolean;
|
174 | /**
|
175 | * Whether to infer the type of local references to DOM elements.
|
176 | *
|
177 | * If this is `true`, the type of a `#ref` variable on a DOM node in the template will be
|
178 | * determined by the type of `document.createElement` for the given DOM node type. If set to
|
179 | * `false`, the type of `ref` for DOM nodes will be `any`.
|
180 | */
|
181 | checkTypeOfDomReferences: boolean;
|
182 | /**
|
183 | * Whether to infer the type of local references.
|
184 | *
|
185 | * If this is `true`, the type of a `#ref` variable that points to a directive or `TemplateRef` in
|
186 | * the template will be inferred correctly. If set to `false`, the type of `ref` for will be
|
187 | * `any`.
|
188 | */
|
189 | checkTypeOfNonDomReferences: boolean;
|
190 | /**
|
191 | * Whether to adjust the output of the TCB to ensure compatibility with the `TemplateTypeChecker`.
|
192 | *
|
193 | * The statements generated in the TCB are optimized for performance and producing diagnostics.
|
194 | * These optimizations can result in generating a TCB that does not have all the information
|
195 | * needed by the `TemplateTypeChecker` for retrieving `Symbol`s. For example, as an optimization,
|
196 | * the TCB will not generate variable declaration statements for directives that have no
|
197 | * references, inputs, or outputs. However, the `TemplateTypeChecker` always needs these
|
198 | * statements to be present in order to provide `ts.Symbol`s and `ts.Type`s for the directives.
|
199 | *
|
200 | * When set to `false`, enables TCB optimizations for template diagnostics.
|
201 | * When set to `true`, ensures all information required by `TemplateTypeChecker` to
|
202 | * retrieve symbols for template nodes is available in the TCB.
|
203 | */
|
204 | enableTemplateTypeChecker: boolean;
|
205 | /**
|
206 | * Whether to include type information from pipes in the type-checking operation.
|
207 | *
|
208 | * If this is `true`, then the pipe's type signature for `transform()` will be used to check the
|
209 | * usage of the pipe. If this is `false`, then the result of applying a pipe will be `any`, and
|
210 | * the types of the pipe's value and arguments will not be matched against the `transform()`
|
211 | * method.
|
212 | */
|
213 | checkTypeOfPipes: boolean;
|
214 | /**
|
215 | * Whether to narrow the types of template contexts.
|
216 | */
|
217 | applyTemplateContextGuards: boolean;
|
218 | /**
|
219 | * Whether to use a strict type for null-safe navigation operations.
|
220 | *
|
221 | * If this is `false`, then the return type of `a?.b` or `a?()` will be `any`. If set to `true`,
|
222 | * then the return type of `a?.b` for example will be the same as the type of the ternary
|
223 | * expression `a != null ? a.b : a`.
|
224 | */
|
225 | strictSafeNavigationTypes: boolean;
|
226 | /**
|
227 | * Whether to descend into template bodies and check any bindings there.
|
228 | */
|
229 | checkTemplateBodies: boolean;
|
230 | /**
|
231 | * Whether to always apply DOM schema checks in template bodies, independently of the
|
232 | * `checkTemplateBodies` setting.
|
233 | */
|
234 | alwaysCheckSchemaInTemplateBodies: boolean;
|
235 | /**
|
236 | * Whether to check resolvable queries.
|
237 | *
|
238 | * This is currently an unsupported feature.
|
239 | */
|
240 | checkQueries: false;
|
241 | /**
|
242 | * Whether to use any generic types of the context component.
|
243 | *
|
244 | * If this is `true`, then if the context component has generic types, those will be mirrored in
|
245 | * the template type-checking context. If `false`, any generic type parameters of the context
|
246 | * component will be set to `any` during type-checking.
|
247 | */
|
248 | useContextGenericType: boolean;
|
249 | /**
|
250 | * Whether or not to infer types for object and array literals in the template.
|
251 | *
|
252 | * If this is `true`, then the type of an object or an array literal in the template will be the
|
253 | * same type that TypeScript would infer if the literal appeared in code. If `false`, then such
|
254 | * literals are cast to `any` when declared.
|
255 | */
|
256 | strictLiteralTypes: boolean;
|
257 | /**
|
258 | * Whether to use inline type constructors.
|
259 | *
|
260 | * If this is `true`, create inline type constructors when required. For example, if a type
|
261 | * constructor's parameters has private types, it cannot be created normally, so we inline it in
|
262 | * the directives definition file.
|
263 | *
|
264 | * If false, do not create inline type constructors. Fall back to using `any` type for
|
265 | * constructors that normally require inlining.
|
266 | *
|
267 | * This option requires the environment to support inlining. If the environment does not support
|
268 | * inlining, this must be set to `false`.
|
269 | */
|
270 | useInlineTypeConstructors: boolean;
|
271 | /**
|
272 | * Whether or not to produce diagnostic suggestions in cases where the compiler could have
|
273 | * inferred a better type for a construct, but was prevented from doing so by the current type
|
274 | * checking configuration.
|
275 | *
|
276 | * For example, if the compiler could have used a template context guard to infer a better type
|
277 | * for a structural directive's context and `let-` variables, but the user is in
|
278 | * `fullTemplateTypeCheck` mode and such guards are therefore disabled.
|
279 | *
|
280 | * This mode is useful for clients like the Language Service which want to inform users of
|
281 | * opportunities to improve their own developer experience.
|
282 | */
|
283 | suggestionsForSuboptimalTypeInference: boolean;
|
284 | }
|
285 | export type TemplateSourceMapping = DirectTemplateSourceMapping | IndirectTemplateSourceMapping | ExternalTemplateSourceMapping;
|
286 | /**
|
287 | * A mapping to an inline template in a TS file.
|
288 | *
|
289 | * `ParseSourceSpan`s for this template should be accurate for direct reporting in a TS error
|
290 | * message.
|
291 | */
|
292 | export interface DirectTemplateSourceMapping {
|
293 | type: 'direct';
|
294 | node: ts.StringLiteral | ts.NoSubstitutionTemplateLiteral;
|
295 | }
|
296 | /**
|
297 | * A mapping to a template which is still in a TS file, but where the node positions in any
|
298 | * `ParseSourceSpan`s are not accurate for one reason or another.
|
299 | *
|
300 | * This can occur if the template expression was interpolated in a way where the compiler could not
|
301 | * construct a contiguous mapping for the template string. The `node` refers to the `template`
|
302 | * expression.
|
303 | */
|
304 | export interface IndirectTemplateSourceMapping {
|
305 | type: 'indirect';
|
306 | componentClass: ClassDeclaration;
|
307 | node: ts.Expression;
|
308 | template: string;
|
309 | }
|
310 | /**
|
311 | * A mapping to a template declared in an external HTML file, where node positions in
|
312 | * `ParseSourceSpan`s represent accurate offsets into the external file.
|
313 | *
|
314 | * In this case, the given `node` refers to the `templateUrl` expression.
|
315 | */
|
316 | export interface ExternalTemplateSourceMapping {
|
317 | type: 'external';
|
318 | componentClass: ClassDeclaration;
|
319 | node: ts.Expression;
|
320 | template: string;
|
321 | templateUrl: string;
|
322 | }
|
323 | /**
|
324 | * A mapping of a TCB template id to a span in the corresponding template source.
|
325 | */
|
326 | export interface SourceLocation {
|
327 | id: TemplateId;
|
328 | span: AbsoluteSourceSpan;
|
329 | }
|
330 | /**
|
331 | * A representation of all a node's template mapping information we know. Useful for producing
|
332 | * diagnostics based on a TCB node or generally mapping from a TCB node back to a template location.
|
333 | */
|
334 | export interface FullTemplateMapping {
|
335 | sourceLocation: SourceLocation;
|
336 | templateSourceMapping: TemplateSourceMapping;
|
337 | span: ParseSourceSpan;
|
338 | }
|