@lwc/engine-core 8.1.1 → 8.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Copyright (c) 2024 Salesforce, Inc.
3
3
  */
4
- import { noop, StringToLowerCase, isNull, ArrayPush as ArrayPush$1, ArrayJoin, isFrozen, isUndefined as isUndefined$1, defineProperty, seal, create, isAPIFeatureEnabled, isArray as isArray$1, isFunction as isFunction$1, keys, ArrayFilter, isObject, getOwnPropertyNames as getOwnPropertyNames$1, getOwnPropertySymbols as getOwnPropertySymbols$1, toString as toString$1, isString, ArrayIndexOf, ArrayPop, isFalse, hasOwnProperty as hasOwnProperty$1, entries, AriaPropNameToAttrNameMap, getPropertyDescriptor, forEach, defineProperties, getPrototypeOf as getPrototypeOf$1, setPrototypeOf, assign, assert, freeze, KEY__SYNTHETIC_MODE, getOwnPropertyDescriptor as getOwnPropertyDescriptor$1, LWC_VERSION_COMMENT_REGEX, LWC_VERSION, getOwnPropertyDescriptors, htmlPropertyToAttribute, ArraySlice, ArrayMap, KEY__SCOPED_CSS, ArraySplice, kebabCaseToCamelCase, StringCharCodeAt, XML_NAMESPACE, XLINK_NAMESPACE, StringSlice, isTrue, SVG_NAMESPACE, KEY__SHADOW_STATIC, KEY__SHADOW_RESOLVER, ArraySome, isNumber, StringReplace, StringTrim, ArraySort, ArrayFrom, htmlEscape, StringCharAt, ArrayUnshift, LOWEST_API_VERSION, KEY__NATIVE_GET_ELEMENT_BY_ID, KEY__NATIVE_QUERY_SELECTOR_ALL, ID_REFERENCING_ATTRIBUTES_SET, KEY__SHADOW_TOKEN, StringSplit, arrayEvery, ArrayIncludes, ArrayCopyWithin, ArrayFill, ArrayReverse, ArrayShift } from '@lwc/shared';
4
+ import { noop, StringToLowerCase, isNull, ArrayPush as ArrayPush$1, ArrayJoin, isFrozen, isUndefined as isUndefined$1, defineProperty, seal, create, isAPIFeatureEnabled, isArray as isArray$1, isFunction as isFunction$1, keys, ArrayFilter, isObject, getOwnPropertyNames as getOwnPropertyNames$1, getOwnPropertySymbols as getOwnPropertySymbols$1, toString as toString$1, isString, ArrayIndexOf, ArrayPop, isFalse, hasOwnProperty as hasOwnProperty$1, entries, AriaPropNameToAttrNameMap, getPropertyDescriptor, forEach, defineProperties, getPrototypeOf as getPrototypeOf$1, setPrototypeOf, assign, assert, freeze, KEY__SYNTHETIC_MODE, getOwnPropertyDescriptor as getOwnPropertyDescriptor$1, LWC_VERSION_COMMENT_REGEX, LWC_VERSION, getOwnPropertyDescriptors, htmlPropertyToAttribute, ArraySlice, ArrayMap, KEY__SCOPED_CSS, ArraySplice, kebabCaseToCamelCase, StringCharCodeAt, XML_NAMESPACE, XLINK_NAMESPACE, StringSlice, isTrue, SVG_NAMESPACE, KEY__SHADOW_STATIC, KEY__SHADOW_RESOLVER, ArraySome, isNumber, StringReplace, StringTrim, ArraySort, ArrayFrom, htmlEscape, StringCharAt, ArrayUnshift, LOWEST_API_VERSION, KEY__NATIVE_GET_ELEMENT_BY_ID, KEY__NATIVE_QUERY_SELECTOR_ALL, ID_REFERENCING_ATTRIBUTES_SET, KEY__SHADOW_TOKEN, StringSplit, parseStyleText, arrayEvery, ArrayCopyWithin, ArrayFill, ArrayReverse, ArrayShift } from '@lwc/shared';
5
5
  export { setFeatureFlag, setFeatureFlagForTest } from '@lwc/features';
6
6
 
