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;
freeze,
getOwnPropertyNames,
isFunction,
isUndefined,
seal,
setPrototypeOf,
} from '@lwc/shared';
import { getAssociatedVM } from './vm';
import { HTMLElementOriginalDescriptors } from './html-properties';
import { reactiveMembrane } from './membrane';
// A bridge descriptor is a descriptor whose job is just to get the component instance
// from the element instance, and get the value or set a new value on the component.
// This means that across different elements, similar names can get the exact same
// descriptor, so we can cache them:
const cachedGetterByKey: Record any> = create(null);
const cachedSetterByKey: Record any> = create(null);
function createGetter(key: string) {
let fn = cachedGetterByKey[key];
if (isUndefined(fn)) {
fn = cachedGetterByKey[key] = function(this: HTMLElement): any {
const vm = getAssociatedVM(this);
const { getHook } = vm;
return getHook(vm.component, key);
};
}
return fn;
}
function createSetter(key: string) {
let fn = cachedSetterByKey[key];
* 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 { create, forEach, getPropertyDescriptor, isUndefined } from '@lwc/shared';
import { defaultDefHTMLPropertyNames } from './attributes';
import { ElementPrototypeAriaPropertyNames } from '../polyfills/aria-properties/main';
/**
* This is a descriptor map that contains
* all standard properties that a Custom Element can support (including AOM properties), which
* determines what kind of capabilities the Base HTML Element and
* Base Lightning Element should support.
*/
export const HTMLElementOriginalDescriptors: PropertyDescriptorMap = create(null);
forEach.call(ElementPrototypeAriaPropertyNames, (propName: string) => {
// Note: intentionally using our in-house getPropertyDescriptor instead of getOwnPropertyDescriptor here because
// in IE11, some properties are on Element.prototype instead of HTMLElement, just to be sure.
const descriptor = getPropertyDescriptor(HTMLElement.prototype, propName);
if (!isUndefined(descriptor)) {
HTMLElementOriginalDescriptors[propName] = descriptor;
}
});
forEach.call(defaultDefHTMLPropertyNames, propName => {
// Note: intentionally using our in-house getPropertyDescriptor instead of getOwnPropertyDescriptor here because
// in IE11, id property is on Element.prototype instead of HTMLElement, and we suspect that more will fall into
// this category, so, better to be sure.
const descriptor = getPropertyDescriptor(HTMLElement.prototype, propName);
if (!isUndefined(descriptor)) {
HTMLElementOriginalDescriptors[propName] = descriptor;
const { isRoot, mode, owner } = options;
idx += 1;
const uninitializedVm: UninitializedVM = {
// component creation index is defined once, and never reset, it can
// be preserved from one insertion to another without any issue
idx,
state: VMState.created,
isScheduled: false,
isDirty: true,
isRoot: isTrue(isRoot),
mode,
def,
owner,
elm,
data: EmptyObject,
context: create(null),
cmpProps: create(null),
cmpTrack: create(null),
cmpSlots: useSyntheticShadow ? create(null) : undefined,
callHook,
setHook,
getHook,
children: EmptyArray,
aChildren: EmptyArray,
velements: EmptyArray,
// Perf optimization to preserve the shape of this obj
cmpTemplate: undefined,
component: undefined,
cmpRoot: undefined,
tro: undefined,
oar: undefined,
};
// component creation index is defined once, and never reset, it can
// be preserved from one insertion to another without any issue
idx,
state: VMState.created,
isScheduled: false,
isDirty: true,
isRoot: isTrue(isRoot),
mode,
def,
owner,
elm,
data: EmptyObject,
context: create(null),
cmpProps: create(null),
cmpTrack: create(null),
cmpSlots: useSyntheticShadow ? create(null) : undefined,
callHook,
setHook,
getHook,
children: EmptyArray,
aChildren: EmptyArray,
velements: EmptyArray,
// Perf optimization to preserve the shape of this obj
cmpTemplate: undefined,
component: undefined,
cmpRoot: undefined,
tro: undefined,
oar: undefined,
};
if (process.env.NODE_ENV !== 'production') {
uninitializedVm.toString = (): string => {
} else {
HTMLBridgeElement = function() {
// Bridge classes are not supposed to be instantiated directly in
// browsers that do not support web components.
throw new TypeError('Illegal constructor');
};
// prototype inheritance dance
setPrototypeOf(HTMLBridgeElement, SuperClass);
setPrototypeOf(HTMLBridgeElement.prototype, SuperClass!.prototype);
defineProperty(HTMLBridgeElement.prototype, 'constructor', {
writable: true,
configurable: true,
value: HTMLBridgeElement,
});
}
const descriptors: PropertyDescriptorMap = create(null);
// expose getters and setters for each public props on the new Element Bridge
for (let i = 0, len = props.length; i < len; i += 1) {
const propName = props[i];
descriptors[propName] = {
get: createGetter(propName),
set: createSetter(propName),
enumerable: true,
configurable: true,
};
}
// expose public methods as props on the new Element Bridge
for (let i = 0, len = methods.length; i < len; i += 1) {
const methodName = methods[i];
descriptors[methodName] = {
value: createMethodCaller(methodName),
writable: true,
export default function apply() {
// https://github.com/w3c/webcomponents/issues/513#issuecomment-224183937
const composedEvents = assign(create(null), {
blur: 1,
focus: 1,
focusin: 1,
focusout: 1,
click: 1,
dblclick: 1,
mousedown: 1,
mouseenter: 1,
mouseleave: 1,
mousemove: 1,
mouseout: 1,
mouseover: 1,
mouseup: 1,
wheel: 1,
beforeinput: 1,
input: 1,
},
},
};
assign(
SyntheticShadowRootDescriptors,
NodePatchDescriptors,
ParentNodePatchDescriptors,
ElementPatchDescriptors,
ShadowRootDescriptors
);
export function SyntheticShadowRoot() {
throw new TypeError('Illegal constructor');
}
SyntheticShadowRoot.prototype = create(DocumentFragment.prototype, SyntheticShadowRootDescriptors);
/**
* This method is only intended to be used in non-production mode in IE11
* and its role is to produce a 1-1 mapping between a shadowRoot instance
* and a comment node that is intended to use to trick the IE11 DevTools
* to show the content of the shadowRoot in the DOM Explorer.
*/
export function getIE11FakeShadowRootPlaceholder(host: Element): Comment {
const shadowRoot = getShadowRoot(host);
// @ts-ignore this $$placeholder$$ is not a security issue because you must
// have access to the shadowRoot in order to extract the fake node, which give
// you access to the same childNodes of the shadowRoot, so, who cares.
let c = shadowRoot.$$placeholder$$;
if (!isUndefined(c)) {
return c;
}
function getEventMap(elm: EventTarget): ListenerMap {
let listenerInfo = customElementToWrappedListeners.get(elm);
if (isUndefined(listenerInfo)) {
listenerInfo = create(null) as ListenerMap;
customElementToWrappedListeners.set(elm, listenerInfo);
}
return listenerInfo;
}
): PropsDef {
if (isUndefined(props) || getOwnPropertyNames(props).length === 0) {
return EmptyObject;
}
return getOwnPropertyNames(props).reduce((propsHash: PropsDef, propName: string): PropsDef => {
const attr = getAttrNameFromPropName(propName);
propsHash[propName] = assign(
{
config: 0,
type: 'any',
attr,
},
props[propName]
);
return propsHash;
}, create(null));
}