@lwc/engine-core 6.3.3 → 6.4.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.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Copyright (c) 2024 Salesforce, Inc.
3
3
  */
4
- import { noop, StringToLowerCase, isNull, ArrayPush as ArrayPush$1, ArrayJoin, isFrozen, isUndefined as isUndefined$1, defineProperty, ArrayIndexOf, ArraySplice, create, isFalse, isFunction as isFunction$1, isObject, seal, isAPIFeatureEnabled, isArray as isArray$1, keys, hasOwnProperty as hasOwnProperty$1, entries, AriaPropNameToAttrNameMap, getPropertyDescriptor, forEach, defineProperties, getPrototypeOf as getPrototypeOf$1, setPrototypeOf, assign, freeze, KEY__SYNTHETIC_MODE, assert, toString as toString$1, getOwnPropertyDescriptor as getOwnPropertyDescriptor$1, LWC_VERSION_COMMENT_REGEX, LWC_VERSION, getOwnPropertyNames as getOwnPropertyNames$1, getOwnPropertyDescriptors, htmlPropertyToAttribute, ArraySlice, ArrayMap, KEY__SCOPED_CSS, kebabCaseToCamelCase, StringCharCodeAt, XML_NAMESPACE, XLINK_NAMESPACE, isString, StringSlice, ArrayShift, ArrayUnshift, isTrue, SVG_NAMESPACE, KEY__SHADOW_STATIC, KEY__SHADOW_RESOLVER, ArraySome, ArrayPop, isNumber, StringReplace, LOWEST_API_VERSION, KEY__NATIVE_GET_ELEMENT_BY_ID, KEY__NATIVE_QUERY_SELECTOR_ALL, ID_REFERENCING_ATTRIBUTES_SET, KEY__SHADOW_TOKEN, ArrayFilter, StringSplit, arrayEvery, ArrayIncludes, ArrayCopyWithin, ArrayFill, ArraySort, ArrayReverse } from '@lwc/shared';
4
+ import { noop, StringToLowerCase, isNull, ArrayPush as ArrayPush$1, ArrayJoin, isFrozen, isUndefined as isUndefined$1, defineProperty, ArrayIndexOf, ArraySplice, create, isFalse, isFunction as isFunction$1, isObject, seal, isAPIFeatureEnabled, isArray as isArray$1, keys, hasOwnProperty as hasOwnProperty$1, entries, AriaPropNameToAttrNameMap, getPropertyDescriptor, forEach, defineProperties, getPrototypeOf as getPrototypeOf$1, setPrototypeOf, assign, freeze, KEY__SYNTHETIC_MODE, assert, toString as toString$1, getOwnPropertyDescriptor as getOwnPropertyDescriptor$1, LWC_VERSION_COMMENT_REGEX, LWC_VERSION, getOwnPropertyNames as getOwnPropertyNames$1, getOwnPropertyDescriptors, htmlPropertyToAttribute, ArraySlice, ArrayMap, KEY__SCOPED_CSS, kebabCaseToCamelCase, StringCharCodeAt, XML_NAMESPACE, XLINK_NAMESPACE, isString, StringSlice, ArrayShift, ArrayUnshift, isTrue, SVG_NAMESPACE, KEY__SHADOW_STATIC, KEY__SHADOW_RESOLVER, ArraySome, ArrayPop, isNumber, StringReplace, htmlEscape, StringCharAt, LOWEST_API_VERSION, KEY__NATIVE_GET_ELEMENT_BY_ID, KEY__NATIVE_QUERY_SELECTOR_ALL, ID_REFERENCING_ATTRIBUTES_SET, KEY__SHADOW_TOKEN, ArrayFilter, StringSplit, arrayEvery, ArrayIncludes, ArrayCopyWithin, ArrayFill, ArraySort, ArrayReverse } from '@lwc/shared';
5
5
  export { setFeatureFlag, setFeatureFlagForTest } from '@lwc/features';
6
6
 
7
7
  /*
@@ -499,29 +499,6 @@ function assertNotProd() {
499
499
  throw new ReferenceError();
500
500
  }
501
501
  }
502
- // Temporary fix for when the LWC v5 compiler is used in conjunction with a v6+ engine
503
- // The old compiler format used the "slot" attribute in the `data` bag, whereas the new
504
- // format uses the special `slotAssignment` key.
505
- // This should be removed when the LWC v5 compiler is not used anywhere where it could be mismatched
506
- // with another LWC engine version.
507
- // TODO [#3974]: remove temporary logic to support v5 compiler + v6+ engine
508
- function applyTemporaryCompilerV5SlotFix(data) {
509
- if (lwcRuntimeFlags.DISABLE_TEMPORARY_V5_COMPILER_SUPPORT) {
510
- return data;
511
- }
512
- const { attrs } = data;
513
- if (!isUndefined$1(attrs)) {
514
- const { slot } = attrs;
515
- if (!isUndefined$1(slot) && !isNull(slot)) {
516
- return {
517
- ...data,
518
- attrs: cloneAndOmitKey(attrs, 'slot'),
519
- slotAssignment: String(slot),
520
- };
521
- }
522
- }
523
- return data;
524
- }
525
502
  function shouldBeFormAssociated(Ctor) {
526
503
  const ctorFormAssociated = Boolean(Ctor.formAssociated);
527
504
  const apiVersion = getComponentAPIVersion(Ctor);
@@ -3668,6 +3645,12 @@ function isVScopedSlotFragment(vnode) {
3668
3645
  function isVStatic(vnode) {
3669
3646
  return vnode.type === 4 /* VNodeType.Static */;
3670
3647
  }
3648
+ function isVStaticPartElement(vnode) {
3649
+ return vnode.type === 1 /* VStaticPartType.Element */;
3650
+ }
3651
+ function isVStaticPartText(vnode) {
3652
+ return vnode.type === 0 /* VStaticPartType.Text */;
3653
+ }
3671
3654
 
3672
3655
  /*
3673
3656
  * Copyright (c) 2018, salesforce.com, inc.
@@ -3677,7 +3660,8 @@ function isVStatic(vnode) {
3677
3660
  */
3678
3661
  const ColonCharCode = 58;
