@lwc/template-compiler 6.2.0 → 6.3.0

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/dist/index.d.ts CHANGED
@@ -3,6 +3,18 @@ import { TemplateCompileResult, TemplateParseResult } from './shared/types';
3
3
  export * from './shared/types';
4
4
  export { CustomRendererConfig, CustomRendererElementConfig } from './shared/renderer-hooks';
5
5
  export { Config } from './config';
6
+ /**
7
+ * Parses HTML markup into an AST
8
+ * @param source HTML markup to parse
9
+ * @param config HTML template compilation config
10
+ * @returns Object containing the AST
11
+ */
6
12
  export declare function parse(source: string, config?: Config): TemplateParseResult;
7
13
  export { compile };
14
+ /**
15
+ * Compiles a LWC template to JavaScript source code consumable by the engine.
16
+ * @param source HTML markup to compile
17
+ * @param config HTML template compilation config
18
+ * @returns Object containing the compiled code and any warnings that occurred.
19
+ */
8
20
  export default function compile(source: string, config: Config): TemplateCompileResult;
package/dist/index.js CHANGED
@@ -54,7 +54,7 @@ const DASHED_TAGNAME_ELEMENT_SET = new Set([
54
54
  const STATIC_SAFE_DIRECTIVES = new Set(['Ref']);
55
55
 
56
56
  /*
57
- * Copyright (c) 2018, salesforce.com, inc.
57
+ * Copyright (c) 2024, Salesforce, Inc.
58
58
  * All rights reserved.
59
59
  * SPDX-License-Identifier: MIT
60
60
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
@@ -78,6 +78,7 @@ function toPropertyName(attr) {
78
78
  * Test if given tag name is a custom element.
79
79
  * @param tagName element tag name to test
80
80
  * @returns true if given tag name represents a custom element, false otherwise.
81
+ * @example isCustomElementTag("my-component") // true
81
82
  */
82
83
  function isCustomElementTag(tagName) {
83
84
  return tagName.includes('-') && !DASHED_TAGNAME_ELEMENT_SET.has(tagName);
@@ -86,6 +87,7 @@ function isCustomElementTag(tagName) {
86
87
  * Test if given tag name is a custom LWC tag denoted lwc:*.
87
88
  * @param tagName element tag name to test
88
89
  * @returns true if given tag name represents a custom LWC tag, false otherwise.
90
+ * @example isLwcElementTag("my-component") // false
89
91
  */
90
92
  function isLwcElementTag(tagName) {
91
93
  return tagName.startsWith('lwc:');
@@ -10132,6 +10134,8 @@ class ParserCtx {
10132
10134
  }
10133
10135
  /**
10134
10136
  * This method flattens the scopes into a single array for traversal.
10137
+ * @param element
10138
+ * @yields Each node in the scope and its parent.
10135
10139
  */
10136
10140
  *ancestors(element) {
10137
10141
  const ancestors = this.elementScopes.flat();
@@ -10144,11 +10148,10 @@ class ParserCtx {
10144
10148
  * This method returns an iterator over ancestor nodes, starting at the parent and ending at the root node.
10145
10149
  *
10146
10150
  * Note: There are instances when we want to terminate the traversal early, such as searching for a ForBlock parent.
10147
- *
10148
- * @param {ParentNode} startNode - Starting node to begin search, defaults to the tail of the current scope.
10149
- * @param {function} predicate - This callback is called once for each ancestor until it finds one where predicate returns true.
10150
- * @param {function} traversalCond - This callback is called after predicate and will terminate the traversal if it returns false.
10151
+ * @param predicate This callback is called once for each ancestor until it finds one where predicate returns true.
10152
+ * @param traversalCond This callback is called after predicate and will terminate the traversal if it returns false.
10151
10153
  * traversalCond is ignored if no value is provided.
10154
+ * @param startNode Starting node to begin search, defaults to the tail of the current scope.
10152
10155
  */
10153
10156
  findAncestor(predicate, traversalCond = () => true, startNode) {
10154
10157
  for (const { current, parent } of this.ancestors(startNode)) {
@@ -10163,8 +10166,7 @@ class ParserCtx {
10163
10166
  }
10164
10167
  /**
10165
10168
  * This method searchs the current scope and returns the value that satisfies the predicate.
10166
- *
10167
- * @param {function} predicate - This callback is called once for each sibling in the current scope
10169
+ * @param predicate This callback is called once for each sibling in the current scope
10168
10170
  * until it finds one where predicate returns true.
10169
10171
  */
10170
10172
  findInCurrentElementScope(predicate) {
@@ -10275,8 +10277,7 @@ class ParserCtx {
10275
10277
  /**
10276
10278
  * This method recovers from diagnostic errors that are encountered when fn is invoked.
10277
10279
  * All other errors are considered compiler errors and can not be recovered from.
10278
- *
10279
- * @param fn - method to be invoked.
10280
+ * @param fn method to be invoked.
10280
10281
  */
10281
10282
  withErrorRecovery(fn) {
10282
10283
  try {
@@ -10313,18 +10314,28 @@ class ParserCtx {
10313
10314
  }
10314
10315
  /**
10315
10316
  * This method throws a diagnostic error with the node's location.
10317
+ * @param errorInfo
10318
+ * @param node
10319
+ * @param messageArgs
10316
10320
  */
10317
10321
  throwOnNode(errorInfo, node, messageArgs) {
10318
10322
  this.throw(errorInfo, messageArgs, node.location);
10319
10323
  }
10320
10324
  /**
10321
10325
  * This method throws a diagnostic error with location information.
10326
+ * @param errorInfo
10327
+ * @param location
10328
+ * @param messageArgs
10322
10329
  */
10323
10330
  throwAtLocation(errorInfo, location, messageArgs) {
10324
10331
  this.throw(errorInfo, messageArgs, location);
10325
10332
  }
10326
10333
  /**
10327
10334
  * This method throws a diagnostic error and will immediately exit the current routine.
10335
+ * @param errorInfo
10336
+ * @param messageArgs
10337
+ * @param location
10338
+ * @throws
10328
10339
  */
10329
10340
  throw(errorInfo, messageArgs, location) {
10330
10341
  throw generateCompilerError(errorInfo, {
@@ -10336,18 +10347,27 @@ class ParserCtx {
10336
10347
  }
10337
10348
  /**
10338
10349
  * This method logs a diagnostic warning with the node's location.
10350
+ * @param errorInfo
10351
+ * @param node
10352
+ * @param messageArgs
10339
10353
  */
10340
10354
  warnOnNode(errorInfo, node, messageArgs) {
10341
10355
  this.warn(errorInfo, messageArgs, node.location);
10342
10356
  }
10343
10357
  /**
10344
10358
  * This method logs a diagnostic warning with location information.
10359
+ * @param errorInfo
10360
+ * @param location
10361
+ * @param messageArgs
10345
10362
  */
10346
10363
  warnAtLocation(errorInfo, location, messageArgs) {
10347
10364
  this.warn(errorInfo, messageArgs, location);
10348
10365
  }
10349
10366
  /**
10350
10367
  * This method logs a diagnostic warning and will continue execution of the current routine.
10368
+ * @param errorInfo
10369
+ * @param messageArgs
10370
+ * @param location
10351
10371
  */
10352
10372
  warn(errorInfo, messageArgs, location) {
10353
10373
  this.addDiagnostic(generateCompilerDiagnostic(errorInfo, {
@@ -10568,22 +10588,24 @@ function getTrailingChars(str) {
10568
10588
  * This function checks for "unbalanced" extraneous parentheses surrounding the expression.
10569
10589
  *
10570
10590
  * Examples of balanced extraneous parentheses (validation passes):
10571
- * {(foo.bar)} <-- the MemberExpressions does not account for the surrounding parens
10572
- * {(foo())} <-- the CallExpression does not account for the surrounding parens
10573
- * {((foo ?? bar)())} <-- the CallExpression does not account for the surrounding parens
10591
+ * - `{(foo.bar)}` <-- the MemberExpressions does not account for the surrounding parens
10592
+ * - `{(foo())}` <-- the CallExpression does not account for the surrounding parens
10593
+ * - `{((foo ?? bar)())}` <-- the CallExpression does not account for the surrounding parens
10574
10594
  *
10575
10595
  * Examples of unbalanced extraneous parentheses (validation fails):
10576
- * {(foo.bar))} <-- there is an extraneous trailing paren
10577
- * {foo())} <-- there is an extraneous trailing paren
10596
+ * - `{(foo.bar))}` <-- there is an extraneous trailing paren
10597
+ * - `{foo())}` <-- there is an extraneous trailing paren
10578
10598
  *
10579
10599
  * Examples of no extraneous parentheses (validation passes):
10580
- * {foo()} <-- the CallExpression accounts for the trailing paren
10581
- * {(foo ?? bar).baz} <-- the outer MemberExpression accounts for the leading paren
10582
- * {(foo).bar} <-- the outer MemberExpression accounts for the leading paren
10600
+ * - `{foo()}` <-- the CallExpression accounts for the trailing paren
10601
+ * - `{(foo ?? bar).baz}` <-- the outer MemberExpression accounts for the leading paren
10602
+ * - `{(foo).bar}` <-- the outer MemberExpression accounts for the leading paren
10583
10603
  *
10584
10604
  * Notably, no examples of extraneous leading parens could be found - these result in a
10585
10605
  * parsing error in Acorn. However, this function still checks, in case there is an
10586
10606
  * unknown expression that would parse with an extraneous leading paren.
10607
+ * @param leadingChars
10608
+ * @param trailingChars
10587
10609
  */
10588
10610
  function validateMatchingExtraParens(leadingChars, trailingChars) {
10589
10611
  const numLeadingParens = leadingChars.split('(').length - 1;
@@ -10595,8 +10617,8 @@ function validateMatchingExtraParens(leadingChars, trailingChars) {
10595
10617
  *
10596
10618
  * Its behavior diverges from that specified in the WHATWG HTML spec
10597
10619
  * in two places:
10598
- * - 13.2.5.38 - unquoted attribute values
10599
- * - 13.2.5.1 - the "data" state, which corresponds to parsing outside of tags
10620
+ * - 13.2.5.38 - unquoted attribute values
10621
+ * - 13.2.5.1 - the "data" state, which corresponds to parsing outside of tags
10600
10622
  *
10601
10623
  * Specifically, this tokenizer defers to Acorn's JavaScript parser when
10602
10624
  * encountering a `{` character for an attribute value or within a text
@@ -10660,7 +10682,7 @@ class TemplateHtmlTokenizer extends Tokenizer {
10660
10682
  // coming later in an unquoted attr value should not be considered
10661
10683
  // the beginning of a template expression.
10662
10684
  this.checkedAttrs.add(this.currentAttr);
10663
- // @ts-ignore
10685
+ // @ts-expect-error private method
10664
10686
  super._stateAttributeValueUnquoted(codePoint);
10665
10687
  }
10666
10688
  }
@@ -10693,7 +10715,7 @@ class TemplateHtmlTokenizer extends Tokenizer {
10693
10715
  this.currentCharacterToken = null;
10694
10716
  }
10695
10717
  else {
10696
- // @ts-ignore
10718
+ // @ts-expect-error private method
10697
10719
  super._stateData(codePoint);
10698
10720
  }
10699
10721
  }
@@ -10747,11 +10769,9 @@ class TemplateHtmlParser extends Parser {
10747
10769
  /**
10748
10770
  * Parse the LWC template using a customized parser & lexer that allow
10749
10771
  * for template expressions to be parsed correctly.
10750
- *
10751
- * @param {string} source raw template markup
10752
- * @param {ParseFragmentConfig} config
10753
- *
10754
- * @return {DocumentFragment} the parsed document
10772
+ * @param source raw template markup
10773
+ * @param config
10774
+ * @returns the parsed document
10755
10775
  */
10756
10776
  function parseFragment(source, config) {
10757
10777
  const { ctx, sourceCodeLocationInfo = true, onParseError } = config;
@@ -11131,6 +11151,7 @@ function isTemplateDirective(attrName) {
11131
11151
  }
11132
11152
  /**
11133
11153
  * Convert attribute name from kebab case to camel case property name
11154
+ * @param attrName
11134
11155
  */
11135
11156
  function attributeToPropertyName(attrName) {
11136
11157
  return ATTRS_PROPS_TRANFORMS[attrName] || toPropertyName(attrName);
@@ -11259,6 +11280,10 @@ function parseRoot(ctx, parse5Elm) {
11259
11280
  *
11260
11281
  * Note: Not every node in the hierarchy is guaranteed to be created, for example,
11261
11282
  * <div></div> will only create an Element node.
11283
+ * @param ctx
11284
+ * @param parse5Elm
11285
+ * @param parentNode
11286
+ * @param parse5ParentLocation
11262
11287
  */
11263
11288
  function parseElement(ctx, parse5Elm, parentNode, parse5ParentLocation) {
11264
11289
  const parse5ElmLocation = parseElementLocation(ctx, parse5Elm, parse5ParentLocation);
@@ -11454,7 +11479,23 @@ function parseText(ctx, parse5Text) {
11454
11479
  }
11455
11480
  // Extract the raw source to avoid HTML entity decoding done by parse5
11456
11481
  const rawText = cleanTextNode(ctx.getSource(location.startOffset, location.endOffset));
11457
- if (!rawText.trim().length) {
11482
+ /*
11483
+ The original job of this if-block was to discard the whitespace between HTML tags, HTML
11484
+ comments, and HTML tags and HTML comments. The whitespace inside the text content of HTML tags
11485
+ would never be considered here because they would not be parsed into individual text nodes until
11486
+ later (several lines below).
11487
+
11488
+ ["Hello {first} {last}!"] => ["Hello ", "{first}", " ", "{last}", "!"]
11489
+
11490
+ With the implementation of complex template expressions, whitespace that shouldn't be discarded
11491
+ has already been parsed into individual text nodes at this point so we only discard when
11492
+ experimentalComplexExpressions is disabled.
11493
+
11494
+ When removing the experimentalComplexExpressions flag, we need to figure out how to best discard
11495
+ the HTML whitespace while preserving text content whitespace, while also taking into account how
11496
+ comments are sometimes preserved (in which case we need to keep the HTML whitespace).
11497
+ */
11498
+ if (!rawText.trim().length && !ctx.config.experimentalComplexExpressions) {
11458
11499
  return parsedTextNodes;
11459
11500
  }
11460
11501
  // TODO [#3370]: remove experimental template expression flag
@@ -12410,6 +12451,8 @@ function objectToAST(obj, valueMapper) {
12410
12451
  *
12411
12452
  * This function searches through the children to determine if flattening needs to occur in the runtime.
12412
12453
  * Children should be flattened if they contain an iterator, a dynamic directive or a slot inside a light dom element.
12454
+ * @param codeGen
12455
+ * @param children
12413
12456
  */
12414
12457
  function shouldFlatten(codeGen, children) {
12415
12458
  return children.some((child) => {
@@ -12427,6 +12470,7 @@ function shouldFlatten(codeGen, children) {
12427
12470
  }
12428
12471
  /**
12429
12472
  * Returns true if the AST element or any of its descendants use an id attribute.
12473
+ * @param node
12430
12474
  */
12431
12475
  function hasIdAttribute(node) {
12432
12476
  if (isBaseElement(node)) {
@@ -12601,6 +12645,7 @@ const rawContentElements = new Set([
12601
12645
  /**
12602
12646
  * Escape all the characters that could break a JavaScript template string literal: "`" (backtick),
12603
12647
  * "${" (dollar + open curly) and "\" (backslash).
12648
+ * @param str
12604
12649
  */
12605
12650
  function templateStringEscape(str) {
12606
12651
  return str.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
@@ -12706,21 +12751,23 @@ function serializeStaticElement(element, preserveComments) {
12706
12751
  /**
12707
12752
  * Bind the passed expression to the component instance. It applies the following
12708
12753
  * transformation to the expression:
12709
- * {value} --> {$cmp.value}
12710
- * {value[index]} --> {$cmp.value[$cmp.index]}
12711
- * {foo ?? bar} --> {$cmp.foo ?? $cmp.bar}
12712
- * {foo?.bar} --> {$cmp.foo?.bar}
12754
+ * - `{value}` --> `{$cmp.value}`
12755
+ * - `{value[index]}` --> `{$cmp.value[$cmp.index]}`
12756
+ * - `{foo ?? bar}` --> `{$cmp.foo ?? $cmp.bar}`
12757
+ * - `{foo?.bar}` --> `{$cmp.foo?.bar}`
12713
12758
  *
12714
12759
  * However, parameter variables are not be transformed in this way. For example,
12715
12760
  * the following transformations do not happen:
12716
- * {(foo) => foo && bar} -> {(foo) => $cmp.foo && $cmp.bar}
12717
- * {(foo) => foo && bar} -> {($cmp.foo) => foo && $cmp.bar}
12718
- * {(foo) => foo && bar} -> {($cmp.foo) => $cmp.foo && $cmp.bar}
12761
+ * - `{(foo) => foo && bar}` --> `{(foo) => $cmp.foo && $cmp.bar}`
12762
+ * - `{(foo) => foo && bar}` --> `{($cmp.foo) => foo && $cmp.bar}`
12763
+ * - `{(foo) => foo && bar}` --> `{($cmp.foo) => $cmp.foo && $cmp.bar}`
12719
12764
  *
12720
12765
  * Instead, the scopes are respected:
12721
- * {(foo) => foo && $cmp.bar}
12766
+ * - `{(foo) => foo && $cmp.bar}`
12722
12767
  *
12723
12768
  * Similar checks occur for local identifiers introduced via for:each or similar.
12769
+ * @param expression
12770
+ * @param codeGen
12724
12771
  */
12725
12772
  function bindComplexExpression(expression, codeGen) {
12726
12773
  const expressionScopes = new ExpressionScopes();
@@ -12984,6 +13031,9 @@ class CodeGen {
12984
13031
  }
12985
13032
  /**
12986
13033
  * Generates childs vnodes when slot content is static.
13034
+ * @param slotName
13035
+ * @param data
13036
+ * @param children
12987
13037
  */
12988
13038
  getSlot(slotName, data, children) {
12989
13039
  this.slotNames.add(slotName);
@@ -12996,6 +13046,8 @@ class CodeGen {
12996
13046
  }
12997
13047
  /**
12998
13048
  * Generates a factory function that inturn generates child vnodes for scoped slot content.
13049
+ * @param callback
13050
+ * @param slotName
12999
13051
  */
13000
13052
  getScopedSlotFactory(callback, slotName) {
13001
13053
  return this._renderApiCall(RENDER_APIS.scopedSlotFactory, [slotName, callback]);
@@ -13029,9 +13081,8 @@ class CodeGen {
13029
13081
  * This routine generates an expression that avoids
13030
13082
  * computing the sanitized html of a raw html if it does not change
13031
13083
  * between renders.
13032
- *
13033
13084
  * @param expr
13034
- * @returns sanitizedHtmlExpr
13085
+ * @returns The generated expression
13035
13086
  */
13036
13087
  genSanitizedHtmlExpr(expr) {
13037
13088
  const instance = this.innerHtmlInstances++;
@@ -13081,6 +13132,7 @@ class CodeGen {
13081
13132
  }
13082
13133
  /**
13083
13134
  * Searches the scopes to find an identifier with a matching name.
13135
+ * @param identifier
13084
13136
  */
13085
13137
  isLocalIdentifier(identifier) {
13086
13138
  let scope = this.scope;
@@ -13096,6 +13148,7 @@ class CodeGen {
13096
13148
  * Bind the passed expression to the component instance. It applies the following transformation to the expression:
13097
13149
  * - {value} --> {$cmp.value}
13098
13150
  * - {value[index]} --> {$cmp.value[$cmp.index]}
13151
+ * @param expression
13099
13152
  */
13100
13153
  bindExpression(expression) {
13101
13154
  if (isIdentifier(expression)) {
@@ -13108,6 +13161,9 @@ class CodeGen {
13108
13161
  }
13109
13162
  // TODO [#3370]: remove experimental template expression flag
13110
13163
  if (this.state.config.experimentalComplexExpressions) {
13164
+ // Cloning here is necessary because `this.replace()` is destructive, and we might use the
13165
+ // node later during static content optimization
13166
+ expression = doStructuredClone(expression);
13111
13167
  return bindComplexExpression(expression, this);
13112
13168
  }
13113
13169
  // We need access to both this `this` and the walker's `this` in the walker
@@ -13277,6 +13333,7 @@ function kebabcaseToCamelcase(name) {
13277
13333
  * };
13278
13334
  * }
13279
13335
  * ```
13336
+ * @param templateFn
13280
13337
  */
13281
13338
  function optimizeStaticExpressions(templateFn) {
13282
13339
  const result = [];
@@ -13359,7 +13416,8 @@ function generateHoistedNodes(codegen) {
13359
13416
  * Generate an ES module AST from a template ESTree AST. The generated module imports the dependent
13360
13417
  * LWC components via import statements and expose the template function via a default export
13361
13418
  * statement.
13362
- *
13419
+ * @param templateFn
13420
+ * @param codeGen
13363
13421
  * @example
13364
13422
  * ```js
13365
13423
  * import { registerTemplate } from 'lwc';
@@ -13538,7 +13596,6 @@ function transform(codeGen) {
13538
13596
  }
13539
13597
  /**
13540
13598
  * Transforms an IfBlock or ElseifBlock along with both its direct descendants and its 'else' descendants.
13541
- *
13542
13599
  * @param conditionalParentBlock The IfBlock or ElseifBlock to transform into a conditional expression
13543
13600
  * @param key The key to use for this chain of IfBlock/ElseifBlock branches, if applicable
13544
13601
  * @returns A conditional expression representing the full conditional tree with conditionalParentBlock as the root node
@@ -13906,16 +13963,28 @@ function generate (root, state) {
13906
13963
  }
13907
13964
 
13908
13965
  /*
13909
- * Copyright (c) 2018, salesforce.com, inc.
13966
+ * Copyright (c) 2024, Salesforce, Inc.
13910
13967
  * All rights reserved.
13911
13968
  * SPDX-License-Identifier: MIT
13912
13969
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
13913
13970
  */
13971
+ /**
13972
+ * Parses HTML markup into an AST
13973
+ * @param source HTML markup to parse
13974
+ * @param config HTML template compilation config
13975
+ * @returns Object containing the AST
13976
+ */
13914
13977
  function parse(source, config = {}) {
13915
13978
  const options = normalizeConfig(config);
13916
13979
  const state = new State$1(options);
13917
13980
  return parse$1(source, state);
13918
13981
  }
13982
+ /**
13983
+ * Compiles a LWC template to JavaScript source code consumable by the engine.
13984
+ * @param source HTML markup to compile
13985
+ * @param config HTML template compilation config
13986
+ * @returns Object containing the compiled code and any warnings that occurred.
13987
+ */
13919
13988
  function compile(source, config) {
13920
13989
  const options = normalizeConfig(config);
13921
13990
  const state = new State$1(options);
@@ -13944,5 +14013,5 @@ function compile(source, config) {
13944
14013
  }
13945
14014
 
13946
14015
  export { ElementDirectiveName, LWCDirectiveDomMode, LWCDirectiveRenderMode, LwcTagName, RootDirectiveName, TemplateDirectiveName, compile, compile as default, parse };
13947
- /** version: 6.2.0 */
14016
+ /** version: 6.3.0 */
13948
14017
  //# sourceMappingURL=index.js.map