Adds support for marking a directive input as required. During template type checking, the compiler will verify that all required inputs have been specified and will raise a diagnostic if one or more are missing. Some specifics:
* Inputs are marked as required by passing an object literal with a `required: true` property to the `Input` decorator or into the `inputs` array.
* Required inputs imply that the directive can't work without them. This is why there's a new check that enforces that all required inputs of a host directive are exposed on the host.
* Required input diagnostics are reported through the `OutOfBandDiagnosticRecorder`, rather than generating a new structure in the TCB, because it allows us to provide a better error message.
* Currently required inputs are only supported during AOT compilation, because knowing which bindings are present during JIT can be tricky and may lead to increased bundle sizes.
Fixes#37706.
PR Close#49468
This reverts commit 13dd614cd1.
This breaks a g3 Typescript compilation tests where diagnostics are
expected for a missing input in the component.
PR Close#49467
Adds support for marking a directive input as required. During template type checking, the compiler will verify that all required inputs have been specified and will raise a diagnostic if one or more are missing. Some specifics:
* Inputs are marked as required by passing an object literal with a `required: true` property to the `Input` decorator or into the `inputs` array.
* Required inputs imply that the directive can't work without them. This is why there's a new check that enforces that all required inputs of a host directive are exposed on the host.
* Required input diagnostics are reported through the `OutOfBandDiagnosticRecorder`, rather than generating a new structure in the TCB, because it allows us to provide a better error message.
* Currently required inputs are only supported during AOT compilation, because knowing which bindings are present during JIT can be tricky and may lead to increased bundle sizes.
Fixes#37706.
PR Close#49453
This reverts commit 1a6ca68154.
This breaks tests in google3 which might be depending on private APIs. We
need to update these tests before we can land this PR.
PR Close#49449
Adds support for marking a directive input as required. During template type checking, the compiler will verify that all required inputs have been specified and will raise a diagnostic if one or more are missing. Some specifics:
* Inputs are marked as required by passing an object literal with a `required: true` property to the `Input` decorator or into the `inputs` array.
* Required inputs imply that the directive can't work without them. This is why there's a new check that enforces that all required inputs of a host directive are exposed on the host.
* Required input diagnostics are reported through the `OutOfBandDiagnosticRecorder`, rather than generating a new structure in the TCB, because it allows us to provide a better error message.
* Currently required inputs are only supported during AOT compilation, because knowing which bindings are present during JIT can be tricky and may lead to increased bundle sizes.
Fixes#37706.
PR Close#49304
The decorator downlevel transform is never used for actual class
decorators because Angular class decorators rely on immediate execution
for JIT. Initially we also supported downleveling of class decorators
for View Engine library output, but libraries are shipped using partial
compilation output and are not using this transform anymore.
The transform is exclusively used for JIT processing, commonly for
test files to help ease temporal dead-zone/forward-ref issues. We can
remove the class decorator downlevel logic to remove technical debt.
PR Close#49351
Consider the following scenario:
1. A TS file with a component and templateUrl exists
2. The template file does not exist.
3. First build: ngtsc will properly report the error, via a FatalDiagnosticError
4. The template file is now created
5. Second build: ngtsc still reports the same errror.
ngtsc persists the analysis data of the component and never invalidates
it when the template/style file becomes available later.
This breaks incremental builds and potentially common workflows
where resource files are added later after the TS file is created. This
did surface as an issue in the Angular CLI yet because Webpack requires
users to re-start the process when a new file is added. With ESBuild
this will change and this also breaks incremental builds with
Bazel/Blaze workers.
To fix this, we have a few options:
* Invalidate the analysis when e.g. the template file is missing. Never
caching it means that it will be re-analyzed on every build iteration.
* Add the resource dependency to ngtsc's incremental file graph. ngtsc
will then know via `host.getModifiedResources` when the file becomes
available- and fresh analysis of component would occur.
The first approach is straightforward to implement and was chosen here.
The second approach would allow ngtsc to re-use more of the analysis
when we know that e.g. the template file still not there, but it
increases complexity unnecessarily because there is no **single**
obvious resource path for e.g. a `templateUrl`. The URL is attempted
to be resolved using multiple strategies, such as TS program root dirs,
or there is support for a custom resolution through
`host.resourceNameToFileName`.
It would be possible to determine some candidate paths and add them to
the dependency tracker, but it seems incomplete given possible external
resolvers like `resourceNameToFileName` and also would likely not have
a sufficient-enough impact given that a broken component decorator is
not expected to remain for too long between N incremental build
iterations.
PR Close#49184
The options to generate NgFactory and NgSummary files were added to Ivy for backwards compatibility with ViewEngine. Since ViewEngine was deprecated and removed, the NgFactory and NgSummary files are no longer used as well.
This commit drops obsolete options to generate NgFactory and NgSummary files. Also, the logic that generates those files is also removed.
PR Close#48268
Fixes that the expression converter was producing code that throws a runtime error if a non-null assertion is used as a part of a safe read, write or call.
Fixes#48742.
PR Close#48801
Reworks some of the existing compiler APIs to make them easier to use in a schematic and exposes a few new ones to surface information we already had. High-level list of changes:
* `getPotentialImportsFor` now requires a class reference, instead of a `PotentialDirective | PotentialPipe`.
* New `getNgModuleMetadata` method has been added to the type checker.
* New `getPipeMetadata` method has been added to the type checker.
* New `getUsedDirectives` method has been added to the type checker.
* New `getUsedPipes` method has been added to the type checker.
* The `decorator` property was exposed on the `TypeCheckableDirectiveMeta`. The property was already present at runtime, but it wasn't specified on the interface.
PR Close#48730
In #47167 an `updateClassDeclaration` call was swapped out with a `createClassDeclaration` which caused a regression where interface references were being retained when using a custom decorator in a project that has `emitDecoratorMetadata` enabled.
These changes switch back to use `updateClassDeclaration`.
Fixes#48448.
PR Close#48638
Allows for self-closing tags to be used for non-native tag names, e.g. `<foo [input]="bar"></foo>` can now be written as `<foo [input]="bar"/>`. Native tag names still have to have closing tags.
Fixes#39525.
PR Close#48535
This is basically a pre-step for combining devmode and prodmode into a
single compilation. We are already achieving this now, and can claim
with confidence that we reduced possible actions by half. This is
especially important now that prodmode is used more often, but rules
potentially still using the devmode ESM sources. We can avoid double
compilations (which existed before the whole ESM migration too!).
We will measure this more when we have more concrete documentation
of the changes & a better planning document.
Changes:
* ts_library will no longer generate devmode `d.ts`. Definitions are
generated as part of prodmode. That way only prodmode can be exposed
via providers.
* applied the same to `ng_module`.
* updates migrations to bundle because *everything* using `ts_library`
is now ESM. This is actually also useful in the future if
schematics rely on e.g. the compiler.
* updates schematics for localize to also bundle. similar reason as
above.
PR Close#48521
Since the Bazel setup in this repo will now always use ESM,
the tooling scripts/binaries in AIO need to be switched to ESM
too. Most of the scripts are already ESM, but a few had to be converted.
Note that the Dgeni generation does not use ESM because it's unaffected
and the Dgeni CLI is used. In the future we could also update the Dgeni
setup to ESM but there is no need currently.
PR Close#48521
Since we generate a `.mjs` file as entry-point for jasmine tests,
a couple of issues prevented the transitive dependencies from
bootstrap targets to be brought in (causing resolution errors):
1. The `_files` (previously `_esm2015`) targets are no longer needed,
and they also miss all the information on runfiles.
2. The aspect for computing linker mappings does not respect the
`bootstrap` attribute from the `spec_entrypoint` so we manually
add the extract ESM output targets (this rule works with the aspect
and forwards linker mappings).
PR Close#48521
For every `ts_library` target we expose a shorthand that grants
access to the JS files because `DefaultInfo` of a ts library
only exposes the `.d.ts` files.
We rename this away from `es2015` since in practice it's a much
higher target these days. Additionally we no longer use the devmode
output but rather use the prodmode output which has the explicit
`.mjs` output- compatible with ESM.
PR Close#48521
For standalone components it may be beneficial to group multiple declarations
into a single array, that can then be imported all at once in `Component.imports`.
If this array is declared within a library, however, would the AOT compiler
need to extract the contents of the array from the declaration file. This
requires that the array is constructed using an `as const` cast, which results
in a readonly tuple declaration in the generated .d.ts file of the library:
```ts
export declare const DECLARATIONS: readonly [typeof StandaloneDir];
```
The partial evaluator logic did not support this syntax, so this pattern was
not functional when a library is involved. This commit adds the necessary
logic in the static interpreter to evaluate this type at compile time.
Closes#48089
PR Close#48091
Because the language service uses the compiler, we try to produce as
much useful information as possible rather than throwing hard errors.
Hard errors cause the compiler to crash. While this can be acceptable
when compiling a program as part of a regular build, this is undesirable
for the language service.
PR Close#48314
The stricter checks under `strictInjectionParameters` in Angular 15 now enforce that
an inherited constructor must be compatible with DI, based on whether all parameters
are valid injection tokens. There is an issue when the constructor is inherited from
a class in a declaration file though, as information on the usage of `@Inject()` is
not present within a declaration file. This means that this stricter check cannot be
accurately performed, resulting in false positives.
This commit disables the stricter check to behave the same as it did prior to
Angular 15, therefore avoiding the false positive.
Fixes#48152
PR Close#48156
`getPotentialPipes` returns possible pipes which can be used in the provided context, whether already in scope or requiring an import.
This is necessary to implement auto-import support for pipes in the language service.
PR Close#48090
This commit updates the logic related to the attribute and property binding rules for <iframe> elements. There is a set of <iframe> attributes that may affect the behavior of an iframe and this change enforces that these attributes are only applied as static attributes, making sure that they are taken into account while creating an <iframe>.
If Angular detects that some of the security-sensitive attributes are applied as an attribute or property binding, it throws an error message, which contains the name of an attribute that is causing the problem and the name of a Component where an iframe is located.
BREAKING CHANGE:
Existing iframe usages may have security-sensitive attributes applied as an attribute or property binding in a template or via host bindings in a directive. Such usages would require an update to ensure compliance with the new stricter rules around iframe bindings.
PR Close#47964
This reverts commit 2d08965b1a.
The reason for revert is that we've identified some issues with implementation. The issues will get addressed soon and the fix would be re-submitted.
PR Close#47959
This commit updates the logic related to the attribute order on iframes and makes the rules more strict. There is a set of iframe attributes that may affect the behavior of an iframe, this change enforces that these attributes are applied before an `src` or `srcdoc` attributes are applied to an iframe, so that they are taken into account.
If Angular detects that some of the attributes are set after the `src` or `srcdoc`, it throws an error message, which contains the name of ann attribute that is causing the problem and the name of a Component where an iframe is located. In most cases, it should be enough to change the order of attributes in a template to move the `src` or `srcdoc` ones to the very end.
BREAKING CHANGE:
Existing iframe usages may have `src` or `srcdoc` preceding other attributes. Such usages may need to be updated to ensure compliance with the new stricter rules around iframe bindings.
PR Close#47935
Implements more of the runtime validations for host directives as compiler diagnostics so that they can be caught earlier. Also does some minor cleanup.
PR Close#47768
In AOT compilations, the `strictInjectionParameters` compiler option can
be enabled to report errors when an `@Injectable` annotated class has a
constructor with parameters that do not provide an injection token, e.g.
only a primitive type or interface.
Since Ivy it's become required that any class with Angular behavior
(e.g. the `ngOnDestroy` lifecycle hook) is decorated using an Angular
decorator, which meant that `@Injectable()` may need to have been added
to abstract base classes. Doing so would then report an error if
`strictInjectionParameters` is enabled, if the abstract class has an
incompatible constructor for DI purposes. This may be fine though, as
a subclass may call the constructor explicitly without relying on
Angular's DI mechanism.
Therefore, this commit excludes abstract classes from the
`strictInjectionParameters` check. This avoids an error from being
reported at compile time. If the constructor ends up being used by
Angular's DI system at runtime, then the factory function of the
abstract class will throw an error by means of the `ɵɵinvalidFactory`
instruction.
In addition to the runtime error, this commit also analyzes the inheritance
chain of an injectable without a constructor to verify that their inherited
constructor is valid.
BREAKING CHANGE: Invalid constructors for DI may now report compilation errors
When a class inherits its constructor from a base class, the compiler may now
report an error when that constructor cannot be used for DI purposes. This may
either be because the base class is missing an Angular decorator such as
`@Injectable()` or `@Directive()`, or because the constructor contains parameters
which do not have an associated token (such as primitive types like `string`).
These situations used to behave unexpectedly at runtime, where the class may be
constructed without any of its constructor parameters, so this is now reported
as an error during compilation.
Any new errors that may be reported because of this change can be resolved either
by decorating the base class from which the constructor is inherited, or by adding
an explicit constructor to the class for which the error is reported.
Closes#37914
PR Close#44615
Previously when a file was being analyzed to determine if a shim should
be generated, up to two calls to the host `fileExists` function per file
per generator were made. In the default host, each `fileExists` call made
two underlying file system calls. Following these calls, the file was then
read via `getSourceFile`. However, `getSourceFile` will return `undefined`
if the requested file does not exist. As a result, `getSourceFile` can be
used directly to request both potential file names and leverage the return
value to determine if the file does not exist. This avoids the need to call
`fileExists` at all.
PR Close#47682
`getPotentialImportsFor` returns an array of possible imports, including TypeScript module specifier and identifier name, for a requested trait in the context of a given component.
PR Close#47631
`getPotentialTemplateDirectives` returns possible directives which can be used in the provided context, whether already in scope or requiring an import.
This is necessary to implement auto-import support for standalone components in the language service.
PR Close#47561
Using raw objects as a lookup structure will inadvertently find methods defined on
`Object`, where strings are expected. This causes errors downstream when string
operations are applied on functions.
This commit switches over to use `Map`s in the DOM element schema registry to fix
this category of issues.
Fixes#46936
PR Close#47220
This option has no longer any effect as Ivy is the only rendering engine.
BREAKING CHANGE: Angular compiler option `enableIvy` has been removed as Ivy is the only rendering engine.
PR Close#47346
This is the compile-time implementation of the `hostDirectives` feature plus a little bit of runtime code to illustrate how the newly-generated code will plug into the runtime. It works by creating a call to the new `ɵɵHostDirectivesFeature` feature whenever a directive has a `hostDirectives` field. Afterwards `ɵɵHostDirectivesFeature` will patch a new function onto the directive definition that will be invoked during directive matching.
For example, if we take the following definition:
```ts
@Directive({
hostDirectives: [HostA, {directive: HostB, inputs: ['input: alias']}]
})
class MyDir {}
```
Will compile to:
```js
MyDir.ɵdir = ɵɵdefineComponent({
features: [ɵɵHostDirectivesFeature([HostA, {
directive: HostB,
inputs: {
input: "alias"
}
}])]
});
```
The template type checking is implemented during directive matching by adding the host directives applied on the host to the array of matched directives whenever the host is matched in a template.
Relates to #8785.
PR Close#46868
This helper accepts a class for an Angular trait, and returns the NgModule which owns that trait. This will be useful for the language service import project, which needs to edit import arrays on the module.
PR Close#47166
Replaces (almost) all of the usages of the deprecated `getMutableClone` function from TypeScript which has started to log deprecation warnings in version 4.8 and will likely be removed in version 5.0. The one place we have left is in the default import handling of ngtsc which will be more difficult to remove.
PR Close#47167
This helper accepts a class, and returns the primary Angular Decorator associated with that trait (e.g. the Component, Pipe, Directive, or NgModule decorator). This will be useful for the language service import project, which needs to edit import arrays inside the decorator.
PR Close#47180
Adds support for TypeScript 4.8 and resolves some issues that came up as a result of the update.
Most of the issues came from some changes in TypeScript where the `decorators` and `modifiers` properties were removed from most node types, and were combined into a single `modifiers` array. Since we need to continue supporting TS 4.6 and 4.7 until v15, I ended up creating a new `ngtsc/ts_compatibility` directory to make it easier to reuse the new backwards-compatible code.
PR Close#47038
improve the error message for non-standalone components which are not
exported from their module, and that are also imported directly as if
they were standalone
this change simply adds the suggestion to the developer to import the
ngModule instead
resolves#46004
PR Close#46114
The source-map package now requires the
`SourceMapConsumer`/`SourceMapGenerator` classes to be instantiated
asynchronously. This commit updates our tests to account for that.
PR Close#46888
Saves us some bytes by not emitting `providers` in `defineInjector`. While the amount of bytes isn't huge, I think that this change is worthwhile, because `ng generate` currently generates `providers: []` with every `NgModule` which users can forget to remove.
PR Close#46301
When generating .d.ts metadata for NgModules, by default we emit type
references to their declarations, imports, and exports. However, this
information is not necessarily useful to consumers. References to private
directives (those that aren't exported by the NgModule) for example aren't
at all useful as they can only affect other components declared in the
NgModule. References to imports are of limited usefulness - they might be
helpful for an IDE to understand the DI structure of an application, but
aren't at all used by a downstream compiler.
Generating this metadata is not without cost. When an incremental build
system uses changes in inputs to determine when a rebuild is necessary, any
changes in .d.ts files might cause downstream targets to rebuild. If those
.d.ts changes are in the "private" side of the NgModule (imports or non-
exported directives/pipes), then these rebuilds are wholly unnecessary.
This commit introduces the `onlyPublishPublicTypingsForNgModules` flag for
the compiler. When this flag is set, the compiler will filter the emitted
references in NgModule .d.ts output and only reference those directives/
pipes that are exported from the NgModule (its public API surface). Omitting
the flag preserves the existing behavior of emitting all references, both
public and private.
This is especially useful for build systems such as Bazel.
PR Close#45894
This commit updates the error message to use correct info depending on whether a component is standalone or not. Previously we were always referring to @NgModules as a place to fix the issue, but not we also mention @Component when needed (for standalone components).
PR Close#46159