@lwc/template-compiler 8.22.1 → 8.22.4

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.
@@ -1,6 +1,13 @@
1
1
  import * as t from '../shared/estree';
2
- import type { Attribute, BaseElement, ComplexExpression, Property } from '../shared/types';
2
+ import type { Attribute, BaseElement, Expression, ComplexExpression, Property } from '../shared/types';
3
3
  import type CodeGen from './codegen';
4
+ /**
5
+ * Bind the passed expression to the component instance. It applies the following transformation to the expression:
6
+ * - {value} --> {$cmp.value}
7
+ * - {value[index]} --> {$cmp.value[$cmp.index]}
8
+ * @param expression
9
+ */
10
+ export declare function bindExpression(expression: Expression | t.Literal | ComplexExpression, isLocalIdentifier: (node: t.Identifier) => boolean, templateInstanceName: string, experimentalComplexExpressions: boolean): t.Expression;
4
11
  /**
5
12
  * Bind the passed expression to the component instance. It applies the following
6
13
  * transformation to the expression:
@@ -22,6 +29,6 @@ import type CodeGen from './codegen';
22
29
  * @param expression
23
30
  * @param codeGen
24
31
  */
25
- export declare function bindComplexExpression(expression: ComplexExpression, codeGen: CodeGen): t.Expression;
32
+ export declare function bindComplexExpression(expression: ComplexExpression, isLocalIdentifier: (node: t.Identifier) => boolean, templateInstanceName: string): t.Expression;
26
33
  export declare function bindAttributeExpression(attr: Attribute | Property, element: BaseElement, codeGen: CodeGen, addLegacySanitizationHook: boolean): import("estree").Identifier | import("estree").MemberExpression | import("estree").ArrayExpression | import("estree").ObjectExpression | import("estree").ArrowFunctionExpression | import("estree").UnaryExpression | import("estree").SimpleLiteral | import("estree").RegExpLiteral | import("estree").BigIntLiteral | import("estree").AssignmentExpression | import("estree").AwaitExpression | import("estree").BinaryExpression | import("estree").SimpleCallExpression | import("estree").NewExpression | import("estree").ChainExpression | import("estree").ClassExpression | import("estree").ConditionalExpression | import("estree").FunctionExpression | import("estree").ImportExpression | import("estree").LogicalExpression | import("estree").MetaProperty | import("estree").SequenceExpression | import("estree").TaggedTemplateExpression | import("estree").TemplateLiteral | import("estree").ThisExpression | import("estree").UpdateExpression | import("estree").YieldExpression;
27
34
  //# sourceMappingURL=expression.d.ts.map
package/dist/index.cjs.js CHANGED
@@ -10087,104 +10087,6 @@ function isReservedES6Keyword(str) {
10087
10087
  return REVERSED_KEYWORDS.has(str);
10088
10088
  }
10089
10089
 
