@lwc/engine-core 6.2.1 → 6.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,13 +23,14 @@ export interface LightningElementConstructor {
23
23
  }
24
24
  type HTMLElementTheGoodParts = {
25
25
  toString: () => string;
26
- } & Pick<HTMLElement, 'accessKey' | 'addEventListener' | 'attachInternals' | 'children' | 'childNodes' | 'classList' | 'dir' | 'dispatchEvent' | 'draggable' | 'firstChild' | 'firstElementChild' | 'getAttribute' | 'getAttributeNS' | 'getBoundingClientRect' | 'getElementsByClassName' | 'getElementsByTagName' | 'hasAttribute' | 'hasAttributeNS' | 'hidden' | 'id' | 'isConnected' | 'lang' | 'lastChild' | 'lastElementChild' | 'ownerDocument' | 'querySelector' | 'querySelectorAll' | 'removeAttribute' | 'removeAttributeNS' | 'removeEventListener' | 'setAttribute' | 'setAttributeNS' | 'spellcheck' | 'tabIndex' | 'tagName' | 'title'>;
26
+ } & Pick<HTMLElement, 'accessKey' | 'addEventListener' | 'attachInternals' | 'children' | 'childNodes' | 'classList' | 'dir' | 'dispatchEvent' | 'draggable' | 'firstChild' | 'firstElementChild' | 'getAttribute' | 'getAttributeNS' | 'getBoundingClientRect' | 'getElementsByClassName' | 'getElementsByTagName' | 'hasAttribute' | 'hasAttributeNS' | 'hidden' | 'id' | 'isConnected' | 'lang' | 'lastChild' | 'lastElementChild' | 'ownerDocument' | 'querySelector' | 'querySelectorAll' | 'removeAttribute' | 'removeAttributeNS' | 'removeEventListener' | 'setAttribute' | 'setAttributeNS' | 'shadowRoot' | 'spellcheck' | 'tabIndex' | 'tagName' | 'title'>;
27
27
  type RefNodes = {
28
28
  [name: string]: Element;
29
29
  };
