When parsing interpolations, the input string is _decoded_ from what was
in the orginal template. This means that we cannot soley rely on the input
string to compute source spans because it does not necessarily reflect
the exact content of the original template. Specifically, when there is
an HTML entity (i.e. ` `), this will show up in its decoded form
when processing the interpolation (' '). We need to compute offsets
using the original _encoded_ string.
Note that this problem only surfaces in the splitting of interpolations.
The spans to this point have already been tracked accurately. For
example, given the template ` <div></div>`, the source span for the
`div` is already correctly determined to be 6. Only when we encounter
interpolations with many parts do we run into situations where we need
to compute new spans for the individual parts of the interpolation.
PR Close#44811
Proactively replaces our usages of the deprecated `ts.create*` methods in favor of using `ts.factory.create*` so that we're not surprised when the TS removes them in the future. Also accounts for some cases where the signature had changed.
PR Close#45134
Before this, the compiler resolves the value in the DTS as dynamic.
If the `trigger` is imported from `@angular/animations`, this PR will
use FFR to simulate the actual implementation in JS and extracts the
animation name.
PR Close#45107
This commit implements the first phase of standalone components in the Angular
compiler. This mainly includes the scoping rules for standalone components
(`@Component({imports})`).
Significant functionality from the design is _not_ implemented by this PR,
including:
* imports of standalone components into NgModules.
* the provider aspect of standalone components
Future commits will address these issues, as we proceed with the design of
this feature.
PR Close#44812
In preparation for standalone components, this commit moves the logic which
determines the potential set of components/directives/pipes in a template into
a separate function. This is a simple but crucial refactoring that breaks the
assumption that all template scopes come from NgModules.
PR Close#44812
Previously each `DecoratorHandler` in the compiler was stored in a single file
in the 'annotations' package. The `ComponentDecoratorHandler` in particular was
several thousand lines long.
Prior to implementing the new standalone functionality for components, this
commit refactors 'annotations' to split these large files into their own build
targets with multiple separate files. This should make the implementation of
standalone significantly cleaner.
PR Close#44812
The logical filesystem would store a cached result based on the canonical path,
where the cached value contains the physical path that was originally provided.
This meant that other physical paths with an identical canonical path would use
a cached result derived from another physical path.
This inconsistency is not known to result in actual issues but is primarily
being made as a performance improvement, as using the provided physical paths
as cache key avoids the need to canonicalize the path if its result is already
cached.
PR Close#44798
The generated imports should normally use module specifiers that are valid for
use in production code, where arbitrary relative imports into e.g. node_modules
are not allowed. For template type-checking code it is however acceptable to
use relative imports, as such files are never emitted to JS code. It is
desirable to allow a filesystem relative import as fallback if an import would
otherwise fail to be generated, as doing so allows fewer situations from
needing an inline type constructor.
PR Close#44798
This commit removes the leftover `Identifiers` class that was used in the
ViewEngine compiler. The remaining usages of the `inlineInterpolate` and
`interpolate` instructions were refactored to make use of an
`InterpolationExpression` output expression to capture the argument list of an
interpolation expression. An attempt was made to refactor this further by
converting to the desired interpolation instruction immediately, but some
downstream consumers are designed in a way where the argument list itself is
needed, e.g. as other arguments need to be prepended/appended.
PR Close#44676
So-called "Quote expressions" were added in b6ec2387b3
to support foreign syntax to be used in Angular templates, requiring a custom
template transform to convert them somehow during compilation. Support for template
transforms was originally implemented in a43ed79ee7 but
has since been dropped. Since the compiler is not public API the quote expressions
should not have any usages anymore. Removing support for them can improve error
reporting for expressions that contain a `:`, e.g. binding to a URL without quotes:
```html
<a [href]="http://google.com">Click me</a>
```
Here, `http` would be parsed as foreign "http" quote expression with `//google.com` as
value, later reporting the error "Quotes are not supported for evaluation!" because
there was no template transform to convert that code.
Closes#40398
PR Close#44915
TypeScript configures `strictNullChecks` to be disabled by default, so the nullish
coalescing check should follow the same default. The rule actively depends on
`strictNullChecks`, as TypeScript doesn't include `null`/`undefined` in its types
otherwise so the check wouldn't have a way to differentiate between them.
This commit also takes the `strict` flag into account when `strictNullChecks` itself
is not configured.
PR Close#44862
The initial commit e9124b42d5 stored the errors rather than
throwing but did not store them in a place that was accessible to consumers. Instead,
the errors should be added to the IndexedComponent so they can be surfaced where the
index results are consumed
PR Close#44884
When the indexer encounters a location where the source span doesn't
match up with the expected identifier, the current visitor code throws
an error. Instead, this change creates an error and moves on to the next
template item. This allows the indexer to continue analysis even when
there are errors in the source mapping. In addition, it still allows callers
to surface those errors in their own way while still providing as much indexed
information as possible about a node.
PR Close#44825
An `ng-template` with an inline template (i.e. has a structural
directive) would previously not get an `undefined` `tagName` because the
logic assumed the element would be `t.Element` or `t.Content` and read
the tag name from the `name` property. For a `t.Template`, this exists
instead on the `t.tagName`. The final result would be an `tagName` of `undefined`
for the parent `t.Template`, causing failures in the indexer downstream.
This `undefined` value is actually expected in the renderer code, even
though the type does not specify this possibility. This change updates
the type of `tagName` to be `string|null` and explicitly handles the
case where there is a structural directive on an `ng-template`. You can
see how the two are differentiated in the compliance code that was
modified in this commit.
PR Close#44788
The previous fix for correcting spans with comments in
59eef29a6c
had the unfortunate side effect of _breaking_ the spans with comments
when there was leading whitespace. This happened because the previous
fix was testing one without a comment, identifying that the offset shouldn't
have anything added to it, and then removing that offset adjustment
(`offsets[i] + (expressionText.length - sourceToLex.length)`).
Upon further investigation, this offset adjustment _was actually
necessary_ for when the input had comments, but this was only because
the `stripComments` function used `trim` to remove whitespace for these
cases. This is the real problem -- not only does it create a ton of confusion
but also it means that the behavior of the lexer and resulting spans is
different between inputs with comments and inputs without comments.
After reviewing how the `inputLength` of `_ParseAST` was used, it
appears that the correct behavior would be to _not_ trim the input. The
`inputLength` is used to advance the current index beyond points which
have been processed. This _should_ include any whitespace. Additionally,
`inputLength` doesn't appear to be needed at all. When there was no
comment in the input, it was always equal to the `input.length` anyways.
When there _is_ a comment, it should include that comment anyways to
advance the index beyond the comment.
PR Close#44785
The original fix for svg elements in
92b23f4851
did not account for svg elements when they also had a structural
directive on them, making the node a template. This resulted in the
logic added in fix above not being applied.
PR Close#44785
Previously, if a bad extended diagnostic category was given, it would fail with the expected error as well as an unexpected assertion error:
```
$ ng build -c development
✔ Browser application bundle generation complete.
./src/main.ts - Error: Module build failed (from ./node_modules/@ngtools/webpack/src/ivy/index.js):
Error: Unexpected call to 'assertNever()' with value:
test
at /home/douglasparker/Source/ng-new/node_modules/@ngtools/webpack/src/ivy/loader.js:77:18
at processTicksAndRejections (internal/process/task_queues.js:95:5)
./src/polyfills.ts - Error: Module build failed (from ./node_modules/@ngtools/webpack/src/ivy/index.js):
Error: Unexpected call to 'assertNever()' with value:
test
at /home/douglasparker/Source/ng-new/node_modules/@ngtools/webpack/src/ivy/loader.js:77:18
at processTicksAndRejections (internal/process/task_queues.js:95:5)
Error: error NG4004: Angular compiler option "extendedDiagnostics.checks['invalidBananaInBox']" has an unknown diagnostic category: "test".
Allowed diagnostic categories are:
warning
error
suppress
```
The assertion comes from `ExtendedTemplateCheckerImpl`, which expects a well-formed configuration, yet the compiler would construct it even when errors were found. This commit skips constructing and running extended diagnostics if the configuration had errors, which should avoid triggering these assertion errors.
I'm unfortunately not able to actually test this change. The test passes even before the fix because the `ngc` binary and end-to-end tests [don't request diagnostics unless the configuration is considered valid](ed21f5c753/packages/compiler-cli/src/perform_compile.ts (L292-L293)). See [Slack](https://angular-team.slack.com/archives/C4WHZQMRA/p1642641305003800) for more details.
PR Close#44778
Refs #42966.
There were two remaining places where `_extendedTemplateDiagnostics` needed to be set which should have been removed in #44712 but got missed. This updates them to only require `strictTemplates` and not `_extendedTemplateDiagnostics` so the feature is properly enabled in production.
PR Close#44777
Refs #42966.
Extended diagnostics provide additional analysis about Angular templates by emitting warnings for specific patterns known to be error prone or cause developer confusion. Currently, there are two such diagnostics which are enabled by default:
* `invalidBananaInBox` emits a warning if a user writes a two-way binding backwards like `([foo])="bar"`, when they actually wanted `[(foo)]="bar"`.
* `nullishCoalescingNotNullable` emits a warning if a binding attempts to perform nullish coalescing (`??`) on a type which does not include `null` or `undefined`, such as `{{ foo ?? 'bar' }}` where `foo` is defined as `string` instead of `string | null`.
These diagnostics are enabled as warnings by default, but this can be configured in the `tsconfig.json` like so:
```jsonc
{
"angularCompilerOptions": {
"extendedDiagnostics": {
// The categories to use for specific diagnostics.
"checks": {
// Maps check name to its category.
"invalidBananaInBox": "suppress"
},
// The category to use for any diagnostics not listed in `checks` above.
"defaultCategory": "error"
}
}
}
```
Allowed categories for a diagnostic are `warning` (default), `error`, or `suppress`. `warning` emits the diagnostic but allows the compilation to succeed, `error` *will* fail the compilation, while `suppress` will ignore the diagnostic altogether.
The initial release has two diagnostics, and we are hoping to expand this longer term to add more diagnostics and provide additional insight into Angular templates to detect and surface developer mistakes *before* hours of debugging are wasted.
PR Close#44712
This commit reduces the analysis work that needs to happen during an
incremental rebuild by properly recording files for which no traits were found
in the set of files that have no traits, such that the same file doesn't have
to be reanalyzed during subsequent rebuilds. It also excludes shim files from
analysis.
PR Close#44731
In the `Element` node of a parsed `<svg>` element, the `name` is recorded
as `:svg:svg`. When the Angular Indexer ran over this element, it would
attempt to find this name in the template text and fail, as the namespace
portion of the name was added automatically at parse time and is of course
missing from the original template.
This commit changes the indexer to detect these namespaced elements and only
search for the tag name.
PR Close#44678
When parsing a binding with a comment at the end of the expression, the
parser previously had logic to offset the parsed spans by the length of the
comment. This logic seemed not to serve any useful purpose, and instead
resulted in the corruption of the spans. For example, in the expression
`{{foo // comment}}`, the parser would map the parsed `foo` `PropertyRead`
node at the location of the characters 'ent' from the comment suffix.
This commit removes that logic, correcting the parsed spans of such nodes in
the presence of comments. Removing this logic does not seem to have caused
any tests to fail.
PR Close#44678
Previously, the Angular Indexer made an assumption that in any binding to
a property of an `ImplicitReceiver`, the property name begins at the start
of the binding. This is true for normal reads from `ImplicitReceiver` as
the implicit receiver has no representation in the template.
However, `ThisReceiver` inherits from `ImplicitReceiver` and _does_ have a
template representation. Such a binding looks like `{{this.foo}}`. This
commit corrects the logic of the indexer to use the `nameSpan` of the
property binding instead of its `sourceSpan` to locate the identifier.
PR Close#44678
Refs #42966.
This validates the `tsconfig.json` options for extended template diagnostics. It verifies:
* `strictTemplates` must be enabled if `extendedDiagnostics` have any explicit configuration.
* `extendedDiagnostics.defaultCategory` must be a valid `DiagnosticCategoryLabel`.
* `extendedDiagnostics.checks` keys must all be real diagnostics.
* `extendedDiagnostics.checks` values must all be valid `DiagnosticCategoryLabel`s.
These include new error codes, each of which prints out the exact property that was the issue and what the available options are to fix them.
It does disallow the config:
```json
{
"angularCompilerOptions": {
"strictTemplates": false,
"extendedDiagnostics": {
"defaultCategory": "suppress"
}
}
}
```
Such a configuration is technically valid and could be executed, but will be rejected by this verification logic. There isn't much reason to ever do this, since users could just drop `extendedDiagnostics` altogether and get the intended effect. This is unlikely to be a significant issue for users, so it is considered invalid for now to keep the implementation simple.
PR Close#44391
Refs #42966.
The `defaultCategory` option is used for any extended template diagnostics which do not have any specific category specified for them. It defaults to `warning`, since that is the most common behavior expected for users. This provides an easy way for users to promote all diagnostics to errors or suppress all diagnostics.
PR Close#44391
Refs #42966.
This updates `TemplateContext` to include a new `makeTemplateDiagnostic()` function which automatically uses the correct diagnostic category for that check. This makes sure that each diagnostic is emitted with the correct category. It also implicitly passes some known values like `component` and `code` to make the extended template diagnostics a little simpler. Diagnostics which are suppressed are never instantiated at all, which acts as a slight performance optimization since any emitted diagnostics would be ignored anyways.
Unfortunately, diagnostics still have access to `ctx.templateTypeChecker.makeTemplateDiagnostic()` to manually create diagnostics with a different category. Both banana in box and nullish coalescing checks include tests to make sure they respect a manually configured category. This convention should hopefully give a reasonable certainty that new diagnostics will use the correct reporting function, even if that is not strictly enforced.
PR Close#44391
Refs #42966.
This includes a mapping of extended template diagnostics to their associated diagnostic category. It is generated from the list of diagnostic names, so the list should always be implicitly kept up to date. Usage looks like:
```json
{
"angularCompilerOptions": {
"extendedDiagnostics": {
"checks": {
"invalidBananaInBox": "error",
"nullishCoalescingNotNullable": "suppress"
}
}
}
}
```
PR Close#44391
Refs #42966.
This is a static array of all the 1P extended template diagnostic factories built into the Angular compiler directly. It provides an encapsulated list of all diagnostics rather than requiring users to manually list each one individually.
PR Close#44391
Refs #42966.
This moves extended template check factory invocations into the checker itself, where it can provide a more consistent API contract. Factories are called with compiler options and may return a `TemplateCheck` or `undefined` if the current options do not support that check. This allows `nullishCoalescingNotNullable` to disable itself when `strictNullChecks` is disabled without throwing errors. This gives extended template diagnostics a stronger abstraction model to define their behavior with.
PR Close#44391
Refs #42966.
The enum of extended template diagnostic names allows a global registry of first-party diagnostics with a developer-friendly string name which can be used for configuration. This name is used in the new `TemplateCheckFactory` to bind the name to a particular `ErrorCode` and make both available *before* constructing the actual template check, which is necessary to configure it appropriately.
PR Close#44391
In `language-service`, the `checker.getDirectiveMetadata` doesn't return the animations meta of the `Component`.
but it's useful for animation completion.
PR Close#44630
The changes in 2028c3933f caused method
calls to be emitted using additional parenthesis into the TCB, which in
turn prevented proper type narrowing when the method acts as a type
guard. This commit special-cases method calls from property reads to
avoid the additional parenthesis.
Fixes#44353
PR Close#44447
This was flagged during the code review of #44580. When generating a type check block, we were interpreting any call to `$any` as an `as any` cast, even if it's part of a `PropertyRead` (e.g. `foo.$any(1)`). This is handled correctly in other parts of the compiler, but it looks like it was missed in the type checker.
PR Close#44657
This page exists in the most recent angular.io version (v13 currently), so there's no need to link to an old version. The hash also refers to the title section of the page, which isn't necessary and is now dropped.
PR Close#44649
Dev mode output was switched from ES5 -> ES2015 recently and as a part of those changes, some target names that contained `_es5` postfixes were changes to `_es2015` instead. This commit fixes the issue with one of the recently merged BUILD files that contained the old (`_es5`) postfix.
PR Close#44651
When building a library, the `rootDir` option is configured to ensure
that all source files are present within the entry-point that is being
build. This imposes an extra constraint on the reference emit logic,
which does not allow emitting a reference into a source file outside of
this `rootDir`.
During the generation of type-check blocks we used to make a best-effort
estimation of whether a type reference can be emitted into the
type-check file. This check was relaxed in #42492 to support emitting
more syntax forms and type references, but this change did not consider
the `rootDir` constraint that is present in library builds. As such, the
compiler might conclude that a type reference is eligible for emit into
the type-check file, whereas in practice this would cause a failure.
This commit changes the best-effort estimation into a "preflight"
reference emit that is fully accurate as to whether emitting a type
reference is possible.
Fixes#43624
PR Close#44587
The `NgtscCompilerHost` is implemented using the `FileSystem`
abstraction of the compiler, which is implemented for tests using an
in-memory `MockFileSystem`. If the in-memory filesystem contains
symlinks, then using `NgtscCompilerHost` would not reflect their
resolved real path. Instead, the TypeScript compiler would use its
default implementation based on the real filesystem, which is unaware of
the in-memory `MockFileSystem` setup.
This change does not currently address any issues, but is being fixed
as it prevented a reproduction scenario from behaving correctly.
PR Close#44587
In certain scenarios, the compiler may have crashed with an
`Unable to write a reference` error which would be particularly hard
to diagnose. One of the primary reasons for this failure is when the
`rootDir` option is configured---typically the case for libraries---
and a source file is imported using a relative import from an external
entry-point. This would normally report TS6059 for the invalid relative
import, but the crash prevents this error from being surfaced.
This commit refactors the reference emit logic to result in an explicit
`Failure` state with a reason as to why the failure occurred. This state
is then used to report a `FatalDiagnosticException`, preventing a hard
crash.
Closes#44414
PR Close#44587
This commit moves some logic to make the location of runtime error codes consistent across packages. Now all error codes are located in `packages/core/src/errors.ts` file.
PR Close#44398
To make our test output i.e. devmode output more aligned
with what we produce in the NPM packages, or to be more
aligned with what Angular applications will usually consume,
the devmode output is switched from ES5 to ES2015.
Additionally various tsconfigs (outside of Bazel) have been
updated to match with the other parts of the build. The rules
are:
ES2015 for test configurations, ES2020 for actual code that will
end up being shipped (this includes the IDE-only tsconfigs).
PR Close#44505