10090
- /*
10091
- * Copyright (c) 2018, salesforce.com, inc.
10092
- * All rights reserved.
10093
- * SPDX-License-Identifier: MIT
10094
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
10095
- */
10096
- const EXPRESSION_SYMBOL_START = '{';
10097
- const EXPRESSION_SYMBOL_END = '}';
10098
- const POTENTIAL_EXPRESSION_RE = /^.?{.+}.*$/;
10099
- const WHITESPACES_RE = /\s/;
10100
- function isExpression(source) {
10101
- // Issue #3418: Legacy behavior, previous regex treated "{}" attribute value as non expression
10102
- return source[0] === '{' && source.slice(-1) === '}' && source.length > 2;
10103
- }
10104
- function isPotentialExpression(source) {
10105
- return !!source.match(POTENTIAL_EXPRESSION_RE);
10106
- }
10107
- function validateExpression(source, node, config) {
10108
- const isValidNode = isIdentifier(node) || isMemberExpression(node);
10109
- // INVALID_XYZ_COMPLEX provides additional context to the user if CTE is enabled.
10110
- // The author may not have delimited the CTE with quotes, resulting in it being parsed
10111
- // as a legacy expression.
10112
- errors.invariant(isValidNode, config.experimentalComplexExpressions
10113
- ? errors.ParserDiagnostics.INVALID_NODE_COMPLEX
10114
- : errors.ParserDiagnostics.INVALID_NODE, [node.type, source]);
10115
- if (isMemberExpression(node)) {
10116
- errors.invariant(config.experimentalComputedMemberExpression || !node.computed, config.experimentalComplexExpressions
10117
- ? errors.ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED_COMPLEX
10118
- : errors.ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED, [source]);
10119
- const { object, property } = node;
10120
- if (!isIdentifier(object)) {
10121
- validateExpression(source, object, config);
10122
- }
10123
- if (!isIdentifier(property)) {
10124
- validateExpression(source, property, config);
10125
- }
10126
- }
10127
- }
10128
- function validateSourceIsParsedExpression(source, parsedExpression) {
10129
- if (parsedExpression.end === source.length - 1) {
10130
- return;
10131
- }
10132
- let unclosedParenthesisCount = 0;
10133
- for (let i = 0, n = parsedExpression.start; i < n; i++) {
10134
- if (source[i] === '(') {
10135
- unclosedParenthesisCount++;
10136
- }
10137
- }
10138
- // source[source.length - 1] === '}', n = source.length - 1 is to avoid processing '}'.
10139
- for (let i = parsedExpression.end, n = source.length - 1; i < n; i++) {
10140
- const character = source[i];
10141
- if (character === ')') {
10142
- unclosedParenthesisCount--;
10143
- }
10144
- else if (character === ';') {
10145
- // acorn parseExpressionAt will stop at the first ";", it may be that the expression is not
10146
- // a multiple expression ({foo;}), but this is a case that we explicitly do not want to support.
10147
- // in such case, let's fail with the same error as if it were a multiple expression.
10148
- errors.invariant(false, errors.ParserDiagnostics.MULTIPLE_EXPRESSIONS);
10149
- }
10150
- else {
10151
- errors.invariant(WHITESPACES_RE.test(character), errors.ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, ['Unexpected end of expression']);
10152
- }
10153
- }
10154
- errors.invariant(unclosedParenthesisCount === 0, errors.ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, [
10155
- 'Unexpected end of expression',
10156
- ]);
10157
- }
10158
- function parseExpression(ctx, source, location) {
10159
- const { ecmaVersion } = ctx;
10160
- return ctx.withErrorWrapping(() => {
10161
- const parsed = acorn.parseExpressionAt(source, 1, {
10162
- ecmaVersion,
10163
- allowAwaitOutsideFunction: false,
10164
- onComment: () => errors.invariant(false, errors.ParserDiagnostics.INVALID_EXPR_COMMENTS_DISALLOWED),
10165
- });
10166
- validateSourceIsParsedExpression(source, parsed);
10167
- validateExpression(source, parsed, ctx.config);
10168
- return { ...parsed, location };
10169
- }, errors.ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, location, (err) => `Invalid expression ${source} - ${err.message}`);
10170
- }
10171
- function parseIdentifier(ctx, source, location) {
10172
- let isValid = true;
10173
- isValid = acorn.isIdentifierStart(source.charCodeAt(0));
10174
- for (let i = 1; i < source.length && isValid; i++) {
10175
- isValid = acorn.isIdentifierChar(source.charCodeAt(i));
10176
- }
10177
- if (isValid && !isReservedES6Keyword(source)) {
10178
- return {
10179
- ...identifier(source),
10180
- location,
10181
- };
10182
- }
10183
- else {
10184
- ctx.throwAtLocation(errors.ParserDiagnostics.INVALID_IDENTIFIER, location, [source]);
10185
- }
10186
- }
10187
-
10188
10090
  /**
10189
10091
  * @typedef { import('estree').Node} Node
10190
10092
  * @typedef {{
@@ -10616,6 +10518,120 @@ function parseComplexExpression(ctx, source, templateSource, location, expressio
10616
10518
  }, errors.ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, location, (err) => `Invalid expression ${source} - ${err.message}`);
10617
10519
  }
10618
10520
 
10521
+ /*
10522
+ * Copyright (c) 2018, salesforce.com, inc.
10523
+ * All rights reserved.
10524
+ * SPDX-License-Identifier: MIT
10525
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
10526
+ */
10527
+ const EXPRESSION_SYMBOL_START = '{';
10528
+ const EXPRESSION_SYMBOL_END = '}';
10529
+ const POTENTIAL_EXPRESSION_RE = /^.?{.+}.*$/;
10530
+ const WHITESPACES_RE = /\s/;
10531
+ function isExpression(source) {
10532
+ // Issue #3418: Legacy behavior, previous regex treated "{}" attribute value as non expression
10533
+ return source[0] === '{' && source.slice(-1) === '}' && source.length > 2;
10534
+ }
10535
+ function isPotentialExpression(source) {
10536
+ return !!source.match(POTENTIAL_EXPRESSION_RE);
10537
+ }
10538
+ const minCteApiVersion = shared.minApiVersion(11 /* APIFeature.ENABLE_COMPLEX_TEMPLATE_EXPRESSIONS */);
10539
+ function validateExpression(source, node, ctx, unquotedAttributeExpression) {
10540
+ const cteOnlyNode = !isIdentifier(node) && !isMemberExpression(node);
10541
+ // If this node is not an identifier or a member expression (the only two nodes allowed if complexTemplateExpressions are disabled),
10542
+ // then we throw if the following invariants do not hold true.
10543
+ if (cteOnlyNode) {
10544
+ // complexTemplateExpressions must be enabled if this is a cteOnlyNode.
10545
+ errors.invariant(ctx.config.experimentalComplexExpressions, errors.ParserDiagnostics.INVALID_NODE, [
10546
+ node.type,
10547
+ ]);
10548
+ // complexTemplateExpressions must be enabled and the component API version must be sufficient.
10549
+ errors.invariant(isComplexTemplateExpressionEnabled(ctx), errors.ParserDiagnostics.INVALID_NODE_CTE_API_VERSION, [node.type, ctx.apiVersion, minCteApiVersion]);
10550
+ // complexTemplateExpressions must be enabled, the component API version must be sufficient and the expression should not be
10551
+ // an unquoted attribute expression.
10552
+ errors.invariant(isComplexTemplateExpressionEnabled(ctx) && !unquotedAttributeExpression, errors.ParserDiagnostics.INVALID_NODE_CTE_UNQUOTED, [node.type, source]);
10553
+ }
10554
+ if (isMemberExpression(node)) {
10555
+ // If this is a computed node and experimentalComputedMemberExpressions is not enabled,
10556
+ // then we throw if the following invariants do not hold true.
10557
+ if (!ctx.config.experimentalComputedMemberExpression && node.computed) {
10558
+ // complexTemplateExpressions must be enabled.
10559
+ errors.invariant(ctx.config.experimentalComplexExpressions, errors.ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED, [source]);
10560
+ // complexTemplateExpressions must be enabled and the component API version must be sufficient.
10561
+ errors.invariant(isComplexTemplateExpressionEnabled(ctx), errors.ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED_CTE_API_VERSION, [source, ctx.apiVersion, minCteApiVersion]);
10562
+ // complexTemplateExpressions must be enabled, the component API version must be sufficient and the expression
10563
+ // should not be an unquoted attribute expression.
10564
+ errors.invariant(isComplexTemplateExpressionEnabled(ctx) && !unquotedAttributeExpression, errors.ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED_CTE_UNQUOTED, [source]);
10565
+ }
10566
+ const { object, property } = node;
10567
+ if (!isIdentifier(object)) {
10568
+ validateExpression(source, object, ctx, unquotedAttributeExpression);
10569
+ }
10570
+ if (!isIdentifier(property)) {
10571
+ validateExpression(source, property, ctx, unquotedAttributeExpression);
10572
+ }
10573
+ }
10574
+ }
10575
+ function validateSourceIsParsedExpression(source, parsedExpression) {
10576
+ if (parsedExpression.end === source.length - 1) {
10577
+ return;
10578
+ }
10579
+ let unclosedParenthesisCount = 0;
10580
+ for (let i = 0, n = parsedExpression.start; i < n; i++) {
10581
+ if (source[i] === '(') {
10582
+ unclosedParenthesisCount++;
10583
+ }
10584
+ }
10585
+ // source[source.length - 1] === '}', n = source.length - 1 is to avoid processing '}'.
10586
+ for (let i = parsedExpression.end, n = source.length - 1; i < n; i++) {
10587
+ const character = source[i];
10588
+ if (character === ')') {
10589
+ unclosedParenthesisCount--;
10590
+ }
10591
+ else if (character === ';') {
10592
+ // acorn parseExpressionAt will stop at the first ";", it may be that the expression is not
10593
+ // a multiple expression ({foo;}), but this is a case that we explicitly do not want to support.
10594
+ // in such case, let's fail with the same error as if it were a multiple expression.
10595
+ errors.invariant(false, errors.ParserDiagnostics.MULTIPLE_EXPRESSIONS);
10596
+ }
10597
+ else {
10598
+ errors.invariant(WHITESPACES_RE.test(character), errors.ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, ['Unexpected end of expression']);
10599
+ }
10600
+ }
10601
+ errors.invariant(unclosedParenthesisCount === 0, errors.ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, [
10602
+ 'Unexpected end of expression',
10603
+ ]);
10604
+ }
10605
+ function parseExpression(ctx, source, location, unquotedAttributeExpression) {
10606
+ const { ecmaVersion } = ctx;
10607
+ return ctx.withErrorWrapping(() => {
10608
+ const parsed = acorn.parseExpressionAt(source, 1, {
10609
+ ecmaVersion,
10610
+ allowAwaitOutsideFunction: false,
10611
+ onComment: () => errors.invariant(false, errors.ParserDiagnostics.INVALID_EXPR_COMMENTS_DISALLOWED),
10612
+ });
10613
+ validateSourceIsParsedExpression(source, parsed);
10614
+ validateExpression(source, parsed, ctx, unquotedAttributeExpression);
10615
+ return { ...parsed, location };
10616
+ }, errors.ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, location, (err) => `Invalid expression ${source} - ${err.message}`);
10617
+ }
10618
+ function parseIdentifier(ctx, source, location) {
10619
+ let isValid = true;
10620
+ isValid = acorn.isIdentifierStart(source.charCodeAt(0));
10621
+ for (let i = 1; i < source.length && isValid; i++) {
10622
+ isValid = acorn.isIdentifierChar(source.charCodeAt(i));
10623
+ }
10624
+ if (isValid && !isReservedES6Keyword(source)) {
10625
+ return {
10626
+ ...identifier(source),
10627
+ location,
10628
+ };
10629
+ }
10630
+ else {
10631
+ ctx.throwAtLocation(errors.ParserDiagnostics.INVALID_IDENTIFIER, location, [source]);
10632
+ }
10633
+ }
10634
+
10619
10635
  /*
10620
10636
  * Copyright (c) 2018, salesforce.com, inc.
10621
10637
  * All rights reserved.
@@ -11081,7 +11097,9 @@ function normalizeAttributeValue(ctx, raw, tag, attr, location) {
11081
11097
  const isQuoted = isQuotedAttribute(rawAttrVal);
11082
11098
  const isEscaped = isEscapedAttribute(rawAttrVal);
11083
11099
  if (!isEscaped && isExpression(value)) {
11084
- if (isQuoted && !isComplexTemplateExpressionEnabled(ctx)) {
11100
+ // Don't test for the API version here, just check if CTE is enabled.
11101
+ // We can provide more specific errors w.r.t API versions after the expression has been parsed and we know what it is.
11102
+ if (isQuoted && !ctx.config.experimentalComplexExpressions) {
11085
11103
  // <input value="{myValue}" />
11086
11104
  // -> ambiguity if the attribute value is a template identifier or a string literal.
11087
11105
  const unquoted = raw.replace(/"/g, '');
@@ -11527,7 +11545,7 @@ function parseText(ctx, rawText, sourceLocation, location) {
11527
11545
  }
11528
11546
  let value;
11529
11547
  if (isExpression(token)) {
11530
- value = parseExpression(ctx, token, sourceLocation);
11548
+ value = parseExpression(ctx, token, sourceLocation, false);
11531
11549
  }
11532
11550
  else {
11533
11551
  value = literal(decodeTextContent(token));
@@ -11579,7 +11597,7 @@ function parseTextNode(ctx, parse5Text) {
11579
11597
  return [];
11580
11598
  }
11581
11599
  const sourceLocation$1 = sourceLocation(location);
11582
- return ctx.config.experimentalComplexExpressions
11600
+ return isComplexTemplateExpressionEnabled(ctx)
11583
11601
  ? parseTextComplex(ctx, rawText, sourceLocation$1, location)
11584
11602
  : parseText(ctx, rawText, sourceLocation$1, location);
11585
11603
  }
@@ -12462,13 +12480,13 @@ function getTemplateAttribute(ctx, tag, attribute$1, attributeLocation) {
12462
12480
  to be used.
12463
12481
  */
