Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
/*
* Copyright (c) 2018, salesforce.com, inc.
* All rights reserved.
* SPDX-License-Identifier: MIT
* For full license text, see the LICENSE file in the repo root or https://opensource.org/licenses/MIT
*/
import features, { FeatureFlagLookup, FeatureFlagValue } from './flags';
import { create, isFalse, isTrue, isUndefined } from '@lwc/shared';
const runtimeFlags: FeatureFlagLookup = create(null);
// This function is not whitelisted for use within components and is meant for
// configuring runtime feature flags during app initialization.
function setFeatureFlag(name: string, value: FeatureFlagValue) {
const isBoolean = isTrue(value) || isFalse(value);
if (!isBoolean) {
const message = `Invalid ${typeof value} value specified for the "${name}" flag. Runtime feature flags can only be set to a boolean value.`;
if (process.env.NODE_ENV === 'production') {
// eslint-disable-next-line no-console
console.error(message);
} else {
throw new TypeError(message);
}
}
if (!isUndefined(features[name])) {
runtimeFlags[name] = value;
function initialize() {
let init = (DocumentConstructor as any)[InitializationSlot];
if (isUndefined(init)) {
patchDomApi();
init = () => {
return {
connected: reactWhenConnected,
disconnected: reactWhenDisconnected,
};
};
// Defined as an arrow function to avoid anybody walking the prototype chain from
// accidentally discovering the cached apis
defineProperty(DocumentConstructor, InitializationSlot, { value: init });
}
const cachedApis = init();
reactWhenConnectedCached = cachedApis.connected;
reactWhenDisconnectedCached = cachedApis.disconnected;
}
function setFeatureFlag(name: string, value: FeatureFlagValue) {
const isBoolean = isTrue(value) || isFalse(value);
if (!isBoolean) {
const message = `Invalid ${typeof value} value specified for the "${name}" flag. Runtime feature flags can only be set to a boolean value.`;
if (process.env.NODE_ENV === 'production') {
// eslint-disable-next-line no-console
console.error(message);
} else {
throw new TypeError(message);
}
}
if (!isUndefined(features[name])) {
runtimeFlags[name] = value;
} else {
// eslint-disable-next-line no-console
console.warn(
`LWC feature flag "${name}" is undefined. Possible reasons are that 1) it was misspelled or 2) it was removed from the @lwc/features package.`
);
function createContextWatcher(
vm: VM,
wireDef: WireDef,
callbackWhenContextIsReady: (newContext: ContextValue) => void
) {
const { adapter } = wireDef;
const adapterContextToken = getAdapterToken(adapter);
if (isUndefined(adapterContextToken)) {
return; // no provider found, nothing to be done
}
const {
elm,
context: { wiredConnecting, wiredDisconnecting },
} = vm;
// waiting for the component to be connected to formally request the context via the token
ArrayPush.call(wiredConnecting, () => {
// This event is responsible for connecting the host element with another
// element in the composed path that is providing contextual data. The provider
// must be listening for a special dom event with the name corresponding to the value of
// `adapterContextToken`, which will remain secret and internal to this file only to
// guarantee that the linkage can be forged.
const internalDomEvent = new CustomEvent(adapterContextToken, {
bubbles: true,
composed: true,
function queueReactionsForSingleElement(
elm: Element,
reactionTypes: QualifyingReactionTypes,
reactionQueue: ReactionRecord[]
) {
// Disconnected callback has to be processed before connected callback
if (reactionTypes & 2) {
const reactionRecords = getDisconnectedRecordsForElement(elm);
if (!isUndefined(reactionRecords)) {
queueReactionRecord(reactionQueue, reactionRecords);
}
}
if (reactionTypes & 1) {
const reactionRecords = getConnectedRecordsForElement(elm);
if (!isUndefined(reactionRecords)) {
queueReactionRecord(reactionQueue, reactionRecords);
}
}
}
export default function queueReactionsForSubtree(
rootElm: Element | DocumentFragment,
nodeList: NodeListOf<element>,
reactionTypes: QualifyingReactionTypes,
reactionQueue: ReactionRecord[]
) {
if (process.env.NODE_ENV !== 'production') {
assert.invariant(!isUndefined(rootElm), `Expected a dom node but received undefined`);
}
// Process root node first
queueReactionsForSingleElement(rootElm as any, reactionTypes, reactionQueue);
// If root node has a shadow tree, process its shadow tree
const sr = (rootElm as any).shadowRoot;
if (sr != null) {
// coerce to null, shadowRoot of docFrag will be undefined
queueReactionsForShadowRoot(sr, reactionTypes, reactionQueue);
}
// Process all registered nodes in subtree in pre-order
queueReactionsForNodeList(nodeList, reactionTypes, reactionQueue);
}
</element>
function patchedDisconnect(this: MutationObserver): void {
originalDisconnect.call(this);
// Clear the node to observer reference which is a strong references
const observedNodes = observerToNodesMap.get(this);
if (!isUndefined(observedNodes)) {
forEach.call(observedNodes, observedNode => {
const observers = observedNode[observerLookupField];
if (!isUndefined(observers)) {
const index = ArrayIndexOf.call(observers, this);
if (index !== -1) {
ArraySplice.call(observers, index, 1);
}
}
});
observedNodes.length = 0;
}
}
export function getNonPatchedFilteredArrayOfNodes(
context: Element,
unfilteredNodes: Array
): Array {
let filtered: T[];
const ownerKey = getNodeOwnerKey(context);
// a node inside a shadow.
if (!isUndefined(ownerKey)) {
if (isHostElement(context)) {
// element with shadowRoot attached
const owner = getNodeOwner(context);
if (isNull(owner)) {
filtered = [];
} else if (getNodeKey(context)) {
// it is a custom element, and we should then filter by slotted elements
filtered = getAllSlottedMatches(context, unfilteredNodes);
} else {
// regular element, we should then filter by ownership
filtered = getAllMatches(owner, unfilteredNodes);
}
} else {
// context is handled by lwc, using getNodeNearestOwnerKey to include manually inserted elements in the same shadow.
filtered = ArrayFilter.call(
unfilteredNodes,
}
// Element is inside a shadow but we dont know which one. Use the
// "nearest" owner key to filter by ownership.
const contextNearestOwnerKey = getNodeNearestOwnerKey(this);
const elm = ArrayFind.call(
nodeList,
elm => getNodeNearestOwnerKey(elm) === contextNearestOwnerKey
);
return isUndefined(elm) ? null : elm;
}
} else {
if (!featureFlags.ENABLE_NODE_LIST_PATCH) {
if (!(this instanceof HTMLBodyElement)) {
const elm = nodeList[0];
return isUndefined(elm) ? null : elm;
}
}
// element belonging to the document
const elm = ArrayFind.call(
nodeList,
// TODO [#1222]: remove global bypass
elm => isUndefined(getNodeOwnerKey(elm)) || isGlobalPatchingSkipped(this)
);
return isUndefined(elm) ? null : elm;
}
}
}
if (isFalse(vm.isDirty)) {
// this guarantees that if the component is reused/reinserted,
// it will be re-rendered because we are disconnecting the reactivity
// linking, so mutations are not automatically reflected on the state
// of disconnected components.
vm.isDirty = true;
}
vm.state = VMState.disconnected;
// reporting disconnection
const { disconnected } = Services;
if (disconnected) {
invokeServiceHook(vm, disconnected);
}
const { disconnectedCallback } = vm.def;
if (!isUndefined(disconnectedCallback)) {
if (process.env.NODE_ENV !== 'production') {
startMeasure('disconnectedCallback', vm);
}
invokeComponentCallback(vm, disconnectedCallback);
if (process.env.NODE_ENV !== 'production') {
endMeasure('disconnectedCallback', vm);
}
}
}