@angular/compiler 17.2.0-next.1 → 17.2.0-rc.1
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/compiler_util/expression_converter.mjs +98 -25
- package/esm2022/src/constant_pool.mjs +14 -4
- package/esm2022/src/expression_parser/ast.mjs +1 -3
- package/esm2022/src/expression_parser/parser.mjs +8 -27
- 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_class_metadata_compiler.mjs +5 -3
- package/esm2022/src/render3/r3_identifiers.mjs +6 -1
- package/esm2022/src/render3/r3_template_transform.mjs +2 -2
- package/esm2022/src/render3/view/api.mjs +1 -1
- package/esm2022/src/render3/view/compiler.mjs +3 -3
- package/esm2022/src/render3/view/template.mjs +18 -8
- package/esm2022/src/render3/view/util.mjs +3 -1
- package/esm2022/src/template/pipeline/ir/src/enums.mjs +27 -11
- package/esm2022/src/template/pipeline/ir/src/expression.mjs +32 -1
- package/esm2022/src/template/pipeline/ir/src/ops/create.mjs +19 -1
- package/esm2022/src/template/pipeline/ir/src/ops/update.mjs +22 -1
- package/esm2022/src/template/pipeline/src/compilation.mjs +2 -2
- package/esm2022/src/template/pipeline/src/emit.mjs +3 -1
- package/esm2022/src/template/pipeline/src/ingest.mjs +54 -13
- package/esm2022/src/template/pipeline/src/instruction.mjs +14 -1
- package/esm2022/src/template/pipeline/src/phases/attribute_extraction.mjs +15 -1
- package/esm2022/src/template/pipeline/src/phases/binding_specialization.mjs +11 -1
- package/esm2022/src/template/pipeline/src/phases/chaining.mjs +3 -1
- package/esm2022/src/template/pipeline/src/phases/const_collection.mjs +12 -5
- package/esm2022/src/template/pipeline/src/phases/create_defer_deps_fns.mjs +4 -2
- package/esm2022/src/template/pipeline/src/phases/generate_variables.mjs +2 -1
- package/esm2022/src/template/pipeline/src/phases/naming.mjs +14 -2
- package/esm2022/src/template/pipeline/src/phases/next_context_merging.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/ordering.mjs +14 -5
- package/esm2022/src/template/pipeline/src/phases/reify.mjs +9 -1
- package/esm2022/src/template/pipeline/src/phases/resolve_contexts.mjs +2 -1
- package/esm2022/src/template/pipeline/src/phases/resolve_dollar_event.mjs +6 -3
- package/esm2022/src/template/pipeline/src/phases/resolve_names.mjs +3 -2
- package/esm2022/src/template/pipeline/src/phases/save_restore_view.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/temporary_variables.mjs +2 -2
- package/esm2022/src/template/pipeline/src/phases/transform_two_way_binding_set.mjs +79 -0
- package/esm2022/src/template/pipeline/src/phases/var_counting.mjs +4 -1
- package/esm2022/src/template/pipeline/src/phases/variable_optimization.mjs +3 -3
- package/esm2022/src/template_parser/binding_parser.mjs +35 -8
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +511 -122
- package/fesm2022/compiler.mjs.map +1 -1
- package/index.d.ts +40 -219
- package/package.json +2 -2
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v17.2.0-
|
|
2
|
+
* @license Angular v17.2.0-rc.1
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -2236,6 +2236,13 @@ class ConstantPool {
|
|
|
2236
2236
|
this.literals = new Map();
|
|
2237
2237
|
this.literalFactories = new Map();
|
|
2238
2238
|
this.sharedConstants = new Map();
|
|
2239
|
+
/**
|
|
2240
|
+
* Constant pool also tracks claimed names from {@link uniqueName}.
|
|
2241
|
+
* This is useful to avoid collisions if variables are intended to be
|
|
2242
|
+
* named a certain way- but may conflict. We wouldn't want to always suffix
|
|
2243
|
+
* them with unique numbers.
|
|
2244
|
+
*/
|
|
2245
|
+
this._claimedNames = new Map();
|
|
2239
2246
|
this.nextNameIndex = 0;
|
|
2240
2247
|
}
|
|
2241
2248
|
getConstLiteral(literal, forceShared) {
|
|
@@ -2358,14 +2365,17 @@ class ConstantPool {
|
|
|
2358
2365
|
return { literalFactory, literalFactoryArguments };
|
|
2359
2366
|
}
|
|
2360
2367
|
/**
|
|
2361
|
-
* Produce a unique name.
|
|
2368
|
+
* Produce a unique name in the context of this pool.
|
|
2362
2369
|
*
|
|
2363
2370
|
* The name might be unique among different prefixes if any of the prefixes end in
|
|
2364
2371
|
* a digit so the prefix should be a constant string (not based on user input) and
|
|
2365
2372
|
* must not end in a digit.
|
|
2366
2373
|
*/
|
|
2367
|
-
uniqueName(
|
|
2368
|
-
|
|
2374
|
+
uniqueName(name, alwaysIncludeSuffix = true) {
|
|
2375
|
+
const count = this._claimedNames.get(name) ?? 0;
|
|
2376
|
+
const result = count === 0 && !alwaysIncludeSuffix ? `${name}` : `${name}${count}`;
|
|
2377
|
+
this._claimedNames.set(name, count + 1);
|
|
2378
|
+
return result;
|
|
2369
2379
|
}
|
|
2370
2380
|
freshName() {
|
|
2371
2381
|
return this.uniqueName(CONSTANT_PREFIX);
|
|
@@ -2632,6 +2642,10 @@ class Identifiers {
|
|
|
2632
2642
|
static { this.viewQuerySignal = { name: 'ɵɵviewQuerySignal', moduleName: CORE }; }
|
|
2633
2643
|
static { this.contentQuerySignal = { name: 'ɵɵcontentQuerySignal', moduleName: CORE }; }
|
|
2634
2644
|
static { this.queryAdvance = { name: 'ɵɵqueryAdvance', moduleName: CORE }; }
|
|
2645
|
+
// Two-way bindings
|
|
2646
|
+
static { this.twoWayProperty = { name: 'ɵɵtwoWayProperty', moduleName: CORE }; }
|
|
2647
|
+
static { this.twoWayBindingSet = { name: 'ɵɵtwoWayBindingSet', moduleName: CORE }; }
|
|
2648
|
+
static { this.twoWayListener = { name: 'ɵɵtwoWayListener', moduleName: CORE }; }
|
|
2635
2649
|
static { this.NgOnChangesFeature = { name: 'ɵɵNgOnChangesFeature', moduleName: CORE }; }
|
|
2636
2650
|
static { this.InheritDefinitionFeature = { name: 'ɵɵInheritDefinitionFeature', moduleName: CORE }; }
|
|
2637
2651
|
static { this.CopyDefinitionFeature = { name: 'ɵɵCopyDefinitionFeature', moduleName: CORE }; }
|
|
@@ -2661,6 +2675,7 @@ class Identifiers {
|
|
|
2661
2675
|
// type-checking
|
|
2662
2676
|
static { this.InputSignalBrandWriteType = { name: 'ɵINPUT_SIGNAL_BRAND_WRITE_TYPE', moduleName: CORE }; }
|
|
2663
2677
|
static { this.UnwrapDirectiveSignalInputs = { name: 'ɵUnwrapDirectiveSignalInputs', moduleName: CORE }; }
|
|
2678
|
+
static { this.unwrapWritableSignal = { name: 'ɵunwrapWritableSignal', moduleName: CORE }; }
|
|
2664
2679
|
}
|
|
2665
2680
|
|
|
2666
2681
|
const DASH_CASE_REGEXP = /-+([a-z0-9])/g;
|
|
@@ -4961,6 +4976,8 @@ const CHAINABLE_INSTRUCTIONS = new Set([
|
|
|
4961
4976
|
Identifiers.textInterpolate8,
|
|
4962
4977
|
Identifiers.textInterpolateV,
|
|
4963
4978
|
Identifiers.templateCreate,
|
|
4979
|
+
Identifiers.twoWayProperty,
|
|
4980
|
+
Identifiers.twoWayListener,
|
|
4964
4981
|
]);
|
|
4965
4982
|
/** Generates a call to a single instruction. */
|
|
4966
4983
|
function invokeInstruction(span, reference, params) {
|
|
@@ -6933,8 +6950,6 @@ var ParsedPropertyType;
|
|
|
6933
6950
|
ParsedPropertyType[ParsedPropertyType["TWO_WAY"] = 3] = "TWO_WAY";
|
|
6934
6951
|
})(ParsedPropertyType || (ParsedPropertyType = {}));
|
|
6935
6952
|
class ParsedEvent {
|
|
6936
|
-
// Regular events have a target
|
|
6937
|
-
// Animation events have a phase
|
|
6938
6953
|
constructor(name, targetOrPhase, type, handler, sourceSpan, handlerSpan, keySpan) {
|
|
6939
6954
|
this.name = name;
|
|
6940
6955
|
this.targetOrPhase = targetOrPhase;
|
|
@@ -6978,32 +6993,10 @@ class EventHandlerVars {
|
|
|
6978
6993
|
* used in an action binding (e.g. an event handler).
|
|
6979
6994
|
*/
|
|
6980
6995
|
function convertActionBinding(localResolver, implicitReceiver, action, bindingId, baseSourceSpan, implicitReceiverAccesses, globals) {
|
|
6981
|
-
|
|
6982
|
-
localResolver = new DefaultLocalResolver(globals);
|
|
6983
|
-
}
|
|
6984
|
-
const actionWithoutBuiltins = convertPropertyBindingBuiltins({
|
|
6985
|
-
createLiteralArrayConverter: (argCount) => {
|
|
6986
|
-
// Note: no caching for literal arrays in actions.
|
|
6987
|
-
return (args) => literalArr(args);
|
|
6988
|
-
},
|
|
6989
|
-
createLiteralMapConverter: (keys) => {
|
|
6990
|
-
// Note: no caching for literal maps in actions.
|
|
6991
|
-
return (values) => {
|
|
6992
|
-
const entries = keys.map((k, i) => ({
|
|
6993
|
-
key: k.key,
|
|
6994
|
-
value: values[i],
|
|
6995
|
-
quoted: k.quoted,
|
|
6996
|
-
}));
|
|
6997
|
-
return literalMap(entries);
|
|
6998
|
-
};
|
|
6999
|
-
},
|
|
7000
|
-
createPipeConverter: (name) => {
|
|
7001
|
-
throw new Error(`Illegal State: Actions are not allowed to contain pipes. Pipe: ${name}`);
|
|
7002
|
-
}
|
|
7003
|
-
}, action);
|
|
6996
|
+
localResolver ??= new DefaultLocalResolver(globals);
|
|
7004
6997
|
const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, /* supportsInterpolation */ false, baseSourceSpan, implicitReceiverAccesses);
|
|
7005
6998
|
const actionStmts = [];
|
|
7006
|
-
flattenStatements(
|
|
6999
|
+
flattenStatements(convertActionBuiltins(action).visit(visitor, _Mode.Statement), actionStmts);
|
|
7007
7000
|
prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
|
|
7008
7001
|
if (visitor.usesImplicitReceiver) {
|
|
7009
7002
|
localResolver.notifyImplicitReceiverUse();
|
|
@@ -7018,6 +7011,77 @@ function convertActionBinding(localResolver, implicitReceiver, action, bindingId
|
|
|
7018
7011
|
}
|
|
7019
7012
|
return actionStmts;
|
|
7020
7013
|
}
|
|
7014
|
+
function convertAssignmentActionBinding(localResolver, implicitReceiver, action, bindingId, baseSourceSpan, implicitReceiverAccesses, globals) {
|
|
7015
|
+
localResolver ??= new DefaultLocalResolver(globals);
|
|
7016
|
+
const visitor = new _AstToIrVisitor(localResolver, implicitReceiver, bindingId, /* supportsInterpolation */ false, baseSourceSpan, implicitReceiverAccesses);
|
|
7017
|
+
let convertedAction = convertActionBuiltins(action).visit(visitor, _Mode.Statement);
|
|
7018
|
+
// This should already have been asserted in the parser, but we verify it here just in case.
|
|
7019
|
+
if (!(convertedAction instanceof ExpressionStatement)) {
|
|
7020
|
+
throw new Error(`Illegal state: unsupported expression in two-way action binding.`);
|
|
7021
|
+
}
|
|
7022
|
+
// Converts `[(ngModel)]="name"` to `twoWayBindingSet(ctx.name, $event) || (ctx.name = $event)`.
|
|
7023
|
+
convertedAction = wrapAssignmentAction(convertedAction.expr).toStmt();
|
|
7024
|
+
const actionStmts = [];
|
|
7025
|
+
flattenStatements(convertedAction, actionStmts);
|
|
7026
|
+
prependTemporaryDecls(visitor.temporaryCount, bindingId, actionStmts);
|
|
7027
|
+
// Assignment events always return `$event`.
|
|
7028
|
+
actionStmts.push(new ReturnStatement(EventHandlerVars.event));
|
|
7029
|
+
implicitReceiverAccesses?.add(EventHandlerVars.event.name);
|
|
7030
|
+
if (visitor.usesImplicitReceiver) {
|
|
7031
|
+
localResolver.notifyImplicitReceiverUse();
|
|
7032
|
+
}
|
|
7033
|
+
return actionStmts;
|
|
7034
|
+
}
|
|
7035
|
+
function wrapAssignmentReadExpression(ast) {
|
|
7036
|
+
return new ExternalExpr(Identifiers.twoWayBindingSet)
|
|
7037
|
+
.callFn([ast, EventHandlerVars.event])
|
|
7038
|
+
.or(ast.set(EventHandlerVars.event));
|
|
7039
|
+
}
|
|
7040
|
+
function isReadExpression$1(value) {
|
|
7041
|
+
return value instanceof ReadPropExpr || value instanceof ReadKeyExpr;
|
|
7042
|
+
}
|
|
7043
|
+
function wrapAssignmentAction(ast) {
|
|
7044
|
+
// The only officially supported expressions inside of a two-way binding are read expressions.
|
|
7045
|
+
if (isReadExpression$1(ast)) {
|
|
7046
|
+
return wrapAssignmentReadExpression(ast);
|
|
7047
|
+
}
|
|
7048
|
+
// However, historically the expression parser was handling two-way events by appending `=$event`
|
|
7049
|
+
// to the raw string before attempting to parse it. This has led to bugs over the years (see
|
|
7050
|
+
// #37809) and to unintentionally supporting unassignable events in the two-way binding. The
|
|
7051
|
+
// logic below aims to emulate the old behavior while still supporting the new output format
|
|
7052
|
+
// which uses `twoWayBindingSet`. Note that the generated code doesn't necessarily make sense
|
|
7053
|
+
// based on what the user wrote, for example the event binding for `[(value)]="a ? b : c"`
|
|
7054
|
+
// would produce `ctx.a ? ctx.b : ctx.c = $event`. We aim to reproduce what the parser used
|
|
7055
|
+
// to generate before #54154.
|
|
7056
|
+
if (ast instanceof BinaryOperatorExpr && isReadExpression$1(ast.rhs)) {
|
|
7057
|
+
// `a && b` -> `ctx.a && twoWayBindingSet(ctx.b, $event) || (ctx.b = $event)`
|
|
7058
|
+
return new BinaryOperatorExpr(ast.operator, ast.lhs, wrapAssignmentReadExpression(ast.rhs));
|
|
7059
|
+
}
|
|
7060
|
+
// Note: this also supports nullish coalescing expressions which
|
|
7061
|
+
// would've been downleveled to ternary expressions by this point.
|
|
7062
|
+
if (ast instanceof ConditionalExpr && isReadExpression$1(ast.falseCase)) {
|
|
7063
|
+
// `a ? b : c` -> `ctx.a ? ctx.b : twoWayBindingSet(ctx.c, $event) || (ctx.c = $event)`
|
|
7064
|
+
return new ConditionalExpr(ast.condition, ast.trueCase, wrapAssignmentReadExpression(ast.falseCase));
|
|
7065
|
+
}
|
|
7066
|
+
// `!!a` -> `twoWayBindingSet(ctx.a, $event) || (ctx.a = $event)`
|
|
7067
|
+
// Note: previously we'd actually produce `!!(ctx.a = $event)`, but the wrapping
|
|
7068
|
+
// node doesn't affect the result so we don't need to carry it over.
|
|
7069
|
+
if (ast instanceof NotExpr) {
|
|
7070
|
+
let expr = ast.condition;
|
|
7071
|
+
while (true) {
|
|
7072
|
+
if (expr instanceof NotExpr) {
|
|
7073
|
+
expr = expr.condition;
|
|
7074
|
+
}
|
|
7075
|
+
else {
|
|
7076
|
+
if (isReadExpression$1(expr)) {
|
|
7077
|
+
return wrapAssignmentReadExpression(expr);
|
|
7078
|
+
}
|
|
7079
|
+
break;
|
|
7080
|
+
}
|
|
7081
|
+
}
|
|
7082
|
+
}
|
|
7083
|
+
throw new Error(`Illegal state: unsupported expression in two-way action binding.`);
|
|
7084
|
+
}
|
|
7021
7085
|
function convertPropertyBindingBuiltins(converterFactory, ast) {
|
|
7022
7086
|
return convertBuiltins(converterFactory, ast);
|
|
7023
7087
|
}
|
|
@@ -7101,6 +7165,29 @@ function convertBuiltins(converterFactory, ast) {
|
|
|
7101
7165
|
const visitor = new _BuiltinAstConverter(converterFactory);
|
|
7102
7166
|
return ast.visit(visitor);
|
|
7103
7167
|
}
|
|
7168
|
+
function convertActionBuiltins(action) {
|
|
7169
|
+
const converterFactory = {
|
|
7170
|
+
createLiteralArrayConverter: () => {
|
|
7171
|
+
// Note: no caching for literal arrays in actions.
|
|
7172
|
+
return (args) => literalArr(args);
|
|
7173
|
+
},
|
|
7174
|
+
createLiteralMapConverter: (keys) => {
|
|
7175
|
+
// Note: no caching for literal maps in actions.
|
|
7176
|
+
return (values) => {
|
|
7177
|
+
const entries = keys.map((k, i) => ({
|
|
7178
|
+
key: k.key,
|
|
7179
|
+
value: values[i],
|
|
7180
|
+
quoted: k.quoted,
|
|
7181
|
+
}));
|
|
7182
|
+
return literalMap(entries);
|
|
7183
|
+
};
|
|
7184
|
+
},
|
|
7185
|
+
createPipeConverter: (name) => {
|
|
7186
|
+
throw new Error(`Illegal State: Actions are not allowed to contain pipes. Pipe: ${name}`);
|
|
7187
|
+
}
|
|
7188
|
+
};
|
|
7189
|
+
return convertPropertyBindingBuiltins(converterFactory, action);
|
|
7190
|
+
}
|
|
7104
7191
|
function temporaryName(bindingId, temporaryNumber) {
|
|
7105
7192
|
return `tmp_${bindingId}_${temporaryNumber}`;
|
|
7106
7193
|
}
|
|
@@ -8984,46 +9071,54 @@ var OpKind;
|
|
|
8984
9071
|
* An update up for a repeater.
|
|
8985
9072
|
*/
|
|
8986
9073
|
OpKind[OpKind["Repeater"] = 35] = "Repeater";
|
|
9074
|
+
/**
|
|
9075
|
+
* An operation to bind an expression to the property side of a two-way binding.
|
|
9076
|
+
*/
|
|
9077
|
+
OpKind[OpKind["TwoWayProperty"] = 36] = "TwoWayProperty";
|
|
9078
|
+
/**
|
|
9079
|
+
* An operation declaring the event side of a two-way binding.
|
|
9080
|
+
*/
|
|
9081
|
+
OpKind[OpKind["TwoWayListener"] = 37] = "TwoWayListener";
|
|
8987
9082
|
/**
|
|
8988
9083
|
* The start of an i18n block.
|
|
8989
9084
|
*/
|
|
8990
|
-
OpKind[OpKind["I18nStart"] =
|
|
9085
|
+
OpKind[OpKind["I18nStart"] = 38] = "I18nStart";
|
|
8991
9086
|
/**
|
|
8992
9087
|
* A self-closing i18n on a single element.
|
|
8993
9088
|
*/
|
|
8994
|
-
OpKind[OpKind["I18n"] =
|
|
9089
|
+
OpKind[OpKind["I18n"] = 39] = "I18n";
|
|
8995
9090
|
/**
|
|
8996
9091
|
* The end of an i18n block.
|
|
8997
9092
|
*/
|
|
8998
|
-
OpKind[OpKind["I18nEnd"] =
|
|
9093
|
+
OpKind[OpKind["I18nEnd"] = 40] = "I18nEnd";
|
|
8999
9094
|
/**
|
|
9000
9095
|
* An expression in an i18n message.
|
|
9001
9096
|
*/
|
|
9002
|
-
OpKind[OpKind["I18nExpression"] =
|
|
9097
|
+
OpKind[OpKind["I18nExpression"] = 41] = "I18nExpression";
|
|
9003
9098
|
/**
|
|
9004
9099
|
* An instruction that applies a set of i18n expressions.
|
|
9005
9100
|
*/
|
|
9006
|
-
OpKind[OpKind["I18nApply"] =
|
|
9101
|
+
OpKind[OpKind["I18nApply"] = 42] = "I18nApply";
|
|
9007
9102
|
/**
|
|
9008
9103
|
* An instruction to create an ICU expression.
|
|
9009
9104
|
*/
|
|
9010
|
-
OpKind[OpKind["IcuStart"] =
|
|
9105
|
+
OpKind[OpKind["IcuStart"] = 43] = "IcuStart";
|
|
9011
9106
|
/**
|
|
9012
9107
|
* An instruction to update an ICU expression.
|
|
9013
9108
|
*/
|
|
9014
|
-
OpKind[OpKind["IcuEnd"] =
|
|
9109
|
+
OpKind[OpKind["IcuEnd"] = 44] = "IcuEnd";
|
|
9015
9110
|
/**
|
|
9016
9111
|
* An instruction representing a placeholder in an ICU expression.
|
|
9017
9112
|
*/
|
|
9018
|
-
OpKind[OpKind["IcuPlaceholder"] =
|
|
9113
|
+
OpKind[OpKind["IcuPlaceholder"] = 45] = "IcuPlaceholder";
|
|
9019
9114
|
/**
|
|
9020
9115
|
* An i18n context containing information needed to generate an i18n message.
|
|
9021
9116
|
*/
|
|
9022
|
-
OpKind[OpKind["I18nContext"] =
|
|
9117
|
+
OpKind[OpKind["I18nContext"] = 46] = "I18nContext";
|
|
9023
9118
|
/**
|
|
9024
9119
|
* A creation op that corresponds to i18n attributes on an element.
|
|
9025
9120
|
*/
|
|
9026
|
-
OpKind[OpKind["I18nAttributes"] =
|
|
9121
|
+
OpKind[OpKind["I18nAttributes"] = 47] = "I18nAttributes";
|
|
9027
9122
|
})(OpKind || (OpKind = {}));
|
|
9028
9123
|
/**
|
|
9029
9124
|
* Distinguishes different kinds of IR expressions.
|
|
@@ -9135,6 +9230,10 @@ var ExpressionKind;
|
|
|
9135
9230
|
* An expression that will be automatically extracted to the component const array.
|
|
9136
9231
|
*/
|
|
9137
9232
|
ExpressionKind[ExpressionKind["ConstCollected"] = 25] = "ConstCollected";
|
|
9233
|
+
/**
|
|
9234
|
+
* Operation that sets the value of a two-way binding.
|
|
9235
|
+
*/
|
|
9236
|
+
ExpressionKind[ExpressionKind["TwoWayBindingSet"] = 26] = "TwoWayBindingSet";
|
|
9138
9237
|
})(ExpressionKind || (ExpressionKind = {}));
|
|
9139
9238
|
var VariableFlags;
|
|
9140
9239
|
(function (VariableFlags) {
|
|
@@ -9220,6 +9319,10 @@ var BindingKind;
|
|
|
9220
9319
|
* Animation property bindings.
|
|
9221
9320
|
*/
|
|
9222
9321
|
BindingKind[BindingKind["Animation"] = 6] = "Animation";
|
|
9322
|
+
/**
|
|
9323
|
+
* Property side of a two-way binding.
|
|
9324
|
+
*/
|
|
9325
|
+
BindingKind[BindingKind["TwoWayProperty"] = 7] = "TwoWayProperty";
|
|
9223
9326
|
})(BindingKind || (BindingKind = {}));
|
|
9224
9327
|
/**
|
|
9225
9328
|
* Enumeration of possible times i18n params can be resolved.
|
|
@@ -9486,6 +9589,27 @@ function createPropertyOp(target, name, expression, isAnimationTrigger, security
|
|
|
9486
9589
|
...NEW_OP,
|
|
9487
9590
|
};
|
|
9488
9591
|
}
|
|
9592
|
+
/**
|
|
9593
|
+
* Create a `TwoWayPropertyOp`.
|
|
9594
|
+
*/
|
|
9595
|
+
function createTwoWayPropertyOp(target, name, expression, securityContext, isStructuralTemplateAttribute, templateKind, i18nContext, i18nMessage, sourceSpan) {
|
|
9596
|
+
return {
|
|
9597
|
+
kind: OpKind.TwoWayProperty,
|
|
9598
|
+
target,
|
|
9599
|
+
name,
|
|
9600
|
+
expression,
|
|
9601
|
+
securityContext,
|
|
9602
|
+
sanitizer: null,
|
|
9603
|
+
isStructuralTemplateAttribute,
|
|
9604
|
+
templateKind,
|
|
9605
|
+
i18nContext,
|
|
9606
|
+
i18nMessage,
|
|
9607
|
+
sourceSpan,
|
|
9608
|
+
...TRAIT_DEPENDS_ON_SLOT_CONTEXT,
|
|
9609
|
+
...TRAIT_CONSUMES_VARS,
|
|
9610
|
+
...NEW_OP,
|
|
9611
|
+
};
|
|
9612
|
+
}
|
|
9489
9613
|
/** Create a `StylePropOp`. */
|
|
9490
9614
|
function createStylePropOp(xref, name, expression, unit, sourceSpan) {
|
|
9491
9615
|
return {
|
|
@@ -9863,6 +9987,31 @@ class ResetViewExpr extends ExpressionBase {
|
|
|
9863
9987
|
return new ResetViewExpr(this.expr.clone());
|
|
9864
9988
|
}
|
|
9865
9989
|
}
|
|
9990
|
+
class TwoWayBindingSetExpr extends ExpressionBase {
|
|
9991
|
+
constructor(target, value) {
|
|
9992
|
+
super();
|
|
9993
|
+
this.target = target;
|
|
9994
|
+
this.value = value;
|
|
9995
|
+
this.kind = ExpressionKind.TwoWayBindingSet;
|
|
9996
|
+
}
|
|
9997
|
+
visitExpression(visitor, context) {
|
|
9998
|
+
this.target.visitExpression(visitor, context);
|
|
9999
|
+
this.value.visitExpression(visitor, context);
|
|
10000
|
+
}
|
|
10001
|
+
isEquivalent(other) {
|
|
10002
|
+
return this.target.isEquivalent(other.target) && this.value.isEquivalent(other.value);
|
|
10003
|
+
}
|
|
10004
|
+
isConstant() {
|
|
10005
|
+
return false;
|
|
10006
|
+
}
|
|
10007
|
+
transformInternalExpressions(transform, flags) {
|
|
10008
|
+
this.target = transformExpressionsInExpression(this.target, transform, flags);
|
|
10009
|
+
this.value = transformExpressionsInExpression(this.value, transform, flags);
|
|
10010
|
+
}
|
|
10011
|
+
clone() {
|
|
10012
|
+
return new TwoWayBindingSetExpr(this.target, this.value);
|
|
10013
|
+
}
|
|
10014
|
+
}
|
|
9866
10015
|
/**
|
|
9867
10016
|
* Read of a variable declared as an `ir.VariableOp` and referenced through its `ir.XrefId`.
|
|
9868
10017
|
*/
|
|
@@ -10322,6 +10471,11 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10322
10471
|
op.sanitizer =
|
|
10323
10472
|
op.sanitizer && transformExpressionsInExpression(op.sanitizer, transform, flags);
|
|
10324
10473
|
break;
|
|
10474
|
+
case OpKind.TwoWayProperty:
|
|
10475
|
+
op.expression = transformExpressionsInExpression(op.expression, transform, flags);
|
|
10476
|
+
op.sanitizer =
|
|
10477
|
+
op.sanitizer && transformExpressionsInExpression(op.sanitizer, transform, flags);
|
|
10478
|
+
break;
|
|
10325
10479
|
case OpKind.I18nExpression:
|
|
10326
10480
|
op.expression = transformExpressionsInExpression(op.expression, transform, flags);
|
|
10327
10481
|
break;
|
|
@@ -10350,6 +10504,7 @@ function transformExpressionsInOp(op, transform, flags) {
|
|
|
10350
10504
|
}
|
|
10351
10505
|
break;
|
|
10352
10506
|
case OpKind.Listener:
|
|
10507
|
+
case OpKind.TwoWayListener:
|
|
10353
10508
|
for (const innerOp of op.handlerOps) {
|
|
10354
10509
|
transformExpressionsInOp(innerOp, transform, flags | VisitorContextFlag.InChildOperation);
|
|
10355
10510
|
}
|
|
@@ -10968,6 +11123,24 @@ function createListenerOp(target, targetSlot, name, tag, handlerOps, animationPh
|
|
|
10968
11123
|
...NEW_OP,
|
|
10969
11124
|
};
|
|
10970
11125
|
}
|
|
11126
|
+
/**
|
|
11127
|
+
* Create a `TwoWayListenerOp`.
|
|
11128
|
+
*/
|
|
11129
|
+
function createTwoWayListenerOp(target, targetSlot, name, tag, handlerOps, sourceSpan) {
|
|
11130
|
+
const handlerList = new OpList();
|
|
11131
|
+
handlerList.push(handlerOps);
|
|
11132
|
+
return {
|
|
11133
|
+
kind: OpKind.TwoWayListener,
|
|
11134
|
+
target,
|
|
11135
|
+
targetSlot,
|
|
11136
|
+
tag,
|
|
11137
|
+
name,
|
|
11138
|
+
handlerOps: handlerList,
|
|
11139
|
+
handlerFnName: null,
|
|
11140
|
+
sourceSpan,
|
|
11141
|
+
...NEW_OP,
|
|
11142
|
+
};
|
|
11143
|
+
}
|
|
10971
11144
|
function createPipeOp(xref, slot, name) {
|
|
10972
11145
|
return {
|
|
10973
11146
|
kind: OpKind.Pipe,
|
|
@@ -11325,7 +11498,7 @@ class CompilationUnit {
|
|
|
11325
11498
|
*ops() {
|
|
11326
11499
|
for (const op of this.create) {
|
|
11327
11500
|
yield op;
|
|
11328
|
-
if (op.kind === OpKind.Listener) {
|
|
11501
|
+
if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
|
|
11329
11502
|
for (const listenerOp of op.handlerOps) {
|
|
11330
11503
|
yield listenerOp;
|
|
11331
11504
|
}
|
|
@@ -11571,6 +11744,11 @@ function extractAttributes(job) {
|
|
|
11571
11744
|
/* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
|
|
11572
11745
|
}
|
|
11573
11746
|
break;
|
|
11747
|
+
case OpKind.TwoWayProperty:
|
|
11748
|
+
OpList.insertBefore(createExtractedAttributeOp(op.target, BindingKind.TwoWayProperty, null, op.name, /* expression */ null,
|
|
11749
|
+
/* i18nContext */ null,
|
|
11750
|
+
/* i18nMessage */ null, op.securityContext), lookupElement$2(elements, op.target));
|
|
11751
|
+
break;
|
|
11574
11752
|
case OpKind.StyleProp:
|
|
11575
11753
|
case OpKind.ClassProp:
|
|
11576
11754
|
// TODO: Can style or class bindings be i18n attributes?
|
|
@@ -11604,6 +11782,15 @@ function extractAttributes(job) {
|
|
|
11604
11782
|
}
|
|
11605
11783
|
}
|
|
11606
11784
|
break;
|
|
11785
|
+
case OpKind.TwoWayListener:
|
|
11786
|
+
// Two-way listeners aren't supported in host bindings.
|
|
11787
|
+
if (job.kind !== CompilationJobKind.Host) {
|
|
11788
|
+
const extractedAttributeOp = createExtractedAttributeOp(op.target, BindingKind.Property, null, op.name, /* expression */ null,
|
|
11789
|
+
/* i18nContext */ null,
|
|
11790
|
+
/* i18nMessage */ null, SecurityContext.NONE);
|
|
11791
|
+
OpList.insertBefore(extractedAttributeOp, lookupElement$2(elements, op.target));
|
|
11792
|
+
}
|
|
11793
|
+
break;
|
|
11607
11794
|
}
|
|
11608
11795
|
}
|
|
11609
11796
|
}
|
|
@@ -11692,6 +11879,15 @@ function specializeBindings(job) {
|
|
|
11692
11879
|
OpList.replace(op, createPropertyOp(op.target, op.name, op.expression, op.bindingKind === BindingKind.Animation, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
|
|
11693
11880
|
}
|
|
11694
11881
|
break;
|
|
11882
|
+
case BindingKind.TwoWayProperty:
|
|
11883
|
+
if (!(op.expression instanceof Expression)) {
|
|
11884
|
+
// We shouldn't be able to hit this code path since interpolations in two-way bindings
|
|
11885
|
+
// result in a parser error. We assert here so that downstream we can assume that
|
|
11886
|
+
// the value is always an expression.
|
|
11887
|
+
throw new Error(`Expected value of two-way property binding "${op.name}" to be an expression`);
|
|
11888
|
+
}
|
|
11889
|
+
OpList.replace(op, createTwoWayPropertyOp(op.target, op.name, op.expression, op.securityContext, op.isStructuralTemplateAttribute, op.templateKind, op.i18nContext, op.i18nMessage, op.sourceSpan));
|
|
11890
|
+
break;
|
|
11695
11891
|
case BindingKind.I18n:
|
|
11696
11892
|
case BindingKind.ClassName:
|
|
11697
11893
|
case BindingKind.StyleProperty:
|
|
@@ -11728,6 +11924,8 @@ const CHAINABLE = new Set([
|
|
|
11728
11924
|
Identifiers.syntheticHostListener,
|
|
11729
11925
|
Identifiers.syntheticHostProperty,
|
|
11730
11926
|
Identifiers.templateCreate,
|
|
11927
|
+
Identifiers.twoWayProperty,
|
|
11928
|
+
Identifiers.twoWayListener,
|
|
11731
11929
|
]);
|
|
11732
11930
|
/**
|
|
11733
11931
|
* Post-process a reified view compilation and convert sequential calls to chainable instructions
|
|
@@ -12001,7 +12199,7 @@ class ElementAttributes {
|
|
|
12001
12199
|
return this.byKind.get(BindingKind.StyleProperty) ?? FLYWEIGHT_ARRAY;
|
|
12002
12200
|
}
|
|
12003
12201
|
get bindings() {
|
|
12004
|
-
return this.
|
|
12202
|
+
return this.propertyBindings ?? FLYWEIGHT_ARRAY;
|
|
12005
12203
|
}
|
|
12006
12204
|
get template() {
|
|
12007
12205
|
return this.byKind.get(BindingKind.Template) ?? FLYWEIGHT_ARRAY;
|
|
@@ -12013,6 +12211,7 @@ class ElementAttributes {
|
|
|
12013
12211
|
this.compatibility = compatibility;
|
|
12014
12212
|
this.known = new Map();
|
|
12015
12213
|
this.byKind = new Map;
|
|
12214
|
+
this.propertyBindings = null;
|
|
12016
12215
|
this.projectAs = null;
|
|
12017
12216
|
}
|
|
12018
12217
|
isKnown(kind, name, value) {
|
|
@@ -12062,10 +12261,16 @@ class ElementAttributes {
|
|
|
12062
12261
|
}
|
|
12063
12262
|
}
|
|
12064
12263
|
arrayFor(kind) {
|
|
12065
|
-
if (
|
|
12066
|
-
this.
|
|
12264
|
+
if (kind === BindingKind.Property || kind === BindingKind.TwoWayProperty) {
|
|
12265
|
+
this.propertyBindings ??= [];
|
|
12266
|
+
return this.propertyBindings;
|
|
12267
|
+
}
|
|
12268
|
+
else {
|
|
12269
|
+
if (!this.byKind.has(kind)) {
|
|
12270
|
+
this.byKind.set(kind, []);
|
|
12271
|
+
}
|
|
12272
|
+
return this.byKind.get(kind);
|
|
12067
12273
|
}
|
|
12068
|
-
return this.byKind.get(kind);
|
|
12069
12274
|
}
|
|
12070
12275
|
}
|
|
12071
12276
|
/**
|
|
@@ -12168,7 +12373,9 @@ function createDeferDepsFns(job) {
|
|
|
12168
12373
|
for (const dep of op.metadata.deps) {
|
|
12169
12374
|
if (dep.isDeferrable) {
|
|
12170
12375
|
// Callback function, e.g. `m () => m.MyCmp;`.
|
|
12171
|
-
const innerFn = arrowFn(
|
|
12376
|
+
const innerFn = arrowFn(
|
|
12377
|
+
// Default imports are always accessed through the `default` property.
|
|
12378
|
+
[new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(dep.isDefaultImport ? 'default' : dep.symbolName));
|
|
12172
12379
|
// Dynamic import, e.g. `import('./a').then(...)`.
|
|
12173
12380
|
const importExpr = (new DynamicImportExpr(dep.importPath)).prop('then').callFn([innerFn]);
|
|
12174
12381
|
dependencies.push(importExpr);
|
|
@@ -12995,6 +13202,7 @@ function recursivelyProcessView(view, parentScope) {
|
|
|
12995
13202
|
}
|
|
12996
13203
|
break;
|
|
12997
13204
|
case OpKind.Listener:
|
|
13205
|
+
case OpKind.TwoWayListener:
|
|
12998
13206
|
// Prepend variables to listener handler functions.
|
|
12999
13207
|
op.handlerOps.prepend(generateVariablesInScopeForView(view, scope));
|
|
13000
13208
|
break;
|
|
@@ -13658,15 +13866,12 @@ class Parser$1 {
|
|
|
13658
13866
|
this._lexer = _lexer;
|
|
13659
13867
|
this.errors = [];
|
|
13660
13868
|
}
|
|
13661
|
-
parseAction(input,
|
|
13869
|
+
parseAction(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
|
|
13662
13870
|
this._checkNoInterpolation(input, location, interpolationConfig);
|
|
13663
13871
|
const sourceToLex = this._stripComments(input);
|
|
13664
13872
|
const tokens = this._lexer.tokenize(sourceToLex);
|
|
13665
|
-
|
|
13666
|
-
|
|
13667
|
-
flags |= 2 /* ParseFlags.AssignmentEvent */;
|
|
13668
|
-
}
|
|
13669
|
-
const ast = new _ParseAST(input, location, absoluteOffset, tokens, flags, this.errors, 0).parseChain();
|
|
13873
|
+
const ast = new _ParseAST(input, location, absoluteOffset, tokens, 1 /* ParseFlags.Action */, this.errors, 0)
|
|
13874
|
+
.parseChain();
|
|
13670
13875
|
return new ASTWithSource(ast, input, location, absoluteOffset, this.errors);
|
|
13671
13876
|
}
|
|
13672
13877
|
parseBinding(input, location, absoluteOffset, interpolationConfig = DEFAULT_INTERPOLATION_CONFIG) {
|
|
@@ -14143,7 +14348,7 @@ class _ParseAST {
|
|
|
14143
14348
|
let result = this.parseExpression();
|
|
14144
14349
|
if (this.consumeOptionalOperator('|')) {
|
|
14145
14350
|
if (this.parseFlags & 1 /* ParseFlags.Action */) {
|
|
14146
|
-
this.error(
|
|
14351
|
+
this.error(`Cannot have a pipe in an action expression`);
|
|
14147
14352
|
}
|
|
14148
14353
|
do {
|
|
14149
14354
|
const nameStart = this.inputIndex;
|
|
@@ -14485,7 +14690,7 @@ class _ParseAST {
|
|
|
14485
14690
|
const nameSpan = this.sourceSpan(nameStart);
|
|
14486
14691
|
let receiver;
|
|
14487
14692
|
if (isSafe) {
|
|
14488
|
-
if (this.
|
|
14693
|
+
if (this.consumeOptionalOperator('=')) {
|
|
14489
14694
|
this.error('The \'?.\' operator cannot be used in the assignment');
|
|
14490
14695
|
receiver = new EmptyExpr$1(this.span(start), this.sourceSpan(start));
|
|
14491
14696
|
}
|
|
@@ -14494,7 +14699,7 @@ class _ParseAST {
|
|
|
14494
14699
|
}
|
|
14495
14700
|
}
|
|
14496
14701
|
else {
|
|
14497
|
-
if (this.
|
|
14702
|
+
if (this.consumeOptionalOperator('=')) {
|
|
14498
14703
|
if (!(this.parseFlags & 1 /* ParseFlags.Action */)) {
|
|
14499
14704
|
this.error('Bindings cannot contain assignments');
|
|
14500
14705
|
return new EmptyExpr$1(this.span(start), this.sourceSpan(start));
|
|
@@ -14521,22 +14726,6 @@ class _ParseAST {
|
|
|
14521
14726
|
return isSafe ? new SafeCall(span, sourceSpan, receiver, args, argumentSpan) :
|
|
14522
14727
|
new Call(span, sourceSpan, receiver, args, argumentSpan);
|
|
14523
14728
|
}
|
|
14524
|
-
consumeOptionalAssignment() {
|
|
14525
|
-
// When parsing assignment events (originating from two-way-binding aka banana-in-a-box syntax),
|
|
14526
|
-
// it is valid for the primary expression to be terminated by the non-null operator. This
|
|
14527
|
-
// primary expression is substituted as LHS of the assignment operator to achieve
|
|
14528
|
-
// two-way-binding, such that the LHS could be the non-null operator. The grammar doesn't
|
|
14529
|
-
// naturally allow for this syntax, so assignment events are parsed specially.
|
|
14530
|
-
if ((this.parseFlags & 2 /* ParseFlags.AssignmentEvent */) && this.next.isOperator('!') &&
|
|
14531
|
-
this.peek(1).isOperator('=')) {
|
|
14532
|
-
// First skip over the ! operator.
|
|
14533
|
-
this.advance();
|
|
14534
|
-
// Then skip over the = operator, to fully consume the optional assignment operator.
|
|
14535
|
-
this.advance();
|
|
14536
|
-
return true;
|
|
14537
|
-
}
|
|
14538
|
-
return this.consumeOptionalOperator('=');
|
|
14539
|
-
}
|
|
14540
14729
|
parseCallArguments() {
|
|
14541
14730
|
if (this.next.isCharacter($RPAREN))
|
|
14542
14731
|
return [];
|
|
@@ -20614,7 +20803,10 @@ function nameFunctionsAndVariables(job) {
|
|
|
20614
20803
|
}
|
|
20615
20804
|
function addNamesToView(unit, baseName, state, compatibility) {
|
|
20616
20805
|
if (unit.fnName === null) {
|
|
20617
|
-
|
|
20806
|
+
// Ensure unique names for view units. This is necessary because there might be multiple
|
|
20807
|
+
// components with same names in the context of the same pool. Only add the suffix
|
|
20808
|
+
// if really needed.
|
|
20809
|
+
unit.fnName = unit.job.pool.uniqueName(sanitizeIdentifier(`${baseName}_${unit.job.fnSuffix}`), /* alwaysIncludeSuffix */ false);
|
|
20618
20810
|
}
|
|
20619
20811
|
// Keep track of the names we assign to variables in the view. We'll need to propagate these
|
|
20620
20812
|
// into reads of those variables afterwards.
|
|
@@ -20647,6 +20839,15 @@ function addNamesToView(unit, baseName, state, compatibility) {
|
|
|
20647
20839
|
}
|
|
20648
20840
|
op.handlerFnName = sanitizeIdentifier(op.handlerFnName);
|
|
20649
20841
|
break;
|
|
20842
|
+
case OpKind.TwoWayListener:
|
|
20843
|
+
if (op.handlerFnName !== null) {
|
|
20844
|
+
break;
|
|
20845
|
+
}
|
|
20846
|
+
if (op.targetSlot.slot === null) {
|
|
20847
|
+
throw new Error(`Expected a slot to be assigned`);
|
|
20848
|
+
}
|
|
20849
|
+
op.handlerFnName = sanitizeIdentifier(`${unit.fnName}_${op.tag.replace('-', '_')}_${op.name}_${op.targetSlot.slot}_listener`);
|
|
20850
|
+
break;
|
|
20650
20851
|
case OpKind.Variable:
|
|
20651
20852
|
varNames.set(op.xref, getVariableName(unit, op.variable, state));
|
|
20652
20853
|
break;
|
|
@@ -20761,7 +20962,7 @@ function stripImportant(name) {
|
|
|
20761
20962
|
function mergeNextContextExpressions(job) {
|
|
20762
20963
|
for (const unit of job.units) {
|
|
20763
20964
|
for (const op of unit.create) {
|
|
20764
|
-
if (op.kind === OpKind.Listener) {
|
|
20965
|
+
if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
|
|
20765
20966
|
mergeNextContextsInOps(op.handlerOps);
|
|
20766
20967
|
}
|
|
20767
20968
|
}
|
|
@@ -20902,6 +21103,14 @@ function kindWithInterpolationTest(kind, interpolation) {
|
|
|
20902
21103
|
return op.kind === kind && interpolation === op.expression instanceof Interpolation;
|
|
20903
21104
|
};
|
|
20904
21105
|
}
|
|
21106
|
+
function basicListenerKindTest(op) {
|
|
21107
|
+
return (op.kind === OpKind.Listener && !(op.hostListener && op.isAnimationListener)) ||
|
|
21108
|
+
op.kind === OpKind.TwoWayListener;
|
|
21109
|
+
}
|
|
21110
|
+
function nonInterpolationPropertyKindTest(op) {
|
|
21111
|
+
return (op.kind === OpKind.Property || op.kind === OpKind.TwoWayProperty) &&
|
|
21112
|
+
!(op.expression instanceof Interpolation);
|
|
21113
|
+
}
|
|
20905
21114
|
/**
|
|
20906
21115
|
* Defines the groups based on `OpKind` that ops will be divided into, for the various create
|
|
20907
21116
|
* op kinds. Ops will be collected into groups, then optionally transformed, before recombining
|
|
@@ -20909,7 +21118,7 @@ function kindWithInterpolationTest(kind, interpolation) {
|
|
|
20909
21118
|
*/
|
|
20910
21119
|
const CREATE_ORDERING = [
|
|
20911
21120
|
{ test: op => op.kind === OpKind.Listener && op.hostListener && op.isAnimationListener },
|
|
20912
|
-
{ test:
|
|
21121
|
+
{ test: basicListenerKindTest },
|
|
20913
21122
|
];
|
|
20914
21123
|
/**
|
|
20915
21124
|
* Defines the groups based on `OpKind` that ops will be divided into, for the various update
|
|
@@ -20922,7 +21131,7 @@ const UPDATE_ORDERING = [
|
|
|
20922
21131
|
{ test: kindTest(OpKind.ClassProp) },
|
|
20923
21132
|
{ test: kindWithInterpolationTest(OpKind.Attribute, true) },
|
|
20924
21133
|
{ test: kindWithInterpolationTest(OpKind.Property, true) },
|
|
20925
|
-
{ test:
|
|
21134
|
+
{ test: nonInterpolationPropertyKindTest },
|
|
20926
21135
|
{ test: kindWithInterpolationTest(OpKind.Attribute, false) },
|
|
20927
21136
|
];
|
|
20928
21137
|
/**
|
|
@@ -20941,8 +21150,9 @@ const UPDATE_HOST_ORDERING = [
|
|
|
20941
21150
|
* The set of all op kinds we handle in the reordering phase.
|
|
20942
21151
|
*/
|
|
20943
21152
|
const handledOpKinds = new Set([
|
|
20944
|
-
OpKind.Listener, OpKind.
|
|
20945
|
-
OpKind.
|
|
21153
|
+
OpKind.Listener, OpKind.TwoWayListener, OpKind.StyleMap, OpKind.ClassMap,
|
|
21154
|
+
OpKind.StyleProp, OpKind.ClassProp, OpKind.Property, OpKind.TwoWayProperty,
|
|
21155
|
+
OpKind.HostProperty, OpKind.Attribute
|
|
20946
21156
|
]);
|
|
20947
21157
|
/**
|
|
20948
21158
|
* Many type of operations have ordering constraints that must be respected. For example, a
|
|
@@ -21408,6 +21618,12 @@ function listener(name, handlerFn, eventTargetResolver, syntheticHost, sourceSpa
|
|
|
21408
21618
|
}
|
|
21409
21619
|
return call(syntheticHost ? Identifiers.syntheticHostListener : Identifiers.listener, args, sourceSpan);
|
|
21410
21620
|
}
|
|
21621
|
+
function twoWayBindingSet(target, value) {
|
|
21622
|
+
return importExpr(Identifiers.twoWayBindingSet).callFn([target, value]);
|
|
21623
|
+
}
|
|
21624
|
+
function twoWayListener(name, handlerFn, sourceSpan) {
|
|
21625
|
+
return call(Identifiers.twoWayListener, [literal(name), handlerFn], sourceSpan);
|
|
21626
|
+
}
|
|
21411
21627
|
function pipe(slot, name) {
|
|
21412
21628
|
return call(Identifiers.pipe, [
|
|
21413
21629
|
literal(slot),
|
|
@@ -21568,6 +21784,13 @@ function property(name, expression, sanitizer, sourceSpan) {
|
|
|
21568
21784
|
}
|
|
21569
21785
|
return call(Identifiers.property, args, sourceSpan);
|
|
21570
21786
|
}
|
|
21787
|
+
function twoWayProperty(name, expression, sanitizer, sourceSpan) {
|
|
21788
|
+
const args = [literal(name), expression];
|
|
21789
|
+
if (sanitizer !== null) {
|
|
21790
|
+
args.push(sanitizer);
|
|
21791
|
+
}
|
|
21792
|
+
return call(Identifiers.twoWayProperty, args, sourceSpan);
|
|
21793
|
+
}
|
|
21571
21794
|
function attribute(name, expression, sanitizer, namespace) {
|
|
21572
21795
|
const args = [literal(name), expression];
|
|
21573
21796
|
if (sanitizer !== null || namespace !== null) {
|
|
@@ -22010,6 +22233,9 @@ function reifyCreateOperations(unit, ops) {
|
|
|
22010
22233
|
}
|
|
22011
22234
|
OpList.replace(op, listener(op.name, listenerFn, eventTargetResolver, op.hostListener && op.isAnimationListener, op.sourceSpan));
|
|
22012
22235
|
break;
|
|
22236
|
+
case OpKind.TwoWayListener:
|
|
22237
|
+
OpList.replace(op, twoWayListener(op.name, reifyListenerHandler(unit, op.handlerFnName, op.handlerOps, true), op.sourceSpan));
|
|
22238
|
+
break;
|
|
22013
22239
|
case OpKind.Variable:
|
|
22014
22240
|
if (op.variable.name === null) {
|
|
22015
22241
|
throw new Error(`AssertionError: unnamed variable ${op.xref}`);
|
|
@@ -22118,6 +22344,9 @@ function reifyUpdateOperations(_unit, ops) {
|
|
|
22118
22344
|
OpList.replace(op, property(op.name, op.expression, op.sanitizer, op.sourceSpan));
|
|
22119
22345
|
}
|
|
22120
22346
|
break;
|
|
22347
|
+
case OpKind.TwoWayProperty:
|
|
22348
|
+
OpList.replace(op, twoWayProperty(op.name, op.expression, op.sanitizer, op.sourceSpan));
|
|
22349
|
+
break;
|
|
22121
22350
|
case OpKind.StyleProp:
|
|
22122
22351
|
if (op.expression instanceof Interpolation) {
|
|
22123
22352
|
OpList.replace(op, stylePropInterpolate(op.name, op.expression.strings, op.expression.expressions, op.unit, op.sourceSpan));
|
|
@@ -22215,6 +22444,8 @@ function reifyIrExpression(expr) {
|
|
|
22215
22444
|
return reference(expr.targetSlot.slot + 1 + expr.offset);
|
|
22216
22445
|
case ExpressionKind.LexicalRead:
|
|
22217
22446
|
throw new Error(`AssertionError: unresolved LexicalRead of ${expr.name}`);
|
|
22447
|
+
case ExpressionKind.TwoWayBindingSet:
|
|
22448
|
+
throw new Error(`AssertionError: unresolved TwoWayBindingSet`);
|
|
22218
22449
|
case ExpressionKind.RestoreView:
|
|
22219
22450
|
if (typeof expr.view === 'number') {
|
|
22220
22451
|
throw new Error(`AssertionError: unresolved RestoreView`);
|
|
@@ -22375,6 +22606,7 @@ function processLexicalScope$1(view, ops) {
|
|
|
22375
22606
|
}
|
|
22376
22607
|
break;
|
|
22377
22608
|
case OpKind.Listener:
|
|
22609
|
+
case OpKind.TwoWayListener:
|
|
22378
22610
|
processLexicalScope$1(view, op.handlerOps);
|
|
22379
22611
|
break;
|
|
22380
22612
|
}
|
|
@@ -22410,10 +22642,13 @@ function resolveDollarEvent(job) {
|
|
|
22410
22642
|
}
|
|
22411
22643
|
function transformDollarEvent(unit, ops) {
|
|
22412
22644
|
for (const op of ops) {
|
|
22413
|
-
if (op.kind === OpKind.Listener) {
|
|
22645
|
+
if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
|
|
22414
22646
|
transformExpressionsInOp(op, (expr) => {
|
|
22415
22647
|
if (expr instanceof LexicalReadExpr && expr.name === '$event') {
|
|
22416
|
-
|
|
22648
|
+
// Two-way listeners always consume `$event` so they omit this field.
|
|
22649
|
+
if (op.kind === OpKind.Listener) {
|
|
22650
|
+
op.consumesDollarEvent = true;
|
|
22651
|
+
}
|
|
22417
22652
|
return new ReadVarExpr(expr.name);
|
|
22418
22653
|
}
|
|
22419
22654
|
return expr;
|
|
@@ -22788,6 +23023,7 @@ function processLexicalScope(unit, ops, savedView) {
|
|
|
22788
23023
|
}
|
|
22789
23024
|
break;
|
|
22790
23025
|
case OpKind.Listener:
|
|
23026
|
+
case OpKind.TwoWayListener:
|
|
22791
23027
|
// Listener functions have separate variable declarations, so process them as a separate
|
|
22792
23028
|
// lexical scope.
|
|
22793
23029
|
processLexicalScope(unit, op.handlerOps, savedView);
|
|
@@ -22798,7 +23034,7 @@ function processLexicalScope(unit, ops, savedView) {
|
|
|
22798
23034
|
// scope. Also, look for `ir.RestoreViewExpr`s and match them with the snapshotted view context
|
|
22799
23035
|
// variable.
|
|
22800
23036
|
for (const op of ops) {
|
|
22801
|
-
if (op.kind == OpKind.Listener) {
|
|
23037
|
+
if (op.kind == OpKind.Listener || op.kind === OpKind.TwoWayListener) {
|
|
22802
23038
|
// Listeners were already processed above with their own scopes.
|
|
22803
23039
|
continue;
|
|
22804
23040
|
}
|
|
@@ -22947,6 +23183,75 @@ function getOnlySecurityContext(securityContext) {
|
|
|
22947
23183
|
return securityContext;
|
|
22948
23184
|
}
|
|
22949
23185
|
|
|
23186
|
+
/**
|
|
23187
|
+
* Transforms a `TwoWayBindingSet` expression into an expression that either
|
|
23188
|
+
* sets a value through the `twoWayBindingSet` instruction or falls back to setting
|
|
23189
|
+
* the value directly. E.g. the expression `TwoWayBindingSet(target, value)` becomes:
|
|
23190
|
+
* `ng.twoWayBindingSet(target, value) || (target = value)`.
|
|
23191
|
+
*/
|
|
23192
|
+
function transformTwoWayBindingSet(job) {
|
|
23193
|
+
for (const unit of job.units) {
|
|
23194
|
+
for (const op of unit.create) {
|
|
23195
|
+
if (op.kind === OpKind.TwoWayListener) {
|
|
23196
|
+
transformExpressionsInOp(op, (expr) => {
|
|
23197
|
+
if (expr instanceof TwoWayBindingSetExpr) {
|
|
23198
|
+
return wrapAction(expr.target, expr.value);
|
|
23199
|
+
}
|
|
23200
|
+
return expr;
|
|
23201
|
+
}, VisitorContextFlag.InChildOperation);
|
|
23202
|
+
}
|
|
23203
|
+
}
|
|
23204
|
+
}
|
|
23205
|
+
}
|
|
23206
|
+
function wrapSetOperation(target, value) {
|
|
23207
|
+
return twoWayBindingSet(target, value).or(target.set(value));
|
|
23208
|
+
}
|
|
23209
|
+
function isReadExpression(value) {
|
|
23210
|
+
return value instanceof ReadPropExpr || value instanceof ReadKeyExpr;
|
|
23211
|
+
}
|
|
23212
|
+
function wrapAction(target, value) {
|
|
23213
|
+
// The only officially supported expressions inside of a two-way binding are read expressions.
|
|
23214
|
+
if (isReadExpression(target)) {
|
|
23215
|
+
return wrapSetOperation(target, value);
|
|
23216
|
+
}
|
|
23217
|
+
// However, historically the expression parser was handling two-way events by appending `=$event`
|
|
23218
|
+
// to the raw string before attempting to parse it. This has led to bugs over the years (see
|
|
23219
|
+
// #37809) and to unintentionally supporting unassignable events in the two-way binding. The
|
|
23220
|
+
// logic below aims to emulate the old behavior while still supporting the new output format
|
|
23221
|
+
// which uses `twoWayBindingSet`. Note that the generated code doesn't necessarily make sense
|
|
23222
|
+
// based on what the user wrote, for example the event binding for `[(value)]="a ? b : c"`
|
|
23223
|
+
// would produce `ctx.a ? ctx.b : ctx.c = $event`. We aim to reproduce what the parser used
|
|
23224
|
+
// to generate before #54154.
|
|
23225
|
+
if (target instanceof BinaryOperatorExpr && isReadExpression(target.rhs)) {
|
|
23226
|
+
// `a && b` -> `ctx.a && twoWayBindingSet(ctx.b, $event) || (ctx.b = $event)`
|
|
23227
|
+
return new BinaryOperatorExpr(target.operator, target.lhs, wrapSetOperation(target.rhs, value));
|
|
23228
|
+
}
|
|
23229
|
+
// Note: this also supports nullish coalescing expressions which
|
|
23230
|
+
// would've been downleveled to ternary expressions by this point.
|
|
23231
|
+
if (target instanceof ConditionalExpr && isReadExpression(target.falseCase)) {
|
|
23232
|
+
// `a ? b : c` -> `ctx.a ? ctx.b : twoWayBindingSet(ctx.c, $event) || (ctx.c = $event)`
|
|
23233
|
+
return new ConditionalExpr(target.condition, target.trueCase, wrapSetOperation(target.falseCase, value));
|
|
23234
|
+
}
|
|
23235
|
+
// `!!a` -> `twoWayBindingSet(ctx.a, $event) || (ctx.a = $event)`
|
|
23236
|
+
// Note: previously we'd actually produce `!!(ctx.a = $event)`, but the wrapping
|
|
23237
|
+
// node doesn't affect the result so we don't need to carry it over.
|
|
23238
|
+
if (target instanceof NotExpr) {
|
|
23239
|
+
let expr = target.condition;
|
|
23240
|
+
while (true) {
|
|
23241
|
+
if (expr instanceof NotExpr) {
|
|
23242
|
+
expr = expr.condition;
|
|
23243
|
+
}
|
|
23244
|
+
else {
|
|
23245
|
+
if (isReadExpression(expr)) {
|
|
23246
|
+
return wrapSetOperation(expr, value);
|
|
23247
|
+
}
|
|
23248
|
+
break;
|
|
23249
|
+
}
|
|
23250
|
+
}
|
|
23251
|
+
}
|
|
23252
|
+
throw new Error(`Unsupported expression in two-way action binding.`);
|
|
23253
|
+
}
|
|
23254
|
+
|
|
22950
23255
|
/**
|
|
22951
23256
|
* When inside of a listener, we may need access to one or more enclosing views. Therefore, each
|
|
22952
23257
|
* view should save the current view, and each listener must have the ability to restore the
|
|
@@ -22962,7 +23267,7 @@ function saveAndRestoreView(job) {
|
|
|
22962
23267
|
}, new GetCurrentViewExpr(), VariableFlags.None),
|
|
22963
23268
|
]);
|
|
22964
23269
|
for (const op of unit.create) {
|
|
22965
|
-
if (op.kind !== OpKind.Listener) {
|
|
23270
|
+
if (op.kind !== OpKind.Listener && op.kind !== OpKind.TwoWayListener) {
|
|
22966
23271
|
continue;
|
|
22967
23272
|
}
|
|
22968
23273
|
// Embedded views always need the save/restore view operation.
|
|
@@ -23152,7 +23457,7 @@ function generateTemporaries(ops) {
|
|
|
23152
23457
|
generatedStatements.push(...Array.from(new Set(defs.values()))
|
|
23153
23458
|
.map(name => createStatementOp(new DeclareVarStmt(name))));
|
|
23154
23459
|
opCount++;
|
|
23155
|
-
if (op.kind === OpKind.Listener) {
|
|
23460
|
+
if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
|
|
23156
23461
|
op.handlerOps.prepend(generateTemporaries(op.handlerOps));
|
|
23157
23462
|
}
|
|
23158
23463
|
}
|
|
@@ -23400,6 +23705,9 @@ function varsUsedByOp(op) {
|
|
|
23400
23705
|
slots += op.expression.expressions.length;
|
|
23401
23706
|
}
|
|
23402
23707
|
return slots;
|
|
23708
|
+
case OpKind.TwoWayProperty:
|
|
23709
|
+
// Two-way properties can only have expressions so they only need one variable slot.
|
|
23710
|
+
return 1;
|
|
23403
23711
|
case OpKind.StyleProp:
|
|
23404
23712
|
case OpKind.ClassProp:
|
|
23405
23713
|
case OpKind.StyleMap:
|
|
@@ -23473,14 +23781,14 @@ function optimizeVariables(job) {
|
|
|
23473
23781
|
inlineAlwaysInlineVariables(unit.create);
|
|
23474
23782
|
inlineAlwaysInlineVariables(unit.update);
|
|
23475
23783
|
for (const op of unit.create) {
|
|
23476
|
-
if (op.kind === OpKind.Listener) {
|
|
23784
|
+
if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
|
|
23477
23785
|
inlineAlwaysInlineVariables(op.handlerOps);
|
|
23478
23786
|
}
|
|
23479
23787
|
}
|
|
23480
23788
|
optimizeVariablesInOpList(unit.create, job.compatibility);
|
|
23481
23789
|
optimizeVariablesInOpList(unit.update, job.compatibility);
|
|
23482
23790
|
for (const op of unit.create) {
|
|
23483
|
-
if (op.kind === OpKind.Listener) {
|
|
23791
|
+
if (op.kind === OpKind.Listener || op.kind === OpKind.TwoWayListener) {
|
|
23484
23792
|
optimizeVariablesInOpList(op.handlerOps, job.compatibility);
|
|
23485
23793
|
}
|
|
23486
23794
|
}
|
|
@@ -23935,6 +24243,7 @@ const phases = [
|
|
|
23935
24243
|
{ kind: CompilationJobKind.Tmpl, fn: generateTrackVariables },
|
|
23936
24244
|
{ kind: CompilationJobKind.Both, fn: resolveNames },
|
|
23937
24245
|
{ kind: CompilationJobKind.Tmpl, fn: resolveDeferTargetNames },
|
|
24246
|
+
{ kind: CompilationJobKind.Tmpl, fn: transformTwoWayBindingSet },
|
|
23938
24247
|
{ kind: CompilationJobKind.Tmpl, fn: optimizeTrackFns },
|
|
23939
24248
|
{ kind: CompilationJobKind.Both, fn: resolveContexts },
|
|
23940
24249
|
{ kind: CompilationJobKind.Both, fn: resolveSanitizers },
|
|
@@ -24731,8 +25040,7 @@ function convertAstWithInterpolation(job, value, i18nMeta, sourceSpan) {
|
|
|
24731
25040
|
// TODO: Can we populate Template binding kinds in ingest?
|
|
24732
25041
|
const BINDING_KINDS = new Map([
|
|
24733
25042
|
[0 /* e.BindingType.Property */, BindingKind.Property],
|
|
24734
|
-
|
|
24735
|
-
[5 /* e.BindingType.TwoWay */, BindingKind.Property],
|
|
25043
|
+
[5 /* e.BindingType.TwoWay */, BindingKind.TwoWayProperty],
|
|
24736
25044
|
[1 /* e.BindingType.Attribute */, BindingKind.Attribute],
|
|
24737
25045
|
[2 /* e.BindingType.Class */, BindingKind.ClassName],
|
|
24738
25046
|
[3 /* e.BindingType.Style */, BindingKind.StyleProperty],
|
|
@@ -24776,12 +25084,20 @@ function asMessage(i18nMeta) {
|
|
|
24776
25084
|
*/
|
|
24777
25085
|
function ingestElementBindings(unit, op, element) {
|
|
24778
25086
|
let bindings = new Array();
|
|
25087
|
+
let i18nAttributeBindingNames = new Set();
|
|
24779
25088
|
for (const attr of element.attributes) {
|
|
24780
25089
|
// Attribute literal bindings, such as `attr.foo="bar"`.
|
|
24781
25090
|
const securityContext = domSchema.securityContext(element.name, attr.name, true);
|
|
24782
25091
|
bindings.push(createBindingOp(op.xref, BindingKind.Attribute, attr.name, convertAstWithInterpolation(unit.job, attr.value, attr.i18n), null, securityContext, true, false, null, asMessage(attr.i18n), attr.sourceSpan));
|
|
25092
|
+
if (attr.i18n) {
|
|
25093
|
+
i18nAttributeBindingNames.add(attr.name);
|
|
25094
|
+
}
|
|
24783
25095
|
}
|
|
24784
25096
|
for (const input of element.inputs) {
|
|
25097
|
+
if (i18nAttributeBindingNames.has(input.name)) {
|
|
25098
|
+
console.error(`On component ${unit.job.componentName}, the binding ${input
|
|
25099
|
+
.name} is both an i18n attribute and a property. You may want to remove the property binding. This will become a compilation error in future versions of Angular.`);
|
|
25100
|
+
}
|
|
24785
25101
|
// All dynamic bindings (both attribute and property bindings).
|
|
24786
25102
|
bindings.push(createBindingOp(op.xref, BINDING_KINDS.get(input.type), input.name, convertAstWithInterpolation(unit.job, astOf(input.value), input.i18n), input.unit, input.securityContext, false, false, null, asMessage(input.i18n) ?? null, input.sourceSpan));
|
|
24787
25103
|
}
|
|
@@ -24791,7 +25107,12 @@ function ingestElementBindings(unit, op, element) {
|
|
|
24791
25107
|
if (output.type === 1 /* e.ParsedEventType.Animation */ && output.phase === null) {
|
|
24792
25108
|
throw Error('Animation listener should have a phase');
|
|
24793
25109
|
}
|
|
24794
|
-
|
|
25110
|
+
if (output.type === 2 /* e.ParsedEventType.TwoWay */) {
|
|
25111
|
+
unit.create.push(createTwoWayListenerOp(op.xref, op.handle, output.name, op.tag, makeTwoWayListenerHandlerOps(unit, output.handler, output.handlerSpan), output.sourceSpan));
|
|
25112
|
+
}
|
|
25113
|
+
else {
|
|
25114
|
+
unit.create.push(createListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.phase, output.target, false, output.sourceSpan));
|
|
25115
|
+
}
|
|
24795
25116
|
}
|
|
24796
25117
|
// If any of the bindings on this element have an i18n message, then an i18n attrs configuration
|
|
24797
25118
|
// op is also required.
|
|
@@ -24830,7 +25151,12 @@ function ingestTemplateBindings(unit, op, template, templateKind) {
|
|
|
24830
25151
|
throw Error('Animation listener should have a phase');
|
|
24831
25152
|
}
|
|
24832
25153
|
if (templateKind === TemplateKind.NgTemplate) {
|
|
24833
|
-
|
|
25154
|
+
if (output.type === 2 /* e.ParsedEventType.TwoWay */) {
|
|
25155
|
+
unit.create.push(createTwoWayListenerOp(op.xref, op.handle, output.name, op.tag, makeTwoWayListenerHandlerOps(unit, output.handler, output.handlerSpan), output.sourceSpan));
|
|
25156
|
+
}
|
|
25157
|
+
else {
|
|
25158
|
+
unit.create.push(createListenerOp(op.xref, op.handle, output.name, op.tag, makeListenerHandlerOps(unit, output.handler, output.handlerSpan), output.phase, output.target, false, output.sourceSpan));
|
|
25159
|
+
}
|
|
24834
25160
|
}
|
|
24835
25161
|
if (templateKind === TemplateKind.Structural &&
|
|
24836
25162
|
output.type !== 1 /* e.ParsedEventType.Animation */) {
|
|
@@ -24877,14 +25203,19 @@ function createTemplateBinding(view, xref, type, name, value, unit, securityCont
|
|
|
24877
25203
|
// If this is a structural template, then several kinds of bindings should not result in an
|
|
24878
25204
|
// update instruction.
|
|
24879
25205
|
if (templateKind === TemplateKind.Structural) {
|
|
24880
|
-
if (!isStructuralTemplateAttribute
|
|
24881
|
-
(type
|
|
24882
|
-
|
|
24883
|
-
|
|
24884
|
-
|
|
24885
|
-
|
|
24886
|
-
|
|
24887
|
-
|
|
25206
|
+
if (!isStructuralTemplateAttribute) {
|
|
25207
|
+
switch (type) {
|
|
25208
|
+
case 0 /* e.BindingType.Property */:
|
|
25209
|
+
case 2 /* e.BindingType.Class */:
|
|
25210
|
+
case 3 /* e.BindingType.Style */:
|
|
25211
|
+
// Because this binding doesn't really target the ng-template, it must be a binding on an
|
|
25212
|
+
// inner node of a structural template. We can't skip it entirely, because we still need
|
|
25213
|
+
// it on the ng-template's consts (e.g. for the purposes of directive matching). However,
|
|
25214
|
+
// we should not generate an update instruction for it.
|
|
25215
|
+
return createExtractedAttributeOp(xref, BindingKind.Property, null, name, null, null, i18nMessage, securityContext);
|
|
25216
|
+
case 5 /* e.BindingType.TwoWay */:
|
|
25217
|
+
return createExtractedAttributeOp(xref, BindingKind.TwoWayProperty, null, name, null, null, i18nMessage, securityContext);
|
|
25218
|
+
}
|
|
24888
25219
|
}
|
|
24889
25220
|
if (!isTextBinding && (type === 1 /* e.BindingType.Attribute */ || type === 4 /* e.BindingType.Animation */)) {
|
|
24890
25221
|
// Again, this binding doesn't really target the ng-template; it actually targets the element
|
|
@@ -24932,6 +25263,25 @@ function makeListenerHandlerOps(unit, handler, handlerSpan) {
|
|
|
24932
25263
|
handlerOps.push(createStatementOp(new ReturnStatement(returnExpr, returnExpr.sourceSpan)));
|
|
24933
25264
|
return handlerOps;
|
|
24934
25265
|
}
|
|
25266
|
+
function makeTwoWayListenerHandlerOps(unit, handler, handlerSpan) {
|
|
25267
|
+
handler = astOf(handler);
|
|
25268
|
+
const handlerOps = new Array();
|
|
25269
|
+
if (handler instanceof Chain) {
|
|
25270
|
+
if (handler.expressions.length === 1) {
|
|
25271
|
+
handler = handler.expressions[0];
|
|
25272
|
+
}
|
|
25273
|
+
else {
|
|
25274
|
+
// This is validated during parsing already, but we do it here just in case.
|
|
25275
|
+
throw new Error('Expected two-way listener to have a single expression.');
|
|
25276
|
+
}
|
|
25277
|
+
}
|
|
25278
|
+
const handlerExpr = convertAst(handler, unit.job, handlerSpan);
|
|
25279
|
+
const eventReference = new LexicalReadExpr('$event');
|
|
25280
|
+
const twoWaySetExpr = new TwoWayBindingSetExpr(handlerExpr, eventReference);
|
|
25281
|
+
handlerOps.push(createStatementOp(new ExpressionStatement(twoWaySetExpr)));
|
|
25282
|
+
handlerOps.push(createStatementOp(new ReturnStatement(eventReference)));
|
|
25283
|
+
return handlerOps;
|
|
25284
|
+
}
|
|
24935
25285
|
function astOf(ast) {
|
|
24936
25286
|
return ast instanceof ASTWithSource ? ast.ast : ast;
|
|
24937
25287
|
}
|
|
@@ -25434,7 +25784,7 @@ class BindingParser {
|
|
|
25434
25784
|
if (keySpan !== undefined) {
|
|
25435
25785
|
keySpan = moveParseSourceSpan(keySpan, new AbsoluteSourceSpan(keySpan.start.offset + 1, keySpan.end.offset));
|
|
25436
25786
|
}
|
|
25437
|
-
this._parseAnimationEvent(name, expression,
|
|
25787
|
+
this._parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan);
|
|
25438
25788
|
}
|
|
25439
25789
|
else {
|
|
25440
25790
|
this._parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan);
|
|
@@ -25444,11 +25794,11 @@ class BindingParser {
|
|
|
25444
25794
|
const prop = this._schemaRegistry.getMappedPropName(propName);
|
|
25445
25795
|
return calcPossibleSecurityContexts(this._schemaRegistry, selector, prop, isAttribute);
|
|
25446
25796
|
}
|
|
25447
|
-
_parseAnimationEvent(name, expression,
|
|
25797
|
+
_parseAnimationEvent(name, expression, sourceSpan, handlerSpan, targetEvents, keySpan) {
|
|
25448
25798
|
const matches = splitAtPeriod(name, [name, '']);
|
|
25449
25799
|
const eventName = matches[0];
|
|
25450
25800
|
const phase = matches[1].toLowerCase();
|
|
25451
|
-
const ast = this._parseAction(expression,
|
|
25801
|
+
const ast = this._parseAction(expression, handlerSpan);
|
|
25452
25802
|
targetEvents.push(new ParsedEvent(eventName, phase, 1 /* ParsedEventType.Animation */, ast, sourceSpan, handlerSpan, keySpan));
|
|
25453
25803
|
if (eventName.length === 0) {
|
|
25454
25804
|
this._reportError(`Animation event name is missing in binding`, sourceSpan);
|
|
@@ -25465,17 +25815,24 @@ class BindingParser {
|
|
|
25465
25815
|
_parseRegularEvent(name, expression, isAssignmentEvent, sourceSpan, handlerSpan, targetMatchableAttrs, targetEvents, keySpan) {
|
|
25466
25816
|
// long format: 'target: eventName'
|
|
25467
25817
|
const [target, eventName] = splitAtColon(name, [null, name]);
|
|
25468
|
-
const
|
|
25818
|
+
const prevErrorCount = this.errors.length;
|
|
25819
|
+
const ast = this._parseAction(expression, handlerSpan);
|
|
25820
|
+
const isValid = this.errors.length === prevErrorCount;
|
|
25469
25821
|
targetMatchableAttrs.push([name, ast.source]);
|
|
25822
|
+
// Don't try to validate assignment events if there were other
|
|
25823
|
+
// parsing errors to avoid adding more noise to the error logs.
|
|
25824
|
+
if (isAssignmentEvent && isValid && !this._isAllowedAssignmentEvent(ast)) {
|
|
25825
|
+
this._reportError('Unsupported expression in a two-way binding', sourceSpan);
|
|
25826
|
+
}
|
|
25470
25827
|
targetEvents.push(new ParsedEvent(eventName, target, isAssignmentEvent ? 2 /* ParsedEventType.TwoWay */ : 0 /* ParsedEventType.Regular */, ast, sourceSpan, handlerSpan, keySpan));
|
|
25471
25828
|
// Don't detect directives for event names for now,
|
|
25472
25829
|
// so don't add the event name to the matchableAttrs
|
|
25473
25830
|
}
|
|
25474
|
-
_parseAction(value,
|
|
25831
|
+
_parseAction(value, sourceSpan) {
|
|
25475
25832
|
const sourceInfo = (sourceSpan && sourceSpan.start || '(unknown').toString();
|
|
25476
25833
|
const absoluteOffset = (sourceSpan && sourceSpan.start) ? sourceSpan.start.offset : 0;
|
|
25477
25834
|
try {
|
|
25478
|
-
const ast = this._exprParser.parseAction(value,
|
|
25835
|
+
const ast = this._exprParser.parseAction(value, sourceInfo, absoluteOffset, this._interpolationConfig);
|
|
25479
25836
|
if (ast) {
|
|
25480
25837
|
this._reportExpressionParserErrors(ast.errors, sourceSpan);
|
|
25481
25838
|
}
|
|
@@ -25510,6 +25867,26 @@ class BindingParser {
|
|
|
25510
25867
|
this._reportError(report.msg, sourceSpan, ParseErrorLevel.ERROR);
|
|
25511
25868
|
}
|
|
25512
25869
|
}
|
|
25870
|
+
/**
|
|
25871
|
+
* Returns whether a parsed AST is allowed to be used within the event side of a two-way binding.
|
|
25872
|
+
* @param ast Parsed AST to be checked.
|
|
25873
|
+
*/
|
|
25874
|
+
_isAllowedAssignmentEvent(ast) {
|
|
25875
|
+
if (ast instanceof ASTWithSource) {
|
|
25876
|
+
return this._isAllowedAssignmentEvent(ast.ast);
|
|
25877
|
+
}
|
|
25878
|
+
if (ast instanceof NonNullAssert) {
|
|
25879
|
+
return this._isAllowedAssignmentEvent(ast.expression);
|
|
25880
|
+
}
|
|
25881
|
+
if (ast instanceof PropertyRead || ast instanceof KeyedRead) {
|
|
25882
|
+
return true;
|
|
25883
|
+
}
|
|
25884
|
+
if (ast instanceof Binary) {
|
|
25885
|
+
return (ast.operation === '&&' || ast.operation === '||' || ast.operation === '??') &&
|
|
25886
|
+
(ast.right instanceof PropertyRead || ast.right instanceof KeyedRead);
|
|
25887
|
+
}
|
|
25888
|
+
return ast instanceof Conditional || ast instanceof PrefixNot;
|
|
25889
|
+
}
|
|
25513
25890
|
}
|
|
25514
25891
|
class PipeCollector extends RecursiveAstVisitor {
|
|
25515
25892
|
constructor() {
|
|
@@ -26950,7 +27327,7 @@ class HtmlAstToIvyAst {
|
|
|
26950
27327
|
}
|
|
26951
27328
|
parseAssignmentEvent(name, expression, sourceSpan, valueSpan, targetMatchableAttrs, boundEvents, keySpan) {
|
|
26952
27329
|
const events = [];
|
|
26953
|
-
this.bindingParser.parseEvent(`${name}Change`,
|
|
27330
|
+
this.bindingParser.parseEvent(`${name}Change`, expression, /* isAssignmentEvent */ true, sourceSpan, valueSpan || sourceSpan, targetMatchableAttrs, events, keySpan);
|
|
26954
27331
|
addEvents(events, boundEvents);
|
|
26955
27332
|
}
|
|
26956
27333
|
reportError(message, sourceSpan, level = ParseErrorLevel.ERROR) {
|
|
@@ -27784,7 +28161,9 @@ function prepareEventListenerParameters(eventAst, handlerName = null, scope = nu
|
|
|
27784
28161
|
const implicitReceiverExpr = (scope === null || scope.bindingLevel === 0) ?
|
|
27785
28162
|
variable(CONTEXT_NAME) :
|
|
27786
28163
|
scope.getOrCreateSharedContextVar(0);
|
|
27787
|
-
const bindingStatements =
|
|
28164
|
+
const bindingStatements = eventAst.type === 2 /* ParsedEventType.TwoWay */ ?
|
|
28165
|
+
convertAssignmentActionBinding(scope, implicitReceiverExpr, handler, 'b', eventAst.handlerSpan, implicitReceiverAccesses, EVENT_BINDING_SCOPE_GLOBALS) :
|
|
28166
|
+
convertActionBinding(scope, implicitReceiverExpr, handler, 'b', eventAst.handlerSpan, implicitReceiverAccesses, EVENT_BINDING_SCOPE_GLOBALS);
|
|
27788
28167
|
const statements = [];
|
|
27789
28168
|
const variableDeclarations = scope?.variableDeclarations();
|
|
27790
28169
|
const restoreViewStatement = scope?.restoreViewStatement();
|
|
@@ -28352,7 +28731,7 @@ class TemplateDefinitionBuilder {
|
|
|
28352
28731
|
// Generate Listeners (outputs)
|
|
28353
28732
|
if (element.outputs.length > 0) {
|
|
28354
28733
|
for (const outputAst of element.outputs) {
|
|
28355
|
-
this.creationInstruction(outputAst.sourceSpan, Identifiers.listener, this.prepareListenerParameter(element.name, outputAst, elementIndex));
|
|
28734
|
+
this.creationInstruction(outputAst.sourceSpan, outputAst.type === 2 /* ParsedEventType.TwoWay */ ? Identifiers.twoWayListener : Identifiers.listener, this.prepareListenerParameter(element.name, outputAst, elementIndex));
|
|
28356
28735
|
}
|
|
28357
28736
|
}
|
|
28358
28737
|
// Note: it's important to keep i18n/i18nStart instructions after i18nAttributes and
|
|
@@ -28395,6 +28774,7 @@ class TemplateDefinitionBuilder {
|
|
|
28395
28774
|
this.allocateBindingSlots(value);
|
|
28396
28775
|
propertyBindings.push({
|
|
28397
28776
|
span: input.sourceSpan,
|
|
28777
|
+
reference: Identifiers.property,
|
|
28398
28778
|
paramsOrFn: getBindingFunctionParams(() => hasValue ? this.convertPropertyBinding(value) : emptyValueBindInstruction, prepareSyntheticPropertyName(input.name))
|
|
28399
28779
|
});
|
|
28400
28780
|
}
|
|
@@ -28433,6 +28813,8 @@ class TemplateDefinitionBuilder {
|
|
|
28433
28813
|
}
|
|
28434
28814
|
}
|
|
28435
28815
|
this.allocateBindingSlots(value);
|
|
28816
|
+
// Note: we don't separate two-way property bindings and regular ones,
|
|
28817
|
+
// because their assignment order needs to be maintained.
|
|
28436
28818
|
if (inputType === 0 /* BindingType.Property */ || inputType === 5 /* BindingType.TwoWay */) {
|
|
28437
28819
|
if (value instanceof Interpolation$1) {
|
|
28438
28820
|
// prop="{{value}}" and friends
|
|
@@ -28443,6 +28825,7 @@ class TemplateDefinitionBuilder {
|
|
|
28443
28825
|
// Collect all the properties so that we can chain into a single function at the end.
|
|
28444
28826
|
propertyBindings.push({
|
|
28445
28827
|
span: input.sourceSpan,
|
|
28828
|
+
reference: inputType === 5 /* BindingType.TwoWay */ ? Identifiers.twoWayProperty : Identifiers.property,
|
|
28446
28829
|
paramsOrFn: getBindingFunctionParams(() => this.convertPropertyBinding(value), attrName, params)
|
|
28447
28830
|
});
|
|
28448
28831
|
}
|
|
@@ -28475,7 +28858,7 @@ class TemplateDefinitionBuilder {
|
|
|
28475
28858
|
}
|
|
28476
28859
|
});
|
|
28477
28860
|
for (const propertyBinding of propertyBindings) {
|
|
28478
|
-
this.updateInstructionWithAdvance(elementIndex, propertyBinding.span,
|
|
28861
|
+
this.updateInstructionWithAdvance(elementIndex, propertyBinding.span, propertyBinding.reference, propertyBinding.paramsOrFn);
|
|
28479
28862
|
}
|
|
28480
28863
|
for (const attributeBinding of attributeBindings) {
|
|
28481
28864
|
this.updateInstructionWithAdvance(elementIndex, attributeBinding.span, Identifiers.attribute, attributeBinding.paramsOrFn);
|
|
@@ -28508,7 +28891,9 @@ class TemplateDefinitionBuilder {
|
|
|
28508
28891
|
}
|
|
28509
28892
|
}
|
|
28510
28893
|
const contextName = `${this.contextName}${contextNameSuffix}_${index}`;
|
|
28511
|
-
|
|
28894
|
+
// Note: For the unique name, we don't include an unique suffix, unless really needed.
|
|
28895
|
+
// This keeps the generated output more clean as most of the time, we don't expect conflicts.
|
|
28896
|
+
const name = this.constantPool.uniqueName(`${contextName}_Template`, /** alwaysIncludeSuffix */ false);
|
|
28512
28897
|
// Create the template function
|
|
28513
28898
|
const visitor = new TemplateDefinitionBuilder(this.constantPool, this._bindingScope, this.level + 1, contextName, this.i18n, index, name, this._namespace, this.fileBasedI18nSuffix, this.i18nUseExternalIds, this.deferBlocks, this.elementLocations, this.allDeferrableDepsFn, this._constants);
|
|
28514
28899
|
// Nested templates must not be visited until after their parent templates have completed
|
|
@@ -28571,7 +28956,7 @@ class TemplateDefinitionBuilder {
|
|
|
28571
28956
|
}
|
|
28572
28957
|
// Generate listeners for directive output
|
|
28573
28958
|
for (const outputAst of template.outputs) {
|
|
28574
|
-
this.creationInstruction(outputAst.sourceSpan, Identifiers.listener, this.prepareListenerParameter('ng_template', outputAst, templateIndex));
|
|
28959
|
+
this.creationInstruction(outputAst.sourceSpan, outputAst.type === 2 /* ParsedEventType.TwoWay */ ? Identifiers.twoWayListener : Identifiers.listener, this.prepareListenerParameter('ng_template', outputAst, templateIndex));
|
|
28575
28960
|
}
|
|
28576
28961
|
}
|
|
28577
28962
|
}
|
|
@@ -28825,7 +29210,9 @@ class TemplateDefinitionBuilder {
|
|
|
28825
29210
|
for (const deferredDep of metadata.deps) {
|
|
28826
29211
|
if (deferredDep.isDeferrable) {
|
|
28827
29212
|
// Callback function, e.g. `m () => m.MyCmp;`.
|
|
28828
|
-
const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)],
|
|
29213
|
+
const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)],
|
|
29214
|
+
// Default imports are always accessed through the `default` property.
|
|
29215
|
+
variable('m').prop(deferredDep.isDefaultImport ? 'default' : deferredDep.symbolName));
|
|
28829
29216
|
// Dynamic import, e.g. `import('./a').then(...)`.
|
|
28830
29217
|
const importExpr = (new DynamicImportExpr(deferredDep.importPath)).prop('then').callFn([innerFn]);
|
|
28831
29218
|
dependencyExp.push(importExpr);
|
|
@@ -30332,9 +30719,9 @@ function compileDirectiveFromMetadata(meta, constantPool, bindingParser) {
|
|
|
30332
30719
|
function createDeferredDepsFunction(constantPool, name, deps) {
|
|
30333
30720
|
// This defer block has deps for which we need to generate dynamic imports.
|
|
30334
30721
|
const dependencyExp = [];
|
|
30335
|
-
for (const [symbolName, importPath] of deps) {
|
|
30722
|
+
for (const [symbolName, { importPath, isDefaultImport }] of deps) {
|
|
30336
30723
|
// Callback function, e.g. `m () => m.MyCmp;`.
|
|
30337
|
-
const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(symbolName));
|
|
30724
|
+
const innerFn = arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(isDefaultImport ? 'default' : symbolName));
|
|
30338
30725
|
// Dynamic import, e.g. `import('./a').then(...)`.
|
|
30339
30726
|
const importExpr = (new DynamicImportExpr(importPath)).prop('then').callFn([innerFn]);
|
|
30340
30727
|
dependencyExp.push(importExpr);
|
|
@@ -32446,7 +32833,7 @@ function publishFacade(global) {
|
|
|
32446
32833
|
* @description
|
|
32447
32834
|
* Entry point for all public APIs of the compiler package.
|
|
32448
32835
|
*/
|
|
32449
|
-
const VERSION = new Version('17.2.0-
|
|
32836
|
+
const VERSION = new Version('17.2.0-rc.1');
|
|
32450
32837
|
|
|
32451
32838
|
class CompilerConfig {
|
|
32452
32839
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -33947,9 +34334,11 @@ function compileComponentClassMetadata(metadata, deferrableTypes) {
|
|
|
33947
34334
|
}
|
|
33948
34335
|
const dynamicImports = [];
|
|
33949
34336
|
const importedSymbols = [];
|
|
33950
|
-
for (const [symbolName, importPath] of deferrableTypes) {
|
|
34337
|
+
for (const [symbolName, { importPath, isDefaultImport }] of deferrableTypes) {
|
|
33951
34338
|
// e.g. `(m) => m.CmpA`
|
|
33952
|
-
const innerFn =
|
|
34339
|
+
const innerFn =
|
|
34340
|
+
// Default imports are always accessed through the `default` property.
|
|
34341
|
+
arrowFn([new FnParam('m', DYNAMIC_TYPE)], variable('m').prop(isDefaultImport ? 'default' : symbolName));
|
|
33953
34342
|
// e.g. `import('./cmp-a').then(...)`
|
|
33954
34343
|
const importExpr = (new DynamicImportExpr(importPath)).prop('then').callFn([innerFn]);
|
|
33955
34344
|
dynamicImports.push(importExpr);
|
|
@@ -34012,7 +34401,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$5 = '12.0.0';
|
|
|
34012
34401
|
function compileDeclareClassMetadata(metadata) {
|
|
34013
34402
|
const definitionMap = new DefinitionMap();
|
|
34014
34403
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$5));
|
|
34015
|
-
definitionMap.set('version', literal('17.2.0-
|
|
34404
|
+
definitionMap.set('version', literal('17.2.0-rc.1'));
|
|
34016
34405
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34017
34406
|
definitionMap.set('type', metadata.type);
|
|
34018
34407
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -34108,7 +34497,7 @@ function createDirectiveDefinitionMap(meta) {
|
|
|
34108
34497
|
const definitionMap = new DefinitionMap();
|
|
34109
34498
|
const minVersion = getMinimumVersionForPartialOutput(meta);
|
|
34110
34499
|
definitionMap.set('minVersion', literal(minVersion));
|
|
34111
|
-
definitionMap.set('version', literal('17.2.0-
|
|
34500
|
+
definitionMap.set('version', literal('17.2.0-rc.1'));
|
|
34112
34501
|
// e.g. `type: MyDirective`
|
|
34113
34502
|
definitionMap.set('type', meta.type.value);
|
|
34114
34503
|
if (meta.isStandalone) {
|
|
@@ -34500,7 +34889,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
34500
34889
|
function compileDeclareFactoryFunction(meta) {
|
|
34501
34890
|
const definitionMap = new DefinitionMap();
|
|
34502
34891
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
34503
|
-
definitionMap.set('version', literal('17.2.0-
|
|
34892
|
+
definitionMap.set('version', literal('17.2.0-rc.1'));
|
|
34504
34893
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34505
34894
|
definitionMap.set('type', meta.type.value);
|
|
34506
34895
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -34535,7 +34924,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
34535
34924
|
function createInjectableDefinitionMap(meta) {
|
|
34536
34925
|
const definitionMap = new DefinitionMap();
|
|
34537
34926
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
34538
|
-
definitionMap.set('version', literal('17.2.0-
|
|
34927
|
+
definitionMap.set('version', literal('17.2.0-rc.1'));
|
|
34539
34928
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34540
34929
|
definitionMap.set('type', meta.type.value);
|
|
34541
34930
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -34586,7 +34975,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
34586
34975
|
function createInjectorDefinitionMap(meta) {
|
|
34587
34976
|
const definitionMap = new DefinitionMap();
|
|
34588
34977
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
34589
|
-
definitionMap.set('version', literal('17.2.0-
|
|
34978
|
+
definitionMap.set('version', literal('17.2.0-rc.1'));
|
|
34590
34979
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34591
34980
|
definitionMap.set('type', meta.type.value);
|
|
34592
34981
|
definitionMap.set('providers', meta.providers);
|
|
@@ -34619,7 +35008,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
34619
35008
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
34620
35009
|
}
|
|
34621
35010
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
34622
|
-
definitionMap.set('version', literal('17.2.0-
|
|
35011
|
+
definitionMap.set('version', literal('17.2.0-rc.1'));
|
|
34623
35012
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34624
35013
|
definitionMap.set('type', meta.type.value);
|
|
34625
35014
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -34670,7 +35059,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
34670
35059
|
function createPipeDefinitionMap(meta) {
|
|
34671
35060
|
const definitionMap = new DefinitionMap();
|
|
34672
35061
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
34673
|
-
definitionMap.set('version', literal('17.2.0-
|
|
35062
|
+
definitionMap.set('version', literal('17.2.0-rc.1'));
|
|
34674
35063
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
34675
35064
|
// e.g. `type: MyPipe`
|
|
34676
35065
|
definitionMap.set('type', meta.type.value);
|
|
@@ -34703,5 +35092,5 @@ publishFacade(_global);
|
|
|
34703
35092
|
|
|
34704
35093
|
// This file is not used to build this module. It is only used during editing
|
|
34705
35094
|
|
|
34706
|
-
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, ArrowFunctionExpr, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, ForLoopBlock as TmplAstForLoopBlock, ForLoopBlockEmpty as TmplAstForLoopBlockEmpty, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, IfBlock as TmplAstIfBlock, IfBlockBranch as TmplAstIfBlockBranch, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, SwitchBlock as TmplAstSwitchBlock, SwitchBlockCase as TmplAstSwitchBlockCase, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, UnknownBlock as TmplAstUnknownBlock, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb,
|
|
35095
|
+
export { AST, ASTWithName, ASTWithSource, AbsoluteSourceSpan, ArrayType, ArrowFunctionExpr, AstMemoryEfficientTransformer, AstTransformer, Attribute, Binary, BinaryOperator, BinaryOperatorExpr, BindingPipe, Block, BlockParameter, BoundElementProperty, BuiltinType, BuiltinTypeName, CUSTOM_ELEMENTS_SCHEMA, Call, Chain, ChangeDetectionStrategy, CommaExpr, Comment, CompilerConfig, Conditional, ConditionalExpr, ConstantPool, CssSelector, DEFAULT_INTERPOLATION_CONFIG, DYNAMIC_TYPE, DeclareFunctionStmt, DeclareVarStmt, DomElementSchemaRegistry, DynamicImportExpr, EOF, Element, ElementSchemaRegistry, EmitterVisitorContext, EmptyExpr$1 as EmptyExpr, Expansion, ExpansionCase, Expression, ExpressionBinding, ExpressionStatement, ExpressionType, ExternalExpr, ExternalReference, FactoryTarget$1 as FactoryTarget, FunctionExpr, HtmlParser, HtmlTagDefinition, I18NHtmlParser, IfStmt, ImplicitReceiver, InstantiateExpr, Interpolation$1 as Interpolation, InterpolationConfig, InvokeFunctionExpr, JSDocComment, JitEvaluator, KeyedRead, KeyedWrite, LeadingComment, Lexer, LiteralArray, LiteralArrayExpr, LiteralExpr, LiteralMap, LiteralMapExpr, LiteralPrimitive, LocalizedString, MapType, MessageBundle, NONE_TYPE, NO_ERRORS_SCHEMA, NodeWithI18n, NonNullAssert, NotExpr, ParseError, ParseErrorLevel, ParseLocation, ParseSourceFile, ParseSourceSpan, ParseSpan, ParseTreeResult, ParsedEvent, ParsedProperty, ParsedPropertyType, ParsedVariable, Parser$1 as Parser, ParserError, PrefixNot, PropertyRead, PropertyWrite, R3BoundTarget, Identifiers as R3Identifiers, R3NgModuleMetadataKind, R3SelectorScopeMode, R3TargetBinder, R3TemplateDependencyKind, ReadKeyExpr, ReadPropExpr, ReadVarExpr, RecursiveAstVisitor, RecursiveVisitor, ResourceLoader, ReturnStatement, STRING_TYPE, SafeCall, SafeKeyedRead, SafePropertyRead, SelectorContext, SelectorListContext, SelectorMatcher, Serializer, SplitInterpolation, Statement, StmtModifier, TagContentType, TaggedTemplateExpr, TemplateBindingParseResult, TemplateLiteral, TemplateLiteralElement, Text, ThisReceiver, BoundAttribute as TmplAstBoundAttribute, BoundDeferredTrigger as TmplAstBoundDeferredTrigger, BoundEvent as TmplAstBoundEvent, BoundText as TmplAstBoundText, Content as TmplAstContent, DeferredBlock as TmplAstDeferredBlock, DeferredBlockError as TmplAstDeferredBlockError, DeferredBlockLoading as TmplAstDeferredBlockLoading, DeferredBlockPlaceholder as TmplAstDeferredBlockPlaceholder, DeferredTrigger as TmplAstDeferredTrigger, Element$1 as TmplAstElement, ForLoopBlock as TmplAstForLoopBlock, ForLoopBlockEmpty as TmplAstForLoopBlockEmpty, HoverDeferredTrigger as TmplAstHoverDeferredTrigger, Icu$1 as TmplAstIcu, IdleDeferredTrigger as TmplAstIdleDeferredTrigger, IfBlock as TmplAstIfBlock, IfBlockBranch as TmplAstIfBlockBranch, ImmediateDeferredTrigger as TmplAstImmediateDeferredTrigger, InteractionDeferredTrigger as TmplAstInteractionDeferredTrigger, RecursiveVisitor$1 as TmplAstRecursiveVisitor, Reference as TmplAstReference, SwitchBlock as TmplAstSwitchBlock, SwitchBlockCase as TmplAstSwitchBlockCase, Template as TmplAstTemplate, Text$3 as TmplAstText, TextAttribute as TmplAstTextAttribute, TimerDeferredTrigger as TmplAstTimerDeferredTrigger, UnknownBlock as TmplAstUnknownBlock, Variable as TmplAstVariable, ViewportDeferredTrigger as TmplAstViewportDeferredTrigger, Token, TokenType, TransplantedType, TreeError, Type, TypeModifier, TypeofExpr, Unary, UnaryOperator, UnaryOperatorExpr, VERSION, VariableBinding, Version, ViewEncapsulation, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr, Xliff, Xliff2, Xmb, XmlParser, Xtb, compileClassDebugInfo, compileClassMetadata, compileComponentClassMetadata, compileComponentFromMetadata, compileDeclareClassMetadata, compileDeclareComponentFromMetadata, compileDeclareDirectiveFromMetadata, compileDeclareFactoryFunction, compileDeclareInjectableFromMetadata, compileDeclareInjectorFromMetadata, compileDeclareNgModuleFromMetadata, compileDeclarePipeFromMetadata, compileDirectiveFromMetadata, compileFactoryFunction, compileInjectable, compileInjector, compileNgModule, compilePipeFromMetadata, computeMsgId, core, createCssSelectorFromNode, createInjectableType, createMayBeForwardRefExpression, devOnlyGuardedExpression, emitDistinctChangesOnlyDefaultValue, encapsulateStyle, getHtmlTagDefinition, getNsPrefix, getSafePropertyAccessString, identifierName, isIdentifier, isNgContainer, isNgContent, isNgTemplate, jsDocComment, leadingComment, literal, literalMap, makeBindingParser, mergeNsAndName, output_ast as outputAst, parseHostBindings, parseTemplate, preserveWhitespacesDefault, publishFacade, r3JitTypeSourceSpan, sanitizeIdentifier, splitNsName, verifyHostBindings, visitAll };
|
|
34707
35096
|
//# sourceMappingURL=compiler.mjs.map
|