12464
12482
  const isPotentialComplexExpression = quotedExpression && !escapedExpression && value.startsWith(EXPRESSION_SYMBOL_START);
12465
- if (ctx.config.experimentalComplexExpressions && isPotentialComplexExpression) {
12483
+ if (isComplexTemplateExpressionEnabled(ctx) && isPotentialComplexExpression) {
12466
12484
  const attributeNameOffset = attribute$1.name.length + 2; // The +2 accounts for the '="' in the attribute: attr="...
12467
12485
  const templateSource = ctx.getSource(attributeLocation.startOffset + attributeNameOffset);
12468
12486
  attrValue = parseComplexExpression(ctx, value, templateSource, location).expression;
12469
12487
  }
12470
12488
  else if (isExpression(value) && !escapedExpression) {
12471
- attrValue = parseExpression(ctx, value, location);
12489
+ attrValue = parseExpression(ctx, value, location, !quotedExpression);
12472
12490
  }
12473
12491
  else if (isBooleanAttribute) {
12474
12492
  attrValue = literal(true);
@@ -13067,6 +13085,48 @@ function serializeStaticElement(element, codeGen) {
13067
13085
  * SPDX-License-Identifier: MIT
13068
13086
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
13069
13087
  */
13088
+ /**
13089
+ * Bind the passed expression to the component instance. It applies the following transformation to the expression:
13090
+ * - {value} --> {$cmp.value}
13091
+ * - {value[index]} --> {$cmp.value[$cmp.index]}
13092
+ * @param expression
13093
+ */
13094
+ function bindExpression(expression, isLocalIdentifier, templateInstanceName, experimentalComplexExpressions) {
13095
+ if (isIdentifier(expression)) {
13096
+ if (!isLocalIdentifier(expression)) {
13097
+ return memberExpression(identifier(templateInstanceName), expression);
13098
+ }
13099
+ else {
13100
+ return expression;
13101
+ }
13102
+ }
13103
+ // TODO [#3370]: remove experimental template expression flag
13104
+ if (experimentalComplexExpressions) {
13105
+ // Cloning here is necessary because `this.replace()` is destructive, and we might use the
13106
+ // node later during static content optimization
13107
+ expression = structuredClone(expression);
13108
+ return bindComplexExpression(expression, isLocalIdentifier, templateInstanceName);
13109
+ }
13110
+ // Cloning here is necessary because `this.replace()` is destructive, and we might use the
13111
+ // node later during static content optimization
13112
+ expression = structuredClone(expression);
13113
+ // TODO [#3370]: when the template expression flag is removed, the
13114
+ // ComplexExpression type should be redefined as an ESTree Node. Doing
13115
+ // so when the flag is still in place results in a cascade of required
13116
+ // type changes across the codebase.
13117
+ walk(expression, {
13118
+ leave(node, parent) {
13119
+ if (parent !== null &&
13120
+ isIdentifier(node) &&
13121
+ isMemberExpression(parent) &&
13122
+ parent.object === node &&
13123
+ !isLocalIdentifier(node)) {
13124
+ this.replace(memberExpression(identifier(templateInstanceName), node));
13125
+ }
13126
+ },
13127
+ });
13128
+ return expression;
13129
+ }
13070
13130
  /**
13071
13131
  * Bind the passed expression to the component instance. It applies the following
13072
13132
  * transformation to the expression:
@@ -13088,7 +13148,7 @@ function serializeStaticElement(element, codeGen) {
13088
13148
  * @param expression
13089
13149
  * @param codeGen
13090
13150
  */
13091
- function bindComplexExpression(expression, codeGen) {
13151
+ function bindComplexExpression(expression, isLocalIdentifier, templateInstanceName) {
13092
13152
  const expressionScopes = new ExpressionScopes();
13093
13153
  // TODO [#3370]: when the template expression flag is removed, the
13094
13154
  // ComplexExpression type should be redefined as an ESTree Node. Doing
@@ -13112,9 +13172,9 @@ function bindComplexExpression(expression, codeGen) {
13112
13172
  isIdentifier$1 &&
13113
13173
  !(isMemberExpression(parent) && parent.property === node && !parent.computed) &&
13114
13174
  !(isProperty$1(parent) && parent.key === node) &&
13115
- !codeGen.isLocalIdentifier(node) &&
13175
+ !isLocalIdentifier(node) &&
13116
13176
  !expressionScopes.isScopedToExpression(node)) {
13117
- this.replace(memberExpression(identifier(TEMPLATE_PARAMS.INSTANCE), node));
13177
+ this.replace(memberExpression(identifier(templateInstanceName), node));
13118
13178
  }
13119
13179
  },
13120
13180
  });
@@ -13595,43 +13655,7 @@ class CodeGen {
13595
13655
  * @param expression
13596
13656
  */
13597
13657
  bindExpression(expression) {
13598
- if (isIdentifier(expression)) {
13599
- if (!this.isLocalIdentifier(expression)) {
13600
- return memberExpression(identifier(TEMPLATE_PARAMS.INSTANCE), expression);
13601
- }
13602
- else {
13603
- return expression;
13604
- }
13605
- }
13606
- // TODO [#3370]: remove experimental template expression flag
13607
- if (this.state.config.experimentalComplexExpressions) {
13608
- // Cloning here is necessary because `this.replace()` is destructive, and we might use the
13609
- // node later during static content optimization
13610
- expression = structuredClone(expression);
13611
- return bindComplexExpression(expression, this);
13612
- }
13613
- // We need access to both this `this` and the walker's `this` in the walker
13614
- // eslint-disable-next-line @typescript-eslint/no-this-alias
13615
- const scope = this;
13616
- // Cloning here is necessary because `this.replace()` is destructive, and we might use the
13617
- // node later during static content optimization
13618
- expression = structuredClone(expression);
13619
- // TODO [#3370]: when the template expression flag is removed, the
13620
- // ComplexExpression type should be redefined as an ESTree Node. Doing
13621
- // so when the flag is still in place results in a cascade of required
13622
- // type changes across the codebase.
13623
- walk(expression, {
13624
- leave(node, parent) {
13625
- if (parent !== null &&
13626
- isIdentifier(node) &&
13627
- isMemberExpression(parent) &&
13628
- parent.object === node &&
13629
- !scope.isLocalIdentifier(node)) {
13630
- this.replace(memberExpression(identifier(TEMPLATE_PARAMS.INSTANCE), node));
13631
- }
13632
- },
13633
- });
13634
- return expression;
13658
+ return bindExpression(expression, this.isLocalIdentifier.bind(this), TEMPLATE_PARAMS.INSTANCE, this.state.config.experimentalComplexExpressions);
13635
13659
  }
13636
13660
  genStaticElement(element, slotParentName) {
13637
13661
  const staticParts = this.genStaticParts(element);
@@ -14543,11 +14567,12 @@ function compile(source, filename, config) {
14543
14567
  };
14544
14568
  }
14545
14569
 
14570
+ exports.bindExpression = bindExpression;
14546
14571
  exports.compile = compile;
14547
14572
  exports.default = compile;
14548
14573
  exports.generateScopeTokens = generateScopeTokens;
14549
14574
  exports.kebabcaseToCamelcase = kebabcaseToCamelcase;
14550
14575
  exports.parse = parse;
14551
14576
  exports.toPropertyName = toPropertyName;
14552
- /** version: 8.22.1 */
14577
+ /** version: 8.22.4 */
14553
14578
  //# sourceMappingURL=index.cjs.js.map
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export { Config } from './config';
6
6
  export { toPropertyName } from './shared/utils';
7
7
  export { kebabcaseToCamelcase } from './shared/naming';
8
8
  export { generateScopeTokens } from './scopeTokens';
9
+ export { bindExpression } from './codegen/expression';
9
10
  /**
10
11
  * Parses HTML markup into an AST
11
12
  * @param source HTML markup to parse
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { invariant, TemplateErrors, generateCompilerError, CompilerError, normalizeToDiagnostic, generateCompilerDiagnostic, ParserDiagnostics, DiagnosticLevel, CompilerMetrics } from '@lwc/errors';
5
5
  import path from 'path';
6
- import { StringCharAt, hasOwnProperty, getAPIVersionFromNumber, HTML_NAMESPACE, AriaAttrNameToPropNameMap, fromEntries, ArrayFrom, SPECIAL_PROPERTY_ATTRIBUTE_MAPPING, isAPIFeatureEnabled, ID_REFERENCING_ATTRIBUTES_SET, SVG_NAMESPACE, isBooleanAttribute, isGlobalHtmlAttribute, isAriaAttribute, isVoidElement, MATHML_NAMESPACE, isNull, isUndefined, IMPORTANT_FLAG, isArray, ArrayEvery, ArraySome, normalizeStyleAttributeValue, htmlEscape, parseStyleText, LWC_VERSION_COMMENT } from '@lwc/shared';
6
+ import { StringCharAt, hasOwnProperty, getAPIVersionFromNumber, HTML_NAMESPACE, AriaAttrNameToPropNameMap, fromEntries, ArrayFrom, SPECIAL_PROPERTY_ATTRIBUTE_MAPPING, isAPIFeatureEnabled, minApiVersion, ID_REFERENCING_ATTRIBUTES_SET, SVG_NAMESPACE, isBooleanAttribute, isGlobalHtmlAttribute, isAriaAttribute, isVoidElement, MATHML_NAMESPACE, isNull, isUndefined, IMPORTANT_FLAG, isArray, ArrayEvery, ArraySome, normalizeStyleAttributeValue, htmlEscape, parseStyleText, LWC_VERSION_COMMENT } from '@lwc/shared';
7
7
  import * as he from 'he';
8
8
  import { parseExpressionAt, isIdentifierStart, isIdentifierChar } from 'acorn';
9
9
  import * as astring from 'astring';
@@ -10063,104 +10063,6 @@ function isReservedES6Keyword(str) {
10063
10063
  return REVERSED_KEYWORDS.has(str);
10064
10064
  }
10065
10065
 
10066
- /*
10067
- * Copyright (c) 2018, salesforce.com, inc.
10068
- * All rights reserved.
10069
- * SPDX-License-Identifier: MIT
10070
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
10071
- */
10072
- const EXPRESSION_SYMBOL_START = '{';
10073
- const EXPRESSION_SYMBOL_END = '}';
10074
- const POTENTIAL_EXPRESSION_RE = /^.?{.+}.*$/;
10075
- const WHITESPACES_RE = /\s/;
10076
- function isExpression(source) {
10077
- // Issue #3418: Legacy behavior, previous regex treated "{}" attribute value as non expression
10078
- return source[0] === '{' && source.slice(-1) === '}' && source.length > 2;
10079
- }
10080
- function isPotentialExpression(source) {
10081
- return !!source.match(POTENTIAL_EXPRESSION_RE);
10082
- }
10083
- function validateExpression(source, node, config) {
10084
- const isValidNode = isIdentifier(node) || isMemberExpression(node);
10085
- // INVALID_XYZ_COMPLEX provides additional context to the user if CTE is enabled.
10086
- // The author may not have delimited the CTE with quotes, resulting in it being parsed
10087
- // as a legacy expression.
10088
- invariant(isValidNode, config.experimentalComplexExpressions
10089
- ? ParserDiagnostics.INVALID_NODE_COMPLEX
10090
- : ParserDiagnostics.INVALID_NODE, [node.type, source]);
10091
- if (isMemberExpression(node)) {
10092
- invariant(config.experimentalComputedMemberExpression || !node.computed, config.experimentalComplexExpressions
10093
- ? ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED_COMPLEX
10094
- : ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED, [source]);
10095
- const { object, property } = node;
10096
- if (!isIdentifier(object)) {
10097
- validateExpression(source, object, config);
10098
- }
10099
- if (!isIdentifier(property)) {
10100
- validateExpression(source, property, config);
10101
- }
10102
- }
10103
- }
10104
- function validateSourceIsParsedExpression(source, parsedExpression) {
10105
- if (parsedExpression.end === source.length - 1) {
10106
- return;
10107
- }
10108
- let unclosedParenthesisCount = 0;
10109
- for (let i = 0, n = parsedExpression.start; i < n; i++) {
10110
- if (source[i] === '(') {
10111
- unclosedParenthesisCount++;
10112
- }
10113
- }
10114
- // source[source.length - 1] === '}', n = source.length - 1 is to avoid processing '}'.
10115
- for (let i = parsedExpression.end, n = source.length - 1; i < n; i++) {
10116
- const character = source[i];
10117
- if (character === ')') {
10118
- unclosedParenthesisCount--;
10119
- }
10120
- else if (character === ';') {
10121
- // acorn parseExpressionAt will stop at the first ";", it may be that the expression is not
10122
- // a multiple expression ({foo;}), but this is a case that we explicitly do not want to support.
10123
- // in such case, let's fail with the same error as if it were a multiple expression.
10124
- invariant(false, ParserDiagnostics.MULTIPLE_EXPRESSIONS);
10125
- }
10126
- else {
10127
- invariant(WHITESPACES_RE.test(character), ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, ['Unexpected end of expression']);
10128
- }
10129
- }
10130
- invariant(unclosedParenthesisCount === 0, ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, [
10131
- 'Unexpected end of expression',
10132
- ]);
10133
- }
10134
- function parseExpression(ctx, source, location) {
10135
- const { ecmaVersion } = ctx;
10136
- return ctx.withErrorWrapping(() => {
10137
- const parsed = parseExpressionAt(source, 1, {
10138
- ecmaVersion,
10139
- allowAwaitOutsideFunction: false,
10140
- onComment: () => invariant(false, ParserDiagnostics.INVALID_EXPR_COMMENTS_DISALLOWED),
10141
- });
10142
- validateSourceIsParsedExpression(source, parsed);
10143
- validateExpression(source, parsed, ctx.config);
10144
- return { ...parsed, location };
10145
- }, ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, location, (err) => `Invalid expression ${source} - ${err.message}`);
10146
- }
10147
- function parseIdentifier(ctx, source, location) {
10148
- let isValid = true;
10149
- isValid = isIdentifierStart(source.charCodeAt(0));
10150
- for (let i = 1; i < source.length && isValid; i++) {
10151
- isValid = isIdentifierChar(source.charCodeAt(i));
10152
- }
10153
- if (isValid && !isReservedES6Keyword(source)) {
10154
- return {
10155
- ...identifier(source),
10156
- location,
10157
- };
10158
- }
10159
- else {
10160
- ctx.throwAtLocation(ParserDiagnostics.INVALID_IDENTIFIER, location, [source]);
10161
- }
10162
- }
10163
-
10164
10066
  /**
10165
10067
  * @typedef { import('estree').Node} Node
10166
10068
  * @typedef {{
@@ -10592,6 +10494,120 @@ function parseComplexExpression(ctx, source, templateSource, location, expressio
10592
10494
  }, ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, location, (err) => `Invalid expression ${source} - ${err.message}`);
10593
10495
  }
10594
10496
 
10497
+ /*
10498
+ * Copyright (c) 2018, salesforce.com, inc.
10499
+ * All rights reserved.
10500
+ * SPDX-License-Identifier: MIT
10501
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
10502
+ */
10503
+ const EXPRESSION_SYMBOL_START = '{';
10504
+ const EXPRESSION_SYMBOL_END = '}';
10505
+ const POTENTIAL_EXPRESSION_RE = /^.?{.+}.*$/;
10506
+ const WHITESPACES_RE = /\s/;
10507
+ function isExpression(source) {
10508
+ // Issue #3418: Legacy behavior, previous regex treated "{}" attribute value as non expression
10509
+ return source[0] === '{' && source.slice(-1) === '}' && source.length > 2;
10510
+ }
10511
+ function isPotentialExpression(source) {
10512
+ return !!source.match(POTENTIAL_EXPRESSION_RE);
10513
+ }
10514
+ const minCteApiVersion = minApiVersion(11 /* APIFeature.ENABLE_COMPLEX_TEMPLATE_EXPRESSIONS */);
10515
+ function validateExpression(source, node, ctx, unquotedAttributeExpression) {
10516
+ const cteOnlyNode = !isIdentifier(node) && !isMemberExpression(node);
10517
+ // If this node is not an identifier or a member expression (the only two nodes allowed if complexTemplateExpressions are disabled),
10518
+ // then we throw if the following invariants do not hold true.
10519
+ if (cteOnlyNode) {
10520
+ // complexTemplateExpressions must be enabled if this is a cteOnlyNode.
10521
+ invariant(ctx.config.experimentalComplexExpressions, ParserDiagnostics.INVALID_NODE, [
10522
+ node.type,
10523
+ ]);
10524
+ // complexTemplateExpressions must be enabled and the component API version must be sufficient.
10525
+ invariant(isComplexTemplateExpressionEnabled(ctx), ParserDiagnostics.INVALID_NODE_CTE_API_VERSION, [node.type, ctx.apiVersion, minCteApiVersion]);
10526
+ // complexTemplateExpressions must be enabled, the component API version must be sufficient and the expression should not be
10527
+ // an unquoted attribute expression.
10528
+ invariant(isComplexTemplateExpressionEnabled(ctx) && !unquotedAttributeExpression, ParserDiagnostics.INVALID_NODE_CTE_UNQUOTED, [node.type, source]);
10529
+ }
10530
+ if (isMemberExpression(node)) {
10531
+ // If this is a computed node and experimentalComputedMemberExpressions is not enabled,
10532
+ // then we throw if the following invariants do not hold true.
10533
+ if (!ctx.config.experimentalComputedMemberExpression && node.computed) {
10534
+ // complexTemplateExpressions must be enabled.
10535
+ invariant(ctx.config.experimentalComplexExpressions, ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED, [source]);
10536
+ // complexTemplateExpressions must be enabled and the component API version must be sufficient.
10537
+ invariant(isComplexTemplateExpressionEnabled(ctx), ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED_CTE_API_VERSION, [source, ctx.apiVersion, minCteApiVersion]);
10538
+ // complexTemplateExpressions must be enabled, the component API version must be sufficient and the expression
10539
+ // should not be an unquoted attribute expression.
10540
+ invariant(isComplexTemplateExpressionEnabled(ctx) && !unquotedAttributeExpression, ParserDiagnostics.COMPUTED_PROPERTY_ACCESS_NOT_ALLOWED_CTE_UNQUOTED, [source]);
10541
+ }
10542
+ const { object, property } = node;
10543
+ if (!isIdentifier(object)) {
10544
+ validateExpression(source, object, ctx, unquotedAttributeExpression);
10545
+ }
10546
+ if (!isIdentifier(property)) {
10547
+ validateExpression(source, property, ctx, unquotedAttributeExpression);
10548
+ }
10549
+ }
10550
+ }
10551
+ function validateSourceIsParsedExpression(source, parsedExpression) {
10552
+ if (parsedExpression.end === source.length - 1) {
10553
+ return;
10554
+ }
10555
+ let unclosedParenthesisCount = 0;
10556
+ for (let i = 0, n = parsedExpression.start; i < n; i++) {
10557
+ if (source[i] === '(') {
10558
+ unclosedParenthesisCount++;
10559
+ }
10560
+ }
10561
+ // source[source.length - 1] === '}', n = source.length - 1 is to avoid processing '}'.
10562
+ for (let i = parsedExpression.end, n = source.length - 1; i < n; i++) {
10563
+ const character = source[i];
10564
+ if (character === ')') {
10565
+ unclosedParenthesisCount--;
10566
+ }
10567
+ else if (character === ';') {
10568
+ // acorn parseExpressionAt will stop at the first ";", it may be that the expression is not
10569
+ // a multiple expression ({foo;}), but this is a case that we explicitly do not want to support.
10570
+ // in such case, let's fail with the same error as if it were a multiple expression.
10571
+ invariant(false, ParserDiagnostics.MULTIPLE_EXPRESSIONS);
10572
+ }
10573
+ else {
10574
+ invariant(WHITESPACES_RE.test(character), ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, ['Unexpected end of expression']);
10575
+ }
10576
+ }
10577
+ invariant(unclosedParenthesisCount === 0, ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, [
10578
+ 'Unexpected end of expression',
10579
+ ]);
10580
+ }
10581
+ function parseExpression(ctx, source, location, unquotedAttributeExpression) {
10582
+ const { ecmaVersion } = ctx;
10583
+ return ctx.withErrorWrapping(() => {
10584
+ const parsed = parseExpressionAt(source, 1, {
10585
+ ecmaVersion,
10586
+ allowAwaitOutsideFunction: false,
10587
+ onComment: () => invariant(false, ParserDiagnostics.INVALID_EXPR_COMMENTS_DISALLOWED),
10588
+ });
10589
+ validateSourceIsParsedExpression(source, parsed);
10590
+ validateExpression(source, parsed, ctx, unquotedAttributeExpression);
10591
+ return { ...parsed, location };
10592
+ }, ParserDiagnostics.TEMPLATE_EXPRESSION_PARSING_ERROR, location, (err) => `Invalid expression ${source} - ${err.message}`);
10593
+ }
10594
+ function parseIdentifier(ctx, source, location) {
10595
+ let isValid = true;
10596
+ isValid = isIdentifierStart(source.charCodeAt(0));
10597
+ for (let i = 1; i < source.length && isValid; i++) {
10598
+ isValid = isIdentifierChar(source.charCodeAt(i));
10599
+ }
10600
+ if (isValid && !isReservedES6Keyword(source)) {
10601
+ return {
10602
+ ...identifier(source),
10603
+ location,
10604
+ };
10605
+ }
10606
+ else {
10607
+ ctx.throwAtLocation(ParserDiagnostics.INVALID_IDENTIFIER, location, [source]);
10608
+ }
10609
+ }
10610
+
10595
10611
  /*
10596
10612
  * Copyright (c) 2018, salesforce.com, inc.
10597
10613
  * All rights reserved.
@@ -11057,7 +11073,9 @@ function normalizeAttributeValue(ctx, raw, tag, attr, location) {
11057
11073
  const isQuoted = isQuotedAttribute(rawAttrVal);
11058
11074
  const isEscaped = isEscapedAttribute(rawAttrVal);
11059
11075
  if (!isEscaped && isExpression(value)) {
11060
- if (isQuoted && !isComplexTemplateExpressionEnabled(ctx)) {
11076
+ // Don't test for the API version here, just check if CTE is enabled.
11077
+ // We can provide more specific errors w.r.t API versions after the expression has been parsed and we know what it is.
11078
+ if (isQuoted && !ctx.config.experimentalComplexExpressions) {
11061
11079
  // <input value="{myValue}" />
11062
11080
  // -> ambiguity if the attribute value is a template identifier or a string literal.
11063
11081
  const unquoted = raw.replace(/"/g, '');
@@ -11503,7 +11521,7 @@ function parseText(ctx, rawText, sourceLocation, location) {
11503
11521
  }
11504
11522
  let value;
11505
11523
  if (isExpression(token)) {
11506
- value = parseExpression(ctx, token, sourceLocation);
11524
+ value = parseExpression(ctx, token, sourceLocation, false);
11507
11525
  }
11508
11526
  else {
11509
11527
  value = literal(decodeTextContent(token));
@@ -11555,7 +11573,7 @@ function parseTextNode(ctx, parse5Text) {
11555
11573
  return [];
11556
11574
  }
11557
11575
  const sourceLocation$1 = sourceLocation(location);
11558
- return ctx.config.experimentalComplexExpressions
11576
+ return isComplexTemplateExpressionEnabled(ctx)
11559
11577
  ? parseTextComplex(ctx, rawText, sourceLocation$1, location)
11560
11578
  : parseText(ctx, rawText, sourceLocation$1, location);
11561
11579
  }
@@ -12438,13 +12456,13 @@ function getTemplateAttribute(ctx, tag, attribute$1, attributeLocation) {
12438
12456
  to be used.
12439
12457
  */
12440
12458
  const isPotentialComplexExpression = quotedExpression && !escapedExpression && value.startsWith(EXPRESSION_SYMBOL_START);
12441
- if (ctx.config.experimentalComplexExpressions && isPotentialComplexExpression) {
12459
+ if (isComplexTemplateExpressionEnabled(ctx) && isPotentialComplexExpression) {
12442
12460
  const attributeNameOffset = attribute$1.name.length + 2; // The +2 accounts for the '="' in the attribute: attr="...
12443
12461
  const templateSource = ctx.getSource(attributeLocation.startOffset + attributeNameOffset);
12444
12462
  attrValue = parseComplexExpression(ctx, value, templateSource, location).expression;
12445
12463
  }
12446
12464
  else if (isExpression(value) && !escapedExpression) {
12447
- attrValue = parseExpression(ctx, value, location);
12465
+ attrValue = parseExpression(ctx, value, location, !quotedExpression);
12448
12466
  }
12449
12467
  else if (isBooleanAttribute) {
12450
12468
  attrValue = literal(true);
@@ -13043,6 +13061,48 @@ function serializeStaticElement(element, codeGen) {
13043
13061
  * SPDX-License-Identifier: MIT
13044
13062
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
13045
13063
  */
13064
+ /**
13065
+ * Bind the passed expression to the component instance. It applies the following transformation to the expression:
13066
+ * - {value} --> {$cmp.value}
13067
+ * - {value[index]} --> {$cmp.value[$cmp.index]}
13068
+ * @param expression
13069
+ */
13070
+ function bindExpression(expression, isLocalIdentifier, templateInstanceName, experimentalComplexExpressions) {
13071
+ if (isIdentifier(expression)) {
13072
+ if (!isLocalIdentifier(expression)) {
13073
+ return memberExpression(identifier(templateInstanceName), expression);
13074
+ }
13075
+ else {
13076
+ return expression;
13077
+ }
13078
+ }
13079
+ // TODO [#3370]: remove experimental template expression flag
13080
+ if (experimentalComplexExpressions) {
13081
+ // Cloning here is necessary because `this.replace()` is destructive, and we might use the
13082
+ // node later during static content optimization
13083
+ expression = structuredClone(expression);
13084
+ return bindComplexExpression(expression, isLocalIdentifier, templateInstanceName);
13085
+ }
13086
+ // Cloning here is necessary because `this.replace()` is destructive, and we might use the
13087
+ // node later during static content optimization
13088
+ expression = structuredClone(expression);
13089
+ // TODO [#3370]: when the template expression flag is removed, the
13090
+ // ComplexExpression type should be redefined as an ESTree Node. Doing
13091
+ // so when the flag is still in place results in a cascade of required
13092
+ // type changes across the codebase.
13093
+ walk(expression, {
13094
+ leave(node, parent) {
13095
+ if (parent !== null &&
13096
+ isIdentifier(node) &&
13097
+ isMemberExpression(parent) &&
13098
+ parent.object === node &&
13099
+ !isLocalIdentifier(node)) {
13100
+ this.replace(memberExpression(identifier(templateInstanceName), node));
13101
+ }
13102
+ },
13103
+ });
13104
+ return expression;
13105
+ }
13046
13106
  /**
13047
13107
  * Bind the passed expression to the component instance. It applies the following
13048
13108
  * transformation to the expression:
@@ -13064,7 +13124,7 @@ function serializeStaticElement(element, codeGen) {
13064
13124
  * @param expression
13065
13125
  * @param codeGen
13066
13126
  */
13067
- function bindComplexExpression(expression, codeGen) {
13127
+ function bindComplexExpression(expression, isLocalIdentifier, templateInstanceName) {
13068
13128
  const expressionScopes = new ExpressionScopes();
13069
13129
  // TODO [#3370]: when the template expression flag is removed, the
13070
13130
  // ComplexExpression type should be redefined as an ESTree Node. Doing
@@ -13088,9 +13148,9 @@ function bindComplexExpression(expression, codeGen) {
13088
13148
  isIdentifier$1 &&
13089
13149
  !(isMemberExpression(parent) && parent.property === node && !parent.computed) &&
13090
13150
  !(isProperty$1(parent) && parent.key === node) &&
13091
- !codeGen.isLocalIdentifier(node) &&
13151
+ !isLocalIdentifier(node) &&
13092
13152
  !expressionScopes.isScopedToExpression(node)) {
13093
- this.replace(memberExpression(identifier(TEMPLATE_PARAMS.INSTANCE), node));
13153
+ this.replace(memberExpression(identifier(templateInstanceName), node));
13094
13154
  }
13095
13155
  },
13096
13156
  });
@@ -13571,43 +13631,7 @@ class CodeGen {
13571
13631
  * @param expression
13572
13632
  */
13573
13633
  bindExpression(expression) {
13574
- if (isIdentifier(expression)) {
13575
- if (!this.isLocalIdentifier(expression)) {
13576
- return memberExpression(identifier(TEMPLATE_PARAMS.INSTANCE), expression);
13577
- }
13578
- else {
13579
- return expression;
13580
- }
13581
- }
13582
- // TODO [#3370]: remove experimental template expression flag
13583
- if (this.state.config.experimentalComplexExpressions) {
13584
- // Cloning here is necessary because `this.replace()` is destructive, and we might use the
13585
- // node later during static content optimization
13586
- expression = structuredClone(expression);
13587
- return bindComplexExpression(expression, this);
13588
- }
13589
- // We need access to both this `this` and the walker's `this` in the walker
13590
- // eslint-disable-next-line @typescript-eslint/no-this-alias
13591
- const scope = this;
13592
- // Cloning here is necessary because `this.replace()` is destructive, and we might use the
13593
- // node later during static content optimization
13594
- expression = structuredClone(expression);
13595
- // TODO [#3370]: when the template expression flag is removed, the
13596
- // ComplexExpression type should be redefined as an ESTree Node. Doing
13597
- // so when the flag is still in place results in a cascade of required
13598
- // type changes across the codebase.
13599
- walk(expression, {
13600
- leave(node, parent) {
13601
- if (parent !== null &&
13602
- isIdentifier(node) &&
13603
- isMemberExpression(parent) &&
13604
- parent.object === node &&
13605
- !scope.isLocalIdentifier(node)) {
13606
- this.replace(memberExpression(identifier(TEMPLATE_PARAMS.INSTANCE), node));
13607
- }
13608
- },
13609
- });
13610
- return expression;
13634
+ return bindExpression(expression, this.isLocalIdentifier.bind(this), TEMPLATE_PARAMS.INSTANCE, this.state.config.experimentalComplexExpressions);
13611
13635
  }
13612
13636
  genStaticElement(element, slotParentName) {
13613
13637
  const staticParts = this.genStaticParts(element);
@@ -14519,6 +14543,6 @@ function compile(source, filename, config) {
14519
14543
  };
14520
14544
  }
14521
14545
 
14522
- export { ElementDirectiveName, LWCDirectiveDomMode, LWCDirectiveRenderMode, LwcTagName, RootDirectiveName, TemplateDirectiveName, compile, compile as default, generateScopeTokens, kebabcaseToCamelcase, parse, toPropertyName };
14523
- /** version: 8.22.1 */
14546
+ export { ElementDirectiveName, LWCDirectiveDomMode, LWCDirectiveRenderMode, LwcTagName, RootDirectiveName, TemplateDirectiveName, bindExpression, compile, compile as default, generateScopeTokens, kebabcaseToCamelcase, parse, toPropertyName };
14547
+ /** version: 8.22.4 */
14524
14548
  //# sourceMappingURL=index.js.map
@@ -6,6 +6,6 @@ export declare const EXPRESSION_SYMBOL_END = "}";
6
6
  export declare function isExpression(source: string): boolean;
7
7
  export declare function isPotentialExpression(source: string): boolean;
8
8
  export declare function validateSourceIsParsedExpression(source: string, parsedExpression: Node): void;
9
- export declare function parseExpression(ctx: ParserCtx, source: string, location: SourceLocation): Expression;
9
+ export declare function parseExpression(ctx: ParserCtx, source: string, location: SourceLocation, unquotedAttributeExpression: boolean): Expression;
10
10
  export declare function parseIdentifier(ctx: ParserCtx, source: string, location: SourceLocation): Identifier;
11
11
  //# sourceMappingURL=expression.d.ts.map
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "You can safely modify dependencies, devDependencies, keywords, etc., but other props will be overwritten."
5
5
  ],
6
6
  "name": "@lwc/template-compiler",
7
- "version": "8.22.1",
7
+ "version": "8.22.4",
8
8
  "description": "Template compiler package",
9
9
  "keywords": [
10
10
  "lwc"
@@ -46,8 +46,8 @@
46
46
  }
47
47
  },
48
48
  "dependencies": {
49
- "@lwc/errors": "8.22.1",
50
- "@lwc/shared": "8.22.1",
49
+ "@lwc/errors": "8.22.4",
50
+ "@lwc/shared": "8.22.4",
51
51
  "acorn": "~8.15.0",
52
52
  "astring": "~1.9.0",
53
53
  "he": "~1.2.0"