Leading trivia, such as whitespace or comments, is
confusing for developers looking at source-mapped
templates, since they expect the source-map segment
to start after the trivia.
This commit adds skipping trivial characters to the lexer;
and then implements that in the template parser.
PR Close#30095
Fixes view and content queries not being inherited in Ivy, if the base class hasn't been annotated with an Angular decorator (e.g. `Component` or `Directive`).
Also reworks the way the `ngBaseDef` is created so that it is added at the same point as the queries, rather than inside of the `Input` and `Output` decorators.
This PR partially resolves FW-1275. Support for host bindings will be added in a follow-up, because this PR is somewhat large as it is.
PR Close#30015
Previously, a template's context name would only be included in an embedded
template function if the element that the template was declared on has a
tag name. This is generally true for elements, except for `ng-content`
that does not have a tag name. By omitting the context name the compiler
could introduce duplicate template function names, which would fail at runtime.
This commit fixes the behavior by always including the context name in the
template function's name, regardless of tag name.
Resolves FW-1272
PR Close#30025
Fixes Ivy throwing an error because it tries to generate styling instructions for empty `style` and `class` bindings.
This PR resolves FW-1274.
PR Close#30024
Previously, Template.templateAttrs was introduced to capture attribute
bindings which originated from microsyntax (e.g. bindings in *ngFor="...").
This means that a Template node can have two different structures, depending
on whether it originated from microsyntax or from a literal <ng-template>.
In the literal case, the node behaves much like an Element node, it has
attributes, inputs, and outputs which determine which directives apply.
In the microsyntax case, though, only the templateAttrs should be used
to determine which directives apply.
Previously, both the t2_binder and the TemplateDefinitionBuilder were using
the wrong set of attributes to match directives - combining the attributes,
inputs, outputs, and templateAttrs of the Template node regardless of its
origin. In the TDB's case this wasn't a problem, since the TDB collects a
global Set of directives used in the template, so it didn't matter whether
the directive was also recognized on the <ng-template>. t2_binder's API
distinguishes between directives on specific nodes, though, so it's more
sensitive to mismatching.
In particular, this showed up as an assertion failure in template type-
checking in certain cases, when a directive was accidentally matched on
a microsyntax template element and also had a binding which referenced a
variable declared in the microsyntax. This resulted in the type-checker
attempting to generate a reference to a variable that didn't exist in that
scope.
The fix is to distinguish between the two cases and select the appropriate
set of attributes to match on accordingly.
Testing strategy: tested in the t2_binder tests.
PR Close#29698
Previously the template type-checking engine processed templates in a linear
manner, and could not handle '#' references within a template. One reason
for this is that '#' references are non-linear - a reference can be used
before its declaration. Consider the template:
```html
{{ref.value}}
<input #ref>
```
Accommodating this required refactoring the type-checking code generator to
be able to produce Type Check Block (TCB) code non-linearly. Now, each
template is processed and a list of TCB operations (`TcbOp`s) are created.
Non-linearity is modeled via dependencies between operations, with the
appropriate protection in place for circular dependencies.
Testing strategy: TCB tests included.
PR Close#29698
This commit adds registration of AOT compiled NgModules that have 'id'
properties set in their metadata. Such modules have a call to
registerNgModuleType() emitted as part of compilation.
The JIT behavior of this code is already in place.
This is required for module loading systems (such as g3) which rely on
getModuleFactory().
PR Close#29980
The `@angular/compiler` package currently contains the logic for determining whether
given queries are used statically or dynamically. This logic would be necessary in order
to build a schematic that leverages the Angular compiler API's in order to simulate the
query timing based on what ViewEngine computed at compilation-time/runtime.
Exporting the logic that is necessary to detect the timing should not affect the public
API as the `@angular/compiler` package is denoted as private in `PUBLIC_API.md`
PR Close#29815
Prior to this change, element attributes annotated with i18n- prefix were removed from element attribute list and processed separately by i18n-specific logic. This behavior is causing issues with directive matching, since attributes are not present in the list of attrs for matching purposes. This commit updates i18n logic to retain attributes in the main attribute list, thus allowing directive matching logic to work correctly.
PR Close#29856
The `Δ` caused issue with other infrastructure, and we are temporarily
changing it to `ɵɵ`.
This commit also patches ts_api_guardian_test and AIO to understand `ɵɵ`.
PR Close#29850
So far using runtime i18n with ivy meant that you needed to use Closure and `goog.getMsg` (or a polyfill). This PR changes the compiler to output both closure & non-closure code, while the unused option will be tree-shaken by minifiers.
This means that if you use the Angular CLI with ivy and load a translations file, you can use i18n and the application will not throw at runtime.
For now it will not translate your application, but at least you can try ivy without having to remove all of your i18n code and configuration.
PR Close#28689
Currently in Ivy we pass both the raw and parsed selectors to the projectionDef instruction, because the parsed selectors are used to match most nodes, whereas the raw ones are used to match against nodes with the ngProjectAs attribute. The raw selectors add a fair bit of code that won't be used in most cases, because ngProjectAs is somewhat rare.
These changes rework the compiler not to output the raw selectors in the projectionDef, but to parse the selector in ngProjectAs and to store it on the TAttributes. The logic for matching has also been changed so that it matches the pre-parsed ngProjectAs selector against the list of projection selectors.
PR Close#29578
The defineInjector function specifies its providers and imports array to
be optional, so if no providers/imports are present these keys may be
omitted. This commit updates the compiler to only generate the keys when
necessary.
PR Close#29598
Prior to this change, a module's imports and exports would be used verbatim
as an injectors' imports. This is detrimental for tree-shaking, as a
module's exports could reference declarations that would then prevent such
declarations from being eligible for tree-shaking.
Since an injector actually only needs NgModule references as its imports,
we may safely filter out any declarations from the list of module exports.
This makes them eligible for tree-shaking once again.
PR Close#29598
Prior to this change, all module metadata would be included in the
`defineNgModule` call that is set as the `ngModuleDef` field of module
types. Part of the metadata is scope information like declarations,
imports and exports that is used for computing the transitive module
scope in JIT environments, preventing those references from being
tree-shaken for production builds.
This change moves the metadata for scope computations to a pure function
call that patches the scope references onto the module type. Because the
function is marked pure, it may be tree-shaken out during production builds
such that references to declarations and exports are dropped, which in turn
allows for tree-shaken any declaration that is not otherwise referenced.
Fixes#28077, FW-1035
PR Close#29598
In some cases ivy expects projectable nodes to be passed in a different order
to ViewEngine. Specifically, ivy expects the catch-all ("*") to be at index
0, whereas ViewEngine expects it to be at its position at which it was parsed
in the template.
This commit adds one test that breaks under ivy and others that just describe
more accurately what happens in corner cases.
PR Close#27791
Previously, only directives and services with generic type parameters
would emit `any` as generic type when emitting Ivy metadata into .d.ts
files. Pipes can also have generic type parameters but did not emit
`any` for all type parameters, resulting in the omission of those
parameters which causes compilation errors.
This commit adds support for pipes with generic type arguments and emits
`any` as generic type in the Ivy metadata.
Fixes#29400
PR Close#29403
This PR alligns markup language lexer with the previous behaviour in version 7.x:
https://stackblitz.com/edit/angular-iancj2
While this behaviour is not perfect (we should be giving users an error message
here about invalid HTML instead of assuming text node) this is probably best we
can do without more substential re-write of lexing / parsing infrastructure.
This PR just fixes#29231 and restores VE behaviour - a more elaborate fix will
be done in a separate PR as it requries non-trivial rewrites.
PR Close#29328
This patch is the first of a few patches which separates the
styling logic between template bindings (e.g. <div [style])
from host bindings (e.g. @HostBinding('style')). This patch
in particular introduces a series of host-specific styling
instructions and changes the existing set of template styling
instructions not to accept directives. The underyling code (which
communicates with the styling algorithm) still works as it did
before.
This PR also separates the styling instruction code into a separate
file and moves over all other instructions into an dedicated
instructions directory.
PR Close#29292
This PR alligns markup language lexer with the previous behaviour in version 7.x:
https://stackblitz.com/edit/angular-iancj2
While this behaviour is not perfect (we should be giving users an error message
here about invalid HTML instead of assuming text node) this is probably best we
can do without more substential re-write of lexing / parsing infrastructure.
This PR just fixes#29231 and restores VE behaviour - a more elaborate fix will
be done in a separate PR as it requries non-trivial rewrites.
PR Close#29328
BREAKING CHANGE:
Certain elements (like `<tr>` or `<col>`) require parent elements to be of a certain type by the HTML specification
(ex. <tr> can only be inside <tbody> / <thead>). Before this change Angular template parser was auto-correcting
"invalid" HTML using the following rules:
- `<tr>` would be wrapped in `<tbody>` if not inside `<tbody>`, `<tfoot>` or `<thead>`;
- `<col>` would be wrapped in `<colgroup>` if not inside `<colgroup>`.
This meachanism of automatic wrapping / auto-correcting was problematic for several reasons:
- it is non-obvious and arbitrary (ex. there are more HTML elements that has rules for parent type);
- it is incorrect for cases where `<tr>` / `<col>` are at the root of a component's content, ex.:
```html
<projecting-tr-inside-tbody>
<tr>...</tr>
</projecting-tr-inside-tbody>
```
In the above example the `<projecting-tr-inside-tbody>` component culd be "surprised" to see additional
`<tbody>` elements inserted by Angular HTML parser.
PR Close#29219
Previously, ngtsc would resolve forward references while evaluating the
bootstrap, declaration, imports, and exports fields of NgModule types.
However, when generating the resulting ngModuleDef, the forward nature of
these references was not taken into consideration, and so the generated JS
code would incorrectly reference types not yet declared.
This commit fixes this issue by introducing function closures in the
NgModuleDef type, similarly to how NgComponentDef uses them for forward
declarations of its directives and pipes arrays. ngtsc will then generate
closures when required, and the runtime will unwrap them if present.
PR Close#29198
Currently with ViewEngine, if someone runs the platform's
`bootstrapModule` method in order to boostrap a module in
JIT mode, external component resources are properly resolved
*automatically*.
Currently with Ivy, the developer would need to manually call
`resolveComponentResources` in order to asynchronously fetch
the determined external component resources. In order to make
this backwards compatible with ViewEngine, and also since
platforms can already specify a `ResourceLoader` compiler
provider, we need to automatically resolve all external
component resources on module bootstrap.
--
Since the `ResourceLoader` is part of the `@angular/compiler`,
because ViewEngine performed the factory creation in the compiler,
we can't access the `ResourceLoader` token from within core.
In order to workaround this without introducing a breaking change,
we just proxy the `ResourceLoader` token to `core` through the
compiler facade. In the future, we should be able to move the
`ResourceLoader` to core when ViewEngine code no longer exists in
the `@angular/compiler`.
PR Close#29083
At the moment, certain tests relies on resolving the module with an index.d.ts, this root cause might be some implementations are missing from the mocks.
Similar to: 58b4045359
PR Close#28884
Prior to this commit, i18n instructions (i18n, i18nStart) were generated before listener instructions. As a result, event listeners were attached to the wrong element (text node, not the parent element). This change updates the order of instructions and puts i18n ones after listeners, to make sure listeners are attached to the right elements.
PR Close#29173
For the template type checking to work correctly, it needs to know
what attributes are bound to expressions or directives, which may
require expressions in the template to be evaluated in a different
scope.
In inline templates, there are attributes that are now marked as
"Template" attributes. We need to ensure that the template
type checking code looks at these "bound" attributes as well as the
"input" attributes.
PR Close#29041
The content projection mechanism is static, in that it only looks at the static
template nodes before directives are matched and change detection is run.
When you have a selector-based content projection the selection is based
on nodes that are available in the template.
For example:
```
<ng-content selector="[some-attr]"></ng-content>
```
would match
```
<div some-attr="..."></div>
```
If you have an inline-template in your projected nodes. For example:
```
<div *ngIf="..." some-attr="..."></div>
```
This gets pre-parsed and converted to a canonical form.
For example:
```
<ng-template [ngIf]="...">
<div some-attr=".."></div>
</ng-template>
```
Note that only structural attributes (e.g. `*ngIf`) stay with the `<ng-template>`
node. The other attributes move to the contained element inside the template.
When this happens in ivy, the ng-template content is removed
from the component template function and is compiled into its own
template function. But this means that the information about the
attributes that were on the content are lost and the projection
selection mechanism is unable to match the original
`<div *ngIf="..." some-attr>`.
This commit adds support for this in ivy. Attributes are separated into three
groups (Bindings, Templates and "other"). For inline-templates the Bindings
and "other" types are hoisted back from the contained node to the `template()`
instruction, so that they can be used in content projection matching.
PR Close#29041
This commit adds a new `AttributeMarker` type that will be used, in a
future commit, to mark attributes as coming from an inline-template
expansion, rather than the element that is being contained in the template.
PR Close#29041
Prior to this change, the RegExp that was used to check for dashes in field names used "g" (global) flag that retains lastIndex, which might result in skipping some fields that should be wrapped in quotes (since lastIndex advanced beyond the next "-" location). This commit removes this flag and updates the test to make sure there are no regressions.
PR Close#29126
ngtsc occasionally converts a type reference (such as the type of a
parameter in a constructor) to a value reference (argument to a
directiveInject call). TypeScript has a bad habit of sometimes removing
the import statement associated with this type reference, because it's a
type only import when it initially looks at the file.
A solution to this is to always add an import to refer to a type position
value that's imported, and not rely on the existing import.
PR Close#29111
Prior to this change, keys in "inputs" and "outputs" objects generated by compiler were not checked against unsafe characters. As a result, in some cases the generated code was throwing JS error. Now we check whether a given key contains any unsafe chars and wrap it in quotes if needed.
PR Close#28919
ngtsc has cyclic import detection, to determine when adding an import to a
directive or pipe would create a cycle. However, this detection must also
account for already inserted imports, as it's possible for both directions
of a circular import to be inserted by Ivy (as opposed to at least one of
those edges existing in the user's program).
This commit fixes the circular import detection for components to take into
consideration already added edges. This is difficult for one critical
reason: only edges to files which will *actually* be imported should be
considered. However, that depends on which directives & pipes are used in
a given template, which is currently only known by running the
TemplateDefinitionBuilder during the 'compile' phase. This is too late; the
decision whether to use remote scoping (which consults the import graph) is
made during the 'resolve' phase, before any compilation has taken place.
Thus, the only way to correctly consider synthetic edges is for the compiler
to know exactly which directives & pipes are used in a template during
'resolve'. There are two ways to achieve this:
1) refactor `TemplateDefinitionBuilder` to do its work in two phases, with
directive matching occurring as a separate step which can be performed
earlier.
2) use the `R3TargetBinder` in the 'resolve' phase to independently bind the
template and get information about used directives.
Option 1 is ideal, but option 2 is currently used for practical reasons. The
cost of binding the template can be shared with template-typechecking.
PR Close#29040
In the @Component decorator, the 'host' field is an object which represents
host bindings. The type of this field is complex, but is generally of the
form {[key: string]: string}. Several different kinds of bindings can be
specified, depending on the structure of the key.
For example:
```
@Component({
host: {'[prop]': 'someExpr'}
})
```
will bind an expression 'someExpr' to the property 'prop'. This is known to
be a property binding because of the square brackets in the binding key.
If the binding key is a plain string (no brackets or parentheses), then it
is known as an attribute binding. In this case, the right-hand side is not
interpreted as an expression, but is instead a constant string.
There is no actual requirement that at build time, these constant strings
are known to the compiler, but this was previously enforced as a side effect
of requiring the binding expressions for property and event bindings to be
statically known (as they need to be parsed). This commit breaks that
relationship and allows the attribute bindings to be dynamic. In the case
that they are dynamic, the references to the dynamic values are reflected
into the Ivy instructions for attribute bindings.
PR Close#29033
This change helps highlight certain misoptimizations with Closure
compiler. It is also stylistically preferable to consistently use index
access on index sig types.
Roughly, when one sees '.foo' they know it is always checked for typos
in the prop name by the type system (unless 'any'), while "['foo']" is
always not.
Once all angular repos are conforming this will become a tsetse.info
check, enforced by bazel.
PR Close#28937