@angular/compiler 17.0.0-rc.1 → 17.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/src/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/directive.mjs +1 -1
- package/esm2022/src/render3/partial/factory.mjs +1 -1
- package/esm2022/src/render3/partial/injectable.mjs +1 -1
- package/esm2022/src/render3/partial/injector.mjs +1 -1
- package/esm2022/src/render3/partial/ng_module.mjs +1 -1
- package/esm2022/src/render3/partial/pipe.mjs +1 -1
- package/esm2022/src/render3/r3_ast.mjs +55 -61
- package/esm2022/src/render3/r3_control_flow.mjs +17 -13
- package/esm2022/src/render3/r3_deferred_blocks.mjs +7 -8
- package/esm2022/src/render3/r3_deferred_triggers.mjs +46 -27
- package/esm2022/src/render3/view/t2_api.mjs +1 -1
- package/esm2022/src/render3/view/t2_binder.mjs +22 -10
- package/esm2022/src/render3/view/template.mjs +54 -5
- package/esm2022/src/template/pipeline/ir/index.mjs +2 -1
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +75 -20
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +74 -71
- package/esm2022/src/template/pipeline/ir/src/handle.mjs +13 -0
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +47 -47
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +10 -9
- package/esm2022/src/template/pipeline/ir/src/traits.mjs +1 -32
- package/esm2022/src/template/pipeline/src/conversion.mjs +2 -2
- package/esm2022/src/template/pipeline/src/emit.mjs +117 -107
- package/esm2022/src/template/pipeline/src/ingest.mjs +155 -49
- package/esm2022/src/template/pipeline/src/instruction.mjs +36 -12
- package/esm2022/src/template/pipeline/src/phases/any_cast.mjs +4 -3
- package/esm2022/src/template/pipeline/src/phases/apply_i18n_expressions.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/assign_i18n_slot_dependencies.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/chaining.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/collapse_singleton_interpolations.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/conditionals.mjs +6 -6
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/defer_configs.mjs +30 -0
- package/esm2022/src/template/pipeline/src/phases/defer_resolve_targets.mjs +93 -0
- package/esm2022/src/template/pipeline/src/phases/empty_elements.mjs +4 -4
- package/esm2022/src/template/pipeline/src/phases/expand_safe_reads.mjs +7 -4
- package/esm2022/src/template/pipeline/src/phases/format_i18n_params.mjs +114 -0
- package/esm2022/src/template/pipeline/src/phases/generate_advance.mjs +4 -4
- package/esm2022/src/template/pipeline/src/phases/generate_projection_def.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +4 -3
- package/esm2022/src/template/pipeline/src/phases/has_const_expression_collection.mjs +28 -0
- package/esm2022/src/template/pipeline/src/phases/host_style_property_parsing.mjs +8 -2
- package/esm2022/src/template/pipeline/src/phases/i18n_const_collection.mjs +129 -7
- package/esm2022/src/template/pipeline/src/phases/i18n_message_extraction.mjs +4 -105
- package/esm2022/src/template/pipeline/src/phases/i18n_text_extraction.mjs +9 -6
- package/esm2022/src/template/pipeline/src/phases/icu_extraction.mjs +8 -5
- package/esm2022/src/template/pipeline/src/phases/local_refs.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/namespace.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/naming.mjs +11 -13
- package/esm2022/src/template/pipeline/src/phases/next_context_merging.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/ng_container.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/nonbindable.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/nullish_coalescing.mjs +8 -2
- package/esm2022/src/template/pipeline/src/phases/ordering.mjs +7 -2
- package/esm2022/src/template/pipeline/src/phases/parse_extracted_styles.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/phase_remove_content_selectors.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/pipe_creation.mjs +16 -11
- package/esm2022/src/template/pipeline/src/phases/pipe_variadic.mjs +7 -3
- package/esm2022/src/template/pipeline/src/phases/propagate_i18n_blocks.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/propagate_i18n_placeholders.mjs +61 -0
- package/esm2022/src/template/pipeline/src/phases/pure_function_extraction.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/pure_literal_structures.mjs +4 -4
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +49 -29
- package/esm2022/src/template/pipeline/src/phases/remove_empty_bindings.mjs +5 -2
- package/esm2022/src/template/pipeline/src/phases/repeater_derived_vars.mjs +7 -2
- package/esm2022/src/template/pipeline/src/phases/resolve_contexts.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/resolve_dollar_event.mjs +5 -5
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_element_placeholders.mjs +109 -0
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_expression_placeholders.mjs +58 -0
- package/esm2022/src/template/pipeline/src/phases/resolve_names.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/resolve_sanitizers.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/save_restore_view.mjs +14 -9
- package/esm2022/src/template/pipeline/src/phases/slot_allocation.mjs +4 -29
- package/esm2022/src/template/pipeline/src/phases/style_binding_specialization.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/temporary_variables.mjs +3 -3
- package/esm2022/src/template/pipeline/src/phases/track_fn_generation.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/track_fn_optimization.mjs +8 -2
- package/esm2022/src/template/pipeline/src/phases/track_variables.mjs +7 -2
- package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/variable_optimization.mjs +5 -5
- package/esm2022/src/template/pipeline/src/phases/wrap_icus.mjs +2 -2
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +1467 -1017
- package/fesm2022/compiler.mjs.map +1 -1
- package/index.d.ts +41 -58
- package/package.json +3 -3
- package/esm2022/src/template/pipeline/src/phases/has_const_trait_collection.mjs +0 -34
- package/esm2022/src/template/pipeline/src/phases/resolve_i18n_placeholders.mjs +0 -288
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v17.0.0-rc.
|
|
2
|
+
* @license Angular v17.0.0-rc.2
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -3792,16 +3792,21 @@ class Element$1 {
|
|
|
3792
3792
|
}
|
|
3793
3793
|
}
|
|
3794
3794
|
class DeferredTrigger {
|
|
3795
|
-
constructor(sourceSpan) {
|
|
3795
|
+
constructor(nameSpan, sourceSpan, prefetchSpan, whenOrOnSourceSpan) {
|
|
3796
|
+
this.nameSpan = nameSpan;
|
|
3796
3797
|
this.sourceSpan = sourceSpan;
|
|
3798
|
+
this.prefetchSpan = prefetchSpan;
|
|
3799
|
+
this.whenOrOnSourceSpan = whenOrOnSourceSpan;
|
|
3797
3800
|
}
|
|
3798
3801
|
visit(visitor) {
|
|
3799
3802
|
return visitor.visitDeferredTrigger(this);
|
|
3800
3803
|
}
|
|
3801
3804
|
}
|
|
3802
3805
|
class BoundDeferredTrigger extends DeferredTrigger {
|
|
3803
|
-
constructor(value, sourceSpan) {
|
|
3804
|
-
|
|
3806
|
+
constructor(value, sourceSpan, prefetchSpan, whenSourceSpan) {
|
|
3807
|
+
// BoundDeferredTrigger is for 'when' triggers. These aren't really "triggers" and don't have a
|
|
3808
|
+
// nameSpan. Trigger names are the built in event triggers like hover, interaction, etc.
|
|
3809
|
+
super(/** nameSpan */ null, sourceSpan, prefetchSpan, whenSourceSpan);
|
|
3805
3810
|
this.value = value;
|
|
3806
3811
|
}
|
|
3807
3812
|
}
|
|
@@ -3810,75 +3815,75 @@ class IdleDeferredTrigger extends DeferredTrigger {
|
|
|
3810
3815
|
class ImmediateDeferredTrigger extends DeferredTrigger {
|
|
3811
3816
|
}
|
|
3812
3817
|
class HoverDeferredTrigger extends DeferredTrigger {
|
|
3813
|
-
constructor(reference, sourceSpan) {
|
|
3814
|
-
super(sourceSpan);
|
|
3818
|
+
constructor(reference, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
|
|
3819
|
+
super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
3815
3820
|
this.reference = reference;
|
|
3816
3821
|
}
|
|
3817
3822
|
}
|
|
3818
3823
|
class TimerDeferredTrigger extends DeferredTrigger {
|
|
3819
|
-
constructor(delay, sourceSpan) {
|
|
3820
|
-
super(sourceSpan);
|
|
3824
|
+
constructor(delay, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
|
|
3825
|
+
super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
3821
3826
|
this.delay = delay;
|
|
3822
3827
|
}
|
|
3823
3828
|
}
|
|
3824
3829
|
class InteractionDeferredTrigger extends DeferredTrigger {
|
|
3825
|
-
constructor(reference, sourceSpan) {
|
|
3826
|
-
super(sourceSpan);
|
|
3830
|
+
constructor(reference, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
|
|
3831
|
+
super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
3827
3832
|
this.reference = reference;
|
|
3828
3833
|
}
|
|
3829
3834
|
}
|
|
3830
3835
|
class ViewportDeferredTrigger extends DeferredTrigger {
|
|
3831
|
-
constructor(reference, sourceSpan) {
|
|
3832
|
-
super(sourceSpan);
|
|
3836
|
+
constructor(reference, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
|
|
3837
|
+
super(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
3833
3838
|
this.reference = reference;
|
|
3834
3839
|
}
|
|
3835
3840
|
}
|
|
3836
|
-
class
|
|
3837
|
-
constructor(
|
|
3838
|
-
this.
|
|
3839
|
-
this.minimumTime = minimumTime;
|
|
3841
|
+
class BlockNode {
|
|
3842
|
+
constructor(nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3843
|
+
this.nameSpan = nameSpan;
|
|
3840
3844
|
this.sourceSpan = sourceSpan;
|
|
3841
3845
|
this.startSourceSpan = startSourceSpan;
|
|
3842
3846
|
this.endSourceSpan = endSourceSpan;
|
|
3843
3847
|
}
|
|
3848
|
+
}
|
|
3849
|
+
class DeferredBlockPlaceholder extends BlockNode {
|
|
3850
|
+
constructor(children, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3851
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3852
|
+
this.children = children;
|
|
3853
|
+
this.minimumTime = minimumTime;
|
|
3854
|
+
}
|
|
3844
3855
|
visit(visitor) {
|
|
3845
3856
|
return visitor.visitDeferredBlockPlaceholder(this);
|
|
3846
3857
|
}
|
|
3847
3858
|
}
|
|
3848
|
-
class DeferredBlockLoading {
|
|
3849
|
-
constructor(children, afterTime, minimumTime, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3859
|
+
class DeferredBlockLoading extends BlockNode {
|
|
3860
|
+
constructor(children, afterTime, minimumTime, nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3861
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3850
3862
|
this.children = children;
|
|
3851
3863
|
this.afterTime = afterTime;
|
|
3852
3864
|
this.minimumTime = minimumTime;
|
|
3853
|
-
this.sourceSpan = sourceSpan;
|
|
3854
|
-
this.startSourceSpan = startSourceSpan;
|
|
3855
|
-
this.endSourceSpan = endSourceSpan;
|
|
3856
3865
|
}
|
|
3857
3866
|
visit(visitor) {
|
|
3858
3867
|
return visitor.visitDeferredBlockLoading(this);
|
|
3859
3868
|
}
|
|
3860
3869
|
}
|
|
3861
|
-
class DeferredBlockError {
|
|
3862
|
-
constructor(children, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3870
|
+
class DeferredBlockError extends BlockNode {
|
|
3871
|
+
constructor(children, nameSpan, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3872
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3863
3873
|
this.children = children;
|
|
3864
|
-
this.sourceSpan = sourceSpan;
|
|
3865
|
-
this.startSourceSpan = startSourceSpan;
|
|
3866
|
-
this.endSourceSpan = endSourceSpan;
|
|
3867
3874
|
}
|
|
3868
3875
|
visit(visitor) {
|
|
3869
3876
|
return visitor.visitDeferredBlockError(this);
|
|
3870
3877
|
}
|
|
3871
3878
|
}
|
|
3872
|
-
class DeferredBlock {
|
|
3873
|
-
constructor(children, triggers, prefetchTriggers, placeholder, loading, error, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
|
|
3879
|
+
class DeferredBlock extends BlockNode {
|
|
3880
|
+
constructor(children, triggers, prefetchTriggers, placeholder, loading, error, nameSpan, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
|
|
3881
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3874
3882
|
this.children = children;
|
|
3875
3883
|
this.placeholder = placeholder;
|
|
3876
3884
|
this.loading = loading;
|
|
3877
3885
|
this.error = error;
|
|
3878
|
-
this.sourceSpan = sourceSpan;
|
|
3879
3886
|
this.mainBlockSpan = mainBlockSpan;
|
|
3880
|
-
this.startSourceSpan = startSourceSpan;
|
|
3881
|
-
this.endSourceSpan = endSourceSpan;
|
|
3882
3887
|
this.triggers = triggers;
|
|
3883
3888
|
this.prefetchTriggers = prefetchTriggers;
|
|
3884
3889
|
// We cache the keys since we know that they won't change and we
|
|
@@ -3900,83 +3905,72 @@ class DeferredBlock {
|
|
|
3900
3905
|
visitAll$1(visitor, keys.map(k => triggers[k]));
|
|
3901
3906
|
}
|
|
3902
3907
|
}
|
|
3903
|
-
class SwitchBlock {
|
|
3908
|
+
class SwitchBlock extends BlockNode {
|
|
3904
3909
|
constructor(expression, cases,
|
|
3905
3910
|
/**
|
|
3906
3911
|
* These blocks are only captured to allow for autocompletion in the language service. They
|
|
3907
3912
|
* aren't meant to be processed in any other way.
|
|
3908
3913
|
*/
|
|
3909
|
-
unknownBlocks, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3914
|
+
unknownBlocks, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
3915
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3910
3916
|
this.expression = expression;
|
|
3911
3917
|
this.cases = cases;
|
|
3912
3918
|
this.unknownBlocks = unknownBlocks;
|
|
3913
|
-
this.sourceSpan = sourceSpan;
|
|
3914
|
-
this.startSourceSpan = startSourceSpan;
|
|
3915
|
-
this.endSourceSpan = endSourceSpan;
|
|
3916
3919
|
}
|
|
3917
3920
|
visit(visitor) {
|
|
3918
3921
|
return visitor.visitSwitchBlock(this);
|
|
3919
3922
|
}
|
|
3920
3923
|
}
|
|
3921
|
-
class SwitchBlockCase {
|
|
3922
|
-
constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3924
|
+
class SwitchBlockCase extends BlockNode {
|
|
3925
|
+
constructor(expression, children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
3926
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3923
3927
|
this.expression = expression;
|
|
3924
3928
|
this.children = children;
|
|
3925
|
-
this.sourceSpan = sourceSpan;
|
|
3926
|
-
this.startSourceSpan = startSourceSpan;
|
|
3927
|
-
this.endSourceSpan = endSourceSpan;
|
|
3928
3929
|
}
|
|
3929
3930
|
visit(visitor) {
|
|
3930
3931
|
return visitor.visitSwitchBlockCase(this);
|
|
3931
3932
|
}
|
|
3932
3933
|
}
|
|
3933
|
-
class ForLoopBlock {
|
|
3934
|
-
constructor(item, expression, trackBy, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan) {
|
|
3934
|
+
class ForLoopBlock extends BlockNode {
|
|
3935
|
+
constructor(item, expression, trackBy, trackKeywordSpan, contextVariables, children, empty, sourceSpan, mainBlockSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
3936
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3935
3937
|
this.item = item;
|
|
3936
3938
|
this.expression = expression;
|
|
3937
3939
|
this.trackBy = trackBy;
|
|
3940
|
+
this.trackKeywordSpan = trackKeywordSpan;
|
|
3938
3941
|
this.contextVariables = contextVariables;
|
|
3939
3942
|
this.children = children;
|
|
3940
3943
|
this.empty = empty;
|
|
3941
|
-
this.sourceSpan = sourceSpan;
|
|
3942
3944
|
this.mainBlockSpan = mainBlockSpan;
|
|
3943
|
-
this.startSourceSpan = startSourceSpan;
|
|
3944
|
-
this.endSourceSpan = endSourceSpan;
|
|
3945
3945
|
}
|
|
3946
3946
|
visit(visitor) {
|
|
3947
3947
|
return visitor.visitForLoopBlock(this);
|
|
3948
3948
|
}
|
|
3949
3949
|
}
|
|
3950
|
-
class ForLoopBlockEmpty {
|
|
3951
|
-
constructor(children, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3950
|
+
class ForLoopBlockEmpty extends BlockNode {
|
|
3951
|
+
constructor(children, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
3952
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3952
3953
|
this.children = children;
|
|
3953
|
-
this.sourceSpan = sourceSpan;
|
|
3954
|
-
this.startSourceSpan = startSourceSpan;
|
|
3955
|
-
this.endSourceSpan = endSourceSpan;
|
|
3956
3954
|
}
|
|
3957
3955
|
visit(visitor) {
|
|
3958
3956
|
return visitor.visitForLoopBlockEmpty(this);
|
|
3959
3957
|
}
|
|
3960
3958
|
}
|
|
3961
|
-
class IfBlock {
|
|
3962
|
-
constructor(branches, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3959
|
+
class IfBlock extends BlockNode {
|
|
3960
|
+
constructor(branches, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
3961
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3963
3962
|
this.branches = branches;
|
|
3964
|
-
this.sourceSpan = sourceSpan;
|
|
3965
|
-
this.startSourceSpan = startSourceSpan;
|
|
3966
|
-
this.endSourceSpan = endSourceSpan;
|
|
3967
3963
|
}
|
|
3968
3964
|
visit(visitor) {
|
|
3969
3965
|
return visitor.visitIfBlock(this);
|
|
3970
3966
|
}
|
|
3971
3967
|
}
|
|
3972
|
-
class IfBlockBranch {
|
|
3973
|
-
constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
3968
|
+
class IfBlockBranch extends BlockNode {
|
|
3969
|
+
constructor(expression, children, expressionAlias, sourceSpan, startSourceSpan, endSourceSpan, nameSpan) {
|
|
3970
|
+
super(nameSpan, sourceSpan, startSourceSpan, endSourceSpan);
|
|
3974
3971
|
this.expression = expression;
|
|
3975
3972
|
this.children = children;
|
|
3976
3973
|
this.expressionAlias = expressionAlias;
|
|
3977
|
-
this.sourceSpan = sourceSpan;
|
|
3978
|
-
this.startSourceSpan = startSourceSpan;
|
|
3979
|
-
this.endSourceSpan = endSourceSpan;
|
|
3980
3974
|
}
|
|
3981
3975
|
visit(visitor) {
|
|
3982
3976
|
return visitor.visitIfBlockBranch(this);
|
|
@@ -8799,70 +8793,66 @@ var OpKind;
|
|
|
8799
8793
|
* An operation that configures a `@defer` block.
|
|
8800
8794
|
*/
|
|
8801
8795
|
OpKind[OpKind["Defer"] = 26] = "Defer";
|
|
8802
|
-
/**
|
|
8803
|
-
* An IR operation that provides secondary templates of a `@defer` block.
|
|
8804
|
-
*/
|
|
8805
|
-
OpKind[OpKind["DeferSecondaryBlock"] = 27] = "DeferSecondaryBlock";
|
|
8806
8796
|
/**
|
|
8807
8797
|
* An operation that controls when a `@defer` loads.
|
|
8808
8798
|
*/
|
|
8809
|
-
OpKind[OpKind["DeferOn"] =
|
|
8799
|
+
OpKind[OpKind["DeferOn"] = 27] = "DeferOn";
|
|
8810
8800
|
/**
|
|
8811
8801
|
* An i18n message that has been extracted for inclusion in the consts array.
|
|
8812
8802
|
*/
|
|
8813
|
-
OpKind[OpKind["ExtractedMessage"] =
|
|
8803
|
+
OpKind[OpKind["ExtractedMessage"] = 28] = "ExtractedMessage";
|
|
8814
8804
|
/**
|
|
8815
8805
|
* A host binding property.
|
|
8816
8806
|
*/
|
|
8817
|
-
OpKind[OpKind["HostProperty"] =
|
|
8807
|
+
OpKind[OpKind["HostProperty"] = 29] = "HostProperty";
|
|
8818
8808
|
/**
|
|
8819
8809
|
* A namespace change, which causes the subsequent elements to be processed as either HTML or SVG.
|
|
8820
8810
|
*/
|
|
8821
|
-
OpKind[OpKind["Namespace"] =
|
|
8811
|
+
OpKind[OpKind["Namespace"] = 30] = "Namespace";
|
|
8822
8812
|
/**
|
|
8823
8813
|
* Configure a content projeciton definition for the view.
|
|
8824
8814
|
*/
|
|
8825
|
-
OpKind[OpKind["ProjectionDef"] =
|
|
8815
|
+
OpKind[OpKind["ProjectionDef"] = 31] = "ProjectionDef";
|
|
8826
8816
|
/**
|
|
8827
8817
|
* Create a content projection slot.
|
|
8828
8818
|
*/
|
|
8829
|
-
OpKind[OpKind["Projection"] =
|
|
8819
|
+
OpKind[OpKind["Projection"] = 32] = "Projection";
|
|
8830
8820
|
/**
|
|
8831
8821
|
* Create a repeater creation instruction op.
|
|
8832
8822
|
*/
|
|
8833
|
-
OpKind[OpKind["RepeaterCreate"] =
|
|
8823
|
+
OpKind[OpKind["RepeaterCreate"] = 33] = "RepeaterCreate";
|
|
8834
8824
|
/**
|
|
8835
8825
|
* An update up for a repeater.
|
|
8836
8826
|
*/
|
|
8837
|
-
OpKind[OpKind["Repeater"] =
|
|
8827
|
+
OpKind[OpKind["Repeater"] = 34] = "Repeater";
|
|
8838
8828
|
/**
|
|
8839
8829
|
* The start of an i18n block.
|
|
8840
8830
|
*/
|
|
8841
|
-
OpKind[OpKind["I18nStart"] =
|
|
8831
|
+
OpKind[OpKind["I18nStart"] = 35] = "I18nStart";
|
|
8842
8832
|
/**
|
|
8843
8833
|
* A self-closing i18n on a single element.
|
|
8844
8834
|
*/
|
|
8845
|
-
OpKind[OpKind["I18n"] =
|
|
8835
|
+
OpKind[OpKind["I18n"] = 36] = "I18n";
|
|
8846
8836
|
/**
|
|
8847
8837
|
* The end of an i18n block.
|
|
8848
8838
|
*/
|
|
8849
|
-
OpKind[OpKind["I18nEnd"] =
|
|
8839
|
+
OpKind[OpKind["I18nEnd"] = 37] = "I18nEnd";
|
|
8850
8840
|
/**
|
|
8851
8841
|
* An expression in an i18n message.
|
|
8852
8842
|
*/
|
|
8853
|
-
OpKind[OpKind["I18nExpression"] =
|
|
8843
|
+
OpKind[OpKind["I18nExpression"] = 38] = "I18nExpression";
|
|
8854
8844
|
/**
|
|
8855
8845
|
* An instruction that applies a set of i18n expressions.
|
|
8856
8846
|
*/
|
|
8857
|
-
OpKind[OpKind["I18nApply"] =
|
|
8847
|
+
OpKind[OpKind["I18nApply"] = 39] = "I18nApply";
|
|
8858
8848
|
/**
|
|
8859
8849
|
* An instruction to create an ICU expression.
|
|
8860
8850
|
*/
|
|
8861
|
-
OpKind[OpKind["Icu"] =
|
|
8851
|
+
OpKind[OpKind["Icu"] = 40] = "Icu";
|
|
8862
8852
|
/**
|
|
8863
8853
|
* An instruction to update an ICU expression.
|
|
8864
8854
|
*/
|
|
8865
|
-
OpKind[OpKind["IcuUpdate"] =
|
|
8855
|
+
OpKind[OpKind["IcuUpdate"] = 41] = "IcuUpdate";
|
|
8866
8856
|
})(OpKind || (OpKind = {}));
|
|
8867
8857
|
/**
|
|
8868
8858
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -8966,6 +8956,10 @@ var ExpressionKind;
|
|
|
8966
8956
|
* properties ($even, $first, etc.).
|
|
8967
8957
|
*/
|
|
8968
8958
|
ExpressionKind[ExpressionKind["DerivedRepeaterVar"] = 23] = "DerivedRepeaterVar";
|
|
8959
|
+
/**
|
|
8960
|
+
* An expression that will be automatically extracted to the component const array.
|
|
8961
|
+
*/
|
|
8962
|
+
ExpressionKind[ExpressionKind["ConstCollected"] = 24] = "ConstCollected";
|
|
8969
8963
|
})(ExpressionKind || (ExpressionKind = {}));
|
|
8970
8964
|
var VariableFlags;
|
|
8971
8965
|
(function (VariableFlags) {
|
|
@@ -9080,6 +9074,61 @@ var I18nParamResolutionTime;
|
|
|
9080
9074
|
*/
|
|
9081
9075
|
I18nParamResolutionTime[I18nParamResolutionTime["Postproccessing"] = 1] = "Postproccessing";
|
|
9082
9076
|
})(I18nParamResolutionTime || (I18nParamResolutionTime = {}));
|
|
9077
|
+
/**
|
|
9078
|
+
* Flags that describe what an i18n param value. These determine how the value is serialized into
|
|
9079
|
+
* the final map.
|
|
9080
|
+
*/
|
|
9081
|
+
var I18nParamValueFlags;
|
|
9082
|
+
(function (I18nParamValueFlags) {
|
|
9083
|
+
I18nParamValueFlags[I18nParamValueFlags["None"] = 0] = "None";
|
|
9084
|
+
/**
|
|
9085
|
+
* This value represtents an element tag.
|
|
9086
|
+
*/
|
|
9087
|
+
I18nParamValueFlags[I18nParamValueFlags["ElementTag"] = 1] = "ElementTag";
|
|
9088
|
+
/**
|
|
9089
|
+
* This value represents a template tag.
|
|
9090
|
+
*/
|
|
9091
|
+
I18nParamValueFlags[I18nParamValueFlags["TemplateTag"] = 2] = "TemplateTag";
|
|
9092
|
+
/**
|
|
9093
|
+
* This value represents the opening of a tag.
|
|
9094
|
+
*/
|
|
9095
|
+
I18nParamValueFlags[I18nParamValueFlags["OpenTag"] = 4] = "OpenTag";
|
|
9096
|
+
/**
|
|
9097
|
+
* This value represents the closing of a tag.
|
|
9098
|
+
*/
|
|
9099
|
+
I18nParamValueFlags[I18nParamValueFlags["CloseTag"] = 8] = "CloseTag";
|
|
9100
|
+
})(I18nParamValueFlags || (I18nParamValueFlags = {}));
|
|
9101
|
+
/**
|
|
9102
|
+
* Whether the active namespace is HTML, MathML, or SVG mode.
|
|
9103
|
+
*/
|
|
9104
|
+
var Namespace;
|
|
9105
|
+
(function (Namespace) {
|
|
9106
|
+
Namespace[Namespace["HTML"] = 0] = "HTML";
|
|
9107
|
+
Namespace[Namespace["SVG"] = 1] = "SVG";
|
|
9108
|
+
Namespace[Namespace["Math"] = 2] = "Math";
|
|
9109
|
+
})(Namespace || (Namespace = {}));
|
|
9110
|
+
/**
|
|
9111
|
+
* The type of a `@defer` trigger, for use in the ir.
|
|
9112
|
+
*/
|
|
9113
|
+
var DeferTriggerKind;
|
|
9114
|
+
(function (DeferTriggerKind) {
|
|
9115
|
+
DeferTriggerKind[DeferTriggerKind["Idle"] = 0] = "Idle";
|
|
9116
|
+
DeferTriggerKind[DeferTriggerKind["Immediate"] = 1] = "Immediate";
|
|
9117
|
+
DeferTriggerKind[DeferTriggerKind["Timer"] = 2] = "Timer";
|
|
9118
|
+
DeferTriggerKind[DeferTriggerKind["Hover"] = 3] = "Hover";
|
|
9119
|
+
DeferTriggerKind[DeferTriggerKind["Interaction"] = 4] = "Interaction";
|
|
9120
|
+
DeferTriggerKind[DeferTriggerKind["Viewport"] = 5] = "Viewport";
|
|
9121
|
+
})(DeferTriggerKind || (DeferTriggerKind = {}));
|
|
9122
|
+
/**
|
|
9123
|
+
* Repeaters implicitly define these derived variables, and child nodes may read them.
|
|
9124
|
+
*/
|
|
9125
|
+
var DerivedRepeaterVarIdentity;
|
|
9126
|
+
(function (DerivedRepeaterVarIdentity) {
|
|
9127
|
+
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["First"] = 0] = "First";
|
|
9128
|
+
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Last"] = 1] = "Last";
|
|
9129
|
+
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Even"] = 2] = "Even";
|
|
9130
|
+
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Odd"] = 3] = "Odd";
|
|
9131
|
+
})(DerivedRepeaterVarIdentity || (DerivedRepeaterVarIdentity = {}));
|
|
9083
9132
|
|
|
9084
9133
|
/**
|
|
9085
9134
|
* Marker symbol for `ConsumesSlotOpTrait`.
|
|
@@ -9089,10 +9138,6 @@ const ConsumesSlot = Symbol('ConsumesSlot');
|
|
|
9089
9138
|
* Marker symbol for `DependsOnSlotContextOpTrait`.
|
|
9090
9139
|
*/
|
|
9091
9140
|
const DependsOnSlotContext = Symbol('DependsOnSlotContext');
|
|
9092
|
-
/**
|
|
9093
|
-
* Marker symbol for `UsesSlotIndex` trait.
|
|
9094
|
-
*/
|
|
9095
|
-
const UsesSlotIndex = Symbol('UsesSlotIndex');
|
|
9096
9141
|
/**
|
|
9097
9142
|
* Marker symbol for `ConsumesVars` trait.
|
|
9098
9143
|
*/
|
|
@@ -9101,27 +9146,14 @@ const ConsumesVarsTrait = Symbol('ConsumesVars');
|
|
|
9101
9146
|
* Marker symbol for `UsesVarOffset` trait.
|
|
9102
9147
|
*/
|
|
9103
9148
|
const UsesVarOffset = Symbol('UsesVarOffset');
|
|
9104
|
-
/**
|
|
9105
|
-
* Marker symbol for `HasConst` trait.
|
|
9106
|
-
*/
|
|
9107
|
-
const HasConst = Symbol('HasConst');
|
|
9108
9149
|
/**
|
|
9109
9150
|
* Default values for most `ConsumesSlotOpTrait` fields (used with the spread operator to initialize
|
|
9110
9151
|
* implementors of the trait).
|
|
9111
9152
|
*/
|
|
9112
9153
|
const TRAIT_CONSUMES_SLOT = {
|
|
9113
9154
|
[ConsumesSlot]: true,
|
|
9114
|
-
slot: null,
|
|
9115
9155
|
numSlotsUsed: 1,
|
|
9116
9156
|
};
|
|
9117
|
-
/**
|
|
9118
|
-
* Default values for most `UsesSlotIndexTrait` fields (used with the spread operator to initialize
|
|
9119
|
-
* implementors of the trait).
|
|
9120
|
-
*/
|
|
9121
|
-
const TRAIT_USES_SLOT_INDEX = {
|
|
9122
|
-
[UsesSlotIndex]: true,
|
|
9123
|
-
targetSlot: null,
|
|
9124
|
-
};
|
|
9125
9157
|
/**
|
|
9126
9158
|
* Default values for most `DependsOnSlotContextOpTrait` fields (used with the spread operator to
|
|
9127
9159
|
* initialize implementors of the trait).
|
|
@@ -9144,14 +9176,6 @@ const TRAIT_USES_VAR_OFFSET = {
|
|
|
9144
9176
|
[UsesVarOffset]: true,
|
|
9145
9177
|
varOffset: null,
|
|
9146
9178
|
};
|
|
9147
|
-
/**
|
|
9148
|
-
* Default values for `HasConst` fields (used with the spread operator to initialize
|
|
9149
|
-
* implementors of this trait).
|
|
9150
|
-
*/
|
|
9151
|
-
const TRAIT_HAS_CONST = {
|
|
9152
|
-
[HasConst]: true,
|
|
9153
|
-
constIndex: null,
|
|
9154
|
-
};
|
|
9155
9179
|
/**
|
|
9156
9180
|
* Test whether an operation implements `ConsumesSlotOpTrait`.
|
|
9157
9181
|
*/
|
|
@@ -9173,12 +9197,6 @@ function hasConsumesVarsTrait(value) {
|
|
|
9173
9197
|
function hasUsesVarOffsetTrait(expr) {
|
|
9174
9198
|
return expr[UsesVarOffset] === true;
|
|
9175
9199
|
}
|
|
9176
|
-
function hasUsesSlotIndexTrait(value) {
|
|
9177
|
-
return value[UsesSlotIndex] === true;
|
|
9178
|
-
}
|
|
9179
|
-
function hasConstTrait(value) {
|
|
9180
|
-
return value[HasConst] === true;
|
|
9181
|
-
}
|
|
9182
9200
|
|
|
9183
9201
|
/**
|
|
9184
9202
|
* Create a `StatementOp`.
|
|
@@ -9361,38 +9379,39 @@ function createAdvanceOp(delta, sourceSpan) {
|
|
|
9361
9379
|
/**
|
|
9362
9380
|
* Create a conditional op, which will display an embedded view according to a condtion.
|
|
9363
9381
|
*/
|
|
9364
|
-
function createConditionalOp(target, test, conditions, sourceSpan) {
|
|
9382
|
+
function createConditionalOp(target, targetSlot, test, conditions, sourceSpan) {
|
|
9365
9383
|
return {
|
|
9366
9384
|
kind: OpKind.Conditional,
|
|
9367
9385
|
target,
|
|
9386
|
+
targetSlot,
|
|
9368
9387
|
test,
|
|
9369
9388
|
conditions,
|
|
9370
9389
|
processed: null,
|
|
9371
9390
|
sourceSpan,
|
|
9372
9391
|
contextValue: null,
|
|
9373
9392
|
...NEW_OP,
|
|
9374
|
-
...TRAIT_USES_SLOT_INDEX,
|
|
9375
9393
|
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9376
9394
|
...TRAIT_CONSUMES_VARS,
|
|
9377
9395
|
};
|
|
9378
9396
|
}
|
|
9379
|
-
function createRepeaterOp(repeaterCreate, collection, sourceSpan) {
|
|
9397
|
+
function createRepeaterOp(repeaterCreate, targetSlot, collection, sourceSpan) {
|
|
9380
9398
|
return {
|
|
9381
9399
|
kind: OpKind.Repeater,
|
|
9382
9400
|
target: repeaterCreate,
|
|
9401
|
+
targetSlot,
|
|
9383
9402
|
collection,
|
|
9384
9403
|
sourceSpan,
|
|
9385
9404
|
...NEW_OP,
|
|
9386
|
-
...TRAIT_USES_SLOT_INDEX,
|
|
9387
9405
|
};
|
|
9388
9406
|
}
|
|
9389
9407
|
/**
|
|
9390
9408
|
* Create an i18n expression op.
|
|
9391
9409
|
*/
|
|
9392
|
-
function createI18nExpressionOp(owner, expression, i18nPlaceholder, resolutionTime, sourceSpan) {
|
|
9410
|
+
function createI18nExpressionOp(owner, ownerSlot, expression, i18nPlaceholder, resolutionTime, sourceSpan) {
|
|
9393
9411
|
return {
|
|
9394
9412
|
kind: OpKind.I18nExpression,
|
|
9395
9413
|
owner,
|
|
9414
|
+
ownerSlot,
|
|
9396
9415
|
target: owner,
|
|
9397
9416
|
expression,
|
|
9398
9417
|
i18nPlaceholder,
|
|
@@ -9406,13 +9425,13 @@ function createI18nExpressionOp(owner, expression, i18nPlaceholder, resolutionTi
|
|
|
9406
9425
|
/**
|
|
9407
9426
|
*Creates an op to apply i18n expression ops
|
|
9408
9427
|
*/
|
|
9409
|
-
function createI18nApplyOp(target, sourceSpan) {
|
|
9428
|
+
function createI18nApplyOp(target, targetSlot, sourceSpan) {
|
|
9410
9429
|
return {
|
|
9411
9430
|
kind: OpKind.I18nApply,
|
|
9412
9431
|
target,
|
|
9432
|
+
targetSlot,
|
|
9413
9433
|
sourceSpan,
|
|
9414
9434
|
...NEW_OP,
|
|
9415
|
-
...TRAIT_USES_SLOT_INDEX,
|
|
9416
9435
|
};
|
|
9417
9436
|
}
|
|
9418
9437
|
/**
|
|
@@ -9427,7 +9446,7 @@ function createIcuUpdateOp(xref, sourceSpan) {
|
|
|
9427
9446
|
};
|
|
9428
9447
|
}
|
|
9429
9448
|
|
|
9430
|
-
var _a, _b, _c, _d, _e, _f
|
|
9449
|
+
var _a, _b, _c, _d, _e, _f;
|
|
9431
9450
|
/**
|
|
9432
9451
|
* Check whether a given `o.Expression` is a logical IR expression type.
|
|
9433
9452
|
*/
|
|
@@ -9470,14 +9489,12 @@ class LexicalReadExpr extends ExpressionBase {
|
|
|
9470
9489
|
* Runtime operation to retrieve the value of a local reference.
|
|
9471
9490
|
*/
|
|
9472
9491
|
class ReferenceExpr extends ExpressionBase {
|
|
9473
|
-
|
|
9474
|
-
constructor(target, offset) {
|
|
9492
|
+
constructor(target, targetSlot, offset) {
|
|
9475
9493
|
super();
|
|
9476
9494
|
this.target = target;
|
|
9495
|
+
this.targetSlot = targetSlot;
|
|
9477
9496
|
this.offset = offset;
|
|
9478
9497
|
this.kind = ExpressionKind.Reference;
|
|
9479
|
-
this[_a] = true;
|
|
9480
|
-
this.targetSlot = null;
|
|
9481
9498
|
}
|
|
9482
9499
|
visitExpression() { }
|
|
9483
9500
|
isEquivalent(e) {
|
|
@@ -9488,9 +9505,7 @@ class ReferenceExpr extends ExpressionBase {
|
|
|
9488
9505
|
}
|
|
9489
9506
|
transformInternalExpressions() { }
|
|
9490
9507
|
clone() {
|
|
9491
|
-
|
|
9492
|
-
expr.targetSlot = this.targetSlot;
|
|
9493
|
-
return expr;
|
|
9508
|
+
return new ReferenceExpr(this.target, this.targetSlot, this.offset);
|
|
9494
9509
|
}
|
|
9495
9510
|
}
|
|
9496
9511
|
/**
|
|
@@ -9668,12 +9683,12 @@ class ReadVariableExpr extends ExpressionBase {
|
|
|
9668
9683
|
}
|
|
9669
9684
|
}
|
|
9670
9685
|
class PureFunctionExpr extends ExpressionBase {
|
|
9671
|
-
static {
|
|
9686
|
+
static { _a = ConsumesVarsTrait, _b = UsesVarOffset; }
|
|
9672
9687
|
constructor(expression, args) {
|
|
9673
9688
|
super();
|
|
9674
9689
|
this.kind = ExpressionKind.PureFunctionExpr;
|
|
9690
|
+
this[_a] = true;
|
|
9675
9691
|
this[_b] = true;
|
|
9676
|
-
this[_c] = true;
|
|
9677
9692
|
this.varOffset = null;
|
|
9678
9693
|
/**
|
|
9679
9694
|
* Once extracted to the `ConstantPool`, a reference to the function which defines the computation
|
|
@@ -9737,17 +9752,16 @@ class PureFunctionParameterExpr extends ExpressionBase {
|
|
|
9737
9752
|
}
|
|
9738
9753
|
}
|
|
9739
9754
|
class PipeBindingExpr extends ExpressionBase {
|
|
9740
|
-
static {
|
|
9741
|
-
constructor(target, name, args) {
|
|
9755
|
+
static { _c = ConsumesVarsTrait, _d = UsesVarOffset; }
|
|
9756
|
+
constructor(target, targetSlot, name, args) {
|
|
9742
9757
|
super();
|
|
9743
9758
|
this.target = target;
|
|
9759
|
+
this.targetSlot = targetSlot;
|
|
9744
9760
|
this.name = name;
|
|
9745
9761
|
this.args = args;
|
|
9746
9762
|
this.kind = ExpressionKind.PipeBinding;
|
|
9763
|
+
this[_c] = true;
|
|
9747
9764
|
this[_d] = true;
|
|
9748
|
-
this[_e] = true;
|
|
9749
|
-
this[_f] = true;
|
|
9750
|
-
this.targetSlot = null;
|
|
9751
9765
|
this.varOffset = null;
|
|
9752
9766
|
}
|
|
9753
9767
|
visitExpression(visitor, context) {
|
|
@@ -9767,25 +9781,23 @@ class PipeBindingExpr extends ExpressionBase {
|
|
|
9767
9781
|
}
|
|
9768
9782
|
}
|
|
9769
9783
|
clone() {
|
|
9770
|
-
const r = new PipeBindingExpr(this.target, this.name, this.args.map(a => a.clone()));
|
|
9771
|
-
r.targetSlot = this.targetSlot;
|
|
9784
|
+
const r = new PipeBindingExpr(this.target, this.targetSlot, this.name, this.args.map(a => a.clone()));
|
|
9772
9785
|
r.varOffset = this.varOffset;
|
|
9773
9786
|
return r;
|
|
9774
9787
|
}
|
|
9775
9788
|
}
|
|
9776
9789
|
class PipeBindingVariadicExpr extends ExpressionBase {
|
|
9777
|
-
static {
|
|
9778
|
-
constructor(target, name, args, numArgs) {
|
|
9790
|
+
static { _e = ConsumesVarsTrait, _f = UsesVarOffset; }
|
|
9791
|
+
constructor(target, targetSlot, name, args, numArgs) {
|
|
9779
9792
|
super();
|
|
9780
9793
|
this.target = target;
|
|
9794
|
+
this.targetSlot = targetSlot;
|
|
9781
9795
|
this.name = name;
|
|
9782
9796
|
this.args = args;
|
|
9783
9797
|
this.numArgs = numArgs;
|
|
9784
9798
|
this.kind = ExpressionKind.PipeBindingVariadic;
|
|
9785
|
-
this[
|
|
9786
|
-
this[
|
|
9787
|
-
this[_j] = true;
|
|
9788
|
-
this.targetSlot = null;
|
|
9799
|
+
this[_e] = true;
|
|
9800
|
+
this[_f] = true;
|
|
9789
9801
|
this.varOffset = null;
|
|
9790
9802
|
}
|
|
9791
9803
|
visitExpression(visitor, context) {
|
|
@@ -9801,8 +9813,7 @@ class PipeBindingVariadicExpr extends ExpressionBase {
|
|
|
9801
9813
|
this.args = transformExpressionsInExpression(this.args, transform, flags);
|
|
9802
9814
|
}
|
|
9803
9815
|
clone() {
|
|
9804
|
-
const r = new PipeBindingVariadicExpr(this.target, this.name, this.args.clone(), this.numArgs);
|
|
9805
|
-
r.targetSlot = this.targetSlot;
|
|
9816
|
+
const r = new PipeBindingVariadicExpr(this.target, this.targetSlot, this.name, this.args.clone(), this.numArgs);
|
|
9806
9817
|
r.varOffset = this.varOffset;
|
|
9807
9818
|
return r;
|
|
9808
9819
|
}
|
|
@@ -9996,26 +10007,20 @@ class SanitizerExpr extends ExpressionBase {
|
|
|
9996
10007
|
transformInternalExpressions() { }
|
|
9997
10008
|
}
|
|
9998
10009
|
class SlotLiteralExpr extends ExpressionBase {
|
|
9999
|
-
|
|
10000
|
-
constructor(target) {
|
|
10010
|
+
constructor(slot) {
|
|
10001
10011
|
super();
|
|
10002
|
-
this.
|
|
10012
|
+
this.slot = slot;
|
|
10003
10013
|
this.kind = ExpressionKind.SlotLiteralExpr;
|
|
10004
|
-
this[_k] = true;
|
|
10005
|
-
this.targetSlot = null;
|
|
10006
10014
|
}
|
|
10007
10015
|
visitExpression(visitor, context) { }
|
|
10008
10016
|
isEquivalent(e) {
|
|
10009
|
-
return e instanceof SlotLiteralExpr && e.
|
|
10010
|
-
e.targetSlot === this.targetSlot;
|
|
10017
|
+
return e instanceof SlotLiteralExpr && e.slot === this.slot;
|
|
10011
10018
|
}
|
|
10012
10019
|
isConstant() {
|
|
10013
10020
|
return true;
|
|
10014
10021
|
}
|
|
10015
10022
|
clone() {
|
|
10016
|
-
|
|
10017
|
-
copy.targetSlot = this.targetSlot;
|
|
10018
|
-
return copy;
|
|
10023
|
+
return new SlotLiteralExpr(this.slot);
|
|
10019
10024
|
}
|
|
10020
10025
|
transformInternalExpressions() { }
|
|
10021
10026
|
}
|
|
@@ -10025,10 +10030,11 @@ class ConditionalCaseExpr extends ExpressionBase {
|
|
|
10025
10030
|
* @param expr The expression to be tested for this case. Might be null, as in an `else` case.
|
|
10026
10031
|
* @param target The Xref of the view to be displayed if this condition is true.
|
|
10027
10032
|
*/
|
|
10028
|
-
constructor(expr, target, alias = null) {
|
|
10033
|
+
constructor(expr, target, targetSlot, alias = null) {
|
|
10029
10034
|
super();
|
|
10030
10035
|
this.expr = expr;
|
|
10031
10036
|
this.target = target;
|
|
10037
|
+
this.targetSlot = targetSlot;
|
|
10032
10038
|
this.alias = alias;
|
|
10033
10039
|
this.kind = ExpressionKind.ConditionalCase;
|
|
10034
10040
|
}
|
|
@@ -10044,7 +10050,7 @@ class ConditionalCaseExpr extends ExpressionBase {
|
|
|
10044
10050
|
return true;
|
|
10045
10051
|
}
|
|
10046
10052
|
clone() {
|
|
10047
|
-
return new ConditionalCaseExpr(this.expr, this.target);
|
|
10053
|
+
return new ConditionalCaseExpr(this.expr, this.target, this.targetSlot);
|
|
10048
10054
|
}
|
|
10049
10055
|
transformInternalExpressions(transform, flags) {
|
|
10050
10056
|
if (this.expr !== null) {
|
|
@@ -10052,13 +10058,6 @@ class ConditionalCaseExpr extends ExpressionBase {
|
|
|
10052
10058
|
}
|
|
10053
10059
|
}
|
|
10054
10060
|
}
|
|
10055
|
-
var DerivedRepeaterVarIdentity;
|
|
10056
|
-
(function (DerivedRepeaterVarIdentity) {
|
|
10057
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["First"] = 0] = "First";
|
|
10058
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Last"] = 1] = "Last";
|
|
10059
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Even"] = 2] = "Even";
|
|
10060
|
-
DerivedRepeaterVarIdentity[DerivedRepeaterVarIdentity["Odd"] = 3] = "Odd";
|
|
10061
|
-
})(DerivedRepeaterVarIdentity || (DerivedRepeaterVarIdentity = {}));
|
|
10062
10061
|
class DerivedRepeaterVarExpr extends ExpressionBase {
|
|
10063
10062
|
constructor(xref, identity) {
|
|
10064
10063
|
super();
|
|
@@ -10079,6 +10078,31 @@ class DerivedRepeaterVarExpr extends ExpressionBase {
|
|
|
10079
10078
|
return new DerivedRepeaterVarExpr(this.xref, this.identity);
|
|
10080
10079
|
}
|
|
10081
10080
|
}
|
|
10081
|
+
class ConstCollectedExpr extends ExpressionBase {
|
|
10082
|
+
constructor(expr) {
|
|
10083
|
+
super();
|
|
10084
|
+
this.expr = expr;
|
|
10085
|
+
this.kind = ExpressionKind.ConstCollected;
|
|
10086
|
+
}
|
|
10087
|
+
transformInternalExpressions(transform, flags) {
|
|
10088
|
+
this.expr = transform(this.expr, flags);
|
|
10089
|
+
}
|
|
10090
|
+
visitExpression(visitor, context) {
|
|
10091
|
+
this.expr.visitExpression(visitor, context);
|
|
10092
|
+
}
|
|
10093
|
+
isEquivalent(e) {
|
|
10094
|
+
if (!(e instanceof ConstCollectedExpr)) {
|
|
10095
|
+
return false;
|
|
10096
|
+
}
|
|
10097
|
+
return this.expr.isEquivalent(e.expr);
|
|
10098
|
+
}
|
|
10099
|
+
isConstant() {
|
|
10100
|
+
return this.expr.isConstant();
|
|
10101
|
+
}
|
|
10102
|
+
clone() {
|
|
10103
|
+
return new ConstCollectedExpr(this.expr);
|
|
10104
|
+
}
|
|
10105
|
+
}
|
|
10082
10106
|
/**
|
|
10083
10107
|
* Visits all `Expression`s in the AST of `op` with the `visitor` function.
|
|
10084
10108
|
*/
|
|
@@ -10167,12 +10191,6 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10167
10191
|
op.expression =
|
|
10168
10192
|
op.expression && transformExpressionsInExpression(op.expression, transform, flags);
|
|
10169
10193
|
break;
|
|
10170
|
-
case OpKind.ExtractedMessage:
|
|
10171
|
-
op.expression = transformExpressionsInExpression(op.expression, transform, flags);
|
|
10172
|
-
for (const statement of op.statements) {
|
|
10173
|
-
transformExpressionsInStatement(statement, transform, flags);
|
|
10174
|
-
}
|
|
10175
|
-
break;
|
|
10176
10194
|
case OpKind.RepeaterCreate:
|
|
10177
10195
|
op.track = transformExpressionsInExpression(op.track, transform, flags);
|
|
10178
10196
|
if (op.trackByFn !== null) {
|
|
@@ -10182,34 +10200,38 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10182
10200
|
case OpKind.Repeater:
|
|
10183
10201
|
op.collection = transformExpressionsInExpression(op.collection, transform, flags);
|
|
10184
10202
|
break;
|
|
10185
|
-
case OpKind.
|
|
10186
|
-
|
|
10187
|
-
|
|
10188
|
-
|
|
10203
|
+
case OpKind.Defer:
|
|
10204
|
+
if (op.loadingConfig !== null) {
|
|
10205
|
+
op.loadingConfig = transformExpressionsInExpression(op.loadingConfig, transform, flags);
|
|
10206
|
+
}
|
|
10207
|
+
if (op.placeholderConfig !== null) {
|
|
10208
|
+
op.placeholderConfig =
|
|
10209
|
+
transformExpressionsInExpression(op.placeholderConfig, transform, flags);
|
|
10189
10210
|
}
|
|
10190
10211
|
break;
|
|
10191
|
-
case OpKind.
|
|
10192
|
-
case OpKind.DeferSecondaryBlock:
|
|
10193
|
-
case OpKind.DeferOn:
|
|
10194
|
-
case OpKind.Projection:
|
|
10195
|
-
case OpKind.ProjectionDef:
|
|
10196
|
-
case OpKind.Element:
|
|
10197
|
-
case OpKind.ElementStart:
|
|
10198
|
-
case OpKind.ElementEnd:
|
|
10199
|
-
case OpKind.I18nEnd:
|
|
10212
|
+
case OpKind.Advance:
|
|
10200
10213
|
case OpKind.Container:
|
|
10201
|
-
case OpKind.ContainerStart:
|
|
10202
10214
|
case OpKind.ContainerEnd:
|
|
10203
|
-
case OpKind.
|
|
10215
|
+
case OpKind.ContainerStart:
|
|
10216
|
+
case OpKind.DeferOn:
|
|
10204
10217
|
case OpKind.DisableBindings:
|
|
10218
|
+
case OpKind.Element:
|
|
10219
|
+
case OpKind.ElementEnd:
|
|
10220
|
+
case OpKind.ElementStart:
|
|
10205
10221
|
case OpKind.EnableBindings:
|
|
10206
|
-
case OpKind.
|
|
10207
|
-
case OpKind.
|
|
10208
|
-
case OpKind.Advance:
|
|
10209
|
-
case OpKind.Namespace:
|
|
10222
|
+
case OpKind.ExtractedMessage:
|
|
10223
|
+
case OpKind.I18n:
|
|
10210
10224
|
case OpKind.I18nApply:
|
|
10225
|
+
case OpKind.I18nEnd:
|
|
10226
|
+
case OpKind.I18nStart:
|
|
10211
10227
|
case OpKind.Icu:
|
|
10212
10228
|
case OpKind.IcuUpdate:
|
|
10229
|
+
case OpKind.Namespace:
|
|
10230
|
+
case OpKind.Pipe:
|
|
10231
|
+
case OpKind.Projection:
|
|
10232
|
+
case OpKind.ProjectionDef:
|
|
10233
|
+
case OpKind.Template:
|
|
10234
|
+
case OpKind.Text:
|
|
10213
10235
|
// These operations contain no expressions.
|
|
10214
10236
|
break;
|
|
10215
10237
|
default:
|
|
@@ -10581,6 +10603,12 @@ class OpList {
|
|
|
10581
10603
|
}
|
|
10582
10604
|
}
|
|
10583
10605
|
|
|
10606
|
+
class SlotHandle {
|
|
10607
|
+
constructor() {
|
|
10608
|
+
this.slot = null;
|
|
10609
|
+
}
|
|
10610
|
+
}
|
|
10611
|
+
|
|
10584
10612
|
/**
|
|
10585
10613
|
* The set of OpKinds that represent the creation of an element or container
|
|
10586
10614
|
*/
|
|
@@ -10602,6 +10630,7 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10602
10630
|
kind: OpKind.ElementStart,
|
|
10603
10631
|
xref,
|
|
10604
10632
|
tag,
|
|
10633
|
+
handle: new SlotHandle(),
|
|
10605
10634
|
attributes: null,
|
|
10606
10635
|
localRefs: [],
|
|
10607
10636
|
nonBindable: false,
|
|
@@ -10615,13 +10644,14 @@ function createElementStartOp(tag, xref, namespace, i18nPlaceholder, sourceSpan)
|
|
|
10615
10644
|
/**
|
|
10616
10645
|
* Create a `TemplateOp`.
|
|
10617
10646
|
*/
|
|
10618
|
-
function createTemplateOp(xref, tag,
|
|
10647
|
+
function createTemplateOp(xref, tag, functionNameSuffix, namespace, i18nPlaceholder, sourceSpan) {
|
|
10619
10648
|
return {
|
|
10620
10649
|
kind: OpKind.Template,
|
|
10621
10650
|
xref,
|
|
10622
10651
|
attributes: null,
|
|
10623
10652
|
tag,
|
|
10624
|
-
|
|
10653
|
+
handle: new SlotHandle(),
|
|
10654
|
+
functionNameSuffix,
|
|
10625
10655
|
decls: null,
|
|
10626
10656
|
vars: null,
|
|
10627
10657
|
localRefs: [],
|
|
@@ -10633,15 +10663,17 @@ function createTemplateOp(xref, tag, namespace, generatedInBlock, i18nPlaceholde
|
|
|
10633
10663
|
...NEW_OP,
|
|
10634
10664
|
};
|
|
10635
10665
|
}
|
|
10636
|
-
function createRepeaterCreateOp(primaryView, emptyView, track, varNames, sourceSpan) {
|
|
10666
|
+
function createRepeaterCreateOp(primaryView, emptyView, tag, track, varNames, sourceSpan) {
|
|
10637
10667
|
return {
|
|
10638
10668
|
kind: OpKind.RepeaterCreate,
|
|
10639
10669
|
attributes: null,
|
|
10640
10670
|
xref: primaryView,
|
|
10671
|
+
handle: new SlotHandle(),
|
|
10641
10672
|
emptyView,
|
|
10642
10673
|
track,
|
|
10643
10674
|
trackByFn: null,
|
|
10644
|
-
tag
|
|
10675
|
+
tag,
|
|
10676
|
+
functionNameSuffix: 'For',
|
|
10645
10677
|
namespace: Namespace.HTML,
|
|
10646
10678
|
nonBindable: false,
|
|
10647
10679
|
localRefs: [],
|
|
@@ -10687,6 +10719,7 @@ function createTextOp(xref, initialValue, sourceSpan) {
|
|
|
10687
10719
|
return {
|
|
10688
10720
|
kind: OpKind.Text,
|
|
10689
10721
|
xref,
|
|
10722
|
+
handle: new SlotHandle(),
|
|
10690
10723
|
initialValue,
|
|
10691
10724
|
sourceSpan,
|
|
10692
10725
|
...TRAIT_CONSUMES_SLOT,
|
|
@@ -10696,10 +10729,11 @@ function createTextOp(xref, initialValue, sourceSpan) {
|
|
|
10696
10729
|
/**
|
|
10697
10730
|
* Create a `ListenerOp`. Host bindings reuse all the listener logic.
|
|
10698
10731
|
*/
|
|
10699
|
-
function createListenerOp(target, name, tag, animationPhase, hostListener, sourceSpan) {
|
|
10732
|
+
function createListenerOp(target, targetSlot, name, tag, animationPhase, hostListener, sourceSpan) {
|
|
10700
10733
|
return {
|
|
10701
10734
|
kind: OpKind.Listener,
|
|
10702
10735
|
target,
|
|
10736
|
+
targetSlot,
|
|
10703
10737
|
tag,
|
|
10704
10738
|
hostListener,
|
|
10705
10739
|
name,
|
|
@@ -10710,27 +10744,18 @@ function createListenerOp(target, name, tag, animationPhase, hostListener, sourc
|
|
|
10710
10744
|
animationPhase: animationPhase,
|
|
10711
10745
|
sourceSpan,
|
|
10712
10746
|
...NEW_OP,
|
|
10713
|
-
...TRAIT_USES_SLOT_INDEX,
|
|
10714
10747
|
};
|
|
10715
10748
|
}
|
|
10716
|
-
function createPipeOp(xref, name) {
|
|
10749
|
+
function createPipeOp(xref, slot, name) {
|
|
10717
10750
|
return {
|
|
10718
10751
|
kind: OpKind.Pipe,
|
|
10719
10752
|
xref,
|
|
10753
|
+
handle: slot,
|
|
10720
10754
|
name,
|
|
10721
10755
|
...NEW_OP,
|
|
10722
10756
|
...TRAIT_CONSUMES_SLOT,
|
|
10723
10757
|
};
|
|
10724
10758
|
}
|
|
10725
|
-
/**
|
|
10726
|
-
* Whether the active namespace is HTML, MathML, or SVG mode.
|
|
10727
|
-
*/
|
|
10728
|
-
var Namespace;
|
|
10729
|
-
(function (Namespace) {
|
|
10730
|
-
Namespace[Namespace["HTML"] = 0] = "HTML";
|
|
10731
|
-
Namespace[Namespace["SVG"] = 1] = "SVG";
|
|
10732
|
-
Namespace[Namespace["Math"] = 2] = "Math";
|
|
10733
|
-
})(Namespace || (Namespace = {}));
|
|
10734
10759
|
function createNamespaceOp(namespace) {
|
|
10735
10760
|
return {
|
|
10736
10761
|
kind: OpKind.Namespace,
|
|
@@ -10749,6 +10774,7 @@ function createProjectionOp(xref, selector, sourceSpan) {
|
|
|
10749
10774
|
return {
|
|
10750
10775
|
kind: OpKind.Projection,
|
|
10751
10776
|
xref,
|
|
10777
|
+
handle: new SlotHandle(),
|
|
10752
10778
|
selector,
|
|
10753
10779
|
projectionSlotIndex: 0,
|
|
10754
10780
|
attributes: [],
|
|
@@ -10771,51 +10797,54 @@ function createExtractedAttributeOp(target, bindingKind, name, expression) {
|
|
|
10771
10797
|
...NEW_OP,
|
|
10772
10798
|
};
|
|
10773
10799
|
}
|
|
10774
|
-
function createDeferOp(xref, main, sourceSpan) {
|
|
10800
|
+
function createDeferOp(xref, main, mainSlot, sourceSpan) {
|
|
10775
10801
|
return {
|
|
10776
10802
|
kind: OpKind.Defer,
|
|
10777
10803
|
xref,
|
|
10778
|
-
|
|
10779
|
-
|
|
10780
|
-
|
|
10781
|
-
|
|
10804
|
+
handle: new SlotHandle(),
|
|
10805
|
+
mainView: main,
|
|
10806
|
+
mainSlot,
|
|
10807
|
+
loadingView: null,
|
|
10808
|
+
loadingSlot: null,
|
|
10809
|
+
loadingConfig: null,
|
|
10810
|
+
loadingMinimumTime: null,
|
|
10811
|
+
loadingAfterTime: null,
|
|
10812
|
+
placeholderView: null,
|
|
10813
|
+
placeholderSlot: null,
|
|
10814
|
+
placeholderConfig: null,
|
|
10815
|
+
placeholderMinimumTime: null,
|
|
10816
|
+
errorView: null,
|
|
10817
|
+
errorSlot: null,
|
|
10782
10818
|
sourceSpan,
|
|
10783
10819
|
...NEW_OP,
|
|
10784
10820
|
...TRAIT_CONSUMES_SLOT,
|
|
10785
|
-
|
|
10786
|
-
};
|
|
10787
|
-
}
|
|
10788
|
-
function createDeferSecondaryOp(deferOp, secondaryView, secondaryBlockKind) {
|
|
10789
|
-
return {
|
|
10790
|
-
kind: OpKind.DeferSecondaryBlock,
|
|
10791
|
-
deferOp,
|
|
10792
|
-
target: secondaryView,
|
|
10793
|
-
secondaryBlockKind,
|
|
10794
|
-
constValue: null,
|
|
10795
|
-
makeExpression: literalOrArrayLiteral$1,
|
|
10796
|
-
...NEW_OP,
|
|
10797
|
-
...TRAIT_USES_SLOT_INDEX,
|
|
10798
|
-
...TRAIT_HAS_CONST,
|
|
10821
|
+
numSlotsUsed: 2,
|
|
10799
10822
|
};
|
|
10800
10823
|
}
|
|
10801
|
-
function createDeferOnOp(
|
|
10824
|
+
function createDeferOnOp(defer, trigger, prefetch, sourceSpan) {
|
|
10802
10825
|
return {
|
|
10803
10826
|
kind: OpKind.DeferOn,
|
|
10804
|
-
|
|
10827
|
+
defer,
|
|
10828
|
+
trigger,
|
|
10829
|
+
prefetch,
|
|
10805
10830
|
sourceSpan,
|
|
10806
10831
|
...NEW_OP,
|
|
10807
|
-
...TRAIT_CONSUMES_SLOT,
|
|
10808
10832
|
};
|
|
10809
10833
|
}
|
|
10810
10834
|
/**
|
|
10811
10835
|
* Create an `ExtractedMessageOp`.
|
|
10812
10836
|
*/
|
|
10813
|
-
function createExtractedMessageOp(owner,
|
|
10837
|
+
function createExtractedMessageOp(owner, message, isRoot) {
|
|
10814
10838
|
return {
|
|
10815
10839
|
kind: OpKind.ExtractedMessage,
|
|
10816
10840
|
owner,
|
|
10817
|
-
|
|
10818
|
-
|
|
10841
|
+
message,
|
|
10842
|
+
isRoot,
|
|
10843
|
+
params: new Map(),
|
|
10844
|
+
postprocessingParams: new Map(),
|
|
10845
|
+
needsPostprocessing: false,
|
|
10846
|
+
formattedParams: null,
|
|
10847
|
+
formattedPostprocessingParams: null,
|
|
10819
10848
|
...NEW_OP,
|
|
10820
10849
|
};
|
|
10821
10850
|
}
|
|
@@ -10826,13 +10855,11 @@ function createI18nStartOp(xref, message, root) {
|
|
|
10826
10855
|
return {
|
|
10827
10856
|
kind: OpKind.I18nStart,
|
|
10828
10857
|
xref,
|
|
10858
|
+
handle: new SlotHandle(),
|
|
10829
10859
|
root: root ?? xref,
|
|
10830
10860
|
message,
|
|
10831
|
-
params: new Map(),
|
|
10832
|
-
postprocessingParams: new Map(),
|
|
10833
10861
|
messageIndex: null,
|
|
10834
10862
|
subTemplateIndex: null,
|
|
10835
|
-
needsPostprocessing: false,
|
|
10836
10863
|
...NEW_OP,
|
|
10837
10864
|
...TRAIT_CONSUMES_SLOT,
|
|
10838
10865
|
};
|
|
@@ -11069,9 +11096,10 @@ class HostBindingCompilationUnit extends CompilationUnit {
|
|
|
11069
11096
|
}
|
|
11070
11097
|
|
|
11071
11098
|
/**
|
|
11072
|
-
* Find any function calls to `$any`, excluding `this.$any`, and delete them
|
|
11099
|
+
* Find any function calls to `$any`, excluding `this.$any`, and delete them, since they have no
|
|
11100
|
+
* runtime effects.
|
|
11073
11101
|
*/
|
|
11074
|
-
function
|
|
11102
|
+
function deleteAnyCasts(job) {
|
|
11075
11103
|
for (const unit of job.units) {
|
|
11076
11104
|
for (const op of unit.ops()) {
|
|
11077
11105
|
transformExpressionsInOp(op, removeAnys, VisitorContextFlag.None);
|
|
@@ -11092,13 +11120,13 @@ function removeAnys(e) {
|
|
|
11092
11120
|
/**
|
|
11093
11121
|
* Adds apply operations after i18n expressions.
|
|
11094
11122
|
*/
|
|
11095
|
-
function
|
|
11123
|
+
function applyI18nExpressions(job) {
|
|
11096
11124
|
for (const unit of job.units) {
|
|
11097
11125
|
for (const op of unit.update) {
|
|
11098
11126
|
// Only add apply after expressions that are not followed by more expressions.
|
|
11099
11127
|
if (op.kind === OpKind.I18nExpression && needsApplication(op)) {
|
|
11100
11128
|
// TODO: what should be the source span for the apply op?
|
|
11101
|
-
OpList.insertAfter(createI18nApplyOp(op.owner, null), op);
|
|
11129
|
+
OpList.insertAfter(createI18nApplyOp(op.owner, op.ownerSlot, null), op);
|
|
11102
11130
|
}
|
|
11103
11131
|
}
|
|
11104
11132
|
}
|
|
@@ -11121,7 +11149,7 @@ function needsApplication(op) {
|
|
|
11121
11149
|
/**
|
|
11122
11150
|
* Updates i18n expression ops to depend on the last slot in their owning i18n block.
|
|
11123
11151
|
*/
|
|
11124
|
-
function
|
|
11152
|
+
function assignI18nSlotDependencies(job) {
|
|
11125
11153
|
const i18nLastSlotConsumers = new Map();
|
|
11126
11154
|
let lastSlotConsumer = null;
|
|
11127
11155
|
for (const unit of job.units) {
|
|
@@ -11143,29 +11171,6 @@ function phaseAssignI18nSlotDependencies(job) {
|
|
|
11143
11171
|
}
|
|
11144
11172
|
}
|
|
11145
11173
|
|
|
11146
|
-
/**
|
|
11147
|
-
* Attribute interpolations of the form `[attr.foo]="{{foo}}""` should be "collapsed" into a plain
|
|
11148
|
-
* attribute instruction, instead of an `attributeInterpolate` instruction.
|
|
11149
|
-
*
|
|
11150
|
-
* (We cannot do this for singleton property interpolations, because `propertyInterpolate`
|
|
11151
|
-
* stringifies its expression.)
|
|
11152
|
-
*
|
|
11153
|
-
* The reification step is also capable of performing this transformation, but doing it early in the
|
|
11154
|
-
* pipeline allows other phases to accurately know what instruction will be emitted.
|
|
11155
|
-
*/
|
|
11156
|
-
function phaseCollapseSingletonInterpolations(job) {
|
|
11157
|
-
for (const unit of job.units) {
|
|
11158
|
-
for (const op of unit.update) {
|
|
11159
|
-
const eligibleOpKind = op.kind === OpKind.Attribute;
|
|
11160
|
-
if (eligibleOpKind && op.expression instanceof Interpolation &&
|
|
11161
|
-
op.expression.strings.length === 2 &&
|
|
11162
|
-
op.expression.strings.every((s) => s === '')) {
|
|
11163
|
-
op.expression = op.expression.expressions[0];
|
|
11164
|
-
}
|
|
11165
|
-
}
|
|
11166
|
-
}
|
|
11167
|
-
}
|
|
11168
|
-
|
|
11169
11174
|
/**
|
|
11170
11175
|
* Gets a map of all elements in the given view by their xref id.
|
|
11171
11176
|
*/
|
|
@@ -11184,7 +11189,7 @@ function createOpXrefMap(unit) {
|
|
|
11184
11189
|
* Find all extractable attribute and binding ops, and create ExtractedAttributeOps for them.
|
|
11185
11190
|
* In cases where no instruction needs to be generated for the attribute or binding, it is removed.
|
|
11186
11191
|
*/
|
|
11187
|
-
function
|
|
11192
|
+
function extractAttributes(job) {
|
|
11188
11193
|
for (const unit of job.units) {
|
|
11189
11194
|
const elements = createOpXrefMap(unit);
|
|
11190
11195
|
for (const op of unit.ops()) {
|
|
@@ -11282,7 +11287,7 @@ function lookupElement$1(elements, xref) {
|
|
|
11282
11287
|
}
|
|
11283
11288
|
return el;
|
|
11284
11289
|
}
|
|
11285
|
-
function
|
|
11290
|
+
function specializeBindings(job) {
|
|
11286
11291
|
const elements = new Map();
|
|
11287
11292
|
for (const unit of job.units) {
|
|
11288
11293
|
for (const op of unit.create) {
|
|
@@ -11371,7 +11376,7 @@ const CHAINABLE = new Set([
|
|
|
11371
11376
|
* elementStart(0, 'div')(1, 'span');
|
|
11372
11377
|
* ```
|
|
11373
11378
|
*/
|
|
11374
|
-
function
|
|
11379
|
+
function chain(job) {
|
|
11375
11380
|
for (const unit of job.units) {
|
|
11376
11381
|
chainOperationsInList(unit.create);
|
|
11377
11382
|
chainOperationsInList(unit.update);
|
|
@@ -11418,9 +11423,32 @@ function chainOperationsInList(opList) {
|
|
|
11418
11423
|
}
|
|
11419
11424
|
|
|
11420
11425
|
/**
|
|
11421
|
-
*
|
|
11426
|
+
* Attribute interpolations of the form `[attr.foo]="{{foo}}""` should be "collapsed" into a plain
|
|
11427
|
+
* attribute instruction, instead of an `attributeInterpolate` instruction.
|
|
11428
|
+
*
|
|
11429
|
+
* (We cannot do this for singleton property interpolations, because `propertyInterpolate`
|
|
11430
|
+
* stringifies its expression.)
|
|
11431
|
+
*
|
|
11432
|
+
* The reification step is also capable of performing this transformation, but doing it early in the
|
|
11433
|
+
* pipeline allows other phases to accurately know what instruction will be emitted.
|
|
11434
|
+
*/
|
|
11435
|
+
function collapseSingletonInterpolations(job) {
|
|
11436
|
+
for (const unit of job.units) {
|
|
11437
|
+
for (const op of unit.update) {
|
|
11438
|
+
const eligibleOpKind = op.kind === OpKind.Attribute;
|
|
11439
|
+
if (eligibleOpKind && op.expression instanceof Interpolation &&
|
|
11440
|
+
op.expression.strings.length === 2 &&
|
|
11441
|
+
op.expression.strings.every((s) => s === '')) {
|
|
11442
|
+
op.expression = op.expression.expressions[0];
|
|
11443
|
+
}
|
|
11444
|
+
}
|
|
11445
|
+
}
|
|
11446
|
+
}
|
|
11447
|
+
|
|
11448
|
+
/**
|
|
11449
|
+
* Collapse the various conditions of conditional ops (if, switch) into a single test expression.
|
|
11422
11450
|
*/
|
|
11423
|
-
function
|
|
11451
|
+
function generateConditionalExpressions(job) {
|
|
11424
11452
|
for (const unit of job.units) {
|
|
11425
11453
|
for (const op of unit.ops()) {
|
|
11426
11454
|
if (op.kind !== OpKind.Conditional) {
|
|
@@ -11430,8 +11458,8 @@ function phaseConditionals(job) {
|
|
|
11430
11458
|
// Any case with a `null` condition is `default`. If one exists, default to it instead.
|
|
11431
11459
|
const defaultCase = op.conditions.findIndex((cond) => cond.expr === null);
|
|
11432
11460
|
if (defaultCase >= 0) {
|
|
11433
|
-
const
|
|
11434
|
-
test = new SlotLiteralExpr(
|
|
11461
|
+
const slot = op.conditions.splice(defaultCase, 1)[0].targetSlot;
|
|
11462
|
+
test = new SlotLiteralExpr(slot);
|
|
11435
11463
|
}
|
|
11436
11464
|
else {
|
|
11437
11465
|
// By default, a switch evaluates to `-1`, causing no template to be displayed.
|
|
@@ -11457,7 +11485,7 @@ function phaseConditionals(job) {
|
|
|
11457
11485
|
new AssignTemporaryExpr(conditionalCase.expr, caseExpressionTemporaryXref);
|
|
11458
11486
|
op.contextValue = new ReadTemporaryExpr(caseExpressionTemporaryXref);
|
|
11459
11487
|
}
|
|
11460
|
-
test = new ConditionalExpr(conditionalCase.expr, new SlotLiteralExpr(conditionalCase.
|
|
11488
|
+
test = new ConditionalExpr(conditionalCase.expr, new SlotLiteralExpr(conditionalCase.targetSlot), test);
|
|
11461
11489
|
}
|
|
11462
11490
|
// Save the resulting aggregate Joost-expression.
|
|
11463
11491
|
op.processed = test;
|
|
@@ -11548,14 +11576,14 @@ function literalOrArrayLiteral(value) {
|
|
|
11548
11576
|
if (Array.isArray(value)) {
|
|
11549
11577
|
return literalArr(value.map(literalOrArrayLiteral));
|
|
11550
11578
|
}
|
|
11551
|
-
return literal(value
|
|
11579
|
+
return literal(value);
|
|
11552
11580
|
}
|
|
11553
11581
|
|
|
11554
11582
|
/**
|
|
11555
11583
|
* Converts the semantic attributes of element-like operations (elements, templates) into constant
|
|
11556
11584
|
* array expressions, and lifts them into the overall component `consts`.
|
|
11557
11585
|
*/
|
|
11558
|
-
function
|
|
11586
|
+
function collectElementConsts(job) {
|
|
11559
11587
|
// Collect all extracted attributes.
|
|
11560
11588
|
const allElementAttributes = new Map();
|
|
11561
11589
|
for (const unit of job.units) {
|
|
@@ -11701,20 +11729,126 @@ function serializeAttributes({ attributes, bindings, classes, i18n, projectAs, s
|
|
|
11701
11729
|
return literalArr(attrArray);
|
|
11702
11730
|
}
|
|
11703
11731
|
|
|
11704
|
-
const REPLACEMENTS = new Map([
|
|
11705
|
-
[OpKind.ElementEnd, [OpKind.ElementStart, OpKind.Element]],
|
|
11706
|
-
[OpKind.ContainerEnd, [OpKind.ContainerStart, OpKind.Container]],
|
|
11707
|
-
[OpKind.I18nEnd, [OpKind.I18nStart, OpKind.I18n]],
|
|
11708
|
-
]);
|
|
11709
11732
|
/**
|
|
11710
|
-
*
|
|
11733
|
+
* Defer instructions take a configuration array, which should be collected into the component
|
|
11734
|
+
* consts. This phase finds the config options, and creates the corresponding const array.
|
|
11735
|
+
*/
|
|
11736
|
+
function configureDeferInstructions(job) {
|
|
11737
|
+
for (const unit of job.units) {
|
|
11738
|
+
for (const op of unit.create) {
|
|
11739
|
+
if (op.kind !== OpKind.Defer) {
|
|
11740
|
+
continue;
|
|
11741
|
+
}
|
|
11742
|
+
if (op.placeholderMinimumTime !== null) {
|
|
11743
|
+
op.placeholderConfig =
|
|
11744
|
+
new ConstCollectedExpr(literalOrArrayLiteral([op.placeholderMinimumTime]));
|
|
11745
|
+
}
|
|
11746
|
+
if (op.loadingMinimumTime !== null || op.loadingAfterTime !== null) {
|
|
11747
|
+
op.loadingConfig = new ConstCollectedExpr(literalOrArrayLiteral([op.loadingMinimumTime, op.loadingAfterTime]));
|
|
11748
|
+
}
|
|
11749
|
+
}
|
|
11750
|
+
}
|
|
11751
|
+
}
|
|
11752
|
+
|
|
11753
|
+
/**
|
|
11754
|
+
* Some `defer` conditions can reference other elements in the template, using their local reference
|
|
11755
|
+
* names. However, the semantics are quite different from the normal local reference system: in
|
|
11756
|
+
* particular, we need to look at local reference names in enclosing views. This phase resolves
|
|
11757
|
+
* all such references to actual xrefs.
|
|
11758
|
+
*/
|
|
11759
|
+
function resolveDeferTargetNames(job) {
|
|
11760
|
+
const scopes = new Map();
|
|
11761
|
+
function getScopeForView(view) {
|
|
11762
|
+
if (scopes.has(view.xref)) {
|
|
11763
|
+
return scopes.get(view.xref);
|
|
11764
|
+
}
|
|
11765
|
+
const scope = new Scope$1();
|
|
11766
|
+
for (const op of view.create) {
|
|
11767
|
+
// add everything that can be referenced.
|
|
11768
|
+
if (!isElementOrContainerOp(op) || op.localRefs === null) {
|
|
11769
|
+
continue;
|
|
11770
|
+
}
|
|
11771
|
+
if (!Array.isArray(op.localRefs)) {
|
|
11772
|
+
throw new Error('LocalRefs were already processed, but were needed to resolve defer targets.');
|
|
11773
|
+
}
|
|
11774
|
+
for (const ref of op.localRefs) {
|
|
11775
|
+
if (ref.target !== '') {
|
|
11776
|
+
continue;
|
|
11777
|
+
}
|
|
11778
|
+
scope.targets.set(ref.name, { xref: op.xref, slot: op.handle });
|
|
11779
|
+
}
|
|
11780
|
+
}
|
|
11781
|
+
scopes.set(view.xref, scope);
|
|
11782
|
+
return scope;
|
|
11783
|
+
}
|
|
11784
|
+
function resolveTrigger(deferOwnerView, op, placeholderView) {
|
|
11785
|
+
switch (op.trigger.kind) {
|
|
11786
|
+
case DeferTriggerKind.Idle:
|
|
11787
|
+
case DeferTriggerKind.Immediate:
|
|
11788
|
+
case DeferTriggerKind.Timer:
|
|
11789
|
+
return;
|
|
11790
|
+
case DeferTriggerKind.Hover:
|
|
11791
|
+
case DeferTriggerKind.Interaction:
|
|
11792
|
+
case DeferTriggerKind.Viewport:
|
|
11793
|
+
if (op.trigger.targetName === null) {
|
|
11794
|
+
return;
|
|
11795
|
+
}
|
|
11796
|
+
let view = placeholderView !== null ? job.views.get(placeholderView) : deferOwnerView;
|
|
11797
|
+
let step = placeholderView !== null ? -1 : 0;
|
|
11798
|
+
while (view !== null) {
|
|
11799
|
+
const scope = getScopeForView(view);
|
|
11800
|
+
if (scope.targets.has(op.trigger.targetName)) {
|
|
11801
|
+
const { xref, slot } = scope.targets.get(op.trigger.targetName);
|
|
11802
|
+
op.trigger.targetXref = xref;
|
|
11803
|
+
op.trigger.targetView = view.xref;
|
|
11804
|
+
op.trigger.targetSlotViewSteps = step;
|
|
11805
|
+
op.trigger.targetSlot = slot;
|
|
11806
|
+
return;
|
|
11807
|
+
}
|
|
11808
|
+
view = view.parent !== null ? job.views.get(view.parent) : null;
|
|
11809
|
+
step++;
|
|
11810
|
+
}
|
|
11811
|
+
break;
|
|
11812
|
+
default:
|
|
11813
|
+
throw new Error(`Trigger kind ${op.trigger.kind} not handled`);
|
|
11814
|
+
}
|
|
11815
|
+
}
|
|
11816
|
+
// Find the defer ops, and assign the data about their targets.
|
|
11817
|
+
for (const unit of job.units) {
|
|
11818
|
+
const defers = new Map();
|
|
11819
|
+
for (const op of unit.create) {
|
|
11820
|
+
switch (op.kind) {
|
|
11821
|
+
case OpKind.Defer:
|
|
11822
|
+
defers.set(op.xref, op);
|
|
11823
|
+
break;
|
|
11824
|
+
case OpKind.DeferOn:
|
|
11825
|
+
const deferOp = defers.get(op.defer);
|
|
11826
|
+
resolveTrigger(unit, op, deferOp.placeholderView);
|
|
11827
|
+
break;
|
|
11828
|
+
}
|
|
11829
|
+
}
|
|
11830
|
+
}
|
|
11831
|
+
}
|
|
11832
|
+
class Scope$1 {
|
|
11833
|
+
constructor() {
|
|
11834
|
+
this.targets = new Map();
|
|
11835
|
+
}
|
|
11836
|
+
}
|
|
11837
|
+
|
|
11838
|
+
const REPLACEMENTS = new Map([
|
|
11839
|
+
[OpKind.ElementEnd, [OpKind.ElementStart, OpKind.Element]],
|
|
11840
|
+
[OpKind.ContainerEnd, [OpKind.ContainerStart, OpKind.Container]],
|
|
11841
|
+
[OpKind.I18nEnd, [OpKind.I18nStart, OpKind.I18n]],
|
|
11842
|
+
]);
|
|
11843
|
+
/**
|
|
11844
|
+
* Op kinds that should not prevent merging of start/end ops.
|
|
11711
11845
|
*/
|
|
11712
11846
|
const IGNORED_OP_KINDS = new Set([OpKind.Pipe]);
|
|
11713
11847
|
/**
|
|
11714
|
-
* Replace sequences of mergable
|
|
11715
|
-
*
|
|
11848
|
+
* Replace sequences of mergable instructions (e.g. `ElementStart` and `ElementEnd`) with a
|
|
11849
|
+
* consolidated instruction (e.g. `Element`).
|
|
11716
11850
|
*/
|
|
11717
|
-
function
|
|
11851
|
+
function collapseEmptyInstructions(job) {
|
|
11718
11852
|
for (const unit of job.units) {
|
|
11719
11853
|
for (const op of unit.create) {
|
|
11720
11854
|
// Find end ops that may be able to be merged.
|
|
@@ -11741,10 +11875,13 @@ function phaseEmptyElements(job) {
|
|
|
11741
11875
|
}
|
|
11742
11876
|
|
|
11743
11877
|
/**
|
|
11744
|
-
*
|
|
11745
|
-
*
|
|
11878
|
+
* Safe read expressions such as `a?.b` have different semantics in Angular templates as
|
|
11879
|
+
* compared to JavaScript. In particular, they default to `null` instead of `undefined`. This phase
|
|
11880
|
+
* finds all unresolved safe read expressions, and converts them into the appropriate output AST
|
|
11881
|
+
* reads, guarded by null checks. We generate temporaries as needed, to avoid re-evaluating the same
|
|
11882
|
+
* sub-expression multiple times.
|
|
11746
11883
|
*/
|
|
11747
|
-
function
|
|
11884
|
+
function expandSafeReads(job) {
|
|
11748
11885
|
for (const unit of job.units) {
|
|
11749
11886
|
for (const op of unit.ops()) {
|
|
11750
11887
|
transformExpressionsInOp(op, e => safeTransform(e, { job }), VisitorContextFlag.None);
|
|
@@ -11915,42 +12052,116 @@ function ternaryTransform(e) {
|
|
|
11915
12052
|
return new ConditionalExpr(new BinaryOperatorExpr(BinaryOperator.Equals, e.guard, NULL_EXPR), NULL_EXPR, e.expr);
|
|
11916
12053
|
}
|
|
11917
12054
|
|
|
11918
|
-
|
|
11919
|
-
|
|
12055
|
+
/**
|
|
12056
|
+
* The escape sequence used indicate message param values.
|
|
12057
|
+
*/
|
|
12058
|
+
const ESCAPE = '\uFFFD';
|
|
12059
|
+
/**
|
|
12060
|
+
* Marker used to indicate an element tag.
|
|
12061
|
+
*/
|
|
12062
|
+
const ELEMENT_MARKER = '#';
|
|
12063
|
+
/**
|
|
12064
|
+
* Marker used to indicate a template tag.
|
|
12065
|
+
*/
|
|
12066
|
+
const TEMPLATE_MARKER = '*';
|
|
12067
|
+
/**
|
|
12068
|
+
* Marker used to indicate closing of an element or template tag.
|
|
12069
|
+
*/
|
|
12070
|
+
const TAG_CLOSE_MARKER = '/';
|
|
12071
|
+
/**
|
|
12072
|
+
* Marker used to indicate the sub-template context.
|
|
12073
|
+
*/
|
|
12074
|
+
const CONTEXT_MARKER = ':';
|
|
12075
|
+
/**
|
|
12076
|
+
* Marker used to indicate the start of a list of values.
|
|
12077
|
+
*/
|
|
12078
|
+
const LIST_START_MARKER = '[';
|
|
12079
|
+
/**
|
|
12080
|
+
* Marker used to indicate the end of a list of values.
|
|
12081
|
+
*/
|
|
12082
|
+
const LIST_END_MARKER = ']';
|
|
12083
|
+
/**
|
|
12084
|
+
* Delimiter used to separate multiple values in a list.
|
|
12085
|
+
*/
|
|
12086
|
+
const LIST_DELIMITER = '|';
|
|
12087
|
+
/**
|
|
12088
|
+
* Formats the param maps on extracted message ops into a maps of `Expression` objects that can be
|
|
12089
|
+
* used in the final output.
|
|
12090
|
+
*/
|
|
12091
|
+
function formatI18nParams(job) {
|
|
11920
12092
|
for (const unit of job.units) {
|
|
11921
|
-
for (const op of unit.
|
|
11922
|
-
if (op.kind === OpKind.
|
|
11923
|
-
|
|
12093
|
+
for (const op of unit.create) {
|
|
12094
|
+
if (op.kind === OpKind.ExtractedMessage) {
|
|
12095
|
+
if (op.isRoot) {
|
|
12096
|
+
op.formattedParams = formatParams(op.params);
|
|
12097
|
+
op.formattedPostprocessingParams = formatParams(op.postprocessingParams);
|
|
12098
|
+
// The message will need post-processing if there are any post-processing params, or if
|
|
12099
|
+
// there are any normal params that have multiple values
|
|
12100
|
+
op.needsPostprocessing = op.postprocessingParams.size > 0;
|
|
12101
|
+
for (const [param, values] of op.params) {
|
|
12102
|
+
if (values.length > 1) {
|
|
12103
|
+
op.needsPostprocessing = true;
|
|
12104
|
+
}
|
|
12105
|
+
}
|
|
12106
|
+
}
|
|
11924
12107
|
}
|
|
11925
12108
|
}
|
|
11926
12109
|
}
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
case DerivedRepeaterVarIdentity.Last:
|
|
11938
|
-
return new BinaryOperatorExpr(BinaryOperator.Identical, new LexicalReadExpr(repeaterOp.varNames.$index), new BinaryOperatorExpr(BinaryOperator.Minus, new LexicalReadExpr(repeaterOp.varNames.$count), literal(1)));
|
|
11939
|
-
case DerivedRepeaterVarIdentity.Even:
|
|
11940
|
-
return new BinaryOperatorExpr(BinaryOperator.Identical, new BinaryOperatorExpr(BinaryOperator.Modulo, new LexicalReadExpr(repeaterOp.varNames.$index), literal(2)), literal(0));
|
|
11941
|
-
case DerivedRepeaterVarIdentity.Odd:
|
|
11942
|
-
return new BinaryOperatorExpr(BinaryOperator.NotIdentical, new BinaryOperatorExpr(BinaryOperator.Modulo, new LexicalReadExpr(repeaterOp.varNames.$index), literal(2)), literal(0));
|
|
11943
|
-
}
|
|
11944
|
-
}, VisitorContextFlag.None);
|
|
12110
|
+
}
|
|
12111
|
+
/**
|
|
12112
|
+
* Formats a map of `I18nParamValue[]` values into a map of `Expression` values.
|
|
12113
|
+
*/
|
|
12114
|
+
function formatParams(params) {
|
|
12115
|
+
const result = new Map();
|
|
12116
|
+
for (const [placeholder, placeholderValues] of [...params].sort()) {
|
|
12117
|
+
const serializedValues = formatParamValues(placeholderValues);
|
|
12118
|
+
if (serializedValues !== null) {
|
|
12119
|
+
result.set(placeholder, literal(formatParamValues(placeholderValues)));
|
|
11945
12120
|
}
|
|
11946
12121
|
}
|
|
12122
|
+
return result;
|
|
12123
|
+
}
|
|
12124
|
+
/**
|
|
12125
|
+
* Formats an `I18nParamValue[]` into a string (or null for empty array).
|
|
12126
|
+
*/
|
|
12127
|
+
function formatParamValues(values) {
|
|
12128
|
+
if (values.length === 0) {
|
|
12129
|
+
return null;
|
|
12130
|
+
}
|
|
12131
|
+
const serializedValues = values.map(value => formatValue(value));
|
|
12132
|
+
return serializedValues.length === 1 ?
|
|
12133
|
+
serializedValues[0] :
|
|
12134
|
+
`${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`;
|
|
12135
|
+
}
|
|
12136
|
+
/**
|
|
12137
|
+
* Formats a single `I18nParamValue` into a string
|
|
12138
|
+
*/
|
|
12139
|
+
function formatValue(value) {
|
|
12140
|
+
let tagMarker = '';
|
|
12141
|
+
let closeMarker = '';
|
|
12142
|
+
if (value.flags & I18nParamValueFlags.ElementTag) {
|
|
12143
|
+
tagMarker = ELEMENT_MARKER;
|
|
12144
|
+
}
|
|
12145
|
+
else if (value.flags & I18nParamValueFlags.TemplateTag) {
|
|
12146
|
+
tagMarker = TEMPLATE_MARKER;
|
|
12147
|
+
}
|
|
12148
|
+
if (tagMarker !== '') {
|
|
12149
|
+
closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
|
|
12150
|
+
}
|
|
12151
|
+
const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
|
|
12152
|
+
// Self-closing tags use a special form that concatenates the start and close tag values.
|
|
12153
|
+
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
12154
|
+
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
12155
|
+
return `${ESCAPE}${tagMarker}${value.value}${context}${ESCAPE}${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
12156
|
+
}
|
|
12157
|
+
return `${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
11947
12158
|
}
|
|
11948
12159
|
|
|
11949
12160
|
/**
|
|
11950
12161
|
* Generate `ir.AdvanceOp`s in between `ir.UpdateOp`s that ensure the runtime's implicit slot
|
|
11951
12162
|
* context will be advanced correctly.
|
|
11952
12163
|
*/
|
|
11953
|
-
function
|
|
12164
|
+
function generateAdvance(job) {
|
|
11954
12165
|
for (const unit of job.units) {
|
|
11955
12166
|
// First build a map of all of the declarations in the view that have assigned slots.
|
|
11956
12167
|
const slotMap = new Map();
|
|
@@ -11958,10 +12169,10 @@ function phaseGenerateAdvance(job) {
|
|
|
11958
12169
|
if (!hasConsumesSlotTrait(op)) {
|
|
11959
12170
|
continue;
|
|
11960
12171
|
}
|
|
11961
|
-
else if (op.slot === null) {
|
|
12172
|
+
else if (op.handle.slot === null) {
|
|
11962
12173
|
throw new Error(`AssertionError: expected slots to have been allocated before generating advance() calls`);
|
|
11963
12174
|
}
|
|
11964
|
-
slotMap.set(op.xref, op.slot);
|
|
12175
|
+
slotMap.set(op.xref, op.handle.slot);
|
|
11965
12176
|
}
|
|
11966
12177
|
// Next, step through the update operations and generate `ir.AdvanceOp`s as required to ensure
|
|
11967
12178
|
// the runtime's implicit slot counter will be set to the correct slot before executing each
|
|
@@ -11999,7 +12210,7 @@ function phaseGenerateAdvance(job) {
|
|
|
11999
12210
|
* populate `project` arguments, and generate the required `projectionDef` instruction for the job's
|
|
12000
12211
|
* root view.
|
|
12001
12212
|
*/
|
|
12002
|
-
function
|
|
12213
|
+
function generateProjectionDefs(job) {
|
|
12003
12214
|
// TODO: Why does TemplateDefinitionBuilder force a shared constant?
|
|
12004
12215
|
const share = job.compatibility === CompatibilityMode.TemplateDefinitionBuilder;
|
|
12005
12216
|
// Collect all selectors from this component, and its nested views. Also, assign each projection a
|
|
@@ -12044,7 +12255,7 @@ function phaseGenerateProjectionDef(job) {
|
|
|
12044
12255
|
* Variables are generated here unconditionally, and may optimized away in future operations if it
|
|
12045
12256
|
* turns out their values (and any side effects) are unused.
|
|
12046
12257
|
*/
|
|
12047
|
-
function
|
|
12258
|
+
function generateVariables(job) {
|
|
12048
12259
|
recursivelyProcessView(job.root, /* there is no parent scope for the root view */ null);
|
|
12049
12260
|
}
|
|
12050
12261
|
/**
|
|
@@ -12110,6 +12321,7 @@ function getScopeForView(view, parent) {
|
|
|
12110
12321
|
scope.references.push({
|
|
12111
12322
|
name: op.localRefs[offset].name,
|
|
12112
12323
|
targetId: op.xref,
|
|
12324
|
+
targetSlot: op.handle,
|
|
12113
12325
|
offset,
|
|
12114
12326
|
variable: {
|
|
12115
12327
|
kind: SemanticVariableKind.Identifier,
|
|
@@ -12151,7 +12363,7 @@ function generateVariablesInScopeForView(view, scope) {
|
|
|
12151
12363
|
}
|
|
12152
12364
|
// Add variables for all local references declared for elements in this scope.
|
|
12153
12365
|
for (const ref of scope.references) {
|
|
12154
|
-
newOps.push(createVariableOp(view.job.allocateXrefId(), ref.variable, new ReferenceExpr(ref.targetId, ref.offset), VariableFlags.None));
|
|
12366
|
+
newOps.push(createVariableOp(view.job.allocateXrefId(), ref.variable, new ReferenceExpr(ref.targetId, ref.targetSlot, ref.offset), VariableFlags.None));
|
|
12155
12367
|
}
|
|
12156
12368
|
if (scope.parent !== null) {
|
|
12157
12369
|
// Recursively add variables from the parent scope.
|
|
@@ -12161,27 +12373,20 @@ function generateVariablesInScopeForView(view, scope) {
|
|
|
12161
12373
|
}
|
|
12162
12374
|
|
|
12163
12375
|
/**
|
|
12164
|
-
*
|
|
12165
|
-
*
|
|
12166
|
-
*
|
|
12376
|
+
* `ir.ConstCollectedExpr` may be present in any IR expression. This means that expression needs to
|
|
12377
|
+
* be lifted into the component const array, and replaced with a reference to the const array at its
|
|
12378
|
+
*
|
|
12379
|
+
* usage site. This phase walks the IR and performs this transformation.
|
|
12167
12380
|
*/
|
|
12168
|
-
function
|
|
12169
|
-
const collectGlobalConsts = (e) => {
|
|
12170
|
-
if (e instanceof ExpressionBase && hasConstTrait(e)) {
|
|
12171
|
-
// TODO: Figure out how to make this type narrowing work.
|
|
12172
|
-
const ea = e;
|
|
12173
|
-
if (ea.constValue !== null) {
|
|
12174
|
-
ea.constIndex = job.addConst(ea.constValue);
|
|
12175
|
-
}
|
|
12176
|
-
}
|
|
12177
|
-
return e;
|
|
12178
|
-
};
|
|
12381
|
+
function collectConstExpressions(job) {
|
|
12179
12382
|
for (const unit of job.units) {
|
|
12180
12383
|
for (const op of unit.ops()) {
|
|
12181
|
-
|
|
12182
|
-
|
|
12183
|
-
|
|
12184
|
-
|
|
12384
|
+
transformExpressionsInOp(op, expr => {
|
|
12385
|
+
if (!(expr instanceof ConstCollectedExpr)) {
|
|
12386
|
+
return expr;
|
|
12387
|
+
}
|
|
12388
|
+
return literal(job.addConst(expr.expr));
|
|
12389
|
+
}, VisitorContextFlag.None);
|
|
12185
12390
|
}
|
|
12186
12391
|
}
|
|
12187
12392
|
}
|
|
@@ -12191,7 +12396,13 @@ const CLASS_DOT = 'class.';
|
|
|
12191
12396
|
const STYLE_BANG = 'style!';
|
|
12192
12397
|
const CLASS_BANG = 'class!';
|
|
12193
12398
|
const BANG_IMPORTANT = '!important';
|
|
12194
|
-
|
|
12399
|
+
/**
|
|
12400
|
+
* Host bindings are compiled using a different parser entrypoint, and are parsed quite differently
|
|
12401
|
+
* as a result. Therefore, we need to do some extra parsing for host style properties, as compared
|
|
12402
|
+
* to non-host style properties.
|
|
12403
|
+
* TODO: Unify host bindings and non-host bindings in the parser.
|
|
12404
|
+
*/
|
|
12405
|
+
function parseHostStyleProperties(job) {
|
|
12195
12406
|
for (const op of job.root.update) {
|
|
12196
12407
|
if (op.kind !== OpKind.Binding) {
|
|
12197
12408
|
continue;
|
|
@@ -12253,31 +12464,6 @@ function parseProperty$1(name) {
|
|
|
12253
12464
|
return { property, suffix };
|
|
12254
12465
|
}
|
|
12255
12466
|
|
|
12256
|
-
/**
|
|
12257
|
-
* Lifts i18n properties into the consts array.
|
|
12258
|
-
*/
|
|
12259
|
-
function phaseI18nConstCollection(job) {
|
|
12260
|
-
// Serialize the extracted messages into the const array.
|
|
12261
|
-
// TODO: Use `Map` instead of object.
|
|
12262
|
-
const messageConstIndices = {};
|
|
12263
|
-
for (const unit of job.units) {
|
|
12264
|
-
for (const op of unit.create) {
|
|
12265
|
-
if (op.kind === OpKind.ExtractedMessage) {
|
|
12266
|
-
messageConstIndices[op.owner] = job.addConst(op.expression, op.statements);
|
|
12267
|
-
OpList.remove(op);
|
|
12268
|
-
}
|
|
12269
|
-
}
|
|
12270
|
-
}
|
|
12271
|
-
// Assign const index to i18n ops that messages were extracted from.
|
|
12272
|
-
for (const unit of job.units) {
|
|
12273
|
-
for (const op of unit.create) {
|
|
12274
|
-
if (op.kind === OpKind.I18nStart) {
|
|
12275
|
-
op.messageIndex = messageConstIndices[op.root];
|
|
12276
|
-
}
|
|
12277
|
-
}
|
|
12278
|
-
}
|
|
12279
|
-
}
|
|
12280
|
-
|
|
12281
12467
|
function mapEntry(key, value) {
|
|
12282
12468
|
return { key, value, quoted: false };
|
|
12283
12469
|
}
|
|
@@ -19155,16 +19341,19 @@ const NG_I18N_CLOSURE_MODE$1 = 'ngI18nClosureMode';
|
|
|
19155
19341
|
* considers variables like `I18N_0` as constants and throws an error when their value changes.
|
|
19156
19342
|
*/
|
|
19157
19343
|
const TRANSLATION_VAR_PREFIX = 'i18n_';
|
|
19158
|
-
/**
|
|
19159
|
-
|
|
19344
|
+
/**
|
|
19345
|
+
* Lifts i18n properties into the consts array.
|
|
19346
|
+
* TODO: Can we use `ConstCollectedExpr`?
|
|
19347
|
+
*/
|
|
19348
|
+
function collectI18nConsts(job) {
|
|
19160
19349
|
const fileBasedI18nSuffix = job.relativeContextFilePath.replace(/[^A-Za-z0-9]/g, '_').toUpperCase() + '_';
|
|
19350
|
+
const messageConstIndices = new Map();
|
|
19161
19351
|
for (const unit of job.units) {
|
|
19162
19352
|
for (const op of unit.create) {
|
|
19163
|
-
if (op.kind === OpKind.
|
|
19164
|
-
//
|
|
19165
|
-
if (op.
|
|
19166
|
-
|
|
19167
|
-
const params = new Map([...op.params.entries()].sort());
|
|
19353
|
+
if (op.kind === OpKind.ExtractedMessage) {
|
|
19354
|
+
// Serialize the extracted root messages into the const array.
|
|
19355
|
+
if (op.isRoot) {
|
|
19356
|
+
assertAllParamsResolved(op);
|
|
19168
19357
|
const mainVar = variable(job.pool.uniqueName(TRANSLATION_VAR_PREFIX));
|
|
19169
19358
|
// Closure Compiler requires const names to start with `MSG_` but disallows any other
|
|
19170
19359
|
// const to start with `MSG_`. We define a variable starting with `MSG_` just for the
|
|
@@ -19175,14 +19364,24 @@ function phaseI18nMessageExtraction(job) {
|
|
|
19175
19364
|
// set in post-processing.
|
|
19176
19365
|
if (op.needsPostprocessing) {
|
|
19177
19366
|
const extraTransformFnParams = [];
|
|
19178
|
-
if (op.
|
|
19179
|
-
extraTransformFnParams.push(literalMap([...op.
|
|
19367
|
+
if (op.formattedPostprocessingParams.size > 0) {
|
|
19368
|
+
extraTransformFnParams.push(literalMap([...op.formattedPostprocessingParams].map(([key, value]) => ({ key, value, quoted: true }))));
|
|
19180
19369
|
}
|
|
19181
19370
|
transformFn = (expr) => importExpr(Identifiers.i18nPostprocess).callFn([expr, ...extraTransformFnParams]);
|
|
19182
19371
|
}
|
|
19183
|
-
const statements = getTranslationDeclStmts$1(op.message, mainVar, closureVar,
|
|
19184
|
-
|
|
19372
|
+
const statements = getTranslationDeclStmts$1(op.message, mainVar, closureVar, op.formattedParams, transformFn);
|
|
19373
|
+
messageConstIndices.set(op.owner, job.addConst(mainVar, statements));
|
|
19185
19374
|
}
|
|
19375
|
+
// Remove the extracted messages from the IR now that they have been collected.
|
|
19376
|
+
OpList.remove(op);
|
|
19377
|
+
}
|
|
19378
|
+
}
|
|
19379
|
+
}
|
|
19380
|
+
// Assign const index to i18n ops that messages were extracted from.
|
|
19381
|
+
for (const unit of job.units) {
|
|
19382
|
+
for (const op of unit.create) {
|
|
19383
|
+
if (op.kind === OpKind.I18nStart) {
|
|
19384
|
+
op.messageIndex = messageConstIndices.get(op.root);
|
|
19186
19385
|
}
|
|
19187
19386
|
}
|
|
19188
19387
|
}
|
|
@@ -19254,27 +19453,63 @@ function i18nGenerateClosureVar(pool, messageId, fileBasedI18nSuffix, useExterna
|
|
|
19254
19453
|
}
|
|
19255
19454
|
return variable(name);
|
|
19256
19455
|
}
|
|
19456
|
+
/**
|
|
19457
|
+
* Asserts that all of the message's placeholders have values.
|
|
19458
|
+
*/
|
|
19459
|
+
function assertAllParamsResolved(op) {
|
|
19460
|
+
if (op.formattedParams === null || op.formattedPostprocessingParams === null) {
|
|
19461
|
+
throw Error('Params should have been formatted.');
|
|
19462
|
+
}
|
|
19463
|
+
for (const placeholder in op.message.placeholders) {
|
|
19464
|
+
if (!op.formattedParams.has(placeholder) &&
|
|
19465
|
+
!op.formattedPostprocessingParams.has(placeholder)) {
|
|
19466
|
+
throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
|
|
19467
|
+
}
|
|
19468
|
+
}
|
|
19469
|
+
for (const placeholder in op.message.placeholderToMessage) {
|
|
19470
|
+
if (!op.formattedParams.has(placeholder) &&
|
|
19471
|
+
!op.formattedPostprocessingParams.has(placeholder)) {
|
|
19472
|
+
throw Error(`Failed to resolve i18n message placeholder: ${placeholder}`);
|
|
19473
|
+
}
|
|
19474
|
+
}
|
|
19475
|
+
}
|
|
19476
|
+
|
|
19477
|
+
/**
|
|
19478
|
+
* Extracts i18n messages into their own op.
|
|
19479
|
+
*/
|
|
19480
|
+
function extractI18nMessages(job) {
|
|
19481
|
+
for (const unit of job.units) {
|
|
19482
|
+
for (const op of unit.create) {
|
|
19483
|
+
if (op.kind === OpKind.I18nStart) {
|
|
19484
|
+
unit.create.push(createExtractedMessageOp(op.xref, op.message, op.xref === op.root));
|
|
19485
|
+
}
|
|
19486
|
+
}
|
|
19487
|
+
}
|
|
19488
|
+
}
|
|
19257
19489
|
|
|
19258
19490
|
/**
|
|
19259
19491
|
* Removes text nodes within i18n blocks since they are already hardcoded into the i18n message.
|
|
19260
19492
|
*/
|
|
19261
|
-
function
|
|
19493
|
+
function extractI18nText(job) {
|
|
19262
19494
|
for (const unit of job.units) {
|
|
19263
19495
|
// Remove all text nodes within i18n blocks, their content is already captured in the i18n
|
|
19264
19496
|
// message.
|
|
19265
19497
|
let currentI18nId = null;
|
|
19498
|
+
let currentI18nSlot = null;
|
|
19266
19499
|
const textNodes = new Map();
|
|
19267
19500
|
for (const op of unit.create) {
|
|
19268
19501
|
switch (op.kind) {
|
|
19269
19502
|
case OpKind.I18nStart:
|
|
19270
19503
|
currentI18nId = op.xref;
|
|
19504
|
+
currentI18nSlot = op.handle;
|
|
19271
19505
|
break;
|
|
19272
19506
|
case OpKind.I18nEnd:
|
|
19273
19507
|
currentI18nId = null;
|
|
19508
|
+
currentI18nSlot = null;
|
|
19274
19509
|
break;
|
|
19275
19510
|
case OpKind.Text:
|
|
19276
|
-
if (currentI18nId !== null) {
|
|
19277
|
-
textNodes.set(op.xref, currentI18nId);
|
|
19511
|
+
if (currentI18nId !== null && currentI18nSlot !== null) {
|
|
19512
|
+
textNodes.set(op.xref, { xref: currentI18nId, slot: currentI18nSlot });
|
|
19278
19513
|
OpList.remove(op);
|
|
19279
19514
|
}
|
|
19280
19515
|
break;
|
|
@@ -19288,12 +19523,12 @@ function phaseI18nTextExtraction(job) {
|
|
|
19288
19523
|
if (!textNodes.has(op.target)) {
|
|
19289
19524
|
continue;
|
|
19290
19525
|
}
|
|
19291
|
-
const
|
|
19526
|
+
const i18nBlock = textNodes.get(op.target);
|
|
19292
19527
|
const ops = [];
|
|
19293
19528
|
for (let i = 0; i < op.interpolation.expressions.length; i++) {
|
|
19294
19529
|
const expr = op.interpolation.expressions[i];
|
|
19295
19530
|
const placeholder = op.i18nPlaceholders[i];
|
|
19296
|
-
ops.push(createI18nExpressionOp(
|
|
19531
|
+
ops.push(createI18nExpressionOp(i18nBlock.xref, i18nBlock.slot, expr, placeholder.name, I18nParamResolutionTime.Creation, expr.sourceSpan ?? op.sourceSpan));
|
|
19297
19532
|
}
|
|
19298
19533
|
if (ops.length > 0) {
|
|
19299
19534
|
// ops.push(ir.createI18nApplyOp(i18nBlockId, op.i18nPlaceholders, op.sourceSpan));
|
|
@@ -19308,24 +19543,27 @@ function phaseI18nTextExtraction(job) {
|
|
|
19308
19543
|
/**
|
|
19309
19544
|
* Extracts ICUs into i18n expressions.
|
|
19310
19545
|
*/
|
|
19311
|
-
function
|
|
19546
|
+
function extractI18nICUs(job) {
|
|
19312
19547
|
for (const unit of job.units) {
|
|
19313
19548
|
// Build a map of ICU to the i18n block they belong to, then remove the `Icu` ops.
|
|
19314
19549
|
const icus = new Map();
|
|
19315
19550
|
let currentI18nId = null;
|
|
19551
|
+
let currentI18nSlot = null;
|
|
19316
19552
|
for (const op of unit.create) {
|
|
19317
19553
|
switch (op.kind) {
|
|
19318
19554
|
case OpKind.I18nStart:
|
|
19319
19555
|
currentI18nId = op.xref;
|
|
19556
|
+
currentI18nSlot = op.handle;
|
|
19320
19557
|
break;
|
|
19321
19558
|
case OpKind.I18nEnd:
|
|
19322
19559
|
currentI18nId = null;
|
|
19560
|
+
currentI18nSlot = null;
|
|
19323
19561
|
break;
|
|
19324
19562
|
case OpKind.Icu:
|
|
19325
19563
|
if (currentI18nId === null) {
|
|
19326
19564
|
throw Error('Unexpected ICU outside of an i18n block.');
|
|
19327
19565
|
}
|
|
19328
|
-
icus.set(op.xref, { message: op.message, i18nBlockId: currentI18nId });
|
|
19566
|
+
icus.set(op.xref, { message: op.message, i18nBlockId: currentI18nId, i18nBlockSlot: currentI18nSlot });
|
|
19329
19567
|
OpList.remove(op);
|
|
19330
19568
|
break;
|
|
19331
19569
|
}
|
|
@@ -19334,7 +19572,7 @@ function phaseIcuExtraction(job) {
|
|
|
19334
19572
|
for (const op of unit.update) {
|
|
19335
19573
|
switch (op.kind) {
|
|
19336
19574
|
case OpKind.IcuUpdate:
|
|
19337
|
-
const { message, i18nBlockId } = icus.get(op.xref);
|
|
19575
|
+
const { message, i18nBlockId, i18nBlockSlot } = icus.get(op.xref);
|
|
19338
19576
|
const icuNode = message.nodes.find((n) => n instanceof Icu);
|
|
19339
19577
|
if (icuNode === undefined) {
|
|
19340
19578
|
throw Error('Could not find ICU in i18n AST');
|
|
@@ -19342,7 +19580,7 @@ function phaseIcuExtraction(job) {
|
|
|
19342
19580
|
if (icuNode.expressionPlaceholder === undefined) {
|
|
19343
19581
|
throw Error('ICU is missing an i18n placeholder');
|
|
19344
19582
|
}
|
|
19345
|
-
OpList.replace(op, createI18nExpressionOp(i18nBlockId, new LexicalReadExpr(icuNode.expression), icuNode.expressionPlaceholder, I18nParamResolutionTime.Postproccessing, null));
|
|
19583
|
+
OpList.replace(op, createI18nExpressionOp(i18nBlockId, i18nBlockSlot, new LexicalReadExpr(icuNode.expression), icuNode.expressionPlaceholder, I18nParamResolutionTime.Postproccessing, null));
|
|
19346
19584
|
break;
|
|
19347
19585
|
}
|
|
19348
19586
|
}
|
|
@@ -19353,7 +19591,7 @@ function phaseIcuExtraction(job) {
|
|
|
19353
19591
|
* Lifts local reference declarations on element-like structures within each view into an entry in
|
|
19354
19592
|
* the `consts` array for the whole component.
|
|
19355
19593
|
*/
|
|
19356
|
-
function
|
|
19594
|
+
function liftLocalRefs(job) {
|
|
19357
19595
|
for (const unit of job.units) {
|
|
19358
19596
|
for (const op of unit.create) {
|
|
19359
19597
|
switch (op.kind) {
|
|
@@ -19386,7 +19624,7 @@ function serializeLocalRefs(refs) {
|
|
|
19386
19624
|
/**
|
|
19387
19625
|
* Change namespaces between HTML, SVG and MathML, depending on the next element.
|
|
19388
19626
|
*/
|
|
19389
|
-
function
|
|
19627
|
+
function emitNamespaceChanges(job) {
|
|
19390
19628
|
for (const unit of job.units) {
|
|
19391
19629
|
let activeNamespace = Namespace.HTML;
|
|
19392
19630
|
for (const op of unit.create) {
|
|
@@ -19486,8 +19724,8 @@ function hyphenate(value) {
|
|
|
19486
19724
|
* This includes propagating those names into any `ir.ReadVariableExpr`s of those variables, so that
|
|
19487
19725
|
* the reads can be emitted correctly.
|
|
19488
19726
|
*/
|
|
19489
|
-
function
|
|
19490
|
-
addNamesToView(
|
|
19727
|
+
function nameFunctionsAndVariables(job) {
|
|
19728
|
+
addNamesToView(job.root, job.componentName, { index: 0 }, job.compatibility === CompatibilityMode.TemplateDefinitionBuilder);
|
|
19491
19729
|
}
|
|
19492
19730
|
function addNamesToView(unit, baseName, state, compatibility) {
|
|
19493
19731
|
if (unit.fnName === null) {
|
|
@@ -19508,7 +19746,7 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
19508
19746
|
if (op.handlerFnName !== null) {
|
|
19509
19747
|
break;
|
|
19510
19748
|
}
|
|
19511
|
-
if (!op.hostListener && op.targetSlot === null) {
|
|
19749
|
+
if (!op.hostListener && op.targetSlot.slot === null) {
|
|
19512
19750
|
throw new Error(`Expected a slot to be assigned`);
|
|
19513
19751
|
}
|
|
19514
19752
|
let animation = '';
|
|
@@ -19520,7 +19758,7 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
19520
19758
|
op.handlerFnName = `${baseName}_${animation}${op.name}_HostBindingHandler`;
|
|
19521
19759
|
}
|
|
19522
19760
|
else {
|
|
19523
|
-
op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animation}${op.name}_${op.targetSlot}_listener`;
|
|
19761
|
+
op.handlerFnName = `${unit.fnName}_${op.tag.replace('-', '_')}_${animation}${op.name}_${op.targetSlot.slot}_listener`;
|
|
19524
19762
|
}
|
|
19525
19763
|
op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
|
|
19526
19764
|
break;
|
|
@@ -19531,28 +19769,27 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
19531
19769
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
19532
19770
|
throw new Error(`AssertionError: must be compiling a component`);
|
|
19533
19771
|
}
|
|
19534
|
-
if (op.slot === null) {
|
|
19772
|
+
if (op.handle.slot === null) {
|
|
19535
19773
|
throw new Error(`Expected slot to be assigned`);
|
|
19536
19774
|
}
|
|
19537
19775
|
if (op.emptyView !== null) {
|
|
19538
19776
|
const emptyView = unit.job.views.get(op.emptyView);
|
|
19539
19777
|
// Repeater empty view function is at slot +2 (metadata is in the first slot).
|
|
19540
|
-
addNamesToView(emptyView, `${baseName}_${
|
|
19778
|
+
addNamesToView(emptyView, `${baseName}_${`${op.functionNameSuffix}Empty`}_${op.handle.slot + 2}`, state, compatibility);
|
|
19541
19779
|
}
|
|
19542
|
-
const repeaterToken = op.tag === null ? '' : '_' + prefixWithNamespace(op.tag, op.namespace);
|
|
19543
19780
|
// Repeater primary view function is at slot +1 (metadata is in the first slot).
|
|
19544
|
-
addNamesToView(unit.job.views.get(op.xref), `${baseName}${
|
|
19781
|
+
addNamesToView(unit.job.views.get(op.xref), `${baseName}_${op.functionNameSuffix}_${op.handle.slot + 1}`, state, compatibility);
|
|
19545
19782
|
break;
|
|
19546
19783
|
case OpKind.Template:
|
|
19547
19784
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
19548
19785
|
throw new Error(`AssertionError: must be compiling a component`);
|
|
19549
19786
|
}
|
|
19550
19787
|
const childView = unit.job.views.get(op.xref);
|
|
19551
|
-
if (op.slot === null) {
|
|
19788
|
+
if (op.handle.slot === null) {
|
|
19552
19789
|
throw new Error(`Expected slot to be assigned`);
|
|
19553
19790
|
}
|
|
19554
|
-
const
|
|
19555
|
-
addNamesToView(childView, `${baseName}${
|
|
19791
|
+
const suffix = op.functionNameSuffix.length === 0 ? '' : `_${op.functionNameSuffix}`;
|
|
19792
|
+
addNamesToView(childView, `${baseName}${suffix}_${op.handle.slot}`, state, compatibility);
|
|
19556
19793
|
break;
|
|
19557
19794
|
case OpKind.StyleProp:
|
|
19558
19795
|
op.name = normalizeStylePropName(op.name);
|
|
@@ -19628,7 +19865,7 @@ function stripImportant(name) {
|
|
|
19628
19865
|
* is, the call is purely side-effectful).
|
|
19629
19866
|
* * No operations in between them uses the implicit context.
|
|
19630
19867
|
*/
|
|
19631
|
-
function
|
|
19868
|
+
function mergeNextContextExpressions(job) {
|
|
19632
19869
|
for (const unit of job.units) {
|
|
19633
19870
|
for (const op of unit.create) {
|
|
19634
19871
|
if (op.kind === OpKind.Listener) {
|
|
@@ -19684,7 +19921,7 @@ const CONTAINER_TAG = 'ng-container';
|
|
|
19684
19921
|
/**
|
|
19685
19922
|
* Replace an `Element` or `ElementStart` whose tag is `ng-container` with a specific op.
|
|
19686
19923
|
*/
|
|
19687
|
-
function
|
|
19924
|
+
function generateNgContainerOps(job) {
|
|
19688
19925
|
for (const unit of job.units) {
|
|
19689
19926
|
const updatedElementXrefs = new Set();
|
|
19690
19927
|
for (const op of unit.create) {
|
|
@@ -19716,7 +19953,7 @@ function lookupElement(elements, xref) {
|
|
|
19716
19953
|
* all descendants of that container. Therefore, we must emit `disableBindings` and `enableBindings`
|
|
19717
19954
|
* instructions for every such container.
|
|
19718
19955
|
*/
|
|
19719
|
-
function
|
|
19956
|
+
function disableBindings$1(job) {
|
|
19720
19957
|
const elements = new Map();
|
|
19721
19958
|
for (const view of job.units) {
|
|
19722
19959
|
for (const op of view.create) {
|
|
@@ -19740,7 +19977,13 @@ function phaseNonbindable(job) {
|
|
|
19740
19977
|
}
|
|
19741
19978
|
}
|
|
19742
19979
|
|
|
19743
|
-
|
|
19980
|
+
/**
|
|
19981
|
+
* Nullish coalescing expressions such as `a ?? b` have different semantics in Angular templates as
|
|
19982
|
+
* compared to JavaScript. In particular, they default to `null` instead of `undefined`. Therefore,
|
|
19983
|
+
* we replace them with ternary expressions, assigning temporaries as needed to avoid re-evaluating
|
|
19984
|
+
* the same sub-expression multiple times.
|
|
19985
|
+
*/
|
|
19986
|
+
function generateNullishCoalesceExpressions(job) {
|
|
19744
19987
|
for (const unit of job.units) {
|
|
19745
19988
|
for (const op of unit.ops()) {
|
|
19746
19989
|
transformExpressionsInOp(op, expr => {
|
|
@@ -19798,7 +20041,12 @@ const handledOpKinds = new Set([
|
|
|
19798
20041
|
OpKind.Listener, OpKind.StyleMap, OpKind.ClassMap, OpKind.StyleProp,
|
|
19799
20042
|
OpKind.ClassProp, OpKind.Property, OpKind.HostProperty, OpKind.Attribute
|
|
19800
20043
|
]);
|
|
19801
|
-
|
|
20044
|
+
/**
|
|
20045
|
+
* Many type of operations have ordering constraints that must be respected. For example, a
|
|
20046
|
+
* `ClassMap` instruction must be ordered after a `StyleMap` instruction, in order to have
|
|
20047
|
+
* predictable semantics that match TemplateDefinitionBuilder and don't break applications.
|
|
20048
|
+
*/
|
|
20049
|
+
function orderOps(job) {
|
|
19802
20050
|
for (const unit of job.units) {
|
|
19803
20051
|
// First, we pull out ops that need to be ordered. Then, when we encounter an op that shouldn't
|
|
19804
20052
|
// be reordered, put the ones we've pulled so far back in the correct order. Finally, if we
|
|
@@ -19860,8 +20108,8 @@ function keepLast(ops) {
|
|
|
19860
20108
|
* Parses extracted style and class attributes into separate ExtractedAttributeOps per style or
|
|
19861
20109
|
* class property.
|
|
19862
20110
|
*/
|
|
19863
|
-
function
|
|
19864
|
-
for (const unit of
|
|
20111
|
+
function parseExtractedStyles(job) {
|
|
20112
|
+
for (const unit of job.units) {
|
|
19865
20113
|
for (const op of unit.create) {
|
|
19866
20114
|
if (op.kind === OpKind.ExtractedAttribute && op.bindingKind === BindingKind.Attribute &&
|
|
19867
20115
|
isStringLiteral(op.expression)) {
|
|
@@ -19888,7 +20136,7 @@ function phaseParseExtractedStyles(cpl) {
|
|
|
19888
20136
|
* Attributes of `ng-content` named 'select' are specifically removed, because they control which
|
|
19889
20137
|
* content matches as a property of the `projection`, and are not a plain attribute.
|
|
19890
20138
|
*/
|
|
19891
|
-
function
|
|
20139
|
+
function removeContentSelectors(job) {
|
|
19892
20140
|
for (const unit of job.units) {
|
|
19893
20141
|
const elements = createOpXrefMap(unit);
|
|
19894
20142
|
for (const op of unit.update) {
|
|
@@ -19914,7 +20162,14 @@ function lookupInXrefMap(map, xref) {
|
|
|
19914
20162
|
return el;
|
|
19915
20163
|
}
|
|
19916
20164
|
|
|
19917
|
-
|
|
20165
|
+
/**
|
|
20166
|
+
* This phase generates pipe creation instructions. We do this based on the pipe bindings found in
|
|
20167
|
+
* the update block, in the order we see them.
|
|
20168
|
+
*
|
|
20169
|
+
* When not in compatibility mode, we can simply group all these creation instructions together, to
|
|
20170
|
+
* maximize chaining opportunities.
|
|
20171
|
+
*/
|
|
20172
|
+
function createPipes(job) {
|
|
19918
20173
|
for (const unit of job.units) {
|
|
19919
20174
|
processPipeBindingsInView(unit);
|
|
19920
20175
|
}
|
|
@@ -19931,21 +20186,19 @@ function processPipeBindingsInView(unit) {
|
|
|
19931
20186
|
if (flags & VisitorContextFlag.InChildOperation) {
|
|
19932
20187
|
throw new Error(`AssertionError: pipe bindings should not appear in child expressions`);
|
|
19933
20188
|
}
|
|
19934
|
-
// This update op must be associated with a create op that consumes a slot (either by
|
|
19935
|
-
// depending on the ambient context of `target`, or merely referencing that create op via
|
|
19936
|
-
// `target`).
|
|
19937
|
-
if (!hasDependsOnSlotContextTrait(updateOp) &&
|
|
19938
|
-
!hasUsesSlotIndexTrait(updateOp)) {
|
|
19939
|
-
throw new Error(`AssertionError: pipe binding associated with non-slot operation ${OpKind[updateOp.kind]}`);
|
|
19940
|
-
}
|
|
19941
20189
|
if (unit.job.compatibility) {
|
|
20190
|
+
// TODO: We can delete this cast and check once compatibility mode is removed.
|
|
20191
|
+
const slotHandle = updateOp.target;
|
|
20192
|
+
if (slotHandle == undefined) {
|
|
20193
|
+
throw new Error(`AssertionError: expected slot handle to be assigned for pipe creation`);
|
|
20194
|
+
}
|
|
19942
20195
|
addPipeToCreationBlock(unit, updateOp.target, expr);
|
|
19943
20196
|
}
|
|
19944
20197
|
else {
|
|
19945
20198
|
// When not in compatibility mode, we just add the pipe to the end of the create block. This
|
|
19946
20199
|
// is not only simpler and faster, but allows more chaining opportunities for other
|
|
19947
20200
|
// instructions.
|
|
19948
|
-
unit.create.push(createPipeOp(expr.target, expr.name));
|
|
20201
|
+
unit.create.push(createPipeOp(expr.target, expr.targetSlot, expr.name));
|
|
19949
20202
|
}
|
|
19950
20203
|
});
|
|
19951
20204
|
}
|
|
@@ -19966,7 +20219,7 @@ function addPipeToCreationBlock(unit, afterTargetXref, binding) {
|
|
|
19966
20219
|
while (op.next.kind === OpKind.Pipe) {
|
|
19967
20220
|
op = op.next;
|
|
19968
20221
|
}
|
|
19969
|
-
const pipe = createPipeOp(binding.target, binding.name);
|
|
20222
|
+
const pipe = createPipeOp(binding.target, binding.targetSlot, binding.name);
|
|
19970
20223
|
OpList.insertBefore(pipe, op.next);
|
|
19971
20224
|
// This completes adding the pipe to the creation block.
|
|
19972
20225
|
return;
|
|
@@ -19975,7 +20228,11 @@ function addPipeToCreationBlock(unit, afterTargetXref, binding) {
|
|
|
19975
20228
|
throw new Error(`AssertionError: unable to find insertion point for pipe ${binding.name}`);
|
|
19976
20229
|
}
|
|
19977
20230
|
|
|
19978
|
-
|
|
20231
|
+
/**
|
|
20232
|
+
* Pipes that accept more than 4 arguments are variadic, and are handled with a different runtime
|
|
20233
|
+
* instruction.
|
|
20234
|
+
*/
|
|
20235
|
+
function createVariadicPipes(job) {
|
|
19979
20236
|
for (const unit of job.units) {
|
|
19980
20237
|
for (const op of unit.update) {
|
|
19981
20238
|
transformExpressionsInOp(op, expr => {
|
|
@@ -19986,7 +20243,7 @@ function phasePipeVariadic(job) {
|
|
|
19986
20243
|
if (expr.args.length <= 4) {
|
|
19987
20244
|
return expr;
|
|
19988
20245
|
}
|
|
19989
|
-
return new PipeBindingVariadicExpr(expr.target, expr.name, literalArr(expr.args), expr.args.length);
|
|
20246
|
+
return new PipeBindingVariadicExpr(expr.target, expr.targetSlot, expr.name, literalArr(expr.args), expr.args.length);
|
|
19990
20247
|
}, VisitorContextFlag.None);
|
|
19991
20248
|
}
|
|
19992
20249
|
}
|
|
@@ -19996,7 +20253,7 @@ function phasePipeVariadic(job) {
|
|
|
19996
20253
|
* Propagate i18n blocks down through child templates that act as placeholders in the root i18n
|
|
19997
20254
|
* message.
|
|
19998
20255
|
*/
|
|
19999
|
-
function
|
|
20256
|
+
function propagateI18nBlocks(job) {
|
|
20000
20257
|
propagateI18nBlocksToTemplates(job.root, 0);
|
|
20001
20258
|
}
|
|
20002
20259
|
/**
|
|
@@ -20041,7 +20298,60 @@ function wrapTemplateWithI18n(unit, parentI18n) {
|
|
|
20041
20298
|
}
|
|
20042
20299
|
}
|
|
20043
20300
|
|
|
20044
|
-
|
|
20301
|
+
/**
|
|
20302
|
+
* Propagate extractd message placeholders up to their root extracted message op.
|
|
20303
|
+
*/
|
|
20304
|
+
function propogateI18nPlaceholders(job) {
|
|
20305
|
+
// Record all of the i18n and extracted message ops for use later.
|
|
20306
|
+
const i18nOps = new Map();
|
|
20307
|
+
const extractedMessageOps = new Map();
|
|
20308
|
+
for (const unit of job.units) {
|
|
20309
|
+
for (const op of unit.create) {
|
|
20310
|
+
switch (op.kind) {
|
|
20311
|
+
case OpKind.I18nStart:
|
|
20312
|
+
i18nOps.set(op.xref, op);
|
|
20313
|
+
break;
|
|
20314
|
+
case OpKind.ExtractedMessage:
|
|
20315
|
+
extractedMessageOps.set(op.owner, op);
|
|
20316
|
+
break;
|
|
20317
|
+
}
|
|
20318
|
+
}
|
|
20319
|
+
}
|
|
20320
|
+
// For each non-root message, merge its params into the root message's params.
|
|
20321
|
+
for (const [xref, childExtractedMessageOp] of extractedMessageOps) {
|
|
20322
|
+
if (!childExtractedMessageOp.isRoot) {
|
|
20323
|
+
const i18nOp = i18nOps.get(xref);
|
|
20324
|
+
if (i18nOp === undefined) {
|
|
20325
|
+
throw Error('Could not find owner i18n block for extracted message.');
|
|
20326
|
+
}
|
|
20327
|
+
const rootExtractedMessageOp = extractedMessageOps.get(i18nOp.root);
|
|
20328
|
+
if (rootExtractedMessageOp === undefined) {
|
|
20329
|
+
throw Error('Could not find extracted message op for root i18n block.');
|
|
20330
|
+
}
|
|
20331
|
+
mergeParams(rootExtractedMessageOp.params, childExtractedMessageOp.params);
|
|
20332
|
+
mergeParams(rootExtractedMessageOp.postprocessingParams, childExtractedMessageOp.postprocessingParams);
|
|
20333
|
+
}
|
|
20334
|
+
}
|
|
20335
|
+
}
|
|
20336
|
+
/**
|
|
20337
|
+
* Merges the params in the `from` map to into the `to` map.
|
|
20338
|
+
*/
|
|
20339
|
+
function mergeParams(to, from) {
|
|
20340
|
+
for (const [placeholder, fromValues] of from) {
|
|
20341
|
+
const toValues = to.get(placeholder) || [];
|
|
20342
|
+
// TODO(mmalerba): Child element close tag params should be prepended to maintain the same order
|
|
20343
|
+
// as TemplateDefinitionBuilder. Can be cleaned up when compatibility is no longer required.
|
|
20344
|
+
const flags = fromValues[0].flags;
|
|
20345
|
+
if ((flags & I18nParamValueFlags.CloseTag) && !(flags & I18nParamValueFlags.OpenTag)) {
|
|
20346
|
+
to.set(placeholder, [...fromValues, ...toValues]);
|
|
20347
|
+
}
|
|
20348
|
+
else {
|
|
20349
|
+
to.set(placeholder, [...toValues, ...fromValues]);
|
|
20350
|
+
}
|
|
20351
|
+
}
|
|
20352
|
+
}
|
|
20353
|
+
|
|
20354
|
+
function extractPureFunctions(job) {
|
|
20045
20355
|
for (const view of job.units) {
|
|
20046
20356
|
for (const op of view.ops()) {
|
|
20047
20357
|
visitExpressionsInOp(op, expr => {
|
|
@@ -20086,9 +20396,9 @@ class PureFunctionConstant extends GenericKeyFn {
|
|
|
20086
20396
|
}
|
|
20087
20397
|
}
|
|
20088
20398
|
|
|
20089
|
-
function
|
|
20090
|
-
for (const
|
|
20091
|
-
for (const op of
|
|
20399
|
+
function generatePureLiteralStructures(job) {
|
|
20400
|
+
for (const unit of job.units) {
|
|
20401
|
+
for (const op of unit.update) {
|
|
20092
20402
|
transformExpressionsInOp(op, (expr, flags) => {
|
|
20093
20403
|
if (flags & VisitorContextFlag.InChildOperation) {
|
|
20094
20404
|
return expr;
|
|
@@ -20246,7 +20556,7 @@ function text(slot, initialValue, sourceSpan) {
|
|
|
20246
20556
|
}
|
|
20247
20557
|
return call(Identifiers.text, args, sourceSpan);
|
|
20248
20558
|
}
|
|
20249
|
-
function defer(selfSlot, primarySlot, dependencyResolverFn, loadingSlot, placeholderSlot, errorSlot,
|
|
20559
|
+
function defer(selfSlot, primarySlot, dependencyResolverFn, loadingSlot, placeholderSlot, errorSlot, loadingConfig, placeholderConfig, enableTimerScheduling, sourceSpan) {
|
|
20250
20560
|
const args = [
|
|
20251
20561
|
literal(selfSlot),
|
|
20252
20562
|
literal(primarySlot),
|
|
@@ -20254,16 +20564,40 @@ function defer(selfSlot, primarySlot, dependencyResolverFn, loadingSlot, placeho
|
|
|
20254
20564
|
literal(loadingSlot),
|
|
20255
20565
|
literal(placeholderSlot),
|
|
20256
20566
|
literal(errorSlot),
|
|
20257
|
-
literal(
|
|
20258
|
-
literal(
|
|
20567
|
+
loadingConfig ?? literal(null),
|
|
20568
|
+
placeholderConfig ?? literal(null),
|
|
20569
|
+
enableTimerScheduling ? importExpr(Identifiers.deferEnableTimerScheduling) : literal(null),
|
|
20259
20570
|
];
|
|
20260
|
-
|
|
20571
|
+
let expr;
|
|
20572
|
+
while ((expr = args[args.length - 1]) !== null && expr instanceof LiteralExpr &&
|
|
20573
|
+
expr.value === null) {
|
|
20261
20574
|
args.pop();
|
|
20262
20575
|
}
|
|
20263
20576
|
return call(Identifiers.defer, args, sourceSpan);
|
|
20264
20577
|
}
|
|
20265
|
-
|
|
20266
|
-
|
|
20578
|
+
const deferTriggerToR3TriggerInstructionsMap = new Map([
|
|
20579
|
+
[DeferTriggerKind.Idle, [Identifiers.deferOnIdle, Identifiers.deferPrefetchOnIdle]],
|
|
20580
|
+
[
|
|
20581
|
+
DeferTriggerKind.Immediate,
|
|
20582
|
+
[Identifiers.deferOnImmediate, Identifiers.deferPrefetchOnImmediate]
|
|
20583
|
+
],
|
|
20584
|
+
[DeferTriggerKind.Timer, [Identifiers.deferOnTimer, Identifiers.deferPrefetchOnTimer]],
|
|
20585
|
+
[DeferTriggerKind.Hover, [Identifiers.deferOnHover, Identifiers.deferPrefetchOnHover]],
|
|
20586
|
+
[
|
|
20587
|
+
DeferTriggerKind.Interaction,
|
|
20588
|
+
[Identifiers.deferOnInteraction, Identifiers.deferPrefetchOnInteraction]
|
|
20589
|
+
],
|
|
20590
|
+
[
|
|
20591
|
+
DeferTriggerKind.Viewport, [Identifiers.deferOnViewport, Identifiers.deferPrefetchOnViewport]
|
|
20592
|
+
],
|
|
20593
|
+
]);
|
|
20594
|
+
function deferOn(trigger, args, prefetch, sourceSpan) {
|
|
20595
|
+
const instructions = deferTriggerToR3TriggerInstructionsMap.get(trigger);
|
|
20596
|
+
if (instructions === undefined) {
|
|
20597
|
+
throw new Error(`Unable to determine instruction for trigger ${trigger}`);
|
|
20598
|
+
}
|
|
20599
|
+
const instructionToCall = prefetch ? instructions[1] : instructions[0];
|
|
20600
|
+
return call(instructionToCall, args.map(a => literal(a)), sourceSpan);
|
|
20267
20601
|
}
|
|
20268
20602
|
function projectionDef(def) {
|
|
20269
20603
|
return call(Identifiers.projectionDef, def ? [def] : [], null);
|
|
@@ -20285,20 +20619,20 @@ function i18nStart(slot, constIndex, subTemplateIndex) {
|
|
|
20285
20619
|
}
|
|
20286
20620
|
return call(Identifiers.i18nStart, args, null);
|
|
20287
20621
|
}
|
|
20288
|
-
function repeaterCreate(slot, viewFnName, decls, vars, trackByFn, trackByUsesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, sourceSpan) {
|
|
20289
|
-
|
|
20622
|
+
function repeaterCreate(slot, viewFnName, decls, vars, tag, constIndex, trackByFn, trackByUsesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, sourceSpan) {
|
|
20623
|
+
const args = [
|
|
20290
20624
|
literal(slot),
|
|
20291
20625
|
variable(viewFnName),
|
|
20292
20626
|
literal(decls),
|
|
20293
20627
|
literal(vars),
|
|
20628
|
+
literal(tag),
|
|
20629
|
+
literal(constIndex),
|
|
20294
20630
|
trackByFn,
|
|
20295
20631
|
];
|
|
20296
20632
|
if (trackByUsesComponentInstance || emptyViewFnName !== null) {
|
|
20297
20633
|
args.push(literal(trackByUsesComponentInstance));
|
|
20298
20634
|
if (emptyViewFnName !== null) {
|
|
20299
|
-
args.push(variable(emptyViewFnName));
|
|
20300
|
-
args.push(literal(emptyDecls));
|
|
20301
|
-
args.push(literal(emptyVars));
|
|
20635
|
+
args.push(variable(emptyViewFnName), literal(emptyDecls), literal(emptyVars));
|
|
20302
20636
|
}
|
|
20303
20637
|
}
|
|
20304
20638
|
return call(Identifiers.repeaterCreate, args, sourceSpan);
|
|
@@ -20662,8 +20996,8 @@ const sanitizerIdentifierMap = new Map([
|
|
|
20662
20996
|
* structures. After reification, the create/update operation lists of all views should only contain
|
|
20663
20997
|
* `ir.StatementOp`s (which wrap generated `o.Statement`s).
|
|
20664
20998
|
*/
|
|
20665
|
-
function
|
|
20666
|
-
for (const unit of
|
|
20999
|
+
function reify(job) {
|
|
21000
|
+
for (const unit of job.units) {
|
|
20667
21001
|
reifyCreateOperations(unit, unit.create);
|
|
20668
21002
|
reifyUpdateOperations(unit, unit.update);
|
|
20669
21003
|
}
|
|
@@ -20673,41 +21007,41 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20673
21007
|
transformExpressionsInOp(op, reifyIrExpression, VisitorContextFlag.None);
|
|
20674
21008
|
switch (op.kind) {
|
|
20675
21009
|
case OpKind.Text:
|
|
20676
|
-
OpList.replace(op, text(op.slot, op.initialValue, op.sourceSpan));
|
|
21010
|
+
OpList.replace(op, text(op.handle.slot, op.initialValue, op.sourceSpan));
|
|
20677
21011
|
break;
|
|
20678
21012
|
case OpKind.ElementStart:
|
|
20679
|
-
OpList.replace(op, elementStart(op.slot, op.tag, op.attributes, op.localRefs, op.sourceSpan));
|
|
21013
|
+
OpList.replace(op, elementStart(op.handle.slot, op.tag, op.attributes, op.localRefs, op.sourceSpan));
|
|
20680
21014
|
break;
|
|
20681
21015
|
case OpKind.Element:
|
|
20682
|
-
OpList.replace(op, element(op.slot, op.tag, op.attributes, op.localRefs, op.sourceSpan));
|
|
21016
|
+
OpList.replace(op, element(op.handle.slot, op.tag, op.attributes, op.localRefs, op.sourceSpan));
|
|
20683
21017
|
break;
|
|
20684
21018
|
case OpKind.ElementEnd:
|
|
20685
21019
|
OpList.replace(op, elementEnd(op.sourceSpan));
|
|
20686
21020
|
break;
|
|
20687
21021
|
case OpKind.ContainerStart:
|
|
20688
|
-
OpList.replace(op, elementContainerStart(op.slot, op.attributes, op.localRefs, op.sourceSpan));
|
|
21022
|
+
OpList.replace(op, elementContainerStart(op.handle.slot, op.attributes, op.localRefs, op.sourceSpan));
|
|
20689
21023
|
break;
|
|
20690
21024
|
case OpKind.Container:
|
|
20691
|
-
OpList.replace(op, elementContainer(op.slot, op.attributes, op.localRefs, op.sourceSpan));
|
|
21025
|
+
OpList.replace(op, elementContainer(op.handle.slot, op.attributes, op.localRefs, op.sourceSpan));
|
|
20692
21026
|
break;
|
|
20693
21027
|
case OpKind.ContainerEnd:
|
|
20694
21028
|
OpList.replace(op, elementContainerEnd());
|
|
20695
21029
|
break;
|
|
20696
21030
|
case OpKind.I18nStart:
|
|
20697
|
-
OpList.replace(op, i18nStart(op.slot, op.messageIndex, op.subTemplateIndex));
|
|
21031
|
+
OpList.replace(op, i18nStart(op.handle.slot, op.messageIndex, op.subTemplateIndex));
|
|
20698
21032
|
break;
|
|
20699
21033
|
case OpKind.I18nEnd:
|
|
20700
21034
|
OpList.replace(op, i18nEnd());
|
|
20701
21035
|
break;
|
|
20702
21036
|
case OpKind.I18n:
|
|
20703
|
-
OpList.replace(op, i18n(op.slot, op.messageIndex, op.subTemplateIndex));
|
|
21037
|
+
OpList.replace(op, i18n(op.handle.slot, op.messageIndex, op.subTemplateIndex));
|
|
20704
21038
|
break;
|
|
20705
21039
|
case OpKind.Template:
|
|
20706
21040
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
20707
21041
|
throw new Error(`AssertionError: must be compiling a component`);
|
|
20708
21042
|
}
|
|
20709
21043
|
const childView = unit.job.views.get(op.xref);
|
|
20710
|
-
OpList.replace(op, template(op.slot, variable(childView.fnName), childView.decls, childView.vars, op.
|
|
21044
|
+
OpList.replace(op, template(op.handle.slot, variable(childView.fnName), childView.decls, childView.vars, op.tag, op.attributes, op.sourceSpan));
|
|
20711
21045
|
break;
|
|
20712
21046
|
case OpKind.DisableBindings:
|
|
20713
21047
|
OpList.replace(op, disableBindings());
|
|
@@ -20716,7 +21050,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20716
21050
|
OpList.replace(op, enableBindings());
|
|
20717
21051
|
break;
|
|
20718
21052
|
case OpKind.Pipe:
|
|
20719
|
-
OpList.replace(op, pipe(op.slot, op.name));
|
|
21053
|
+
OpList.replace(op, pipe(op.handle.slot, op.name));
|
|
20720
21054
|
break;
|
|
20721
21055
|
case OpKind.Listener:
|
|
20722
21056
|
const listenerFn = reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, op.consumesDollarEvent);
|
|
@@ -20745,25 +21079,45 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20745
21079
|
}
|
|
20746
21080
|
break;
|
|
20747
21081
|
case OpKind.Defer:
|
|
20748
|
-
|
|
20749
|
-
|
|
20750
|
-
case OpKind.DeferSecondaryBlock:
|
|
20751
|
-
OpList.remove(op);
|
|
21082
|
+
const timerScheduling = !!op.loadingMinimumTime || !!op.loadingAfterTime || !!op.placeholderMinimumTime;
|
|
21083
|
+
OpList.replace(op, defer(op.handle.slot, op.mainSlot.slot, null, op.loadingSlot?.slot ?? null, op.placeholderSlot?.slot ?? null, op.errorSlot?.slot ?? null, op.loadingConfig, op.placeholderConfig, timerScheduling, op.sourceSpan));
|
|
20752
21084
|
break;
|
|
20753
21085
|
case OpKind.DeferOn:
|
|
20754
|
-
|
|
21086
|
+
let args = [];
|
|
21087
|
+
switch (op.trigger.kind) {
|
|
21088
|
+
case DeferTriggerKind.Idle:
|
|
21089
|
+
case DeferTriggerKind.Immediate:
|
|
21090
|
+
break;
|
|
21091
|
+
case DeferTriggerKind.Timer:
|
|
21092
|
+
args = [op.trigger.delay];
|
|
21093
|
+
break;
|
|
21094
|
+
case DeferTriggerKind.Interaction:
|
|
21095
|
+
case DeferTriggerKind.Hover:
|
|
21096
|
+
case DeferTriggerKind.Viewport:
|
|
21097
|
+
if (op.trigger.targetSlot?.slot == null || op.trigger.targetSlotViewSteps === null) {
|
|
21098
|
+
throw new Error(`Slot or view steps not set in trigger reification for trigger kind ${op.trigger.kind}`);
|
|
21099
|
+
}
|
|
21100
|
+
args = [op.trigger.targetSlot.slot];
|
|
21101
|
+
if (op.trigger.targetSlotViewSteps !== 0) {
|
|
21102
|
+
args.push(op.trigger.targetSlotViewSteps);
|
|
21103
|
+
}
|
|
21104
|
+
break;
|
|
21105
|
+
default:
|
|
21106
|
+
throw new Error(`AssertionError: Unsupported reification of defer trigger kind ${op.trigger.kind}`);
|
|
21107
|
+
}
|
|
21108
|
+
OpList.replace(op, deferOn(op.trigger.kind, args, op.prefetch, op.sourceSpan));
|
|
20755
21109
|
break;
|
|
20756
21110
|
case OpKind.ProjectionDef:
|
|
20757
21111
|
OpList.replace(op, projectionDef(op.def));
|
|
20758
21112
|
break;
|
|
20759
21113
|
case OpKind.Projection:
|
|
20760
|
-
if (op.slot === null) {
|
|
21114
|
+
if (op.handle.slot === null) {
|
|
20761
21115
|
throw new Error('No slot was assigned for project instruction');
|
|
20762
21116
|
}
|
|
20763
|
-
OpList.replace(op, projection(op.slot, op.projectionSlotIndex, op.attributes, op.sourceSpan));
|
|
21117
|
+
OpList.replace(op, projection(op.handle.slot, op.projectionSlotIndex, op.attributes, op.sourceSpan));
|
|
20764
21118
|
break;
|
|
20765
21119
|
case OpKind.RepeaterCreate:
|
|
20766
|
-
if (op.slot === null) {
|
|
21120
|
+
if (op.handle.slot === null) {
|
|
20767
21121
|
throw new Error('No slot was assigned for repeater instruction');
|
|
20768
21122
|
}
|
|
20769
21123
|
if (!(unit instanceof ViewCompilationUnit)) {
|
|
@@ -20788,7 +21142,7 @@ function reifyCreateOperations(unit, ops) {
|
|
|
20788
21142
|
emptyDecls = emptyView.decls;
|
|
20789
21143
|
emptyVars = emptyView.vars;
|
|
20790
21144
|
}
|
|
20791
|
-
OpList.replace(op, repeaterCreate(op.slot, repeaterView.fnName, op.decls, op.vars, op.trackByFn, op.usesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, op.sourceSpan));
|
|
21145
|
+
OpList.replace(op, repeaterCreate(op.handle.slot, repeaterView.fnName, op.decls, op.vars, op.tag, op.attributes, op.trackByFn, op.usesComponentInstance, emptyViewFnName, emptyDecls, emptyVars, op.sourceSpan));
|
|
20792
21146
|
break;
|
|
20793
21147
|
case OpKind.Statement:
|
|
20794
21148
|
// Pass statement operations directly through.
|
|
@@ -20844,7 +21198,7 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
20844
21198
|
OpList.replace(op, i18nExp(op.expression, op.sourceSpan));
|
|
20845
21199
|
break;
|
|
20846
21200
|
case OpKind.I18nApply:
|
|
20847
|
-
OpList.replace(op, i18nApply(op.targetSlot, op.sourceSpan));
|
|
21201
|
+
OpList.replace(op, i18nApply(op.targetSlot.slot, op.sourceSpan));
|
|
20848
21202
|
break;
|
|
20849
21203
|
case OpKind.InterpolateText:
|
|
20850
21204
|
OpList.replace(op, textInterpolate(op.interpolation.strings, op.interpolation.expressions, op.sourceSpan));
|
|
@@ -20880,13 +21234,13 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
20880
21234
|
if (op.processed === null) {
|
|
20881
21235
|
throw new Error(`Conditional test was not set.`);
|
|
20882
21236
|
}
|
|
20883
|
-
if (op.targetSlot === null) {
|
|
21237
|
+
if (op.targetSlot.slot === null) {
|
|
20884
21238
|
throw new Error(`Conditional slot was not set.`);
|
|
20885
21239
|
}
|
|
20886
|
-
OpList.replace(op, conditional(op.targetSlot, op.processed, op.contextValue, op.sourceSpan));
|
|
21240
|
+
OpList.replace(op, conditional(op.targetSlot.slot, op.processed, op.contextValue, op.sourceSpan));
|
|
20887
21241
|
break;
|
|
20888
21242
|
case OpKind.Repeater:
|
|
20889
|
-
OpList.replace(op, repeater(op.targetSlot, op.collection, op.sourceSpan));
|
|
21243
|
+
OpList.replace(op, repeater(op.targetSlot.slot, op.collection, op.sourceSpan));
|
|
20890
21244
|
break;
|
|
20891
21245
|
case OpKind.Statement:
|
|
20892
21246
|
// Pass statement operations directly through.
|
|
@@ -20904,7 +21258,7 @@ function reifyIrExpression(expr) {
|
|
|
20904
21258
|
case ExpressionKind.NextContext:
|
|
20905
21259
|
return nextContext(expr.steps);
|
|
20906
21260
|
case ExpressionKind.Reference:
|
|
20907
|
-
return reference(expr.targetSlot + 1 + expr.offset);
|
|
21261
|
+
return reference(expr.targetSlot.slot + 1 + expr.offset);
|
|
20908
21262
|
case ExpressionKind.LexicalRead:
|
|
20909
21263
|
throw new Error(`AssertionError: unresolved LexicalRead of ${expr.name}`);
|
|
20910
21264
|
case ExpressionKind.RestoreView:
|
|
@@ -20939,13 +21293,13 @@ function reifyIrExpression(expr) {
|
|
|
20939
21293
|
case ExpressionKind.PureFunctionParameterExpr:
|
|
20940
21294
|
throw new Error(`AssertionError: expected PureFunctionParameterExpr to have been extracted`);
|
|
20941
21295
|
case ExpressionKind.PipeBinding:
|
|
20942
|
-
return pipeBind(expr.targetSlot, expr.varOffset, expr.args);
|
|
21296
|
+
return pipeBind(expr.targetSlot.slot, expr.varOffset, expr.args);
|
|
20943
21297
|
case ExpressionKind.PipeBindingVariadic:
|
|
20944
|
-
return pipeBindV(expr.targetSlot, expr.varOffset, expr.args);
|
|
21298
|
+
return pipeBindV(expr.targetSlot.slot, expr.varOffset, expr.args);
|
|
20945
21299
|
case ExpressionKind.SanitizerExpr:
|
|
20946
21300
|
return importExpr(sanitizerIdentifierMap.get(expr.fn));
|
|
20947
21301
|
case ExpressionKind.SlotLiteralExpr:
|
|
20948
|
-
return literal(expr.
|
|
21302
|
+
return literal(expr.slot.slot);
|
|
20949
21303
|
default:
|
|
20950
21304
|
throw new Error(`AssertionError: Unsupported reification of ir.Expression kind: ${ExpressionKind[expr.kind]}`);
|
|
20951
21305
|
}
|
|
@@ -20975,7 +21329,10 @@ function reifyListenerHandler(unit, name, handlerOps, consumesDollarEvent) {
|
|
|
20975
21329
|
return fn(params, handlerStmts, undefined, undefined, name);
|
|
20976
21330
|
}
|
|
20977
21331
|
|
|
20978
|
-
|
|
21332
|
+
/**
|
|
21333
|
+
* Bidningd with no content can be safely deleted.
|
|
21334
|
+
*/
|
|
21335
|
+
function removeEmptyBindings(job) {
|
|
20979
21336
|
for (const unit of job.units) {
|
|
20980
21337
|
for (const op of unit.update) {
|
|
20981
21338
|
switch (op.kind) {
|
|
@@ -20996,14 +21353,50 @@ function phaseRemoveEmptyBindings(job) {
|
|
|
20996
21353
|
}
|
|
20997
21354
|
|
|
20998
21355
|
/**
|
|
20999
|
-
*
|
|
21000
|
-
*
|
|
21001
|
-
*
|
|
21356
|
+
* Inside the body of a repeater, certain context variables (such as `$first`) are ambiently
|
|
21357
|
+
* available. This phase finds those variable usages, and replaces them with the appropriate
|
|
21358
|
+
* expression.
|
|
21002
21359
|
*/
|
|
21003
|
-
function
|
|
21004
|
-
|
|
21005
|
-
|
|
21006
|
-
|
|
21360
|
+
function generateRepeaterDerivedVars(job) {
|
|
21361
|
+
const repeaters = new Map();
|
|
21362
|
+
for (const unit of job.units) {
|
|
21363
|
+
for (const op of unit.ops()) {
|
|
21364
|
+
if (op.kind === OpKind.RepeaterCreate) {
|
|
21365
|
+
repeaters.set(op.xref, op);
|
|
21366
|
+
}
|
|
21367
|
+
}
|
|
21368
|
+
}
|
|
21369
|
+
for (const unit of job.units) {
|
|
21370
|
+
for (const op of unit.ops()) {
|
|
21371
|
+
transformExpressionsInOp(op, expr => {
|
|
21372
|
+
if (!(expr instanceof DerivedRepeaterVarExpr)) {
|
|
21373
|
+
return expr;
|
|
21374
|
+
}
|
|
21375
|
+
const repeaterOp = repeaters.get(expr.xref);
|
|
21376
|
+
switch (expr.identity) {
|
|
21377
|
+
case DerivedRepeaterVarIdentity.First:
|
|
21378
|
+
return new BinaryOperatorExpr(BinaryOperator.Identical, new LexicalReadExpr(repeaterOp.varNames.$index), literal(0));
|
|
21379
|
+
case DerivedRepeaterVarIdentity.Last:
|
|
21380
|
+
return new BinaryOperatorExpr(BinaryOperator.Identical, new LexicalReadExpr(repeaterOp.varNames.$index), new BinaryOperatorExpr(BinaryOperator.Minus, new LexicalReadExpr(repeaterOp.varNames.$count), literal(1)));
|
|
21381
|
+
case DerivedRepeaterVarIdentity.Even:
|
|
21382
|
+
return new BinaryOperatorExpr(BinaryOperator.Identical, new BinaryOperatorExpr(BinaryOperator.Modulo, new LexicalReadExpr(repeaterOp.varNames.$index), literal(2)), literal(0));
|
|
21383
|
+
case DerivedRepeaterVarIdentity.Odd:
|
|
21384
|
+
return new BinaryOperatorExpr(BinaryOperator.NotIdentical, new BinaryOperatorExpr(BinaryOperator.Modulo, new LexicalReadExpr(repeaterOp.varNames.$index), literal(2)), literal(0));
|
|
21385
|
+
}
|
|
21386
|
+
}, VisitorContextFlag.None);
|
|
21387
|
+
}
|
|
21388
|
+
}
|
|
21389
|
+
}
|
|
21390
|
+
|
|
21391
|
+
/**
|
|
21392
|
+
* Resolves `ir.ContextExpr` expressions (which represent embedded view or component contexts) to
|
|
21393
|
+
* either the `ctx` parameter to component functions (for the current view context) or to variables
|
|
21394
|
+
* that store those contexts (for contexts accessed via the `nextContext()` instruction).
|
|
21395
|
+
*/
|
|
21396
|
+
function resolveContexts(job) {
|
|
21397
|
+
for (const unit of job.units) {
|
|
21398
|
+
processLexicalScope$1(unit, unit.create);
|
|
21399
|
+
processLexicalScope$1(unit, unit.update);
|
|
21007
21400
|
}
|
|
21008
21401
|
}
|
|
21009
21402
|
function processLexicalScope$1(view, ops) {
|
|
@@ -21049,13 +21442,13 @@ function processLexicalScope$1(view, ops) {
|
|
|
21049
21442
|
* Any variable inside a listener with the name `$event` will be transformed into a output lexical
|
|
21050
21443
|
* read immediately, and does not participate in any of the normal logic for handling variables.
|
|
21051
21444
|
*/
|
|
21052
|
-
function
|
|
21445
|
+
function resolveDollarEvent(job) {
|
|
21053
21446
|
for (const unit of job.units) {
|
|
21054
|
-
|
|
21055
|
-
|
|
21447
|
+
transformDollarEvent(unit, unit.create);
|
|
21448
|
+
transformDollarEvent(unit, unit.update);
|
|
21056
21449
|
}
|
|
21057
21450
|
}
|
|
21058
|
-
function
|
|
21451
|
+
function transformDollarEvent(unit, ops) {
|
|
21059
21452
|
for (const op of ops) {
|
|
21060
21453
|
if (op.kind === OpKind.Listener) {
|
|
21061
21454
|
transformExpressionsInOp(op, (expr) => {
|
|
@@ -21070,201 +21463,46 @@ function resolveDollarEvent(unit, ops) {
|
|
|
21070
21463
|
}
|
|
21071
21464
|
|
|
21072
21465
|
/**
|
|
21073
|
-
*
|
|
21074
|
-
*/
|
|
21075
|
-
const ESCAPE = '\uFFFD';
|
|
21076
|
-
/**
|
|
21077
|
-
* Marker used to indicate an element tag.
|
|
21078
|
-
*/
|
|
21079
|
-
const ELEMENT_MARKER = '#';
|
|
21080
|
-
/**
|
|
21081
|
-
* Marker used to indicate a template tag.
|
|
21082
|
-
*/
|
|
21083
|
-
const TEMPLATE_MARKER = '*';
|
|
21084
|
-
/**
|
|
21085
|
-
* Marker used to indicate closing of an element or template tag.
|
|
21086
|
-
*/
|
|
21087
|
-
const TAG_CLOSE_MARKER = '/';
|
|
21088
|
-
/**
|
|
21089
|
-
* Marker used to indicate the sub-template context.
|
|
21090
|
-
*/
|
|
21091
|
-
const CONTEXT_MARKER = ':';
|
|
21092
|
-
/**
|
|
21093
|
-
* Marker used to indicate the start of a list of values.
|
|
21094
|
-
*/
|
|
21095
|
-
const LIST_START_MARKER = '[';
|
|
21096
|
-
/**
|
|
21097
|
-
* Marker used to indicate the end of a list of values.
|
|
21098
|
-
*/
|
|
21099
|
-
const LIST_END_MARKER = ']';
|
|
21100
|
-
/**
|
|
21101
|
-
* Delimiter used to separate multiple values in a list.
|
|
21102
|
-
*/
|
|
21103
|
-
const LIST_DELIMITER = '|';
|
|
21104
|
-
/**
|
|
21105
|
-
* Flags that describe what an i18n param value. These determine how the value is serialized into
|
|
21106
|
-
* the final map.
|
|
21107
|
-
*/
|
|
21108
|
-
var I18nParamValueFlags;
|
|
21109
|
-
(function (I18nParamValueFlags) {
|
|
21110
|
-
I18nParamValueFlags[I18nParamValueFlags["None"] = 0] = "None";
|
|
21111
|
-
/**
|
|
21112
|
-
* This value represtents an element tag.
|
|
21113
|
-
*/
|
|
21114
|
-
I18nParamValueFlags[I18nParamValueFlags["ElementTag"] = 1] = "ElementTag";
|
|
21115
|
-
/**
|
|
21116
|
-
* This value represents a template tag.
|
|
21117
|
-
*/
|
|
21118
|
-
I18nParamValueFlags[I18nParamValueFlags["TemplateTag"] = 2] = "TemplateTag";
|
|
21119
|
-
/**
|
|
21120
|
-
* This value represents the opening of a tag.
|
|
21121
|
-
*/
|
|
21122
|
-
I18nParamValueFlags[I18nParamValueFlags["OpenTag"] = 4] = "OpenTag";
|
|
21123
|
-
/**
|
|
21124
|
-
* This value represents the closing of a tag.
|
|
21125
|
-
*/
|
|
21126
|
-
I18nParamValueFlags[I18nParamValueFlags["CloseTag"] = 8] = "CloseTag";
|
|
21127
|
-
})(I18nParamValueFlags || (I18nParamValueFlags = {}));
|
|
21128
|
-
/**
|
|
21129
|
-
* Represents the complete i18n params map for an i18n op.
|
|
21130
|
-
*/
|
|
21131
|
-
class I18nPlaceholderParams {
|
|
21132
|
-
constructor() {
|
|
21133
|
-
this.values = new Map();
|
|
21134
|
-
}
|
|
21135
|
-
/**
|
|
21136
|
-
* Adds a new value to the params map.
|
|
21137
|
-
*/
|
|
21138
|
-
addValue(placeholder, value, subTemplateIndex, resolutionTime, flags) {
|
|
21139
|
-
const placeholderValues = this.values.get(placeholder) ?? [];
|
|
21140
|
-
placeholderValues.push({ value, subTemplateIndex, resolutionTime, flags });
|
|
21141
|
-
this.values.set(placeholder, placeholderValues);
|
|
21142
|
-
}
|
|
21143
|
-
/**
|
|
21144
|
-
* Saves the params map, in serialized form, into the given i18n op.
|
|
21145
|
-
*/
|
|
21146
|
-
saveToOp(op) {
|
|
21147
|
-
for (const [placeholder, placeholderValues] of this.values) {
|
|
21148
|
-
// We need to run post-processing for any 1i8n ops that contain parameters with more than
|
|
21149
|
-
// one value, even if there are no parameters resolved at post-processing time.
|
|
21150
|
-
const creationValues = placeholderValues.filter(({ resolutionTime }) => resolutionTime === I18nParamResolutionTime.Creation);
|
|
21151
|
-
if (creationValues.length > 1) {
|
|
21152
|
-
op.needsPostprocessing = true;
|
|
21153
|
-
}
|
|
21154
|
-
// Save creation time params to op.
|
|
21155
|
-
const serializedCreationValues = this.serializeValues(creationValues);
|
|
21156
|
-
if (serializedCreationValues !== null) {
|
|
21157
|
-
op.params.set(placeholder, literal(serializedCreationValues));
|
|
21158
|
-
}
|
|
21159
|
-
// Save post-processing time params to op.
|
|
21160
|
-
const serializedPostprocessingValues = this.serializeValues(placeholderValues.filter(({ resolutionTime }) => resolutionTime === I18nParamResolutionTime.Postproccessing));
|
|
21161
|
-
if (serializedPostprocessingValues !== null) {
|
|
21162
|
-
op.needsPostprocessing = true;
|
|
21163
|
-
op.postprocessingParams.set(placeholder, literal(serializedPostprocessingValues));
|
|
21164
|
-
}
|
|
21165
|
-
}
|
|
21166
|
-
}
|
|
21167
|
-
/**
|
|
21168
|
-
* Merges another param map into this one.
|
|
21169
|
-
*/
|
|
21170
|
-
merge(other) {
|
|
21171
|
-
for (const [placeholder, otherValues] of other.values) {
|
|
21172
|
-
const currentValues = this.values.get(placeholder) || [];
|
|
21173
|
-
// Child element close tag params should be prepended to maintain the same order as
|
|
21174
|
-
// TemplateDefinitionBuilder.
|
|
21175
|
-
const flags = otherValues[0].flags;
|
|
21176
|
-
if ((flags & I18nParamValueFlags.CloseTag) && !(flags & I18nParamValueFlags.OpenTag)) {
|
|
21177
|
-
this.values.set(placeholder, [...otherValues, ...currentValues]);
|
|
21178
|
-
}
|
|
21179
|
-
else {
|
|
21180
|
-
this.values.set(placeholder, [...currentValues, ...otherValues]);
|
|
21181
|
-
}
|
|
21182
|
-
}
|
|
21183
|
-
}
|
|
21184
|
-
/**
|
|
21185
|
-
* Serializes a list of i18n placeholder values.
|
|
21186
|
-
*/
|
|
21187
|
-
serializeValues(values) {
|
|
21188
|
-
if (values.length === 0) {
|
|
21189
|
-
return null;
|
|
21190
|
-
}
|
|
21191
|
-
const serializedValues = values.map(value => this.serializeValue(value));
|
|
21192
|
-
return serializedValues.length === 1 ?
|
|
21193
|
-
serializedValues[0] :
|
|
21194
|
-
`${LIST_START_MARKER}${serializedValues.join(LIST_DELIMITER)}${LIST_END_MARKER}`;
|
|
21195
|
-
}
|
|
21196
|
-
/**
|
|
21197
|
-
* Serializes a single i18n placeholder value.
|
|
21198
|
-
*/
|
|
21199
|
-
serializeValue(value) {
|
|
21200
|
-
let tagMarker = '';
|
|
21201
|
-
let closeMarker = '';
|
|
21202
|
-
if (value.flags & I18nParamValueFlags.ElementTag) {
|
|
21203
|
-
tagMarker = ELEMENT_MARKER;
|
|
21204
|
-
}
|
|
21205
|
-
else if (value.flags & I18nParamValueFlags.TemplateTag) {
|
|
21206
|
-
tagMarker = TEMPLATE_MARKER;
|
|
21207
|
-
}
|
|
21208
|
-
if (tagMarker !== '') {
|
|
21209
|
-
closeMarker = value.flags & I18nParamValueFlags.CloseTag ? TAG_CLOSE_MARKER : '';
|
|
21210
|
-
}
|
|
21211
|
-
const context = value.subTemplateIndex === null ? '' : `${CONTEXT_MARKER}${value.subTemplateIndex}`;
|
|
21212
|
-
// Self-closing tags use a special form that concatenates the start and close tag values.
|
|
21213
|
-
if ((value.flags & I18nParamValueFlags.OpenTag) &&
|
|
21214
|
-
(value.flags & I18nParamValueFlags.CloseTag)) {
|
|
21215
|
-
return `${ESCAPE}${tagMarker}${value.value}${context}${ESCAPE}${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
21216
|
-
}
|
|
21217
|
-
return `${ESCAPE}${closeMarker}${tagMarker}${value.value}${context}${ESCAPE}`;
|
|
21218
|
-
}
|
|
21219
|
-
}
|
|
21220
|
-
/**
|
|
21221
|
-
* Resolve the placeholders in i18n messages.
|
|
21466
|
+
* Resolve the element placeholders in i18n messages.
|
|
21222
21467
|
*/
|
|
21223
|
-
function
|
|
21224
|
-
|
|
21225
|
-
const
|
|
21226
|
-
|
|
21227
|
-
|
|
21228
|
-
|
|
21229
|
-
|
|
21230
|
-
|
|
21231
|
-
|
|
21232
|
-
|
|
21233
|
-
|
|
21234
|
-
|
|
21235
|
-
|
|
21236
|
-
if (!op.params.has(placeholder) && !op.postprocessingParams.has(placeholder)) {
|
|
21237
|
-
throw Error(`Failed to resolve i18n placeholder: ${placeholder}`);
|
|
21238
|
-
}
|
|
21468
|
+
function resolveI18nElementPlaceholders(job) {
|
|
21469
|
+
// Record all of the element and extracted message ops for use later.
|
|
21470
|
+
const extractedMessageOps = new Map();
|
|
21471
|
+
const elements = new Map();
|
|
21472
|
+
for (const unit of job.units) {
|
|
21473
|
+
for (const op of unit.create) {
|
|
21474
|
+
switch (op.kind) {
|
|
21475
|
+
case OpKind.ExtractedMessage:
|
|
21476
|
+
extractedMessageOps.set(op.owner, op);
|
|
21477
|
+
break;
|
|
21478
|
+
case OpKind.ElementStart:
|
|
21479
|
+
elements.set(op.xref, op);
|
|
21480
|
+
break;
|
|
21239
21481
|
}
|
|
21240
21482
|
}
|
|
21241
21483
|
}
|
|
21242
|
-
}
|
|
21243
|
-
/**
|
|
21244
|
-
* Resolve placeholders for each i18n op.
|
|
21245
|
-
*/
|
|
21246
|
-
function resolvePlaceholders(job, params, i18nOps) {
|
|
21247
21484
|
for (const unit of job.units) {
|
|
21248
|
-
|
|
21249
|
-
|
|
21250
|
-
|
|
21485
|
+
// Track the current i18n op and corresponding extracted message op as we step through the
|
|
21486
|
+
// creation IR.
|
|
21487
|
+
let currentOps = null;
|
|
21251
21488
|
for (const op of unit.create) {
|
|
21252
21489
|
switch (op.kind) {
|
|
21253
21490
|
case OpKind.I18nStart:
|
|
21254
|
-
|
|
21255
|
-
|
|
21491
|
+
if (!extractedMessageOps.has(op.xref)) {
|
|
21492
|
+
throw Error('Could not find extracted message for i18n op');
|
|
21493
|
+
}
|
|
21494
|
+
currentOps = { i18n: op, extractedMessage: extractedMessageOps.get(op.xref) };
|
|
21256
21495
|
break;
|
|
21257
21496
|
case OpKind.I18nEnd:
|
|
21258
|
-
|
|
21497
|
+
currentOps = null;
|
|
21259
21498
|
break;
|
|
21260
21499
|
case OpKind.ElementStart:
|
|
21261
21500
|
// For elements with i18n placeholders, record its slot value in the params map under the
|
|
21262
21501
|
// corresponding tag start placeholder.
|
|
21263
21502
|
if (op.i18nPlaceholder !== undefined) {
|
|
21264
|
-
if (
|
|
21503
|
+
if (currentOps === null) {
|
|
21265
21504
|
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21266
21505
|
}
|
|
21267
|
-
elements.set(op.xref, op);
|
|
21268
21506
|
const { startName, closeName } = op.i18nPlaceholder;
|
|
21269
21507
|
let flags = I18nParamValueFlags.ElementTag | I18nParamValueFlags.OpenTag;
|
|
21270
21508
|
// For self-closing tags, there is no close tag placeholder. Instead, the start tag
|
|
@@ -21272,57 +21510,40 @@ function resolvePlaceholders(job, params, i18nOps) {
|
|
|
21272
21510
|
if (closeName === '') {
|
|
21273
21511
|
flags |= I18nParamValueFlags.CloseTag;
|
|
21274
21512
|
}
|
|
21275
|
-
addParam(params,
|
|
21513
|
+
addParam(currentOps.extractedMessage.params, startName, op.handle.slot, currentOps.i18n.subTemplateIndex, flags);
|
|
21276
21514
|
}
|
|
21277
21515
|
break;
|
|
21278
21516
|
case OpKind.ElementEnd:
|
|
21517
|
+
// For elements with i18n placeholders, record its slot value in the params map under the
|
|
21518
|
+
// corresponding tag close placeholder.
|
|
21279
21519
|
const startOp = elements.get(op.xref);
|
|
21280
21520
|
if (startOp && startOp.i18nPlaceholder !== undefined) {
|
|
21281
|
-
if (
|
|
21521
|
+
if (currentOps === null) {
|
|
21282
21522
|
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21283
21523
|
}
|
|
21284
21524
|
const { closeName } = startOp.i18nPlaceholder;
|
|
21285
21525
|
// Self-closing tags don't have a closing tag placeholder.
|
|
21286
21526
|
if (closeName !== '') {
|
|
21287
|
-
addParam(params,
|
|
21527
|
+
addParam(currentOps.extractedMessage.params, closeName, startOp.handle.slot, currentOps.i18n.subTemplateIndex, I18nParamValueFlags.ElementTag | I18nParamValueFlags.CloseTag);
|
|
21288
21528
|
}
|
|
21289
21529
|
}
|
|
21290
21530
|
break;
|
|
21291
21531
|
case OpKind.Template:
|
|
21532
|
+
// For templates with i18n placeholders, record its slot value in the params map under the
|
|
21533
|
+
// corresponding template start and close placeholders.
|
|
21292
21534
|
if (op.i18nPlaceholder !== undefined) {
|
|
21293
|
-
if (
|
|
21535
|
+
if (currentOps === null) {
|
|
21294
21536
|
throw Error('i18n tag placeholder should only occur inside an i18n block');
|
|
21295
21537
|
}
|
|
21296
|
-
const subTemplateIndex = getSubTemplateIndexForTemplateTag(job,
|
|
21297
|
-
addParam(params,
|
|
21298
|
-
addParam(params,
|
|
21538
|
+
const subTemplateIndex = getSubTemplateIndexForTemplateTag(job, currentOps.i18n, op);
|
|
21539
|
+
addParam(currentOps.extractedMessage.params, op.i18nPlaceholder.startName, op.handle.slot, subTemplateIndex, I18nParamValueFlags.TemplateTag);
|
|
21540
|
+
addParam(currentOps.extractedMessage.params, op.i18nPlaceholder.closeName, op.handle.slot, subTemplateIndex, I18nParamValueFlags.TemplateTag | I18nParamValueFlags.CloseTag);
|
|
21299
21541
|
}
|
|
21300
21542
|
break;
|
|
21301
21543
|
}
|
|
21302
21544
|
}
|
|
21303
|
-
// Fill in values for each of the i18n expression placeholders.
|
|
21304
|
-
const i18nBlockPlaceholderIndices = new Map();
|
|
21305
|
-
for (const op of unit.update) {
|
|
21306
|
-
if (op.kind === OpKind.I18nExpression) {
|
|
21307
|
-
const i18nOp = i18nOps.get(op.owner);
|
|
21308
|
-
let index = i18nBlockPlaceholderIndices.get(op.owner) || 0;
|
|
21309
|
-
if (!i18nOp) {
|
|
21310
|
-
throw Error('Cannot find corresponding i18nStart for i18nExpr');
|
|
21311
|
-
}
|
|
21312
|
-
addParam(params, i18nOp, op.i18nPlaceholder, index++, i18nOp.subTemplateIndex, op.resolutionTime);
|
|
21313
|
-
i18nBlockPlaceholderIndices.set(op.owner, index);
|
|
21314
|
-
}
|
|
21315
|
-
}
|
|
21316
21545
|
}
|
|
21317
21546
|
}
|
|
21318
|
-
/**
|
|
21319
|
-
* Add a param to the params map for the given i18n op.
|
|
21320
|
-
*/
|
|
21321
|
-
function addParam(params, i18nOp, placeholder, value, subTemplateIndex, resolutionTime, flags = I18nParamValueFlags.None) {
|
|
21322
|
-
const i18nOpParams = params.get(i18nOp.xref) || new I18nPlaceholderParams();
|
|
21323
|
-
i18nOpParams.addValue(placeholder, value, subTemplateIndex, resolutionTime, flags);
|
|
21324
|
-
params.set(i18nOp.xref, i18nOpParams);
|
|
21325
|
-
}
|
|
21326
21547
|
/**
|
|
21327
21548
|
* Get the subTemplateIndex for the given template op. For template ops, use the subTemplateIndex of
|
|
21328
21549
|
* the child i18n block inside the template.
|
|
@@ -21335,15 +21556,59 @@ function getSubTemplateIndexForTemplateTag(job, i18nOp, op) {
|
|
|
21335
21556
|
}
|
|
21336
21557
|
return i18nOp.subTemplateIndex;
|
|
21337
21558
|
}
|
|
21559
|
+
/** Add a param value to the given params map. */
|
|
21560
|
+
function addParam(params, placeholder, value, subTemplateIndex, flags = I18nParamValueFlags.None) {
|
|
21561
|
+
const values = params.get(placeholder) ?? [];
|
|
21562
|
+
values.push({ value, subTemplateIndex, flags });
|
|
21563
|
+
params.set(placeholder, values);
|
|
21564
|
+
}
|
|
21565
|
+
|
|
21338
21566
|
/**
|
|
21339
|
-
*
|
|
21567
|
+
* Resolve the i18n expression placeholders in i18n messages.
|
|
21340
21568
|
*/
|
|
21341
|
-
function
|
|
21342
|
-
|
|
21343
|
-
|
|
21344
|
-
|
|
21345
|
-
|
|
21346
|
-
|
|
21569
|
+
function resolveI18nExpressionPlaceholders(job) {
|
|
21570
|
+
// Record all of the i18n and extracted message ops for use later.
|
|
21571
|
+
const i18nOps = new Map();
|
|
21572
|
+
const extractedMessageOps = new Map();
|
|
21573
|
+
for (const unit of job.units) {
|
|
21574
|
+
for (const op of unit.create) {
|
|
21575
|
+
switch (op.kind) {
|
|
21576
|
+
case OpKind.I18nStart:
|
|
21577
|
+
i18nOps.set(op.xref, op);
|
|
21578
|
+
break;
|
|
21579
|
+
case OpKind.ExtractedMessage:
|
|
21580
|
+
extractedMessageOps.set(op.owner, op);
|
|
21581
|
+
break;
|
|
21582
|
+
}
|
|
21583
|
+
}
|
|
21584
|
+
}
|
|
21585
|
+
// Keep track of the next available expression index per i18n block.
|
|
21586
|
+
const expressionIndices = new Map();
|
|
21587
|
+
for (const unit of job.units) {
|
|
21588
|
+
for (const op of unit.update) {
|
|
21589
|
+
if (op.kind === OpKind.I18nExpression) {
|
|
21590
|
+
const i18nOp = i18nOps.get(op.owner);
|
|
21591
|
+
let index = expressionIndices.get(op.owner) || 0;
|
|
21592
|
+
if (!i18nOp) {
|
|
21593
|
+
throw Error('Cannot find corresponding i18n block for i18nExpr');
|
|
21594
|
+
}
|
|
21595
|
+
const extractedMessageOp = extractedMessageOps.get(i18nOp.xref);
|
|
21596
|
+
if (!extractedMessageOp) {
|
|
21597
|
+
throw Error('Cannot find extracted message for i18n block');
|
|
21598
|
+
}
|
|
21599
|
+
// Add the expression index in the appropriate params map.
|
|
21600
|
+
const params = op.resolutionTime === I18nParamResolutionTime.Creation ?
|
|
21601
|
+
extractedMessageOp.params :
|
|
21602
|
+
extractedMessageOp.postprocessingParams;
|
|
21603
|
+
const values = params.get(op.i18nPlaceholder) || [];
|
|
21604
|
+
values.push({
|
|
21605
|
+
value: index,
|
|
21606
|
+
subTemplateIndex: i18nOp.subTemplateIndex,
|
|
21607
|
+
flags: I18nParamValueFlags.None
|
|
21608
|
+
});
|
|
21609
|
+
params.set(op.i18nPlaceholder, values);
|
|
21610
|
+
expressionIndices.set(op.owner, index + 1);
|
|
21611
|
+
}
|
|
21347
21612
|
}
|
|
21348
21613
|
}
|
|
21349
21614
|
}
|
|
@@ -21355,8 +21620,8 @@ function propagatePlaceholders(params, i18nOps) {
|
|
|
21355
21620
|
* Also matches `ir.RestoreViewExpr` expressions with the variables of their corresponding saved
|
|
21356
21621
|
* views.
|
|
21357
21622
|
*/
|
|
21358
|
-
function
|
|
21359
|
-
for (const unit of
|
|
21623
|
+
function resolveNames(job) {
|
|
21624
|
+
for (const unit of job.units) {
|
|
21360
21625
|
processLexicalScope(unit, unit.create, null);
|
|
21361
21626
|
processLexicalScope(unit, unit.update, null);
|
|
21362
21627
|
}
|
|
@@ -21457,7 +21722,7 @@ const sanitizers = new Map([
|
|
|
21457
21722
|
/**
|
|
21458
21723
|
* Resolves sanitization functions for ops that need them.
|
|
21459
21724
|
*/
|
|
21460
|
-
function
|
|
21725
|
+
function resolveSanitizers(job) {
|
|
21461
21726
|
for (const unit of job.units) {
|
|
21462
21727
|
const elements = createOpXrefMap(unit);
|
|
21463
21728
|
let sanitizerFn;
|
|
@@ -21492,21 +21757,26 @@ function isIframeElement$1(op) {
|
|
|
21492
21757
|
return op.kind === OpKind.ElementStart && op.tag?.toLowerCase() === 'iframe';
|
|
21493
21758
|
}
|
|
21494
21759
|
|
|
21495
|
-
|
|
21496
|
-
|
|
21497
|
-
|
|
21498
|
-
|
|
21760
|
+
/**
|
|
21761
|
+
* When inside of a listener, we may need access to one or more enclosing views. Therefore, each
|
|
21762
|
+
* view should save the current view, and each listener must have the ability to restore the
|
|
21763
|
+
* appropriate view. We eagerly generate all save view variables; they will be optimized away later.
|
|
21764
|
+
*/
|
|
21765
|
+
function saveAndRestoreView(job) {
|
|
21766
|
+
for (const unit of job.units) {
|
|
21767
|
+
unit.create.prepend([
|
|
21768
|
+
createVariableOp(unit.job.allocateXrefId(), {
|
|
21499
21769
|
kind: SemanticVariableKind.SavedView,
|
|
21500
21770
|
name: null,
|
|
21501
|
-
view:
|
|
21771
|
+
view: unit.xref,
|
|
21502
21772
|
}, new GetCurrentViewExpr(), VariableFlags.None),
|
|
21503
21773
|
]);
|
|
21504
|
-
for (const op of
|
|
21774
|
+
for (const op of unit.create) {
|
|
21505
21775
|
if (op.kind !== OpKind.Listener) {
|
|
21506
21776
|
continue;
|
|
21507
21777
|
}
|
|
21508
21778
|
// Embedded views always need the save/restore view operation.
|
|
21509
|
-
let needsRestoreView =
|
|
21779
|
+
let needsRestoreView = unit !== job.root;
|
|
21510
21780
|
if (!needsRestoreView) {
|
|
21511
21781
|
for (const handlerOp of op.handlerOps) {
|
|
21512
21782
|
visitExpressionsInOp(handlerOp, expr => {
|
|
@@ -21518,7 +21788,7 @@ function phaseSaveRestoreView(job) {
|
|
|
21518
21788
|
}
|
|
21519
21789
|
}
|
|
21520
21790
|
if (needsRestoreView) {
|
|
21521
|
-
addSaveRestoreViewOperationToListener(
|
|
21791
|
+
addSaveRestoreViewOperationToListener(unit, op);
|
|
21522
21792
|
}
|
|
21523
21793
|
}
|
|
21524
21794
|
}
|
|
@@ -21550,7 +21820,7 @@ function addSaveRestoreViewOperationToListener(unit, op) {
|
|
|
21550
21820
|
* This phase is also responsible for counting the number of slots used for each view (its `decls`)
|
|
21551
21821
|
* and propagating that number into the `Template` operations which declare embedded views.
|
|
21552
21822
|
*/
|
|
21553
|
-
function
|
|
21823
|
+
function allocateSlots(job) {
|
|
21554
21824
|
// Map of all declarations in all views within the component which require an assigned slot index.
|
|
21555
21825
|
// This map needs to be global (across all views within the component) since it's possible to
|
|
21556
21826
|
// reference a slot from one view from an expression within another (e.g. local references work
|
|
@@ -21566,9 +21836,9 @@ function phaseSlotAllocation(job) {
|
|
|
21566
21836
|
continue;
|
|
21567
21837
|
}
|
|
21568
21838
|
// Assign slots to this declaration starting at the current `slotCount`.
|
|
21569
|
-
op.slot = slotCount;
|
|
21839
|
+
op.handle.slot = slotCount;
|
|
21570
21840
|
// And track its assigned slot in the `slotMap`.
|
|
21571
|
-
slotMap.set(op.xref, op.slot);
|
|
21841
|
+
slotMap.set(op.xref, op.handle.slot);
|
|
21572
21842
|
// Each declaration may use more than 1 slot, so increment `slotCount` to reserve the number
|
|
21573
21843
|
// of slots required.
|
|
21574
21844
|
slotCount += op.numSlotsUsed;
|
|
@@ -21590,31 +21860,6 @@ function phaseSlotAllocation(job) {
|
|
|
21590
21860
|
const childView = job.views.get(op.xref);
|
|
21591
21861
|
op.decls = childView.decls;
|
|
21592
21862
|
}
|
|
21593
|
-
if (hasUsesSlotIndexTrait(op) && op.target !== null && op.targetSlot === null) {
|
|
21594
|
-
if (!slotMap.has(op.target)) {
|
|
21595
|
-
// We do expect to find a slot allocated for everything which might be referenced.
|
|
21596
|
-
throw new Error(`AssertionError: no slot allocated for ${OpKind[op.kind]} target ${op.target}`);
|
|
21597
|
-
}
|
|
21598
|
-
op.targetSlot = slotMap.get(op.target);
|
|
21599
|
-
}
|
|
21600
|
-
// Process all `ir.Expression`s within this view, and look for `usesSlotIndexExprTrait`.
|
|
21601
|
-
visitExpressionsInOp(op, expr => {
|
|
21602
|
-
if (!isIrExpression(expr)) {
|
|
21603
|
-
return;
|
|
21604
|
-
}
|
|
21605
|
-
if (!hasUsesSlotIndexTrait(expr) || expr.targetSlot !== null) {
|
|
21606
|
-
return;
|
|
21607
|
-
}
|
|
21608
|
-
// The `UsesSlotIndexExprTrait` indicates that this expression references something declared
|
|
21609
|
-
// in this component template by its slot index. Use the `target` `ir.XrefId` to find the
|
|
21610
|
-
// allocated slot for that declaration in `slotMap`.
|
|
21611
|
-
if (!slotMap.has(expr.target)) {
|
|
21612
|
-
// We do expect to find a slot allocated for everything which might be referenced.
|
|
21613
|
-
throw new Error(`AssertionError: no slot allocated for ${expr.constructor.name} target ${expr.target}`);
|
|
21614
|
-
}
|
|
21615
|
-
// Record the allocated slot on the expression.
|
|
21616
|
-
expr.targetSlot = slotMap.get(expr.target);
|
|
21617
|
-
});
|
|
21618
21863
|
}
|
|
21619
21864
|
}
|
|
21620
21865
|
}
|
|
@@ -21623,8 +21868,8 @@ function phaseSlotAllocation(job) {
|
|
|
21623
21868
|
* Transforms special-case bindings with 'style' or 'class' in their names. Must run before the
|
|
21624
21869
|
* main binding specialization pass.
|
|
21625
21870
|
*/
|
|
21626
|
-
function
|
|
21627
|
-
for (const unit of
|
|
21871
|
+
function specializeStyleBindings(job) {
|
|
21872
|
+
for (const unit of job.units) {
|
|
21628
21873
|
for (const op of unit.update) {
|
|
21629
21874
|
if (op.kind !== OpKind.Binding) {
|
|
21630
21875
|
continue;
|
|
@@ -21662,8 +21907,8 @@ function phaseStyleBindingSpecialization(cpl) {
|
|
|
21662
21907
|
* in the double keyed read `a?.[f()]?.[f()]`, the two function calls have non-overlapping scopes.
|
|
21663
21908
|
* Implement an algorithm for reuse.
|
|
21664
21909
|
*/
|
|
21665
|
-
function
|
|
21666
|
-
for (const unit of
|
|
21910
|
+
function generateTemporaryVariables(job) {
|
|
21911
|
+
for (const unit of job.units) {
|
|
21667
21912
|
unit.create.prepend(generateTemporaries(unit.create));
|
|
21668
21913
|
unit.update.prepend(generateTemporaries(unit.update));
|
|
21669
21914
|
}
|
|
@@ -21732,11 +21977,149 @@ function assignName(names, expr) {
|
|
|
21732
21977
|
expr.name = name;
|
|
21733
21978
|
}
|
|
21734
21979
|
|
|
21980
|
+
/**
|
|
21981
|
+
* Generate track functions that need to be extracted to the constant pool. This entails wrapping
|
|
21982
|
+
* them in an arrow (or traditional) function, replacing context reads with `this.`, and storing
|
|
21983
|
+
* them in the constant pool.
|
|
21984
|
+
*
|
|
21985
|
+
* Note that, if a track function was previously optimized, it will not need to be extracted, and
|
|
21986
|
+
* this phase is a no-op.
|
|
21987
|
+
*/
|
|
21988
|
+
function generateTrackFns(job) {
|
|
21989
|
+
for (const unit of job.units) {
|
|
21990
|
+
for (const op of unit.create) {
|
|
21991
|
+
if (op.kind !== OpKind.RepeaterCreate) {
|
|
21992
|
+
continue;
|
|
21993
|
+
}
|
|
21994
|
+
if (op.trackByFn !== null) {
|
|
21995
|
+
// The final track function was already set, probably because it was optimized.
|
|
21996
|
+
continue;
|
|
21997
|
+
}
|
|
21998
|
+
// Find all component context reads.
|
|
21999
|
+
let usesComponentContext = false;
|
|
22000
|
+
op.track = transformExpressionsInExpression(op.track, expr => {
|
|
22001
|
+
if (expr instanceof TrackContextExpr) {
|
|
22002
|
+
usesComponentContext = true;
|
|
22003
|
+
return variable('this');
|
|
22004
|
+
}
|
|
22005
|
+
return expr;
|
|
22006
|
+
}, VisitorContextFlag.None);
|
|
22007
|
+
let fn;
|
|
22008
|
+
const fnParams = [new FnParam('$index'), new FnParam('$item')];
|
|
22009
|
+
if (usesComponentContext) {
|
|
22010
|
+
fn = new FunctionExpr(fnParams, [new ReturnStatement(op.track)]);
|
|
22011
|
+
}
|
|
22012
|
+
else {
|
|
22013
|
+
fn = arrowFn(fnParams, op.track);
|
|
22014
|
+
}
|
|
22015
|
+
op.trackByFn = job.pool.getSharedFunctionReference(fn, '_forTrack');
|
|
22016
|
+
}
|
|
22017
|
+
}
|
|
22018
|
+
}
|
|
22019
|
+
|
|
22020
|
+
/**
|
|
22021
|
+
* `track` functions in `for` repeaters can sometimes be "optimized," i.e. transformed into inline
|
|
22022
|
+
* expressions, in lieu of an external function call. For example, tracking by `$index` can be be
|
|
22023
|
+
* optimized into an inline `trackByIndex` reference. This phase checks track expressions for
|
|
22024
|
+
* optimizable cases.
|
|
22025
|
+
*/
|
|
22026
|
+
function optimizeTrackFns(job) {
|
|
22027
|
+
for (const unit of job.units) {
|
|
22028
|
+
for (const op of unit.create) {
|
|
22029
|
+
if (op.kind !== OpKind.RepeaterCreate) {
|
|
22030
|
+
continue;
|
|
22031
|
+
}
|
|
22032
|
+
if (op.track instanceof ReadVarExpr && op.track.name === '$index') {
|
|
22033
|
+
// Top-level access of `$index` uses the built in `repeaterTrackByIndex`.
|
|
22034
|
+
op.trackByFn = importExpr(Identifiers.repeaterTrackByIndex);
|
|
22035
|
+
}
|
|
22036
|
+
else if (op.track instanceof ReadVarExpr && op.track.name === '$item') {
|
|
22037
|
+
// Top-level access of the item uses the built in `repeaterTrackByIdentity`.
|
|
22038
|
+
op.trackByFn = importExpr(Identifiers.repeaterTrackByIdentity);
|
|
22039
|
+
}
|
|
22040
|
+
else if (isTrackByFunctionCall(job.root.xref, op.track)) {
|
|
22041
|
+
// Top-level method calls in the form of `fn($index, item)` can be passed in directly.
|
|
22042
|
+
if (op.track.receiver.receiver.view === unit.xref) {
|
|
22043
|
+
// TODO: this may be wrong
|
|
22044
|
+
op.trackByFn = op.track.receiver;
|
|
22045
|
+
}
|
|
22046
|
+
else {
|
|
22047
|
+
// This is a plain method call, but not in the component's root view.
|
|
22048
|
+
// We need to get the component instance, and then call the method on it.
|
|
22049
|
+
op.trackByFn =
|
|
22050
|
+
importExpr(Identifiers.componentInstance).callFn([]).prop(op.track.receiver.name);
|
|
22051
|
+
// Because the context is not avaiable (without a special function), we don't want to
|
|
22052
|
+
// try to resolve it later. Let's get rid of it by overwriting the original track
|
|
22053
|
+
// expression (which won't be used anyway).
|
|
22054
|
+
op.track = op.trackByFn;
|
|
22055
|
+
}
|
|
22056
|
+
}
|
|
22057
|
+
else {
|
|
22058
|
+
// The track function could not be optimized.
|
|
22059
|
+
// Replace context reads with a special IR expression, since context reads in a track
|
|
22060
|
+
// function are emitted specially.
|
|
22061
|
+
op.track = transformExpressionsInExpression(op.track, expr => {
|
|
22062
|
+
if (expr instanceof ContextExpr) {
|
|
22063
|
+
op.usesComponentInstance = true;
|
|
22064
|
+
return new TrackContextExpr(expr.view);
|
|
22065
|
+
}
|
|
22066
|
+
return expr;
|
|
22067
|
+
}, VisitorContextFlag.None);
|
|
22068
|
+
}
|
|
22069
|
+
}
|
|
22070
|
+
}
|
|
22071
|
+
}
|
|
22072
|
+
function isTrackByFunctionCall(rootView, expr) {
|
|
22073
|
+
if (!(expr instanceof InvokeFunctionExpr) || expr.args.length !== 2) {
|
|
22074
|
+
return false;
|
|
22075
|
+
}
|
|
22076
|
+
if (!(expr.receiver instanceof ReadPropExpr &&
|
|
22077
|
+
expr.receiver.receiver instanceof ContextExpr) ||
|
|
22078
|
+
expr.receiver.receiver.view !== rootView) {
|
|
22079
|
+
return false;
|
|
22080
|
+
}
|
|
22081
|
+
const [arg0, arg1] = expr.args;
|
|
22082
|
+
if (!(arg0 instanceof ReadVarExpr) || arg0.name !== '$index') {
|
|
22083
|
+
return false;
|
|
22084
|
+
}
|
|
22085
|
+
if (!(arg1 instanceof ReadVarExpr) || arg1.name !== '$item') {
|
|
22086
|
+
return false;
|
|
22087
|
+
}
|
|
22088
|
+
return true;
|
|
22089
|
+
}
|
|
22090
|
+
|
|
22091
|
+
/**
|
|
22092
|
+
* Inside the `track` expression on a `for` repeater, the `$index` and `$item` variables are
|
|
22093
|
+
* ambiently available. In this phase, we find those variable usages, and replace them with the
|
|
22094
|
+
* appropriate output read.
|
|
22095
|
+
*/
|
|
22096
|
+
function generateTrackVariables(job) {
|
|
22097
|
+
for (const unit of job.units) {
|
|
22098
|
+
for (const op of unit.create) {
|
|
22099
|
+
if (op.kind !== OpKind.RepeaterCreate) {
|
|
22100
|
+
continue;
|
|
22101
|
+
}
|
|
22102
|
+
op.track = transformExpressionsInExpression(op.track, expr => {
|
|
22103
|
+
if (expr instanceof LexicalReadExpr) {
|
|
22104
|
+
if (expr.name === op.varNames.$index) {
|
|
22105
|
+
return variable('$index');
|
|
22106
|
+
}
|
|
22107
|
+
else if (expr.name === op.varNames.$implicit) {
|
|
22108
|
+
return variable('$item');
|
|
22109
|
+
}
|
|
22110
|
+
// TODO: handle prohibited context variables (emit as globals?)
|
|
22111
|
+
}
|
|
22112
|
+
return expr;
|
|
22113
|
+
}, VisitorContextFlag.None);
|
|
22114
|
+
}
|
|
22115
|
+
}
|
|
22116
|
+
}
|
|
22117
|
+
|
|
21735
22118
|
/**
|
|
21736
22119
|
* Counts the number of variable slots used within each view, and stores that on the view itself, as
|
|
21737
22120
|
* well as propagates it to the `ir.TemplateOp` for embedded views.
|
|
21738
22121
|
*/
|
|
21739
|
-
function
|
|
22122
|
+
function countVariables(job) {
|
|
21740
22123
|
// First, count the vars used in each view, and update the view-level counter.
|
|
21741
22124
|
for (const unit of job.units) {
|
|
21742
22125
|
let varCount = 0;
|
|
@@ -21881,7 +22264,7 @@ function isSingletonInterpolation(expr) {
|
|
|
21881
22264
|
* To guarantee correctness, analysis of "fences" in the instruction lists is used to determine
|
|
21882
22265
|
* which optimizations are safe to perform.
|
|
21883
22266
|
*/
|
|
21884
|
-
function
|
|
22267
|
+
function optimizeVariables(job) {
|
|
21885
22268
|
for (const unit of job.units) {
|
|
21886
22269
|
inlineAlwaysInlineVariables(unit.create);
|
|
21887
22270
|
inlineAlwaysInlineVariables(unit.update);
|
|
@@ -21923,7 +22306,7 @@ var Fence;
|
|
|
21923
22306
|
* Note that all `ContextWrite` fences are implicitly `ContextRead` fences as operations which
|
|
21924
22307
|
* change the view context do so based on the current one.
|
|
21925
22308
|
*/
|
|
21926
|
-
Fence[Fence["ViewContextWrite"] =
|
|
22309
|
+
Fence[Fence["ViewContextWrite"] = 2] = "ViewContextWrite";
|
|
21927
22310
|
/**
|
|
21928
22311
|
* Indicates that a call is required for its side-effects, even if nothing reads its result.
|
|
21929
22312
|
*
|
|
@@ -22103,9 +22486,9 @@ function optimizeVariablesInOpList(ops, compatibility) {
|
|
|
22103
22486
|
function fencesForIrExpression(expr) {
|
|
22104
22487
|
switch (expr.kind) {
|
|
22105
22488
|
case ExpressionKind.NextContext:
|
|
22106
|
-
return Fence.ViewContextWrite;
|
|
22489
|
+
return Fence.ViewContextRead | Fence.ViewContextWrite;
|
|
22107
22490
|
case ExpressionKind.RestoreView:
|
|
22108
|
-
return Fence.ViewContextWrite | Fence.SideEffectful;
|
|
22491
|
+
return Fence.ViewContextRead | Fence.ViewContextWrite | Fence.SideEffectful;
|
|
22109
22492
|
case ExpressionKind.Reference:
|
|
22110
22493
|
return Fence.ViewContextRead;
|
|
22111
22494
|
default:
|
|
@@ -22277,7 +22660,7 @@ function allowConservativeInlining(decl, target) {
|
|
|
22277
22660
|
/**
|
|
22278
22661
|
* Wraps ICUs that do not already belong to an i18n block in a new i18n block.
|
|
22279
22662
|
*/
|
|
22280
|
-
function
|
|
22663
|
+
function wrapI18nIcus(job) {
|
|
22281
22664
|
for (const unit of job.units) {
|
|
22282
22665
|
let currentI18nOp = null;
|
|
22283
22666
|
for (const op of unit.create) {
|
|
@@ -22300,133 +22683,6 @@ function phaseWrapIcus(job) {
|
|
|
22300
22683
|
}
|
|
22301
22684
|
}
|
|
22302
22685
|
|
|
22303
|
-
function phaseTrackVariables(job) {
|
|
22304
|
-
for (const unit of job.units) {
|
|
22305
|
-
for (const op of unit.create) {
|
|
22306
|
-
if (op.kind !== OpKind.RepeaterCreate) {
|
|
22307
|
-
continue;
|
|
22308
|
-
}
|
|
22309
|
-
op.track = transformExpressionsInExpression(op.track, expr => {
|
|
22310
|
-
if (expr instanceof LexicalReadExpr) {
|
|
22311
|
-
if (expr.name === op.varNames.$index) {
|
|
22312
|
-
return variable('$index');
|
|
22313
|
-
}
|
|
22314
|
-
else if (expr.name === op.varNames.$implicit) {
|
|
22315
|
-
return variable('$item');
|
|
22316
|
-
}
|
|
22317
|
-
// TODO: handle prohibited context variables (emit as globals?)
|
|
22318
|
-
}
|
|
22319
|
-
return expr;
|
|
22320
|
-
}, VisitorContextFlag.None);
|
|
22321
|
-
}
|
|
22322
|
-
}
|
|
22323
|
-
}
|
|
22324
|
-
|
|
22325
|
-
/**
|
|
22326
|
-
* Generate track functions that need to be extracted to the constant pool. This entails wrapping
|
|
22327
|
-
* them in an arrow (or traditional) function, replacing context reads with `this.`, and storing
|
|
22328
|
-
* them in the constant pool.
|
|
22329
|
-
*
|
|
22330
|
-
* Note that, if a track function was previously optimized, it will not need to be extracted, and
|
|
22331
|
-
* this phase is a no-op.
|
|
22332
|
-
*/
|
|
22333
|
-
function phaseTrackFnGeneration(job) {
|
|
22334
|
-
for (const unit of job.units) {
|
|
22335
|
-
for (const op of unit.create) {
|
|
22336
|
-
if (op.kind !== OpKind.RepeaterCreate) {
|
|
22337
|
-
continue;
|
|
22338
|
-
}
|
|
22339
|
-
if (op.trackByFn !== null) {
|
|
22340
|
-
// The final track function was already set, probably because it was optimized.
|
|
22341
|
-
continue;
|
|
22342
|
-
}
|
|
22343
|
-
// Find all component context reads.
|
|
22344
|
-
let usesComponentContext = false;
|
|
22345
|
-
op.track = transformExpressionsInExpression(op.track, expr => {
|
|
22346
|
-
if (expr instanceof TrackContextExpr) {
|
|
22347
|
-
usesComponentContext = true;
|
|
22348
|
-
return variable('this');
|
|
22349
|
-
}
|
|
22350
|
-
return expr;
|
|
22351
|
-
}, VisitorContextFlag.None);
|
|
22352
|
-
let fn;
|
|
22353
|
-
const fnParams = [new FnParam('$index'), new FnParam('$item')];
|
|
22354
|
-
if (usesComponentContext) {
|
|
22355
|
-
fn = new FunctionExpr(fnParams, [new ReturnStatement(op.track)]);
|
|
22356
|
-
}
|
|
22357
|
-
else {
|
|
22358
|
-
fn = arrowFn(fnParams, op.track);
|
|
22359
|
-
}
|
|
22360
|
-
op.trackByFn = job.pool.getSharedFunctionReference(fn, '_forTrack');
|
|
22361
|
-
}
|
|
22362
|
-
}
|
|
22363
|
-
}
|
|
22364
|
-
|
|
22365
|
-
function phaseTrackFnOptimization(job) {
|
|
22366
|
-
for (const unit of job.units) {
|
|
22367
|
-
for (const op of unit.create) {
|
|
22368
|
-
if (op.kind !== OpKind.RepeaterCreate) {
|
|
22369
|
-
continue;
|
|
22370
|
-
}
|
|
22371
|
-
if (op.track instanceof ReadVarExpr && op.track.name === '$index') {
|
|
22372
|
-
// Top-level access of `$index` uses the built in `repeaterTrackByIndex`.
|
|
22373
|
-
op.trackByFn = importExpr(Identifiers.repeaterTrackByIndex);
|
|
22374
|
-
}
|
|
22375
|
-
else if (op.track instanceof ReadVarExpr && op.track.name === '$item') {
|
|
22376
|
-
// Top-level access of the item uses the built in `repeaterTrackByIdentity`.
|
|
22377
|
-
op.trackByFn = importExpr(Identifiers.repeaterTrackByIdentity);
|
|
22378
|
-
}
|
|
22379
|
-
else if (isTrackByFunctionCall(job.root.xref, op.track)) {
|
|
22380
|
-
// Top-level method calls in the form of `fn($index, item)` can be passed in directly.
|
|
22381
|
-
if (op.track.receiver.receiver.view === unit.xref) {
|
|
22382
|
-
// TODO: this may be wrong
|
|
22383
|
-
op.trackByFn = op.track.receiver;
|
|
22384
|
-
}
|
|
22385
|
-
else {
|
|
22386
|
-
// This is a plain method call, but not in the component's root view.
|
|
22387
|
-
// We need to get the component instance, and then call the method on it.
|
|
22388
|
-
op.trackByFn =
|
|
22389
|
-
importExpr(Identifiers.componentInstance).callFn([]).prop(op.track.receiver.name);
|
|
22390
|
-
// Because the context is not avaiable (without a special function), we don't want to
|
|
22391
|
-
// try to resolve it later. Let's get rid of it by overwriting the original track
|
|
22392
|
-
// expression (which won't be used anyway).
|
|
22393
|
-
op.track = op.trackByFn;
|
|
22394
|
-
}
|
|
22395
|
-
}
|
|
22396
|
-
else {
|
|
22397
|
-
// The track function could not be optimized.
|
|
22398
|
-
// Replace context reads with a special IR expression, since context reads in a track
|
|
22399
|
-
// function are emitted specially.
|
|
22400
|
-
op.track = transformExpressionsInExpression(op.track, expr => {
|
|
22401
|
-
if (expr instanceof ContextExpr) {
|
|
22402
|
-
op.usesComponentInstance = true;
|
|
22403
|
-
return new TrackContextExpr(expr.view);
|
|
22404
|
-
}
|
|
22405
|
-
return expr;
|
|
22406
|
-
}, VisitorContextFlag.None);
|
|
22407
|
-
}
|
|
22408
|
-
}
|
|
22409
|
-
}
|
|
22410
|
-
}
|
|
22411
|
-
function isTrackByFunctionCall(rootView, expr) {
|
|
22412
|
-
if (!(expr instanceof InvokeFunctionExpr) || expr.args.length !== 2) {
|
|
22413
|
-
return false;
|
|
22414
|
-
}
|
|
22415
|
-
if (!(expr.receiver instanceof ReadPropExpr &&
|
|
22416
|
-
expr.receiver.receiver instanceof ContextExpr) ||
|
|
22417
|
-
expr.receiver.receiver.view !== rootView) {
|
|
22418
|
-
return false;
|
|
22419
|
-
}
|
|
22420
|
-
const [arg0, arg1] = expr.args;
|
|
22421
|
-
if (!(arg0 instanceof ReadVarExpr) || arg0.name !== '$index') {
|
|
22422
|
-
return false;
|
|
22423
|
-
}
|
|
22424
|
-
if (!(arg1 instanceof ReadVarExpr) || arg1.name !== '$item') {
|
|
22425
|
-
return false;
|
|
22426
|
-
}
|
|
22427
|
-
return true;
|
|
22428
|
-
}
|
|
22429
|
-
|
|
22430
22686
|
/**
|
|
22431
22687
|
*
|
|
22432
22688
|
* @license
|
|
@@ -22436,59 +22692,64 @@ function isTrackByFunctionCall(rootView, expr) {
|
|
|
22436
22692
|
* found in the LICENSE file at https://angular.io/license
|
|
22437
22693
|
*/
|
|
22438
22694
|
const phases = [
|
|
22439
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22440
|
-
{ kind: CompilationJobKind.Host, fn:
|
|
22441
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22442
|
-
{ kind: CompilationJobKind.Both, fn:
|
|
22443
|
-
{ kind: CompilationJobKind.Both, fn:
|
|
22444
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22445
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22446
|
-
{ kind: CompilationJobKind.Both, fn:
|
|
22447
|
-
{ kind: CompilationJobKind.Both, fn:
|
|
22448
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22449
|
-
{ kind: CompilationJobKind.Both, fn:
|
|
22450
|
-
{ kind: CompilationJobKind.Both, fn:
|
|
22451
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22452
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22453
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22454
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22455
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22456
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22457
|
-
{ kind: CompilationJobKind.
|
|
22458
|
-
{ kind: CompilationJobKind.
|
|
22459
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22460
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22461
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22462
|
-
{ kind: CompilationJobKind.
|
|
22463
|
-
{ kind: CompilationJobKind.
|
|
22464
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22465
|
-
{ kind: CompilationJobKind.
|
|
22466
|
-
{ kind: CompilationJobKind.
|
|
22467
|
-
{ kind: CompilationJobKind.
|
|
22468
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22469
|
-
{ kind: CompilationJobKind.
|
|
22470
|
-
{ kind: CompilationJobKind.
|
|
22471
|
-
{ kind: CompilationJobKind.
|
|
22472
|
-
{ kind: CompilationJobKind.Both, fn:
|
|
22473
|
-
{ kind: CompilationJobKind.
|
|
22474
|
-
{ kind: CompilationJobKind.
|
|
22475
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22476
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22477
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22478
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22479
|
-
{ kind: CompilationJobKind.
|
|
22480
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22481
|
-
{ kind: CompilationJobKind.
|
|
22482
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22483
|
-
{ kind: CompilationJobKind.
|
|
22484
|
-
{ kind: CompilationJobKind.Both, fn:
|
|
22485
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22486
|
-
{ kind: CompilationJobKind.
|
|
22487
|
-
{ kind: CompilationJobKind.Tmpl, fn:
|
|
22488
|
-
{ kind: CompilationJobKind.
|
|
22489
|
-
{ kind: CompilationJobKind.Both, fn:
|
|
22490
|
-
{ kind: CompilationJobKind.
|
|
22491
|
-
{ kind: CompilationJobKind.
|
|
22695
|
+
{ kind: CompilationJobKind.Tmpl, fn: removeContentSelectors },
|
|
22696
|
+
{ kind: CompilationJobKind.Host, fn: parseHostStyleProperties },
|
|
22697
|
+
{ kind: CompilationJobKind.Tmpl, fn: emitNamespaceChanges },
|
|
22698
|
+
{ kind: CompilationJobKind.Both, fn: specializeStyleBindings },
|
|
22699
|
+
{ kind: CompilationJobKind.Both, fn: specializeBindings },
|
|
22700
|
+
{ kind: CompilationJobKind.Tmpl, fn: propagateI18nBlocks },
|
|
22701
|
+
{ kind: CompilationJobKind.Tmpl, fn: wrapI18nIcus },
|
|
22702
|
+
{ kind: CompilationJobKind.Both, fn: extractAttributes },
|
|
22703
|
+
{ kind: CompilationJobKind.Both, fn: parseExtractedStyles },
|
|
22704
|
+
{ kind: CompilationJobKind.Tmpl, fn: removeEmptyBindings },
|
|
22705
|
+
{ kind: CompilationJobKind.Both, fn: collapseSingletonInterpolations },
|
|
22706
|
+
{ kind: CompilationJobKind.Both, fn: orderOps },
|
|
22707
|
+
{ kind: CompilationJobKind.Tmpl, fn: generateConditionalExpressions },
|
|
22708
|
+
{ kind: CompilationJobKind.Tmpl, fn: createPipes },
|
|
22709
|
+
{ kind: CompilationJobKind.Tmpl, fn: configureDeferInstructions },
|
|
22710
|
+
{ kind: CompilationJobKind.Tmpl, fn: extractI18nText },
|
|
22711
|
+
{ kind: CompilationJobKind.Tmpl, fn: extractI18nICUs },
|
|
22712
|
+
{ kind: CompilationJobKind.Tmpl, fn: applyI18nExpressions },
|
|
22713
|
+
{ kind: CompilationJobKind.Tmpl, fn: createVariadicPipes },
|
|
22714
|
+
{ kind: CompilationJobKind.Both, fn: generatePureLiteralStructures },
|
|
22715
|
+
{ kind: CompilationJobKind.Tmpl, fn: generateProjectionDefs },
|
|
22716
|
+
{ kind: CompilationJobKind.Tmpl, fn: generateVariables },
|
|
22717
|
+
{ kind: CompilationJobKind.Tmpl, fn: saveAndRestoreView },
|
|
22718
|
+
{ kind: CompilationJobKind.Tmpl, fn: deleteAnyCasts },
|
|
22719
|
+
{ kind: CompilationJobKind.Both, fn: resolveDollarEvent },
|
|
22720
|
+
{ kind: CompilationJobKind.Tmpl, fn: generateRepeaterDerivedVars },
|
|
22721
|
+
{ kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
|
|
22722
|
+
{ kind: CompilationJobKind.Both, fn: resolveNames },
|
|
22723
|
+
{ kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
|
|
22724
|
+
{ kind: CompilationJobKind.Tmpl, fn: optimizeTrackFns },
|
|
22725
|
+
{ kind: CompilationJobKind.Both, fn: resolveContexts },
|
|
22726
|
+
{ kind: CompilationJobKind.Tmpl, fn: resolveSanitizers },
|
|
22727
|
+
{ kind: CompilationJobKind.Tmpl, fn: liftLocalRefs },
|
|
22728
|
+
{ kind: CompilationJobKind.Both, fn: generateNullishCoalesceExpressions },
|
|
22729
|
+
{ kind: CompilationJobKind.Both, fn: expandSafeReads },
|
|
22730
|
+
{ kind: CompilationJobKind.Both, fn: generateTemporaryVariables },
|
|
22731
|
+
{ kind: CompilationJobKind.Tmpl, fn: allocateSlots },
|
|
22732
|
+
{ kind: CompilationJobKind.Tmpl, fn: extractI18nMessages },
|
|
22733
|
+
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nElementPlaceholders },
|
|
22734
|
+
{ kind: CompilationJobKind.Tmpl, fn: resolveI18nExpressionPlaceholders },
|
|
22735
|
+
{ kind: CompilationJobKind.Tmpl, fn: propogateI18nPlaceholders },
|
|
22736
|
+
{ kind: CompilationJobKind.Tmpl, fn: formatI18nParams },
|
|
22737
|
+
{ kind: CompilationJobKind.Tmpl, fn: generateTrackFns },
|
|
22738
|
+
{ kind: CompilationJobKind.Tmpl, fn: collectI18nConsts },
|
|
22739
|
+
{ kind: CompilationJobKind.Tmpl, fn: collectConstExpressions },
|
|
22740
|
+
{ kind: CompilationJobKind.Both, fn: collectElementConsts },
|
|
22741
|
+
{ kind: CompilationJobKind.Tmpl, fn: assignI18nSlotDependencies },
|
|
22742
|
+
{ kind: CompilationJobKind.Both, fn: countVariables },
|
|
22743
|
+
{ kind: CompilationJobKind.Tmpl, fn: generateAdvance },
|
|
22744
|
+
{ kind: CompilationJobKind.Both, fn: optimizeVariables },
|
|
22745
|
+
{ kind: CompilationJobKind.Both, fn: nameFunctionsAndVariables },
|
|
22746
|
+
{ kind: CompilationJobKind.Tmpl, fn: mergeNextContextExpressions },
|
|
22747
|
+
{ kind: CompilationJobKind.Tmpl, fn: generateNgContainerOps },
|
|
22748
|
+
{ kind: CompilationJobKind.Tmpl, fn: collapseEmptyInstructions },
|
|
22749
|
+
{ kind: CompilationJobKind.Tmpl, fn: disableBindings$1 },
|
|
22750
|
+
{ kind: CompilationJobKind.Both, fn: extractPureFunctions },
|
|
22751
|
+
{ kind: CompilationJobKind.Both, fn: reify },
|
|
22752
|
+
{ kind: CompilationJobKind.Both, fn: chain },
|
|
22492
22753
|
];
|
|
22493
22754
|
/**
|
|
22494
22755
|
* Run all transformation phases in the correct order against a compilation job. After this
|
|
@@ -22604,9 +22865,9 @@ const compatibilityMode = CompatibilityMode.TemplateDefinitionBuilder;
|
|
|
22604
22865
|
* TODO: Refactor more of the ingestion code into phases.
|
|
22605
22866
|
*/
|
|
22606
22867
|
function ingestComponent(componentName, template, constantPool, relativeContextFilePath, i18nUseExternalIds) {
|
|
22607
|
-
const
|
|
22608
|
-
ingestNodes(
|
|
22609
|
-
return
|
|
22868
|
+
const job = new ComponentCompilationJob(componentName, constantPool, compatibilityMode, relativeContextFilePath, i18nUseExternalIds);
|
|
22869
|
+
ingestNodes(job.root, template);
|
|
22870
|
+
return job;
|
|
22610
22871
|
}
|
|
22611
22872
|
/**
|
|
22612
22873
|
* Process a host binding AST and convert it into a `HostBindingCompilationJob` in the intermediate
|
|
@@ -22654,7 +22915,7 @@ function ingestHostAttribute(job, name, value) {
|
|
|
22654
22915
|
job.root.update.push(attrBinding);
|
|
22655
22916
|
}
|
|
22656
22917
|
function ingestHostEvent(job, event) {
|
|
22657
|
-
const eventBinding = createListenerOp(job.root.xref, event.name, null, event.targetOrPhase, true, event.sourceSpan);
|
|
22918
|
+
const eventBinding = createListenerOp(job.root.xref, new SlotHandle(), event.name, null, event.targetOrPhase, true, event.sourceSpan);
|
|
22658
22919
|
// TODO: Can this be a chain?
|
|
22659
22920
|
eventBinding.handlerOps.push(createStatementOp(new ReturnStatement(convertAst(event.handler.ast, job, event.sourceSpan), event.handlerSpan)));
|
|
22660
22921
|
job.root.create.push(eventBinding);
|
|
@@ -22707,10 +22968,6 @@ function ingestElement(unit, element) {
|
|
|
22707
22968
|
!(element.i18n instanceof Message || element.i18n instanceof TagPlaceholder)) {
|
|
22708
22969
|
throw Error(`Unhandled i18n metadata type for element: ${element.i18n.constructor.name}`);
|
|
22709
22970
|
}
|
|
22710
|
-
const staticAttributes = {};
|
|
22711
|
-
for (const attr of element.attributes) {
|
|
22712
|
-
staticAttributes[attr.name] = attr.value;
|
|
22713
|
-
}
|
|
22714
22971
|
const id = unit.job.allocateXrefId();
|
|
22715
22972
|
const [namespaceKey, elementName] = splitNsName(element.name);
|
|
22716
22973
|
const startOp = createElementStartOp(elementName, id, namespaceForKey(namespaceKey), element.i18n instanceof TagPlaceholder ? element.i18n : undefined, element.startSourceSpan);
|
|
@@ -22742,7 +22999,11 @@ function ingestTemplate(unit, tmpl) {
|
|
|
22742
22999
|
[namespacePrefix, tagNameWithoutNamespace] = splitNsName(tmpl.tagName);
|
|
22743
23000
|
}
|
|
22744
23001
|
const i18nPlaceholder = tmpl.i18n instanceof TagPlaceholder ? tmpl.i18n : undefined;
|
|
22745
|
-
const
|
|
23002
|
+
const namespace = namespaceForKey(namespacePrefix);
|
|
23003
|
+
const functionNameSuffix = tagNameWithoutNamespace === null ?
|
|
23004
|
+
'' :
|
|
23005
|
+
prefixWithNamespace(tagNameWithoutNamespace, namespace);
|
|
23006
|
+
const tplOp = createTemplateOp(childView.xref, tagNameWithoutNamespace, functionNameSuffix, namespace, i18nPlaceholder, tmpl.startSourceSpan);
|
|
22746
23007
|
unit.create.push(tplOp);
|
|
22747
23008
|
ingestBindings(unit, tplOp, tmpl);
|
|
22748
23009
|
ingestReferences(tplOp, tmpl);
|
|
@@ -22805,22 +23066,32 @@ function ingestBoundText(unit, text) {
|
|
|
22805
23066
|
*/
|
|
22806
23067
|
function ingestIfBlock(unit, ifBlock) {
|
|
22807
23068
|
let firstXref = null;
|
|
23069
|
+
let firstSlotHandle = null;
|
|
22808
23070
|
let conditions = [];
|
|
22809
|
-
for (
|
|
23071
|
+
for (let i = 0; i < ifBlock.branches.length; i++) {
|
|
23072
|
+
const ifCase = ifBlock.branches[i];
|
|
22810
23073
|
const cView = unit.job.allocateView(unit.xref);
|
|
23074
|
+
let tagName = null;
|
|
23075
|
+
// Only the first branch can be used for projection, because the conditional
|
|
23076
|
+
// uses the container of the first branch as the insertion point for all branches.
|
|
23077
|
+
if (i === 0) {
|
|
23078
|
+
tagName = ingestControlFlowInsertionPoint(unit, cView.xref, ifCase);
|
|
23079
|
+
}
|
|
22811
23080
|
if (ifCase.expressionAlias !== null) {
|
|
22812
23081
|
cView.contextVariables.set(ifCase.expressionAlias.name, CTX_REF);
|
|
22813
23082
|
}
|
|
23083
|
+
const tmplOp = createTemplateOp(cView.xref, tagName, 'Conditional', Namespace.HTML, undefined /* TODO: figure out how i18n works with new control flow */, ifCase.sourceSpan);
|
|
23084
|
+
unit.create.push(tmplOp);
|
|
22814
23085
|
if (firstXref === null) {
|
|
22815
23086
|
firstXref = cView.xref;
|
|
23087
|
+
firstSlotHandle = tmplOp.handle;
|
|
22816
23088
|
}
|
|
22817
|
-
unit.create.push(createTemplateOp(cView.xref, 'Conditional', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, ifCase.sourceSpan));
|
|
22818
23089
|
const caseExpr = ifCase.expression ? convertAst(ifCase.expression, unit.job, null) : null;
|
|
22819
|
-
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr,
|
|
23090
|
+
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, tmplOp.xref, tmplOp.handle, ifCase.expressionAlias);
|
|
22820
23091
|
conditions.push(conditionalCaseExpr);
|
|
22821
23092
|
ingestNodes(cView, ifCase.children);
|
|
22822
23093
|
}
|
|
22823
|
-
const conditional = createConditionalOp(firstXref, null, conditions, ifBlock.sourceSpan);
|
|
23094
|
+
const conditional = createConditionalOp(firstXref, firstSlotHandle, null, conditions, ifBlock.sourceSpan);
|
|
22824
23095
|
unit.update.push(conditional);
|
|
22825
23096
|
}
|
|
22826
23097
|
/**
|
|
@@ -22828,21 +23099,24 @@ function ingestIfBlock(unit, ifBlock) {
|
|
|
22828
23099
|
*/
|
|
22829
23100
|
function ingestSwitchBlock(unit, switchBlock) {
|
|
22830
23101
|
let firstXref = null;
|
|
23102
|
+
let firstSlotHandle = null;
|
|
22831
23103
|
let conditions = [];
|
|
22832
23104
|
for (const switchCase of switchBlock.cases) {
|
|
22833
23105
|
const cView = unit.job.allocateView(unit.xref);
|
|
23106
|
+
const tmplOp = createTemplateOp(cView.xref, null, 'Case', Namespace.HTML, undefined /* TODO: figure out how i18n works with new control flow */, switchCase.sourceSpan);
|
|
23107
|
+
unit.create.push(tmplOp);
|
|
22834
23108
|
if (firstXref === null) {
|
|
22835
23109
|
firstXref = cView.xref;
|
|
23110
|
+
firstSlotHandle = tmplOp.handle;
|
|
22836
23111
|
}
|
|
22837
|
-
unit.create.push(createTemplateOp(cView.xref, 'Case', Namespace.HTML, true, undefined /* TODO: figure out how i18n works with new control flow */, switchCase.sourceSpan));
|
|
22838
23112
|
const caseExpr = switchCase.expression ?
|
|
22839
23113
|
convertAst(switchCase.expression, unit.job, switchBlock.startSourceSpan) :
|
|
22840
23114
|
null;
|
|
22841
|
-
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr,
|
|
23115
|
+
const conditionalCaseExpr = new ConditionalCaseExpr(caseExpr, tmplOp.xref, tmplOp.handle);
|
|
22842
23116
|
conditions.push(conditionalCaseExpr);
|
|
22843
23117
|
ingestNodes(cView, switchCase.children);
|
|
22844
23118
|
}
|
|
22845
|
-
const conditional = createConditionalOp(firstXref, convertAst(switchBlock.expression, unit.job, null), conditions, switchBlock.sourceSpan);
|
|
23119
|
+
const conditional = createConditionalOp(firstXref, firstSlotHandle, convertAst(switchBlock.expression, unit.job, null), conditions, switchBlock.sourceSpan);
|
|
22846
23120
|
unit.update.push(conditional);
|
|
22847
23121
|
}
|
|
22848
23122
|
function ingestDeferView(unit, suffix, children, sourceSpan) {
|
|
@@ -22851,7 +23125,7 @@ function ingestDeferView(unit, suffix, children, sourceSpan) {
|
|
|
22851
23125
|
}
|
|
22852
23126
|
const secondaryView = unit.job.allocateView(unit.xref);
|
|
22853
23127
|
ingestNodes(secondaryView, children);
|
|
22854
|
-
const templateOp = createTemplateOp(secondaryView.xref, `Defer${suffix}`, Namespace.HTML,
|
|
23128
|
+
const templateOp = createTemplateOp(secondaryView.xref, null, `Defer${suffix}`, Namespace.HTML, undefined, sourceSpan);
|
|
22855
23129
|
unit.create.push(templateOp);
|
|
22856
23130
|
return templateOp;
|
|
22857
23131
|
}
|
|
@@ -22862,32 +23136,74 @@ function ingestDeferBlock(unit, deferBlock) {
|
|
|
22862
23136
|
const placeholder = ingestDeferView(unit, 'Placeholder', deferBlock.placeholder?.children, deferBlock.placeholder?.sourceSpan);
|
|
22863
23137
|
const error = ingestDeferView(unit, 'Error', deferBlock.error?.children, deferBlock.error?.sourceSpan);
|
|
22864
23138
|
// Create the main defer op, and ops for all secondary views.
|
|
22865
|
-
const
|
|
23139
|
+
const deferXref = unit.job.allocateXrefId();
|
|
23140
|
+
const deferOp = createDeferOp(deferXref, main.xref, main.handle, deferBlock.sourceSpan);
|
|
23141
|
+
deferOp.placeholderView = placeholder?.xref ?? null;
|
|
23142
|
+
deferOp.placeholderSlot = placeholder?.handle ?? null;
|
|
23143
|
+
deferOp.loadingSlot = loading?.handle ?? null;
|
|
23144
|
+
deferOp.errorSlot = error?.handle ?? null;
|
|
23145
|
+
deferOp.placeholderMinimumTime = deferBlock.placeholder?.minimumTime ?? null;
|
|
23146
|
+
deferOp.loadingMinimumTime = deferBlock.loading?.minimumTime ?? null;
|
|
23147
|
+
deferOp.loadingAfterTime = deferBlock.loading?.afterTime ?? null;
|
|
22866
23148
|
unit.create.push(deferOp);
|
|
22867
|
-
|
|
22868
|
-
|
|
22869
|
-
|
|
22870
|
-
|
|
22871
|
-
|
|
22872
|
-
|
|
22873
|
-
|
|
22874
|
-
|
|
22875
|
-
|
|
22876
|
-
|
|
22877
|
-
if (
|
|
22878
|
-
|
|
22879
|
-
|
|
22880
|
-
|
|
22881
|
-
|
|
22882
|
-
|
|
22883
|
-
|
|
22884
|
-
|
|
22885
|
-
|
|
22886
|
-
|
|
22887
|
-
|
|
22888
|
-
|
|
22889
|
-
|
|
22890
|
-
|
|
23149
|
+
// Configure all defer `on` conditions.
|
|
23150
|
+
// TODO: refactor prefetch triggers to use a separate op type, with a shared superclass. This will
|
|
23151
|
+
// make it easier to refactor prefetch behavior in the future.
|
|
23152
|
+
let prefetch = false;
|
|
23153
|
+
let deferOnOps = [];
|
|
23154
|
+
for (const triggers of [deferBlock.triggers, deferBlock.prefetchTriggers]) {
|
|
23155
|
+
if (triggers.idle !== undefined) {
|
|
23156
|
+
const deferOnOp = createDeferOnOp(deferXref, { kind: DeferTriggerKind.Idle }, prefetch, null);
|
|
23157
|
+
deferOnOps.push(deferOnOp);
|
|
23158
|
+
}
|
|
23159
|
+
if (triggers.immediate !== undefined) {
|
|
23160
|
+
const deferOnOp = createDeferOnOp(deferXref, { kind: DeferTriggerKind.Immediate }, prefetch, null);
|
|
23161
|
+
deferOnOps.push(deferOnOp);
|
|
23162
|
+
}
|
|
23163
|
+
if (triggers.timer !== undefined) {
|
|
23164
|
+
const deferOnOp = createDeferOnOp(deferXref, { kind: DeferTriggerKind.Timer, delay: triggers.timer.delay }, prefetch, null);
|
|
23165
|
+
deferOnOps.push(deferOnOp);
|
|
23166
|
+
}
|
|
23167
|
+
if (triggers.hover !== undefined) {
|
|
23168
|
+
const deferOnOp = createDeferOnOp(deferXref, {
|
|
23169
|
+
kind: DeferTriggerKind.Hover,
|
|
23170
|
+
targetName: triggers.hover.reference,
|
|
23171
|
+
targetXref: null,
|
|
23172
|
+
targetSlot: null,
|
|
23173
|
+
targetView: null,
|
|
23174
|
+
targetSlotViewSteps: null,
|
|
23175
|
+
}, prefetch, null);
|
|
23176
|
+
deferOnOps.push(deferOnOp);
|
|
23177
|
+
}
|
|
23178
|
+
if (triggers.interaction !== undefined) {
|
|
23179
|
+
const deferOnOp = createDeferOnOp(deferXref, {
|
|
23180
|
+
kind: DeferTriggerKind.Interaction,
|
|
23181
|
+
targetName: triggers.interaction.reference,
|
|
23182
|
+
targetXref: null,
|
|
23183
|
+
targetSlot: null,
|
|
23184
|
+
targetView: null,
|
|
23185
|
+
targetSlotViewSteps: null,
|
|
23186
|
+
}, prefetch, null);
|
|
23187
|
+
deferOnOps.push(deferOnOp);
|
|
23188
|
+
}
|
|
23189
|
+
if (triggers.viewport !== undefined) {
|
|
23190
|
+
const deferOnOp = createDeferOnOp(deferXref, {
|
|
23191
|
+
kind: DeferTriggerKind.Viewport,
|
|
23192
|
+
targetName: triggers.viewport.reference,
|
|
23193
|
+
targetXref: null,
|
|
23194
|
+
targetSlot: null,
|
|
23195
|
+
targetView: null,
|
|
23196
|
+
targetSlotViewSteps: null,
|
|
23197
|
+
}, prefetch, null);
|
|
23198
|
+
deferOnOps.push(deferOnOp);
|
|
23199
|
+
}
|
|
23200
|
+
// If no (non-prefetching) defer triggers were provided, default to `idle`.
|
|
23201
|
+
if (deferOnOps.length === 0) {
|
|
23202
|
+
deferOnOps.push(createDeferOnOp(deferXref, { kind: DeferTriggerKind.Idle }, false, null));
|
|
23203
|
+
}
|
|
23204
|
+
prefetch = true;
|
|
23205
|
+
}
|
|
23206
|
+
unit.create.push(deferOnOps);
|
|
22891
23207
|
}
|
|
22892
23208
|
function ingestIcu(unit, icu) {
|
|
22893
23209
|
if (icu.i18n instanceof Message) {
|
|
@@ -22937,10 +23253,11 @@ function ingestForBlock(unit, forBlock) {
|
|
|
22937
23253
|
$odd: forBlock.contextVariables.$odd.name,
|
|
22938
23254
|
$implicit: forBlock.item.name,
|
|
22939
23255
|
};
|
|
22940
|
-
const
|
|
23256
|
+
const tagName = ingestControlFlowInsertionPoint(unit, repeaterView.xref, forBlock);
|
|
23257
|
+
const repeaterCreate = createRepeaterCreateOp(repeaterView.xref, emptyView?.xref ?? null, tagName, track, varNames, forBlock.sourceSpan);
|
|
22941
23258
|
unit.create.push(repeaterCreate);
|
|
22942
23259
|
const expression = convertAst(forBlock.expression, unit.job, convertSourceSpan(forBlock.expression.span, forBlock.sourceSpan));
|
|
22943
|
-
const repeater = createRepeaterOp(repeaterCreate.xref, expression, forBlock.sourceSpan);
|
|
23260
|
+
const repeater = createRepeaterOp(repeaterCreate.xref, repeaterCreate.handle, expression, forBlock.sourceSpan);
|
|
22944
23261
|
unit.update.push(repeater);
|
|
22945
23262
|
}
|
|
22946
23263
|
/**
|
|
@@ -23014,7 +23331,7 @@ function convertAst(ast, job, baseSourceSpan) {
|
|
|
23014
23331
|
}
|
|
23015
23332
|
else if (ast instanceof BindingPipe) {
|
|
23016
23333
|
// TODO: pipes should probably have source maps; figure out details.
|
|
23017
|
-
return new PipeBindingExpr(job.allocateXrefId(), ast.name, [
|
|
23334
|
+
return new PipeBindingExpr(job.allocateXrefId(), new SlotHandle(), ast.name, [
|
|
23018
23335
|
convertAst(ast.exp, job, baseSourceSpan),
|
|
23019
23336
|
...ast.args.map(arg => convertAst(arg, job, baseSourceSpan)),
|
|
23020
23337
|
]);
|
|
@@ -23098,8 +23415,7 @@ function ingestBindings(unit, op, element) {
|
|
|
23098
23415
|
unit.create.push(createExtractedAttributeOp(op.xref, BindingKind.Property, output.name, null));
|
|
23099
23416
|
continue;
|
|
23100
23417
|
}
|
|
23101
|
-
listenerOp =
|
|
23102
|
-
createListenerOp(op.xref, output.name, op.tag, output.phase, false, output.sourceSpan);
|
|
23418
|
+
listenerOp = createListenerOp(op.xref, op.handle, output.name, op.tag, output.phase, false, output.sourceSpan);
|
|
23103
23419
|
// if output.handler is a chain, then push each statement from the chain separately, and
|
|
23104
23420
|
// return the last one?
|
|
23105
23421
|
let handlerExprs;
|
|
@@ -23220,6 +23536,57 @@ function convertSourceSpan(span, baseSourceSpan) {
|
|
|
23220
23536
|
const fullStart = baseSourceSpan.fullStart.moveBy(span.start);
|
|
23221
23537
|
return new ParseSourceSpan(start, end, fullStart);
|
|
23222
23538
|
}
|
|
23539
|
+
/**
|
|
23540
|
+
* With the directive-based control flow users were able to conditionally project content using
|
|
23541
|
+
* the `*` syntax. E.g. `<div *ngIf="expr" projectMe></div>` will be projected into
|
|
23542
|
+
* `<ng-content select="[projectMe]"/>`, because the attributes and tag name from the `div` are
|
|
23543
|
+
* copied to the template via the template creation instruction. With `@if` and `@for` that is
|
|
23544
|
+
* not the case, because the conditional is placed *around* elements, rather than *on* them.
|
|
23545
|
+
* The result is that content projection won't work in the same way if a user converts from
|
|
23546
|
+
* `*ngIf` to `@if`.
|
|
23547
|
+
*
|
|
23548
|
+
* This function aims to cover the most common case by doing the same copying when a control flow
|
|
23549
|
+
* node has *one and only one* root element or template node.
|
|
23550
|
+
*
|
|
23551
|
+
* This approach comes with some caveats:
|
|
23552
|
+
* 1. As soon as any other node is added to the root, the copying behavior won't work anymore.
|
|
23553
|
+
* A diagnostic will be added to flag cases like this and to explain how to work around it.
|
|
23554
|
+
* 2. If `preserveWhitespaces` is enabled, it's very likely that indentation will break this
|
|
23555
|
+
* workaround, because it'll include an additional text node as the first child. We can work
|
|
23556
|
+
* around it here, but in a discussion it was decided not to, because the user explicitly opted
|
|
23557
|
+
* into preserving the whitespace and we would have to drop it from the generated code.
|
|
23558
|
+
* The diagnostic mentioned point #1 will flag such cases to users.
|
|
23559
|
+
*
|
|
23560
|
+
* @returns Tag name to be used for the control flow template.
|
|
23561
|
+
*/
|
|
23562
|
+
function ingestControlFlowInsertionPoint(unit, xref, node) {
|
|
23563
|
+
let root = null;
|
|
23564
|
+
for (const child of node.children) {
|
|
23565
|
+
// Skip over comment nodes.
|
|
23566
|
+
if (child instanceof Comment$1) {
|
|
23567
|
+
continue;
|
|
23568
|
+
}
|
|
23569
|
+
// We can only infer the tag name/attributes if there's a single root node.
|
|
23570
|
+
if (root !== null) {
|
|
23571
|
+
return null;
|
|
23572
|
+
}
|
|
23573
|
+
// Root nodes can only elements or templates with a tag name (e.g. `<div *foo></div>`).
|
|
23574
|
+
if (child instanceof Element$1 || (child instanceof Template && child.tagName !== null)) {
|
|
23575
|
+
root = child;
|
|
23576
|
+
}
|
|
23577
|
+
}
|
|
23578
|
+
// If we've found a single root node, its tag name and *static* attributes can be copied
|
|
23579
|
+
// to the surrounding template to be used for content projection. Note that it's important
|
|
23580
|
+
// that we don't copy any bound attributes since they don't participate in content projection
|
|
23581
|
+
// and they can be used in directive matching (in the case of `Template.templateAttrs`).
|
|
23582
|
+
if (root !== null) {
|
|
23583
|
+
for (const attr of root.attributes) {
|
|
23584
|
+
ingestBinding(unit, xref, attr.name, literal(attr.value), 1 /* e.BindingType.Attribute */, null, SecurityContext.NONE, attr.sourceSpan, BindingFlags.TextValue);
|
|
23585
|
+
}
|
|
23586
|
+
return root instanceof Element$1 ? root.name : root.tagName;
|
|
23587
|
+
}
|
|
23588
|
+
return null;
|
|
23589
|
+
}
|
|
23223
23590
|
|
|
23224
23591
|
const USE_TEMPLATE_PIPELINE = false;
|
|
23225
23592
|
|
|
@@ -24356,7 +24723,7 @@ function normalizeNgContentSelect(selectAttr) {
|
|
|
24356
24723
|
}
|
|
24357
24724
|
|
|
24358
24725
|
/** Pattern for the expression in a for loop block. */
|
|
24359
|
-
const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+(
|
|
24726
|
+
const FOR_LOOP_EXPRESSION_PATTERN = /^\s*([0-9A-Za-z_$]*)\s+of\s+([\S\s]*)/;
|
|
24360
24727
|
/** Pattern for the tracking expression in a for loop block. */
|
|
24361
24728
|
const FOR_LOOP_TRACK_PATTERN = /^track\s+([\S\s]*)/;
|
|
24362
24729
|
/** Pattern for the `as` expression in a conditional block. */
|
|
@@ -24387,19 +24754,19 @@ function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
24387
24754
|
const branches = [];
|
|
24388
24755
|
const mainBlockParams = parseConditionalBlockParameters(ast, errors, bindingParser);
|
|
24389
24756
|
if (mainBlockParams !== null) {
|
|
24390
|
-
branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan));
|
|
24757
|
+
branches.push(new IfBlockBranch(mainBlockParams.expression, visitAll(visitor, ast.children, ast.children), mainBlockParams.expressionAlias, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan));
|
|
24391
24758
|
}
|
|
24392
24759
|
for (const block of connectedBlocks) {
|
|
24393
24760
|
if (ELSE_IF_PATTERN.test(block.name)) {
|
|
24394
24761
|
const params = parseConditionalBlockParameters(block, errors, bindingParser);
|
|
24395
24762
|
if (params !== null) {
|
|
24396
24763
|
const children = visitAll(visitor, block.children, block.children);
|
|
24397
|
-
branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan));
|
|
24764
|
+
branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan));
|
|
24398
24765
|
}
|
|
24399
24766
|
}
|
|
24400
24767
|
else if (block.name === 'else') {
|
|
24401
24768
|
const children = visitAll(visitor, block.children, block.children);
|
|
24402
|
-
branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan));
|
|
24769
|
+
branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan));
|
|
24403
24770
|
}
|
|
24404
24771
|
}
|
|
24405
24772
|
// The outer IfBlock should have a span that encapsulates all branches.
|
|
@@ -24411,7 +24778,7 @@ function createIfBlock(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
24411
24778
|
wholeSourceSpan = new ParseSourceSpan(ifBlockStartSourceSpan.start, lastBranch.sourceSpan.end);
|
|
24412
24779
|
}
|
|
24413
24780
|
return {
|
|
24414
|
-
node: new IfBlock(branches, wholeSourceSpan, ast.startSourceSpan, ifBlockEndSourceSpan),
|
|
24781
|
+
node: new IfBlock(branches, wholeSourceSpan, ast.startSourceSpan, ifBlockEndSourceSpan, ast.nameSpan),
|
|
24415
24782
|
errors,
|
|
24416
24783
|
};
|
|
24417
24784
|
}
|
|
@@ -24430,7 +24797,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
24430
24797
|
errors.push(new ParseError(block.sourceSpan, '@empty block cannot have parameters'));
|
|
24431
24798
|
}
|
|
24432
24799
|
else {
|
|
24433
|
-
empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan);
|
|
24800
|
+
empty = new ForLoopBlockEmpty(visitAll(visitor, block.children, block.children), block.sourceSpan, block.startSourceSpan, block.endSourceSpan, block.nameSpan);
|
|
24434
24801
|
}
|
|
24435
24802
|
}
|
|
24436
24803
|
else {
|
|
@@ -24448,7 +24815,7 @@ function createForLoop(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
24448
24815
|
// main `for` body, use `mainSourceSpan`.
|
|
24449
24816
|
const endSpan = empty?.endSourceSpan ?? ast.endSourceSpan;
|
|
24450
24817
|
const sourceSpan = new ParseSourceSpan(ast.sourceSpan.start, endSpan?.end ?? ast.sourceSpan.end);
|
|
24451
|
-
node = new ForLoopBlock(params.itemName, params.expression, params.trackBy, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan);
|
|
24818
|
+
node = new ForLoopBlock(params.itemName, params.expression, params.trackBy.expression, params.trackBy.keywordSpan, params.context, visitAll(visitor, ast.children, ast.children), empty, sourceSpan, ast.sourceSpan, ast.startSourceSpan, endSpan, ast.nameSpan);
|
|
24452
24819
|
}
|
|
24453
24820
|
}
|
|
24454
24821
|
return { node, errors };
|
|
@@ -24474,7 +24841,7 @@ function createSwitchBlock(ast, visitor, bindingParser) {
|
|
|
24474
24841
|
const expression = node.name === 'case' ?
|
|
24475
24842
|
parseBlockParameterToBinding(node.parameters[0], bindingParser) :
|
|
24476
24843
|
null;
|
|
24477
|
-
const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan);
|
|
24844
|
+
const ast = new SwitchBlockCase(expression, visitAll(visitor, node.children, node.children), node.sourceSpan, node.startSourceSpan, node.endSourceSpan, node.nameSpan);
|
|
24478
24845
|
if (expression === null) {
|
|
24479
24846
|
defaultCase = ast;
|
|
24480
24847
|
}
|
|
@@ -24487,7 +24854,7 @@ function createSwitchBlock(ast, visitor, bindingParser) {
|
|
|
24487
24854
|
cases.push(defaultCase);
|
|
24488
24855
|
}
|
|
24489
24856
|
return {
|
|
24490
|
-
node: new SwitchBlock(primaryExpression, cases, unknownBlocks, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan),
|
|
24857
|
+
node: new SwitchBlock(primaryExpression, cases, unknownBlocks, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan, ast.nameSpan),
|
|
24491
24858
|
errors
|
|
24492
24859
|
};
|
|
24493
24860
|
}
|
|
@@ -24522,7 +24889,9 @@ function parseForLoopParameters(block, errors, bindingParser) {
|
|
|
24522
24889
|
errors.push(new ParseError(param.sourceSpan, '@for loop can only have one "track" expression'));
|
|
24523
24890
|
}
|
|
24524
24891
|
else {
|
|
24525
|
-
|
|
24892
|
+
const expression = parseBlockParameterToBinding(param, bindingParser, trackMatch[1]);
|
|
24893
|
+
const keywordSpan = new ParseSourceSpan(param.sourceSpan.start, param.sourceSpan.start.moveBy('track'.length));
|
|
24894
|
+
result.trackBy = { expression, keywordSpan };
|
|
24526
24895
|
}
|
|
24527
24896
|
continue;
|
|
24528
24897
|
}
|
|
@@ -24596,8 +24965,10 @@ function validateSwitchBlock(ast) {
|
|
|
24596
24965
|
return errors;
|
|
24597
24966
|
}
|
|
24598
24967
|
for (const node of ast.children) {
|
|
24599
|
-
// Skip over empty text nodes inside the switch block
|
|
24600
|
-
|
|
24968
|
+
// Skip over comments and empty text nodes inside the switch block.
|
|
24969
|
+
// Empty text nodes can be used for formatting while comments don't affect the runtime.
|
|
24970
|
+
if (node instanceof Comment ||
|
|
24971
|
+
(node instanceof Text && node.value.trim().length === 0)) {
|
|
24601
24972
|
continue;
|
|
24602
24973
|
}
|
|
24603
24974
|
if (!(node instanceof Block) || (node.name !== 'case' && node.name !== 'default')) {
|
|
@@ -24720,7 +25091,7 @@ function stripOptionalParentheses(param, errors) {
|
|
|
24720
25091
|
}
|
|
24721
25092
|
|
|
24722
25093
|
/** Pattern for a timing value in a trigger. */
|
|
24723
|
-
const TIME_PATTERN = /^\d
|
|
25094
|
+
const TIME_PATTERN = /^\d+\.?\d*(ms|s)?$/;
|
|
24724
25095
|
/** Pattern for a separator between keywords in a trigger expression. */
|
|
24725
25096
|
const SEPARATOR_PATTERN = /^\s$/;
|
|
24726
25097
|
/** Pairs of characters that form syntax that is comma-delimited. */
|
|
@@ -24742,6 +25113,8 @@ var OnTriggerType;
|
|
|
24742
25113
|
/** Parses a `when` deferred trigger. */
|
|
24743
25114
|
function parseWhenTrigger({ expression, sourceSpan }, bindingParser, triggers, errors) {
|
|
24744
25115
|
const whenIndex = expression.indexOf('when');
|
|
25116
|
+
const whenSourceSpan = new ParseSourceSpan(sourceSpan.start.moveBy(whenIndex), sourceSpan.start.moveBy(whenIndex + 'when'.length));
|
|
25117
|
+
const prefetchSpan = getPrefetchSpan(expression, sourceSpan);
|
|
24745
25118
|
// This is here just to be safe, we shouldn't enter this function
|
|
24746
25119
|
// in the first place if a block doesn't have the "when" keyword.
|
|
24747
25120
|
if (whenIndex === -1) {
|
|
@@ -24750,12 +25123,14 @@ function parseWhenTrigger({ expression, sourceSpan }, bindingParser, triggers, e
|
|
|
24750
25123
|
else {
|
|
24751
25124
|
const start = getTriggerParametersStart(expression, whenIndex + 1);
|
|
24752
25125
|
const parsed = bindingParser.parseBinding(expression.slice(start), false, sourceSpan, sourceSpan.start.offset + start);
|
|
24753
|
-
trackTrigger('when', triggers, errors, new BoundDeferredTrigger(parsed, sourceSpan));
|
|
25126
|
+
trackTrigger('when', triggers, errors, new BoundDeferredTrigger(parsed, sourceSpan, prefetchSpan, whenSourceSpan));
|
|
24754
25127
|
}
|
|
24755
25128
|
}
|
|
24756
25129
|
/** Parses an `on` trigger */
|
|
24757
25130
|
function parseOnTrigger({ expression, sourceSpan }, triggers, errors, placeholder) {
|
|
24758
25131
|
const onIndex = expression.indexOf('on');
|
|
25132
|
+
const onSourceSpan = new ParseSourceSpan(sourceSpan.start.moveBy(onIndex), sourceSpan.start.moveBy(onIndex + 'on'.length));
|
|
25133
|
+
const prefetchSpan = getPrefetchSpan(expression, sourceSpan);
|
|
24759
25134
|
// This is here just to be safe, we shouldn't enter this function
|
|
24760
25135
|
// in the first place if a block doesn't have the "on" keyword.
|
|
24761
25136
|
if (onIndex === -1) {
|
|
@@ -24763,18 +25138,26 @@ function parseOnTrigger({ expression, sourceSpan }, triggers, errors, placeholde
|
|
|
24763
25138
|
}
|
|
24764
25139
|
else {
|
|
24765
25140
|
const start = getTriggerParametersStart(expression, onIndex + 1);
|
|
24766
|
-
const parser = new OnTriggerParser(expression, start, sourceSpan, triggers, errors, placeholder);
|
|
25141
|
+
const parser = new OnTriggerParser(expression, start, sourceSpan, triggers, errors, placeholder, prefetchSpan, onSourceSpan);
|
|
24767
25142
|
parser.parse();
|
|
24768
25143
|
}
|
|
24769
25144
|
}
|
|
25145
|
+
function getPrefetchSpan(expression, sourceSpan) {
|
|
25146
|
+
if (!expression.startsWith('prefetch')) {
|
|
25147
|
+
return null;
|
|
25148
|
+
}
|
|
25149
|
+
return new ParseSourceSpan(sourceSpan.start, sourceSpan.start.moveBy('prefetch'.length));
|
|
25150
|
+
}
|
|
24770
25151
|
class OnTriggerParser {
|
|
24771
|
-
constructor(expression, start, span, triggers, errors, placeholder) {
|
|
25152
|
+
constructor(expression, start, span, triggers, errors, placeholder, prefetchSpan, onSourceSpan) {
|
|
24772
25153
|
this.expression = expression;
|
|
24773
25154
|
this.start = start;
|
|
24774
25155
|
this.span = span;
|
|
24775
25156
|
this.triggers = triggers;
|
|
24776
25157
|
this.errors = errors;
|
|
24777
25158
|
this.placeholder = placeholder;
|
|
25159
|
+
this.prefetchSpan = prefetchSpan;
|
|
25160
|
+
this.onSourceSpan = onSourceSpan;
|
|
24778
25161
|
this.index = 0;
|
|
24779
25162
|
this.tokens = new Lexer().tokenize(expression.slice(start));
|
|
24780
25163
|
}
|
|
@@ -24820,28 +25203,35 @@ class OnTriggerParser {
|
|
|
24820
25203
|
return this.tokens[Math.min(this.index, this.tokens.length - 1)];
|
|
24821
25204
|
}
|
|
24822
25205
|
consumeTrigger(identifier, parameters) {
|
|
24823
|
-
const
|
|
24824
|
-
const
|
|
24825
|
-
const
|
|
25206
|
+
const triggerNameStartSpan = this.span.start.moveBy(this.start + identifier.index - this.tokens[0].index);
|
|
25207
|
+
const nameSpan = new ParseSourceSpan(triggerNameStartSpan, triggerNameStartSpan.moveBy(identifier.strValue.length));
|
|
25208
|
+
const endSpan = triggerNameStartSpan.moveBy(this.token().end - identifier.index);
|
|
25209
|
+
// Put the prefetch and on spans with the first trigger
|
|
25210
|
+
// This should maybe be refactored to have something like an outer OnGroup AST
|
|
25211
|
+
// Since triggers can be grouped with commas "on hover(x), interaction(y)"
|
|
25212
|
+
const isFirstTrigger = identifier.index === 0;
|
|
25213
|
+
const onSourceSpan = isFirstTrigger ? this.onSourceSpan : null;
|
|
25214
|
+
const prefetchSourceSpan = isFirstTrigger ? this.prefetchSpan : null;
|
|
25215
|
+
const sourceSpan = new ParseSourceSpan(isFirstTrigger ? this.span.start : triggerNameStartSpan, endSpan);
|
|
24826
25216
|
try {
|
|
24827
25217
|
switch (identifier.toString()) {
|
|
24828
25218
|
case OnTriggerType.IDLE:
|
|
24829
|
-
this.trackTrigger('idle', createIdleTrigger(parameters, sourceSpan));
|
|
25219
|
+
this.trackTrigger('idle', createIdleTrigger(parameters, nameSpan, sourceSpan, prefetchSourceSpan, onSourceSpan));
|
|
24830
25220
|
break;
|
|
24831
25221
|
case OnTriggerType.TIMER:
|
|
24832
|
-
this.trackTrigger('timer', createTimerTrigger(parameters, sourceSpan));
|
|
25222
|
+
this.trackTrigger('timer', createTimerTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan));
|
|
24833
25223
|
break;
|
|
24834
25224
|
case OnTriggerType.INTERACTION:
|
|
24835
|
-
this.trackTrigger('interaction', createInteractionTrigger(parameters, sourceSpan, this.placeholder));
|
|
25225
|
+
this.trackTrigger('interaction', createInteractionTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.placeholder));
|
|
24836
25226
|
break;
|
|
24837
25227
|
case OnTriggerType.IMMEDIATE:
|
|
24838
|
-
this.trackTrigger('immediate', createImmediateTrigger(parameters, sourceSpan));
|
|
25228
|
+
this.trackTrigger('immediate', createImmediateTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan));
|
|
24839
25229
|
break;
|
|
24840
25230
|
case OnTriggerType.HOVER:
|
|
24841
|
-
this.trackTrigger('hover', createHoverTrigger(parameters, sourceSpan, this.placeholder));
|
|
25231
|
+
this.trackTrigger('hover', createHoverTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.placeholder));
|
|
24842
25232
|
break;
|
|
24843
25233
|
case OnTriggerType.VIEWPORT:
|
|
24844
|
-
this.trackTrigger('viewport', createViewportTrigger(parameters, sourceSpan, this.placeholder));
|
|
25234
|
+
this.trackTrigger('viewport', createViewportTrigger(parameters, nameSpan, sourceSpan, this.prefetchSpan, this.onSourceSpan, this.placeholder));
|
|
24845
25235
|
break;
|
|
24846
25236
|
default:
|
|
24847
25237
|
throw new Error(`Unrecognized trigger type "${identifier}"`);
|
|
@@ -24931,13 +25321,13 @@ function trackTrigger(name, allTriggers, errors, trigger) {
|
|
|
24931
25321
|
allTriggers[name] = trigger;
|
|
24932
25322
|
}
|
|
24933
25323
|
}
|
|
24934
|
-
function createIdleTrigger(parameters, sourceSpan) {
|
|
25324
|
+
function createIdleTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
|
|
24935
25325
|
if (parameters.length > 0) {
|
|
24936
25326
|
throw new Error(`"${OnTriggerType.IDLE}" trigger cannot have parameters`);
|
|
24937
25327
|
}
|
|
24938
|
-
return new IdleDeferredTrigger(sourceSpan);
|
|
25328
|
+
return new IdleDeferredTrigger(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
24939
25329
|
}
|
|
24940
|
-
function createTimerTrigger(parameters, sourceSpan) {
|
|
25330
|
+
function createTimerTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
|
|
24941
25331
|
if (parameters.length !== 1) {
|
|
24942
25332
|
throw new Error(`"${OnTriggerType.TIMER}" trigger must have exactly one parameter`);
|
|
24943
25333
|
}
|
|
@@ -24945,25 +25335,25 @@ function createTimerTrigger(parameters, sourceSpan) {
|
|
|
24945
25335
|
if (delay === null) {
|
|
24946
25336
|
throw new Error(`Could not parse time value of trigger "${OnTriggerType.TIMER}"`);
|
|
24947
25337
|
}
|
|
24948
|
-
return new TimerDeferredTrigger(delay, sourceSpan);
|
|
25338
|
+
return new TimerDeferredTrigger(delay, nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
24949
25339
|
}
|
|
24950
|
-
function createImmediateTrigger(parameters, sourceSpan) {
|
|
25340
|
+
function createImmediateTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan) {
|
|
24951
25341
|
if (parameters.length > 0) {
|
|
24952
25342
|
throw new Error(`"${OnTriggerType.IMMEDIATE}" trigger cannot have parameters`);
|
|
24953
25343
|
}
|
|
24954
|
-
return new ImmediateDeferredTrigger(sourceSpan);
|
|
25344
|
+
return new ImmediateDeferredTrigger(nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
24955
25345
|
}
|
|
24956
|
-
function createHoverTrigger(parameters, sourceSpan, placeholder) {
|
|
25346
|
+
function createHoverTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, placeholder) {
|
|
24957
25347
|
validateReferenceBasedTrigger(OnTriggerType.HOVER, parameters, placeholder);
|
|
24958
|
-
return new HoverDeferredTrigger(parameters[0] ?? null, sourceSpan);
|
|
25348
|
+
return new HoverDeferredTrigger(parameters[0] ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
24959
25349
|
}
|
|
24960
|
-
function createInteractionTrigger(parameters, sourceSpan, placeholder) {
|
|
25350
|
+
function createInteractionTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, placeholder) {
|
|
24961
25351
|
validateReferenceBasedTrigger(OnTriggerType.INTERACTION, parameters, placeholder);
|
|
24962
|
-
return new InteractionDeferredTrigger(parameters[0] ?? null, sourceSpan);
|
|
25352
|
+
return new InteractionDeferredTrigger(parameters[0] ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
24963
25353
|
}
|
|
24964
|
-
function createViewportTrigger(parameters, sourceSpan, placeholder) {
|
|
25354
|
+
function createViewportTrigger(parameters, nameSpan, sourceSpan, prefetchSpan, onSourceSpan, placeholder) {
|
|
24965
25355
|
validateReferenceBasedTrigger(OnTriggerType.VIEWPORT, parameters, placeholder);
|
|
24966
|
-
return new ViewportDeferredTrigger(parameters[0] ?? null, sourceSpan);
|
|
25356
|
+
return new ViewportDeferredTrigger(parameters[0] ?? null, nameSpan, sourceSpan, prefetchSpan, onSourceSpan);
|
|
24967
25357
|
}
|
|
24968
25358
|
function validateReferenceBasedTrigger(type, parameters, placeholder) {
|
|
24969
25359
|
if (parameters.length > 1) {
|
|
@@ -25002,7 +25392,7 @@ function parseDeferredTime(value) {
|
|
|
25002
25392
|
return null;
|
|
25003
25393
|
}
|
|
25004
25394
|
const [time, units] = match;
|
|
25005
|
-
return
|
|
25395
|
+
return parseFloat(time) * (units === 's' ? 1000 : 1);
|
|
25006
25396
|
}
|
|
25007
25397
|
|
|
25008
25398
|
/** Pattern to identify a `prefetch when` trigger. */
|
|
@@ -25029,8 +25419,7 @@ function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
25029
25419
|
const errors = [];
|
|
25030
25420
|
const { placeholder, loading, error } = parseConnectedBlocks(connectedBlocks, errors, visitor);
|
|
25031
25421
|
const { triggers, prefetchTriggers } = parsePrimaryTriggers(ast.parameters, bindingParser, errors, placeholder);
|
|
25032
|
-
// The `defer` block has a main span encompassing all of the connected branches as well.
|
|
25033
|
-
// span of only the first "main" branch, use `mainSourceSpan`.
|
|
25422
|
+
// The `defer` block has a main span encompassing all of the connected branches as well.
|
|
25034
25423
|
let lastEndSourceSpan = ast.endSourceSpan;
|
|
25035
25424
|
let endOfLastSourceSpan = ast.sourceSpan.end;
|
|
25036
25425
|
if (connectedBlocks.length > 0) {
|
|
@@ -25038,8 +25427,8 @@ function createDeferredBlock(ast, connectedBlocks, visitor, bindingParser) {
|
|
|
25038
25427
|
lastEndSourceSpan = lastConnectedBlock.endSourceSpan;
|
|
25039
25428
|
endOfLastSourceSpan = lastConnectedBlock.sourceSpan.end;
|
|
25040
25429
|
}
|
|
25041
|
-
const
|
|
25042
|
-
const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error,
|
|
25430
|
+
const sourceSpanWithConnectedBlocks = new ParseSourceSpan(ast.sourceSpan.start, endOfLastSourceSpan);
|
|
25431
|
+
const node = new DeferredBlock(visitAll(visitor, ast.children, ast.children), triggers, prefetchTriggers, placeholder, loading, error, ast.nameSpan, sourceSpanWithConnectedBlocks, ast.sourceSpan, ast.startSourceSpan, lastEndSourceSpan);
|
|
25043
25432
|
return { node, errors };
|
|
25044
25433
|
}
|
|
25045
25434
|
function parseConnectedBlocks(connectedBlocks, errors, visitor) {
|
|
@@ -25102,7 +25491,7 @@ function parsePlaceholderBlock(ast, visitor) {
|
|
|
25102
25491
|
throw new Error(`Unrecognized parameter in @placeholder block: "${param.expression}"`);
|
|
25103
25492
|
}
|
|
25104
25493
|
}
|
|
25105
|
-
return new DeferredBlockPlaceholder(visitAll(visitor, ast.children, ast.children), minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
25494
|
+
return new DeferredBlockPlaceholder(visitAll(visitor, ast.children, ast.children), minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
25106
25495
|
}
|
|
25107
25496
|
function parseLoadingBlock(ast, visitor) {
|
|
25108
25497
|
let afterTime = null;
|
|
@@ -25132,13 +25521,13 @@ function parseLoadingBlock(ast, visitor) {
|
|
|
25132
25521
|
throw new Error(`Unrecognized parameter in @loading block: "${param.expression}"`);
|
|
25133
25522
|
}
|
|
25134
25523
|
}
|
|
25135
|
-
return new DeferredBlockLoading(visitAll(visitor, ast.children, ast.children), afterTime, minimumTime, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
25524
|
+
return new DeferredBlockLoading(visitAll(visitor, ast.children, ast.children), afterTime, minimumTime, ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
25136
25525
|
}
|
|
25137
25526
|
function parseErrorBlock(ast, visitor) {
|
|
25138
25527
|
if (ast.parameters.length > 0) {
|
|
25139
25528
|
throw new Error(`@error block cannot have parameters`);
|
|
25140
25529
|
}
|
|
25141
|
-
return new DeferredBlockError(visitAll(visitor, ast.children, ast.children), ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
25530
|
+
return new DeferredBlockError(visitAll(visitor, ast.children, ast.children), ast.nameSpan, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
25142
25531
|
}
|
|
25143
25532
|
function parsePrimaryTriggers(params, bindingParser, errors, placeholder) {
|
|
25144
25533
|
const triggers = {};
|
|
@@ -25887,6 +26276,8 @@ const NG_CONTENT_SELECT_ATTR = 'select';
|
|
|
25887
26276
|
const NG_PROJECT_AS_ATTR_NAME = 'ngProjectAs';
|
|
25888
26277
|
// Global symbols available only inside event bindings.
|
|
25889
26278
|
const EVENT_BINDING_SCOPE_GLOBALS = new Set(['$event']);
|
|
26279
|
+
// Tag name of the `ng-template` element.
|
|
26280
|
+
const NG_TEMPLATE_TAG_NAME = 'ng-template';
|
|
25890
26281
|
// List of supported global targets for event listeners
|
|
25891
26282
|
const GLOBAL_TARGET_RESOLVERS = new Map([['window', Identifiers.resolveWindow], ['document', Identifiers.resolveDocument], ['body', Identifiers.resolveBody]]);
|
|
25892
26283
|
const LEADING_TRIVIA_CHARS = [' ', '\n', '\r', '\t'];
|
|
@@ -26658,7 +27049,6 @@ class TemplateDefinitionBuilder {
|
|
|
26658
27049
|
// it based on the parent nodes inside the template instruction.
|
|
26659
27050
|
const tagNameWithoutNamespace = template.tagName ? splitNsName(template.tagName)[1] : template.tagName;
|
|
26660
27051
|
const contextNameSuffix = template.tagName ? '_' + sanitizeIdentifier(template.tagName) : '';
|
|
26661
|
-
const NG_TEMPLATE_TAG_NAME = 'ng-template';
|
|
26662
27052
|
// prepare attributes parameter (including attributes used for directive matching)
|
|
26663
27053
|
const attrsExprs = this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, template.attributes, template.inputs, template.outputs, undefined /* styles */, template.templateAttrs);
|
|
26664
27054
|
const templateIndex = this.createEmbeddedTemplateFn(tagNameWithoutNamespace, template.children, contextNameSuffix, template.sourceSpan, template.variables, attrsExprs, template.references, template.i18n);
|
|
@@ -26761,18 +27151,28 @@ class TemplateDefinitionBuilder {
|
|
|
26761
27151
|
// We have to process the block in two steps: once here and again in the update instruction
|
|
26762
27152
|
// callback in order to generate the correct expressions when pipes or pure functions are
|
|
26763
27153
|
// used inside the branch expressions.
|
|
26764
|
-
const branchData = block.branches.map((
|
|
27154
|
+
const branchData = block.branches.map((branch, branchIndex) => {
|
|
27155
|
+
const { expression, expressionAlias, children, sourceSpan } = branch;
|
|
26765
27156
|
// If the branch has an alias, it'll be assigned directly to the container's context.
|
|
26766
27157
|
// We define a variable referring directly to the context so that any nested usages can be
|
|
26767
27158
|
// rewritten to refer to it.
|
|
26768
27159
|
const variables = expressionAlias !== null ?
|
|
26769
27160
|
[new Variable(expressionAlias.name, DIRECT_CONTEXT_REFERENCE, expressionAlias.sourceSpan, expressionAlias.keySpan)] :
|
|
26770
27161
|
undefined;
|
|
27162
|
+
let tagName = null;
|
|
27163
|
+
let attrsExprs;
|
|
27164
|
+
// Only the first branch can be used for projection, because the conditional
|
|
27165
|
+
// uses the container of the first branch as the insertion point for all branches.
|
|
27166
|
+
if (branchIndex === 0) {
|
|
27167
|
+
const inferredData = this.inferProjectionDataFromInsertionPoint(branch);
|
|
27168
|
+
tagName = inferredData.tagName;
|
|
27169
|
+
attrsExprs = inferredData.attrsExprs;
|
|
27170
|
+
}
|
|
26771
27171
|
// Note: the template needs to be created *before* we process the expression,
|
|
26772
27172
|
// otherwise pipes injecting some symbols won't work (see #52102).
|
|
26773
|
-
const
|
|
27173
|
+
const templateIndex = this.createEmbeddedTemplateFn(tagName, children, '_Conditional', sourceSpan, variables, attrsExprs);
|
|
26774
27174
|
const processedExpression = expression === null ? null : expression.visit(this._valueConverter);
|
|
26775
|
-
return { index, expression: processedExpression, alias: expressionAlias };
|
|
27175
|
+
return { index: templateIndex, expression: processedExpression, alias: expressionAlias };
|
|
26776
27176
|
});
|
|
26777
27177
|
// Use the index of the first block as the index for the entire container.
|
|
26778
27178
|
const containerIndex = branchData[0].index;
|
|
@@ -26994,6 +27394,41 @@ class TemplateDefinitionBuilder {
|
|
|
26994
27394
|
return params;
|
|
26995
27395
|
});
|
|
26996
27396
|
}
|
|
27397
|
+
/**
|
|
27398
|
+
* Infers the data used for content projection (tag name and attributes) from the content of a
|
|
27399
|
+
* node.
|
|
27400
|
+
* @param node Node for which to infer the projection data.
|
|
27401
|
+
*/
|
|
27402
|
+
inferProjectionDataFromInsertionPoint(node) {
|
|
27403
|
+
let root = null;
|
|
27404
|
+
let tagName = null;
|
|
27405
|
+
let attrsExprs;
|
|
27406
|
+
for (const child of node.children) {
|
|
27407
|
+
// Skip over comment nodes.
|
|
27408
|
+
if (child instanceof Comment$1) {
|
|
27409
|
+
continue;
|
|
27410
|
+
}
|
|
27411
|
+
// We can only infer the tag name/attributes if there's a single root node.
|
|
27412
|
+
if (root !== null) {
|
|
27413
|
+
root = null;
|
|
27414
|
+
break;
|
|
27415
|
+
}
|
|
27416
|
+
// Root nodes can only elements or templates with a tag name (e.g. `<div *foo></div>`).
|
|
27417
|
+
if (child instanceof Element$1 || (child instanceof Template && child.tagName !== null)) {
|
|
27418
|
+
root = child;
|
|
27419
|
+
}
|
|
27420
|
+
}
|
|
27421
|
+
// If we've found a single root node, its tag name and *static* attributes can be copied
|
|
27422
|
+
// to the surrounding template to be used for content projection. Note that it's important
|
|
27423
|
+
// that we don't copy any bound attributes since they don't participate in content projection
|
|
27424
|
+
// and they can be used in directive matching (in the case of `Template.templateAttrs`).
|
|
27425
|
+
if (root !== null) {
|
|
27426
|
+
tagName = root instanceof Element$1 ? root.name : root.tagName;
|
|
27427
|
+
attrsExprs =
|
|
27428
|
+
this.getAttributeExpressions(NG_TEMPLATE_TAG_NAME, root.attributes, root.inputs, []);
|
|
27429
|
+
}
|
|
27430
|
+
return { tagName, attrsExprs };
|
|
27431
|
+
}
|
|
26997
27432
|
allocateDataSlot() {
|
|
26998
27433
|
return this._dataIndex++;
|
|
26999
27434
|
}
|
|
@@ -27001,6 +27436,7 @@ class TemplateDefinitionBuilder {
|
|
|
27001
27436
|
// Allocate one slot for the repeater metadata. The slots for the primary and empty block
|
|
27002
27437
|
// are implicitly inferred by the runtime to index + 1 and index + 2.
|
|
27003
27438
|
const blockIndex = this.allocateDataSlot();
|
|
27439
|
+
const { tagName, attrsExprs } = this.inferProjectionDataFromInsertionPoint(block);
|
|
27004
27440
|
const primaryData = this.prepareEmbeddedTemplateFn(block.children, '_For', [block.item, block.contextVariables.$index, block.contextVariables.$count]);
|
|
27005
27441
|
const { expression: trackByExpression, usesComponentInstance: trackByUsesComponentInstance } = this.createTrackByFunction(block);
|
|
27006
27442
|
let emptyData = null;
|
|
@@ -27017,6 +27453,8 @@ class TemplateDefinitionBuilder {
|
|
|
27017
27453
|
variable(primaryData.name),
|
|
27018
27454
|
literal(primaryData.getConstCount()),
|
|
27019
27455
|
literal(primaryData.getVarCount()),
|
|
27456
|
+
literal(tagName),
|
|
27457
|
+
this.addAttrsToConsts(attrsExprs || null),
|
|
27020
27458
|
trackByExpression,
|
|
27021
27459
|
];
|
|
27022
27460
|
if (emptyData !== null) {
|
|
@@ -29549,13 +29987,25 @@ class R3BoundTarget {
|
|
|
29549
29987
|
}
|
|
29550
29988
|
const name = trigger.reference;
|
|
29551
29989
|
if (name === null) {
|
|
29552
|
-
|
|
29553
|
-
|
|
29554
|
-
|
|
29555
|
-
|
|
29556
|
-
|
|
29557
|
-
|
|
29558
|
-
|
|
29990
|
+
let trigger = null;
|
|
29991
|
+
if (block.placeholder !== null) {
|
|
29992
|
+
for (const child of block.placeholder.children) {
|
|
29993
|
+
// Skip over comment nodes. Currently by default the template parser doesn't capture
|
|
29994
|
+
// comments, but we have a safeguard here just in case since it can be enabled.
|
|
29995
|
+
if (child instanceof Comment$1) {
|
|
29996
|
+
continue;
|
|
29997
|
+
}
|
|
29998
|
+
// We can only infer the trigger if there's one root element node. Any other
|
|
29999
|
+
// nodes at the root make it so that we can't infer the trigger anymore.
|
|
30000
|
+
if (trigger !== null) {
|
|
30001
|
+
return null;
|
|
30002
|
+
}
|
|
30003
|
+
if (child instanceof Element$1) {
|
|
30004
|
+
trigger = child;
|
|
30005
|
+
}
|
|
30006
|
+
}
|
|
30007
|
+
}
|
|
30008
|
+
return trigger;
|
|
29559
30009
|
}
|
|
29560
30010
|
const outsideRef = this.findEntityInScope(block, name);
|
|
29561
30011
|
// First try to resolve the target in the scope of the main deferred block. Note that we
|
|
@@ -29567,7 +30017,7 @@ class R3BoundTarget {
|
|
|
29567
30017
|
}
|
|
29568
30018
|
}
|
|
29569
30019
|
// If the trigger couldn't be found in the main block, check the
|
|
29570
|
-
// placeholder
|
|
30020
|
+
// placeholder block which is shown before the main block has loaded.
|
|
29571
30021
|
if (block.placeholder !== null) {
|
|
29572
30022
|
const refInPlaceholder = this.findEntityInScope(block.placeholder, name);
|
|
29573
30023
|
const targetInPlaceholder = refInPlaceholder instanceof Reference ? this.getReferenceTarget(refInPlaceholder) : null;
|
|
@@ -30262,7 +30712,7 @@ function publishFacade(global) {
|
|
|
30262
30712
|
* @description
|
|
30263
30713
|
* Entry point for all public APIs of the compiler package.
|
|
30264
30714
|
*/
|
|
30265
|
-
const VERSION = new Version('17.0.0-rc.
|
|
30715
|
+
const VERSION = new Version('17.0.0-rc.2');
|
|
30266
30716
|
|
|
30267
30717
|
class CompilerConfig {
|
|
30268
30718
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -31792,7 +32242,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
31792
32242
|
function compileDeclareClassMetadata(metadata) {
|
|
31793
32243
|
const definitionMap = new DefinitionMap();
|
|
31794
32244
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
31795
|
-
definitionMap.set('version', literal('17.0.0-rc.
|
|
32245
|
+
definitionMap.set('version', literal('17.0.0-rc.2'));
|
|
31796
32246
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
31797
32247
|
definitionMap.set('type', metadata.type);
|
|
31798
32248
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -31900,7 +32350,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
31900
32350
|
// in 16.1 is actually used.
|
|
31901
32351
|
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
31902
32352
|
definitionMap.set('minVersion', literal(minVersion));
|
|
31903
|
-
definitionMap.set('version', literal('17.0.0-rc.
|
|
32353
|
+
definitionMap.set('version', literal('17.0.0-rc.2'));
|
|
31904
32354
|
// e.g. `type: MyDirective`
|
|
31905
32355
|
definitionMap.set('type', meta.type.value);
|
|
31906
32356
|
if (meta.isStandalone) {
|
|
@@ -32177,7 +32627,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
32177
32627
|
function compileDeclareFactoryFunction(meta) {
|
|
32178
32628
|
const definitionMap = new DefinitionMap();
|
|
32179
32629
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
32180
|
-
definitionMap.set('version', literal('17.0.0-rc.
|
|
32630
|
+
definitionMap.set('version', literal('17.0.0-rc.2'));
|
|
32181
32631
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
32182
32632
|
definitionMap.set('type', meta.type.value);
|
|
32183
32633
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -32212,7 +32662,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
32212
32662
|
function createInjectableDefinitionMap(meta) {
|
|
32213
32663
|
const definitionMap = new DefinitionMap();
|
|
32214
32664
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
32215
|
-
definitionMap.set('version', literal('17.0.0-rc.
|
|
32665
|
+
definitionMap.set('version', literal('17.0.0-rc.2'));
|
|
32216
32666
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
32217
32667
|
definitionMap.set('type', meta.type.value);
|
|
32218
32668
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -32263,7 +32713,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
32263
32713
|
function createInjectorDefinitionMap(meta) {
|
|
32264
32714
|
const definitionMap = new DefinitionMap();
|
|
32265
32715
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
32266
|
-
definitionMap.set('version', literal('17.0.0-rc.
|
|
32716
|
+
definitionMap.set('version', literal('17.0.0-rc.2'));
|
|
32267
32717
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
32268
32718
|
definitionMap.set('type', meta.type.value);
|
|
32269
32719
|
definitionMap.set('providers', meta.providers);
|
|
@@ -32296,7 +32746,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
32296
32746
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
32297
32747
|
}
|
|
32298
32748
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
32299
|
-
definitionMap.set('version', literal('17.0.0-rc.
|
|
32749
|
+
definitionMap.set('version', literal('17.0.0-rc.2'));
|
|
32300
32750
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
32301
32751
|
definitionMap.set('type', meta.type.value);
|
|
32302
32752
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -32347,7 +32797,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
32347
32797
|
function createPipeDefinitionMap(meta) {
|
|
32348
32798
|
const definitionMap = new DefinitionMap();
|
|
32349
32799
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
32350
|
-
definitionMap.set('version', literal('17.0.0-rc.
|
|
32800
|
+
definitionMap.set('version', literal('17.0.0-rc.2'));
|
|
32351
32801
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
32352
32802
|
// e.g. `type: MyPipe`
|
|
32353
32803
|
definitionMap.set('type', meta.type.value);
|