3679
3662
  function patchAttributes(oldVnode, vnode, renderer) {
3680
- const { attrs, external } = vnode.data;
3663
+ const { data, elm } = vnode;
3664
+ const { attrs } = data;
3681
3665
  if (isUndefined$1(attrs)) {
3682
3666
  return;
3683
3667
  }
@@ -3686,7 +3670,8 @@ function patchAttributes(oldVnode, vnode, renderer) {
3686
3670
  if (oldAttrs === attrs) {
3687
3671
  return;
3688
3672
  }
3689
- const { elm } = vnode;
3673
+ // Note VStaticPartData does not contain the external property so it will always default to false.
3674
+ const external = 'external' in data ? data.external : false;
3690
3675
  const { setAttribute, removeAttribute, setProperty } = renderer;
3691
3676
  for (const key in attrs) {
3692
3677
  const cur = attrs[key];
@@ -3790,8 +3775,7 @@ function patchProps(oldVnode, vnode, renderer) {
3790
3775
  */
3791
3776
  const classNameToClassMap = create(null);
3792
3777
  function getMapFromClassName(className) {
3793
- // Intentionally using == to match undefined and null values from computed style attribute
3794
- if (className == null) {
3778
+ if (isUndefined$1(className) || isNull(className) || className === '') {
3795
3779
  return EmptyObject;
3796
3780
  }
3797
3781
  // computed class names must be string
@@ -3830,10 +3814,16 @@ function patchClassAttribute(oldVnode, vnode, renderer) {
3830
3814
  if (oldClass === newClass) {
3831
3815
  return;
3832
3816
  }
3833
- const { getClassList } = renderer;
3834
- const classList = getClassList(elm);
3835
3817
  const newClassMap = getMapFromClassName(newClass);
3836
3818
  const oldClassMap = getMapFromClassName(oldClass);
3819
+ if (oldClassMap === newClassMap) {
3820
+ // These objects are cached by className string (`classNameToClassMap`), so we can only get here if there is
3821
+ // a key collision due to types, e.g. oldClass is `undefined` and newClass is `""` (empty string), or oldClass
3822
+ // is `1` (number) and newClass is `"1"` (string).
3823
+ return;
3824
+ }
3825
+ const { getClassList } = renderer;
3826
+ const classList = getClassList(elm);
3837
3827
  let name;
3838
3828
  for (name in oldClassMap) {
3839
3829
  // remove only if it is not in the new class collection and it is not set from within the instance
@@ -3855,8 +3845,13 @@ function patchClassAttribute(oldVnode, vnode, renderer) {
3855
3845
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
3856
3846
  */
3857
3847
  // The style property is a string when defined via an expression in the template.
3858
- function patchStyleAttribute(oldVnode, vnode, renderer) {
3848
+ function patchStyleAttribute(oldVnode, vnode, renderer, owner) {
3859
3849
  const { elm, data: { style: newStyle }, } = vnode;
3850
+ if (process.env.NODE_ENV !== 'production') {
3851
+ if (!isNull(newStyle) && !isUndefined$1(newStyle) && !isString(newStyle)) {
3852
+ logError(`Invalid 'style' attribute passed to <${elm.tagName.toLowerCase()}> is ignored. This attribute must be a string value.`, owner);
3853
+ }
3854
+ }
3860
3855
  const oldStyle = isNull(oldVnode) ? undefined : oldVnode.data.style;
3861
3856
  if (oldStyle === newStyle) {
3862
3857
  return;
@@ -3877,8 +3872,8 @@ function patchStyleAttribute(oldVnode, vnode, renderer) {
3877
3872
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
3878
3873
  */
3879
3874
  function applyEventListeners(vnode, renderer) {
3880
- const { elm } = vnode;
3881
- const on = vnode.data?.on;
3875
+ const { elm, data } = vnode;
3876
+ const { on } = data;
3882
3877
  if (isUndefined$1(on)) {
3883
3878
  return;
3884
3879
  }
@@ -3955,12 +3950,47 @@ function applyRefs(vnode, owner) {
3955
3950
  refVNodes[ref] = vnode;
3956
3951
  }
3957
3952
 
3953
+ /*
3954
+ * Copyright (c) 2024, salesforce.com, inc.
3955
+ * All rights reserved.
3956
+ * SPDX-License-Identifier: MIT
3957
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
3958
+ */
3959
+ function patchTextVNode(n1, n2, renderer) {
3960
+ n2.elm = n1.elm;
3961
+ if (n2.text !== n1.text) {
3962
+ updateTextContent$1(n2, renderer);
3963
+ }
3964
+ }
3965
+ function patchTextVStaticPart(n1, n2, renderer) {
3966
+ if (isNull(n1) || n2.text !== n1.text) {
3967
+ updateTextContent$1(n2, renderer);
3968
+ }
3969
+ }
3970
+ function updateTextContent$1(vnode, renderer) {
3971
+ const { elm, text } = vnode;
3972
+ const { setText } = renderer;
3973
+ if (process.env.NODE_ENV !== 'production') {
3974
+ unlockDomMutation();
3975
+ }
3976
+ setText(elm, text);
3977
+ if (process.env.NODE_ENV !== 'production') {
3978
+ lockDomMutation();
3979
+ }
3980
+ }
3981
+
3958
3982
  /*
3959
3983
  * Copyright (c) 2023, salesforce.com, inc.
3960
3984
  * All rights reserved.
3961
3985
  * SPDX-License-Identifier: MIT
3962
3986
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
3963
3987
  */
3988
+ /**
3989
+ * Given an array of static parts, mounts the DOM element to the part based on the staticPartId
3990
+ * @param root the root element
3991
+ * @param parts an array of VStaticParts
3992
+ * @param renderer the renderer to use
3993
+ */
3964
3994
  function traverseAndSetElements(root, parts, renderer) {
3965
3995
  const numParts = parts.length;
3966
3996
  // Optimization given that, in most cases, there will be one part, and it's just the root
@@ -4026,18 +4056,30 @@ function mountStaticParts(root, vnode, renderer) {
4026
4056
  traverseAndSetElements(root, parts, renderer);
4027
4057
  // Currently only event listeners and refs are supported for static vnodes
4028
4058
  for (const part of parts) {
4029
- // Event listeners only need to be applied once when mounting
4030
- applyEventListeners(part, renderer);
4031
- // Refs must be updated after every render due to refVNodes getting reset before every render
4032
- applyRefs(part, owner);
4059
+ if (isVStaticPartElement(part)) {
4060
+ // Event listeners only need to be applied once when mounting
4061
+ applyEventListeners(part, renderer);
4062
+ // Refs must be updated after every render due to refVNodes getting reset before every render
4063
+ applyRefs(part, owner);
4064
+ patchAttributes(null, part, renderer);
4065
+ patchClassAttribute(null, part, renderer);
4066
+ patchStyleAttribute(null, part, renderer, owner);
4067
+ }
4068
+ else {
4069
+ if (process.env.NODE_ENV !== 'production' && !isVStaticPartText(part)) {
4070
+ throw new Error(`LWC internal error, encountered unknown static part type: ${part.type}`);
4071
+ }
4072
+ patchTextVStaticPart(null, part, renderer);
4073
+ }
4033
4074
  }
4034
4075
  }
4035
4076
  /**
4036
- * Mounts elements to the newly generated VStatic node
4077
+ * Updates the static elements based on the content of the VStaticParts
4037
4078
  * @param n1 the previous VStatic vnode
4038
4079
  * @param n2 the current VStatic vnode
4080
+ * @param renderer the renderer to use
4039
4081
  */
4040
- function patchStaticParts(n1, n2) {
4082
+ function patchStaticParts(n1, n2, renderer) {
4041
4083
  // On the server, we don't support ref (because it relies on renderedCallback), nor do we
4042
4084
  // support event listeners (no interactivity), so traversing parts makes no sense
4043
4085
  if (!process.env.IS_BROWSER) {
@@ -4052,12 +4094,49 @@ function patchStaticParts(n1, n2) {
4052
4094
  assert.isTrue(currParts.length === prevParts?.length, 'Expected static parts to be the same for the same element. This is an error with the LWC framework itself.');
4053
4095
  }
4054
4096
  for (let i = 0; i < currParts.length; i++) {
4097
+ const prevPart = prevParts[i];
4055
4098
  const part = currParts[i];
4056
4099
  // Patch only occurs if the vnode is newly generated, which means the part.elm is always undefined
4057
4100
  // Since the vnode and elements are the same we can safely assume that prevParts[i].elm is defined.
4058
- part.elm = prevParts[i].elm;
4059
- // Refs must be updated after every render due to refVNodes getting reset before every render
4060
- applyRefs(part, currPartsOwner);
4101
+ part.elm = prevPart.elm;
4102
+ if (process.env.NODE_ENV !== 'production' && prevPart.type !== part.type) {
4103
+ throw new Error(`LWC internal error, static part types do not match. Previous type was ${prevPart.type} and current type is ${part.type}`);
4104
+ }
4105
+ if (isVStaticPartElement(part)) {
4106
+ // Refs must be updated after every render due to refVNodes getting reset before every render
4107
+ applyRefs(part, currPartsOwner);
4108
+ patchAttributes(prevPart, part, renderer);
4109
+ patchClassAttribute(prevPart, part, renderer);
4110
+ patchStyleAttribute(prevPart, part, renderer, currPartsOwner);
4111
+ }
4112
+ else {
4113
+ patchTextVStaticPart(null, part, renderer);
4114
+ }
4115
+ }
4116
+ }
4117
+ /**
4118
+ * Mounts the hydration specific attributes
4119
+ * @param vnode the parent VStatic node
4120
+ * @param renderer the renderer to use
4121
+ */
4122
+ function hydrateStaticParts(vnode, renderer) {
4123
+ if (!process.env.IS_BROWSER) {
4124
+ return;
4125
+ }
4126
+ const { parts, owner } = vnode;
4127
+ if (isUndefined$1(parts)) {
4128
+ return;
4129
+ }
4130
+ // Note, hydration doesn't patch attributes because hydration validation occurs before this routine
4131
+ // which guarantees that the elements are the same.
4132
+ // We only need to apply the parts for things that cannot be done on the server.
4133
+ for (const part of parts) {
4134
+ if (isVStaticPartElement(part)) {
4135
+ // Event listeners only need to be applied once when mounting
4136
+ applyEventListeners(part, renderer);
4137
+ // Refs must be updated after every render due to refVNodes getting reset before every render
4138
+ applyRefs(part, owner);
4139
+ }
4061
4140
  }
4062
4141
  }
4063
4142
 
@@ -4095,7 +4174,7 @@ function patch(n1, n2, parent, renderer) {
4095
4174
  switch (n2.type) {
4096
4175
  case 0 /* VNodeType.Text */:
4097
4176
  // VText has no special capability, fallback to the owner's renderer
4098
- patchText(n1, n2, renderer);
4177
+ patchTextVNode(n1, n2, renderer);
4099
4178
  break;
4100
4179
  case 1 /* VNodeType.Comment */:
4101
4180
  // VComment has no special capability, fallback to the owner's renderer
@@ -4142,12 +4221,6 @@ function mount(node, parent, renderer, anchor) {
4142
4221
  break;
4143
4222
  }
4144
4223
  }
4145
- function patchText(n1, n2, renderer) {
4146
- n2.elm = n1.elm;
4147
- if (n2.text !== n1.text) {
4148
- updateTextContent(n2, renderer);
4149
- }
4150
- }
4151
4224
  function mountText(vnode, parent, anchor, renderer) {
4152
4225
  const { owner } = vnode;
4153
4226
  const { createText } = renderer;
@@ -4160,7 +4233,7 @@ function patchComment(n1, n2, renderer) {
4160
4233
  // FIXME: Comment nodes should be static, we shouldn't need to diff them together. However
4161
4234
  // it is the case today.
4162
4235
  if (n2.text !== n1.text) {
4163
- updateTextContent(n2, renderer);
4236
+ updateTextContent$1(n2, renderer);
4164
4237
  }
4165
4238
  }
4166
4239
  function mountComment(vnode, parent, anchor, renderer) {
@@ -4204,7 +4277,7 @@ function patchStatic(n1, n2, renderer) {
4204
4277
  // slotAssignments can only apply to the top level element, never to a static part.
4205
4278
  patchSlotAssignment(n1, n2, renderer);
4206
4279
  // The `refs` object is blown away in every re-render, so we always need to re-apply them
4207
- patchStaticParts(n1, n2);
4280
+ patchStaticParts(n1, n2, renderer);
4208
4281
  }
4209
4282
  function patchElement(n1, n2, renderer) {
4210
4283
  const elm = (n2.elm = n1.elm);
@@ -4215,19 +4288,20 @@ function mountStatic(vnode, parent, anchor, renderer) {
4215
4288
  const { owner } = vnode;
4216
4289
  const { cloneNode, isSyntheticShadowDefined } = renderer;
4217
4290
  const elm = (vnode.elm = cloneNode(vnode.fragment, true));
4291
+ // Define the root node shadow resolver
4218
4292
  linkNodeToShadow(elm, owner, renderer);
4219
4293
  applyElementRestrictions(elm, vnode);
4220
- // Marks this node as Static to propagate the shadow resolver. must happen after elm is assigned to the proper shadow
4221
4294
  const { renderMode, shadowMode } = owner;
4222
4295
  if (isSyntheticShadowDefined) {
4296
+ // Marks this node as Static to propagate the shadow resolver. must happen after elm is assigned to the proper shadow
4223
4297
  if (shadowMode === 1 /* ShadowMode.Synthetic */ || renderMode === 0 /* RenderMode.Light */) {
4224
4298
  elm[KEY__SHADOW_STATIC] = true;
4225
4299
  }
4226
4300
  }
4227
4301
  // slotAssignments can only apply to the top level element, never to a static part.
4228
4302
  patchSlotAssignment(null, vnode, renderer);
4229
- insertNode(elm, parent, anchor, renderer);
4230
4303
  mountStaticParts(elm, vnode, renderer);
4304
+ insertNode(elm, parent, anchor, renderer);
4231
4305
  }
4232
4306
  function mountCustomElement(vnode, parent, anchor, renderer) {
4233
4307
  const { sel, owner, ctor } = vnode;
@@ -4392,17 +4466,6 @@ function linkNodeToShadow(elm, owner, renderer) {
4392
4466
  }
4393
4467
  }
4394
4468
  }
4395
- function updateTextContent(vnode, renderer) {
4396
- const { elm, text } = vnode;
4397
- const { setText } = renderer;
4398
- if (process.env.NODE_ENV !== 'production') {
4399
- unlockDomMutation();
4400
- }
4401
- setText(elm, text);
4402
- if (process.env.NODE_ENV !== 'production') {
4403
- lockDomMutation();
4404
- }
4405
- }
4406
4469
  function insertFragmentOrNode(vnode, parent, anchor, renderer) {
4407
4470
  if (process.env.NODE_ENV !== 'production') {
4408
4471
  unlockDomMutation();
@@ -4447,15 +4510,16 @@ function patchElementPropsAndAttrsAndRefs$1(oldVnode, vnode, renderer) {
4447
4510
  applyStaticClassAttribute(vnode, renderer);
4448
4511
  applyStaticStyleAttribute(vnode, renderer);
4449
4512
  }
4513
+ const { owner } = vnode;
4450
4514
  // Attrs need to be applied to element before props IE11 will wipe out value on radio inputs if
4451
4515
  // value is set before type=radio.
4452
4516
  patchClassAttribute(oldVnode, vnode, renderer);
4453
- patchStyleAttribute(oldVnode, vnode, renderer);
4517
+ patchStyleAttribute(oldVnode, vnode, renderer, owner);
4454
4518
  patchAttributes(oldVnode, vnode, renderer);
4455
4519
  patchProps(oldVnode, vnode, renderer);
4456
4520
  patchSlotAssignment(oldVnode, vnode, renderer);
4457
4521
  // The `refs` object is blown away in every re-render, so we always need to re-apply them
4458
- applyRefs(vnode, vnode.owner);
4522
+ applyRefs(vnode, owner);
4459
4523
  }
4460
4524
  function applyStyleScoping(elm, owner, renderer) {
4461
4525
  const { getClassList } = renderer;
@@ -4857,10 +4921,14 @@ function addVNodeToChildLWC(vnode) {
4857
4921
  ArrayPush$1.call(getVMBeingRendered().velements, vnode);
4858
4922
  }
4859
4923
  // [s]tatic [p]art
4860
- function sp(partId, data) {
4924
+ function sp(partId, data, text) {
4925
+ // Static part will always have either text or data, it's guaranteed by the compiler.
4926
+ const type = isNull(text) ? 1 /* VStaticPartType.Element */ : 0 /* VStaticPartType.Text */;
4861
4927
  return {
4928
+ type,
4862
4929
  partId,
4863
4930
  data,
4931
+ text,
4864
4932
  elm: undefined, // elm is defined later
4865
4933
  };
4866
4934
  }
@@ -4877,8 +4945,9 @@ function ssf(slotName, factory) {
4877
4945
  };
4878
4946
  }
4879
4947
  // [st]atic node
4880
- function st(fragment, key, parts) {
4948
+ function st(fragmentFactory, key, parts) {
4881
4949
  const owner = getVMBeingRendered();
4950
+ const fragment = fragmentFactory(parts);
4882
4951
  const vnode = {
4883
4952
  type: 4 /* VNodeType.Static */,
4884
4953
  sel: undefined,
@@ -4920,9 +4989,6 @@ function h(sel, data, children = EmptyArray) {
4920
4989
  // checking reserved internal data properties
4921
4990
  assert.isFalse(data.className && data.classMap, `vnode.data.className and vnode.data.classMap ambiguous declaration.`);
4922
4991
  assert.isFalse(data.styleDecls && data.style, `vnode.data.styleDecls and vnode.data.style ambiguous declaration.`);
4923
- if (data.style && !isString(data.style)) {
4924
- logError(`Invalid 'style' attribute passed to <${sel}> is ignored. This attribute must be a string value.`, vmBeingRendered);
4925
- }
4926
4992
  forEach.call(children, (childVnode) => {
4927
4993
  if (childVnode != null) {
4928
4994
  assert.isTrue('type' in childVnode &&
@@ -4932,8 +4998,6 @@ function h(sel, data, children = EmptyArray) {
4932
4998
  }
4933
4999
  });
4934
5000
  }
4935
- // TODO [#3974]: remove temporary logic to support v5 compiler + v6+ engine
4936
- data = applyTemporaryCompilerV5SlotFix(data);
4937
5001
  const { key, slotAssignment } = data;
4938
5002
  const vnode = {
4939
5003
  type: 2 /* VNodeType.Element */,
@@ -4970,8 +5034,6 @@ function s(slotName, data, children, slotset) {
4970
5034
  }
4971
5035
  const vmBeingRendered = getVMBeingRendered();
4972
5036
  const { renderMode, apiVersion } = vmBeingRendered;
4973
- // TODO [#3974]: remove temporary logic to support v5 compiler + v6+ engine
4974
- data = applyTemporaryCompilerV5SlotFix(data);
4975
5037
  if (!isUndefined$1(slotset) &&
4976
5038
  !isUndefined$1(slotset.slotAssignments) &&
4977
5039
  !isUndefined$1(slotset.slotAssignments[slotName]) &&
@@ -5075,8 +5137,6 @@ function c(sel, Ctor, data, children = EmptyArray) {
5075
5137
  });
5076
5138
  }
5077
5139
  }
5078
- // TODO [#3974]: remove temporary logic to support v5 compiler + v6+ engine
5079
- data = applyTemporaryCompilerV5SlotFix(data);
5080
5140
  const { key, slotAssignment } = data;
5081
5141
  let elm, aChildren, vm;
5082
5142
  const vnode = {
@@ -5138,16 +5198,19 @@ function i(iterable, factory) {
5138
5198
  if (process.env.NODE_ENV !== 'production') {
5139
5199
  const vnodes = isArray$1(vnode) ? vnode : [vnode];
5140
5200
  forEach.call(vnodes, (childVnode) => {
5141
- if (!isNull(childVnode) && isObject(childVnode) && !isUndefined$1(childVnode.sel)) {
5201
+ // Check that the child vnode is either an element or VStatic
5202
+ if (!isNull(childVnode) && (isVBaseElement(childVnode) || isVStatic(childVnode))) {
5142
5203
  const { key } = childVnode;
5204
+ // In @lwc/engine-server the fragment doesn't have a tagName, default to the VM's tagName.
5205
+ const { tagName } = vmBeingRendered;
5143
5206
  if (isString(key) || isNumber(key)) {
5144
5207
  if (keyMap[key] === 1 && isUndefined$1(iterationError)) {
5145
- iterationError = `Duplicated "key" attribute value for "<${childVnode.sel}>" in ${vmBeingRendered} for item number ${j}. A key with value "${childVnode.key}" appears more than once in the iteration. Key values must be unique numbers or strings.`;
5208
+ iterationError = `Duplicated "key" attribute value in "<${tagName}>" for item number ${j}. A key with value "${key}" appears more than once in the iteration. Key values must be unique numbers or strings.`;
5146
5209
  }
5147
5210
  keyMap[key] = 1;
5148
5211
  }
5149
5212
  else if (isUndefined$1(iterationError)) {
5150
- iterationError = `Invalid "key" attribute value in "<${childVnode.sel}>" in ${vmBeingRendered} for item number ${j}. Set a unique "key" value on all iterated child elements.`;
5213
+ iterationError = `Invalid "key" attribute value in "<${tagName}>" for item number ${j}. Set a unique "key" value on all iterated child elements.`;
5151
5214
  }
5152
5215
  }
5153
5216
  });
@@ -5546,6 +5609,111 @@ function validateLightDomTemplate(template, vm) {
5546
5609
  }
5547
5610
  }
5548
5611
  }
5612
+ const browserExpressionSerializer = (partToken, classAttrToken) => {
5613
+ // This will insert the scoped style token as a static class attribute in the fragment
5614
+ // bypassing the need to call applyStyleScoping when mounting static parts.
5615
+ const type = StringCharAt.call(partToken, 0);
5616
+ switch (type) {
5617
+ case "c" /* STATIC_PART_TOKEN_ID.CLASS */:
5618
+ return classAttrToken;
5619
+ case "t" /* STATIC_PART_TOKEN_ID.TEXT */:
5620
+ // Using a single space here gives us a single empty text node
5621
+ return ' ';
5622
+ default:
5623
+ return '';
5624
+ }
5625
+ };
5626
+ const serializerNoop = () => {
5627
+ throw new Error('LWC internal error, attempted to serialize partToken without static parts');
5628
+ };
5629
+ // This function serializes the expressions generated by static content optimization.
5630
+ // Currently this is only needed for SSR.
5631
+ // TODO [#4078]: Split the implementation between @lwc/engine-dom and @lwc/engine-server
5632
+ function buildSerializeExpressionFn(parts) {
5633
+ if (process.env.IS_BROWSER) {
5634
+ return browserExpressionSerializer;
5635
+ }
5636
+ if (isUndefined$1(parts)) {
5637
+ // Technically this should not be reachable, if there are no parts there should be no partTokens
5638
+ // and this function should never be invoked.
5639
+ return serializerNoop;
5640
+ }
5641
+ const partIdsToParts = new Map();
5642
+ for (const staticPart of parts) {
5643
+ partIdsToParts.set(`${staticPart.partId}`, staticPart);
5644
+ }
5645
+ const parsePartToken = (partToken) => {
5646
+ // The partTokens are split into 3 section:
5647
+ // 1. The first character represents the expression type (attribute, class, style, or text).
5648
+ // 2. For attributes, the characters from index 1 to the first occurrence of a ':' is the partId.
5649
+ // 3. Everything after the first ':' represents the attribute name.
5650
+ // 4. For non-attributes everything from index 1 to the string length is the partId.
5651
+ // Ex, attribute: a0:data-name, a = an attribute, 0 = partId, data-name = attribute name.
5652
+ // Ex, style: s0, s = a style attribute, 0 = partId.
5653
+ const type = StringCharAt.call(partToken, 0);
5654
+ let delimiterIndex = partToken.length;
5655
+ let attrName = '';
5656
+ if (type === "a" /* STATIC_PART_TOKEN_ID.ATTRIBUTE */) {
5657
+ delimiterIndex = partToken.indexOf(':');
5658
+ // Only VStaticPartData.attrs have an attribute name
5659
+ attrName = partToken.substring(delimiterIndex + 1);
5660
+ }
5661
+ const partId = partToken.substring(1, delimiterIndex);
5662
+ const part = partIdsToParts.get(partId) ?? EmptyObject;
5663
+ return { type, part, attrName };
5664
+ };
5665
+ return (partToken, classToken) => {
5666
+ const { type, part, attrName } = parsePartToken(partToken);
5667
+ switch (type) {
5668
+ case "a" /* STATIC_PART_TOKEN_ID.ATTRIBUTE */:
5669
+ return serializeAttribute(part, attrName);
5670
+ case "c" /* STATIC_PART_TOKEN_ID.CLASS */: // class
5671
+ return serializeClassAttribute(part, classToken);
5672
+ case "s" /* STATIC_PART_TOKEN_ID.STYLE */: // style
5673
+ return serializeStyleAttribute(part);
5674
+ case "t" /* STATIC_PART_TOKEN_ID.TEXT */: // text
5675
+ return serializeTextContent(part);
5676
+ default:
5677
+ // This should not be reachable
5678
+ throw new Error(`LWC internal error, unrecognized part token during serialization ${partToken}`);
5679
+ }
5680
+ };
5681
+ }
5682
+ function serializeTextContent(part) {
5683
+ const { text } = part;
5684
+ if (text === '') {
5685
+ return '\u200D'; // Special serialization for empty text nodes
5686
+ }
5687
+ // Note the serialization logic doesn't need to validate against the style tag as in serializeTextContent
5688
+ // because style tags are always inserted through the engine.
5689
+ // User input of style tags are blocked, furthermore, all dynamic text is escaped at this point.
5690
+ return htmlEscape(text);
5691
+ }
5692
+ function serializeStyleAttribute(part) {
5693
+ const { data: { style }, } = part;
5694
+ // This is designed to mirror logic patchStyleAttribute
5695
+ return isString(style) && style.length ? ` style="${htmlEscape(style, true)}"` : '';
5696
+ }
5697
+ function serializeAttribute(part, name) {
5698
+ const { data: { attrs = {} }, } = part;
5699
+ const rawValue = attrs[name];
5700
+ let value = '';
5701
+ // The undefined and null checks here are designed to match patchAttributes routine.
5702
+ if (!isUndefined$1(rawValue) && !isNull(rawValue)) {
5703
+ const stringifiedValue = String(rawValue);
5704
+ value = stringifiedValue.length
5705
+ ? ` ${name}="${htmlEscape(stringifiedValue, true)}"`
5706
+ : ` ${name}`;
5707
+ }
5708
+ return value;
5709
+ }
5710
+ function serializeClassAttribute(part, classToken) {
5711
+ const classMap = getMapFromClassName(part.data?.className);
5712
+ // Trim the leading and trailing whitespace here because classToken contains a leading space and
5713
+ // there will be a trailing space if classMap is empty.
5714
+ const computedClassName = `${classToken} ${keys(classMap).join(' ')}`.trim();
5715
+ return computedClassName.length ? ` class="${htmlEscape(computedClassName, true)}"` : '';
5716
+ }
5549
5717
  // This should be a no-op outside of LWC's Karma tests, where it's not needed
5550
5718
  let registerFragmentCache = noop;
5551
5719
  // Only used in LWC's Karma tests
@@ -5567,7 +5735,7 @@ function buildParseFragmentFn(createFragmentFn) {
5567
5735
  return (strings, ...keys) => {
5568
5736
  const cache = create(null);
5569
5737
  registerFragmentCache(cache);
5570
- return function () {
5738
+ return function (parts) {
5571
5739
  const { context: { hasScopedStyles, stylesheetToken, legacyStylesheetToken }, shadowMode, renderer, } = getVMBeingRendered();
5572
5740
  const hasStyleToken = !isUndefined$1(stylesheetToken);
5573
5741
  const isSyntheticShadow = shadowMode === 1 /* ShadowMode.Synthetic */;
@@ -5579,14 +5747,27 @@ function buildParseFragmentFn(createFragmentFn) {
5579
5747
  if (hasStyleToken && isSyntheticShadow) {
5580
5748
  cacheKey |= 2 /* FragmentCache.SHADOW_MODE_SYNTHETIC */;
5581
5749
  }
5582
- if (!isUndefined$1(cache[cacheKey])) {
5583
- return cache[cacheKey];
5750
+ // Cache is only here to prevent calling innerHTML multiple times which doesn't happen on the server.
5751
+ if (process.env.IS_BROWSER) {
5752
+ // Disable this on the server to prevent cache poisoning when expressions are used.
5753
+ const cached = cache[cacheKey];
5754
+ if (!isUndefined$1(cached)) {
5755
+ return cached;
5756
+ }
5584
5757
  }
5585
5758
  // If legacy stylesheet tokens are required, then add them to the rendered string
5586
5759
  const stylesheetTokenToRender = stylesheetToken + (hasLegacyToken ? ` ${legacyStylesheetToken}` : '');
5587
5760
  const classToken = hasScopedStyles && hasStyleToken ? ' ' + stylesheetTokenToRender : '';
5588
5761
  const classAttrToken = hasScopedStyles && hasStyleToken ? ` class="${stylesheetTokenToRender}"` : '';
5589
5762
  const attrToken = hasStyleToken && isSyntheticShadow ? ' ' + stylesheetTokenToRender : '';
5763
+ // In the browser, we provide the entire class attribute as a perf optimization to avoid applying it on mount.
5764
+ // The remaining class expression will be applied when the static parts are mounted.
5765
+ // In SSR, the entire class attribute (expression included) is assembled along with the fragment.
5766
+ // This is why in the browser we provide the entire class attribute and in SSR we only provide the class token.
5767
+ const exprClassToken = process.env.IS_BROWSER ? classAttrToken : classToken;
5768
+ // TODO [#3624]: The implementation of this function should be specific to @lwc/engine-dom and @lwc/engine-server.
5769
+ // Find a way to split this in a future refactor.
5770
+ const serializeExpression = buildSerializeExpressionFn(parts);
5590
5771
  let htmlFragment = '';
5591
5772
  for (let i = 0, n = keys.length; i < n; i++) {
5592
5773
  switch (keys[i]) {
@@ -5602,6 +5783,10 @@ function buildParseFragmentFn(createFragmentFn) {
5602
5783
  case 3: // ${1}${2}
5603
5784
  htmlFragment += strings[i] + classAttrToken + attrToken;
5604
5785
  break;
5786
+ default: // expressions ${partId:attributeName/textId}
5787
+ htmlFragment +=
5788
+ strings[i] + serializeExpression(keys[i], exprClassToken);
5789
+ break;
5605
5790
  }
5606
5791
  }
5607
5792
  htmlFragment += strings[strings.length - 1];
@@ -6484,25 +6669,25 @@ function forceRehydration(vm) {
6484
6669
  scheduleRehydration(vm);
6485
6670
  }
6486
6671
  }
6487
- function runFormAssociatedCustomElementCallback(vm, faceCb) {
6672
+ function runFormAssociatedCustomElementCallback(vm, faceCb, args) {
6488
6673
  const { renderMode, shadowMode } = vm;
6489
6674
  if (shadowMode === 1 /* ShadowMode.Synthetic */ && renderMode !== 0 /* RenderMode.Light */) {
6490
6675
  throw new Error('Form associated lifecycle methods are not available in synthetic shadow. Please use native shadow or light DOM.');
6491
6676
  }
6492
- invokeComponentCallback(vm, faceCb);
6677
+ invokeComponentCallback(vm, faceCb, args);
6493
6678
  }
6494
- function runFormAssociatedCallback(elm) {
6679
+ function runFormAssociatedCallback(elm, form) {
6495
6680
  const vm = getAssociatedVM(elm);
6496
6681
  const { formAssociatedCallback } = vm.def;
6497
6682
  if (!isUndefined$1(formAssociatedCallback)) {
6498
- runFormAssociatedCustomElementCallback(vm, formAssociatedCallback);
6683
+ runFormAssociatedCustomElementCallback(vm, formAssociatedCallback, [form]);
6499
6684
  }
6500
6685
  }
6501
- function runFormDisabledCallback(elm) {
6686
+ function runFormDisabledCallback(elm, disabled) {
6502
6687
  const vm = getAssociatedVM(elm);
6503
6688
  const { formDisabledCallback } = vm.def;
6504
6689
  if (!isUndefined$1(formDisabledCallback)) {
6505
- runFormAssociatedCustomElementCallback(vm, formDisabledCallback);
6690
+ runFormAssociatedCustomElementCallback(vm, formDisabledCallback, [disabled]);
6506
6691
  }
6507
6692
  }
6508
6693
  function runFormResetCallback(elm) {
@@ -6512,11 +6697,11 @@ function runFormResetCallback(elm) {
6512
6697
  runFormAssociatedCustomElementCallback(vm, formResetCallback);
6513
6698
  }
6514
6699
  }
6515
- function runFormStateRestoreCallback(elm) {
6700
+ function runFormStateRestoreCallback(elm, state, reason) {
6516
6701
  const vm = getAssociatedVM(elm);
6517
6702
  const { formStateRestoreCallback } = vm.def;
6518
6703
  if (!isUndefined$1(formStateRestoreCallback)) {
6519
- runFormAssociatedCustomElementCallback(vm, formStateRestoreCallback);
6704
+ runFormAssociatedCustomElementCallback(vm, formStateRestoreCallback, [state, reason]);
6520
6705
  }
6521
6706
  }
6522
6707
  function resetRefVNodes(vm) {
@@ -6884,9 +7069,12 @@ function hydrateText(node, vnode, renderer) {
6884
7069
  if (!hasCorrectNodeType(vnode, node, 3 /* EnvNodeTypes.TEXT */, renderer)) {
6885
7070
  return handleMismatch(node, vnode, renderer);
6886
7071
  }
7072
+ return updateTextContent(node, vnode, vnode.owner, renderer);
7073
+ }
7074
+ function updateTextContent(node, vnode, owner, renderer) {
6887
7075
  if (process.env.NODE_ENV !== 'production') {
6888
7076
  if (!textNodeContentsAreEqual(node, vnode, renderer)) {
6889
- logWarn('Hydration mismatch: text values do not match, will recover from the difference', vnode.owner);
7077
+ logWarn('Hydration mismatch: text values do not match, will recover from the difference', owner);
6890
7078
  }
6891
7079
  }
6892
7080
  const { setText } = renderer;
@@ -6912,11 +7100,24 @@ function hydrateComment(node, vnode, renderer) {
6912
7100
  }
6913
7101
  function hydrateStaticElement(elm, vnode, renderer) {
6914
7102
  if (!hasCorrectNodeType(vnode, elm, 1 /* EnvNodeTypes.ELEMENT */, renderer) ||
6915
- !areCompatibleNodes(vnode.fragment, elm, vnode, renderer)) {
7103
+ !areCompatibleStaticNodes(vnode.fragment, elm, vnode, renderer)) {
7104
+ return handleMismatch(elm, vnode, renderer);
7105
+ }
7106
+ return hydrateStaticElementParts(elm, vnode, renderer);
7107
+ }
7108
+ function hydrateStaticElementParts(elm, vnode, renderer) {
7109
+ const { parts } = vnode;
7110
+ if (!isUndefined$1(parts)) {
7111
+ // Elements must first be set on the static part to validate against.
7112
+ traverseAndSetElements(elm, parts, renderer);
7113
+ }
7114
+ if (!haveCompatibleStaticParts(vnode, renderer)) {
6916
7115
  return handleMismatch(elm, vnode, renderer);
6917
7116
  }
6918
7117
  vnode.elm = elm;
6919
- mountStaticParts(elm, vnode, renderer);
7118
+ // Hydration only requires applying event listeners and refs.
7119
+ // All other expressions should be applied during SSR or through the handleMismatch routine.
7120
+ hydrateStaticParts(vnode, renderer);
6920
7121
  return elm;
6921
7122
  }
6922
7123
  function hydrateFragment(elm, vnode, renderer) {
@@ -7092,12 +7293,13 @@ function isMatchingElement(vnode, elm, renderer, shouldValidateAttr = () => true
7092
7293
  }
7093
7294
  return false;
7094
7295
  }
7095
- const hasCompatibleAttrs = validateAttrs(vnode, elm, renderer, shouldValidateAttr);
7296
+ const { data } = vnode;
7297
+ const hasCompatibleAttrs = validateAttrs(vnode, elm, data, renderer, shouldValidateAttr);
7096
7298
  const hasCompatibleClass = shouldValidateAttr('class')
7097
- ? validateClassAttr(vnode, elm, renderer)
7299
+ ? validateClassAttr(vnode, elm, data, renderer)
7098
7300
  : true;
7099
7301
  const hasCompatibleStyle = shouldValidateAttr('style')
7100
- ? validateStyleAttr(vnode, elm, renderer)
7302
+ ? validateStyleAttr(vnode, elm, data, renderer)
7101
7303
  : true;
7102
7304
  return hasCompatibleAttrs && hasCompatibleClass && hasCompatibleStyle;
7103
7305
  }
@@ -7114,8 +7316,8 @@ function attributeValuesAreEqual(vnodeValue, value) {
7114
7316
  // In all other cases, the two values are not considered equal
7115
7317
  return false;
7116
7318
  }
7117
- function validateAttrs(vnode, elm, renderer, shouldValidateAttr) {
7118
- const { data: { attrs = {} }, } = vnode;
7319
+ function validateAttrs(vnode, elm, data, renderer, shouldValidateAttr) {
7320
+ const { attrs = {} } = data;
7119
7321
  let nodesAreCompatible = true;
7120
7322
  // Validate attributes, though we could always recovery from those by running the update mods.
7121
7323
  // Note: intentionally ONLY matching vnodes.attrs to elm.attrs, in case SSR is adding extra attributes.
@@ -7123,21 +7325,22 @@ function validateAttrs(vnode, elm, renderer, shouldValidateAttr) {
7123
7325
  if (!shouldValidateAttr(attrName)) {
7124
7326
  continue;
7125
7327
  }
7126
- const { owner } = vnode;
7127
7328
  const { getAttribute } = renderer;
7128
7329
  const elmAttrValue = getAttribute(elm, attrName);
7129
7330
  if (!attributeValuesAreEqual(attrValue, elmAttrValue)) {
7130
7331
  if (process.env.NODE_ENV !== 'production') {
7131
7332
  const { getProperty } = renderer;
7132
- logError(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: attribute "${attrName}" has different values, expected "${attrValue}" but found ${isNull(elmAttrValue) ? 'null' : `"${elmAttrValue}"`}`, owner);
7333
+ logError(`Mismatch hydrating element <${getProperty(elm, 'tagName').toLowerCase()}>: attribute "${attrName}" has different values, expected "${attrValue}" but found ${isNull(elmAttrValue) ? 'null' : `"${elmAttrValue}"`}`, vnode.owner);
7133
7334
  }
7134
7335
  nodesAreCompatible = false;
7135
7336
  }
7136
7337
  }
7137
7338
  return nodesAreCompatible;
7138
7339
  }
7139
- function validateClassAttr(vnode, elm, renderer) {
7140
- const { data, owner } = vnode;
7340
+ function validateClassAttr(vnode, elm, data, renderer) {
7341
+ const { owner } = vnode;
7342
+ // classMap is never available on VStaticPartData so it can default to undefined
7343
+ // casting to prevent TS error.
7141
7344
  let { className, classMap } = data;
7142
7345
  const { getProperty, getClassList, getAttribute } = renderer;
7143
7346
  // we don't care about legacy for hydration. it's a new use case
@@ -7210,8 +7413,9 @@ function validateClassAttr(vnode, elm, renderer) {
7210
7413
  }
7211
7414
  return nodesAreCompatible;
7212
7415
  }
7213
- function validateStyleAttr(vnode, elm, renderer) {
7214
- const { data: { style, styleDecls }, } = vnode;
7416
+ function validateStyleAttr(vnode, elm, data, renderer) {
7417
+ // Note styleDecls is always undefined for VStaticPartData, casting here to default it to undefined
7418
+ const { style, styleDecls } = data;
7215
7419
  const { getAttribute } = renderer;
7216
7420
  const elmStyle = getAttribute(elm, 'style') || '';
7217
7421
  let vnodeStyle;
@@ -7251,7 +7455,7 @@ function validateStyleAttr(vnode, elm, renderer) {
7251
7455
  }
7252
7456
  return nodesAreCompatible;
7253
7457
  }
7254
- function areCompatibleNodes(client, ssr, vnode, renderer) {
7458
+ function areCompatibleStaticNodes(client, ssr, vnode, renderer) {
7255
7459
  const { getProperty, getAttribute } = renderer;
7256
7460
  if (getProperty(client, 'nodeType') === 3 /* EnvNodeTypes.TEXT */) {
7257
7461
  if (!hasCorrectNodeType(vnode, ssr, 3 /* EnvNodeTypes.TEXT */, renderer)) {
@@ -7268,24 +7472,63 @@ function areCompatibleNodes(client, ssr, vnode, renderer) {
7268
7472
  if (!hasCorrectNodeType(vnode, ssr, 1 /* EnvNodeTypes.ELEMENT */, renderer)) {
7269
7473
  return false;
7270
7474
  }
7475
+ const { owner, parts } = vnode;
7271
7476
  let isCompatibleElements = true;
7272
7477
  if (getProperty(client, 'tagName') !== getProperty(ssr, 'tagName')) {
7273
7478
  if (process.env.NODE_ENV !== 'production') {
7274
- logError(`Hydration mismatch: expecting element with tag "${getProperty(client, 'tagName').toLowerCase()}" but found "${getProperty(ssr, 'tagName').toLowerCase()}".`, vnode.owner);
7479
+ logError(`Hydration mismatch: expecting element with tag "${getProperty(client, 'tagName').toLowerCase()}" but found "${getProperty(ssr, 'tagName').toLowerCase()}".`, owner);
7275
7480
  }
7276
7481
  return false;
7277
7482
  }
7278
7483
  const clientAttrsNames = getProperty(client, 'getAttributeNames').call(client);
7279
7484
  clientAttrsNames.forEach((attrName) => {
7280
7485
  if (getAttribute(client, attrName) !== getAttribute(ssr, attrName)) {
7281
- if (process.env.NODE_ENV !== 'production') {
7282
- logError(`Mismatch hydrating element <${getProperty(client, 'tagName').toLowerCase()}>: attribute "${attrName}" has different values, expected "${getAttribute(client, attrName)}" but found "${getAttribute(ssr, attrName)}"`, vnode.owner);
7486
+ // Check if the root element attributes have expressions, if it does then we need to delegate hydration
7487
+ // validation to haveCompatibleStaticParts.
7488
+ // Note if there are no parts then it is a fully static fragment.
7489
+ // partId === 0 will always refer to the root element, this is guaranteed by the compiler.
7490
+ if (parts?.[0].partId !== 0) {
7491
+ if (process.env.NODE_ENV !== 'production') {
7492
+ logError(`Mismatch hydrating element <${getProperty(client, 'tagName').toLowerCase()}>: attribute "${attrName}" has different values, expected "${getAttribute(client, attrName)}" but found "${getAttribute(ssr, attrName)}"`, owner);
7493
+ }
7494
+ isCompatibleElements = false;
7283
7495
  }
7284
- isCompatibleElements = false;
7285
7496
  }
7286
7497
  });
7287
7498
  return isCompatibleElements;
7288
7499
  }
7500
+ function haveCompatibleStaticParts(vnode, renderer) {
7501
+ const { parts, owner } = vnode;
7502
+ if (isUndefined$1(parts)) {
7503
+ return true;
7504
+ }
7505
+ // The validation here relies on 2 key invariants:
7506
+ // 1. It's never the case that `parts` is undefined on the server but defined on the client (or vice-versa)
7507
+ // 2. It's never the case that `parts` has one length on the server but another on the client
7508
+ for (const part of parts) {
7509
+ const { elm } = part;
7510
+ if (isVStaticPartElement(part)) {
7511
+ if (!hasCorrectNodeType(vnode, elm, 1 /* EnvNodeTypes.ELEMENT */, renderer)) {
7512
+ return false;
7513
+ }
7514
+ const { data } = part;
7515
+ const hasMatchingAttrs = validateAttrs(vnode, elm, data, renderer, () => true);
7516
+ const hasMatchingStyleAttr = validateStyleAttr(vnode, elm, data, renderer);
7517
+ const hasMatchingClass = validateClassAttr(vnode, elm, data, renderer);
7518
+ if (isFalse(hasMatchingAttrs && hasMatchingStyleAttr && hasMatchingClass)) {
7519
+ return false;
7520
+ }
7521
+ }
7522
+ else {
7523
+ // VStaticPartText
7524
+ if (!hasCorrectNodeType(vnode, elm, 3 /* EnvNodeTypes.TEXT */, renderer)) {
7525
+ return false;
7526
+ }
7527
+ updateTextContent(elm, part, owner, renderer);
7528
+ }
7529
+ }
7530
+ return true;
7531
+ }
7289
7532
 
7290
7533
  /*
7291
7534
  * Copyright (c) 2018, salesforce.com, inc.
@@ -7557,5 +7800,5 @@ function readonly(obj) {
7557
7800
  }
7558
7801
 
7559
7802
  export { LightningElement, profilerControl as __unstable__ProfilerControl, reportingControl as __unstable__ReportingControl, api$1 as api, computeShadowAndRenderMode, connectRootElement, createContextProviderWithRegister, createVM, disconnectRootElement, freezeTemplate, getAssociatedVMIfPresent, getComponentAPIVersion, getComponentConstructor, getComponentDef, getComponentHtmlPrototype, hydrateRoot, isComponentConstructor, parseFragment, parseSVGFragment, readonly, registerComponent, registerDecorators, registerTemplate, runFormAssociatedCallback, runFormDisabledCallback, runFormResetCallback, runFormStateRestoreCallback, sanitizeAttribute, setHooks, shouldBeFormAssociated, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
7560
- /** version: 6.3.3 */
7803
+ /** version: 6.4.0 */
7561
7804
  //# sourceMappingURL=index.js.map