@angular/compiler 17.0.0-next.0 → 17.0.0-next.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/render3/partial/class_metadata.mjs +1 -1
- package/esm2022/src/render3/partial/directive.mjs +9 -4
- 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 +3 -4
- package/esm2022/src/render3/r3_control_flow.mjs +68 -25
- package/esm2022/src/render3/r3_identifiers.mjs +2 -1
- package/esm2022/src/render3/view/template.mjs +159 -12
- package/esm2022/src/render3/view/util.mjs +4 -2
- package/esm2022/src/version.mjs +1 -1
- package/fesm2022/compiler.mjs +246 -49
- package/fesm2022/compiler.mjs.map +1 -1
- package/fesm2022/testing.mjs +1 -1
- package/index.d.ts +15 -3
- package/package.json +2 -2
- package/testing/index.d.ts +1 -1
package/fesm2022/compiler.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v17.0.0-next.
|
|
2
|
+
* @license Angular v17.0.0-next.1
|
|
3
3
|
* (c) 2010-2022 Google LLC. https://angular.io/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
@@ -2628,6 +2628,7 @@ class Identifiers {
|
|
|
2628
2628
|
static { this.deferPrefetchOnHover = { name: 'ɵɵdeferPrefetchOnHover', moduleName: CORE }; }
|
|
2629
2629
|
static { this.deferPrefetchOnInteraction = { name: 'ɵɵdeferPrefetchOnInteraction', moduleName: CORE }; }
|
|
2630
2630
|
static { this.deferPrefetchOnViewport = { name: 'ɵɵdeferPrefetchOnViewport', moduleName: CORE }; }
|
|
2631
|
+
static { this.conditional = { name: 'ɵɵconditional', moduleName: CORE }; }
|
|
2631
2632
|
static { this.text = { name: 'ɵɵtext', moduleName: CORE }; }
|
|
2632
2633
|
static { this.enableBindings = { name: 'ɵɵenableBindings', moduleName: CORE }; }
|
|
2633
2634
|
static { this.disableBindings = { name: 'ɵɵdisableBindings', moduleName: CORE }; }
|
|
@@ -4053,12 +4054,11 @@ class SwitchBlockCase {
|
|
|
4053
4054
|
}
|
|
4054
4055
|
}
|
|
4055
4056
|
class ForLoopBlock {
|
|
4056
|
-
constructor(itemName, expression,
|
|
4057
|
-
// TODO(crisbeto): figure out if trackBy should be an AST
|
|
4058
|
-
trackBy, children, empty, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
4057
|
+
constructor(itemName, expression, trackBy, contextVariables, children, empty, sourceSpan, startSourceSpan, endSourceSpan) {
|
|
4059
4058
|
this.itemName = itemName;
|
|
4060
4059
|
this.expression = expression;
|
|
4061
4060
|
this.trackBy = trackBy;
|
|
4061
|
+
this.contextVariables = contextVariables;
|
|
4062
4062
|
this.children = children;
|
|
4063
4063
|
this.empty = empty;
|
|
4064
4064
|
this.sourceSpan = sourceSpan;
|
|
@@ -4869,7 +4869,7 @@ function declareI18nVariable(variable) {
|
|
|
4869
4869
|
/**
|
|
4870
4870
|
* Checks whether an object key contains potentially unsafe chars, thus the key should be wrapped in
|
|
4871
4871
|
* quotes. Note: we do not wrap all keys into quotes, as it may have impact on minification and may
|
|
4872
|
-
*
|
|
4872
|
+
* not work in some cases when object keys are mangled by a minifier.
|
|
4873
4873
|
*
|
|
4874
4874
|
* TODO(FW-1136): this is a temporary solution, we need to come up with a better way of working with
|
|
4875
4875
|
* inputs that contain potentially unsafe chars.
|
|
@@ -4889,6 +4889,8 @@ const IMPLICIT_REFERENCE = '$implicit';
|
|
|
4889
4889
|
const NON_BINDABLE_ATTR = 'ngNonBindable';
|
|
4890
4890
|
/** Name for the variable keeping track of the context returned by `ɵɵrestoreView`. */
|
|
4891
4891
|
const RESTORED_VIEW_CONTEXT_NAME = 'restoredCtx';
|
|
4892
|
+
/** Special value representing a direct access to a template's context. */
|
|
4893
|
+
const DIRECT_CONTEXT_REFERENCE = '#context';
|
|
4892
4894
|
/**
|
|
4893
4895
|
* Maximum length of a single instruction chain. Because our output AST uses recursion, we're
|
|
4894
4896
|
* limited in how many expressions we can nest before we reach the call stack limit. This
|
|
@@ -21470,6 +21472,10 @@ const FOR_LOOP_TRACK_PATTERN = /^track\s+(.*)/;
|
|
|
21470
21472
|
const CONDITIONAL_ALIAS_PATTERN = /^as\s+(.*)/;
|
|
21471
21473
|
/** Pattern used to identify an `else if` block. */
|
|
21472
21474
|
const ELSE_IF_PATTERN = /^if\s/;
|
|
21475
|
+
/** Pattern used to identify a `let` parameter. */
|
|
21476
|
+
const FOR_LOOP_LET_PATTERN = /^let\s+(.*)/;
|
|
21477
|
+
/** Names of variables that are allowed to be used in the `let` expression of a `for` loop. */
|
|
21478
|
+
const ALLOWED_FOR_LOOP_LET_VARIABLES = new Set(['$index', '$first', '$last', '$even', '$odd', '$count']);
|
|
21473
21479
|
/** Creates an `if` loop block from an HTML AST node. */
|
|
21474
21480
|
function createIfBlock(ast, visitor, bindingParser) {
|
|
21475
21481
|
const errors = validateIfBlock(ast);
|
|
@@ -21485,9 +21491,7 @@ function createIfBlock(ast, visitor, bindingParser) {
|
|
|
21485
21491
|
branches.push(new IfBlockBranch(null, children, null, block.sourceSpan, block.startSourceSpan));
|
|
21486
21492
|
continue;
|
|
21487
21493
|
}
|
|
21488
|
-
|
|
21489
|
-
const expressionStart = block.name === 'if' ? 0 : 2;
|
|
21490
|
-
const params = parseConditionalBlockParameters(block, errors, bindingParser, expressionStart);
|
|
21494
|
+
const params = parseConditionalBlockParameters(block, errors, bindingParser);
|
|
21491
21495
|
if (params !== null) {
|
|
21492
21496
|
branches.push(new IfBlockBranch(params.expression, children, params.expressionAlias, block.sourceSpan, block.startSourceSpan));
|
|
21493
21497
|
}
|
|
@@ -21525,7 +21529,7 @@ function createForLoop(ast, visitor, bindingParser) {
|
|
|
21525
21529
|
errors.push(new ParseError(ast.sourceSpan, 'For loop must have a "track" expression'));
|
|
21526
21530
|
}
|
|
21527
21531
|
else {
|
|
21528
|
-
node = new ForLoopBlock(params.itemName, params.expression, params.trackBy, visitAll(visitor, primaryBlock.children), empty, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
21532
|
+
node = new ForLoopBlock(params.itemName, params.expression, params.trackBy, params.context, visitAll(visitor, primaryBlock.children), empty, ast.sourceSpan, ast.startSourceSpan, ast.endSourceSpan);
|
|
21529
21533
|
}
|
|
21530
21534
|
}
|
|
21531
21535
|
return { node, errors };
|
|
@@ -21578,29 +21582,50 @@ function parseForLoopParameters(block, errors, bindingParser) {
|
|
|
21578
21582
|
const result = {
|
|
21579
21583
|
itemName,
|
|
21580
21584
|
trackBy: null,
|
|
21581
|
-
expression:
|
|
21582
|
-
|
|
21583
|
-
// because we know that it'll be the last matching group. Ideally we could use the `d`
|
|
21584
|
-
// flag on the regex and get the index from `match.indices`, but it's unclear if we can
|
|
21585
|
-
// use it yet since it's a relatively new feature. See:
|
|
21586
|
-
// https://github.com/tc39/proposal-regexp-match-indices
|
|
21587
|
-
Math.max(0, expressionParam.expression.lastIndexOf(rawExpression)))
|
|
21585
|
+
expression: parseBlockParameterToBinding(expressionParam, bindingParser, rawExpression),
|
|
21586
|
+
context: null,
|
|
21588
21587
|
};
|
|
21589
21588
|
for (const param of secondaryParams) {
|
|
21589
|
+
const letMatch = param.expression.match(FOR_LOOP_LET_PATTERN);
|
|
21590
|
+
if (letMatch !== null) {
|
|
21591
|
+
result.context = result.context || {};
|
|
21592
|
+
parseLetParameter(param.sourceSpan, letMatch[1], result.context, errors);
|
|
21593
|
+
continue;
|
|
21594
|
+
}
|
|
21590
21595
|
const trackMatch = param.expression.match(FOR_LOOP_TRACK_PATTERN);
|
|
21591
|
-
|
|
21592
|
-
|
|
21593
|
-
|
|
21594
|
-
|
|
21596
|
+
if (trackMatch !== null) {
|
|
21597
|
+
if (result.trackBy !== null) {
|
|
21598
|
+
errors.push(new ParseError(param.sourceSpan, 'For loop can only have one "track" expression'));
|
|
21599
|
+
}
|
|
21600
|
+
else {
|
|
21601
|
+
result.trackBy = parseBlockParameterToBinding(param, bindingParser, trackMatch[1]);
|
|
21602
|
+
}
|
|
21603
|
+
continue;
|
|
21604
|
+
}
|
|
21605
|
+
errors.push(new ParseError(param.sourceSpan, `Unrecognized loop paramater "${param.expression}"`));
|
|
21606
|
+
}
|
|
21607
|
+
return result;
|
|
21608
|
+
}
|
|
21609
|
+
/** Parses the `let` parameter of a `for` loop block. */
|
|
21610
|
+
function parseLetParameter(sourceSpan, expression, context, errors) {
|
|
21611
|
+
const parts = expression.split(',');
|
|
21612
|
+
for (const part of parts) {
|
|
21613
|
+
const expressionParts = part.split('=');
|
|
21614
|
+
const name = expressionParts.length === 2 ? expressionParts[0].trim() : '';
|
|
21615
|
+
const variableName = expressionParts.length === 2 ? expressionParts[1].trim() : '';
|
|
21616
|
+
if (name.length === 0 || variableName.length === 0) {
|
|
21617
|
+
errors.push(new ParseError(sourceSpan, `Invalid for loop "let" parameter. Parameter should match the pattern "<name> = <variable name>"`));
|
|
21595
21618
|
}
|
|
21596
|
-
else if (
|
|
21597
|
-
errors.push(new ParseError(
|
|
21619
|
+
else if (!ALLOWED_FOR_LOOP_LET_VARIABLES.has(variableName)) {
|
|
21620
|
+
errors.push(new ParseError(sourceSpan, `Unknown "let" parameter variable "${variableName}". The allowed variables are: ${Array.from(ALLOWED_FOR_LOOP_LET_VARIABLES).join(', ')}`));
|
|
21621
|
+
}
|
|
21622
|
+
else if (context.hasOwnProperty(variableName)) {
|
|
21623
|
+
errors.push(new ParseError(sourceSpan, `Duplicate "let" parameter variable "${variableName}"`));
|
|
21598
21624
|
}
|
|
21599
21625
|
else {
|
|
21600
|
-
|
|
21626
|
+
context[variableName] = name;
|
|
21601
21627
|
}
|
|
21602
21628
|
}
|
|
21603
|
-
return result;
|
|
21604
21629
|
}
|
|
21605
21630
|
/** Checks that the shape of a `if` block is valid. Returns an array of errors. */
|
|
21606
21631
|
function validateIfBlock(ast) {
|
|
@@ -21665,17 +21690,34 @@ function validateSwitchBlock(ast) {
|
|
|
21665
21690
|
}
|
|
21666
21691
|
return errors;
|
|
21667
21692
|
}
|
|
21668
|
-
|
|
21669
|
-
|
|
21670
|
-
|
|
21693
|
+
function parseBlockParameterToBinding(ast, bindingParser, part = 0) {
|
|
21694
|
+
let start;
|
|
21695
|
+
let end;
|
|
21696
|
+
if (typeof part === 'number') {
|
|
21697
|
+
start = part;
|
|
21698
|
+
end = ast.expression.length;
|
|
21699
|
+
}
|
|
21700
|
+
else {
|
|
21701
|
+
// Note: `lastIndexOf` here should be enough to know the start index of the expression,
|
|
21702
|
+
// because we know that it'll be at the end of the param. Ideally we could use the `d`
|
|
21703
|
+
// flag when matching via regex and get the index from `match.indices`, but it's unclear
|
|
21704
|
+
// if we can use it yet since it's a relatively new feature. See:
|
|
21705
|
+
// https://github.com/tc39/proposal-regexp-match-indices
|
|
21706
|
+
start = Math.max(0, ast.expression.lastIndexOf(part));
|
|
21707
|
+
end = start + part.length;
|
|
21708
|
+
}
|
|
21709
|
+
return bindingParser.parseBinding(ast.expression.slice(start, end), false, ast.sourceSpan, ast.sourceSpan.start.offset + start);
|
|
21671
21710
|
}
|
|
21672
21711
|
/** Parses the parameter of a conditional block (`if` or `else if`). */
|
|
21673
|
-
function parseConditionalBlockParameters(block, errors, bindingParser
|
|
21712
|
+
function parseConditionalBlockParameters(block, errors, bindingParser) {
|
|
21674
21713
|
if (block.parameters.length === 0) {
|
|
21675
21714
|
errors.push(new ParseError(block.sourceSpan, 'Conditional block does not have an expression'));
|
|
21676
21715
|
return null;
|
|
21677
21716
|
}
|
|
21678
|
-
const
|
|
21717
|
+
const isPrimaryIfBlock = block.name === 'if';
|
|
21718
|
+
const expression =
|
|
21719
|
+
// Expressions for `{:else if}` blocks start at 2 to skip the `if` from the expression.
|
|
21720
|
+
parseBlockParameterToBinding(block.parameters[0], bindingParser, isPrimaryIfBlock ? 0 : 2);
|
|
21679
21721
|
let expressionAlias = null;
|
|
21680
21722
|
// Start from 1 since we processed the first parameter already.
|
|
21681
21723
|
for (let i = 1; i < block.parameters.length; i++) {
|
|
@@ -21686,6 +21728,9 @@ function parseConditionalBlockParameters(block, errors, bindingParser, primaryEx
|
|
|
21686
21728
|
if (aliasMatch === null) {
|
|
21687
21729
|
errors.push(new ParseError(param.sourceSpan, `Unrecognized conditional paramater "${param.expression}"`));
|
|
21688
21730
|
}
|
|
21731
|
+
else if (!isPrimaryIfBlock) {
|
|
21732
|
+
errors.push(new ParseError(param.sourceSpan, '"as" expression is only allowed on the primary "if" block'));
|
|
21733
|
+
}
|
|
21689
21734
|
else if (expressionAlias !== null) {
|
|
21690
21735
|
errors.push(new ParseError(param.sourceSpan, 'Conditional can only have one "as" expression'));
|
|
21691
21736
|
}
|
|
@@ -23760,6 +23805,11 @@ class TemplateDefinitionBuilder {
|
|
|
23760
23805
|
this._currentIndex = 0;
|
|
23761
23806
|
/** Temporary variable declarations generated from visiting pipes, literals, etc. */
|
|
23762
23807
|
this._tempVariables = [];
|
|
23808
|
+
/**
|
|
23809
|
+
* Temporary variable used to store state between control flow instructions.
|
|
23810
|
+
* Should be accessed via the `allocateControlFlowTempVariable` method.
|
|
23811
|
+
*/
|
|
23812
|
+
this._controlFlowTempVariable = null;
|
|
23763
23813
|
/**
|
|
23764
23814
|
* List of callbacks to build nested templates. Nested templates must not be visited until
|
|
23765
23815
|
* after the parent template has finished visiting all of its nodes. This ensures that all
|
|
@@ -23793,6 +23843,8 @@ class TemplateDefinitionBuilder {
|
|
|
23793
23843
|
this.visitDeferredBlockError = invalid;
|
|
23794
23844
|
this.visitDeferredBlockLoading = invalid;
|
|
23795
23845
|
this.visitDeferredBlockPlaceholder = invalid;
|
|
23846
|
+
this.visitIfBlockBranch = invalid;
|
|
23847
|
+
this.visitSwitchBlockCase = invalid;
|
|
23796
23848
|
this._bindingScope = parentBindingScope.nestedScope(level);
|
|
23797
23849
|
// Turn the relative context file path into an identifier by replacing non-alphanumeric
|
|
23798
23850
|
// characters with underscores.
|
|
@@ -23905,8 +23957,16 @@ class TemplateDefinitionBuilder {
|
|
|
23905
23957
|
registerContextVariables(variable$1) {
|
|
23906
23958
|
const scopedName = this._bindingScope.freshReferenceName();
|
|
23907
23959
|
const retrievalLevel = this.level;
|
|
23960
|
+
const isDirect = variable$1.value === DIRECT_CONTEXT_REFERENCE;
|
|
23908
23961
|
const lhs = variable(variable$1.name + scopedName);
|
|
23909
|
-
this._bindingScope.set(retrievalLevel, variable$1.name,
|
|
23962
|
+
this._bindingScope.set(retrievalLevel, variable$1.name, scope => {
|
|
23963
|
+
// If we're at the top level and we're referring to the context variable directly, we
|
|
23964
|
+
// can do so through the implicit receiver, instead of renaming it. Note that this does
|
|
23965
|
+
// not apply to listeners, because they need to restore the context.
|
|
23966
|
+
return isDirect && scope.bindingLevel === retrievalLevel && !scope.isListenerScope() ?
|
|
23967
|
+
variable(CONTEXT_NAME) :
|
|
23968
|
+
lhs;
|
|
23969
|
+
}, 1 /* DeclarationPriority.CONTEXT */, (scope, relativeLevel) => {
|
|
23910
23970
|
let rhs;
|
|
23911
23971
|
if (scope.bindingLevel === retrievalLevel) {
|
|
23912
23972
|
if (scope.isListenerScope() && scope.hasRestoreViewVariable()) {
|
|
@@ -23917,6 +23977,11 @@ class TemplateDefinitionBuilder {
|
|
|
23917
23977
|
rhs = variable(RESTORED_VIEW_CONTEXT_NAME);
|
|
23918
23978
|
scope.notifyRestoredViewContextUse();
|
|
23919
23979
|
}
|
|
23980
|
+
else if (isDirect) {
|
|
23981
|
+
// If we have a direct read of the context at the top level we don't need to
|
|
23982
|
+
// declare any variables and we can refer to it directly.
|
|
23983
|
+
return [];
|
|
23984
|
+
}
|
|
23920
23985
|
else {
|
|
23921
23986
|
// e.g. ctx
|
|
23922
23987
|
rhs = variable(CONTEXT_NAME);
|
|
@@ -23927,8 +23992,11 @@ class TemplateDefinitionBuilder {
|
|
|
23927
23992
|
// e.g. ctx_r0 OR x(2);
|
|
23928
23993
|
rhs = sharedCtxVar ? sharedCtxVar : generateNextContextExpr(relativeLevel);
|
|
23929
23994
|
}
|
|
23930
|
-
|
|
23931
|
-
|
|
23995
|
+
return [
|
|
23996
|
+
// e.g. const $items$ = x(2) for direct context references and
|
|
23997
|
+
// const $item$ = x(2).$implicit for indirect ones.
|
|
23998
|
+
lhs.set(isDirect ? rhs : rhs.prop(variable$1.value || IMPLICIT_REFERENCE)).toConstDecl()
|
|
23999
|
+
];
|
|
23932
24000
|
});
|
|
23933
24001
|
}
|
|
23934
24002
|
i18nAppendBindings(expressions) {
|
|
@@ -24490,6 +24558,118 @@ class TemplateDefinitionBuilder {
|
|
|
24490
24558
|
}
|
|
24491
24559
|
return null;
|
|
24492
24560
|
}
|
|
24561
|
+
visitIfBlock(block) {
|
|
24562
|
+
// We have to process the block in two steps: once here and again in the update instruction
|
|
24563
|
+
// callback in order to generate the correct expressions when pipes or pure functions are
|
|
24564
|
+
// used inside the branch expressions.
|
|
24565
|
+
const branchData = block.branches.map(({ expression, expressionAlias, children, sourceSpan }) => {
|
|
24566
|
+
let processedExpression = null;
|
|
24567
|
+
if (expression !== null) {
|
|
24568
|
+
processedExpression = expression.visit(this._valueConverter);
|
|
24569
|
+
this.allocateBindingSlots(processedExpression);
|
|
24570
|
+
}
|
|
24571
|
+
// If the branch has an alias, it'll be assigned directly to the container's context.
|
|
24572
|
+
// We define a variable referring directly to the context so that any nested usages can be
|
|
24573
|
+
// rewritten to refer to it.
|
|
24574
|
+
const variables = expressionAlias ?
|
|
24575
|
+
[new Variable(expressionAlias, DIRECT_CONTEXT_REFERENCE, sourceSpan, sourceSpan)] :
|
|
24576
|
+
undefined;
|
|
24577
|
+
return {
|
|
24578
|
+
index: this.createEmbeddedTemplateFn(null, children, '_Conditional', sourceSpan, variables),
|
|
24579
|
+
expression: processedExpression,
|
|
24580
|
+
alias: expressionAlias
|
|
24581
|
+
};
|
|
24582
|
+
});
|
|
24583
|
+
// Use the index of the first block as the index for the entire container.
|
|
24584
|
+
const containerIndex = branchData[0].index;
|
|
24585
|
+
const paramsCallback = () => {
|
|
24586
|
+
let contextVariable = null;
|
|
24587
|
+
const generateBranch = (branchIndex) => {
|
|
24588
|
+
// If we've gone beyond the last branch, return the special -1 value which means that no
|
|
24589
|
+
// view will be rendered. Note that we don't need to reset the context here, because -1
|
|
24590
|
+
// won't render a view so the passed-in context won't be captured.
|
|
24591
|
+
if (branchIndex > branchData.length - 1) {
|
|
24592
|
+
return literal(-1);
|
|
24593
|
+
}
|
|
24594
|
+
const { index, expression, alias } = branchData[branchIndex];
|
|
24595
|
+
// If the branch has no expression, it means that it's the final `else`.
|
|
24596
|
+
// Return its index and stop the recursion. Assumes that there's only one
|
|
24597
|
+
// `else` condition and that it's the last branch.
|
|
24598
|
+
if (expression === null) {
|
|
24599
|
+
return literal(index);
|
|
24600
|
+
}
|
|
24601
|
+
let comparisonTarget;
|
|
24602
|
+
if (alias) {
|
|
24603
|
+
// If the branch is aliased, we need to assign the expression value to the temporary
|
|
24604
|
+
// variable and then pass it into `conditional`. E.g. for the expression:
|
|
24605
|
+
// `{#if foo(); as alias}...{/if}` we have to generate:
|
|
24606
|
+
// ```
|
|
24607
|
+
// let temp;
|
|
24608
|
+
// conditional(0, (temp = ctx.foo()) ? 0 : -1, temp);
|
|
24609
|
+
// ```
|
|
24610
|
+
contextVariable = this.allocateControlFlowTempVariable();
|
|
24611
|
+
comparisonTarget = contextVariable.set(this.convertPropertyBinding(expression));
|
|
24612
|
+
}
|
|
24613
|
+
else {
|
|
24614
|
+
comparisonTarget = this.convertPropertyBinding(expression);
|
|
24615
|
+
}
|
|
24616
|
+
return comparisonTarget.conditional(literal(index), generateBranch(branchIndex + 1));
|
|
24617
|
+
};
|
|
24618
|
+
const params = [literal(containerIndex), generateBranch(0)];
|
|
24619
|
+
if (contextVariable !== null) {
|
|
24620
|
+
params.push(contextVariable);
|
|
24621
|
+
}
|
|
24622
|
+
return params;
|
|
24623
|
+
};
|
|
24624
|
+
this.updateInstructionWithAdvance(containerIndex, block.branches[0].sourceSpan, Identifiers.conditional, paramsCallback);
|
|
24625
|
+
}
|
|
24626
|
+
visitSwitchBlock(block) {
|
|
24627
|
+
// Allocate slots for the primary block expression.
|
|
24628
|
+
const blockExpression = block.expression.visit(this._valueConverter);
|
|
24629
|
+
this.allocateBindingSlots(blockExpression);
|
|
24630
|
+
// We have to process the block in two steps: once here and again in the update instruction
|
|
24631
|
+
// callback in order to generate the correct expressions when pipes or pure functions are used.
|
|
24632
|
+
const caseData = block.cases.map(currentCase => {
|
|
24633
|
+
const index = this.createEmbeddedTemplateFn(null, currentCase.children, '_Case', currentCase.sourceSpan);
|
|
24634
|
+
let expression = null;
|
|
24635
|
+
if (currentCase.expression !== null) {
|
|
24636
|
+
expression = currentCase.expression.visit(this._valueConverter);
|
|
24637
|
+
this.allocateBindingSlots(expression);
|
|
24638
|
+
}
|
|
24639
|
+
return { index, expression };
|
|
24640
|
+
});
|
|
24641
|
+
// Use the index of the first block as the index for the entire container.
|
|
24642
|
+
const containerIndex = caseData[0].index;
|
|
24643
|
+
this.updateInstructionWithAdvance(containerIndex, block.sourceSpan, Identifiers.conditional, () => {
|
|
24644
|
+
const generateCases = (caseIndex) => {
|
|
24645
|
+
// If we've gone beyond the last branch, return the special -1
|
|
24646
|
+
// value which means that no view will be rendered.
|
|
24647
|
+
if (caseIndex > caseData.length - 1) {
|
|
24648
|
+
return literal(-1);
|
|
24649
|
+
}
|
|
24650
|
+
const { index, expression } = caseData[caseIndex];
|
|
24651
|
+
// If the case has no expression, it means that it's the `default` case.
|
|
24652
|
+
// Return its index and stop the recursion. Assumes that there's only one
|
|
24653
|
+
// `default` condition and that it's defined last.
|
|
24654
|
+
if (expression === null) {
|
|
24655
|
+
return literal(index);
|
|
24656
|
+
}
|
|
24657
|
+
// If this is the very first comparison, we need to assign the value of the primary
|
|
24658
|
+
// expression as a part of the comparison so the remaining cases can reuse it. In practice
|
|
24659
|
+
// this looks as follows:
|
|
24660
|
+
// ```
|
|
24661
|
+
// let temp;
|
|
24662
|
+
// conditional(1, (temp = ctx.foo) === 1 ? 1 : temp === 2 ? 2 : temp === 3 ? 3 : 4);
|
|
24663
|
+
// ```
|
|
24664
|
+
const comparisonTarget = caseIndex === 0 ?
|
|
24665
|
+
this.allocateControlFlowTempVariable().set(this.convertPropertyBinding(blockExpression)) :
|
|
24666
|
+
this.allocateControlFlowTempVariable();
|
|
24667
|
+
return comparisonTarget.identical(this.convertPropertyBinding(expression))
|
|
24668
|
+
.conditional(literal(index), generateCases(caseIndex + 1));
|
|
24669
|
+
};
|
|
24670
|
+
return [literal(containerIndex), generateCases(0)];
|
|
24671
|
+
});
|
|
24672
|
+
}
|
|
24493
24673
|
visitDeferredBlock(deferred) {
|
|
24494
24674
|
const { loading, placeholder, error, triggers, prefetchTriggers } = deferred;
|
|
24495
24675
|
const primaryTemplateIndex = this.createEmbeddedTemplateFn(null, deferred.children, '_Defer', deferred.sourceSpan);
|
|
@@ -24593,13 +24773,9 @@ class TemplateDefinitionBuilder {
|
|
|
24593
24773
|
allocateDataSlot() {
|
|
24594
24774
|
return this._dataIndex++;
|
|
24595
24775
|
}
|
|
24596
|
-
// TODO: implement
|
|
24597
|
-
visitSwitchBlock(block) { }
|
|
24598
|
-
visitSwitchBlockCase(block) { }
|
|
24776
|
+
// TODO: implement for loop instructions
|
|
24599
24777
|
visitForLoopBlock(block) { }
|
|
24600
24778
|
visitForLoopBlockEmpty(block) { }
|
|
24601
|
-
visitIfBlock(block) { }
|
|
24602
|
-
visitIfBlockBranch(block) { }
|
|
24603
24779
|
getConstCount() {
|
|
24604
24780
|
return this._dataIndex;
|
|
24605
24781
|
}
|
|
@@ -24724,6 +24900,21 @@ class TemplateDefinitionBuilder {
|
|
|
24724
24900
|
this._tempVariables.push(...stmts);
|
|
24725
24901
|
return args;
|
|
24726
24902
|
}
|
|
24903
|
+
/**
|
|
24904
|
+
* Creates and returns a variable that can be used to
|
|
24905
|
+
* store the state between control flow instructions.
|
|
24906
|
+
*/
|
|
24907
|
+
allocateControlFlowTempVariable() {
|
|
24908
|
+
// Note: the assumption here is that we'll only need one temporary variable for all control
|
|
24909
|
+
// flow instructions. It's expected that any instructions will overwrite it before passing it
|
|
24910
|
+
// into the parameters.
|
|
24911
|
+
if (this._controlFlowTempVariable === null) {
|
|
24912
|
+
const name = `${this.contextName}_contFlowTmp`;
|
|
24913
|
+
this._tempVariables.push(new DeclareVarStmt(name));
|
|
24914
|
+
this._controlFlowTempVariable = variable(name);
|
|
24915
|
+
}
|
|
24916
|
+
return this._controlFlowTempVariable;
|
|
24917
|
+
}
|
|
24727
24918
|
/**
|
|
24728
24919
|
* Prepares all attribute expression values for the `TAttributes` array.
|
|
24729
24920
|
*
|
|
@@ -25045,7 +25236,7 @@ class BindingScope {
|
|
|
25045
25236
|
if (value.declareLocalCallback && !value.declare) {
|
|
25046
25237
|
value.declare = true;
|
|
25047
25238
|
}
|
|
25048
|
-
return value.lhs;
|
|
25239
|
+
return typeof value.lhs === 'function' ? value.lhs(this) : value.lhs;
|
|
25049
25240
|
}
|
|
25050
25241
|
current = current.parent;
|
|
25051
25242
|
}
|
|
@@ -25149,7 +25340,8 @@ class BindingScope {
|
|
|
25149
25340
|
const componentValue = this.map.get(SHARED_CONTEXT_KEY + 0);
|
|
25150
25341
|
componentValue.declare = true;
|
|
25151
25342
|
this.maybeRestoreView();
|
|
25152
|
-
|
|
25343
|
+
const lhs = typeof componentValue.lhs === 'function' ? componentValue.lhs(this) : componentValue.lhs;
|
|
25344
|
+
return name === DIRECT_CONTEXT_REFERENCE ? lhs : lhs.prop(name);
|
|
25153
25345
|
}
|
|
25154
25346
|
maybeRestoreView() {
|
|
25155
25347
|
// View restoration is required for listener instructions inside embedded views, because
|
|
@@ -26898,7 +27090,7 @@ function publishFacade(global) {
|
|
|
26898
27090
|
* @description
|
|
26899
27091
|
* Entry point for all public APIs of the compiler package.
|
|
26900
27092
|
*/
|
|
26901
|
-
const VERSION = new Version('17.0.0-next.
|
|
27093
|
+
const VERSION = new Version('17.0.0-next.1');
|
|
26902
27094
|
|
|
26903
27095
|
class CompilerConfig {
|
|
26904
27096
|
constructor({ defaultEncapsulation = ViewEncapsulation.Emulated, useJit = true, missingTranslation = null, preserveWhitespaces, strictInjectionParameters } = {}) {
|
|
@@ -29056,7 +29248,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$6 = '12.0.0';
|
|
|
29056
29248
|
function compileDeclareClassMetadata(metadata) {
|
|
29057
29249
|
const definitionMap = new DefinitionMap();
|
|
29058
29250
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$6));
|
|
29059
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
29251
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
29060
29252
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
29061
29253
|
definitionMap.set('type', metadata.type);
|
|
29062
29254
|
definitionMap.set('decorators', metadata.decorators);
|
|
@@ -29142,7 +29334,7 @@ function compileDependency(dep) {
|
|
|
29142
29334
|
*
|
|
29143
29335
|
* Do not include any prerelease in these versions as they are ignored.
|
|
29144
29336
|
*/
|
|
29145
|
-
const MINIMUM_PARTIAL_LINKER_VERSION$5 = '
|
|
29337
|
+
const MINIMUM_PARTIAL_LINKER_VERSION$5 = '16.1.0';
|
|
29146
29338
|
/**
|
|
29147
29339
|
* Compile a directive declaration defined by the `R3DirectiveMetadata`.
|
|
29148
29340
|
*/
|
|
@@ -29158,8 +29350,13 @@ function compileDeclareDirectiveFromMetadata(meta) {
|
|
|
29158
29350
|
*/
|
|
29159
29351
|
function createDirectiveDefinitionMap(meta) {
|
|
29160
29352
|
const definitionMap = new DefinitionMap();
|
|
29161
|
-
|
|
29162
|
-
|
|
29353
|
+
const hasTransformFunctions = Object.values(meta.inputs).some(input => input.transformFunction !== null);
|
|
29354
|
+
// Note: in order to allow consuming Angular libraries that have been compiled with 16.1+ in
|
|
29355
|
+
// Angular 16.0, we only force a minimum version of 16.1 if input transform feature as introduced
|
|
29356
|
+
// in 16.1 is actually used.
|
|
29357
|
+
const minVersion = hasTransformFunctions ? MINIMUM_PARTIAL_LINKER_VERSION$5 : '14.0.0';
|
|
29358
|
+
definitionMap.set('minVersion', literal(minVersion));
|
|
29359
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
29163
29360
|
// e.g. `type: MyDirective`
|
|
29164
29361
|
definitionMap.set('type', meta.type.value);
|
|
29165
29362
|
if (meta.isStandalone) {
|
|
@@ -29390,7 +29587,7 @@ const MINIMUM_PARTIAL_LINKER_VERSION$4 = '12.0.0';
|
|
|
29390
29587
|
function compileDeclareFactoryFunction(meta) {
|
|
29391
29588
|
const definitionMap = new DefinitionMap();
|
|
29392
29589
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$4));
|
|
29393
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
29590
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
29394
29591
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
29395
29592
|
definitionMap.set('type', meta.type.value);
|
|
29396
29593
|
definitionMap.set('deps', compileDependencies(meta.deps));
|
|
@@ -29425,7 +29622,7 @@ function compileDeclareInjectableFromMetadata(meta) {
|
|
|
29425
29622
|
function createInjectableDefinitionMap(meta) {
|
|
29426
29623
|
const definitionMap = new DefinitionMap();
|
|
29427
29624
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$3));
|
|
29428
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
29625
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
29429
29626
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
29430
29627
|
definitionMap.set('type', meta.type.value);
|
|
29431
29628
|
// Only generate providedIn property if it has a non-null value
|
|
@@ -29476,7 +29673,7 @@ function compileDeclareInjectorFromMetadata(meta) {
|
|
|
29476
29673
|
function createInjectorDefinitionMap(meta) {
|
|
29477
29674
|
const definitionMap = new DefinitionMap();
|
|
29478
29675
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$2));
|
|
29479
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
29676
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
29480
29677
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
29481
29678
|
definitionMap.set('type', meta.type.value);
|
|
29482
29679
|
definitionMap.set('providers', meta.providers);
|
|
@@ -29509,7 +29706,7 @@ function createNgModuleDefinitionMap(meta) {
|
|
|
29509
29706
|
throw new Error('Invalid path! Local compilation mode should not get into the partial compilation path');
|
|
29510
29707
|
}
|
|
29511
29708
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION$1));
|
|
29512
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
29709
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
29513
29710
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
29514
29711
|
definitionMap.set('type', meta.type.value);
|
|
29515
29712
|
// We only generate the keys in the metadata if the arrays contain values.
|
|
@@ -29560,7 +29757,7 @@ function compileDeclarePipeFromMetadata(meta) {
|
|
|
29560
29757
|
function createPipeDefinitionMap(meta) {
|
|
29561
29758
|
const definitionMap = new DefinitionMap();
|
|
29562
29759
|
definitionMap.set('minVersion', literal(MINIMUM_PARTIAL_LINKER_VERSION));
|
|
29563
|
-
definitionMap.set('version', literal('17.0.0-next.
|
|
29760
|
+
definitionMap.set('version', literal('17.0.0-next.1'));
|
|
29564
29761
|
definitionMap.set('ngImport', importExpr(Identifiers.core));
|
|
29565
29762
|
// e.g. `type: MyPipe`
|
|
29566
29763
|
definitionMap.set('type', meta.type.value);
|