InjectionToken can be created with an ngInjectableDef, and previously
this allowed the full expressiveness of @Injectable. However, this
requires a runtime reflection system in order to generate factories
from expressed provider declarations.
Instead, this change requires scoped InjectionTokens to provide the
factory directly (likely using inject() for the arguments), bypassing
the need for a reflection system.
Fixes#22205
PR Close#22207
@Injectable() supports a scope parameter which specifies the target module.
However, it's still difficult to specify that a particular service belongs
in the root injector. A developer attempting to ensure that must either
also provide a module intended for placement in the root injector or target
a module known to already be in the root injector (e.g. BrowserModule).
Both of these strategies are cumbersome and brittle.
Instead, this commit adds a token APP_ROOT_SCOPE which provides a
straightforward way of targeting the root injector directly, without
requiring special knowledge of modules within it.
PR Close#22185
This commit bundles 3 important changes, with the goal of enabling tree-shaking
of services which are never injected. Ordinarily, this tree-shaking is prevented
by the existence of a hard dependency on the service by the module in which it
is declared.
Firstly, @Injectable() is modified to accept a 'scope' parameter, which points
to an @NgModule(). This reverses the dependency edge, permitting the module to
not depend on the service which it "provides".
Secondly, the runtime is modified to understand the new relationship created
above. When a module receives a request to inject a token, and cannot find that
token in its list of providers, it will then look at the token for a special
ngInjectableDef field which indicates which module the token is scoped to. If
that module happens to be in the injector, it will behave as if the token
itself was in the injector to begin with.
Thirdly, the compiler is modified to read the @Injectable() metadata and to
generate the special ngInjectableDef field as part of TS compilation, using the
PartialModules system.
Additionally, this commit adds several unit and integration tests of various
flavors to test this change.
PR Close#22005
All of the providers in a module get compiled into a module definition in the
factory file. Some of these providers are for the actual module types, as those
are available for injection in Angular. For tree-shakeable tokens, the runtime
needs to be able to distinguish which modules are present in an injector.
This change adds a NodeFlag which tags those module providers for later
identification.
PR Close#22005
- Fix the case when first dynamic values are NO_CHANGE
- Do not store the static texts (even indexes) as bindings,
- Do not diff static texts (they do not change),
- Do not stringify static texts,
- Remove superfluous values walking.
PR Close#21881
By adding attributes on the <ng-content> element template authors
can decide how content should be re-projected (or, in other words:
which selectors should match re-projected content).
PR Close#21935
Implement NgOnChangesFeature, ViewContainerRef, TemplateRef,
and the renderEmbeddedTemplate instruction, and wire together the
pieces required for the ngForOf directive to work.
PR Close#21430
To prepare for pending ngForOf work, the dep from instructions -> query
should be broken. This will enable a dep from di -> instructions while
avoiding a di -> instructions -> query -> di cycle.
Analyzing this cycle also uncovered another problem: the implementation
of query() breaks tree-shaking through a hard dependency on DI concepts
of TemplateRef, ElementRef, ViewContainerRef. This is fundamentally due
to how query() can query for those values without any configuration.
Instead, this fix introduces the concept by employing the strategy
pattern, and redefining QueryReadType to pass a function which will
return one of the above values. This strategy is then used for 'read'
instead of an enum in cases where special values should be read from
the DI system.
PR Close#21430
assertLessThan() actually does the opposite of what it advertises.
It's only through luck that existing asserts have not failed
before. This changes assertLessThan to actually assert that the
value is less than something.
PR Close#21430
Adding the binding name to the error message recieved by the user gives
extra context on what exactly changed. The tests are also updated to
reflect the new error message.
PR Close#20352
- Improve `WrappedValue` by adding `unwrap` symetrical to `wrap`.
- remove dead code - `ValueUnwrapper`
The property `wrapped` is an implementation details and should never be accessed
directly - use `unwrap(wrappedValue)`. Will change to protected in Angular 7.
PR Close#20997
This change makes the code cleaner for the user. It does mean
a little bit more work for us since we have to patch the `type` back
into the `DirectiveDef`. However since the patching happens only once
on startup it should not be significant.
PR Close#21374
This separation is no longer needed since directives are now passed into the `container` as an array rather than as child functions of the `containerStart`
PR Close#21374
This change creates a spec file which contains canonical examples
of how the template compiler will translate templates into expected
output.
PR Close#21374
We used to have a separate `directive` instruction for instantiating
directives. However, such an instruction requires that directives
are created in the correct order, which would require that template
compiler would have knowledge of all dependent directives. This
would break template compilation locality principle.
This change only changes the APIs to expected form but does
not change the semantics. The semantics will need to be corrected
in subsequent commits. The semantic change needed is to
resolve the directive instantiation error at runtime based on
injection dependencies.
PR Close#21374