7
7
  /*
@@ -217,23 +217,6 @@ function guid() {
217
217
  }
218
218
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
219
219
  }
220
- // Borrowed from Vue template compiler.
221
- // https://github.com/vuejs/vue/blob/531371b818b0e31a989a06df43789728f23dc4e8/src/platforms/web/util/style.js#L5-L16
222
- const DECLARATION_DELIMITER = /;(?![^(]*\))/g;
223
- const PROPERTY_DELIMITER = /:(.+)/;
224
- function parseStyleText(cssText) {
225
- const styleMap = {};
226
- const declarations = cssText.split(DECLARATION_DELIMITER);
227
- for (const declaration of declarations) {
228
- if (declaration) {
229
- const [prop, value] = declaration.split(PROPERTY_DELIMITER);
230
- if (prop !== undefined && value !== undefined) {
231
- styleMap[prop.trim()] = value.trim();
232
- }
233
- }
234
- }
235
- return styleMap;
236
- }
237
220
  // Make a shallow copy of an object but omit the given key
238
221
  function cloneAndOmitKey(object, keyToOmit) {
239
222
  const result = {};
@@ -3933,6 +3916,65 @@ function isVStaticPartText(vnode) {
3933
3916
  return vnode.type === 0 /* VStaticPartType.Text */;
3934
3917
  }
3935
3918
 