30
30
  export interface LightningElement extends HTMLElementTheGoodParts, AccessibleElementProperties {
31
+ constructor: LightningElementConstructor;
31
32
  template: ShadowRoot | null;
32
- refs: RefNodes;
33
+ refs: RefNodes | undefined;
33
34
  render(): Template;
34
35
  connectedCallback?(): void;
35
36
  disconnectedCallback?(): void;
@@ -42,8 +42,8 @@ export interface RendererAPI {
42
42
  isConnected: (node: N) => boolean;
43
43
  insertStylesheet: (content: string, target?: ShadowRoot) => void;
44
44
  assertInstanceOfHTMLElement: (elm: any, msg: string) => void;
45
- createCustomElement: (tagName: string, upgradeCallback: LifecycleCallback, useNativeLifecycle: boolean) => E;
46
- defineCustomElement: (tagName: string) => void;
45
+ createCustomElement: (tagName: string, upgradeCallback: LifecycleCallback, useNativeLifecycle: boolean, isFormAssociated: boolean) => E;
46
+ defineCustomElement: (tagName: string, isFormAssociated: boolean) => void;
47
47
  ownerDocument(elm: E): Document;
48
48
  registerContextConsumer: (element: E, adapterContextToken: string, subscriptionPayload: WireContextSubscriptionPayload) => void;
49
49
  attachInternals: (elm: E) => ElementInternals;
package/dist/index.cjs.js CHANGED
@@ -132,7 +132,7 @@ function addErrorComponentStack(vm, error) {
132
132
  }
133
133
 
134
134
  /*
135
- * Copyright (c) 2018, salesforce.com, inc.
135
+ * Copyright (c) 2024, Salesforce, Inc.
136
136
  * All rights reserved.
137
137
  * SPDX-License-Identifier: MIT
138
138
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
@@ -140,7 +140,6 @@ function addErrorComponentStack(vm, error) {
140
140
  const alreadyLoggedMessages = new Set();
141
141
  // Only used in LWC's Karma tests
142
142
  if (process.env.NODE_ENV === 'test-karma-lwc') {
143
- // @ts-ignore
144
143
  window.__lwcResetAlreadyLoggedMessages = () => {
145
144
  alreadyLoggedMessages.clear();
146
145
  };
@@ -798,7 +797,7 @@ function getShadowRootRestrictionsDescriptors(sr) {
798
797
  logError('The `addEventListener` method on ShadowRoot does not support any options.', getAssociatedVMIfPresent(this));
799
798
  }
800
799
  // Typescript does not like it when you treat the `arguments` object as an array
801
- // @ts-ignore type-mismatch
800
+ // @ts-expect-error type-mismatch
802
801
  return originalAddEventListener.apply(this, arguments);
803
802
  },
804
803
  }),
@@ -847,7 +846,7 @@ function getCustomElementRestrictionsDescriptors(elm) {
847
846
  logError('The `addEventListener` method in `LightningElement` does not support any options.', getAssociatedVMIfPresent(this));
848
847
  }
849
848
  // Typescript does not like it when you treat the `arguments` object as an array
850
- // @ts-ignore type-mismatch
849
+ // @ts-expect-error type-mismatch
851
850
  return originalAddEventListener.apply(this, arguments);
852
851
  },
853
852
  }),
@@ -1599,7 +1598,7 @@ const refsCache = new WeakMap();
1599
1598
  * This class is the base class for any LWC element.
1600
1599
  * Some elements directly extends this class, others implement it via inheritance.
1601
1600
  */
1602
- // @ts-ignore
1601
+ // @ts-expect-error When exported, it will conform, but we need to build it first!
1603
1602
  const LightningElement = function () {
1604
1603
  // This should be as performant as possible, while any initialization should be done lazily
1605
1604
  if (shared.isNull(vmBeingConstructed)) {
@@ -1668,80 +1667,7 @@ function warnIfInvokedDuringConstruction(vm, methodOrPropName) {
1668
1667
  logError(`this.${methodOrPropName} should not be called during the construction of the custom element for ${getComponentTag(vm)} because the element is not yet in the DOM or has no children yet.`);
1669
1668
  }
1670
1669
  }
1671
- // List of properties on ElementInternals that are formAssociated can be found in the spec:
1672
- // https://html.spec.whatwg.org/multipage/custom-elements.html#form-associated-custom-elements
1673
- const formAssociatedProps = new Set([
1674
- 'setFormValue',
1675
- 'form',
1676
- 'setValidity',
1677
- 'willValidate',
1678
- 'validity',
1679
- 'validationMessage',
1680
- 'checkValidity',
1681
- 'reportValidity',
1682
- 'labels',
1683
- ]);
1684
- // Verify that access to a form-associated property of the ElementInternals proxy has formAssociated set in the LWC.
1685
- function verifyPropForFormAssociation(propertyKey, isFormAssociated) {
1686
- if (shared.isString(propertyKey) && formAssociatedProps.has(propertyKey) && !isFormAssociated) {
1687
- //Note this error message mirrors Chrome and Firefox error messages, in Safari the error is slightly different.
1688
- throw new DOMException(`Failed to execute '${propertyKey}' on 'ElementInternals': The target element is not a form-associated custom element.`);
1689
- }
1690
- }
1691
- const elementInternalsAccessorAllowList = new Set(['shadowRoot', 'role', ...formAssociatedProps]);
1692
- // Prevent access to properties not defined in the HTML spec in case browsers decide to
1693
- // provide new APIs that provide access to form associated properties.
1694
- // This can be removed along with UpgradeableConstructor.
1695
- function isAllowedElementInternalAccessor(propertyKey) {
1696
- let isAllowedAccessor = false;
1697
- // As of this writing all ElementInternal property keys as described in the spec are implemented with strings
1698
- // in Chrome, Firefox, and Safari
1699
- if (shared.isString(propertyKey)) {
1700
- // Allow list is based on HTML spec:
1701
- // https://html.spec.whatwg.org/multipage/custom-elements.html#the-elementinternals-interface
1702
- isAllowedAccessor =
1703
- elementInternalsAccessorAllowList.has(propertyKey) || /^aria/.test(propertyKey);
1704
- if (!isAllowedAccessor && process.env.NODE_ENV !== 'production') {
1705
- logWarn('Only properties defined in the ElementInternals HTML spec are available.');
1706
- }
1707
- }
1708
- return isAllowedAccessor;
1709
- }
1710
- // Wrap all ElementInternal objects in a proxy to prevent form association when `formAssociated` is not set on an LWC.
1711
- // This is needed because the 1UpgradeableConstructor1 always sets `formAssociated=true`, which means all
1712
- // ElementInternal objects will have form-associated properties set when an LWC is placed in a form.
1713
- // We are doing this to guard against customers taking a dependency on form elements being associated to ElementInternals
1714
- // when 'formAssociated' has not been set on the LWC.
1715
- function createElementInternalsProxy(elementInternals, isFormAssociated) {
1716
- const elementInternalsProxy = new Proxy(elementInternals, {
1717
- set(target, propertyKey, newValue) {
1718
- if (isAllowedElementInternalAccessor(propertyKey)) {
1719
- // Verify that formAssociated is set for form associated properties
1720
- verifyPropForFormAssociation(propertyKey, isFormAssociated);
1721
- return Reflect.set(target, propertyKey, newValue);
1722
- }
1723
- // As of this writing ElementInternals do not have non-string properties that can be set.
1724
- return false;
1725
- },
1726
- get(target, propertyKey) {
1727
- if (
1728
- // Pass through Object.prototype methods such as toString()
1729
- shared.hasOwnProperty.call(Object.prototype, propertyKey) ||
1730
- // As of this writing, ElementInternals only uses Symbol.toStringTag which is called
1731
- // on Object.hasOwnProperty invocations
1732
- Symbol.for('Symbol.toStringTag') === propertyKey ||
1733
- // ElementInternals allow listed properties
1734
- isAllowedElementInternalAccessor(propertyKey)) {
1735
- // Verify that formAssociated is set for form associated properties
1736
- verifyPropForFormAssociation(propertyKey, isFormAssociated);
1737
- const propertyValue = Reflect.get(target, propertyKey);
1738
- return shared.isFunction(propertyValue) ? propertyValue.bind(target) : propertyValue;
1739
- }
1740
- },
1741
- });
1742
- return elementInternalsProxy;
1743
- }
1744
- // @ts-ignore
1670
+ // Type assertion because we need to build the prototype before it satisfies the interface.
1745
1671
  LightningElement.prototype = {
1746
1672
  constructor: LightningElement,
1747
1673
  dispatchEvent(event) {
@@ -1834,13 +1760,14 @@ LightningElement.prototype = {
1834
1760
  },
1835
1761
  attachInternals() {
1836
1762
  const vm = getAssociatedVM(this);
1837
- const { elm, def: { formAssociated }, renderer: { attachInternals }, } = vm;
1763
+ const { elm, apiVersion, renderer: { attachInternals }, } = vm;
1764
+ if (!shared.isAPIFeatureEnabled(8 /* APIFeature.ENABLE_ELEMENT_INTERNALS */, apiVersion)) {
1765
+ throw new Error(`The attachInternals API is only supported in API version 61 and above. To use this API please update the LWC component API version.`);
1766
+ }
1838
1767
  if (vm.shadowMode === 1 /* ShadowMode.Synthetic */) {
1839
- throw new Error('attachInternals API is not supported in light DOM or synthetic shadow.');
1768
+ throw new Error('attachInternals API is not supported in synthetic shadow.');
1840
1769
  }
1841
- const internals = attachInternals(elm);
1842
- // #TODO[2970]: remove proxy once `UpgradeableConstructor` has been removed
1843
- return createElementInternalsProxy(internals, Boolean(formAssociated));
1770
+ return attachInternals(elm);
1844
1771
  },
1845
1772
  get isConnected() {
1846
1773
  const vm = getAssociatedVM(this);
@@ -1943,6 +1870,9 @@ LightningElement.prototype = {
1943
1870
  if (process.env.NODE_ENV !== 'production') {
1944
1871
  warnIfInvokedDuringConstruction(vm, 'childNodes');
1945
1872
  }
1873
+ // getChildNodes returns a NodeList, which has `item(index: number): Node | null`.
1874
+ // NodeListOf<T> extends NodeList, but claims to not return null. That seems inaccurate,
1875
+ // but these are built-in types, so ultimately not our problem.
1946
1876
  return renderer.getChildNodes(vm.elm);
1947
1877
  },
1948
1878
  get firstChild() {
@@ -2182,7 +2112,7 @@ function createConfigWatcher(component, configCallback, callbackWhenConfigIsRead
2182
2112
  ro.observe(() => (config = configCallback(component)));
2183
2113
  // eslint-disable-next-line @lwc/lwc-internal/no-invalid-todo
2184
2114
  // TODO: dev-mode validation of config based on the adapter.configSchema
2185
- // @ts-ignore it is assigned in the observe() callback
2115
+ // @ts-expect-error it is assigned in the observe() callback
2186
2116
  callbackWhenConfigIsReady(config);
2187
2117
  };
2188
2118
  return {
@@ -2258,7 +2188,7 @@ function createConnector(vm, name, wireDef) {
2258
2188
  });
2259
2189
  }
2260
2190
  return {
2261
- // @ts-ignore the boundary protection executes sync, connector is always defined
2191
+ // @ts-expect-error the boundary protection executes sync, connector is always defined
2262
2192
  connector,
2263
2193
  computeConfigAndUpdate,
2264
2194
  resetConfigWatcher: () => ro.reset(),
@@ -2737,7 +2667,6 @@ function getDecoratorsMeta(Ctor) {
2737
2667
  let warned = false;
2738
2668
  // Only used in LWC's Karma tests
2739
2669
  if (process.env.NODE_ENV === 'test-karma-lwc') {
2740
- // @ts-ignore
2741
2670
  window.__lwcResetWarnedOnVersionMismatch = () => {
2742
2671
  warned = false;
2743
2672
  };
@@ -2855,7 +2784,7 @@ function createAttributeChangedCallback(attributeToPropMap, superAttributeChange
2855
2784
  if (!shared.isUndefined(superAttributeChangedCallback)) {
2856
2785
  // delegate unknown attributes to the super.
2857
2786
  // Typescript does not like it when you treat the `arguments` object as an array
2858
- // @ts-ignore type-mismatch
2787
+ // @ts-expect-error type-mismatch
2859
2788
  superAttributeChangedCallback.apply(this, arguments);
2860
2789
  }
2861
2790
  return;
@@ -4312,7 +4241,8 @@ function mountCustomElement(vnode, parent, anchor, renderer) {
4312
4241
  // compatibility, we lower case the tagname here.
4313
4242
  const normalizedTagname = sel.toLowerCase();
4314
4243
  const useNativeLifecycle = shouldUseNativeCustomElementLifecycle(ctor);
4315
- const elm = createCustomElement(normalizedTagname, upgradeCallback, useNativeLifecycle);
4244
+ const isFormAssociated = Boolean(ctor.formAssociated);
4245
+ const elm = createCustomElement(normalizedTagname, upgradeCallback, useNativeLifecycle, isFormAssociated);
4316
4246
  vnode.elm = elm;
4317
4247
  vnode.vm = vm;
4318
4248
  linkNodeToShadow(elm, owner, renderer);
@@ -5608,9 +5538,27 @@ function validateLightDomTemplate(template, vm) {
5608
5538
  }
5609
5539
  }
5610
5540
  }
5541
+ // This should be a no-op outside of LWC's Karma tests, where it's not needed
5542
+ let registerFragmentCache = shared.noop;
5543
+ // Only used in LWC's Karma tests
5544
+ if (process.env.NODE_ENV === 'test-karma-lwc') {
5545
+ // Keep track of fragmentCaches, so we can clear them in LWC's Karma tests
5546
+ const fragmentCaches = [];
5547
+ registerFragmentCache = (fragmentCache) => {
5548
+ fragmentCaches.push(fragmentCache);
5549
+ };
5550
+ window.__lwcResetFragmentCaches = () => {
5551
+ for (const fragmentCache of fragmentCaches) {
5552
+ for (const key of shared.keys(fragmentCache)) {
5553
+ delete fragmentCache[key];
5554
+ }
5555
+ }
5556
+ };
5557
+ }
5611
5558
  function buildParseFragmentFn(createFragmentFn) {
5612
5559
  return (strings, ...keys) => {
5613
5560
  const cache = shared.create(null);
5561
+ registerFragmentCache(cache);
5614
5562
  return function () {
5615
5563
  const { context: { hasScopedStyles, stylesheetToken, legacyStylesheetToken }, shadowMode, renderer, } = getVMBeingRendered();
5616
5564
  const hasStyleToken = !shared.isUndefined(stylesheetToken);
@@ -5623,11 +5571,6 @@ function buildParseFragmentFn(createFragmentFn) {
5623
5571
  if (hasStyleToken && isSyntheticShadow) {
5624
5572
  cacheKey |= 2 /* FragmentCache.SHADOW_MODE_SYNTHETIC */;
5625
5573
  }
5626
- if (hasLegacyToken) {
5627
- // This isn't strictly required for prod, but it's required for our karma tests
5628
- // since the lwcRuntimeFlag may change over time
5629
- cacheKey |= 4 /* FragmentCache.HAS_LEGACY_SCOPE_TOKEN */;
5630
- }
5631
5574
  if (!shared.isUndefined(cache[cacheKey])) {
5632
5575
  return cache[cacheKey];
5633
5576
  }
@@ -6535,14 +6478,7 @@ function forceRehydration(vm) {
6535
6478
  }
6536
6479
  }
6537
6480
  function runFormAssociatedCustomElementCallback(vm, faceCb) {
6538
- const { renderMode, shadowMode, def: { formAssociated }, } = vm;
6539
- // Technically the UpgradableConstructor always sets `static formAssociated = true` but silently fail here to match browser behavior.
6540
- if (shared.isUndefined(formAssociated) || shared.isFalse(formAssociated)) {
6541
- if (process.env.NODE_ENV !== 'production') {
6542
- logWarn(`Form associated lifecycle methods must have the 'static formAssociated' value set in the component's prototype chain.`);
6543
- }
6544
- return;
6545
- }
6481
+ const { renderMode, shadowMode } = vm;
6546
6482
  if (shadowMode === 1 /* ShadowMode.Synthetic */ && renderMode !== 0 /* RenderMode.Light */) {
6547
6483
  throw new Error('Form associated lifecycle methods are not available in synthetic shadow. Please use native shadow or light DOM.');
6548
6484
  }
@@ -6817,7 +6753,6 @@ function enableDetection() {
6817
6753
  throw new Error('detect-non-standard-aria.ts loaded before @lwc/aria-reflection');
6818
6754
  }
6819
6755
  }
6820
- // @ts-ignore
6821
6756
  const { get, set } = descriptor;
6822
6757
  // It's important for this defineProperty call to happen _after_ ARIA accessors are applied to the
6823
6758
  // BaseBridgeElement and LightningElement prototypes. Otherwise, we will log/report for access of non-standard
@@ -7036,7 +6971,7 @@ function hydrateCustomElement(elm, vnode, renderer) {
7036
6971
  }
7037
6972
  const { sel, mode, ctor, owner } = vnode;
7038
6973
  const { defineCustomElement, getTagName } = renderer;
7039
- defineCustomElement(shared.StringToLowerCase.call(getTagName(elm)));
6974
+ defineCustomElement(shared.StringToLowerCase.call(getTagName(elm)), Boolean(ctor.formAssociated));
7040
6975
  const vm = createVM(elm, ctor, renderer, {
7041
6976
  mode,
7042
6977
  owner,
@@ -7428,7 +7363,7 @@ function warnOnArrayMutation(stylesheets) {
7428
7363
  const originalArrayMethod = getOriginalArrayMethod(prop);
7429
7364
  stylesheets[prop] = function arrayMutationWarningWrapper() {
7430
7365
  reportTemplateViolation('stylesheets');
7431
- // @ts-ignore
7366
+ // @ts-expect-error can't properly determine the right `this`
7432
7367
  return originalArrayMethod.apply(this, arguments);
7433
7368
  };
7434
7369
  }
@@ -7656,5 +7591,5 @@ exports.swapTemplate = swapTemplate;
7656
7591
  exports.track = track;
7657
7592
  exports.unwrap = unwrap;
7658
7593
  exports.wire = wire;
7659
- /** version: 6.2.1 */
7594
+ /** version: 6.3.1 */
7660
7595
  //# sourceMappingURL=index.cjs.js.map