@lwc/engine-core 2.38.1 → 2.39.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.
@@ -2746,6 +2746,93 @@ if (process.env.IS_BROWSER) {
2746
2746
  freeze(BaseBridgeElement);
2747
2747
  seal(BaseBridgeElement.prototype);
2748
2748
 
2749
+ /*
2750
+ * Copyright (c) 2023, salesforce.com, inc.
2751
+ * All rights reserved.
2752
+ * SPDX-License-Identifier: MIT
2753
+ * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
2754
+ */
2755
+ const supportsWeakRefs = typeof WeakRef === 'function' && typeof FinalizationRegistry === 'function';
2756
+ // In browsers that doesn't support WeakRefs, the values will still leak, but at least the keys won't
2757
+ class LegacyWeakMultiMap {
2758
+ constructor() {
2759
+ this._map = new WeakMap();
2760
+ }
2761
+ _getValues(key) {
2762
+ let values = this._map.get(key);
2763
+ if (isUndefined$1(values)) {
2764
+ values = new Set();
2765
+ this._map.set(key, values);
2766
+ }
2767
+ return values;
2768
+ }
2769
+ get(key) {
2770
+ return this._getValues(key);
2771
+ }
2772
+ add(key, vm) {
2773
+ const set = this._getValues(key);
2774
+ set.add(vm);
2775
+ }
2776
+ delete(key) {
2777
+ this._map.delete(key);
2778
+ }
2779
+ }
2780
+ // This implementation relies on the WeakRef/FinalizationRegistry proposal.
2781
+ // For some background, see: https://github.com/tc39/proposal-weakrefs
2782
+ class ModernWeakMultiMap {
2783
+ constructor() {
2784
+ this._map = new WeakMap();
2785
+ this._registry = new FinalizationRegistry((weakRefs) => {
2786
+ // This should be considered an optional cleanup method to remove GC'ed values from their respective arrays.
2787
+ // JS VMs are not obligated to call FinalizationRegistry callbacks.
2788
+ // Work backwards, removing stale VMs
2789
+ for (let i = weakRefs.length - 1; i >= 0; i--) {
2790
+ const vm = weakRefs[i].deref();
2791
+ if (isUndefined$1(vm)) {
2792
+ ArraySplice.call(weakRefs, i, 1); // remove
2793
+ }
2794
+ }
2795
+ });
2796
+ }
2797
+ _getWeakRefs(key) {
2798
+ let weakRefs = this._map.get(key);
2799
+ if (isUndefined$1(weakRefs)) {
2800
+ weakRefs = [];
2801
+ this._map.set(key, weakRefs);
2802
+ }
2803
+ return weakRefs;
2804
+ }
2805
+ get(key) {
2806
+ const weakRefs = this._getWeakRefs(key);
2807
+ const result = new Set();
2808
+ for (const weakRef of weakRefs) {
2809
+ const vm = weakRef.deref();
2810
+ if (!isUndefined$1(vm)) {
2811
+ result.add(vm);
2812
+ }
2813
+ }
2814
+ return result;
2815
+ }
2816
+ add(key, value) {
2817
+ const weakRefs = this._getWeakRefs(key);
2818
+ // We could check for duplicate values here, but it doesn't seem worth it.
2819
+ // We transform the output into a Set anyway
2820
+ ArrayPush$1.call(weakRefs, new WeakRef(value));
2821
+ // It's important here not to leak the second argument, which is the "held value." The FinalizationRegistry
2822
+ // effectively creates a strong reference between the first argument (the "target") and the held value. When
2823
+ // the target is GC'ed, the callback is called, and then the held value is GC'ed.
2824
+ // Putting the key here would mean the key is not GC'ed until the value is GC'ed, which defeats the purpose
2825
+ // of the WeakMap. Whereas putting the weakRefs array here is fine, because it doesn't have a strong reference
2826
+ // to anything. See also this example:
2827
+ // https://gist.github.com/nolanlawson/79a3d36e8e6cc25c5048bb17c1795aea
2828
+ this._registry.register(value, weakRefs);
2829
+ }
2830
+ delete(key) {
2831
+ this._map.delete(key);
2832
+ }
2833
+ }
2834
+ const WeakMultiMap = supportsWeakRefs ? ModernWeakMultiMap : LegacyWeakMultiMap;
2835
+
2749
2836
  /*
2750
2837
  * Copyright (c) 2020, salesforce.com, inc.
2751
2838
  * All rights reserved.
@@ -2755,67 +2842,62 @@ seal(BaseBridgeElement.prototype);
2755
2842
  const swappedTemplateMap = new WeakMap();
2756
2843
  const swappedComponentMap = new WeakMap();
2757
2844
  const swappedStyleMap = new WeakMap();
2758
- const activeTemplates = new WeakMap();
2759
- const activeComponents = new WeakMap();
2760
- const activeStyles = new WeakMap();
2845
+ // The important thing here is the weak values – VMs are transient (one per component instance) and should be GC'ed,
2846
+ // so we don't want to create strong references to them.
2847
+ // The weak keys are kind of useless, because Templates, LightningElementConstructors, and StylesheetFactories are
2848
+ // never GC'ed. But maybe they will be someday, so we may as well use weak keys too.
2849
+ const activeTemplates = new WeakMultiMap();
2850
+ const activeComponents = new WeakMultiMap();
2851
+ const activeStyles = new WeakMultiMap();
2761
2852
  function rehydrateHotTemplate(tpl) {
2762
2853
  const list = activeTemplates.get(tpl);
2763
- if (!isUndefined$1(list)) {
2764
- list.forEach((vm) => {
2765
- if (isFalse(vm.isDirty)) {
2766
- // forcing the vm to rehydrate in the micro-task:
2767
- markComponentAsDirty(vm);
2768
- scheduleRehydration(vm);
2769
- }
2770
- });
2771
- // resetting the Set to release the memory of those vm references
2772
- // since they are not longer related to this template, instead
2773
- // they will get re-associated once these instances are rehydrated.
2774
- list.clear();
2854
+ for (const vm of list) {
2855
+ if (isFalse(vm.isDirty)) {
2856
+ // forcing the vm to rehydrate in the micro-task:
2857
+ markComponentAsDirty(vm);
2858
+ scheduleRehydration(vm);
2859
+ }
2775
2860
  }
2861
+ // Resetting the Set since these VMs are no longer related to this template, instead
2862
+ // they will get re-associated once these instances are rehydrated.
2863
+ activeTemplates.delete(tpl);
2776
2864
  return true;
2777
2865
  }
2778
2866
  function rehydrateHotStyle(style) {
2779
2867
  const list = activeStyles.get(style);
2780
- if (!isUndefined$1(list)) {
2781
- list.forEach((vm) => {
2782
- // if a style definition is swapped, we must reset
2783
- // vm's template content in the next micro-task:
2784
- forceRehydration(vm);
2785
- });
2786
- // resetting the Set to release the memory of those vm references
2787
- // since they are not longer related to this style, instead
2788
- // they will get re-associated once these instances are rehydrated.
2789
- list.clear();
2790
- }
2868
+ for (const vm of list) {
2869
+ // if a style definition is swapped, we must reset
2870
+ // vm's template content in the next micro-task:
2871
+ forceRehydration(vm);
2872
+ }
2873
+ // Resetting the Set since these VMs are no longer related to this style, instead
2874
+ // they will get re-associated once these instances are rehydrated.
2875
+ activeStyles.delete(style);
2791
2876
  return true;
2792
2877
  }
2793
2878
  function rehydrateHotComponent(Ctor) {
2794
2879
  const list = activeComponents.get(Ctor);
2795
2880
  let canRefreshAllInstances = true;
2796
- if (!isUndefined$1(list)) {
2797
- list.forEach((vm) => {
2798
- const { owner } = vm;
2799
- if (!isNull(owner)) {
2800
- // if a component class definition is swapped, we must reset
2801
- // owner's template content in the next micro-task:
2802
- forceRehydration(owner);
2803
- }
2804
- else {
2805
- // the hot swapping for components only work for instances of components
2806
- // created from a template, root elements can't be swapped because we
2807
- // don't have a way to force the creation of the element with the same state
2808
- // of the current element.
2809
- // Instead, we can report the problem to the caller so it can take action,
2810
- // for example: reload the entire page.
2811
- canRefreshAllInstances = false;
2812
- }
2813
- });
2814
- // resetting the Set to release the memory of those vm references
2815
- // since they are not longer related to this constructor, instead
2816
- // they will get re-associated once these instances are rehydrated.
2817
- list.clear();
2818
- }
2881
+ for (const vm of list) {
2882
+ const { owner } = vm;
2883
+ if (!isNull(owner)) {
2884
+ // if a component class definition is swapped, we must reset
2885
+ // owner's template content in the next micro-task:
2886
+ forceRehydration(owner);
2887
+ }
2888
+ else {
2889
+ // the hot swapping for components only work for instances of components
2890
+ // created from a template, root elements can't be swapped because we
2891
+ // don't have a way to force the creation of the element with the same state
2892
+ // of the current element.
2893
+ // Instead, we can report the problem to the caller so it can take action,
2894
+ // for example: reload the entire page.
2895
+ canRefreshAllInstances = false;
2896
+ }
2897
+ }
2898
+ // resetting the Set since these VMs are no longer related to this constructor, instead
2899
+ // they will get re-associated once these instances are rehydrated.
2900
+ activeComponents.delete(Ctor);
2819
2901
  return canRefreshAllInstances;
2820
2902
  }
2821
2903
  function getTemplateOrSwappedTemplate(tpl) {
@@ -2849,72 +2931,27 @@ function setActiveVM(vm) {
2849
2931
  assertNotProd(); // this method should never leak to prod
2850
2932
  // tracking active component
2851
2933
  const Ctor = vm.def.ctor;
2852
- let componentVMs = activeComponents.get(Ctor);
2853
- if (isUndefined$1(componentVMs)) {
2854
- componentVMs = new Set();
2855
- activeComponents.set(Ctor, componentVMs);
2856
- }
2857
2934
  // this will allow us to keep track of the hot components
2858
- componentVMs.add(vm);
2935
+ activeComponents.add(Ctor, vm);
2859
2936
  // tracking active template
2860
2937
  const tpl = vm.cmpTemplate;
2861
2938
  if (tpl) {
2862
- let templateVMs = activeTemplates.get(tpl);
2863
- if (isUndefined$1(templateVMs)) {
2864
- templateVMs = new Set();
2865
- activeTemplates.set(tpl, templateVMs);
2866
- }
2867
2939
  // this will allow us to keep track of the templates that are
2868
2940
  // being used by a hot component
2869
- templateVMs.add(vm);
2941
+ activeTemplates.add(tpl, vm);
2870
2942
  // tracking active styles associated to template
2871
2943
  const stylesheets = tpl.stylesheets;
2872
2944
  if (!isUndefined$1(stylesheets)) {
2873
- flattenStylesheets(stylesheets).forEach((stylesheet) => {
2945
+ for (const stylesheet of flattenStylesheets(stylesheets)) {
2874
2946
  // this is necessary because we don't hold the list of styles
2875
2947
  // in the vm, we only hold the selected (already swapped template)
2876
2948
  // but the styles attached to the template might not be the actual
2877
2949
  // active ones, but the swapped versions of those.
2878
- stylesheet = getStyleOrSwappedStyle(stylesheet);
2879
- let stylesheetVMs = activeStyles.get(stylesheet);
2880
- if (isUndefined$1(stylesheetVMs)) {
2881
- stylesheetVMs = new Set();
2882
- activeStyles.set(stylesheet, stylesheetVMs);
2883
- }
2950
+ const swappedStylesheet = getStyleOrSwappedStyle(stylesheet);
2884
2951
  // this will allow us to keep track of the stylesheet that are
2885
2952
  // being used by a hot component
2886
- stylesheetVMs.add(vm);
2887
- });
2888
- }
2889
- }
2890
- }
2891
- function removeActiveVM(vm) {
2892
- assertNotProd(); // this method should never leak to prod
2893
- // tracking inactive component
2894
- const Ctor = vm.def.ctor;
2895
- let list = activeComponents.get(Ctor);
2896
- if (!isUndefined$1(list)) {
2897
- // deleting the vm from the set to avoid leaking memory
2898
- list.delete(vm);
2899
- }
2900
- // removing inactive template
2901
- const tpl = vm.cmpTemplate;
2902
- if (tpl) {
2903
- list = activeTemplates.get(tpl);
2904
- if (!isUndefined$1(list)) {
2905
- // deleting the vm from the set to avoid leaking memory
2906
- list.delete(vm);
2907
- }
2908
- // removing active styles associated to template
2909
- const styles = tpl.stylesheets;
2910
- if (!isUndefined$1(styles)) {
2911
- flattenStylesheets(styles).forEach((style) => {
2912
- list = activeStyles.get(style);
2913
- if (!isUndefined$1(list)) {
2914
- // deleting the vm from the set to avoid leaking memory
2915
- list.delete(vm);
2916
- }
2917
- });
2953
+ activeStyles.add(swappedStylesheet, vm);
2954
+ }
2918
2955
  }
2919
2956
  }
2920
2957
  }
@@ -3676,7 +3713,12 @@ function patch(n1, n2, parent, renderer) {
3676
3713
  return;
3677
3714
  }
3678
3715
  if (process.env.NODE_ENV !== 'production') {
3679
- if (!isSameVnode(n1, n2)) {
3716
+ if (!isSameVnode(n1, n2) &&
3717
+ // Currently the only scenario when patch does not receive the same vnodes are for
3718
+ // dynamic components. When a dynamic component's constructor changes, the value of its
3719
+ // tag name (sel) will be different. The engine will unmount the previous element
3720
+ // and mount the new one using the new constructor in patchCustomElement.
3721
+ !(isVCustomElement(n1) && isVCustomElement(n2))) {
3680
3722
  throw new Error('Expected these VNodes to be the same: ' +
3681
3723
  JSON.stringify({ sel: n1.sel, key: n1.key }) +
3682
3724
  ', ' +
@@ -3874,8 +3916,9 @@ function mountCustomElement(vnode, parent, anchor, renderer) {
3874
3916
  }
3875
3917
  }
3876
3918
  function patchCustomElement(n1, n2, parent, renderer) {
3919
+ // TODO [#3331]: This if branch should be removed in 246 with lwc:dynamic
3877
3920
  if (n1.ctor !== n2.ctor) {
3878
- // If the constructor, unmount the current component and mount a new one using the new
3921
+ // If the constructor differs, unmount the current component and mount a new one using the new
3879
3922
  // constructor.
3880
3923
  const anchor = renderer.nextSibling(n1.elm);
3881
3924
  unmount(n1, parent, renderer, true);
@@ -4368,9 +4411,17 @@ function updateStaticChildren(c1, c2, parent, renderer) {
4368
4411
  if (n2 !== n1) {
4369
4412
  if (isVNode(n1)) {
4370
4413
  if (isVNode(n2)) {
4371
- // both vnodes are equivalent, and we just need to patch them
4372
- patch(n1, n2, parent, renderer);
4373
- anchor = n2.elm;
4414
+ if (isSameVnode(n1, n2)) {
4415
+ // both vnodes are equivalent, and we just need to patch them
4416
+ patch(n1, n2, parent, renderer);
4417
+ anchor = n2.elm;
4418
+ }
4419
+ else {
4420
+ // removing the old vnode since the new one is different
4421
+ unmount(n1, parent, renderer, true);
4422
+ mount(n2, parent, renderer, anchor);
4423
+ anchor = n2.elm;
4424
+ }
4374
4425
  }
4375
4426
  else {
4376
4427
  // removing the old vnode since the new one is null
@@ -4772,16 +4823,18 @@ function fid(url) {
4772
4823
  return url;
4773
4824
  }
4774
4825
  /**
4775
- * create a dynamic component via `<x-foo lwc:dynamic={Ctor}>`
4826
+ * [ddc] - create a (deprecated) dynamic component via `<x-foo lwc:dynamic={Ctor}>`
4827
+ *
4828
+ * TODO [#3331]: remove usage of lwc:dynamic in 246
4776
4829
  */
4777
- function dc(sel, Ctor, data, children = EmptyArray) {
4830
+ function ddc(sel, Ctor, data, children = EmptyArray) {
4778
4831
  if (process.env.NODE_ENV !== 'production') {
4779
4832
  assert.isTrue(isString(sel), `dc() 1st argument sel must be a string.`);
4780
4833
  assert.isTrue(isObject(data), `dc() 3nd argument data must be an object.`);
4781
4834
  assert.isTrue(arguments.length === 3 || isArray$1(children), `dc() 4nd argument data must be an array.`);
4782
4835
  }
4783
4836
  // null or undefined values should produce a null value in the VNodes
4784
- if (Ctor == null) {
4837
+ if (isNull(Ctor) || isUndefined$1(Ctor)) {
4785
4838
  return null;
4786
4839
  }
4787
4840
  if (!isComponentConstructor(Ctor)) {
@@ -4789,6 +4842,30 @@ function dc(sel, Ctor, data, children = EmptyArray) {
4789
4842
  }
4790
4843
  return c(sel, Ctor, data, children);
4791
4844
  }
4845
+ /**
4846
+ * [dc] - create a dynamic component via `<lwc:component lwc:is={Ctor}>`
4847
+ */
4848
+ function dc(Ctor, data, children = EmptyArray) {
4849
+ if (process.env.NODE_ENV !== 'production') {
4850
+ assert.isTrue(isObject(data), `dc() 2nd argument data must be an object.`);
4851
+ assert.isTrue(arguments.length === 3 || isArray$1(children), `dc() 3rd argument data must be an array.`);
4852
+ }
4853
+ // Null or undefined values should produce a null value in the VNodes.
4854
+ // This is the only value at compile time as the constructor will not be known.
4855
+ if (isNull(Ctor) || isUndefined$1(Ctor)) {
4856
+ return null;
4857
+ }
4858
+ if (!isComponentConstructor(Ctor)) {
4859
+ throw new Error(`Invalid constructor ${toString$1(Ctor)} is not a LightningElement constructor.`);
4860
+ }
4861
+ // Look up the dynamic component's name at runtime once the constructor is available.
4862
+ // This information is only known at runtime and is stored as part of registerComponent.
4863
+ const sel = getComponentRegisteredName(Ctor);
4864
+ if (isUndefined$1(sel) || sel === '') {
4865
+ throw new Error(`Invalid LWC constructor ${toString$1(Ctor)} does not have a registered name`);
4866
+ }
4867
+ return c(sel, Ctor, data, children);
4868
+ }
4792
4869
  /**
4793
4870
  * slow children collection marking mechanism. this API allows the compiler to signal
4794
4871
  * to the engine that a particular collection of children must be diffed using the slow
@@ -4851,6 +4928,7 @@ const api = freeze({
4851
4928
  fid,
4852
4929
  shc,
4853
4930
  ssf,
4931
+ ddc,
4854
4932
  });
4855
4933
 
4856
4934
  /*
@@ -5250,28 +5328,34 @@ function invokeEventListener(vm, fn, thisValue, event) {
5250
5328
  * SPDX-License-Identifier: MIT
5251
5329
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
5252
5330
  */
5253
- const signedTemplateMap = new Map();
5331
+ const registeredComponentMap = new Map();
5254
5332
  /**
5255
5333
  * INTERNAL: This function can only be invoked by compiled code. The compiler
5256
5334
  * will prevent this function from being imported by userland code.
5257
5335
  */
5258
5336
  function registerComponent(
5259
5337
  // We typically expect a LightningElementConstructor, but technically you can call this with anything
5260
- Ctor, { tmpl }) {
5338
+ Ctor, metadata) {
5261
5339
  if (isFunction$1(Ctor)) {
5262
5340
  if (process.env.NODE_ENV !== 'production') {
5263
5341
  // There is no point in running this in production, because the version mismatch check relies
5264
5342
  // on code comments which are stripped out in production by minifiers
5265
5343
  checkVersionMismatch(Ctor, 'component');
5266
5344
  }
5267
- signedTemplateMap.set(Ctor, tmpl);
5345
+ // TODO [#3331]: add validation to check the value of metadata.sel is not an empty string.
5346
+ registeredComponentMap.set(Ctor, metadata);
5268
5347
  }
5269
5348
  // chaining this method as a way to wrap existing assignment of component constructor easily,
5270
5349
  // without too much transformation
5271
5350
  return Ctor;
5272
5351
  }
5273
5352
  function getComponentRegisteredTemplate(Ctor) {
5274
- return signedTemplateMap.get(Ctor);
5353
+ var _a;
5354
+ return (_a = registeredComponentMap.get(Ctor)) === null || _a === void 0 ? void 0 : _a.tmpl;
5355
+ }
5356
+ function getComponentRegisteredName(Ctor) {
5357
+ var _a;
5358
+ return (_a = registeredComponentMap.get(Ctor)) === null || _a === void 0 ? void 0 : _a.sel;
5275
5359
  }
5276
5360
  function getTemplateReactiveObserver(vm) {
5277
5361
  return createReactiveObserver(() => {
@@ -5407,9 +5491,6 @@ function resetComponentStateWhenRemoved(vm) {
5407
5491
  runChildNodesDisconnectedCallback(vm);
5408
5492
  runLightChildNodesDisconnectedCallback(vm);
5409
5493
  }
5410
- if (process.env.NODE_ENV !== 'production') {
5411
- removeActiveVM(vm);
5412
- }
5413
5494
  }
5414
5495
  // this method is triggered by the diffing algo only when a vnode from the
5415
5496
  // old vnode.children is removed from the DOM.
@@ -6869,5 +6950,5 @@ function readonly(obj) {
6869
6950
  }
6870
6951
 
6871
6952
  export { LightningElement, profilerControl as __unstable__ProfilerControl, reportingControl as __unstable__ReportingControl, api$1 as api, connectRootElement, createContextProviderWithRegister, createVM, disconnectRootElement, freezeTemplate, getAssociatedVMIfPresent, getComponentConstructor, getComponentDef, getComponentHtmlPrototype, hydrateRoot, isComponentConstructor, parseFragment, parseSVGFragment, readonly, register, registerComponent, registerDecorators, registerTemplate, sanitizeAttribute, setHooks, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
6872
- /* version: 2.38.1 */
6953
+ /* version: 2.39.0 */
6873
6954
  //# sourceMappingURL=engine-core.js.map