3919
+ const sanitizedHtmlContentSymbol = Symbol('lwc-get-sanitized-html-content');
3920
+ function isSanitizedHtmlContent(object) {
3921
+ return isObject(object) && !isNull(object) && sanitizedHtmlContentSymbol in object;
3922
+ }
3923
+ function unwrapIfNecessary(object) {
3924
+ return isSanitizedHtmlContent(object) ? object[sanitizedHtmlContentSymbol] : object;
3925
+ }
3926
+ /**
3927
+ * Wrap a pre-sanitized string designated for `.innerHTML` via `lwc:inner-html`
3928
+ * as an object with a Symbol that only we have access to.
3929
+ * @param sanitizedString
3930
+ * @returns SanitizedHtmlContent
3931
+ */
3932
+ function createSanitizedHtmlContent(sanitizedString) {
3933
+ return create(null, {
3934
+ [sanitizedHtmlContentSymbol]: {
3935
+ value: sanitizedString,
3936
+ configurable: false,
3937
+ writable: false,
3938
+ },
3939
+ });
3940
+ }
3941
+ /**
3942
+ * Safely call setProperty on an Element while handling any SanitizedHtmlContent objects correctly
3943
+ *
3944
+ * @param setProperty - renderer.setProperty
3945
+ * @param elm - Element
3946
+ * @param key - key to set
3947
+ * @param value - value to set
3948
+ */
3949
+ function safelySetProperty(setProperty, elm, key, value) {
3950
+ // See W-16614337
3951
+ // we support setting innerHTML to `undefined` because it's inherently safe
3952
+ if ((key === 'innerHTML' || key === 'outerHTML') && !isUndefined$1(value)) {
3953
+ if (isSanitizedHtmlContent(value)) {
3954
+ // it's a SanitizedHtmlContent object
3955
+ setProperty(elm, key, value[sanitizedHtmlContentSymbol]);
3956
+ }
3957
+ else {
3958
+ // not a SanitizedHtmlContent object
3959
+ if (process.env.NODE_ENV !== 'production') {
3960
+ logWarn(`Cannot set property "${key}". Instead, use lwc:inner-html or lwc:dom-manual.`);
3961
+ }
3962
+ }
3963
+ }
3964
+ else {
3965
+ setProperty(elm, key, value);
3966
+ }
3967
+ }
3968
+ /**
3969
+ * Given two objects (likely either a string or a SanitizedHtmlContent object), return true if their
3970
+ * string values are equivalent.
3971
+ * @param first
3972
+ * @param second
3973
+ */
3974
+ function isSanitizedHtmlContentEqual(first, second) {
3975
+ return unwrapIfNecessary(first) === unwrapIfNecessary(second);
3976
+ }
3977
+
3936
3978
  /*
3937
3979
  * Copyright (c) 2018, salesforce.com, inc.
3938
3980
  * All rights reserved.
@@ -3963,7 +4005,7 @@ function patchAttributes(oldVnode, vnode, renderer) {
3963
4005
  // Use kebabCaseToCamelCase directly because we don't want to set props like `ariaLabel` or `tabIndex`
3964
4006
  // on a custom element versus just using the more reliable attribute format.
3965
4007
  if (external && (propName = kebabCaseToCamelCase(key)) in elm) {
3966
- setProperty(elm, propName, cur);
4008
+ safelySetProperty(setProperty, elm, propName, cur);
3967
4009
  }
3968
4010
  else if (StringCharCodeAt.call(key, 3) === ColonCharCode) {
3969
4011
  // Assume xml namespace
@@ -4043,7 +4085,7 @@ function patchProps(oldVnode, vnode, renderer) {
4043
4085
  logWarn(`Unknown public property "${key}" of element <${elm.tagName.toLowerCase()}>. This is either a typo on the corresponding attribute "${htmlPropertyToAttribute(key)}", or the attribute does not exist in this browser or DOM implementation.`);
4044
4086
  }
4045
4087
  }
4046
- setProperty(elm, key, cur);
4088
+ safelySetProperty(setProperty, elm, key, cur);
4047
4089
  }
4048
4090
  }
4049
4091
  }
@@ -5751,7 +5793,8 @@ function setSanitizeHtmlContentHook(newHookImpl) {
5751
5793
  }
5752
5794
  // [s]anitize [h]tml [c]ontent
5753
5795
  function shc(content) {
5754
- return sanitizeHtmlContentHook(content);
5796
+ const sanitizedString = sanitizeHtmlContentHook(content);
5797
+ return createSanitizedHtmlContent(sanitizedString);
5755
5798
  }
5756
5799
  /**
5757
5800
  * [ncls] - Normalize class name attribute.
@@ -7594,31 +7637,41 @@ function textNodeContentsAreEqual(node, vnode, renderer) {
7594
7637
  // Any attribute names specified in that array will not be validated, and the
7595
7638
  // LWC runtime will assume that VDOM attrs and DOM attrs are in sync.
7596
7639
  function getValidationPredicate(elm, renderer, optOutStaticProp) {
7597
- // `data-lwc-host-mutated` is a special attribute added by the SSR engine itself,
7598
- // which does the same thing as an explicit `static validationOptOut = ['attr1', 'attr2']`.
7640
+ // `data-lwc-host-mutated` is a special attribute added by the SSR engine itself, which automatically detects
7641
+ // host mutations during `connectedCallback`.
7599
7642
  const hostMutatedValue = renderer.getAttribute(elm, 'data-lwc-host-mutated');
7600
- if (isString(hostMutatedValue)) {
7601
- const mutatedAttrValues = new Set(StringSplit.call(hostMutatedValue, / /));
7602
- return (attrName) => !mutatedAttrValues.has(attrName);
7603
- }
7604
- if (isUndefined$1(optOutStaticProp)) {
7605
- return (_attrName) => true;
7606
- }
7643
+ const detectedHostMutations = isString(hostMutatedValue)
7644
+ ? new Set(StringSplit.call(hostMutatedValue, / /))
7645
+ : undefined;
7607
7646
  // If validationOptOut is true, no attributes will be checked for correctness
7608
7647
  // and the runtime will assume VDOM attrs and DOM attrs are in sync.
7609
- if (isTrue(optOutStaticProp)) {
7610
- return (_attrName) => false;
7611
- }
7612
- // If validationOptOut is an array of strings, attributes specified in the
7613
- // array will be "opted out". Attributes not specified in the array will still
7614
- // be validated.
7615
- if (isArray$1(optOutStaticProp) && arrayEvery(optOutStaticProp, isString)) {
7616
- return (attrName) => !ArrayIncludes.call(optOutStaticProp, attrName);
7617
- }
7618
- if (process.env.NODE_ENV !== 'production') {
7619
- logWarn('Validation opt out must be `true` or an array of attributes that should not be validated.');
7620
- }
7621
- return (_attrName) => true;
7648
+ const fullOptOut = isTrue(optOutStaticProp);
7649
+ // If validationOptOut is an array of strings, attributes specified in the array will be "opted out". Attributes
7650
+ // not specified in the array will still be validated.
7651
+ const isValidArray = isArray$1(optOutStaticProp) && arrayEvery(optOutStaticProp, isString);
7652
+ const conditionalOptOut = isValidArray ? new Set(optOutStaticProp) : undefined;
7653
+ if (process.env.NODE_ENV !== 'production' &&
7654
+ !isUndefined$1(optOutStaticProp) &&
7655
+ !isTrue(optOutStaticProp) &&
7656
+ !isValidArray) {
7657
+ logWarn('`validationOptOut` must be `true` or an array of attributes that should not be validated.');
7658
+ }
7659
+ return (attrName) => {
7660
+ // Component wants to opt out of all validation
7661
+ if (fullOptOut) {
7662
+ return false;
7663
+ }
7664
+ // Mutations were automatically detected and should be ignored
7665
+ if (!isUndefined$1(detectedHostMutations) && detectedHostMutations.has(attrName)) {
7666
+ return false;
7667
+ }
7668
+ // Component explicitly wants to opt out of certain validations, regardless of auto-detection
7669
+ if (!isUndefined$1(conditionalOptOut) && conditionalOptOut.has(attrName)) {
7670
+ return false;
7671
+ }
7672
+ // Attribute must be validated
7673
+ return true;
7674
+ };
7622
7675
  }
7623
7676
  function hydrateText(node, vnode, renderer) {
7624
7677
  if (!hasCorrectNodeType(vnode, node, 3 /* EnvNodeTypes.TEXT */, renderer)) {
@@ -7649,6 +7702,8 @@ function hydrateComment(node, vnode, renderer) {
7649
7702
  }
7650
7703
  }
