HTML is very lenient when it comes to closing elements, so Angular's parser has
rules that specify which elements are implicitly closed when closing a tag.
The parser keeps track of the nesting of tag names using a stack and parsing
a closing tag will pop as many elements off the stack as possible, provided
that the elements can be implicitly closed.
For example, consider the following templates:
- `<div><br></div>`, the `<br>` is implicitly closed when parsing `</div>`,
because `<br>` is a void element.
- `<div><p></div>`, the `<p>` is implicitly closed when parsing `</div>`,
as `<p>` is allowed to be closed by the closing of its parent element.
- `<ul><li>A <li>B</ul>`, the first `<li>` is implicitly closed when parsing
the second `<li>`, whereas the second `<li>` would be implicitly closed when
parsing the `</ul>`.
In all the cases above the parsed structure would be correct, however the source
span of the closing `</div>` would incorrectly be assigned to the element that
is implicitly closed. The problem was that closing an element would associate
the source span with the element at the top of the stack, however this may not
be the element that is actually being closed if some elements would be
implicitly closed.
This commit fixes the issue by assigning the end source span with the element
on the stack that is actually being closed. Any implicitly closed elements that
are popped off the stack will not be assigned an end source span, as the
implicit closing implies that no ending element is present.
Note that there is a difference between self-closed elements such as `<input/>`
and implicitly closed elements such as `<input>`. The former does have an end
source span (identical to its start source span) whereas the latter does not.
Fixes#36118
Resolves FW-2004
PR Close#38126
Builds on top of #34655 to support more cases that could be using a pipe inside host bindings (e.g. ternary expressions or function calls).
Fixes#37610.
PR Close#37883
ASTs for property read and method calls contain information about
the entire span of the expression, including its receiver. Use cases
like a language service and compile error messages may be more
interested in the span of the direct identifier for which the
expression is constructed (i.e. an accessed property). To support this,
this commit adds a `nameSpan` property on
- `PropertyRead`s
- `SafePropertyRead`s
- `PropertyWrite`s
- `MethodCall`s
- `SafeMethodCall`s
The `nameSpan` property already existed for `BindingPipe`s.
This commit also updates usages of these expressions' `sourceSpan`s in
Ngtsc and the langauge service to use `nameSpan`s where appropriate.
PR Close#36826
In past versions of the View Engine compiler, we added a warning that is
printed whenever the compiler comes across an Angular declaration with a
constructor that does not match suitable DI tokens. The warning mentioned
that in `v6.x` it will turn into an actual error.
This actually happened as expected for most cases. e.g. the constructor
of `@NgModule`, `@Component`'s, `@Pipe`'s etc will be checked and an error
will be reported if constructor is not DI compatible.
The warning has never been removed though as it was still relevant for
unprovided injectables, or injectables serialized into summaries of the
Angular compiler.
As of version 10, classes that use Angular features need an Angular decorator.
This includes base classes of services that use the lifecycles Angular feature.
Due to this being a common pattern now, we can remove the warning in
View Engine. The warning is not correct, and also quite confusing as it
mentions the planned removal in `v6.x`.
Resolves FW-2147.
PR Close#36985
The html parser already normalizes line endings (converting `\r\n` to `\n`)
for most text in templates but it was missing the expressions of ICU expansions.
In ViewEngine backticked literal strings, used to define inline templates,
were already normalized by the TypeScript parser.
In Ivy we are parsing the raw text of the source file directly so the line
endings need to be manually normalized.
This change ensures that inline templates have the line endings of ICU
expression normalized correctly, which matches the ViewEngine.
In ViewEngine external templates, defined in HTML files, the behavior was
different, since TypeScript was not normalizing the line endings.
Specifically, ICU expansion "expressions" are not being normalized.
This is a problem because it means that i18n message ids can be different on
different machines that are setup with different line ending handling,
or if the developer moves a template from inline to external or vice versa.
The goal is always to normalize line endings, whether inline or external.
But this would be a breaking change since it would change i18n message ids
that have been previously computed. Therefore this commit aligns the ivy
template parsing to have the same "buggy" behavior for external templates.
There is now a compiler option `i18nNormalizeLineEndingsInICUs`, which
if set to `true` will ensure the correct non-buggy behavior. For the time
being this option defaults to `false` to ensure backward compatibility while
allowing opt-in to the desired behavior. This option's default will be
flipped in a future breaking change release.
Further, when this option is set to `false`, any ICU expression tokens,
which have not been normalized, are added to the `ParseResult` from the
`HtmlParser.parse()` method. In the future, this collection of tokens could
be used to diagnose and encourage developers to migrate their i18n message
ids. See FW-2106.
Closes#36725
PR Close#36741
The `I18nComponent` was using `!` for some of its properties
because it had not initialized them. This is now resolved by explictly
marking them as optional.
PR Close#36741
Prior to this change, there was a problem while matching template attributes, which mistakenly took i18n attributes (that might be present in attrs array after template ones) into account. This commit updates the logic to avoid template attribute matching logic from entering the i18n section and as a result this also allows generating proper i18n attributes sections instead of keeping these attribute in plain form (with their values) in attribute arrays.
PR Close#36422
From G3 bug ID: 116443331
The View Engine compiler crashes when it tries to compile a test in JIT mode
that includes the d3-scale-chromatic library [1]. The d3 package initializes
some arrays using the following pattern:
```js
export var scheme = new Array(3).concat(
"d8b365f5f5f55ab4ac",
// ... more entries
).map(colors);
```
The stack trace from the crash is as follows:
```
TypeError: Cannot read property 'visitExpression' of undefined
at ../../../third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts:505:39
at JitEmitterVisitor.AbstractEmitterVisitor.visitAllObjects third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=526
at JitEmitterVisitor.AbstractEmitterVisitor.visitAllExpressions third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=505
at JitEmitterVisitor.AbstractEmitterVisitor.visitLiteralArrayExpr third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=484
at LiteralArrayExpr.visitExpression third_party/javascript/angular2/rc/packages/compiler/src/output/output_ast.ts?l=791
at ../../../third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts:492:19
at JitEmitterVisitor.AbstractEmitterVisitor.visitAllObjects third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=526
at JitEmitterVisitor.AbstractEmitterVisitor.visitLiteralMapExpr third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=490
at LiteralMapExpr.visitExpression third_party/javascript/angular2/rc/packages/compiler/src/output/output_ast.ts?l=819
at ../../../third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts:505:39
at JitEmitterVisitor.AbstractEmitterVisitor.visitAllObjects third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=526
at JitEmitterVisitor.AbstractEmitterVisitor.visitAllExpressions third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=505
at JitEmitterVisitor.AbstractEmitterVisitor.visitInvokeFunctionExpr third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_emitter.ts?l=318
at JitEmitterVisitor.AbstractJsEmitterVisitor.visitInvokeFunctionExpr third_party/javascript/angular2/rc/packages/compiler/src/output/abstract_js_emitter.ts?l=112
at InvokeFunctionExpr.visitExpression third_party/javascript/angular2/rc/packages/compiler/src/output/output_ast.ts?l=440
```
This is because the corresponding output AST for the array is of the form
```ts
[
undefined,
undefined,
undefined,
o.LiteralExpr,
// ...
]
```
The output AST is clearly malformed and breaks the type representation of
`LiteralArrayExpr` in which every entry is expected to be of type `Expression`.
This commit fixes the bug by using a plain `for` loop to iterate over the
entire length of the holey array and convert undefined elements to
`LiteralExpr`.
[1]: https://github.com/d3/d3-scale-chromatic/blob/master/src/diverging/BrBG.js
PR Close#36343
Previously, an expansion case could only start with an alpha numeric character.
This commit fixes this by allowing an expansion case to start with any character
except `}`.
The [ICU spec](http://userguide.icu-project.org/formatparse/messages) is pretty vague:
> Use a "select" argument to select sub-messages via a fixed set of keywords.
It does not specify what can be a "keyword" but from looking at the surrounding syntax it
appears that it can indeed be any string that does not contain a `}` character.
Closes#31586
PR Close#36123
This commit propagates the correct value span in an ExpressionBinding of
a microsyntax expression to ParsedProperty, which in turn porpagates the
span to the template ASTs (both VE and Ivy).
PR Close#36133
This commit propagates the `sourceSpan` and `valueSpan` of a `VariableBinding`
in a microsyntax expression to `ParsedVariable`, and subsequently to
View Engine Variable AST and Ivy Variable AST.
Note that this commit does not propagate the `keySpan`, because it involves
significant changes to the template AST.
PR Close#36047
To create the symbols of a module, the static symbol resolver first gets
all the symbols loaded in the module by an export statement. For `export
* from './module'`-like statements, all symbols from `./module` must be
loaded. In cases where the exporting module is actually the same module
that the export statement is in, this causes an unbounded recursive
resolution of the same module.
Exports of the same module are not needed, as their symbols will be
resolved when the symbols in the module metadata's `metadata` key is
explored.
This commit resolves the unbounded recursion by loading exporting
modules only if they differ from the module currently being resolved.
Closes https://github.com/angular/vscode-ng-language-service/issues/593
PR Close#35262
This commit adds fine-grained text spans to TemplateBinding for microsyntax expressions.
1. Source span
By convention, source span refers to the entire span of the binding,
including its key and value.
2. Key span
Span of the binding key, without any whitespace or keywords like `let`
The value span is captured by the value expression AST.
This is part of a series of PRs to fix source span mapping in microsyntax expression.
For more info, see the doc https://docs.google.com/document/d/1mEVF2pSSMSnOloqOPQTYNiAJO0XQxA1H0BZyESASOrE/edit?usp=sharing
PR Close#35897
This commit removes the `NullAstVisitor` and `visitAstChildren` exported
from `packages/compiler/src/expression_parser/ast.ts` because they
contain duplicate and buggy implementation, and their use cases could be
sufficiently covered by `RecursiveAstVisitor` if the latter implements the
`visit` method. This use case is only needed in the language service.
With this change, any visitor that extends `RecursiveAstVisitor` could
just define their own `visit` function and the parent class will behave
correctly.
A bit of historical context:
In language service, we need a way to tranverse the expression AST in a
selective manner based on where the user's cursor is. This means we need a
"filtering" function to decide which node to visit and which node to not
visit. Instead of refactoring `RecursiveAstVisitor` to support this,
`visitAstChildren` was created. `visitAstChildren` duplicates the
implementation of `RecursiveAstVisitor`, but introduced some bugs along
the way. For example, in `visitKeyedWrite`, it visits
```
obj -> key -> obj
```
instead of
```
obj -> key -> value
```
Moreover, because of the following line
```
visitor.visit && visitor.visit(ast, context) || ast.visit(visitor, context);
```
`visitAstChildren` visits every node *twice*.
PR Close#35619
The only test case for `ngFor` exercises an incorrect usage which causes
two bound attributes to be generated . This commit adds a canonical and
correct usage to show the difference between the two.
PR Close#35671
Currently, would-be binding attributes that are missing binding names
are not parsed as bindings, and fall through as regular attributes. In
some cases, this can lead to a runtime error; trying to assign `#` as a
DOM attribute in an element like in `<div #></div>` fails because `#` is
not a valid attribute name.
Attributes composed of binding prefixes but not defining a binding
should be considered invalid, as this almost certainly indicates an
unintentional elision of a binding by the developer. This commit
introduces error reporting for attributes with a binding name prefix but
no actual binding name.
Closes https://github.com/angular/vscode-ng-language-service/issues/293.
PR Close#34595
NOTE: This change must be reverted with previous deletes so that it code remains in build-able state.
This change deletes old styling code and replaces it with a simplified styling algorithm.
The mental model for the new algorithm is:
- Create a linked list of styling bindings in the order of priority. All styling bindings ere executed in compiled order and than a linked list of bindings is created in priority order.
- Flush the style bindings at the end of `advance()` instruction. This implies that there are two flush events. One at the end of template `advance` instruction in the template. Second one at the end of `hostBindings` `advance` instruction when processing host bindings (if any).
- Each binding instructions effectively updates the string to represent the string at that location. Because most of the bindings are additive, this is a cheap strategy in most cases. In rare cases the strategy requires removing tokens from the styling up to this point. (We expect that to be rare case)S Because, the bindings are presorted in the order of priority, it is safe to resume the processing of the concatenated string from the last change binding.
PR Close#34616
The major one that affects the angular repo is the removal of the bootstrap attribute in nodejs_binary, nodejs_test and jasmine_node_test in favor of using templated_args --node_options=--require=/path/to/script. The side-effect of this is that the bootstrap script does not get the require.resolve patches with explicitly loading the targets _loader.js file.
PR Close#34736
The major one that affects the angular repo is the removal of the bootstrap attribute in nodejs_binary, nodejs_test and jasmine_node_test in favor of using templated_args --node_options=--require=/path/to/script. The side-effect of this is that the bootstrap script does not get the require.resolve patches with explicitly loading the targets _loader.js file.
PR Close#34589
In the past, only the starting index of an expression Token has been
recorded, so a parser could demarkate the span of a token only by the
start locations of two tokens. This may lead to trailing whitespace
being included in the token span:
```html
{{ token1 + token2 }}
^^^^^^^^^ recorded span of `token1`
```
It's also not enough for a parser to determine the end of a token by
adding the length of the token value to the token's start location,
because lexed expression values may not exactly reflect the source code.
For example, `"d\\"e"` is lexed as a string token whose value is `d"e`.
Instead, this commit adds a `end` field to expression tokens. `end`
is one past the last index of the token source code. This will enable a
parser to determine the span of a token just by looking at that token.
This is a breaking change because the contructor interface of `Token`
has changed.
Part of #33477.
PR Close#33549
Previously, bound events were incorrectly bound to directives with
inputs matching the bound event attribute. This fixes that so bound
events can only be bound to directives with matching outputs.
Adds tests for all kinds of directive matching on bound attributes.
PR Close#31938
Expressions in an inline template binding are improperly recorded as
spaning an offset calculated from the start of the template binding
attribute key, whereas they should be calculated from the start of the
attribute value, which contains the actual binding AST.
PR Close#31813
Previously the JIT evaluated code for ivy localized strings included
backtick tagged template strings, which are not compatible with ES5
in legacy browsers such as IE 11.
Now the generated code is ES5 compatible.
Fixes#34246
PR Close#34265
It is possible for HTML formatters to add whitespace
around the content of `i18n` attribute values. This can
make the meaning and custom ids brittle to simple
whitespace formatting.
This commit ensures that the metadata string extracted
from HTML `i18n` attributes is trimmed before being parsed
into meaning, description and custom id.
PR Close#34154
Now that `@angular/localize` can interpret multiple legacy message ids in the
metablock of a `$localize` tagged template string, this commit adds those
ids to each i18n message extracted from component templates, but only if
the `enableI18nLegacyMessageIdFormat` is not `false`.
PR Close#34135
Since i18n messages are mapped to `$localize` tagged template strings,
the "raw" version must be properly escaped. Otherwise TS will throw an
error such as:
```
Error: Debug Failure. False expression: Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'.
```
This commit ensures that we properly escape these raw strings before creating
TS AST nodes from them.
PR Close#33820
The `:` char is used as a metadata marker in `$localize` messages.
If this char appears in the metadata it must be escaped, as `\:`.
Previously, although the `:` char was being escaped, the TS AST
being generated was not correct and so it was being output double
escaped, which meant that it appeared in the rendered message.
As of TS 3.6.2 the "raw" string can be specified when creating tagged
template AST nodes, so it is possible to correct this.
PR Close#33820
This is a breaking change in nodejs rules 0.40.0 as part of the API review & cleanup for the 1.0 release. Their APIs are identical as ts_web_test was just karma_web_test without the config_file attribute.
PR Close#33802
Prior to this change, namespaced elements such as SVG elements would not
participate correctly in directive matching as their namespace was not
ignored, which was the case with the View Engine compiler. This led to
incorrect behavior at runtime and template type checking.
This commit resolved the issue by ignoring the namespace of elements and
attributes like they were in View Engine.
Fixes#32061
PR Close#33555
Previously the compiler would ignore everything in the attribute
name after the first dot. For example
<div [attr.someAttr.attrSuffix]="var"></div>
is turned into <div someAttr="varValue"></div>.
This commit ensures that whole attribute name is captured.
Now <div [attr.someAttr.attrSuffix]="var"></div>
is turned into <div someAttr.attrSuffix="varValue"></div>
PR Close#32256
The parser was accidentally reading the `target` tag
below the `alt-trans` target and overriding the correct
`target` tag.
(This already worked in `$localize` but a test has been
added to confirm.)
Fixes#33161
PR Close#33450
Removes `ngBaseDef` from the compiler and any runtime code that was still referring to it. In the cases where we'd previously generate a base def we now generate a definition for an abstract directive.
PR Close#33264