@lwc/engine-core 2.32.0 → 2.33.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.
@@ -3,6 +3,7 @@
3
3
 
4
4
  var features = require('@lwc/features');
5
5
  var shared = require('@lwc/shared');
6
+ var ariaReflection = require('@lwc/aria-reflection');
6
7
 
7
8
  /*
8
9
  * Copyright (c) 2018, salesforce.com, inc.
@@ -562,7 +563,7 @@ function patchElementWithRestrictions(elm, options) {
562
563
  }),
563
564
  };
564
565
  // Apply extra restriction related to DOM manipulation if the element is not a portal.
565
- if (!options.isLight && !options.isPortal) {
566
+ if (!options.isLight && options.isSynthetic && !options.isPortal) {
566
567
  const { appendChild, insertBefore, removeChild, replaceChild } = elm;
567
568
  const originalNodeValueDescriptor = shared.getPropertyDescriptor(elm, 'nodeValue');
568
569
  const originalInnerHTMLDescriptor = shared.getPropertyDescriptor(elm, 'innerHTML');
@@ -1410,46 +1411,51 @@ function markLockerLiveObject(obj) {
1410
1411
  * for the Base Lightning Element, it also include the reactivity bit, so the standard property is reactive.
1411
1412
  */
1412
1413
  function createBridgeToElementDescriptor(propName, descriptor) {
1413
- const { get, set, enumerable, configurable } = descriptor;
1414
- if (!shared.isFunction(get)) {
1415
- if (process.env.NODE_ENV !== 'production') {
1416
- shared.assert.fail(`Detected invalid public property descriptor for HTMLElement.prototype.${propName} definition. Missing the standard getter.`);
1417
- }
1418
- throw new TypeError();
1414
+ const {
1415
+ get,
1416
+ set,
1417
+ enumerable,
1418
+ configurable
1419
+ } = descriptor;
1420
+ if (!shared.isFunction(get)) {
1421
+ if (process.env.NODE_ENV !== 'production') {
1422
+ shared.assert.fail(`Detected invalid public property descriptor for HTMLElement.prototype.${propName} definition. Missing the standard getter.`);
1419
1423
  }
1420
- if (!shared.isFunction(set)) {
1424
+ throw new TypeError();
1425
+ }
1426
+ if (!shared.isFunction(set)) {
1427
+ if (process.env.NODE_ENV !== 'production') {
1428
+ shared.assert.fail(`Detected invalid public property descriptor for HTMLElement.prototype.${propName} definition. Missing the standard setter.`);
1429
+ }
1430
+ throw new TypeError();
1431
+ }
1432
+ return {
1433
+ enumerable,
1434
+ configurable,
1435
+ get() {
1436
+ const vm = getAssociatedVM(this);
1437
+ if (isBeingConstructed(vm)) {
1421
1438
  if (process.env.NODE_ENV !== 'production') {
1422
- shared.assert.fail(`Detected invalid public property descriptor for HTMLElement.prototype.${propName} definition. Missing the standard setter.`);
1439
+ logError(`The value of property \`${propName}\` can't be read from the constructor because the owner component hasn't set the value yet. Instead, use the constructor to set a default value for the property.`, vm);
1423
1440
  }
1424
- throw new TypeError();
1441
+ return;
1442
+ }
1443
+ componentValueObserved(vm, propName);
1444
+ return get.call(vm.elm);
1445
+ },
1446
+ set(newValue) {
1447
+ const vm = getAssociatedVM(this);
1448
+ if (process.env.NODE_ENV !== 'production') {
1449
+ const vmBeingRendered = getVMBeingRendered();
1450
+ shared.assert.invariant(!isInvokingRender, `${vmBeingRendered}.render() method has side effects on the state of ${vm}.${propName}`);
1451
+ shared.assert.invariant(!isUpdatingTemplate, `When updating the template of ${vmBeingRendered}, one of the accessors used by the template has side effects on the state of ${vm}.${propName}`);
1452
+ shared.assert.isFalse(isBeingConstructed(vm), `Failed to construct '${getComponentTag(vm)}': The result must not have attributes.`);
1453
+ shared.assert.invariant(!shared.isObject(newValue) || shared.isNull(newValue), `Invalid value "${newValue}" for "${propName}" of ${vm}. Value cannot be an object, must be a primitive value.`);
1454
+ }
1455
+ updateComponentValue(vm, propName, newValue);
1456
+ return set.call(vm.elm, newValue);
1425
1457
  }
1426
- return {
1427
- enumerable,
1428
- configurable,
1429
- get() {
1430
- const vm = getAssociatedVM(this);
1431
- if (isBeingConstructed(vm)) {
1432
- if (process.env.NODE_ENV !== 'production') {
1433
- logError(`The value of property \`${propName}\` can't be read from the constructor because the owner component hasn't set the value yet. Instead, use the constructor to set a default value for the property.`, vm);
1434
- }
1435
- return;
1436
- }
1437
- componentValueObserved(vm, propName);
1438
- return get.call(vm.elm);
1439
- },
1440
- set(newValue) {
1441
- const vm = getAssociatedVM(this);
1442
- if (process.env.NODE_ENV !== 'production') {
1443
- const vmBeingRendered = getVMBeingRendered();
1444
- shared.assert.invariant(!isInvokingRender, `${vmBeingRendered}.render() method has side effects on the state of ${vm}.${propName}`);
1445
- shared.assert.invariant(!isUpdatingTemplate, `When updating the template of ${vmBeingRendered}, one of the accessors used by the template has side effects on the state of ${vm}.${propName}`);
1446
- shared.assert.isFalse(isBeingConstructed(vm), `Failed to construct '${getComponentTag(vm)}': The result must not have attributes.`);
1447
- shared.assert.invariant(!shared.isObject(newValue) || shared.isNull(newValue), `Invalid value "${newValue}" for "${propName}" of ${vm}. Value cannot be an object, must be a primitive value.`);
1448
- }
1449
- updateComponentValue(vm, propName, newValue);
1450
- return set.call(vm.elm, newValue);
1451
- },
1452
- };
1458
+ };
1453
1459
  }
1454
1460
  const EMPTY_REFS = shared.freeze(shared.create(null));
1455
1461
  const refsCache = new WeakMap();
@@ -1459,345 +1465,444 @@ const refsCache = new WeakMap();
1459
1465
  **/
1460
1466
  // @ts-ignore
1461
1467
  const LightningElement = function () {
1462
- // This should be as performant as possible, while any initialization should be done lazily
1463
- if (shared.isNull(vmBeingConstructed)) {
1464
- // Thrown when doing something like `new LightningElement()` or
1465
- // `class Foo extends LightningElement {}; new Foo()`
1466
- throw new TypeError('Illegal constructor');
1467
- }
1468
- const vm = vmBeingConstructed;
1469
- const { def, elm } = vm;
1470
- const { bridge } = def;
1468
+ // This should be as performant as possible, while any initialization should be done lazily
1469
+ if (shared.isNull(vmBeingConstructed)) {
1470
+ // Thrown when doing something like `new LightningElement()` or
1471
+ // `class Foo extends LightningElement {}; new Foo()`
1472
+ throw new TypeError('Illegal constructor');
1473
+ }
1474
+ const vm = vmBeingConstructed;
1475
+ const {
1476
+ def,
1477
+ elm
1478
+ } = vm;
1479
+ const {
1480
+ bridge
1481
+ } = def;
1482
+ if (process.env.NODE_ENV !== 'production') {
1483
+ const {
1484
+ assertInstanceOfHTMLElement
1485
+ } = vm.renderer;
1486
+ assertInstanceOfHTMLElement(vm.elm, `Component creation requires a DOM element to be associated to ${vm}.`);
1487
+ }
1488
+ const component = this;
1489
+ shared.setPrototypeOf(elm, bridge.prototype);
1490
+ vm.component = this;
1491
+ // Locker hooks assignment. When the LWC engine run with Locker, Locker intercepts all the new
1492
+ // component creation and passes hooks to instrument all the component interactions with the
1493
+ // engine. We are intentionally hiding this argument from the formal API of LightningElement
1494
+ // because we don't want folks to know about it just yet.
1495
+ if (arguments.length === 1) {
1496
+ const {
1497
+ callHook,
1498
+ setHook,
1499
+ getHook
1500
+ } = arguments[0];
1501
+ vm.callHook = callHook;
1502
+ vm.setHook = setHook;
1503
+ vm.getHook = getHook;
1504
+ }
1505
+ markLockerLiveObject(this);
1506
+ // Linking elm, shadow root and component with the VM.
1507
+ associateVM(component, vm);
1508
+ associateVM(elm, vm);
1509
+ if (vm.renderMode === 1 /* RenderMode.Shadow */) {
1510
+ vm.renderRoot = doAttachShadow(vm);
1511
+ } else {
1512
+ vm.renderRoot = elm;
1513
+ }
1514
+ // Adding extra guard rails in DEV mode.
1515
+ if (process.env.NODE_ENV !== 'production') {
1516
+ patchCustomElementWithRestrictions(elm);
1517
+ patchComponentWithRestrictions(component);
1518
+ }
1519
+ return this;
1520
+ };
1521
+ function doAttachShadow(vm) {
1522
+ const {
1523
+ elm,
1524
+ mode,
1525
+ shadowMode,
1526
+ def: {
1527
+ ctor
1528
+ },
1529
+ renderer: {
1530
+ attachShadow
1531
+ }
1532
+ } = vm;
1533
+ const shadowRoot = attachShadow(elm, {
1534
+ [shared.KEY__SYNTHETIC_MODE]: shadowMode === 1 /* ShadowMode.Synthetic */,
1535
+ delegatesFocus: Boolean(ctor.delegatesFocus),
1536
+ mode
1537
+ });
1538
+ vm.shadowRoot = shadowRoot;
1539
+ associateVM(shadowRoot, vm);
1540
+ if (process.env.NODE_ENV !== 'production') {
1541
+ patchShadowRootWithRestrictions(shadowRoot);
1542
+ }
1543
+ return shadowRoot;
1544
+ }
1545
+ function warnIfInvokedDuringConstruction(vm, methodOrPropName) {
1546
+ if (isBeingConstructed(vm)) {
1547
+ 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.`);
1548
+ }
1549
+ }
1550
+ // @ts-ignore
1551
+ LightningElement.prototype = {
1552
+ constructor: LightningElement,
1553
+ dispatchEvent(event) {
1554
+ const vm = getAssociatedVM(this);
1555
+ const {
1556
+ elm,
1557
+ renderer: {
1558
+ dispatchEvent
1559
+ }
1560
+ } = vm;
1561
+ return dispatchEvent(elm, event);
1562
+ },
1563
+ addEventListener(type, listener, options) {
1564
+ const vm = getAssociatedVM(this);
1565
+ const {
1566
+ elm,
1567
+ renderer: {
1568
+ addEventListener
1569
+ }
1570
+ } = vm;
1471
1571
  if (process.env.NODE_ENV !== 'production') {
1472
- const { assertInstanceOfHTMLElement } = vm.renderer;
1473
- assertInstanceOfHTMLElement(vm.elm, `Component creation requires a DOM element to be associated to ${vm}.`);
1474
- }
1475
- const component = this;
1476
- shared.setPrototypeOf(elm, bridge.prototype);
1477
- vm.component = this;
1478
- // Locker hooks assignment. When the LWC engine run with Locker, Locker intercepts all the new
1479
- // component creation and passes hooks to instrument all the component interactions with the
1480
- // engine. We are intentionally hiding this argument from the formal API of LightningElement
1481
- // because we don't want folks to know about it just yet.
1482
- if (arguments.length === 1) {
1483
- const { callHook, setHook, getHook } = arguments[0];
1484
- vm.callHook = callHook;
1485
- vm.setHook = setHook;
1486
- vm.getHook = getHook;
1487
- }
1488
- markLockerLiveObject(this);
1489
- // Linking elm, shadow root and component with the VM.
1490
- associateVM(component, vm);
1491
- associateVM(elm, vm);
1492
- if (vm.renderMode === 1 /* RenderMode.Shadow */) {
1493
- vm.renderRoot = doAttachShadow(vm);
1572
+ const vmBeingRendered = getVMBeingRendered();
1573
+ shared.assert.invariant(!isInvokingRender, `${vmBeingRendered}.render() method has side effects on the state of ${vm} by adding an event listener for "${type}".`);
1574
+ shared.assert.invariant(!isUpdatingTemplate, `Updating the template of ${vmBeingRendered} has side effects on the state of ${vm} by adding an event listener for "${type}".`);
1575
+ shared.assert.invariant(shared.isFunction(listener), `Invalid second argument for this.addEventListener() in ${vm} for event "${type}". Expected an EventListener but received ${listener}.`);
1576
+ }
1577
+ const wrappedListener = getWrappedComponentsListener(vm, listener);
1578
+ addEventListener(elm, type, wrappedListener, options);
1579
+ },
1580
+ removeEventListener(type, listener, options) {
1581
+ const vm = getAssociatedVM(this);
1582
+ const {
1583
+ elm,
1584
+ renderer: {
1585
+ removeEventListener
1586
+ }
1587
+ } = vm;
1588
+ const wrappedListener = getWrappedComponentsListener(vm, listener);
1589
+ removeEventListener(elm, type, wrappedListener, options);
1590
+ },
1591
+ hasAttribute(name) {
1592
+ const vm = getAssociatedVM(this);
1593
+ const {
1594
+ elm,
1595
+ renderer: {
1596
+ getAttribute
1597
+ }
1598
+ } = vm;
1599
+ return !shared.isNull(getAttribute(elm, name));
1600
+ },
1601
+ hasAttributeNS(namespace, name) {
1602
+ const vm = getAssociatedVM(this);
1603
+ const {
1604
+ elm,
1605
+ renderer: {
1606
+ getAttribute
1607
+ }
1608
+ } = vm;
1609
+ return !shared.isNull(getAttribute(elm, name, namespace));
1610
+ },
1611
+ removeAttribute(name) {
1612
+ const vm = getAssociatedVM(this);
1613
+ const {
1614
+ elm,
1615
+ renderer: {
1616
+ removeAttribute
1617
+ }
1618
+ } = vm;
1619
+ unlockAttribute(elm, name);
1620
+ removeAttribute(elm, name);
1621
+ lockAttribute();
1622
+ },
1623
+ removeAttributeNS(namespace, name) {
1624
+ const {
1625
+ elm,
1626
+ renderer: {
1627
+ removeAttribute
1628
+ }
1629
+ } = getAssociatedVM(this);
1630
+ unlockAttribute(elm, name);
1631
+ removeAttribute(elm, name, namespace);
1632
+ lockAttribute();
1633
+ },
1634
+ getAttribute(name) {
1635
+ const vm = getAssociatedVM(this);
1636
+ const {
1637
+ elm
1638
+ } = vm;
1639
+ const {
1640
+ getAttribute
1641
+ } = vm.renderer;
1642
+ return getAttribute(elm, name);
1643
+ },
1644
+ getAttributeNS(namespace, name) {
1645
+ const vm = getAssociatedVM(this);
1646
+ const {
1647
+ elm
1648
+ } = vm;
1649
+ const {
1650
+ getAttribute
1651
+ } = vm.renderer;
1652
+ return getAttribute(elm, name, namespace);
1653
+ },
1654
+ setAttribute(name, value) {
1655
+ const vm = getAssociatedVM(this);
1656
+ const {
1657
+ elm,
1658
+ renderer: {
1659
+ setAttribute
1660
+ }
1661
+ } = vm;
1662
+ if (process.env.NODE_ENV !== 'production') {
1663
+ shared.assert.isFalse(isBeingConstructed(vm), `Failed to construct '${getComponentTag(vm)}': The result must not have attributes.`);
1664
+ }
1665
+ unlockAttribute(elm, name);
1666
+ setAttribute(elm, name, value);
1667
+ lockAttribute();
1668
+ },
1669
+ setAttributeNS(namespace, name, value) {
1670
+ const vm = getAssociatedVM(this);
1671
+ const {
1672
+ elm,
1673
+ renderer: {
1674
+ setAttribute
1675
+ }
1676
+ } = vm;
1677
+ if (process.env.NODE_ENV !== 'production') {
1678
+ shared.assert.isFalse(isBeingConstructed(vm), `Failed to construct '${getComponentTag(vm)}': The result must not have attributes.`);
1679
+ }
1680
+ unlockAttribute(elm, name);
1681
+ setAttribute(elm, name, value, namespace);
1682
+ lockAttribute();
1683
+ },
1684
+ getBoundingClientRect() {
1685
+ const vm = getAssociatedVM(this);
1686
+ const {
1687
+ elm,
1688
+ renderer: {
1689
+ getBoundingClientRect
1690
+ }
1691
+ } = vm;
1692
+ if (process.env.NODE_ENV !== 'production') {
1693
+ warnIfInvokedDuringConstruction(vm, 'getBoundingClientRect()');
1494
1694
  }
1495
- else {
1496
- vm.renderRoot = elm;
1695
+ return getBoundingClientRect(elm);
1696
+ },
1697
+ get isConnected() {
1698
+ const vm = getAssociatedVM(this);
1699
+ const {
1700
+ elm,
1701
+ renderer: {
1702
+ isConnected
1703
+ }
1704
+ } = vm;
1705
+ return isConnected(elm);
1706
+ },
1707
+ get classList() {
1708
+ const vm = getAssociatedVM(this);
1709
+ const {
1710
+ elm,
1711
+ renderer: {
1712
+ getClassList
1713
+ }
1714
+ } = vm;
1715
+ if (process.env.NODE_ENV !== 'production') {
1716
+ // TODO [#1290]: this still fails in dev but works in production, eventually, we should
1717
+ // just throw in all modes
1718
+ shared.assert.isFalse(isBeingConstructed(vm), `Failed to construct ${vm}: The result must not have attributes. Adding or tampering with classname in constructor is not allowed in a web component, use connectedCallback() instead.`);
1719
+ }
1720
+ return getClassList(elm);
1721
+ },
1722
+ get template() {
1723
+ const vm = getAssociatedVM(this);
1724
+ if (process.env.NODE_ENV !== 'production') {
1725
+ if (vm.renderMode === 0 /* RenderMode.Light */) {
1726
+ logError('`this.template` returns null for light DOM components. Since there is no shadow, the rendered content can be accessed via `this` itself. e.g. instead of `this.template.querySelector`, use `this.querySelector`.');
1727
+ }
1728
+ }
1729
+ return vm.shadowRoot;
1730
+ },
1731
+ get refs() {
1732
+ const vm = getAssociatedVM(this);
1733
+ if (isUpdatingTemplate) {
1734
+ if (process.env.NODE_ENV !== 'production') {
1735
+ logError(`this.refs should not be called while ${getComponentTag(vm)} is rendering. Use this.refs only when the DOM is stable, e.g. in renderedCallback().`);
1736
+ }
1737
+ // If the template is in the process of being updated, then we don't want to go through the normal
1738
+ // process of returning the refs and caching them, because the state of the refs is unstable.
1739
+ // This can happen if e.g. a template contains `<div class={foo}></div>` and `foo` is computed
1740
+ // based on `this.refs.bar`.
1741
+ return;
1497
1742
  }
1498
- // Adding extra guard rails in DEV mode.
1499
1743
  if (process.env.NODE_ENV !== 'production') {
1500
- patchCustomElementWithRestrictions(elm);
1501
- patchComponentWithRestrictions(component);
1744
+ warnIfInvokedDuringConstruction(vm, 'refs');
1502
1745
  }
1503
- return this;
1504
- };
1505
- function doAttachShadow(vm) {
1506
- const { elm, mode, shadowMode, def: { ctor }, renderer: { attachShadow }, } = vm;
1507
- const shadowRoot = attachShadow(elm, {
1508
- [shared.KEY__SYNTHETIC_MODE]: shadowMode === 1 /* ShadowMode.Synthetic */,
1509
- delegatesFocus: Boolean(ctor.delegatesFocus),
1510
- mode,
1746
+ const {
1747
+ refVNodes,
1748
+ hasRefVNodes,
1749
+ cmpTemplate
1750
+ } = vm;
1751
+ // If the `cmpTemplate` is null, that means that the template has not been rendered yet. Most likely this occurs
1752
+ // if `this.refs` is called during the `connectedCallback` phase. The DOM elements have not been rendered yet,
1753
+ // so log a warning. Note we also check `isBeingConstructed()` to avoid a double warning (due to
1754
+ // `warnIfInvokedDuringConstruction` above).
1755
+ if (process.env.NODE_ENV !== 'production' && shared.isNull(cmpTemplate) && !isBeingConstructed(vm)) {
1756
+ logError(`this.refs is undefined for ${getComponentTag(vm)}. This is either because the attached template has no "lwc:ref" directive, or this.refs was ` + `invoked before renderedCallback(). Use this.refs only when the referenced HTML elements have ` + `been rendered to the DOM, such as within renderedCallback() or disconnectedCallback().`);
1757
+ }
1758
+ // For backwards compatibility with component written before template refs
1759
+ // were introduced, we return undefined if the template has no refs defined
1760
+ // anywhere. This fixes components that may want to add an expando called `refs`
1761
+ // and are checking if it exists with `if (this.refs)` before adding it.
1762
+ // Note it is not sufficient to just check if `refVNodes` is null or empty,
1763
+ // because a template may have `lwc:ref` defined within a falsy `if:true` block.
1764
+ if (!hasRefVNodes) {
1765
+ return;
1766
+ }
1767
+ // For templates that are using `lwc:ref`, if there are no refs currently available
1768
+ // (e.g. refs inside of a falsy `if:true` block), we return an empty object.
1769
+ if (shared.isNull(refVNodes)) {
1770
+ return EMPTY_REFS;
1771
+ }
1772
+ // The refNodes can be cached based on the refVNodes, since the refVNodes
1773
+ // are recreated from scratch every time the template is rendered.
1774
+ // This happens with `vm.refVNodes = null` in `template.ts` in `@lwc/engine-core`.
1775
+ let refs = refsCache.get(refVNodes);
1776
+ if (shared.isUndefined(refs)) {
1777
+ refs = shared.create(null);
1778
+ for (const key of shared.keys(refVNodes)) {
1779
+ refs[key] = refVNodes[key].elm;
1780
+ }
1781
+ shared.freeze(refs);
1782
+ refsCache.set(refVNodes, refs);
1783
+ }
1784
+ return refs;
1785
+ },
1786
+ // For backwards compat, we allow component authors to set `refs` as an expando
1787
+ set refs(value) {
1788
+ shared.defineProperty(this, 'refs', {
1789
+ configurable: true,
1790
+ enumerable: true,
1791
+ writable: true,
1792
+ value
1511
1793
  });
1512
- vm.shadowRoot = shadowRoot;
1513
- associateVM(shadowRoot, vm);
1794
+ },
1795
+ get shadowRoot() {
1796
+ // From within the component instance, the shadowRoot is always reported as "closed".
1797
+ // Authors should rely on this.template instead.
1798
+ return null;
1799
+ },
1800
+ get children() {
1801
+ const vm = getAssociatedVM(this);
1802
+ const renderer = vm.renderer;
1514
1803
  if (process.env.NODE_ENV !== 'production') {
1515
- patchShadowRootWithRestrictions(shadowRoot);
1804
+ warnIfInvokedDuringConstruction(vm, 'children');
1516
1805
  }
1517
- return shadowRoot;
1518
- }
1519
- function warnIfInvokedDuringConstruction(vm, methodOrPropName) {
1520
- if (isBeingConstructed(vm)) {
1521
- 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.`);
1806
+ return renderer.getChildren(vm.elm);
1807
+ },
1808
+ get childNodes() {
1809
+ const vm = getAssociatedVM(this);
1810
+ const renderer = vm.renderer;
1811
+ if (process.env.NODE_ENV !== 'production') {
1812
+ warnIfInvokedDuringConstruction(vm, 'childNodes');
1522
1813
  }
1523
- }
1524
- // @ts-ignore
1525
- LightningElement.prototype = {
1526
- constructor: LightningElement,
1527
- dispatchEvent(event) {
1528
- const vm = getAssociatedVM(this);
1529
- const { elm, renderer: { dispatchEvent }, } = vm;
1530
- return dispatchEvent(elm, event);
1531
- },
1532
- addEventListener(type, listener, options) {
1533
- const vm = getAssociatedVM(this);
1534
- const { elm, renderer: { addEventListener }, } = vm;
1535
- if (process.env.NODE_ENV !== 'production') {
1536
- const vmBeingRendered = getVMBeingRendered();
1537
- shared.assert.invariant(!isInvokingRender, `${vmBeingRendered}.render() method has side effects on the state of ${vm} by adding an event listener for "${type}".`);
1538
- shared.assert.invariant(!isUpdatingTemplate, `Updating the template of ${vmBeingRendered} has side effects on the state of ${vm} by adding an event listener for "${type}".`);
1539
- shared.assert.invariant(shared.isFunction(listener), `Invalid second argument for this.addEventListener() in ${vm} for event "${type}". Expected an EventListener but received ${listener}.`);
1540
- }
1541
- const wrappedListener = getWrappedComponentsListener(vm, listener);
1542
- addEventListener(elm, type, wrappedListener, options);
1543
- },
1544
- removeEventListener(type, listener, options) {
1545
- const vm = getAssociatedVM(this);
1546
- const { elm, renderer: { removeEventListener }, } = vm;
1547
- const wrappedListener = getWrappedComponentsListener(vm, listener);
1548
- removeEventListener(elm, type, wrappedListener, options);
1549
- },
1550
- hasAttribute(name) {
1551
- const vm = getAssociatedVM(this);
1552
- const { elm, renderer: { getAttribute }, } = vm;
1553
- return !shared.isNull(getAttribute(elm, name));
1554
- },
1555
- hasAttributeNS(namespace, name) {
1556
- const vm = getAssociatedVM(this);
1557
- const { elm, renderer: { getAttribute }, } = vm;
1558
- return !shared.isNull(getAttribute(elm, name, namespace));
1559
- },
1560
- removeAttribute(name) {
1561
- const vm = getAssociatedVM(this);
1562
- const { elm, renderer: { removeAttribute }, } = vm;
1563
- unlockAttribute(elm, name);
1564
- removeAttribute(elm, name);
1565
- lockAttribute();
1566
- },
1567
- removeAttributeNS(namespace, name) {
1568
- const { elm, renderer: { removeAttribute }, } = getAssociatedVM(this);
1569
- unlockAttribute(elm, name);
1570
- removeAttribute(elm, name, namespace);
1571
- lockAttribute();
1572
- },
1573
- getAttribute(name) {
1574
- const vm = getAssociatedVM(this);
1575
- const { elm } = vm;
1576
- const { getAttribute } = vm.renderer;
1577
- return getAttribute(elm, name);
1578
- },
1579
- getAttributeNS(namespace, name) {
1580
- const vm = getAssociatedVM(this);
1581
- const { elm } = vm;
1582
- const { getAttribute } = vm.renderer;
1583
- return getAttribute(elm, name, namespace);
1584
- },
1585
- setAttribute(name, value) {
1586
- const vm = getAssociatedVM(this);
1587
- const { elm, renderer: { setAttribute }, } = vm;
1588
- if (process.env.NODE_ENV !== 'production') {
1589
- shared.assert.isFalse(isBeingConstructed(vm), `Failed to construct '${getComponentTag(vm)}': The result must not have attributes.`);
1590
- }
1591
- unlockAttribute(elm, name);
1592
- setAttribute(elm, name, value);
1593
- lockAttribute();
1594
- },
1595
- setAttributeNS(namespace, name, value) {
1596
- const vm = getAssociatedVM(this);
1597
- const { elm, renderer: { setAttribute }, } = vm;
1598
- if (process.env.NODE_ENV !== 'production') {
1599
- shared.assert.isFalse(isBeingConstructed(vm), `Failed to construct '${getComponentTag(vm)}': The result must not have attributes.`);
1600
- }
1601
- unlockAttribute(elm, name);
1602
- setAttribute(elm, name, value, namespace);
1603
- lockAttribute();
1604
- },
1605
- getBoundingClientRect() {
1606
- const vm = getAssociatedVM(this);
1607
- const { elm, renderer: { getBoundingClientRect }, } = vm;
1608
- if (process.env.NODE_ENV !== 'production') {
1609
- warnIfInvokedDuringConstruction(vm, 'getBoundingClientRect()');
1610
- }
1611
- return getBoundingClientRect(elm);
1612
- },
1613
- get isConnected() {
1614
- const vm = getAssociatedVM(this);
1615
- const { elm, renderer: { isConnected }, } = vm;
1616
- return isConnected(elm);
1617
- },
1618
- get classList() {
1619
- const vm = getAssociatedVM(this);
1620
- const { elm, renderer: { getClassList }, } = vm;
1621
- if (process.env.NODE_ENV !== 'production') {
1622
- // TODO [#1290]: this still fails in dev but works in production, eventually, we should
1623
- // just throw in all modes
1624
- shared.assert.isFalse(isBeingConstructed(vm), `Failed to construct ${vm}: The result must not have attributes. Adding or tampering with classname in constructor is not allowed in a web component, use connectedCallback() instead.`);
1625
- }
1626
- return getClassList(elm);
1627
- },
1628
- get template() {
1629
- const vm = getAssociatedVM(this);
1630
- if (process.env.NODE_ENV !== 'production') {
1631
- if (vm.renderMode === 0 /* RenderMode.Light */) {
1632
- logError('`this.template` returns null for light DOM components. Since there is no shadow, the rendered content can be accessed via `this` itself. e.g. instead of `this.template.querySelector`, use `this.querySelector`.');
1633
- }
1634
- }
1635
- return vm.shadowRoot;
1636
- },
1637
- get refs() {
1638
- const vm = getAssociatedVM(this);
1639
- if (isUpdatingTemplate) {
1640
- if (process.env.NODE_ENV !== 'production') {
1641
- logError(`this.refs should not be called while ${getComponentTag(vm)} is rendering. Use this.refs only when the DOM is stable, e.g. in renderedCallback().`);
1642
- }
1643
- // If the template is in the process of being updated, then we don't want to go through the normal
1644
- // process of returning the refs and caching them, because the state of the refs is unstable.
1645
- // This can happen if e.g. a template contains `<div class={foo}></div>` and `foo` is computed
1646
- // based on `this.refs.bar`.
1647
- return;
1648
- }
1649
- if (process.env.NODE_ENV !== 'production') {
1650
- warnIfInvokedDuringConstruction(vm, 'refs');
1651
- }
1652
- const { refVNodes, hasRefVNodes, cmpTemplate } = vm;
1653
- // If the `cmpTemplate` is null, that means that the template has not been rendered yet. Most likely this occurs
1654
- // if `this.refs` is called during the `connectedCallback` phase. The DOM elements have not been rendered yet,
1655
- // so log a warning. Note we also check `isBeingConstructed()` to avoid a double warning (due to
1656
- // `warnIfInvokedDuringConstruction` above).
1657
- if (process.env.NODE_ENV !== 'production' &&
1658
- shared.isNull(cmpTemplate) &&
1659
- !isBeingConstructed(vm)) {
1660
- logError(`this.refs is undefined for ${getComponentTag(vm)}. This is either because the attached template has no "lwc:ref" directive, or this.refs was ` +
1661
- `invoked before renderedCallback(). Use this.refs only when the referenced HTML elements have ` +
1662
- `been rendered to the DOM, such as within renderedCallback() or disconnectedCallback().`);
1663
- }
1664
- // For backwards compatibility with component written before template refs
1665
- // were introduced, we return undefined if the template has no refs defined
1666
- // anywhere. This fixes components that may want to add an expando called `refs`
1667
- // and are checking if it exists with `if (this.refs)` before adding it.
1668
- // Note it is not sufficient to just check if `refVNodes` is null or empty,
1669
- // because a template may have `lwc:ref` defined within a falsy `if:true` block.
1670
- if (!hasRefVNodes) {
1671
- return;
1672
- }
1673
- // For templates that are using `lwc:ref`, if there are no refs currently available
1674
- // (e.g. refs inside of a falsy `if:true` block), we return an empty object.
1675
- if (shared.isNull(refVNodes)) {
1676
- return EMPTY_REFS;
1677
- }
1678
- // The refNodes can be cached based on the refVNodes, since the refVNodes
1679
- // are recreated from scratch every time the template is rendered.
1680
- // This happens with `vm.refVNodes = null` in `template.ts` in `@lwc/engine-core`.
1681
- let refs = refsCache.get(refVNodes);
1682
- if (shared.isUndefined(refs)) {
1683
- refs = shared.create(null);
1684
- for (const key of shared.keys(refVNodes)) {
1685
- refs[key] = refVNodes[key].elm;
1686
- }
1687
- shared.freeze(refs);
1688
- refsCache.set(refVNodes, refs);
1689
- }
1690
- return refs;
1691
- },
1692
- // For backwards compat, we allow component authors to set `refs` as an expando
1693
- set refs(value) {
1694
- shared.defineProperty(this, 'refs', {
1695
- configurable: true,
1696
- enumerable: true,
1697
- writable: true,
1698
- value,
1699
- });
1700
- },
1701
- get shadowRoot() {
1702
- // From within the component instance, the shadowRoot is always reported as "closed".
1703
- // Authors should rely on this.template instead.
1704
- return null;
1705
- },
1706
- get children() {
1707
- const vm = getAssociatedVM(this);
1708
- const renderer = vm.renderer;
1709
- if (process.env.NODE_ENV !== 'production') {
1710
- warnIfInvokedDuringConstruction(vm, 'children');
1711
- }
1712
- return renderer.getChildren(vm.elm);
1713
- },
1714
- get childNodes() {
1715
- const vm = getAssociatedVM(this);
1716
- const renderer = vm.renderer;
1717
- if (process.env.NODE_ENV !== 'production') {
1718
- warnIfInvokedDuringConstruction(vm, 'childNodes');
1719
- }
1720
- return renderer.getChildNodes(vm.elm);
1721
- },
1722
- get firstChild() {
1723
- const vm = getAssociatedVM(this);
1724
- const renderer = vm.renderer;
1725
- if (process.env.NODE_ENV !== 'production') {
1726
- warnIfInvokedDuringConstruction(vm, 'firstChild');
1727
- }
1728
- return renderer.getFirstChild(vm.elm);
1729
- },
1730
- get firstElementChild() {
1731
- const vm = getAssociatedVM(this);
1732
- const renderer = vm.renderer;
1733
- if (process.env.NODE_ENV !== 'production') {
1734
- warnIfInvokedDuringConstruction(vm, 'firstElementChild');
1735
- }
1736
- return renderer.getFirstElementChild(vm.elm);
1737
- },
1738
- get lastChild() {
1739
- const vm = getAssociatedVM(this);
1740
- const renderer = vm.renderer;
1741
- if (process.env.NODE_ENV !== 'production') {
1742
- warnIfInvokedDuringConstruction(vm, 'lastChild');
1743
- }
1744
- return renderer.getLastChild(vm.elm);
1745
- },
1746
- get lastElementChild() {
1747
- const vm = getAssociatedVM(this);
1748
- const renderer = vm.renderer;
1749
- if (process.env.NODE_ENV !== 'production') {
1750
- warnIfInvokedDuringConstruction(vm, 'lastElementChild');
1751
- }
1752
- return renderer.getLastElementChild(vm.elm);
1753
- },
1754
- render() {
1755
- const vm = getAssociatedVM(this);
1756
- return vm.def.template;
1757
- },
1758
- toString() {
1759
- const vm = getAssociatedVM(this);
1760
- return `[object ${vm.def.name}]`;
1761
- },
1814
+ return renderer.getChildNodes(vm.elm);
1815
+ },
1816
+ get firstChild() {
1817
+ const vm = getAssociatedVM(this);
1818
+ const renderer = vm.renderer;
1819
+ if (process.env.NODE_ENV !== 'production') {
1820
+ warnIfInvokedDuringConstruction(vm, 'firstChild');
1821
+ }
1822
+ return renderer.getFirstChild(vm.elm);
1823
+ },
1824
+ get firstElementChild() {
1825
+ const vm = getAssociatedVM(this);
1826
+ const renderer = vm.renderer;
1827
+ if (process.env.NODE_ENV !== 'production') {
1828
+ warnIfInvokedDuringConstruction(vm, 'firstElementChild');
1829
+ }
1830
+ return renderer.getFirstElementChild(vm.elm);
1831
+ },
1832
+ get lastChild() {
1833
+ const vm = getAssociatedVM(this);
1834
+ const renderer = vm.renderer;
1835
+ if (process.env.NODE_ENV !== 'production') {
1836
+ warnIfInvokedDuringConstruction(vm, 'lastChild');
1837
+ }
1838
+ return renderer.getLastChild(vm.elm);
1839
+ },
1840
+ get lastElementChild() {
1841
+ const vm = getAssociatedVM(this);
1842
+ const renderer = vm.renderer;
1843
+ if (process.env.NODE_ENV !== 'production') {
1844
+ warnIfInvokedDuringConstruction(vm, 'lastElementChild');
1845
+ }
1846
+ return renderer.getLastElementChild(vm.elm);
1847
+ },
1848
+ render() {
1849
+ const vm = getAssociatedVM(this);
1850
+ return vm.def.template;
1851
+ },
1852
+ toString() {
1853
+ const vm = getAssociatedVM(this);
1854
+ return `[object ${vm.def.name}]`;
1855
+ }
1762
1856
  };
1763
1857
  const queryAndChildGetterDescriptors = shared.create(null);
1764
- const queryMethods = [
1765
- 'getElementsByClassName',
1766
- 'getElementsByTagName',
1767
- 'querySelector',
1768
- 'querySelectorAll',
1769
- ];
1858
+ const queryMethods = ['getElementsByClassName', 'getElementsByTagName', 'querySelector', 'querySelectorAll'];
1770
1859
  // Generic passthrough for query APIs on HTMLElement to the relevant Renderer APIs
1771
1860
  for (const queryMethod of queryMethods) {
1772
- queryAndChildGetterDescriptors[queryMethod] = {
1773
- value(arg) {
1774
- const vm = getAssociatedVM(this);
1775
- const { elm, renderer } = vm;
1776
- if (process.env.NODE_ENV !== 'production') {
1777
- warnIfInvokedDuringConstruction(vm, `${queryMethod}()`);
1778
- }
1779
- return renderer[queryMethod](elm, arg);
1780
- },
1781
- configurable: true,
1782
- enumerable: true,
1783
- writable: true,
1784
- };
1861
+ queryAndChildGetterDescriptors[queryMethod] = {
1862
+ value(arg) {
1863
+ const vm = getAssociatedVM(this);
1864
+ const {
1865
+ elm,
1866
+ renderer
1867
+ } = vm;
1868
+ if (process.env.NODE_ENV !== 'production') {
1869
+ warnIfInvokedDuringConstruction(vm, `${queryMethod}()`);
1870
+ }
1871
+ return renderer[queryMethod](elm, arg);
1872
+ },
1873
+ configurable: true,
1874
+ enumerable: true,
1875
+ writable: true
1876
+ };
1785
1877
  }
1786
1878
  shared.defineProperties(LightningElement.prototype, queryAndChildGetterDescriptors);
1787
1879
  const lightningBasedDescriptors = shared.create(null);
1788
1880
  for (const propName in HTMLElementOriginalDescriptors) {
1789
- lightningBasedDescriptors[propName] = createBridgeToElementDescriptor(propName, HTMLElementOriginalDescriptors[propName]);
1881
+ lightningBasedDescriptors[propName] = createBridgeToElementDescriptor(propName, HTMLElementOriginalDescriptors[propName]);
1790
1882
  }
1791
1883
  shared.defineProperties(LightningElement.prototype, lightningBasedDescriptors);
1884
+ function applyAriaReflectionToLightningElement() {
1885
+ // If ARIA reflection is not applied globally to Element.prototype, or if we are running server-side,
1886
+ // apply it to LightningElement.prototype.
1887
+ // This allows `this.aria*` property accessors to work from inside a component, and to reflect `aria-*` attrs.
1888
+ ariaReflection.applyAriaReflection(LightningElement.prototype);
1889
+ }
1890
+ // The reason for this odd if/else branching is limitations in @lwc/features:
1891
+ // https://github.com/salesforce/lwc/blob/master/packages/%40lwc/features/README.md#only-works-with-if-statements
1892
+ if (features.lwcRuntimeFlags.DISABLE_ARIA_REFLECTION_POLYFILL) {
1893
+ applyAriaReflectionToLightningElement();
1894
+ } else if (!process.env.IS_BROWSER) {
1895
+ applyAriaReflectionToLightningElement();
1896
+ }
1792
1897
  shared.defineProperty(LightningElement, 'CustomElementConstructor', {
1793
- get() {
1794
- // If required, a runtime-specific implementation must be defined.
1795
- throw new ReferenceError('The current runtime does not support CustomElementConstructor.');
1796
- },
1797
- configurable: true,
1898
+ get() {
1899
+ // If required, a runtime-specific implementation must be defined.
1900
+ throw new ReferenceError('The current runtime does not support CustomElementConstructor.');
1901
+ },
1902
+ configurable: true
1798
1903
  });
1799
1904
  if (process.env.NODE_ENV !== 'production') {
1800
- patchLightningElementPrototypeWithRestrictions(LightningElement.prototype);
1905
+ patchLightningElementPrototypeWithRestrictions(LightningElement.prototype);
1801
1906
  }
1802
1907
 
1803
1908
  function createObservedFieldPropertyDescriptor(key) {
@@ -1816,60 +1921,6 @@ function createObservedFieldPropertyDescriptor(key) {
1816
1921
  };
1817
1922
  }
1818
1923
 
1819
- /*
1820
- * Copyright (c) 2018, salesforce.com, inc.
1821
- * All rights reserved.
1822
- * SPDX-License-Identifier: MIT
1823
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
1824
- */
1825
- const DUMMY_ACCESSOR_REACTIVE_OBSERVER = {
1826
- observe(job) {
1827
- job();
1828
- },
1829
- reset() { },
1830
- link() { },
1831
- };
1832
- class AccessorReactiveObserver extends ReactiveObserver {
1833
- constructor(vm, set) {
1834
- super(() => {
1835
- if (shared.isFalse(this.debouncing)) {
1836
- this.debouncing = true;
1837
- addCallbackToNextTick(() => {
1838
- if (shared.isTrue(this.debouncing)) {
1839
- const { value } = this;
1840
- const { isDirty: dirtyStateBeforeSetterCall, component, idx } = vm;
1841
- set.call(component, value);
1842
- // de-bouncing after the call to the original setter to prevent
1843
- // infinity loop if the setter itself is mutating things that
1844
- // were accessed during the previous invocation.
1845
- this.debouncing = false;
1846
- if (shared.isTrue(vm.isDirty) && shared.isFalse(dirtyStateBeforeSetterCall) && idx > 0) {
1847
- // immediate rehydration due to a setter driven mutation, otherwise
1848
- // the component will get rendered on the second tick, which it is not
1849
- // desirable.
1850
- rerenderVM(vm);
1851
- }
1852
- }
1853
- });
1854
- }
1855
- });
1856
- this.debouncing = false;
1857
- }
1858
- reset(value) {
1859
- super.reset();
1860
- this.debouncing = false;
1861
- if (arguments.length > 0) {
1862
- this.value = value;
1863
- }
1864
- }
1865
- }
1866
- function createAccessorReactiveObserver(vm, set) {
1867
- // On the server side, we don't need mutation tracking. Skipping it improves performance.
1868
- return process.env.IS_BROWSER
1869
- ? new AccessorReactiveObserver(vm, set)
1870
- : DUMMY_ACCESSOR_REACTIVE_OBSERVER;
1871
- }
1872
-
1873
1924
  /*
1874
1925
  * Copyright (c) 2018, salesforce.com, inc.
1875
1926
  * All rights reserved.
@@ -1877,90 +1928,71 @@ function createAccessorReactiveObserver(vm, set) {
1877
1928
  * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
1878
1929
  */
1879
1930
  function api$1() {
1880
- if (process.env.NODE_ENV !== 'production') {
1881
- shared.assert.fail(`@api decorator can only be used as a decorator function.`);
1882
- }
1883
- throw new Error();
1931
+ if (process.env.NODE_ENV !== 'production') {
1932
+ shared.assert.fail(`@api decorator can only be used as a decorator function.`);
1933
+ }
1934
+ throw new Error();
1884
1935
  }
1885
1936
  function createPublicPropertyDescriptor(key) {
1886
- return {
1887
- get() {
1888
- const vm = getAssociatedVM(this);
1889
- if (isBeingConstructed(vm)) {
1890
- if (process.env.NODE_ENV !== 'production') {
1891
- logError(`Can’t read the value of property \`${shared.toString(key)}\` from the constructor because the owner component hasn’t set the value yet. Instead, use the constructor to set a default value for the property.`, vm);
1892
- }
1893
- return;
1894
- }
1895
- componentValueObserved(vm, key);
1896
- return vm.cmpProps[key];
1897
- },
1898
- set(newValue) {
1899
- const vm = getAssociatedVM(this);
1900
- if (process.env.NODE_ENV !== 'production') {
1901
- const vmBeingRendered = getVMBeingRendered();
1902
- shared.assert.invariant(!isInvokingRender, `${vmBeingRendered}.render() method has side effects on the state of ${vm}.${shared.toString(key)}`);
1903
- shared.assert.invariant(!isUpdatingTemplate, `Updating the template of ${vmBeingRendered} has side effects on the state of ${vm}.${shared.toString(key)}`);
1904
- }
1905
- vm.cmpProps[key] = newValue;
1906
- componentValueMutated(vm, key);
1907
- },
1908
- enumerable: true,
1909
- configurable: true
1910
- };
1937
+ return {
1938
+ get() {
1939
+ const vm = getAssociatedVM(this);
1940
+ if (isBeingConstructed(vm)) {
1941
+ if (process.env.NODE_ENV !== 'production') {
1942
+ logError(`Can’t read the value of property \`${shared.toString(key)}\` from the constructor because the owner component hasn’t set the value yet. Instead, use the constructor to set a default value for the property.`, vm);
1943
+ }
1944
+ return;
1945
+ }
1946
+ componentValueObserved(vm, key);
1947
+ return vm.cmpProps[key];
1948
+ },
1949
+ set(newValue) {
1950
+ const vm = getAssociatedVM(this);
1951
+ if (process.env.NODE_ENV !== 'production') {
1952
+ const vmBeingRendered = getVMBeingRendered();
1953
+ shared.assert.invariant(!isInvokingRender, `${vmBeingRendered}.render() method has side effects on the state of ${vm}.${shared.toString(key)}`);
1954
+ shared.assert.invariant(!isUpdatingTemplate, `Updating the template of ${vmBeingRendered} has side effects on the state of ${vm}.${shared.toString(key)}`);
1955
+ }
1956
+ vm.cmpProps[key] = newValue;
1957
+ componentValueMutated(vm, key);
1958
+ },
1959
+ enumerable: true,
1960
+ configurable: true,
1961
+ };
1911
1962
  }
1912
1963
  function createPublicAccessorDescriptor(key, descriptor) {
1913
- const {
1914
- get,
1915
- set,
1916
- enumerable,
1917
- configurable
1918
- } = descriptor;
1919
- if (!shared.isFunction(get)) {
1920
- if (process.env.NODE_ENV !== 'production') {
1921
- shared.assert.invariant(shared.isFunction(get), `Invalid compiler output for public accessor ${shared.toString(key)} decorated with @api`);
1922
- }
1923
- throw new Error();
1924
- }
1925
- return {
1926
- get() {
1927
- if (process.env.NODE_ENV !== 'production') {
1928
- // Assert that the this value is an actual Component with an associated VM.
1929
- getAssociatedVM(this);
1930
- }
1931
- return get.call(this);
1932
- },
1933
- set(newValue) {
1934
- const vm = getAssociatedVM(this);
1935
- if (process.env.NODE_ENV !== 'production') {
1936
- const vmBeingRendered = getVMBeingRendered();
1937
- shared.assert.invariant(!isInvokingRender, `${vmBeingRendered}.render() method has side effects on the state of ${vm}.${shared.toString(key)}`);
1938
- shared.assert.invariant(!isUpdatingTemplate, `Updating the template of ${vmBeingRendered} has side effects on the state of ${vm}.${shared.toString(key)}`);
1939
- }
1940
- if (set) {
1941
- if (features.lwcRuntimeFlags.ENABLE_REACTIVE_SETTER) {
1942
- let ro = vm.oar[key];
1943
- if (shared.isUndefined(ro)) {
1944
- ro = vm.oar[key] = createAccessorReactiveObserver(vm, set);
1945
- }
1946
- // every time we invoke this setter from outside (through this wrapper setter)
1947
- // we should reset the value and then debounce just in case there is a pending
1948
- // invocation the next tick that is not longer relevant since the value is changing
1949
- // from outside.
1950
- ro.reset(newValue);
1951
- ro.observe(() => {
1952
- set.call(this, newValue);
1953
- });
1954
- } else {
1955
- set.call(this, newValue);
1964
+ const { get, set, enumerable, configurable } = descriptor;
1965
+ if (!shared.isFunction(get)) {
1966
+ if (process.env.NODE_ENV !== 'production') {
1967
+ shared.assert.invariant(shared.isFunction(get), `Invalid compiler output for public accessor ${shared.toString(key)} decorated with @api`);
1956
1968
  }
1957
- } else if (process.env.NODE_ENV !== 'production') {
1958
- shared.assert.fail(`Invalid attempt to set a new value for property ${shared.toString(key)} of ${vm} that does not has a setter decorated with @api.`);
1959
- }
1960
- },
1961
- enumerable,
1962
- configurable
1963
- };
1969
+ throw new Error();
1970
+ }
1971
+ return {
1972
+ get() {
1973
+ if (process.env.NODE_ENV !== 'production') {
1974
+ // Assert that the this value is an actual Component with an associated VM.
1975
+ getAssociatedVM(this);
1976
+ }
1977
+ return get.call(this);
1978
+ },
1979
+ set(newValue) {
1980
+ const vm = getAssociatedVM(this);
1981
+ if (process.env.NODE_ENV !== 'production') {
1982
+ const vmBeingRendered = getVMBeingRendered();
1983
+ shared.assert.invariant(!isInvokingRender, `${vmBeingRendered}.render() method has side effects on the state of ${vm}.${shared.toString(key)}`);
1984
+ shared.assert.invariant(!isUpdatingTemplate, `Updating the template of ${vmBeingRendered} has side effects on the state of ${vm}.${shared.toString(key)}`);
1985
+ }
1986
+ if (set) {
1987
+ set.call(this, newValue);
1988
+ }
1989
+ else if (process.env.NODE_ENV !== 'production') {
1990
+ shared.assert.fail(`Invalid attempt to set a new value for property ${shared.toString(key)} of ${vm} that does not has a setter decorated with @api.`);
1991
+ }
1992
+ },
1993
+ enumerable,
1994
+ configurable,
1995
+ };
1964
1996
  }
1965
1997
 
1966
1998
  /*
@@ -2286,12 +2318,6 @@ function checkVersionMismatch(func, type) {
2286
2318
  }
2287
2319
  }
2288
2320
 
2289
- /*
2290
- * Copyright (c) 2018, salesforce.com, inc.
2291
- * All rights reserved.
2292
- * SPDX-License-Identifier: MIT
2293
- * For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
2294
- */
2295
2321
  const signedTemplateSet = new Set();
2296
2322
  function defaultEmptyTemplate() {
2297
2323
  return [];
@@ -2309,32 +2335,6 @@ function registerTemplate(tpl) {
2309
2335
  checkVersionMismatch(tpl, 'template');
2310
2336
  }
2311
2337
  signedTemplateSet.add(tpl);
2312
- // FIXME[@W-10950976]: the template object should be frozen, and it should not be possible to set
2313
- // the stylesheets or stylesheetToken(s). For backwards compat, though, we shim stylesheetTokens
2314
- // on top of stylesheetToken for anyone who is accessing the old internal API.
2315
- // Details: https://salesforce.quip.com/v1rmAFu2cKAr
2316
- shared.defineProperty(tpl, 'stylesheetTokens', {
2317
- enumerable: true,
2318
- configurable: true,
2319
- get() {
2320
- const { stylesheetToken } = this;
2321
- if (shared.isUndefined(stylesheetToken)) {
2322
- return stylesheetToken;
2323
- }
2324
- // Shim for the old `stylesheetTokens` property
2325
- // See https://github.com/salesforce/lwc/pull/2332/files#diff-7901555acef29969adaa6583185b3e9bce475cdc6f23e799a54e0018cb18abaa
2326
- return {
2327
- hostAttribute: `${stylesheetToken}-host`,
2328
- shadowAttribute: stylesheetToken,
2329
- };
2330
- },
2331
- set(value) {
2332
- // If the value is null or some other exotic object, you would be broken anyway in the past
2333
- // because the engine would try to access hostAttribute/shadowAttribute, which would throw an error.
2334
- // However it may be undefined in newer versions of LWC, so we need to guard against that case.
2335
- this.stylesheetToken = shared.isUndefined(value) ? undefined : value.shadowAttribute;
2336
- },
2337
- });
2338
2338
  // chaining this method as a way to wrap existing
2339
2339
  // assignment of templates easily, without too much transformation
2340
2340
  return tpl;
@@ -2362,138 +2362,161 @@ function sanitizeAttribute(tagName, namespaceUri, attrName, attrValue) {
2362
2362
  const cachedGetterByKey = shared.create(null);
2363
2363
  const cachedSetterByKey = shared.create(null);
2364
2364
  function createGetter(key) {
2365
- let fn = cachedGetterByKey[key];
2366
- if (shared.isUndefined(fn)) {
2367
- fn = cachedGetterByKey[key] = function () {
2368
- const vm = getAssociatedVM(this);
2369
- const { getHook } = vm;
2370
- return getHook(vm.component, key);
2371
- };
2372
- }
2373
- return fn;
2365
+ let fn = cachedGetterByKey[key];
2366
+ if (shared.isUndefined(fn)) {
2367
+ fn = cachedGetterByKey[key] = function () {
2368
+ const vm = getAssociatedVM(this);
2369
+ const {
2370
+ getHook
2371
+ } = vm;
2372
+ return getHook(vm.component, key);
2373
+ };
2374
+ }
2375
+ return fn;
2374
2376
  }
2375
2377
  function createSetter(key) {
2376
- let fn = cachedSetterByKey[key];
2377
- if (shared.isUndefined(fn)) {
2378
- fn = cachedSetterByKey[key] = function (newValue) {
2379
- const vm = getAssociatedVM(this);
2380
- const { setHook } = vm;
2381
- newValue = getReadOnlyProxy(newValue);
2382
- setHook(vm.component, key, newValue);
2383
- };
2384
- }
2385
- return fn;
2378
+ let fn = cachedSetterByKey[key];
2379
+ if (shared.isUndefined(fn)) {
2380
+ fn = cachedSetterByKey[key] = function (newValue) {
2381
+ const vm = getAssociatedVM(this);
2382
+ const {
2383
+ setHook
2384
+ } = vm;
2385
+ newValue = getReadOnlyProxy(newValue);
2386
+ setHook(vm.component, key, newValue);
2387
+ };
2388
+ }
2389
+ return fn;
2386
2390
  }
2387
2391
  function createMethodCaller(methodName) {
2388
- return function () {
2389
- const vm = getAssociatedVM(this);
2390
- const { callHook, component } = vm;
2391
- const fn = component[methodName];
2392
- return callHook(vm.component, fn, shared.ArraySlice.call(arguments));
2393
- };
2392
+ return function () {
2393
+ const vm = getAssociatedVM(this);
2394
+ const {
2395
+ callHook,
2396
+ component
2397
+ } = vm;
2398
+ const fn = component[methodName];
2399
+ return callHook(vm.component, fn, shared.ArraySlice.call(arguments));
2400
+ };
2394
2401
  }
2395
2402
  function createAttributeChangedCallback(attributeToPropMap, superAttributeChangedCallback) {
2396
- return function attributeChangedCallback(attrName, oldValue, newValue) {
2397
- if (oldValue === newValue) {
2398
- // Ignore same values.
2399
- return;
2400
- }
2401
- const propName = attributeToPropMap[attrName];
2402
- if (shared.isUndefined(propName)) {
2403
- if (!shared.isUndefined(superAttributeChangedCallback)) {
2404
- // delegate unknown attributes to the super.
2405
- // Typescript does not like it when you treat the `arguments` object as an array
2406
- // @ts-ignore type-mismatch
2407
- superAttributeChangedCallback.apply(this, arguments);
2408
- }
2409
- return;
2410
- }
2411
- if (!isAttributeLocked(this, attrName)) {
2412
- // Ignore changes triggered by the engine itself during:
2413
- // * diffing when public props are attempting to reflect to the DOM
2414
- // * component via `this.setAttribute()`, should never update the prop
2415
- // Both cases, the setAttribute call is always wrapped by the unlocking of the
2416
- // attribute to be changed
2417
- return;
2418
- }
2419
- // Reflect attribute change to the corresponding property when changed from outside.
2420
- this[propName] = newValue;
2421
- };
2422
- }
2423
- function HTMLBridgeElementFactory(SuperClass, props, methods) {
2424
- let HTMLBridgeElement;
2425
- /**
2426
- * Modern browsers will have all Native Constructors as regular Classes
2427
- * and must be instantiated with the new keyword. In older browsers,
2428
- * specifically IE11, those are objects with a prototype property defined,
2429
- * since they are not supposed to be extended or instantiated with the
2430
- * new keyword. This forking logic supports both cases, specifically because
2431
- * wc.ts relies on the construction path of the bridges to create new
2432
- * fully qualifying web components.
2433
- */
2434
- if (shared.isFunction(SuperClass)) {
2435
- HTMLBridgeElement = class extends SuperClass {
2436
- };
2437
- }
2438
- else {
2439
- HTMLBridgeElement = function () {
2440
- // Bridge classes are not supposed to be instantiated directly in
2441
- // browsers that do not support web components.
2442
- throw new TypeError('Illegal constructor');
2443
- };
2444
- // prototype inheritance dance
2445
- shared.setPrototypeOf(HTMLBridgeElement, SuperClass);
2446
- shared.setPrototypeOf(HTMLBridgeElement.prototype, SuperClass.prototype);
2447
- shared.defineProperty(HTMLBridgeElement.prototype, 'constructor', {
2448
- writable: true,
2449
- configurable: true,
2450
- value: HTMLBridgeElement,
2451
- });
2403
+ return function attributeChangedCallback(attrName, oldValue, newValue) {
2404
+ if (oldValue === newValue) {
2405
+ // Ignore same values.
2406
+ return;
2452
2407
  }
2453
- // generating the hash table for attributes to avoid duplicate fields and facilitate validation
2454
- // and false positives in case of inheritance.
2455
- const attributeToPropMap = shared.create(null);
2456
- const { attributeChangedCallback: superAttributeChangedCallback } = SuperClass.prototype;
2457
- const { observedAttributes: superObservedAttributes = [] } = SuperClass;
2458
- const descriptors = shared.create(null);
2459
- // expose getters and setters for each public props on the new Element Bridge
2460
- for (let i = 0, len = props.length; i < len; i += 1) {
2461
- const propName = props[i];
2462
- attributeToPropMap[shared.htmlPropertyToAttribute(propName)] = propName;
2463
- descriptors[propName] = {
2464
- get: createGetter(propName),
2465
- set: createSetter(propName),
2466
- enumerable: true,
2467
- configurable: true,
2468
- };
2408
+ const propName = attributeToPropMap[attrName];
2409
+ if (shared.isUndefined(propName)) {
2410
+ if (!shared.isUndefined(superAttributeChangedCallback)) {
2411
+ // delegate unknown attributes to the super.
2412
+ // Typescript does not like it when you treat the `arguments` object as an array
2413
+ // @ts-ignore type-mismatch
2414
+ superAttributeChangedCallback.apply(this, arguments);
2415
+ }
2416
+ return;
2469
2417
  }
2470
- // expose public methods as props on the new Element Bridge
2471
- for (let i = 0, len = methods.length; i < len; i += 1) {
2472
- const methodName = methods[i];
2473
- descriptors[methodName] = {
2474
- value: createMethodCaller(methodName),
2475
- writable: true,
2476
- configurable: true,
2477
- };
2418
+ if (!isAttributeLocked(this, attrName)) {
2419
+ // Ignore changes triggered by the engine itself during:
2420
+ // * diffing when public props are attempting to reflect to the DOM
2421
+ // * component via `this.setAttribute()`, should never update the prop
2422
+ // Both cases, the setAttribute call is always wrapped by the unlocking of the
2423
+ // attribute to be changed
2424
+ return;
2478
2425
  }
2479
- // creating a new attributeChangedCallback per bridge because they are bound to the corresponding
2480
- // map of attributes to props. We do this after all other props and methods to avoid the possibility
2481
- // of getting overrule by a class declaration in user-land, and we make it non-writable, non-configurable
2482
- // to preserve this definition.
2483
- descriptors.attributeChangedCallback = {
2484
- value: createAttributeChangedCallback(attributeToPropMap, superAttributeChangedCallback),
2426
+ // Reflect attribute change to the corresponding property when changed from outside.
2427
+ this[propName] = newValue;
2428
+ };
2429
+ }
2430
+ function HTMLBridgeElementFactory(SuperClass, props, methods) {
2431
+ let HTMLBridgeElement;
2432
+ /**
2433
+ * Modern browsers will have all Native Constructors as regular Classes
2434
+ * and must be instantiated with the new keyword. In older browsers,
2435
+ * specifically IE11, those are objects with a prototype property defined,
2436
+ * since they are not supposed to be extended or instantiated with the
2437
+ * new keyword. This forking logic supports both cases, specifically because
2438
+ * wc.ts relies on the construction path of the bridges to create new
2439
+ * fully qualifying web components.
2440
+ */
2441
+ if (shared.isFunction(SuperClass)) {
2442
+ HTMLBridgeElement = class extends SuperClass {};
2443
+ } else {
2444
+ HTMLBridgeElement = function () {
2445
+ // Bridge classes are not supposed to be instantiated directly in
2446
+ // browsers that do not support web components.
2447
+ throw new TypeError('Illegal constructor');
2485
2448
  };
2486
- // Specify attributes for which we want to reflect changes back to their corresponding
2487
- // properties via attributeChangedCallback.
2488
- shared.defineProperty(HTMLBridgeElement, 'observedAttributes', {
2489
- get() {
2490
- return [...superObservedAttributes, ...shared.keys(attributeToPropMap)];
2491
- },
2449
+ // prototype inheritance dance
2450
+ shared.setPrototypeOf(HTMLBridgeElement, SuperClass);
2451
+ shared.setPrototypeOf(HTMLBridgeElement.prototype, SuperClass.prototype);
2452
+ shared.defineProperty(HTMLBridgeElement.prototype, 'constructor', {
2453
+ writable: true,
2454
+ configurable: true,
2455
+ value: HTMLBridgeElement
2492
2456
  });
2493
- shared.defineProperties(HTMLBridgeElement.prototype, descriptors);
2494
- return HTMLBridgeElement;
2457
+ }
2458
+ // generating the hash table for attributes to avoid duplicate fields and facilitate validation
2459
+ // and false positives in case of inheritance.
2460
+ const attributeToPropMap = shared.create(null);
2461
+ const {
2462
+ attributeChangedCallback: superAttributeChangedCallback
2463
+ } = SuperClass.prototype;
2464
+ const {
2465
+ observedAttributes: superObservedAttributes = []
2466
+ } = SuperClass;
2467
+ const descriptors = shared.create(null);
2468
+ // expose getters and setters for each public props on the new Element Bridge
2469
+ for (let i = 0, len = props.length; i < len; i += 1) {
2470
+ const propName = props[i];
2471
+ attributeToPropMap[shared.htmlPropertyToAttribute(propName)] = propName;
2472
+ descriptors[propName] = {
2473
+ get: createGetter(propName),
2474
+ set: createSetter(propName),
2475
+ enumerable: true,
2476
+ configurable: true
2477
+ };
2478
+ }
2479
+ // expose public methods as props on the new Element Bridge
2480
+ for (let i = 0, len = methods.length; i < len; i += 1) {
2481
+ const methodName = methods[i];
2482
+ descriptors[methodName] = {
2483
+ value: createMethodCaller(methodName),
2484
+ writable: true,
2485
+ configurable: true
2486
+ };
2487
+ }
2488
+ // creating a new attributeChangedCallback per bridge because they are bound to the corresponding
2489
+ // map of attributes to props. We do this after all other props and methods to avoid the possibility
2490
+ // of getting overrule by a class declaration in user-land, and we make it non-writable, non-configurable
2491
+ // to preserve this definition.
2492
+ descriptors.attributeChangedCallback = {
2493
+ value: createAttributeChangedCallback(attributeToPropMap, superAttributeChangedCallback)
2494
+ };
2495
+ // Specify attributes for which we want to reflect changes back to their corresponding
2496
+ // properties via attributeChangedCallback.
2497
+ shared.defineProperty(HTMLBridgeElement, 'observedAttributes', {
2498
+ get() {
2499
+ return [...superObservedAttributes, ...shared.keys(attributeToPropMap)];
2500
+ }
2501
+ });
2502
+ shared.defineProperties(HTMLBridgeElement.prototype, descriptors);
2503
+ return HTMLBridgeElement;
2495
2504
  }
2496
2505
  const BaseBridgeElement = HTMLBridgeElementFactory(HTMLElementConstructor, shared.getOwnPropertyNames(HTMLElementOriginalDescriptors), []);
2506
+ if (process.env.IS_BROWSER) {
2507
+ // This ARIA reflection only really makes sense in the browser. On the server, there is no `renderedCallback()`,
2508
+ // so you cannot do e.g. `this.template.querySelector('x-child').ariaBusy = 'true'`. So we don't need to expose
2509
+ // ARIA props outside the LightningElement
2510
+ if (features.lwcRuntimeFlags.DISABLE_ARIA_REFLECTION_POLYFILL) {
2511
+ // If ARIA reflection is not applied globally to Element.prototype, apply it to HTMLBridgeElement.prototype.
2512
+ // This allows `elm.aria*` property accessors to work from outside a component, and to reflect `aria-*` attrs.
2513
+ // This is especially important because the template compiler compiles aria-* attrs on components to aria* props
2514
+ //
2515
+ // Also note that we apply this to BaseBridgeElement.prototype to avoid excessively redefining property
2516
+ // accessors inside the HTMLBridgeElementFactory.
2517
+ ariaReflection.applyAriaReflection(BaseBridgeElement.prototype);
2518
+ }
2519
+ }
2497
2520
  shared.freeze(BaseBridgeElement);
2498
2521
  shared.seal(BaseBridgeElement.prototype);
2499
2522
 
@@ -3875,11 +3898,13 @@ function applyDomManual(elm, vnode) {
3875
3898
  function applyElementRestrictions(elm, vnode) {
3876
3899
  var _a, _b;
3877
3900
  if (process.env.NODE_ENV !== 'production') {
3901
+ const isSynthetic = vnode.owner.shadowMode === 1 /* ShadowMode.Synthetic */;
3878
3902
  const isPortal = vnode.type === 2 /* VNodeType.Element */ && ((_b = (_a = vnode.data.context) === null || _a === void 0 ? void 0 : _a.lwc) === null || _b === void 0 ? void 0 : _b.dom) === "manual" /* LwcDomMode.Manual */;
3879
3903
  const isLight = vnode.owner.renderMode === 0 /* RenderMode.Light */;
3880
3904
  patchElementWithRestrictions(elm, {
3881
3905
  isPortal,
3882
- isLight
3906
+ isLight,
3907
+ isSynthetic
3883
3908
  });
3884
3909
  }
3885
3910
  }
@@ -4295,7 +4320,7 @@ function s(slotName, data, children, slotset) {
4295
4320
  // undefined is for root components, but root components cannot accept slotted content
4296
4321
  setVMBeingRendered(slotset.owner);
4297
4322
  try {
4298
- shared.ArrayPush.apply(newChildren, vnode.factory(data.slotData));
4323
+ shared.ArrayPush.call(newChildren, vnode.factory(data.slotData, data.key));
4299
4324
  }
4300
4325
  finally {
4301
4326
  setVMBeingRendered(vmBeingRenderedInception);
@@ -5175,15 +5200,10 @@ function resetComponentStateWhenRemoved(vm) {
5175
5200
  } = vm;
5176
5201
  if (state !== 2 /* VMState.disconnected */) {
5177
5202
  const {
5178
- oar,
5179
5203
  tro
5180
5204
  } = vm;
5181
5205
  // Making sure that any observing record will not trigger the rehydrated on this vm
5182
5206
  tro.reset();
5183
- // Making sure that any observing accessor record will not trigger the setter to be reinvoked
5184
- for (const key in oar) {
5185
- oar[key].reset();
5186
- }
5187
5207
  runDisconnectedCallback(vm);
5188
5208
  // Spec: https://dom.spec.whatwg.org/#concept-node-remove (step 14-15)
5189
5209
  runChildNodesDisconnectedCallback(vm);
@@ -5236,7 +5256,6 @@ function createVM(elm, ctor, renderer, options) {
5236
5256
  cmpSlots: {
5237
5257
  slotAssignments: shared.create(null)
5238
5258
  },
5239
- oar: shared.create(null),
5240
5259
  cmpTemplate: null,
5241
5260
  hydrated: Boolean(hydrated),
5242
5261
  renderMode: def.renderMode,
@@ -6420,94 +6439,166 @@ function setHooks(hooks) {
6420
6439
  // See @lwc/engine-core/src/framework/template.ts
6421
6440
  const TEMPLATE_PROPS = ['slots', 'stylesheetToken', 'stylesheets', 'renderMode'];
6422
6441
  // Via https://www.npmjs.com/package/object-observer
6423
- const ARRAY_MUTATION_METHODS = [
6424
- 'pop',
6425
- 'push',
6426
- 'shift',
6427
- 'unshift',
6428
- 'reverse',
6429
- 'sort',
6430
- 'fill',
6431
- 'splice',
6432
- 'copyWithin',
6433
- ];
6442
+ const ARRAY_MUTATION_METHODS = ['pop', 'push', 'shift', 'unshift', 'reverse', 'sort', 'fill', 'splice', 'copyWithin'];
6443
+ // Expandos that may be placed on a stylesheet factory function, and which are meaningful to LWC at runtime
6444
+ const STYLESHEET_FUNCTION_EXPANDOS = [
6445
+ // SEE `KEY__SCOPED_CSS` in @lwc/style-compiler
6446
+ '$scoped$'];
6434
6447
  function getOriginalArrayMethod(prop) {
6435
- switch (prop) {
6436
- case 'pop':
6437
- return shared.ArrayPop;
6438
- case 'push':
6439
- return shared.ArrayPush;
6440
- case 'shift':
6441
- return shared.ArrayShift;
6442
- case 'unshift':
6443
- return shared.ArrayUnshift;
6444
- case 'reverse':
6445
- return shared.ArrayReverse;
6446
- case 'sort':
6447
- return shared.ArraySort;
6448
- case 'fill':
6449
- return shared.ArrayFill;
6450
- case 'splice':
6451
- return shared.ArraySplice;
6452
- case 'copyWithin':
6453
- return shared.ArrayCopyWithin;
6454
- }
6448
+ switch (prop) {
6449
+ case 'pop':
6450
+ return shared.ArrayPop;
6451
+ case 'push':
6452
+ return shared.ArrayPush;
6453
+ case 'shift':
6454
+ return shared.ArrayShift;
6455
+ case 'unshift':
6456
+ return shared.ArrayUnshift;
6457
+ case 'reverse':
6458
+ return shared.ArrayReverse;
6459
+ case 'sort':
6460
+ return shared.ArraySort;
6461
+ case 'fill':
6462
+ return shared.ArrayFill;
6463
+ case 'splice':
6464
+ return shared.ArraySplice;
6465
+ case 'copyWithin':
6466
+ return shared.ArrayCopyWithin;
6467
+ }
6455
6468
  }
6456
6469
  let mutationWarningsSilenced = false;
6457
- // Warn if the user tries to mutate tmpl.stylesheets, e.g.:
6470
+ // Warn if the user tries to mutate a stylesheets array, e.g.:
6458
6471
  // `tmpl.stylesheets.push(someStylesheetFunction)`
6459
6472
  function warnOnArrayMutation(stylesheets) {
6460
- // We can't handle users calling Array.prototype.slice.call(tmpl.stylesheets), but
6461
- // we can at least warn when they use the most common mutation methods.
6462
- for (const prop of ARRAY_MUTATION_METHODS) {
6463
- const originalArrayMethod = getOriginalArrayMethod(prop);
6464
- stylesheets[prop] = function arrayMutationWarningWrapper() {
6465
- logError(`Mutating the "stylesheets" array on a template function ` +
6466
- `is deprecated and may be removed in a future version of LWC.`);
6467
- // @ts-ignore
6468
- return originalArrayMethod.apply(this, arguments);
6469
- };
6473
+ // We can't handle users calling Array.prototype.slice.call(tmpl.stylesheets), but
6474
+ // we can at least warn when they use the most common mutation methods.
6475
+ for (const prop of ARRAY_MUTATION_METHODS) {
6476
+ const originalArrayMethod = getOriginalArrayMethod(prop);
6477
+ stylesheets[prop] = function arrayMutationWarningWrapper() {
6478
+ logError(`Mutating the "stylesheets" array on a template function ` + `is deprecated and may be removed in a future version of LWC.`);
6479
+ // @ts-ignore
6480
+ return originalArrayMethod.apply(this, arguments);
6481
+ };
6482
+ }
6483
+ }
6484
+ // Warn if the user tries to mutate a stylesheet factory function, e.g.:
6485
+ // `stylesheet.$scoped$ = true`
6486
+ function warnOnStylesheetFunctionMutation(stylesheet) {
6487
+ // We could warn on other properties, but in practice only certain expandos are meaningful to LWC at runtime
6488
+ for (const prop of STYLESHEET_FUNCTION_EXPANDOS) {
6489
+ let value = stylesheet[prop];
6490
+ shared.defineProperty(stylesheet, prop, {
6491
+ enumerable: true,
6492
+ configurable: true,
6493
+ get() {
6494
+ return value;
6495
+ },
6496
+ set(newValue) {
6497
+ logError(`Dynamically setting the "${prop}" property on a stylesheet function ` + `is deprecated and may be removed in a future version of LWC.`);
6498
+ value = newValue;
6499
+ }
6500
+ });
6501
+ }
6502
+ }
6503
+ // Warn on either array or stylesheet (function) mutation, in a deeply-nested array
6504
+ function warnOnStylesheetsMutation(stylesheets) {
6505
+ traverseStylesheets(stylesheets, subStylesheets => {
6506
+ if (shared.isArray(subStylesheets)) {
6507
+ warnOnArrayMutation(subStylesheets);
6508
+ } else {
6509
+ warnOnStylesheetFunctionMutation(subStylesheets);
6470
6510
  }
6511
+ });
6512
+ }
6513
+ // Deeply freeze the entire array (of arrays) of stylesheet factory functions
6514
+ function deepFreeze(stylesheets) {
6515
+ traverseStylesheets(stylesheets, subStylesheets => {
6516
+ shared.freeze(subStylesheets);
6517
+ });
6518
+ }
6519
+ // Deep-traverse an array (of arrays) of stylesheet factory functions, and call the callback for every array/function
6520
+ function traverseStylesheets(stylesheets, callback) {
6521
+ callback(stylesheets);
6522
+ for (let i = 0; i < stylesheets.length; i++) {
6523
+ const stylesheet = stylesheets[i];
6524
+ if (shared.isArray(stylesheet)) {
6525
+ traverseStylesheets(stylesheet, callback);
6526
+ } else {
6527
+ callback(stylesheet);
6528
+ }
6529
+ }
6471
6530
  }
6472
- // TODO [#2782]: eventually freezeTemplate() will _actually_ freeze the tmpl object. Today it
6473
- // just warns on mutation.
6474
6531
  function freezeTemplate(tmpl) {
6532
+ if (features.lwcRuntimeFlags.ENABLE_FROZEN_TEMPLATE) {
6533
+ // Deep freeze the template
6534
+ shared.freeze(tmpl);
6535
+ if (!shared.isUndefined(tmpl.stylesheets)) {
6536
+ deepFreeze(tmpl.stylesheets);
6537
+ }
6538
+ } else {
6539
+ // TODO [#2782]: remove this flag and delete the legacy behavior
6540
+ // When ENABLE_FROZEN_TEMPLATE is false, then we shim stylesheetTokens on top of stylesheetToken for anyone who
6541
+ // is accessing the old internal API (backwards compat). Details: https://salesforce.quip.com/v1rmAFu2cKAr
6542
+ shared.defineProperty(tmpl, 'stylesheetTokens', {
6543
+ enumerable: true,
6544
+ configurable: true,
6545
+ get() {
6546
+ const {
6547
+ stylesheetToken
6548
+ } = this;
6549
+ if (shared.isUndefined(stylesheetToken)) {
6550
+ return stylesheetToken;
6551
+ }
6552
+ // Shim for the old `stylesheetTokens` property
6553
+ // See https://github.com/salesforce/lwc/pull/2332/files#diff-7901555acef29969adaa6583185b3e9bce475cdc6f23e799a54e0018cb18abaa
6554
+ return {
6555
+ hostAttribute: `${stylesheetToken}-host`,
6556
+ shadowAttribute: stylesheetToken
6557
+ };
6558
+ },
6559
+ set(value) {
6560
+ // If the value is null or some other exotic object, you would be broken anyway in the past
6561
+ // because the engine would try to access hostAttribute/shadowAttribute, which would throw an error.
6562
+ // However it may be undefined in newer versions of LWC, so we need to guard against that case.
6563
+ this.stylesheetToken = shared.isUndefined(value) ? undefined : value.shadowAttribute;
6564
+ }
6565
+ });
6566
+ // When ENABLE_FROZEN_TEMPLATE is false, warn in dev mode whenever someone is mutating the template
6475
6567
  if (process.env.NODE_ENV !== 'production') {
6476
- if (!shared.isUndefined(tmpl.stylesheets)) {
6477
- warnOnArrayMutation(tmpl.stylesheets);
6478
- }
6479
- for (const prop of TEMPLATE_PROPS) {
6480
- let value = tmpl[prop];
6481
- shared.defineProperty(tmpl, prop, {
6482
- enumerable: true,
6483
- configurable: true,
6484
- get() {
6485
- return value;
6486
- },
6487
- set(newValue) {
6488
- if (!mutationWarningsSilenced) {
6489
- logError(`Dynamically setting the "${prop}" property on a template function ` +
6490
- `is deprecated and may be removed in a future version of LWC.`);
6491
- }
6492
- value = newValue;
6493
- },
6494
- });
6495
- }
6496
- const originalDescriptor = shared.getOwnPropertyDescriptor(tmpl, 'stylesheetTokens');
6497
- shared.defineProperty(tmpl, 'stylesheetTokens', {
6498
- enumerable: true,
6499
- configurable: true,
6500
- get: originalDescriptor.get,
6501
- set(value) {
6502
- logError(`Dynamically setting the "stylesheetTokens" property on a template function ` +
6503
- `is deprecated and may be removed in a future version of LWC.`);
6504
- // Avoid logging twice (for both stylesheetToken and stylesheetTokens)
6505
- mutationWarningsSilenced = true;
6506
- originalDescriptor.set.call(this, value);
6507
- mutationWarningsSilenced = false;
6508
- },
6568
+ if (!shared.isUndefined(tmpl.stylesheets)) {
6569
+ warnOnStylesheetsMutation(tmpl.stylesheets);
6570
+ }
6571
+ for (const prop of TEMPLATE_PROPS) {
6572
+ let value = tmpl[prop];
6573
+ shared.defineProperty(tmpl, prop, {
6574
+ enumerable: true,
6575
+ configurable: true,
6576
+ get() {
6577
+ return value;
6578
+ },
6579
+ set(newValue) {
6580
+ if (!mutationWarningsSilenced) {
6581
+ logError(`Dynamically setting the "${prop}" property on a template function ` + `is deprecated and may be removed in a future version of LWC.`);
6582
+ }
6583
+ value = newValue;
6584
+ }
6509
6585
  });
6586
+ }
6587
+ const originalDescriptor = shared.getOwnPropertyDescriptor(tmpl, 'stylesheetTokens');
6588
+ shared.defineProperty(tmpl, 'stylesheetTokens', {
6589
+ enumerable: true,
6590
+ configurable: true,
6591
+ get: originalDescriptor.get,
6592
+ set(value) {
6593
+ logError(`Dynamically setting the "stylesheetTokens" property on a template function ` + `is deprecated and may be removed in a future version of LWC.`);
6594
+ // Avoid logging twice (for both stylesheetToken and stylesheetTokens)
6595
+ mutationWarningsSilenced = true;
6596
+ originalDescriptor.set.call(this, value);
6597
+ mutationWarningsSilenced = false;
6598
+ }
6599
+ });
6510
6600
  }
6601
+ }
6511
6602
  }
6512
6603
 
6513
6604
  /*
@@ -6570,4 +6661,4 @@ exports.swapTemplate = swapTemplate;
6570
6661
  exports.track = track;
6571
6662
  exports.unwrap = unwrap;
6572
6663
  exports.wire = wire;
6573
- /* version: 2.32.0 */
6664
+ /* version: 2.33.0 */