7651
7704
  const { setProperty } = renderer;
7705
+ // We only set the `nodeValue` property here (on a comment), so we don't need
7706
+ // to sanitize the content as HTML using `safelySetProperty`
7652
7707
  setProperty(node, NODE_VALUE_PROP, vnode.text ?? null);
7653
7708
  vnode.elm = node;
7654
7709
  return node;
@@ -7695,7 +7750,7 @@ function hydrateElement(elm, vnode, renderer) {
7695
7750
  const { data: { props }, } = vnode;
7696
7751
  const { getProperty } = renderer;
7697
7752
  if (!isUndefined$1(props) && !isUndefined$1(props.innerHTML)) {
7698
- if (getProperty(elm, 'innerHTML') === props.innerHTML) {
7753
+ if (isSanitizedHtmlContentEqual(getProperty(elm, 'innerHTML'), props.innerHTML)) {
7699
7754
  // Do a shallow clone since VNodeData may be shared across VNodes due to hoist optimization
7700
7755
  vnode.data = {
7701
7756
  ...vnode.data,
@@ -7985,7 +8040,7 @@ function validateStyleAttr(vnode, elm, data, renderer) {
7985
8040
  // styleMap is used when style is set to static value.
7986
8041
  for (let i = 0, n = styleDecls.length; i < n; i++) {
7987
8042
  const [prop, value, important] = styleDecls[i];
7988
- expectedStyle.push(`${prop}: ${value + (important ? ' important!' : '')}`);
8043
+ expectedStyle.push(`${prop}: ${value + (important ? ' !important' : '')};`);
7989
8044
  const parsedPropValue = parsedVnodeStyle[prop];
7990
8045
  if (isUndefined$1(parsedPropValue)) {
7991
8046
  nodesAreCompatible = false;
@@ -8000,7 +8055,7 @@ function validateStyleAttr(vnode, elm, data, renderer) {
8000
8055
  if (keys(parsedVnodeStyle).length > styleDecls.length) {
8001
8056
  nodesAreCompatible = false;
8002
8057
  }
8003
- vnodeStyle = ArrayJoin.call(expectedStyle, ';');
8058
+ vnodeStyle = ArrayJoin.call(expectedStyle, ' ');
8004
8059
  }
8005
8060
  if (!nodesAreCompatible) {
8006
8061
  if (process.env.NODE_ENV !== 'production') {
@@ -8369,5 +8424,5 @@ function readonly(obj) {
8369
8424
  }
8370
8425
 
8371
8426
  export { LightningElement, profilerControl as __unstable__ProfilerControl, reportingControl as __unstable__ReportingControl, api$1 as api, computeShadowAndRenderMode, connectRootElement, createContextProviderWithRegister, createVM, disconnectRootElement, freezeTemplate, getAssociatedVMIfPresent, getComponentAPIVersion, getComponentConstructor, getComponentDef, getComponentHtmlPrototype, hydrateRoot, isComponentConstructor, parseFragment, parseSVGFragment, readonly, registerComponent, registerDecorators, registerTemplate, runFormAssociatedCallback, runFormDisabledCallback, runFormResetCallback, runFormStateRestoreCallback, sanitizeAttribute, setHooks, shouldBeFormAssociated, swapComponent, swapStyle, swapTemplate, track, unwrap, wire };
8372
- /** version: 8.1.1 */
8427
+ /** version: 8.1.3 */
8373
8428
  //# sourceMappingURL=index.js.map