diff --git a/src/app-data/index.ts b/src/app-data/index.ts index 2ceae30adea..47d3f392881 100644 --- a/src/app-data/index.ts +++ b/src/app-data/index.ts @@ -59,6 +59,7 @@ export const BUILD: BuildConditionals = { lazyLoad: false, profile: false, slotRelocation: true, + // TODO: Remove code related to deprecated `appendChildSlotFix` field. appendChildSlotFix: false, cloneNodeFix: false, hydratedAttribute: false, @@ -66,9 +67,11 @@ export const BUILD: BuildConditionals = { // TODO(STENCIL-663): Remove code related to deprecated `safari10` field. safari10: false, scriptDataOpts: false, + // TODO: Remove code related to deprecated `scopedSlotTextContentFix` field. scopedSlotTextContentFix: false, // TODO(STENCIL-662): Remove code related to deprecated shadowDomShim field shadowDomShim: false, + // TODO: Remove code related to deprecated `slotChildNodesFix` field. slotChildNodesFix: false, invisiblePrehydration: true, propBoolean: true, diff --git a/src/compiler/app-core/app-data.ts b/src/compiler/app-core/app-data.ts index 102cab5f40e..429e4c66e3e 100644 --- a/src/compiler/app-core/app-data.ts +++ b/src/compiler/app-core/app-data.ts @@ -146,7 +146,9 @@ export const updateBuildConditionals = (config: Config, b: BuildConditionals) => b.constructableCSS = !b.hotModuleReplacement || !!config._isTesting; b.asyncLoading = !!(b.asyncLoading || b.lazyLoad || b.taskQueue || b.initializeNextTick); b.cssAnnotations = true; + // TODO: Remove code related to deprecated `appendChildSlotFix` field. b.appendChildSlotFix = config.extras.appendChildSlotFix; + // TODO: Remove code related to deprecated `slotChildNodesFix` field. b.slotChildNodesFix = config.extras.slotChildNodesFix; b.cloneNodeFix = config.extras.cloneNodeFix; // TODO(STENCIL-661): Remove code related to the dynamic import shim @@ -154,6 +156,7 @@ export const updateBuildConditionals = (config: Config, b: BuildConditionals) => b.lifecycleDOMEvents = !!(b.isDebug || config._isTesting || config.extras.lifecycleDOMEvents); // TODO(STENCIL-663): Remove code related to deprecated `safari10` field. b.safari10 = config.extras.__deprecated__safari10; + // TODO: Remove code related to deprecated `scopedSlotTextContentFix` field. b.scopedSlotTextContentFix = !!config.extras.scopedSlotTextContentFix; b.scriptDataOpts = config.extras.scriptDataOpts; // TODO(STENCIL-662): Remove code related to deprecated shadowDomShim field diff --git a/src/compiler/config/test/validate-config.spec.ts b/src/compiler/config/test/validate-config.spec.ts index 38dea271ccd..cfb81597998 100644 --- a/src/compiler/config/test/validate-config.spec.ts +++ b/src/compiler/config/test/validate-config.spec.ts @@ -385,6 +385,7 @@ describe('validation', () => { it('should set extras defaults', () => { const { config } = validateConfig(userConfig, bootstrapConfig); + // TODO: Remove code related to deprecated `appendChildSlotFix` field. expect(config.extras.appendChildSlotFix).toBe(false); expect(config.extras.cloneNodeFix).toBe(false); // TODO(STENCIL-659): Remove code implementing the CSS variable shim @@ -397,6 +398,7 @@ describe('validation', () => { expect(config.extras.scriptDataOpts).toBe(false); // TODO(STENCIL-662): Remove code related to deprecated shadowDomShim field expect(config.extras.__deprecated__shadowDomShim).toBe(false); + // TODO: Remove code related to deprecated `slotChildNodesFix` field. expect(config.extras.slotChildNodesFix).toBe(false); expect(config.extras.initializeNextTick).toBe(false); expect(config.extras.tagNameTransform).toBe(false); diff --git a/src/compiler/config/validate-config.ts b/src/compiler/config/validate-config.ts index e18f60d3af2..ec68f92bc2f 100644 --- a/src/compiler/config/validate-config.ts +++ b/src/compiler/config/validate-config.ts @@ -102,6 +102,7 @@ export const validateConfig = ( } validatedConfig.extras = validatedConfig.extras || {}; + // TODO: Remove code related to deprecated `appendChildSlotFix` field. validatedConfig.extras.appendChildSlotFix = !!validatedConfig.extras.appendChildSlotFix; validatedConfig.extras.cloneNodeFix = !!validatedConfig.extras.cloneNodeFix; // TODO(STENCIL-659): Remove code implementing the CSS variable shim diff --git a/src/compiler/output-targets/dist-hydrate-script/generate-hydrate-app.ts b/src/compiler/output-targets/dist-hydrate-script/generate-hydrate-app.ts index c84449a81b7..636d9af535d 100644 --- a/src/compiler/output-targets/dist-hydrate-script/generate-hydrate-app.ts +++ b/src/compiler/output-targets/dist-hydrate-script/generate-hydrate-app.ts @@ -135,7 +135,9 @@ const getHydrateBuildConditionals = (config: d.ValidatedConfig, cmps: d.Componen build.devTools = false; build.hotModuleReplacement = false; build.cloneNodeFix = false; + // TODO: Remove code related to deprecated `appendChildSlotFix` field. build.appendChildSlotFix = false; + // TODO: Remove code related to deprecated `slotChildNodesFix` field. build.slotChildNodesFix = false; // TODO(STENCIL-663): Remove code related to deprecated `safari10` field. build.safari10 = false; diff --git a/src/compiler/output-targets/dist-hydrate-script/hydrate-build-conditionals.ts b/src/compiler/output-targets/dist-hydrate-script/hydrate-build-conditionals.ts index d5485c3c440..c601ad910e5 100644 --- a/src/compiler/output-targets/dist-hydrate-script/hydrate-build-conditionals.ts +++ b/src/compiler/output-targets/dist-hydrate-script/hydrate-build-conditionals.ts @@ -21,8 +21,11 @@ export const getHydrateBuildConditionals = (cmps: d.ComponentCompilerMeta[]) => build.member = true; build.constructableCSS = false; build.asyncLoading = true; + // TODO: Remove code related to deprecated `appendChildSlotFix` field. build.appendChildSlotFix = false; + // TODO: Remove code related to deprecated `slotChildNodesFix` field. build.slotChildNodesFix = false; + build.asyncLoading = true; build.cloneNodeFix = false; build.cssAnnotations = true; // TODO(STENCIL-662): Remove code related to deprecated shadowDomShim field diff --git a/src/declarations/stencil-private.ts b/src/declarations/stencil-private.ts index 56fe5dce13c..d5c4c2c63bb 100644 --- a/src/declarations/stencil-private.ts +++ b/src/declarations/stencil-private.ts @@ -173,9 +173,12 @@ export interface BuildConditionals extends Partial { // TODO(STENCIL-659): Remove code implementing the CSS variable shim cssVarShim?: boolean; constructableCSS?: boolean; - appendChildSlotFix?: boolean; - slotChildNodesFix?: boolean; - scopedSlotTextContentFix?: boolean; + // TODO: Remove code related to deprecated `appendChildSlotFix` field. + appendChildSlotFix: boolean; + // TODO: Remove code related to deprecated `slotChildNodesFix` field. + slotChildNodesFix: boolean; + // TODO: Remove code related to deprecated `scopedSlotTextContentFix` field. + scopedSlotTextContentFix: boolean; cloneNodeFix?: boolean; // TODO(STENCIL-661): Remove code related to the dynamic import shim dynamicImportShim?: boolean; @@ -1267,6 +1270,22 @@ export interface HostElement extends HTMLElement { disconnectedCallback?: () => void; host?: Element; forceUpdate?: () => void; + readonly __childNodes?: NodeListOf; + readonly __children?: HTMLCollectionOf; + readonly __childElementCount?: number; + readonly __firstChild?: ChildNode | null; + readonly __lastChild?: ChildNode | null; + __innerHTML?: string; + __innerText?: string; + __textContent?: string; + __insertBefore?: (node: T, child: Node | null) => T; + __append?: (...nodes: (Node | string)[]) => void; + __prepend?: (...nodes: (Node | string)[]) => void; + __appendChild?: (newChild: T) => T; + __replaceChildren?: (...nodes: (Node | string)[]) => void; + __insertAdjacentElement?: (position: InsertPosition, insertedElement: Element) => Element | null; + __insertAdjacentHTML?: (where: InsertPosition, html: string) => void; + __insertAdjacentText?: (where: InsertPosition, text: string) => void; // "s-" prefixed properties should not be property renamed // and should be common between all versions of stencil @@ -1566,6 +1585,26 @@ export interface RenderNode extends HostElement { */ ['s-sn']?: string; + /** + * Parent slot name + */ + ['s-psn']?: string; + + /** + * Is a slot fallback node + */ + ['s-sf']?: boolean; + + /** + * Slot has fallback nodes + */ + ['s-hsf']?: boolean; + + /** + * Slot fallback node text content + */ + ['s-sfc']?: string; + /** * Host element tag name: * The tag name of the host element that this @@ -1581,6 +1620,12 @@ export interface RenderNode extends HostElement { */ ['s-ol']?: RenderNode; + /** + * Original Order: + * A number representing the order of a slotted node + */ + ['s-oo']?: number; + /** * Node reference: * This is a reference for a original location node diff --git a/src/declarations/stencil-public-compiler.ts b/src/declarations/stencil-public-compiler.ts index a8c74a8c529..47acba69db7 100644 --- a/src/declarations/stencil-public-compiler.ts +++ b/src/declarations/stencil-public-compiler.ts @@ -260,12 +260,15 @@ export interface StencilConfig { } export interface ConfigExtras { + // TODO: Remove code related to deprecated `appendChildSlotFix` field. /** * By default, the slot polyfill does not update `appendChild()` so that it appends * new child nodes into the correct child slot like how shadow dom works. This is an opt-in * polyfill for those who need it when using `element.appendChild(node)` and expecting the * child to be appended in the same location shadow dom would. This is not required for * IE11 or Edge 18, but can be enabled if the app is using `appendChild()`. Defaults to `false`. + * + * @deprecated This is now automatically applied when components do not use `shadow: true` */ appendChildSlotFix?: boolean; @@ -338,9 +341,12 @@ export interface ConfigExtras { */ scriptDataOpts?: boolean; + // TODO: Remove code related to deprecated `scopedSlotTextContentFix` field. /** * Experimental flag to align the behavior of invoking `textContent` on a scoped component to act more like a * component that uses the shadow DOM. Defaults to `false` + * + * @deprecated - this is now automatically applied when components do not use `shadow: true` */ scopedSlotTextContentFix?: boolean; @@ -364,11 +370,14 @@ export interface ConfigExtras { */ initializeNextTick?: boolean; + // TODO: Remove code related to deprecated `slotChildNodesFix` field. /** * For browsers that do not support shadow dom (IE11 and Edge 18 and below), slot is polyfilled * to simulate the same behavior. However, the host element's `childNodes` and `children` * getters are not patched to only show the child nodes and elements of the default slot. * Defaults to `false`. + * + * @deprecated - this is now automatically applied when components do not use `shadow: true` */ slotChildNodesFix?: boolean; diff --git a/src/declarations/stencil-public-runtime.ts b/src/declarations/stencil-public-runtime.ts index 1f5b6938e77..179c2b88839 100644 --- a/src/declarations/stencil-public-runtime.ts +++ b/src/declarations/stencil-public-runtime.ts @@ -332,6 +332,19 @@ export declare function getRenderingRef(): any; export interface HTMLStencilElement extends HTMLElement { componentOnReady(): Promise; + readonly __childNodes?: NodeListOf; + readonly __children?: HTMLCollectionOf; + readonly __childElementCount?: number; + __innerHTML?: string; + __innerText?: string; + __textContent?: string; + __append?: (...nodes: (Node | string)[]) => void; + __prepend?: (...nodes: (Node | string)[]) => void; + __appendChild?: (newChild: T) => T; + __replaceChildren?: (...nodes: (Node | string)[]) => void; + __insertAdjacentElement?: (position: InsertPosition, insertedElement: Element) => Element | null; + __insertAdjacentHTML?: (where: InsertPosition, html: string) => void; + __insertAdjacentText?: (where: InsertPosition, text: string) => void; } /** @@ -620,9 +633,9 @@ export declare function h(sel: any, data: VNodeData | null, children: VNode): VN */ export interface VNode { $flags$: number; - $tag$: string | number | Function; + $tag$: string | number | Function | null; $elm$: any; - $text$: string; + $text$: string | null; $children$: VNode[]; $attrs$?: any; $name$?: string; diff --git a/src/hydrate/runner/create-window.ts b/src/hydrate/runner/create-window.ts index b14b3d70e93..d9803fa6de6 100644 --- a/src/hydrate/runner/create-window.ts +++ b/src/hydrate/runner/create-window.ts @@ -1,14 +1,14 @@ import { cloneWindow, MockWindow } from '@stencil/core/mock-doc'; -const templateWindows = new Map(); +const templateWindows = new Map(); export function createWindowFromHtml(templateHtml: string, uniqueId: string) { let templateWindow = templateWindows.get(uniqueId); if (templateWindow == null) { - templateWindow = new MockWindow(templateHtml) as any; + templateWindow = new MockWindow(templateHtml); templateWindows.set(uniqueId, templateWindow); } - const win = cloneWindow(templateWindow); - return win as any; + const win = cloneWindow(templateWindow as any); + return win; } diff --git a/src/mock-doc/custom-element-registry.ts b/src/mock-doc/custom-element-registry.ts index 233f50fe413..b56ff1bdf9f 100644 --- a/src/mock-doc/custom-element-registry.ts +++ b/src/mock-doc/custom-element-registry.ts @@ -150,7 +150,7 @@ export function createCustomElement(customElements: MockCustomElementRegistry, o proxyElements.set(host, elm); - return host; + return elm; } const proxyElements = new WeakMap(); diff --git a/src/runtime/bootstrap-custom-element.ts b/src/runtime/bootstrap-custom-element.ts index d9a95a9dffb..9fb863b2677 100644 --- a/src/runtime/bootstrap-custom-element.ts +++ b/src/runtime/bootstrap-custom-element.ts @@ -5,6 +5,7 @@ import { CMP_FLAGS } from '@utils'; import type * as d from '../declarations'; import { connectedCallback } from './connected-callback'; import { disconnectedCallback } from './disconnected-callback'; +import { patchCloneNode, patchPseudoShadowDom } from './dom-extras'; import { computeMode } from './mode'; import { proxyComponent } from './proxy-component'; import { PROXY_FLAGS } from './runtime-constants'; @@ -36,6 +37,16 @@ export const proxyCustomElement = (Cstr: any, compactMeta: d.ComponentRuntimeMet cmpMeta.$flags$ |= CMP_FLAGS.needsShadowDomShim; } + if ( + cmpMeta.$flags$ & CMP_FLAGS.hasSlotRelocation || + (cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation && CMP_FLAGS.needsShadowDomShim) + ) { + patchPseudoShadowDom(Cstr.prototype); + if (BUILD.cloneNodeFix) { + patchCloneNode(Cstr.prototype); + } + } + const originalConnectedCallback = Cstr.prototype.connectedCallback; const originalDisconnectedCallback = Cstr.prototype.disconnectedCallback; Object.assign(Cstr.prototype, { @@ -79,7 +90,7 @@ export const forceModeUpdate = (elm: d.RenderNode) => { const mode = computeMode(elm); const hostRef = getHostRef(elm); - if (hostRef.$modeName$ !== mode) { + if (hostRef && hostRef.$modeName$ !== mode) { const cmpMeta = hostRef.$cmpMeta$; const oldScopeId = elm['s-sc']; const scopeId = getScopeId(cmpMeta, mode); diff --git a/src/runtime/bootstrap-lazy.ts b/src/runtime/bootstrap-lazy.ts index 4c9a7bb5164..67e38c2f88a 100644 --- a/src/runtime/bootstrap-lazy.ts +++ b/src/runtime/bootstrap-lazy.ts @@ -5,13 +5,15 @@ import { CMP_FLAGS, queryNonceMetaTagContent } from '@utils'; import type * as d from '../declarations'; import { connectedCallback } from './connected-callback'; import { disconnectedCallback } from './disconnected-callback'; -import { patchChildSlotNodes, patchCloneNode, patchSlotAppendChild, patchTextContent } from './dom-extras'; +import { patchCloneNode, patchPseudoShadowDom } from './dom-extras'; import { hmrStart } from './hmr-component'; +import { computeMode } from './mode'; import { createTime, installDevTools } from './profile'; import { proxyComponent } from './proxy-component'; import { HYDRATED_CSS, HYDRATED_STYLE_ID, PLATFORM_FLAGS, PROXY_FLAGS } from './runtime-constants'; -import { convertScopedToShadow, registerStyle } from './styles'; +import { convertScopedToShadow, getScopeId, registerStyle } from './styles'; import { appDidLoad } from './update-component'; + export { setNonce } from '@platform'; export const bootstrapLazy = (lazyBundles: d.LazyBundlesRuntimeData, options: d.CustomElementsDefineOptions = {}) => { @@ -31,7 +33,6 @@ export const bootstrapLazy = (lazyBundles: d.LazyBundlesRuntimeData, options: d. const styles = /*@__PURE__*/ doc.querySelectorAll(`[${HYDRATED_STYLE_ID}]`); let appLoadFallback: any; let isBootstrapping = true; - let i = 0; Object.assign(plt, options); plt.$resourcesUrl$ = new URL(options.resourcesUrl || './', doc.baseURI).href; @@ -45,11 +46,6 @@ export const bootstrapLazy = (lazyBundles: d.LazyBundlesRuntimeData, options: d. // async queue. This will improve the first input delay plt.$flags$ |= PLATFORM_FLAGS.appLoaded; } - if (BUILD.hydrateClientSide && BUILD.shadowDom) { - for (; i < styles.length; i++) { - registerStyle(styles[i].getAttribute(HYDRATED_STYLE_ID), convertScopedToShadow(styles[i].innerHTML), true); - } - } lazyBundles.map((lazyBundle) => { lazyBundle[1].map((compactMeta) => { @@ -89,6 +85,19 @@ export const bootstrapLazy = (lazyBundles: d.LazyBundlesRuntimeData, options: d. super(self); self = this; + if (BUILD.hydrateClientSide && BUILD.shadowDom) { + const scopeId = getScopeId(cmpMeta, computeMode(self)); + const style = Array.from(styles).find((style) => style.getAttribute(HYDRATED_STYLE_ID) === scopeId); + + if (style) { + if (cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) { + registerStyle(scopeId, convertScopedToShadow(style.innerHTML), true); + } else { + registerStyle(scopeId, style.innerHTML, false); + } + } + } + registerHost(self, cmpMeta); if (BUILD.shadowDom && cmpMeta.$flags$ & CMP_FLAGS.shadowDomEncapsulation) { // this component is using shadow dom @@ -108,9 +117,6 @@ export const bootstrapLazy = (lazyBundles: d.LazyBundlesRuntimeData, options: d. (self as any).shadowRoot = self; } } - if (BUILD.slotChildNodesFix) { - patchChildSlotNodes(self, cmpMeta); - } } connectedCallback() { @@ -135,12 +141,15 @@ export const bootstrapLazy = (lazyBundles: d.LazyBundlesRuntimeData, options: d. } }; - if (BUILD.cloneNodeFix) { - patchCloneNode(HostElement.prototype); - } - - if (BUILD.appendChildSlotFix) { - patchSlotAppendChild(HostElement.prototype); + if ( + !BUILD.hydrateServerSide && + (cmpMeta.$flags$ & CMP_FLAGS.hasSlotRelocation || + cmpMeta.$flags$ & (CMP_FLAGS.shadowDomEncapsulation && CMP_FLAGS.needsShadowDomShim)) + ) { + patchPseudoShadowDom(HostElement.prototype); + if (BUILD.cloneNodeFix) { + patchCloneNode(HostElement.prototype); + } } if (BUILD.hotModuleReplacement) { @@ -149,10 +158,6 @@ export const bootstrapLazy = (lazyBundles: d.LazyBundlesRuntimeData, options: d. }; } - if (BUILD.scopedSlotTextContentFix) { - patchTextContent(HostElement.prototype, cmpMeta); - } - cmpMeta.$lazyBundleId$ = lazyBundle[0]; if (!exclude.includes(tagName) && !customElements.get(tagName)) { diff --git a/src/runtime/client-hydrate.ts b/src/runtime/client-hydrate.ts index c0d948adcd5..9db0ed849d1 100644 --- a/src/runtime/client-hydrate.ts +++ b/src/runtime/client-hydrate.ts @@ -1,19 +1,44 @@ import { BUILD } from '@app-data'; -import { doc, plt, supportsShadow } from '@platform'; +import { doc, plt } from '@platform'; import type * as d from '../declarations'; +import { addSlotRelocateNode, patchNextPrev } from './dom-extras'; import { createTime } from './profile'; import { CONTENT_REF_ID, HYDRATE_CHILD_ID, HYDRATE_ID, + HYDRATED_SLOT_FALLBACK_ID, NODE_TYPE, ORG_LOCATION_ID, SLOT_NODE_ID, TEXT_NODE_ID, } from './runtime-constants'; +import { COMMENT_NODE_ID } from './runtime-constants'; import { newVNode } from './vdom/h'; +interface RenderNodeData extends d.VNode { + $hostId$: string; + $nodeId$: string; + $depth$: string; + $index$: string; +} + +type SlottedNodes = Array<{ slot: d.RenderNode; node: d.RenderNode; hostId: string }>; + +/** + * Takes an SSR rendered document, as annotated by 'vdom-annotations.ts' and: + * 1) Recreate an accurate VDOM tree to reconcile with during 'vdom-render.ts' + * (a failure to do so will result in DOM nodes being duplicated when rendering) + * 2) Add `shadow: true` DOM trees to their document-fragment + * 3) Move slotted nodes out of shadowDOMs + * 4) Add meta nodes to non-shadow DOMs and their 'slotted' nodes + * + * @param hostElm - the current custom element being hydrated + * @param tagName - the custom element's tag + * @param hostId - a unique custom element id + * @param hostRef - the VNode representing this custom element + */ export const initializeClientHydrate = ( hostElm: d.HostElement, tagName: string, @@ -24,49 +49,186 @@ export const initializeClientHydrate = ( const shadowRoot = hostElm.shadowRoot; const childRenderNodes: RenderNodeData[] = []; const slotNodes: RenderNodeData[] = []; + const slottedNodes: SlottedNodes[] = []; const shadowRootNodes: d.RenderNode[] = BUILD.shadowDom && shadowRoot ? [] : null; - const vnode: d.VNode = (hostRef.$vnode$ = newVNode(tagName, null)); + const vnode: d.VNode = newVNode(tagName, null); + vnode.$elm$ = hostElm; if (!plt.$orgLocNodes$) { + // this is the first pass over of this whole document + // does a quick scrape to construct a 'bare-bones' tree of + // what elements we have and where content has been moved from initializeDocumentHydrate(doc.body, (plt.$orgLocNodes$ = new Map())); } hostElm[HYDRATE_ID] = hostId; hostElm.removeAttribute(HYDRATE_ID); - clientHydrate(vnode, childRenderNodes, slotNodes, shadowRootNodes, hostElm, hostElm, hostId); - - childRenderNodes.map((c) => { - const orgLocationId = c.$hostId$ + '.' + c.$nodeId$; + hostRef.$vnode$ = clientHydrate( + vnode, + childRenderNodes, + slotNodes, + shadowRootNodes, + hostElm, + hostElm, + hostId, + slottedNodes + ); + + let crIndex = 0; + const crLength = childRenderNodes.length; + let childRenderNode: RenderNodeData; + + // Steps through childNodes we found. + // If moved from an original location (by nature of being rendered in SSR markup) + // we might be able to move it back there now, + // so slotted nodes don't get added to internal shadowDOMs + for (crIndex; crIndex < crLength; crIndex++) { + childRenderNode = childRenderNodes[crIndex]; + + const orgLocationId = childRenderNode.$hostId$ + '.' + childRenderNode.$nodeId$; const orgLocationNode = plt.$orgLocNodes$.get(orgLocationId); - const node = c.$elm$ as d.RenderNode; - - if (orgLocationNode && supportsShadow && orgLocationNode['s-en'] === '') { - orgLocationNode.parentNode.insertBefore(node, orgLocationNode.nextSibling); - } + const node = childRenderNode.$elm$ as d.RenderNode; if (!shadowRoot) { - node['s-hn'] = tagName; - - if (orgLocationNode) { - node['s-ol'] = orgLocationNode; - node['s-ol']['s-nr'] = node; + node['s-hn'] = tagName.toUpperCase(); + + if (childRenderNode.$tag$ === 'slot') { + // if this is a 'mock slot' + // add it's content position reference now. + // otherwise vdom-render will try to add nodes to it + // (it's a comment node so will error) + node['s-cr'] = hostElm['s-cr']; } } + if (orgLocationNode && orgLocationNode.isConnected) { + if (shadowRoot && orgLocationNode['s-en'] === '') { + // if this node is within a shadowDOM, with an original location home + // we're safe to move it now + orgLocationNode.parentNode.insertBefore(node, orgLocationNode.nextSibling); + } + // Remove original location / slot reference comment now regardless: + // 1) Stops SSR frameworks complaining about mismatches + // 2) is un-required for non-shadow, slotted nodes as + // we'll add all the meta nodes we need when we deal with *all* slotted nodes ↓↓↓ + orgLocationNode.parentNode.removeChild(orgLocationNode); + + if (!shadowRoot) { + // Add the original order of this node. + // we'll use it later to make sure slotted nodes + // get added in the right, original order + node['s-oo'] = parseInt(childRenderNode.$nodeId$); + } + } + // remove the original location from the map plt.$orgLocNodes$.delete(orgLocationId); - }); + } + + const hosts: d.HostElement[] = []; + let snIndex = 0; + const snLen = slottedNodes.length; + let slotGroup: SlottedNodes; + let snGroupIdx: number; + let snGroupLen: number; + let slottedItem: SlottedNodes[0]; + + // Loops through all the slotted nodes we found while + // stepping through this component + for (snIndex; snIndex < snLen; snIndex++) { + slotGroup = slottedNodes[snIndex]; + + if (!slotGroup || !slotGroup.length) continue; + + snGroupLen = slotGroup.length; + snGroupIdx = 0; + + for (snGroupIdx; snGroupIdx < snGroupLen; snGroupIdx++) { + slottedItem = slotGroup[snGroupIdx]; + + if (!hosts[slottedItem.hostId as any]) { + // cache this host for other grouped slotted nodes + hosts[slottedItem.hostId as any] = plt.$orgLocNodes$.get(slottedItem.hostId); + } + // this shouldn't happen + // as we collect all the custom elements first in `initializeDocumentHydrate` + if (!hosts[slottedItem.hostId as any]) continue; + + const hostEle = hosts[slottedItem.hostId as any]; + + // this node is either slotted in a non-shadow host, OR + // *that* host is nested in a non-shadow host + if (!hostEle.shadowRoot || !shadowRoot) { + // try to set an appropriate content position reference + // (CR) node for this host element + + // a CR already set on the host? + slottedItem.slot['s-cr'] = hostEle['s-cr']; + + if (!slottedItem.slot['s-cr'] && hostEle.shadowRoot) { + // host is shadowDOM - just use the host itself as the CR for native slotting + slottedItem.slot['s-cr'] = hostEle; + } else { + // if all else fails - just set the CR as the first child + // (9/10 if node['s-cr'] hasn't been set, the node will be at the element root) + const hostChildren = hostEle.__childNodes || hostEle.childNodes; + slottedItem.slot['s-cr'] = hostChildren[0] as d.RenderNode; + } + // create our original location node + addSlotRelocateNode(slottedItem.node, slottedItem.slot, slottedItem.node['s-oo']); + + // patch this node for accessors like `nextSibling` (et al) + patchNextPrev(slottedItem.node); + } + + if (hostEle.shadowRoot && slottedItem.node.parentElement !== hostEle) { + // shadowDOM - move the item to the element root for + // native slotting + hostEle.appendChild(slottedItem.node); + } + } + } if (BUILD.shadowDom && shadowRoot) { - shadowRootNodes.map((shadowRootNode) => { - if (shadowRootNode) { - shadowRoot.appendChild(shadowRootNode as any); + // add all the root nodes in the shadowDOM + // (a root node can have a whole nested DOM tree) + let rnIdex = 0; + const rnLen = shadowRootNodes.length; + for (rnIdex; rnIdex < rnLen; rnIdex++) { + shadowRoot.appendChild(shadowRootNodes[rnIdex] as any); + } + + // tidy up left-over / unnecessary comments to stop + // frameworks complaining about DOM mismatches + Array.from(hostElm.childNodes).forEach((node) => { + if (node.nodeType === NODE_TYPE.CommentNode && typeof (node as d.RenderNode)['s-sn'] !== 'string') { + node.parentNode.removeChild(node); } }); } + + hostRef.$hostElement$ = hostElm; endHydrate(); }; +/** + * Recursively step through a nodes' SSR DOM. + * Constructs a VDOM. Finds and adds nodes to master arrays + * (`childRenderNodes`, `shadowRootNodes` and `slottedNodes`) + * these are used later for special consideration: + * - Add `shadow: true` DOM trees to their document-fragment + * - Move slotted nodes out of shadowDOMs + * - Add meta nodes to non-shadow DOMs and their 'slotted' nodes + * @param parentVNode - this nodes current parent vnode + * @param childRenderNodes - flat array of all child vnodes + * @param slotNodes - nodes that represent an element's ``s + * @param shadowRootNodes - nodes that are at the root of this hydrating element + * @param hostElm - the root, hydrating element + * @param node - the node currently being iterated over + * @param hostId - the root, hydrating element id + * @param slottedNodes - nodes that have been slotted + * @returns - the constructed VNode + */ const clientHydrate = ( parentVNode: d.VNode, childRenderNodes: RenderNodeData[], @@ -74,12 +236,14 @@ const clientHydrate = ( shadowRootNodes: d.RenderNode[], hostElm: d.HostElement, node: d.RenderNode, - hostId: string + hostId: string, + slottedNodes: SlottedNodes[] = [] ) => { let childNodeType: string; let childIdSplt: string[]; let childVNode: RenderNodeData; let i: number; + const scopeId = hostElm['s-sc']; if (node.nodeType === NODE_TYPE.ElementNode) { childNodeType = (node as HTMLElement).getAttribute(HYDRATE_CHILD_ID); @@ -89,20 +253,19 @@ const clientHydrate = ( childIdSplt = childNodeType.split('.'); if (childIdSplt[0] === hostId || childIdSplt[0] === '0') { - childVNode = { - $flags$: 0, + childVNode = createSimpleVNode({ $hostId$: childIdSplt[0], $nodeId$: childIdSplt[1], $depth$: childIdSplt[2], $index$: childIdSplt[3], $tag$: node.tagName.toLowerCase(), $elm$: node, - $attrs$: null, - $children$: null, - $key$: null, - $name$: null, - $text$: null, - }; + // if we don't add the initial classes to the VNode, + // the first vdom-render patch / reconciliation will fail; + // any client side change before componentDidLoad will be ignored, + // `setAccessor` will just take the element's initial classes + $attrs$: { class: node.className }, + }); childRenderNodes.push(childVNode); node.removeAttribute(HYDRATE_CHILD_ID); @@ -113,28 +276,73 @@ const clientHydrate = ( parentVNode.$children$ = []; } - // add our child vnode to a specific index of the vnode's children - parentVNode.$children$[childVNode.$index$ as any] = childVNode; + // test if this element was 'slotted' + // recreate node attributes + const slotName = childVNode.$elm$.getAttribute('s-sn'); + if (typeof slotName === 'string') { + childVNode.$elm$['s-sn'] = slotName; + childVNode.$elm$.removeAttribute('s-sn'); + } + + // test if this node is the child (a slot fallback node) of a slot + const slotFbId = childVNode.$elm$.getAttribute(HYDRATED_SLOT_FALLBACK_ID); + if (slotFbId) { + childVNode.$elm$.removeAttribute(HYDRATED_SLOT_FALLBACK_ID); + // find the relevant slot node + const slotNode = slotNodes.find( + (slot) => slot.$elm$['s-sn'] === childVNode.$elm$['s-sn'] || slot.$name$ === childVNode.$elm$['s-sn'] + ); + // add the relationship to the VDOM to stop re-renders + if (slotNode) { + childVNode.$elm$['s-sf'] = true; + childVNode.$elm$['s-hn'] = hostElm.tagName; + slotNode.$children$ = slotNode.$children$ || []; + slotNode.$children$[childVNode.$index$ as any] = childVNode; + + // if the slot is an actual `` + // that's a newly created node (↓↓↓) + // move this element there now + if (slotNode.$elm$.nodeType === NODE_TYPE.ElementNode) { + slotNode.$elm$.appendChild(childVNode.$elm$); + } + } + } else if (childVNode.$index$ !== undefined) { + // add our child vnode to a specific index of the vnode's children + parentVNode.$children$[childVNode.$index$ as any] = childVNode; + } + + // host is `scoped: true` - add that flag to child. + // used in 'setAccessor' to make sure our scoped class is present + if (scopeId) node['s-si'] = scopeId; // this is now the new parent vnode for all the next child checks parentVNode = childVNode; - if (shadowRootNodes && childVNode.$depth$ === '0') { + if ( + shadowRootNodes && + childVNode.$depth$ === '0' && + // don't move slot fallback node into the root nodes array + // they'll be moved into a new slot element ↓↓↓ + !slotFbId + ) { shadowRootNodes[childVNode.$index$ as any] = childVNode.$elm$; } } } - // recursively drill down, end to start so we can remove nodes - for (i = node.childNodes.length - 1; i >= 0; i--) { + // recursively drill down, end to start so we can + // construct a VDOM and add meta to nodes + const nonShadowChildNodes = node.__childNodes || node.childNodes; + for (i = nonShadowChildNodes.length - 1; i >= 0; i--) { clientHydrate( parentVNode, childRenderNodes, slotNodes, shadowRootNodes, hostElm, - node.childNodes[i] as any, - hostId + nonShadowChildNodes[i] as any, + hostId, + slottedNodes ); } @@ -148,35 +356,30 @@ const clientHydrate = ( shadowRootNodes, hostElm, node.shadowRoot.childNodes[i] as any, - hostId + hostId, + slottedNodes ); } } } else if (node.nodeType === NODE_TYPE.CommentNode) { - // `${COMMENT_TYPE}.${hostId}.${nodeId}.${depth}.${index}` + // `${COMMENT_TYPE}.${hostId}.${nodeId}.${depth}.${index}.${isSlotFallbackText}.${slotName}` childIdSplt = node.nodeValue.split('.'); if (childIdSplt[1] === hostId || childIdSplt[1] === '0') { // comment node for either the host id or a 0 host id childNodeType = childIdSplt[0]; - childVNode = { - $flags$: 0, + childVNode = createSimpleVNode({ $hostId$: childIdSplt[1], $nodeId$: childIdSplt[2], $depth$: childIdSplt[3], - $index$: childIdSplt[4], + $index$: childIdSplt[4] || '0', $elm$: node, - $attrs$: null, - $children$: null, - $key$: null, - $name$: null, - $tag$: null, - $text$: null, - }; + }); if (childNodeType === TEXT_NODE_ID) { - childVNode.$elm$ = node.nextSibling as any; + const textNode = (childVNode.$elm$ = node.nextSibling as any); + if (childVNode.$elm$ && childVNode.$elm$.nodeType === NODE_TYPE.TextNode) { childVNode.$text$ = childVNode.$elm$.textContent; childRenderNodes.push(childVNode); @@ -184,41 +387,122 @@ const clientHydrate = ( // remove the text comment since it's no longer needed node.remove(); - if (!parentVNode.$children$) { - parentVNode.$children$ = []; - } - parentVNode.$children$[childVNode.$index$ as any] = childVNode; + // test to see if this is slot fallback text + if (childIdSplt[5] === '1') { + textNode['s-sf'] = true; + textNode['s-sn'] = childIdSplt[6] || ''; + textNode['s-sfc'] = textNode.textContent; + textNode['s-hn'] = hostElm.tagName; + + // find the relevant slot node + const slotNode = slotNodes.find( + (slot) => slot.$elm$['s-sn'] === textNode['s-sn'] || slot.$name$ === textNode['s-sn'] + ); + // add the relationship to the VDOM to stop re-renders + if (slotNode) { + slotNode.$children$ = slotNode.$children$ || []; + slotNode.$children$[childVNode.$index$ as any] = childVNode; + + // if the slot is an actual `` + // that's a newly created node (↓↓↓) + // move this text node there now + if (slotNode.$elm$.nodeType === NODE_TYPE.ElementNode) { + slotNode.$elm$.appendChild(textNode); + } + } + } else { + // check to make sure this node actually belongs to this host. + // If it was slotted from another component, we don't want to add it + // to this host's vdom; it can be removed on render reconciliation. + // We want slotting logic to take care of it + if (hostId === childVNode.$hostId$) { + if (!parentVNode.$children$) { + parentVNode.$children$ = []; + } + parentVNode.$children$[childVNode.$index$ as any] = childVNode; + } - if (shadowRootNodes && childVNode.$depth$ === '0') { - shadowRootNodes[childVNode.$index$ as any] = childVNode.$elm$; + if (shadowRootNodes && childVNode.$depth$ === '0') { + shadowRootNodes[childVNode.$index$ as any] = childVNode.$elm$; + } } } + } else if (childNodeType === COMMENT_NODE_ID) { + childVNode.$elm$ = node.nextSibling as any; + + if (childVNode.$elm$ && childVNode.$elm$.nodeType === NODE_TYPE.CommentNode) { + childRenderNodes.push(childVNode); + + // remove the comment comment since it's no longer needed + node.remove(); + } } else if (childVNode.$hostId$ === hostId) { - // this comment node is specifcally for this host id + // this comment node is specifically for this host id if (childNodeType === SLOT_NODE_ID) { - // `${SLOT_NODE_ID}.${hostId}.${nodeId}.${depth}.${index}.${slotName}`; + // `${SLOT_NODE_ID}.${hostId}.${nodeId}.${depth}.${index}.${slotName}.${hasSlotFallback}.${slotFallbackText}`; childVNode.$tag$ = 'slot'; - if (childIdSplt[5]) { - node['s-sn'] = childVNode.$name$ = childIdSplt[5]; - } else { - node['s-sn'] = ''; - } + // TODO: this is clunky. + // Clear out parent VNode attrs so the initial element state is used as a reference. + // The reason: this is a slot container element and requires special scope classes + // This does mean any class changes client-side before 'componentDidLoad', + // will not be respected. + parentVNode.$attrs$ = undefined; + + // add slot name + const slotName = (node['s-sn'] = childVNode.$name$ = childIdSplt[5] || ''); node['s-sr'] = true; + // this slot node has fallback nodes? + if (childIdSplt[6] === '1') { + node['s-hsf'] = true; + } + + if (childIdSplt[7] === '1') { + // this slot has fallback text + // it should be held in the previous comment node + // (white-space depending) + let foundFallbackText = node.previousSibling; + while (!!foundFallbackText && foundFallbackText.nodeType !== NODE_TYPE.CommentNode) { + foundFallbackText = foundFallbackText.previousSibling as d.RenderNode; + } + + // this slot node has fallback text? + // (if so, the previous node comment will have that text) + node['s-sfc'] = foundFallbackText.nodeValue; + } + + // find this slots' current host parent as dictated by the vdom tree. + // this is important because where it is now in the constructed SSR markup + // might be different to where to should be + const parentNodeId = parentVNode?.$elm$ + ? parentVNode.$elm$['s-id'] || parentVNode.$elm$.getAttribute('s-id') + : ''; + if (BUILD.shadowDom && shadowRootNodes) { - // browser support shadowRoot and this is a shadow dom component + /* SHADOW */ + + // browser supports shadowRoot and this is a shadow dom component // create an actual slot element - childVNode.$elm$ = doc.createElement(childVNode.$tag$); + const slot = (childVNode.$elm$ = doc.createElement(childVNode.$tag$) as d.RenderNode); if (childVNode.$name$) { // add the slot name attribute - childVNode.$elm$.setAttribute('name', childVNode.$name$); + childVNode.$elm$.setAttribute('name', slotName); } - // insert the new slot element before the slot comment - node.parentNode.insertBefore(childVNode.$elm$, node); + if (parentNodeId && parentNodeId !== childVNode.$hostId$) { + // shadow component's slot is placed inside a nested component's shadowDOM; + // it doesn't belong to this host - it was forwarded by the SSR markup. + // Insert it in the root of this host; it's lightDOM. + // It doesn't really matter where in the host root; the component will take care of it. + parentVNode.$elm$.insertBefore(slot, parentVNode.$elm$.children[0]); + } else { + // insert the new slot element before the slot comment + node.parentNode.insertBefore(childVNode.$elm$, node); + } + addSlottedNodes(slottedNodes, childIdSplt[2], slotName, node, childVNode.$hostId$); // remove the slot comment since it's not needed for shadow node.remove(); @@ -226,6 +510,30 @@ const clientHydrate = ( if (childVNode.$depth$ === '0') { shadowRootNodes[childVNode.$index$ as any] = childVNode.$elm$; } + } else { + /* NON-SHADOW */ + const slot = childVNode.$elm$ as d.RenderNode; + + // test to see if this non-shadow component's mock 'slot' is placed + // inside a nested component's shadowDOM. If so, it doesn't belong here; + // it was forwarded by the SSR markup. So we'll insert it into the root of this host; + // it's lightDOM with accompanying 'slotted' nodes + const shouldMove = parentNodeId && parentNodeId !== childVNode.$hostId$ && parentVNode.$elm$.shadowRoot; + + // attempt to find any mock slotted nodes which we'll move later + addSlottedNodes( + slottedNodes, + childIdSplt[2], + slotName, + node, + shouldMove ? parentNodeId : childVNode.$hostId$ + ); + + if (shouldMove) { + // move slot comment node (to after any other comment nodes) + parentVNode.$elm$.insertBefore(slot, parentVNode.$elm$.children[0]); + } + childRenderNodes.push(childVNode); } slotNodes.push(childVNode); @@ -252,13 +560,34 @@ const clientHydrate = ( vnode.$index$ = '0'; parentVNode.$children$ = [vnode]; } + + return parentVNode; }; +/** + * Skims whole SSR document to create + * a map of component IDs and 'original location ID's. + * Original location ID's are derived from comment nodes placed by 'vdom-annotations.ts'. + * They relate to lightDOM nodes that were moved deeper into the SSR markup. + * e.g. `` maps to `
` + * + * @param node - a node in the document. If an element, will recursively drill down + * @param orgLocNodes - a master map to add component ids and original location ids to + */ export const initializeDocumentHydrate = (node: d.RenderNode, orgLocNodes: Map) => { if (node.nodeType === NODE_TYPE.ElementNode) { + // add all the loaded component IDs in this document + // they're required to find nodes later + // when deciding where slotted nodes should live + const componentId = node[HYDRATE_ID] || node.getAttribute(HYDRATE_ID); + if (componentId) { + orgLocNodes.set(componentId, node); + } + let i = 0; - for (; i < node.childNodes.length; i++) { - initializeDocumentHydrate(node.childNodes[i] as any, orgLocNodes); + const nonShadowChildNodes = node.__childNodes || node.childNodes; + for (; i < nonShadowChildNodes.length; i++) { + initializeDocumentHydrate(nonShadowChildNodes[i] as any, orgLocNodes); } if (node.shadowRoot) { for (i = 0; i < node.shadowRoot.childNodes.length; i++) { @@ -269,7 +598,6 @@ export const initializeDocumentHydrate = (node: d.RenderNode, orgLocNodes: Map): RenderNodeData => { + const defaultVNode: RenderNodeData = { + $flags$: 0, + $hostId$: null, + $nodeId$: null, + $depth$: null, + $index$: '0', + $elm$: null, + $attrs$: null, + $children$: null, + $key$: null, + $name$: null, + $tag$: null, + $text$: null, + }; + return { ...defaultVNode, ...vnode }; +}; + +/** + * Adds groups of slotted nodes (grouped by slot ID) + * to this host element's 'master' array. We'll use this after + * the host element's VDOM is completely constructed to + * finally position or / and add meta information required by non-shadow slotted nodes + * @param slottedNodes - the main host element 'master' array to add to + * @param slotNodeId - the slot node unique ID + * @param slotName - the slot node name (can be '') + * @param slotNode - the slot node + * @param hostId - the host element id where this node should be slotted + */ +const addSlottedNodes = ( + slottedNodes: SlottedNodes[], + slotNodeId: string, + slotName: string, + slotNode: d.RenderNode, + hostId: string +) => { + let slottedNode = slotNode.nextSibling as d.RenderNode; + slottedNodes[slotNodeId as any] = slottedNodes[slotNodeId as any] || []; + + // looking for nodes that match this slot's name, + // OR are text / comment nodes and the slot is a default slot (no name) + // (text / comments cannot be direct descendants of named slots) + // also ignore slot fallback nodes + while ( + slottedNode && + (slottedNode['s-sn'] === slotName || + (slotName === '' && + !slottedNode['s-sn'] && + ((slottedNode.nodeType === NODE_TYPE.CommentNode && slottedNode.nodeValue.indexOf('.') !== 1) || + slottedNode.nodeType === NODE_TYPE.TextNode))) && + !slottedNode['s-sf'] + ) { + slottedNode['s-sn'] = slotName; + slottedNodes[slotNodeId as any].push({ slot: slotNode, node: slottedNode, hostId }); + slottedNode = slottedNode.nextSibling as d.RenderNode; + } +}; diff --git a/src/runtime/connected-callback.ts b/src/runtime/connected-callback.ts index 8de7d9d9105..8abb98b61c1 100644 --- a/src/runtime/connected-callback.ts +++ b/src/runtime/connected-callback.ts @@ -7,7 +7,7 @@ import { initializeClientHydrate } from './client-hydrate'; import { fireConnectedCallback, initializeComponent } from './initialize-component'; import { createTime } from './profile'; import { HYDRATE_ID, NODE_TYPE, PLATFORM_FLAGS } from './runtime-constants'; -import { addStyle } from './styles'; +import { addStyle, getScopeId } from './styles'; import { attachToAncestor } from './update-component'; export const connectedCallback = (elm: d.HostElement) => { @@ -34,6 +34,9 @@ export const connectedCallback = (elm: d.HostElement) => { ? addStyle(elm.shadowRoot, cmpMeta, elm.getAttribute('s-mode')) : addStyle(elm.shadowRoot, cmpMeta); elm.classList.remove(scopeId + '-h', scopeId + '-s'); + } else if (BUILD.scoped && cmpMeta.$flags$ & CMP_FLAGS.scopedCssEncapsulation) { + const scopeId = getScopeId(cmpMeta, BUILD.mode ? elm.getAttribute('s-mode') : undefined); + elm['s-sc'] = scopeId; } initializeClientHydrate(elm, cmpMeta.$tagName$, hostId, hostRef); } @@ -98,7 +101,7 @@ export const connectedCallback = (elm: d.HostElement) => { } else { initializeComponent(elm, hostRef, cmpMeta); } - } else { + } else if (hostRef) { // not the first time this has connected // reattach any event listeners to the host @@ -124,5 +127,10 @@ const setContentReference = (elm: d.HostElement) => { BUILD.isDebug ? `content-ref (host=${elm.localName})` : '' ) as any); contentRefElm['s-cn'] = true; - elm.insertBefore(contentRefElm, elm.firstChild); + const firstChild = elm.__firstChild || elm.firstChild; + if (!!firstChild) { + elm.__insertBefore ? elm.__insertBefore(contentRefElm, firstChild) : elm.insertBefore(contentRefElm, firstChild); + } else { + elm.__appendChild ? elm.__appendChild(contentRefElm) : elm.appendChild(contentRefElm); + } }; diff --git a/src/runtime/dom-extras.ts b/src/runtime/dom-extras.ts index 03462efd762..25dd51c17d0 100644 --- a/src/runtime/dom-extras.ts +++ b/src/runtime/dom-extras.ts @@ -1,19 +1,59 @@ import { BUILD } from '@app-data'; -import { getHostRef, plt, supportsShadow } from '@platform'; -import { NODE_TYPES } from '@stencil/core/mock-doc'; -import { CMP_FLAGS, HOST_FLAGS } from '@utils'; import type * as d from '../declarations'; -import { PLATFORM_FLAGS } from './runtime-constants'; +import { NODE_TYPE, ORG_LOCATION_ID } from './runtime-constants'; +import { updateFallbackSlotVisibility } from './vdom/render-slot-fallback'; +interface PatchedNode extends d.HostElement { + __removeChild: (node: ChildNode) => void; +} + +/** + * Monkey patches a range of DOM methods and accessors. + * Makes `non-shadow-dom` (`scoped: true` or `shadow: false`) custom elements behave more closely to their native counterparts. + * - `innerHTML` + * - `innerText` + * - `textContent` + * - `insertBefore()` + * - `appendChild()` + * - `append()` + * - `prepend()` + * - `insertAdjacentText()` + * - `insertAdjacentElement()` + * - `insertAdjacentHTML()` + * - `replaceChildren()` + * @param HostElementPrototype the custom element prototype to patch + * @param DescriptorNodePrototype optional. Where to find OG descriptors for accessors. + * This will be different / required during during testing / mock environnement. + */ +export const patchPseudoShadowDom = (HostElementPrototype: any, DescriptorNodePrototype?: any) => { + patchChildNodes(HostElementPrototype, DescriptorNodePrototype); + patchInsertBefore(HostElementPrototype); + patchAppendChild(HostElementPrototype); + patchAppend(HostElementPrototype); + patchPrepend(HostElementPrototype); + patchInsertAdjacentHTML(HostElementPrototype); + patchInsertAdjacentText(HostElementPrototype); + patchInsertAdjacentElement(HostElementPrototype); + patchReplaceChildren(HostElementPrototype); + patchInnerHTML(HostElementPrototype, DescriptorNodePrototype); + patchInnerText(HostElementPrototype, DescriptorNodePrototype); + patchTextContent(HostElementPrototype, DescriptorNodePrototype); +}; + +////// non-shadow host component patches + +/** + * Patch `cloneNode()` for non-shadow components + * @param HostElementPrototype the host element prototype to monkey patch + */ export const patchCloneNode = (HostElementPrototype: any) => { - const orgCloneNode = HostElementPrototype.cloneNode; + HostElementPrototype.__cloneNode = HostElementPrototype.cloneNode; HostElementPrototype.cloneNode = function (deep?: boolean) { - const srcNode = this; - const isShadowDom = BUILD.shadowDom ? srcNode.shadowRoot && supportsShadow : false; - const clonedNode = orgCloneNode.call(srcNode, isShadowDom ? deep : false) as Node; - if (BUILD.slot && !isShadowDom && deep) { + const srcNode: PatchedNode = this; + const clonedNode: PatchedNode = HostElementPrototype.__cloneNode.call(srcNode, false); + if (BUILD.slot && deep) { let i = 0; let slotted, nonStencilNode; const stencilPrivates = [ @@ -30,20 +70,20 @@ export const patchCloneNode = (HostElementPrototype: any) => { 's-ol', 's-nr', 's-si', + 's-sf', + 's-sfc', + 's-hsf', ]; - for (; i < srcNode.childNodes.length; i++) { - slotted = (srcNode.childNodes[i] as any)['s-nr']; - nonStencilNode = stencilPrivates.every((privateField) => !(srcNode.childNodes[i] as any)[privateField]); + for (; i < srcNode.__childNodes.length; i++) { + slotted = (srcNode.__childNodes[i] as any)['s-nr']; + nonStencilNode = stencilPrivates.every((privateField) => !(srcNode.__childNodes[i] as any)[privateField]); + if (slotted) { - if (BUILD.appendChildSlotFix && (clonedNode as any).__appendChild) { - (clonedNode as any).__appendChild(slotted.cloneNode(true)); - } else { - clonedNode.appendChild(slotted.cloneNode(true)); - } + clonedNode.__appendChild(slotted.cloneNode(true)); } if (nonStencilNode) { - clonedNode.appendChild((srcNode.childNodes[i] as any).cloneNode(true)); + clonedNode.__appendChild((srcNode.__childNodes[i] as any).cloneNode(true)); } } } @@ -51,120 +91,665 @@ export const patchCloneNode = (HostElementPrototype: any) => { }; }; -export const patchSlotAppendChild = (HostElementPrototype: any) => { +/** + * Patches children accessors of a non-shadow component. + * (`childNodes`, `children`, `firstChild`, `lastChild` and `childElementCount`) + * @param HostElementPrototype the custom element prototype to patch + * @param DescriptorNodePrototype optional. Where to find the OG descriptor for `childNodes`. + * Required during during testing / mock environnement. + */ +const patchChildNodes = (HostElementPrototype: any, DescriptorNodePrototype?: any) => { + if (!globalThis.Node) return; + + class FakeNodeList extends Array { + item(n: number) { + return this[n]; + } + } + + let childNodesDesc = Object.getOwnPropertyDescriptor(DescriptorNodePrototype || Node.prototype, 'childNodes'); + if (!childNodesDesc) { + childNodesDesc = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(Node.prototype), 'childNodes'); + } + if (childNodesDesc) Object.defineProperty(HostElementPrototype, '__childNodes', childNodesDesc); + + const childrenDesc = Object.getOwnPropertyDescriptor(DescriptorNodePrototype || Element.prototype, 'children'); + // MockNode won't have these + if (childrenDesc) Object.defineProperty(HostElementPrototype, '__children', childrenDesc); + + const childElementCountDesc = Object.getOwnPropertyDescriptor( + DescriptorNodePrototype || Element.prototype, + 'childElementCount' + ); + if (childElementCountDesc) Object.defineProperty(HostElementPrototype, '__childElementCount', childElementCountDesc); + + Object.defineProperty(HostElementPrototype, 'children', { + get() { + return (this.childNodes as FakeNodeList) + .map((n: Node) => { + if (n.nodeType === NODE_TYPE.ElementNode) return n; + else return null; + }) + .filter((n) => !!n); + }, + }); + Object.defineProperty(HostElementPrototype, 'firstChild', { + get() { + return this.childNodes[0]; + }, + }); + Object.defineProperty(HostElementPrototype, 'lastChild', { + get() { + return this.childNodes[this.childNodes.length - 1]; + }, + }); + Object.defineProperty(HostElementPrototype, 'childElementCount', { + get() { + return HostElementPrototype.children.length; + }, + }); + if (!childNodesDesc) return; + + Object.defineProperty(HostElementPrototype, 'childNodes', { + get() { + const childNodes = this.__childNodes as d.RenderNode[]; + const result = new FakeNodeList(); + for (let i = 0; i < childNodes.length; i++) { + const slottedNode = childNodes[i]['s-nr']; + if ( + slottedNode && + (slottedNode.nodeType !== NODE_TYPE.CommentNode || slottedNode.nodeValue.indexOf(ORG_LOCATION_ID + '.') !== 0) + ) { + result.push(slottedNode); + } + } + return result; + }, + }); +}; + +/** + * Patches the inner html accessors of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch + * @param DescriptorNodePrototype optional. Where to find the OG descriptor for `innerHTML`. + * Required during during testing / mock environnement. + */ +const patchInnerHTML = (HostElementPrototype: any, DescriptorNodePrototype?: any) => { + if (!globalThis.Element) return; + + let descriptor = Object.getOwnPropertyDescriptor(DescriptorNodePrototype || Element.prototype, 'innerHTML'); + // on IE it's on HTMLElement.prototype + if (!descriptor) descriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'innerHTML'); + // MockNode won't have these + if (descriptor) Object.defineProperty(HostElementPrototype, '__innerHTML', descriptor); + + Object.defineProperty(HostElementPrototype, 'innerHTML', { + get: function () { + let html = ''; + this.childNodes.forEach((node: d.RenderNode) => (html += node.outerHTML || node.textContent)); + return html; + }, + set: function (value) { + this.childNodes.forEach((node: d.RenderNode) => { + if (node['s-ol']) { + try { + node['s-ol'].remove(); + } catch (e) {} + } + node.remove(); + }); + this.insertAdjacentHTML('beforeend', value); + }, + }); +}; + +/** + * Patches the inner text accessors of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch + * @param DescriptorNodePrototype optional. Where to find the OG descriptor for `innerText`. + * Required during during testing / mock environnement. + */ +const patchInnerText = (HostElementPrototype: any, DescriptorNodePrototype?: any) => { + if (!globalThis.Element) return; + + let descriptor = Object.getOwnPropertyDescriptor(DescriptorNodePrototype || Element.prototype, 'innerText'); + // on IE it's on HTMLElement.prototype + if (!descriptor) descriptor = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'innerText'); + // MockNode won't have these + if (descriptor) Object.defineProperty(HostElementPrototype, '__innerText', descriptor); + + Object.defineProperty(HostElementPrototype, 'innerText', { + get: function () { + let text = ''; + this.childNodes.forEach((node: d.RenderNode) => { + if (node.innerText) text += node.innerText; + else if (node.textContent) text += node.textContent.trimEnd(); + }); + return text; + }, + set: function (value) { + this.childNodes.forEach((node: d.RenderNode) => { + if (node['s-ol']) node['s-ol'].remove(); + node.remove(); + }); + this.insertAdjacentHTML('beforeend', value); + }, + }); +}; + +/** + * Patches the text content accessors of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch + * @param DescriptorNodePrototype optional. Where to find the OG descriptor for `textContent`. + * Required during during testing / mock environnement. + */ +const patchTextContent = (HostElementPrototype: any, DescriptorNodePrototype?: any) => { + if (!globalThis.Node) return; + + const descriptor = Object.getOwnPropertyDescriptor(DescriptorNodePrototype || Node.prototype, 'textContent'); + // MockNode won't have these + if (descriptor) Object.defineProperty(HostElementPrototype, '__textContent', descriptor); + + Object.defineProperty(HostElementPrototype, 'textContent', { + get: function () { + let text = ''; + this.childNodes.forEach((node: d.RenderNode) => (text += node.textContent || '')); + return text; + }, + set: function (value) { + this.childNodes.forEach((node: d.RenderNode) => { + if (node['s-ol']) node['s-ol'].remove(); + node.remove(); + }); + this.insertAdjacentHTML('beforeend', value); + }, + }); +}; + +/** + * Patches the `insertBefore` of a non-shadow component. + * The *current* node to insert before may not be in the root of our component. + * This tries to find where the *current* node lives within the component and insert the new node before it + * @param HostElementPrototype the custom element prototype to patch + */ +const patchInsertBefore = (HostElementPrototype: any) => { + if (HostElementPrototype.__insertBefore) return; + + HostElementPrototype.__insertBefore = HostElementPrototype.insertBefore; + HostElementPrototype.insertBefore = function (this: PatchedNode, newChild: d.RenderNode, curChild: d.RenderNode) { + const slotName = (newChild['s-sn'] = getSlotName(newChild)); + const slotNode = getHostSlotNode(this.__childNodes, slotName); + + if (slotNode) { + let found = false; + this.childNodes.forEach((childNode) => { + // we found the node in our list of other 'lightDOM' / slotted nodes + if (childNode === curChild || curChild === null) { + found = true; + addSlotRelocateNode(newChild, slotNode); + if (curChild === null) { + this.__append(newChild); + return; + } + + if (slotName === curChild['s-sn']) { + // current child ('slot before' node) is 'in' the same slot + const insertBefore = + (curChild.parentNode as PatchedNode).__insertBefore || curChild.parentNode.insertBefore; + insertBefore.call(curChild.parentNode, newChild, curChild); + patchRemove(newChild); + } else { + // current child is not in the same slot as 'slot before' node + // so just toss the node in wherever + this.__append(newChild); + } + return; + } + }); + if (found) { + return newChild; + } + } + return (this as d.RenderNode).__insertBefore(newChild, curChild); + }; +}; + +/** + * Patches the `appendChild` method of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch + */ +const patchAppendChild = (HostElementPrototype: any) => { + if (HostElementPrototype.__appendChild) return; + HostElementPrototype.__appendChild = HostElementPrototype.appendChild; HostElementPrototype.appendChild = function (this: d.RenderNode, newChild: d.RenderNode) { const slotName = (newChild['s-sn'] = getSlotName(newChild)); - const slotNode = getHostSlotNode(this.childNodes, slotName); + const slotNode = getHostSlotNode(this.__childNodes || this.childNodes, slotName); + if (slotNode) { - const slotChildNodes = getHostSlotChildNodes(slotNode, slotName); + addSlotRelocateNode(newChild, slotNode); + + const slotChildNodes = getHostSlotChildNodes(slotNode); const appendAfter = slotChildNodes[slotChildNodes.length - 1]; - return appendAfter.parentNode.insertBefore(newChild, appendAfter.nextSibling); + + if (appendAfter.parentNode) { + const parent = appendAfter.parentNode as d.RenderNode; + parent.__insertBefore + ? parent.__insertBefore(newChild, appendAfter.nextSibling) + : parent.insertBefore(newChild, appendAfter.nextSibling); + patchRemove(newChild); + } + + if (slotNode['s-hsf']) { + updateFallbackSlotVisibility(slotNode.parentNode as d.RenderNode); + } + return newChild; } - return (this as any).__appendChild(newChild); + if (newChild.nodeType === NODE_TYPE.ElementNode && !!newChild.getAttribute('slot') && this.__childNodes) + newChild.hidden = true; + return (this as PatchedNode).__appendChild(newChild); }; }; /** - * Patches the text content of an unnamed slotted node inside a scoped component - * @param hostElementPrototype the `Element` to be patched - * @param cmpMeta component runtime metadata used to determine if the component should be patched or not + * Patches the `prepend` method of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch */ -export const patchTextContent = (hostElementPrototype: HTMLElement, cmpMeta: d.ComponentRuntimeMeta): void => { - if (BUILD.scoped && cmpMeta.$flags$ & CMP_FLAGS.scopedCssEncapsulation) { - const descriptor = Object.getOwnPropertyDescriptor(Node.prototype, 'textContent'); +const patchPrepend = (HostElementPrototype: PatchedNode) => { + if (HostElementPrototype.__prepend) return; + + HostElementPrototype.__prepend = HostElementPrototype.prepend; + HostElementPrototype.prepend = function (this: PatchedNode, ...newChildren: (d.RenderNode | string)[]) { + newChildren.forEach((newChild: d.RenderNode | string) => { + if (typeof newChild === 'string') { + newChild = this.ownerDocument.createTextNode(newChild) as unknown as d.RenderNode; + } + + const slotName = (newChild['s-sn'] = getSlotName(newChild)); + const slotNode = getHostSlotNode(this.__childNodes, slotName); - Object.defineProperty(hostElementPrototype, '__textContent', descriptor); + if (slotNode) { + addSlotRelocateNode(newChild, slotNode); - Object.defineProperty(hostElementPrototype, 'textContent', { - get(): string | null { - // get the 'default slot', which would be the first slot in a shadow tree (if we were using one), whose name is - // the empty string - const slotNode = getHostSlotNode(this.childNodes, ''); - // when a slot node is found, the textContent _may_ be found in the next sibling (text) node, depending on how - // nodes were reordered during the vdom render. first try to get the text content from the sibling. - if (slotNode?.nextSibling?.nodeType === NODE_TYPES.TEXT_NODE) { - return slotNode.nextSibling.textContent; - } else if (slotNode) { - return slotNode.textContent; - } else { - // fallback to the original implementation - return this.__textContent; + const slotChildNodes = getHostSlotChildNodes(slotNode); + const appendAfter = slotChildNodes[0]; + + if (appendAfter.parentNode) { + appendAfter.parentNode.insertBefore(newChild, appendAfter.nextSibling); + patchRemove(newChild); } - }, - - set(value: string | null) { - // get the 'default slot', which would be the first slot in a shadow tree (if we were using one), whose name is - // the empty string - const slotNode = getHostSlotNode(this.childNodes, ''); - // when a slot node is found, the textContent _may_ need to be placed in the next sibling (text) node, - // depending on how nodes were reordered during the vdom render. first try to set the text content on the - // sibling. - if (slotNode?.nextSibling?.nodeType === NODE_TYPES.TEXT_NODE) { - slotNode.nextSibling.textContent = value; - } else if (slotNode) { - slotNode.textContent = value; - } else { - // we couldn't find a slot, but that doesn't mean that there isn't one. if this check ran before the DOM - // loaded, we could have missed it. check for a content reference element on the scoped component and insert - // it there - this.__textContent = value; - const contentRefElm = this['s-cr']; - if (contentRefElm) { - this.insertBefore(contentRefElm, this.firstChild); - } + + if (slotNode['s-hsf']) { + updateFallbackSlotVisibility(slotNode.parentNode as d.RenderNode); } - }, + return; + } + if (newChild.nodeType === NODE_TYPE.ElementNode && !!newChild.getAttribute('slot') && this.__childNodes) + newChild.hidden = true; + return (this as any).__prepend(newChild); }); - } + }; }; -export const patchChildSlotNodes = (elm: any, cmpMeta: d.ComponentRuntimeMeta) => { - class FakeNodeList extends Array { - item(n: number) { - return this[n]; - } - } - // TODO(STENCIL-662): Remove code related to deprecated shadowDomShim field - if (cmpMeta.$flags$ & CMP_FLAGS.needsShadowDomShim) { - const childNodesFn = elm.__lookupGetter__('childNodes'); - - Object.defineProperty(elm, 'children', { - get() { - return this.childNodes.map((n: any) => n.nodeType === 1); - }, - }); +/** + * Patches the `append` method of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch + */ +const patchAppend = (HostElementPrototype: PatchedNode) => { + if (HostElementPrototype.__append) return; - Object.defineProperty(elm, 'childElementCount', { - get() { - return elm.children.length; - }, + HostElementPrototype.__append = HostElementPrototype.append; + HostElementPrototype.append = function (this: d.HostElement, ...newChildren: (d.RenderNode | string)[]) { + newChildren.forEach((newChild: d.RenderNode | string) => { + if (typeof newChild === 'string') { + newChild = this.ownerDocument.createTextNode(newChild) as unknown as d.RenderNode; + } + this.appendChild(newChild); }); + }; +}; - Object.defineProperty(elm, 'childNodes', { - get() { - const childNodes = childNodesFn.call(this); - if ( - (plt.$flags$ & PLATFORM_FLAGS.isTmpDisconnected) === 0 && - getHostRef(this).$flags$ & HOST_FLAGS.hasRendered - ) { - const result = new FakeNodeList(); - for (let i = 0; i < childNodes.length; i++) { - const slot = childNodes[i]['s-nr']; - if (slot) { - result.push(slot); - } - } - return result; +/** + * Patches the `replaceChildren` method of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch + */ +const patchReplaceChildren = (HostElementPrototype: PatchedNode) => { + if (HostElementPrototype.__replaceChildren) return; + + HostElementPrototype.__replaceChildren = HostElementPrototype.replaceChildren; + HostElementPrototype.replaceChildren = function (this: PatchedNode, ...newChildren: (Node | string)[]) { + const slotNode = getHostSlotNode(this.__childNodes, ''); + if (slotNode) { + const slotChildNodes = getHostSlotChildNodes(slotNode); + slotChildNodes.forEach((node) => { + if (!node['s-sr']) { + node.remove(); } - return FakeNodeList.from(childNodes); - }, - }); + }); + this.append(...newChildren); + } + }; +}; + +/** + * Patches the `insertAdjacentHTML` method of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch + */ +const patchInsertAdjacentHTML = (HostElementPrototype: any) => { + if (HostElementPrototype.__insertAdjacentHTML) return; + + HostElementPrototype.__insertAdjacentHTML = HostElementPrototype.insertAdjacentHTML; + HostElementPrototype.insertAdjacentHTML = function (this: PatchedNode, position: InsertPosition, text: string) { + if (position !== 'afterbegin' && position !== 'beforeend') { + return (this as any).__insertAdjacentHTML(position, text); + } + + const container = this.ownerDocument.createElement('_'); + let node: d.RenderNode; + container.innerHTML = text; + + if (position === 'afterbegin') { + while ((node = container.firstChild as d.RenderNode)) { + this.prepend(node); + } + } else if (position === 'beforeend') { + while ((node = container.firstChild as d.RenderNode)) { + this.append(node); + } + } + }; +}; + +/** + * Patches the `insertAdjacentText` method of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch + */ +const patchInsertAdjacentText = (HostElementPrototype: any) => { + if (HostElementPrototype.__insertAdjacentText) return; + HostElementPrototype.__insertAdjacentText = HostElementPrototype.insertAdjacentText; + HostElementPrototype.insertAdjacentText = function (this: PatchedNode, position: InsertPosition, text: string) { + this.insertAdjacentHTML(position, text); + }; +}; + +/** + * Patches the `insertAdjacentElement` method of a non-shadow component + * @param HostElementPrototype the custom element prototype to patch + */ +const patchInsertAdjacentElement = (HostElementPrototype: any) => { + if (HostElementPrototype.__insertAdjacentElement) return; + HostElementPrototype.__insertAdjacentElement = HostElementPrototype.insertAdjacentElement; + HostElementPrototype.insertAdjacentElement = function ( + this: PatchedNode, + position: InsertPosition, + element: d.RenderNode + ) { + if (position !== 'afterbegin' && position !== 'beforeend') { + return (this as any).__insertAdjacentElement(position, element); + } + if (position === 'afterbegin') { + this.prepend(element); + } else if (position === 'beforeend') { + this.append(element); + } + }; +}; + +////// Slotted node patches + +/** + * Patches sibling accessors of a 'slotted' node within a non-shadow component. + * Meaning whilst stepping through a non-shadow element's nodes, only the mock 'lightdom' nodes are returned. + * - `nextSibling` + * - `nextSiblingElement` + * - `previousSibling` + * - `previousSiblingElement` + * @param NodePrototype the slotted node to be patched + */ +export const patchNextPrev = (NodePrototype: any) => { + // Especially relevant when rendering components via SSR. + // Frameworks will often try to reconcile their VDOM with the real DOM + // by stepping through nodes with 'nextSibling' (and similar). + // This works with a shadowDOM; the lightDOM matches the framework's VDOM. + // This does not work without shadowDOM + + if (!NodePrototype || NodePrototype.__nextSibling || !globalThis.Node) return; + + patchNextSibling(NodePrototype); + patchPreviousSibling(NodePrototype); + patchNextElementSibling(NodePrototype); + patchPreviousElementSibling(NodePrototype); +}; + +/** + * Patches the `nextSibling` accessor of a non-shadow slotted node + * @param NodePrototype the slotted node to be patched + * @param DescriptorNodePrototype optional. Where to find the OG descriptor for `nextSibling`. + * Required during during testing / mock environnement. + */ +export const patchNextSibling = (NodePrototype: any, DescriptorNodePrototype?: any) => { + if (!NodePrototype || NodePrototype.__nextSibling) return; + + const descriptor = Object.getOwnPropertyDescriptor(DescriptorNodePrototype || Node.prototype, 'nextSibling'); + // MockNode might not have these + if (descriptor) Object.defineProperty(NodePrototype, '__nextSibling', descriptor); + else { + NodePrototype.__nextSibling = NodePrototype.nextSibling || true; + } + + Object.defineProperty(NodePrototype, 'nextSibling', { + get: function () { + const parentNodes = this['s-ol']?.parentNode.childNodes; + const index = parentNodes?.indexOf(this); + if (parentNodes && index > -1) { + return parentNodes[index + 1]; + } + return this.__nextSibling; + }, + }); +}; + +/** + * Patches the `nextElementSibling` accessor of a non-shadow slotted node + * @param ElementPrototype the slotted node to be patched + * @param DescriptorNodePrototype optional. Where to find the OG descriptor for `nextElementSibling`. + * Required during during testing / mock environnement. + */ +export const patchNextElementSibling = (ElementPrototype: any, DescriptorNodePrototype?: any) => { + if (!ElementPrototype || ElementPrototype.__nextElementSibling || !ElementPrototype.nextSiblingElement) return; + + const descriptor = Object.getOwnPropertyDescriptor( + DescriptorNodePrototype || Element.prototype, + 'nextElementSibling' + ); + // MockNode won't have these + if (descriptor) Object.defineProperty(ElementPrototype, '__nextElementSibling', descriptor); + else { + ElementPrototype.__nextElementSibling = ElementPrototype.nextSiblingElement || true; } + + Object.defineProperty(ElementPrototype, 'nextElementSibling', { + get: function () { + const parentEles = this['s-ol']?.parentNode.children; + const index = parentEles?.indexOf(this); + if (parentEles && index > -1) { + return parentEles[index + 1]; + } + return this.__nextElementSibling; + }, + }); }; +/** + * Patches the `previousSibling` accessor of a non-shadow slotted node + * @param NodePrototype the slotted node to be patched + * @param DescriptorNodePrototype optional. Where to find the OG descriptor for `previousSibling`. + * Required during during testing / mock environnement. + */ +export const patchPreviousSibling = (NodePrototype: any, DescriptorNodePrototype?: any) => { + if (!NodePrototype || NodePrototype.__previousSibling) return; + + const descriptor = Object.getOwnPropertyDescriptor(DescriptorNodePrototype || Node.prototype, 'previousSibling'); + // MockNode won't have these + if (descriptor) Object.defineProperty(NodePrototype, '__previousSibling', descriptor); + else { + NodePrototype.__previousSibling = NodePrototype.previousSibling || true; + } + + Object.defineProperty(NodePrototype, 'previousSibling', { + get: function () { + const parentNodes = this['s-ol']?.parentNode.childNodes; + const index = parentNodes?.indexOf(this); + if (parentNodes && index > -1) { + return parentNodes[index - 1]; + } + return this.__previousSibling; + }, + }); +}; + +/** + * Patches the `previousElementSibling` accessor of a non-shadow slotted node + * @param ElementPrototype the slotted node to be patched + * @param DescriptorNodePrototype optional. Where to find the OG descriptor for `previousElementSibling`. + * Required during during testing / mock environnement. + */ +export const patchPreviousElementSibling = (ElementPrototype: any, DescriptorNodePrototype?: any) => { + if (!ElementPrototype || ElementPrototype.__previousElementSibling || !ElementPrototype.previousElementSibling) + return; + + const descriptor = Object.getOwnPropertyDescriptor( + DescriptorNodePrototype || Element.prototype, + 'previousElementSibling' + ); + // MockNode won't have these + if (descriptor) Object.defineProperty(ElementPrototype, '__previousElementSibling', descriptor); + else { + ElementPrototype.__previousElementSibling = ElementPrototype.previousSiblingElement || true; + } + + ElementPrototype; + Object.defineProperty(ElementPrototype, 'previousElementSibling', { + get: function () { + const parentNodes = this['s-ol']?.parentNode.children; + const index = parentNodes?.indexOf(this); + if (parentNodes && index > -1) { + return parentNodes[index - 1]; + } + return this.__previousElementSibling; + }, + }); +}; + +/** + * Patches removal methods (`remove`, `removeChild`) + * of a 'slotted' node within a non-shadow component. + * @param NodePrototype the slotted node to be patched + */ +export const patchRemoval = (NodePrototype: any) => { + // In-order to decide when a slot's fallback content should show, + // we need to track when added nodes are removed. + // So, every node that gets added using patched methods, + // get patched in-turn to call this method. + + if (!NodePrototype || NodePrototype.__remove) return; + + patchRemoveChild(NodePrototype.parentNode); + patchRemove(NodePrototype.parentNode); +}; + +/** + * Patches the `remove` method of a non-shadow slotted node + * @param NodePrototype the slotted node to be patched + */ +export const patchRemove = (NodePrototype: any) => { + if (!NodePrototype || NodePrototype.__remove) return; + + NodePrototype.__remove = NodePrototype.remove || true; + patchRemoveChild(NodePrototype.parentNode); + + NodePrototype.remove = function (this: Element) { + if (this.parentNode) { + return this.parentNode.removeChild(this); + } + return (this as any).__remove(); + }; +}; + +/** + * Patches the `removeChild` method of a non-shadow slotted node + * @param ElementPrototype the slotted node to be patched + */ +const patchRemoveChild = (ElementPrototype: any) => { + if (!ElementPrototype || ElementPrototype.__removeChild) return; + + ElementPrototype.__removeChild = ElementPrototype.removeChild; + ElementPrototype.removeChild = function (this: d.RenderNode, toRemove: d.RenderNode) { + if (toRemove && typeof toRemove['s-sn'] !== 'undefined') { + const slotNode = getHostSlotNode(this.__childNodes || this.childNodes, toRemove['s-sn']); + (toRemove.parentElement as PatchedNode).__removeChild(toRemove); + + if (slotNode && slotNode['s-hsf']) { + updateFallbackSlotVisibility(slotNode.parentElement); + } + return; + } + return (this as any).__removeChild(toRemove); + }; +}; + +////// Utils + +/** + * Creates an empty text node to act as a forwarding address to a slotted node: + * 1) When non-shadow components re-render, they need a place to temporarily put 'lightDOM' elements. + * 2) Patched dom methods and accessors use this node to calculate what 'lightDOM' nodes are in the host. + * @param newChild a node that's going to be added to the component + * @param slotNode the slot node that the node will be added to + * @param position an ordered position to add the ref node which mirrors the lightDom nodes' order + */ +export const addSlotRelocateNode = (newChild: d.RenderNode, slotNode: d.RenderNode, position?: number) => { + if (newChild['s-ol'] && newChild['s-ol'].isConnected) return; + + const slottedNodeLocation: d.RenderNode = document.createTextNode('') as any; + slottedNodeLocation['s-nr'] = newChild; + + if (slotNode['s-cr'] && slotNode['s-cr'].parentNode) { + const parent = slotNode['s-cr'].parentNode as PatchedNode; + const appendChild = parent.__appendChild || parent.appendChild; + + if (typeof position !== 'undefined') { + slottedNodeLocation['s-oo'] = position; + const childNodes = (parent.__childNodes || parent.childNodes) as NodeListOf; + const slotRelocateNodes: d.RenderNode[] = [slottedNodeLocation]; + childNodes.forEach((n) => { + if (n['s-nr']) slotRelocateNodes.push(n); + }); + + slotRelocateNodes.sort((a, b) => { + if (!a['s-oo'] || a['s-oo'] < b['s-oo']) return -1; + else if (!b['s-oo'] || b['s-oo'] < a['s-oo']) return 1; + return 0; + }); + slotRelocateNodes.forEach((n) => appendChild.call(slotNode['s-cr'].parentNode, n)); + } else { + appendChild.call(slotNode['s-cr'].parentNode, slottedNodeLocation); + } + } + + newChild['s-ol'] = slottedNodeLocation; +}; + +/** + * Find the slot name of a given node + * @param node a dom node + * @returns the node's slot name + */ const getSlotName = (node: d.RenderNode) => - node['s-sn'] || (node.nodeType === 1 && (node as Element).getAttribute('slot')) || ''; + node['s-sn'] || + (node.nodeType === NODE_TYPE.ElementNode && (node as Element).getAttribute('slot')) || + node.slot || + ''; /** * Recursively searches a series of child nodes for a slot with the provided name. @@ -172,12 +757,13 @@ const getSlotName = (node: d.RenderNode) => * @param slotName the name of the slot to match on. * @returns a reference to the slot node that matches the provided name, `null` otherwise */ -const getHostSlotNode = (childNodes: NodeListOf, slotName: string) => { +const getHostSlotNode = (childNodes: NodeListOf, slotName: string): d.RenderNode | null => { let i = 0; - let childNode: d.RenderNode; + let childNode: d.RenderNode | null; + if (!childNodes) return null; for (; i < childNodes.length; i++) { - childNode = childNodes[i] as any; + childNode = childNodes[i] as d.RenderNode; if (childNode['s-sr'] && childNode['s-sn'] === slotName) { return childNode; } @@ -189,10 +775,17 @@ const getHostSlotNode = (childNodes: NodeListOf, slotName: string) => return null; }; -const getHostSlotChildNodes = (n: d.RenderNode, slotName: string) => { - const childNodes: d.RenderNode[] = [n]; - while ((n = n.nextSibling as any) && (n as d.RenderNode)['s-sn'] === slotName) { - childNodes.push(n as any); +/** + * Get all nodes currently assigned to any given slot node + * @param slotNode - the slot node to check + * @returns - all child node 'within' the checked slot node + */ +const getHostSlotChildNodes = (slotNode: d.RenderNode) => { + const childNodes: d.RenderNode[] = [slotNode]; + const slotName = slotNode['s-sn'] || ''; + + while ((slotNode = slotNode.nextSibling as any) && slotNode['s-sn'] === slotName) { + childNodes.push(slotNode as any); } return childNodes; }; diff --git a/src/runtime/runtime-constants.ts b/src/runtime/runtime-constants.ts index c2bdeb85e70..3ea370a4703 100644 --- a/src/runtime/runtime-constants.ts +++ b/src/runtime/runtime-constants.ts @@ -38,10 +38,12 @@ export const CONTENT_REF_ID = 'r'; export const ORG_LOCATION_ID = 'o'; export const SLOT_NODE_ID = 's'; export const TEXT_NODE_ID = 't'; +export const COMMENT_NODE_ID = 'c'; export const HYDRATE_ID = 's-id'; export const HYDRATED_STYLE_ID = 'sty-id'; export const HYDRATE_CHILD_ID = 'c-id'; export const HYDRATED_CSS = '{visibility:hidden}.hydrated{visibility:inherit}'; +export const HYDRATED_SLOT_FALLBACK_ID = 'sf-id'; export const XLINK_NS = 'http://www.w3.org/1999/xlink'; diff --git a/src/runtime/test/dom-extras.spec.tsx b/src/runtime/test/dom-extras.spec.tsx new file mode 100644 index 00000000000..07e46a10e0b --- /dev/null +++ b/src/runtime/test/dom-extras.spec.tsx @@ -0,0 +1,114 @@ +import { Component, h, Host } from '@stencil/core'; +import { newSpecPage, SpecPage } from '@stencil/core/testing'; + +import { patchPseudoShadowDom } from '../../runtime/dom-extras'; + +describe('dom-extras - patches for non-shadow dom methods and accessors', () => { + let specPage: SpecPage; + + const nodeOrEle = (node: Node | Element) => { + return (node as Element)?.outerHTML || node?.nodeValue.trim(); + }; + + beforeAll(async () => { + @Component({ + tag: 'cmp-a', + shadow: false, + }) + class CmpA { + render() { + return ( + + first shadow node +
+
+ fallback text +
+
+ fallback text +
+
+ last shadow node +
+ ); + } + } + + specPage = await newSpecPage({ + components: [CmpA], + html: ` + + Some default slot, slotted text + a default slot, slotted element +
+ a second slot, slotted element + nested element in the second slot +
+ `, + }); + + patchPseudoShadowDom(specPage.root, specPage.root); + }); + + it('childNodes', async () => { + const childNodes = specPage.root.childNodes; + + expect(nodeOrEle(childNodes[0])).toBe(`Some default slot, slotted text`); + expect(nodeOrEle(childNodes[1])).toBe(`a default slot, slotted element`); + expect(nodeOrEle(childNodes[2])).toBe(``); + expect(nodeOrEle(childNodes[3])).toBe( + `
a second slot, slotted element nested element in the second slot
` + ); + + const innerChildNodes = specPage.root.__childNodes; + + expect(nodeOrEle(innerChildNodes[0])).toBe(``); + expect(nodeOrEle(innerChildNodes[1])).toBe(``); + expect(nodeOrEle(innerChildNodes[2])).toBe(``); + expect(nodeOrEle(innerChildNodes[3])).toBe(``); + expect(nodeOrEle(innerChildNodes[4])).toBe(``); + expect(nodeOrEle(innerChildNodes[5])).toBe(`first shadow node`); + }); + + it('children', async () => { + const children = specPage.root.children; + + expect(nodeOrEle(children[0])).toBe(`a default slot, slotted element`); + expect(nodeOrEle(children[1])).toBe( + `
a second slot, slotted element nested element in the second slot
` + ); + expect(nodeOrEle(children[2])).toBe(undefined); + }); + + it('firstChild', async () => { + expect(nodeOrEle(specPage.root.firstChild)).toBe(`Some default slot, slotted text`); + }); + + it('lastChild', async () => { + expect(nodeOrEle(specPage.root.lastChild)).toBe( + `
a second slot, slotted element nested element in the second slot
` + ); + }); + + it('childElementCount', async () => { + expect(specPage.root.childElementCount).toBe(2); + }); + + it('innerHTML', async () => { + expect(specPage.root.innerHTML.trim()).toBe(`Some default slot, slotted text + a default slot, slotted element +
a second slot, slotted element nested element in the second slot
`); + }); + + it('innerText', async () => { + expect(specPage.root.innerText.trim()).toBe(`Some default slot, slotted texta default slot, slotted element + a second slot, slotted element + nested element in the second slot`); + }); + + it('textContent', async () => { + expect(specPage.root.textContent.replace(/\s+/g, ' ').trim()).toBe( + `Some default slot, slotted text a default slot, slotted element a second slot, slotted element nested element in the second slot` + ); + }); +}); diff --git a/src/runtime/test/hydrate-no-encapsulation.spec.tsx b/src/runtime/test/hydrate-no-encapsulation.spec.tsx index 0881b555226..95676e104fc 100644 --- a/src/runtime/test/hydrate-no-encapsulation.spec.tsx +++ b/src/runtime/test/hydrate-no-encapsulation.spec.tsx @@ -48,7 +48,7 @@ describe('hydrate no encapsulation', () => {

- + Hello

@@ -90,7 +90,7 @@ describe('hydrate no encapsulation', () => { expect(serverHydrated.root).toEqualHtml(` - + Hello `); @@ -135,13 +135,13 @@ describe('hydrate no encapsulation', () => { expect(serverHydrated.root).toEqualHtml(` - + top

- + middle

- + bottom
`); @@ -200,8 +200,8 @@ describe('hydrate no encapsulation', () => { - - + + light-dom
@@ -220,8 +220,6 @@ describe('hydrate no encapsulation', () => { - - light-dom
@@ -265,8 +263,8 @@ describe('hydrate no encapsulation', () => {
- - + + light-dom @@ -284,9 +282,7 @@ describe('hydrate no encapsulation', () => { -
- light-dom
@@ -329,8 +325,8 @@ describe('hydrate no encapsulation', () => {
- - + + light-dom
@@ -349,9 +345,7 @@ describe('hydrate no encapsulation', () => { -
- light-dom
@@ -403,17 +397,17 @@ describe('hydrate no encapsulation', () => {
- -
- + +
+ top light-dom
- - + + middle light-dom - -
- + +
+ bottom light-dom
@@ -433,17 +427,13 @@ describe('hydrate no encapsulation', () => { - - -
- +
top light-dom
- middle light-dom - +
bottom light-dom
diff --git a/src/runtime/test/hydrate-prop-types.spec.tsx b/src/runtime/test/hydrate-prop-types.spec.tsx index 26aed0ae0bd..da21325e9ba 100644 --- a/src/runtime/test/hydrate-prop-types.spec.tsx +++ b/src/runtime/test/hydrate-prop-types.spec.tsx @@ -26,7 +26,7 @@ describe('hydrate prop types', () => { expect(serverHydrated.root).toEqualHtml(` - + 101 `); diff --git a/src/runtime/test/hydrate-scoped.spec.tsx b/src/runtime/test/hydrate-scoped.spec.tsx index 233a1336f61..9a22d2a8a45 100644 --- a/src/runtime/test/hydrate-scoped.spec.tsx +++ b/src/runtime/test/hydrate-scoped.spec.tsx @@ -26,7 +26,7 @@ describe('hydrate scoped', () => {
- + 88mph
@@ -44,9 +44,7 @@ describe('hydrate scoped', () => { expect(clientHydrated.root).toEqualHtml(` -
- 88mph
@@ -77,7 +75,7 @@ describe('hydrate scoped', () => {
- + 88mph
@@ -97,9 +95,7 @@ describe('hydrate scoped', () => { expect(clientHydrated.root).toEqualHtml(` - -
- +
88mph
@@ -127,7 +123,7 @@ describe('hydrate scoped', () => {

- + Hello

diff --git a/src/runtime/test/hydrate-shadow-child.spec.tsx b/src/runtime/test/hydrate-shadow-child.spec.tsx index 8f6631e6c1c..95cd409877d 100644 --- a/src/runtime/test/hydrate-shadow-child.spec.tsx +++ b/src/runtime/test/hydrate-shadow-child.spec.tsx @@ -23,7 +23,7 @@ describe('hydrate, shadow child', () => {

- + Hello

@@ -81,8 +81,8 @@ describe('hydrate, shadow child', () => { - - + + light-dom @@ -102,7 +102,6 @@ describe('hydrate, shadow child', () => { - light-dom @@ -143,7 +142,7 @@ describe('hydrate, shadow child', () => {
- +
`); @@ -201,9 +200,9 @@ describe('hydrate, shadow child', () => { - + shadow-header - + `); @@ -263,8 +262,8 @@ describe('hydrate, shadow child', () => {
- - + + light-dom @@ -285,7 +284,6 @@ describe('hydrate, shadow child', () => {
- light-dom @@ -325,10 +323,10 @@ describe('hydrate, shadow child', () => { - + shadow-header
- + shadow-footer
@@ -393,8 +391,8 @@ describe('hydrate, shadow child', () => {
- - + + light-dom
@@ -417,7 +415,6 @@ describe('hydrate, shadow child', () => {
- light-dom @@ -474,13 +471,13 @@ describe('hydrate, shadow child', () => {
- + cmp-b-top-text - +
- + cmp-c
@@ -505,9 +502,7 @@ describe('hydrate, shadow child', () => {
- cmp-b-top-text -
diff --git a/src/runtime/test/hydrate-shadow-in-shadow.spec.tsx b/src/runtime/test/hydrate-shadow-in-shadow.spec.tsx index e0916a7a6d2..4a04e190e40 100644 --- a/src/runtime/test/hydrate-shadow-in-shadow.spec.tsx +++ b/src/runtime/test/hydrate-shadow-in-shadow.spec.tsx @@ -38,8 +38,8 @@ describe('hydrate, shadow in shadow', () => { - - + + light-dom @@ -60,17 +60,14 @@ describe('hydrate, shadow in shadow', () => { - - light-dom `); expect(clientHydrated.root).toEqualLightHtml(` - light-dom `); @@ -109,8 +106,8 @@ describe('hydrate, shadow in shadow', () => { - - + + light-dom @@ -130,7 +127,6 @@ describe('hydrate, shadow in shadow', () => { - light-dom @@ -172,7 +168,7 @@ describe('hydrate, shadow in shadow', () => {
- +
`); @@ -230,9 +226,9 @@ describe('hydrate, shadow in shadow', () => { - + shadow-header - + `); @@ -292,8 +288,8 @@ describe('hydrate, shadow in shadow', () => {
- - + + light-dom @@ -314,7 +310,6 @@ describe('hydrate, shadow in shadow', () => {
- light-dom @@ -354,10 +349,10 @@ describe('hydrate, shadow in shadow', () => { - + shadow-header
- + shadow-footer
@@ -422,8 +417,8 @@ describe('hydrate, shadow in shadow', () => {
- - + + light-dom
@@ -446,7 +441,6 @@ describe('hydrate, shadow in shadow', () => {
- light-dom diff --git a/src/runtime/test/hydrate-shadow-parent.spec.tsx b/src/runtime/test/hydrate-shadow-parent.spec.tsx index d9a7adc73c0..ac83ecf7d6a 100644 --- a/src/runtime/test/hydrate-shadow-parent.spec.tsx +++ b/src/runtime/test/hydrate-shadow-parent.spec.tsx @@ -32,7 +32,7 @@ describe('hydrate, shadow parent', () => {
- + middle
@@ -54,7 +54,6 @@ describe('hydrate, shadow parent', () => {
- middle `); @@ -89,12 +88,12 @@ describe('hydrate, shadow parent', () => { - + top - + middle - + bottom `); @@ -114,7 +113,6 @@ describe('hydrate, shadow parent', () => { bottom - middle `); @@ -142,7 +140,7 @@ describe('hydrate, shadow parent', () => { expect(serverHydrated.root).toEqualHtml(` - + shadow-text `); @@ -194,9 +192,9 @@ describe('hydrate, shadow parent', () => {
- +
- +
`); @@ -253,8 +251,8 @@ describe('hydrate, shadow parent', () => { - - + + cmp-a-light-dom @@ -272,8 +270,6 @@ describe('hydrate, shadow parent', () => { - - cmp-a-light-dom @@ -318,15 +314,15 @@ describe('hydrate, shadow parent', () => {
- - + +
- + Title
- - + +
`); @@ -351,13 +347,11 @@ describe('hydrate, shadow parent', () => { - Title `); expect(clientHydrated.root).toEqualLightHtml(` - Title `); @@ -408,11 +402,11 @@ describe('hydrate, shadow parent', () => { - - + + - + root-text @@ -441,12 +435,10 @@ describe('hydrate, shadow parent', () => { - - root-text @@ -481,11 +473,11 @@ describe('hydrate, shadow parent', () => { - - + + - + cmp-a-light-dom @@ -504,11 +496,8 @@ describe('hydrate, shadow parent', () => { - - - cmp-a-light-dom @@ -516,11 +505,8 @@ describe('hydrate, shadow parent', () => { expect(clientHydrated.root).toEqualLightHtml(` - - - cmp-a-light-dom diff --git a/src/runtime/test/hydrate-shadow.spec.tsx b/src/runtime/test/hydrate-shadow.spec.tsx index 41fbabd7990..f083341bcda 100644 --- a/src/runtime/test/hydrate-shadow.spec.tsx +++ b/src/runtime/test/hydrate-shadow.spec.tsx @@ -38,8 +38,8 @@ describe('hydrate, shadow', () => {
- - + + CmpALightDom
@@ -61,7 +61,6 @@ describe('hydrate, shadow', () => { - CmpALightDom @@ -113,13 +112,13 @@ describe('hydrate, shadow', () => {
- + ShadowDom
- -
+ +

LightDom1 @@ -157,7 +156,6 @@ describe('hydrate, shadow', () => {

-

diff --git a/src/runtime/test/hydrate-slot-fallback.spec.tsx b/src/runtime/test/hydrate-slot-fallback.spec.tsx new file mode 100644 index 00000000000..66e883157d8 --- /dev/null +++ b/src/runtime/test/hydrate-slot-fallback.spec.tsx @@ -0,0 +1,418 @@ +import { Component, h } from '@stencil/core'; +import { newSpecPage } from '@stencil/core/testing'; + +describe('hydrate, slot fallback', () => { + it('light dom parent, renders slot fallback content', async () => { + @Component({ + tag: 'cmp-a', + }) + class CmpA { + render() { + return ( +

+ + Fallback text + Fallback element + +
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA], + html: ``, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + +
+ + Fallback text + + + Fallback element + + + +
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + expect(clientHydrated.root).toEqualHtml(` + + +
+ + Fallback text + + Fallback element + +
+
`); + }); + + it('shadow dom parent, renders slot fallback content', async () => { + @Component({ + tag: 'cmp-a', + shadow: true, + }) + class CmpA { + render() { + return ( +
+ + Fallback text + Fallback element + +
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA], + html: ``, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + +
+ + Fallback text + + + Fallback element + + + +
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + expect(clientHydrated.root).toEqualHtml(` + + +
+ + + Fallback text + + Fallback element + + +
+
+
`); + }); + + it('light dom parent, slotted light dom child renders slot fallback text', async () => { + @Component({ + tag: 'cmp-a', + }) + class CmpA { + render() { + return ( +
+ Fallback content parent +

Non slot based content

+
+ ); + } + } + + @Component({ + tag: 'cmp-b', + }) + class CmpB { + render() { + return ( +
+ Fallback content child +

Non slot based content

+
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: ``, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + + +
+ + + + + +
+ + Fallback content child + + +

+ + Non slot based content +

+
+
+

+ + Non slot based content +

+
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + expect(clientHydrated.root.outerHTML).toEqualHtml(` + + +
+ + + +
+ + Fallback content child +

+ Non slot based content +

+
+
+

+ Non slot based content +

+
+
`); + }); + + it('shadow dom parent, slotted shadow dom child renders slot fallback text', async () => { + @Component({ + tag: 'cmp-a', + shadow: true, + }) + class CmpA { + render() { + return ( +
+ Fallback content parent +

Non slot based content

+
+ ); + } + } + + @Component({ + tag: 'cmp-b', + shadow: true, + }) + class CmpB { + render() { + return ( +
+ Fallback content child +

Non slot based content

+
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: ``, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + + +
+ + + + + +
+ + Fallback content child + + +

+ + Non slot based content +

+
+
+

+ + Non slot based content +

+
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + expect(clientHydrated.root).toEqualHtml(` + + +
+ + + Fallback content parent + +

+ Non slot based content +

+
+
+ + +
+ + + Fallback content child + +

+ Non slot based content +

+
+
+
+
`); + }); + + it('non-shadow forwarded slot to nested shadow', async () => { + @Component({ + tag: 'cmp-a', + shadow: false, + }) + class CmpA { + render() { + return ( +
+ + Fallback content parent + +
+ ); + } + } + + @Component({ + tag: 'cmp-b', + shadow: true, + }) + class CmpB { + render() { + return ( +
+ Fallback content child +
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: ` + +

slotted item 1

+

slotted item 2

+

slotted item 3

+
+ `, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + + + + +
+ + + + +
+ + + + + + +

+ slotted item 1 +

+

+ slotted item 2 +

+

+ slotted item 3 +

+
+
+
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + expect(clientHydrated.root).toEqualHtml(` + + +
+ + +
+ + + Fallback content child + + Fallback content parent + +
+
+

+ slotted item 1 +

+

+ slotted item 2 +

+

+ slotted item 3 +

+
+
+
`); + }); +}); diff --git a/src/runtime/test/hydrate-slotted-content-order.spec.tsx b/src/runtime/test/hydrate-slotted-content-order.spec.tsx new file mode 100644 index 00000000000..7cdedbf89b9 --- /dev/null +++ b/src/runtime/test/hydrate-slotted-content-order.spec.tsx @@ -0,0 +1,490 @@ +import { Component, h } from '@stencil/core'; +import { newSpecPage } from '@stencil/core/testing'; + +import { patchPseudoShadowDom } from '../../runtime/dom-extras'; + +describe('hydrated, components slotted nodes should match the original order they were slotted', () => { + const nodeOrEle = (node: Node | Element) => { + if (!node) return ''; + return (node as Element).outerHTML || node.nodeValue; + }; + + it('Shadow. Default slot', async () => { + @Component({ + tag: 'cmp-a', + shadow: true, + }) + class CmpA { + render() { + return ( +
+ +
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA], + html: ` +

slotted item 1

slotted item 2

A text node

slotted item 3

+ `, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + + + + + + + +
+ +

+ slotted item 1 +

+ + +

+ slotted item 2 +

+ + A text node +

+ slotted item 3 +

+ + +
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + const childNodes = clientHydrated.root.childNodes; + + expect(nodeOrEle(childNodes[0])).toBe(`

slotted item 1

`); + expect(nodeOrEle(childNodes[1])).toBe(` a comment `); + expect(nodeOrEle(childNodes[2])).toBe(`

slotted item 2

`); + expect(nodeOrEle(childNodes[3])).toBe(`A text node`); + expect(nodeOrEle(childNodes[4])).toBe(`

slotted item 3

`); + expect(nodeOrEle(childNodes[5])).toBe(` another comment `); + }); + + it('Shadow. Multiple slots', async () => { + @Component({ + tag: 'cmp-a', + shadow: true, + }) + class CmpA { + render() { + return ( +
+ +
+ +
+
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA], + html: ` + Default slot

second slot

+ `, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + + + + + +
+ +
+ + + + + Default slot + + +
+
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + expect(clientHydrated.root.outerHTML).toEqualHtml(` + + + Default slot +

+ second slot +

+ +
`); + + const childNodes = clientHydrated.root.childNodes; + + expect(nodeOrEle(childNodes[0])).toBe(` comment node `); + expect(nodeOrEle(childNodes[1])).toBe(` Default slot `); + expect(nodeOrEle(childNodes[2])).toBe(`

second slot

`); + expect(nodeOrEle(childNodes[3])).toBe(` another comment node `); + }); + + it('Shadow. Nested components', async () => { + @Component({ + tag: 'cmp-a', + shadow: true, + }) + class CmpA { + render() { + return ( +
+ +
+ ); + } + } + + @Component({ + tag: 'cmp-b', + shadow: true, + }) + class CmpB { + render() { + return ( +
+ +
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: ` +

slotted item 1a

A text node

slotted item 1b

B text node
+ `, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + + + + + + +
+ +

+ slotted item 1a +

+ + + + A text node + + + + + + + + +
+ +

+ slotted item 1b +

+ + + + B text node + + +
+
+
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + const childNodes = clientHydrated.root.childNodes; + + expect(nodeOrEle(childNodes[0])).toBe(`

slotted item 1a

`); + expect(nodeOrEle(childNodes[1])).toBe(` a comment `); + expect(nodeOrEle(childNodes[2])).toBe(`A text node`); + expect(nodeOrEle(childNodes[3])).toBe(` another comment a`); + expect(nodeOrEle(childNodes[4].childNodes[0])).toBe(`

slotted item 1b

`); + expect(nodeOrEle(childNodes[4].childNodes[1])).toBe(` b comment `); + expect(nodeOrEle(childNodes[4].childNodes[2])).toBe(`B text node`); + expect(nodeOrEle(childNodes[4].childNodes[3])).toBe(` another comment b`); + }); + + it('Non-Shadow. Default slot', async () => { + @Component({ + tag: 'cmp-a', + shadow: false, + }) + class CmpA { + render() { + return ( +
+ +
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA], + html: ` +

slotted item 1

slotted item 2

A text node

slotted item 3

+ `, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + + + + + + + +
+ +

+ slotted item 1 +

+ + +

+ slotted item 2 +

+ + A text node +

+ slotted item 3 +

+ + +
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + // patches this element in the same way we patch all elements in the browser + patchPseudoShadowDom(clientHydrated.root, clientHydrated.root); + + const childNodes = clientHydrated.root.childNodes; + + expect(nodeOrEle(childNodes[0])).toBe(`

slotted item 1

`); + expect(nodeOrEle(childNodes[1])).toBe(` a comment `); + expect(nodeOrEle(childNodes[2])).toBe(`

slotted item 2

`); + expect(nodeOrEle(childNodes[3])).toBe(`A text node`); + expect(nodeOrEle(childNodes[4])).toBe(`

slotted item 3

`); + expect(nodeOrEle(childNodes[5])).toBe(` another comment `); + }); + + it('Non-Shadow. Multiple slots', async () => { + @Component({ + tag: 'cmp-a', + shadow: false, + }) + class CmpA { + render() { + return ( +
+ +
+ +
+
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA], + html: ` + Default slot

second slot

+ `, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + + + + + +
+ +
+ + + + + Default slot + + +
+
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + // patches this element in the same way we patch all elements in the browser + patchPseudoShadowDom(clientHydrated.root, clientHydrated.root); + + const childNodes = clientHydrated.root.childNodes; + + expect(nodeOrEle(childNodes[0])).toBe(` comment node `); + expect(nodeOrEle(childNodes[1])).toBe(` Default slot `); + expect(nodeOrEle(childNodes[2])).toBe(`

second slot

`); + expect(nodeOrEle(childNodes[3])).toBe(` another comment node `); + }); + + it('Non-Shadow. Nested components', async () => { + @Component({ + tag: 'cmp-a', + shadow: false, + }) + class CmpA { + render() { + return ( +
+ +
+ ); + } + } + + @Component({ + tag: 'cmp-b', + shadow: false, + }) + class CmpB { + render() { + return ( +
+ +
+ ); + } + } + + const serverHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: ` +

slotted item 1a

A text node

slotted item 1b

B text node
+ `, + hydrateServerSide: true, + }); + expect(serverHydrated.root).toEqualHtml(` + + + + + + + +
+ +

+ slotted item 1a +

+ + + + A text node + + + + + + + + +
+ +

+ slotted item 1b +

+ + + + B text node + + +
+
+
+
`); + + const clientHydrated = await newSpecPage({ + components: [CmpA, CmpB], + html: serverHydrated.root.outerHTML, + hydrateClientSide: true, + }); + + // patches this element in the same way we patch all elements in the browser + patchPseudoShadowDom(clientHydrated.root, clientHydrated.root); + + const childNodes = clientHydrated.root.childNodes; + + patchPseudoShadowDom(childNodes[4], childNodes[4]); + + expect(nodeOrEle(childNodes[0])).toBe(`

slotted item 1a

`); + expect(nodeOrEle(childNodes[1])).toBe(` a comment `); + expect(nodeOrEle(childNodes[2])).toBe(`A text node`); + expect(nodeOrEle(childNodes[3])).toBe(` another comment a`); + expect(nodeOrEle(childNodes[4].childNodes[0])).toBe(`

slotted item 1b

`); + expect(nodeOrEle(childNodes[4].childNodes[1])).toBe(` b comment `); + expect(nodeOrEle(childNodes[4].childNodes[2])).toBe(`B text node`); + expect(nodeOrEle(childNodes[4].childNodes[3])).toBe(` another comment b`); + }); +}); diff --git a/src/runtime/vdom/render-slot-fallback.ts b/src/runtime/vdom/render-slot-fallback.ts new file mode 100644 index 00000000000..b13e889b2c8 --- /dev/null +++ b/src/runtime/vdom/render-slot-fallback.ts @@ -0,0 +1,133 @@ +import type * as d from '../../declarations'; +import { patchRemove } from '../dom-extras'; +import { NODE_TYPE } from '../runtime-constants'; + +/** + * Show or hide a slot nodes children + * @param slotNode a slot node, the 'children' of which should be shown or hidden + * @param hide whether to hide the slot node 'children' + */ +const renderSlotFallbackContent = (slotNode: d.RenderNode, hide: boolean) => { + // if this slot doesn't have fallback content, return + if (!slotNode['s-hsf'] || !slotNode.parentNode) return; + + // in non-shadow component, slot nodes are just empty text nodes or comment nodes + // the 'children' nodes are therefore placed next to it. + // let's loop through those now + const childNodes = ((slotNode.parentNode as d.RenderNode).__childNodes || + slotNode.parentNode.childNodes) as NodeListOf; + let childNode: d.RenderNode; + + const childNodesLen = childNodes.length; + let i = 0; + + for (i; i < childNodesLen; i++) { + childNode = childNodes[i]; + + if (childNode['s-sr'] && hide && childNode['s-psn'] === slotNode['s-sn']) { + // if this child node is a nested slot + // drill into it's children to hide them in-turn + renderSlotFallbackContent(childNode, true); + continue; + } + // this child node doesn't relate to this slot? + if (childNode['s-sn'] !== slotNode['s-sn']) continue; + + if (childNode.nodeType === NODE_TYPE.ElementNode && childNode['s-sf']) { + // we found an fallback element. Hide or show + childNode.hidden = hide; + childNode.style.display = hide ? 'none' : ''; + } else if (!!childNode['s-sfc']) { + // this child has fallback text. Add or remove it + if (hide) { + childNode['s-sfc'] = childNode.textContent || undefined; + childNode.textContent = ''; + } else if (!childNode.textContent || childNode.textContent.trim() === '') { + childNode.textContent = childNode['s-sfc']; + } + } + } +}; + +/** + * Function applied to non-shadow component nodes to mimic native shadowDom behaviour: + * - When slotted node/s are not present, show `` node children + * - When slotted node/s *are* present, hide `` node children + * @param node an entry whose children to iterate over + */ +export const updateFallbackSlotVisibility = (node: d.RenderNode) => { + if (!node) return; + + const childNodes: d.RenderNode[] = (node as d.RenderNode).__childNodes || (node.childNodes as any); + let slotNode: d.RenderNode; + let i: number; + let ilen: number; + let j: number; + let slotNameAttr: string | undefined; + let nodeType: number; + + for (i = 0, ilen = childNodes.length; i < ilen; i++) { + // slot reference node? + if (childNodes[i]['s-sr']) { + // this component uses slots and we're on a slot node + // let's find all it's slotted children or lack thereof + // and show or hide fallback nodes (`` children) + + // get the slot name for this slot reference node + slotNameAttr = childNodes[i]['s-sn']; + slotNode = childNodes[i]; + + // by default always show a fallback slot node + // then hide it if there are other slotted nodes in the light dom + renderSlotFallbackContent(slotNode, false); + + // because we found a slot fallback node let's loop over all + // the children again to + for (j = 0; j < ilen; j++) { + nodeType = childNodes[j].nodeType; + + // ignore slot fallback nodes + if (childNodes[j]['s-sf']) continue; + + // is sibling node is from a different component OR is a named fallback slot node? + if (childNodes[j]['s-hn'] !== slotNode['s-hn'] || slotNameAttr !== '') { + // you can't slot a textNode in a named slot + if (nodeType === NODE_TYPE.ElementNode && slotNameAttr === childNodes[j]['s-sn']) { + // we found a slotted element! + // let's hide all the fallback nodes + renderSlotFallbackContent(slotNode, true); + + // patches this node's removal methods + // so if it gets removed in the future + // re-asses the fallback node status + patchRemove(childNodes[j]); + break; + } + } else if (childNodes[j]['s-sn'] === slotNameAttr) { + // this is a default fallback slot node + // any element or text node (with content) + // should hide the default fallback slot node + if ( + nodeType === NODE_TYPE.ElementNode || + (nodeType === NODE_TYPE.TextNode && + childNodes[j] && + childNodes[j].textContent && + (childNodes[j].textContent as string).trim() !== '') + ) { + // we found a slotted something + // let's hide all the fallback nodes + renderSlotFallbackContent(slotNode, true); + + // patches this node's removal methods + // so if it gets removed in the future + // re-asses the fallback node status + patchRemove(childNodes[j]); + break; + } + } + } + } + // keep drilling down + updateFallbackSlotVisibility(childNodes[i]); + } +}; diff --git a/src/runtime/vdom/set-accessor.ts b/src/runtime/vdom/set-accessor.ts index 7428764808e..1f8858162b5 100644 --- a/src/runtime/vdom/set-accessor.ts +++ b/src/runtime/vdom/set-accessor.ts @@ -6,15 +6,15 @@ * * Modified for Stencil's compiler and vdom */ - import { BUILD } from '@app-data'; import { isMemberInElement, plt, win } from '@platform'; import { isComplexType } from '@utils'; +import type * as d from '../../declarations'; import { VNODE_FLAGS, XLINK_NS } from '../runtime-constants'; export const setAccessor = ( - elm: HTMLElement, + elm: d.RenderNode, memberName: string, oldValue: any, newValue: any, @@ -29,6 +29,13 @@ export const setAccessor = ( const classList = elm.classList; const oldClasses = parseClassList(oldValue); const newClasses = parseClassList(newValue); + + // for `scoped: true` components, new nodes after initial hydration + // from SSR don't have the slotted class added. Let's add that now + if (elm['s-si'] && newClasses.indexOf(elm['s-si']) < 0) { + newClasses.push(elm['s-si']); + } + classList.remove(...oldClasses.filter((c) => c && !newClasses.includes(c))); classList.add(...newClasses.filter((c) => c && !oldClasses.includes(c))); } else if (BUILD.vdomStyle && memberName === 'style') { diff --git a/src/runtime/vdom/test/scoped-slot.spec.tsx b/src/runtime/vdom/test/scoped-slot.spec.tsx index 411fa469888..a2466aa8ccd 100644 --- a/src/runtime/vdom/test/scoped-slot.spec.tsx +++ b/src/runtime/vdom/test/scoped-slot.spec.tsx @@ -42,10 +42,9 @@ describe('scoped slot', () => { }); expect(root.firstElementChild.nodeName).toBe('SPIDER'); - expect(root.firstElementChild.children).toHaveLength(1); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('SLOT-FB'); - expect(root.firstElementChild.firstElementChild.textContent).toBe('default content'); - expect(root.firstElementChild.firstElementChild.childNodes).toHaveLength(1); + expect(root.firstElementChild.children).toHaveLength(0); + expect(root.firstElementChild.textContent).toBe('default content'); + expect(root.firstElementChild.childNodes).toHaveLength(2); }); it('should use components default slot node content', async () => { @@ -68,8 +67,8 @@ describe('scoped slot', () => { }); expect(root.firstElementChild.nodeName).toBe('SPIDER'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('SLOT-FB'); - expect(root.firstElementChild.firstElementChild.firstElementChild.textContent).toBe('default content'); + expect(root.firstElementChild.firstElementChild.nodeName).toBe('DIV'); + expect(root.firstElementChild.firstElementChild.textContent).toBe('default content'); }); it('should relocate nested named slot nodes', async () => { @@ -465,10 +464,15 @@ describe('scoped slot', () => { root.msg = 'change 2'; await waitForChanges(); - expect(root.firstElementChild.nodeName).toBe('ION-CHILD'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('BULL'); - expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('WHALE'); - expect(root.firstElementChild.firstElementChild.firstElementChild.textContent).toBe('change 2'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + change 2 + + + `); }); it('should allow multiple slots with same name', async () => { @@ -504,32 +508,50 @@ describe('scoped slot', () => { html: ``, }); - expect(root.firstElementChild.nodeName).toBe('ION-CHILD'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('MOUSE'); - expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FALCON'); - expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('1'); - expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('EAGLE'); - expect(root.firstElementChild.firstElementChild.children[1].textContent).toBe('2'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + 1 + + + 2 + + + `); forceUpdate(root); await waitForChanges(); - expect(root.firstElementChild.nodeName).toBe('ION-CHILD'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('MOUSE'); - expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FALCON'); - expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('3'); - expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('EAGLE'); - expect(root.firstElementChild.firstElementChild.children[1].textContent).toBe('4'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + 3 + + + 4 + + + `); forceUpdate(root); await waitForChanges(); - expect(root.firstElementChild.nodeName).toBe('ION-CHILD'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('MOUSE'); - expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FALCON'); - expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('5'); - expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('EAGLE'); - expect(root.firstElementChild.firstElementChild.children[1].textContent).toBe('6'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + 5 + + + 6 + + + `); }); it('should only render nested named slots and default slot', async () => { @@ -570,44 +592,71 @@ describe('scoped slot', () => { html: ``, }); - expect(root.firstElementChild.nodeName).toBe('ION-CHILD'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('FLAMINGO'); - expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FERRET'); - expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('3'); - expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('HORSE'); - expect(root.firstElementChild.firstElementChild.children[1].children[0].nodeName).toBe('BUTTERFLY'); - expect(root.firstElementChild.firstElementChild.children[1].children[0].textContent).toBe('1'); - expect(root.firstElementChild.firstElementChild.children[1].children[1].nodeName).toBe('BULLFROG'); - expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].nodeName).toBe('FOX'); - expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].textContent).toBe('2'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + 3 + + + + 1 + + + + 2 + + + + + `); forceUpdate(root); await waitForChanges(); - expect(root.firstElementChild.nodeName).toBe('ION-CHILD'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('FLAMINGO'); - expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FERRET'); - expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('6'); - expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('HORSE'); - expect(root.firstElementChild.firstElementChild.children[1].children[0].nodeName).toBe('BUTTERFLY'); - expect(root.firstElementChild.firstElementChild.children[1].children[0].textContent).toBe('4'); - expect(root.firstElementChild.firstElementChild.children[1].children[1].nodeName).toBe('BULLFROG'); - expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].nodeName).toBe('FOX'); - expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].textContent).toBe('5'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + 6 + + + + 4 + + + + 5 + + + + + `); forceUpdate(root); await waitForChanges(); - expect(root.firstElementChild.nodeName).toBe('ION-CHILD'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('FLAMINGO'); - expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('FERRET'); - expect(root.firstElementChild.firstElementChild.children[0].textContent).toBe('9'); - expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('HORSE'); - expect(root.firstElementChild.firstElementChild.children[1].children[0].nodeName).toBe('BUTTERFLY'); - expect(root.firstElementChild.firstElementChild.children[1].children[0].textContent).toBe('7'); - expect(root.firstElementChild.firstElementChild.children[1].children[1].nodeName).toBe('BULLFROG'); - expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].nodeName).toBe('FOX'); - expect(root.firstElementChild.firstElementChild.children[1].children[1].children[0].textContent).toBe('8'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + 9 + + + + 7 + + + + 8 + + + + + `); }); it('should allow nested default slots', async () => { @@ -653,44 +702,56 @@ describe('scoped slot', () => { html: ``, }); - expect(root.firstElementChild.nodeName).toBe('TEST-1'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL'); - expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('TEST-2'); - expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('GOOSE'); - expect( - root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName - ).toBe('GOAT'); - expect( - root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent - ).toBe('1'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + + + + 1 + + + + + `); forceUpdate(root); await waitForChanges(); - expect(root.firstElementChild.nodeName).toBe('TEST-1'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL'); - expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('TEST-2'); - expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('GOOSE'); - expect( - root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName - ).toBe('GOAT'); - expect( - root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent - ).toBe('2'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + + + + 2 + + + + + `); forceUpdate(root); await waitForChanges(); - expect(root.firstElementChild.nodeName).toBe('TEST-1'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL'); - expect(root.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('TEST-2'); - expect(root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName).toBe('GOOSE'); - expect( - root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.nodeName - ).toBe('GOAT'); - expect( - root.firstElementChild.firstElementChild.firstElementChild.firstElementChild.firstElementChild.textContent - ).toBe('3'); + expect(root.firstElementChild.outerHTML).toEqualHtml(` + + + + + + + + 3 + + + + + `); }); it('should allow nested default slots w/ default slot content', async () => { @@ -738,49 +799,33 @@ describe('scoped slot', () => { html: ``, }); - expect(root.firstElementChild.nodeName).toBe('TEST-1'); - expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL'); - // expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('SLOT-FB'); - // expect(root.firstElementChild.firstElementChild.children[0].hasAttribute('hidden')).toBe(true); - // expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('TEST-2'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.nodeName).toBe('GOOSE'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].nodeName).toBe('SLOT-FB'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].hasAttribute('hidden')).toBe(true); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].nodeName).toBe('GOAT'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].textContent).toBe('hey goat!'); - - // forceUpdate(root); - // await waitForChanges(); - - // expect(root.firstElementChild.nodeName).toBe('TEST-1'); - // expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL'); - // expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('SLOT-FB'); - // expect(root.firstElementChild.firstElementChild.children[0].hasAttribute('hidden')).toBe(true); - // expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('TEST-2'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.nodeName).toBe('GOOSE'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].nodeName).toBe('SLOT-FB'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].hasAttribute('hidden')).toBe(true); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].nodeName).toBe('GOAT'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].textContent).toBe('hey goat!'); - - // forceUpdate(root); - // await waitForChanges(); - - // expect(root.firstElementChild.nodeName).toBe('TEST-1'); - // expect(root.firstElementChild.firstElementChild.nodeName).toBe('SEAL'); - // expect(root.firstElementChild.firstElementChild.children[0].nodeName).toBe('SLOT-FB'); - // expect(root.firstElementChild.firstElementChild.children[0].hasAttribute('hidden')).toBe(true); - // expect(root.firstElementChild.firstElementChild.children[1].nodeName).toBe('TEST-2'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.nodeName).toBe('GOOSE'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].nodeName).toBe('SLOT-FB'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[0].hasAttribute('hidden')).toBe(true); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].nodeName).toBe('GOAT'); - // expect(root.firstElementChild.firstElementChild.children[1].firstElementChild.children[1].textContent).toBe('hey goat!'); + expect(root.outerHTML).toEqualHtml(` + + + + + + + + + + + hey goat! + + + + + + `); }); - it("should hide the slot's fallback content for a scoped component when slot content passed in", async () => { - @Component({ tag: 'fallback-test', scoped: true }) - class ScopedFallbackSlotTest { + it("should hide the slot's fallback content for a non-shadow component when slot content passed in", async () => { + @Component({ tag: 'fallback-test', shadow: false }) + class NonShadowFallbackSlotTest { render() { return (
@@ -792,15 +837,155 @@ describe('scoped slot', () => { } } const { root } = await newSpecPage({ - components: [ScopedFallbackSlotTest], + components: [NonShadowFallbackSlotTest], html: `Content`, }); - expect(root.firstElementChild.children[1].nodeName).toBe('SLOT-FB'); - expect(root.firstElementChild.children[1]).toHaveAttribute('hidden'); + expect(root.outerHTML).toEqualHtml(` + + +
+ + + Content + +
+
`); }); - it("should hide the slot's fallback content for a non-shadow component when slot content passed in", async () => { + it('should deal appropriately with deeply nested slots', async () => { + @Component({ tag: 'slots-in-slots-test', shadow: false }) + class DeepNestedSlots { + render() { + return ( +
+ + DEFAULT BEFORE + DEFAULT CONTENT + + DEFAULT AFTER +

+ DEFAULT NESTED +

+
+
+
+ ); + } + } + const { body } = await newSpecPage({ + components: [DeepNestedSlots, DeepNestedSlots, DeepNestedSlots, DeepNestedSlots, DeepNestedSlots], + html: ` + + hello + hello + hello + hello + hello + `, + }); + + // nothing is slotted so all defaults should be visible + const fallbackTest = body.children[0]; + expect(fallbackTest.outerHTML).toEqualHtml(` + + +
+ DEFAULT BEFORE DEFAULT CONTENT DEFAULT AFTER +

+ DEFAULT NESTED +

+
+
`); + + // the root 'content' slot is used so all fallback slots should be empty + const parentSlotTest = body.children[1]; + expect(parentSlotTest.outerHTML).toEqualHtml(` + + +
+ + + hello + +
+
`); + + // just the before slot is used so fallback should be empty. + // the rest should have default content. + const beforeSlotTest = body.children[2]; + expect(beforeSlotTest.outerHTML).toEqualHtml(` + + +
+ + hello + + DEFAULT CONTENT DEFAULT AFTER +

+ DEFAULT NESTED +

+
+
`); + + // just the default slot is used so fallback should be empty. + // the rest should have default content. + const defaultSlotTest = body.children[3]; + expect(defaultSlotTest.outerHTML).toEqualHtml(` + + +
+ DEFAULT BEFORE + + hello + + DEFAULT AFTER +

+ DEFAULT NESTED +

+
+
`); + + // just the after slot is used so fallback should be empty. + // the fallback includes the 'nested' slot whose fallback content should be hidden. + // the rest should show default content + const afterSlotTest = body.children[4]; + expect(afterSlotTest.outerHTML).toEqualHtml(` + + +
+ DEFAULT BEFORE DEFAULT CONTENT + + + hello + +
+
`); + + // just the nested slot is used so fallback should be empty. + // the rest should have default content. + const nestedSlotTest = body.children[5]; + expect(nestedSlotTest.outerHTML).toEqualHtml(` + + +
+ DEFAULT BEFORE DEFAULT CONTENT DEFAULT AFTER +

+ + hello + +

+
+
`); + }); + + it('Show or hide fallback content on node removal / addition', async () => { @Component({ tag: 'fallback-test', shadow: false }) class NonShadowFallbackSlotTest { render() { @@ -818,7 +1003,45 @@ describe('scoped slot', () => { html: `Content`, }); - expect(root.firstElementChild.children[1].nodeName).toBe('SLOT-FB'); - expect(root.firstElementChild.children[1]).toHaveAttribute('hidden'); + expect(root.outerHTML).toEqualHtml(` + + +
+ + + Content + +
+
`); + + const span = document.querySelector('span'); + span.remove(); + + expect(root.outerHTML).toEqualHtml(` + + +
+

+ Fallback Content +

+
+
`); + + document.querySelector('fallback-test').appendChild(span); + + expect(root.outerHTML).toEqualHtml(` + + +
+ + + Content + +
+
`); }); }); diff --git a/src/runtime/vdom/vdom-annotations.ts b/src/runtime/vdom/vdom-annotations.ts index 51e9514e312..05da09fbc23 100644 --- a/src/runtime/vdom/vdom-annotations.ts +++ b/src/runtime/vdom/vdom-annotations.ts @@ -2,9 +2,11 @@ import { getHostRef } from '@platform'; import type * as d from '../../declarations'; import { + COMMENT_NODE_ID, CONTENT_REF_ID, HYDRATE_CHILD_ID, HYDRATE_ID, + HYDRATED_SLOT_FALLBACK_ID, NODE_TYPE, ORG_LOCATION_ID, SLOT_NODE_ID, @@ -38,6 +40,7 @@ export const insertVdomAnnotations = (doc: Document, staticComponents: string[]) if (nodeRef.nodeType === NODE_TYPE.ElementNode) { nodeRef.setAttribute(HYDRATE_CHILD_ID, childId); + if (typeof nodeRef['s-sn'] === 'string') nodeRef.setAttribute('s-sn', nodeRef['s-sn']); } else if (nodeRef.nodeType === NODE_TYPE.TextNode) { if (hostId === 0) { const textContent = nodeRef.nodeValue.trim(); @@ -50,6 +53,10 @@ export const insertVdomAnnotations = (doc: Document, staticComponents: string[]) const commentBeforeTextNode = doc.createComment(childId); commentBeforeTextNode.nodeValue = `${TEXT_NODE_ID}.${childId}`; nodeRef.parentNode.insertBefore(commentBeforeTextNode, nodeRef); + } else if (nodeRef.nodeType === NODE_TYPE.CommentNode) { + const commentBeforeTextNode = doc.createComment(childId); + commentBeforeTextNode.nodeValue = `${COMMENT_NODE_ID}.${childId}`; + nodeRef.parentNode.insertBefore(commentBeforeTextNode, nodeRef); } } @@ -60,7 +67,7 @@ export const insertVdomAnnotations = (doc: Document, staticComponents: string[]) if (orgLocationParentNode['s-en'] === '') { // ending with a "." means that the parent element // of this node's original location is a SHADOW dom element - // and this node is apart of the root level light dom + // and this node is a part of the root level light dom orgLocationNodeId += `.`; } else if (orgLocationParentNode['s-en'] === 'c') { // ending with a ".c" means that the parent element @@ -128,7 +135,7 @@ const insertVNodeAnnotations = ( }); } - if (hostElm && vnode && vnode.$elm$ && !hostElm.hasAttribute('c-id')) { + if (hostElm && vnode && vnode.$elm$ && !hostElm.hasAttribute(HYDRATE_CHILD_ID)) { const parent: HTMLElement = hostElm.parentElement; if (parent && parent.childNodes) { const parentChildNodes: ChildNode[] = Array.from(parent.childNodes); @@ -168,11 +175,13 @@ const insertChildVNodeAnnotations = ( if (childElm.nodeType === NODE_TYPE.ElementNode) { childElm.setAttribute(HYDRATE_CHILD_ID, childId); + if (typeof childElm['s-sn'] === 'string') childElm.setAttribute('s-sn', childElm['s-sn']); } else if (childElm.nodeType === NODE_TYPE.TextNode) { const parentNode = childElm.parentNode; const nodeName = parentNode.nodeName; if (nodeName !== 'STYLE' && nodeName !== 'SCRIPT') { - const textNodeId = `${TEXT_NODE_ID}.${childId}`; + const slotName = childElm['s-sn'] || ''; + const textNodeId = `${TEXT_NODE_ID}.${childId}.${childElm['s-sf'] ? '1' : '0'}.${slotName}`; const commentBeforeTextNode = doc.createComment(textNodeId); parentNode.insertBefore(commentBeforeTextNode, childElm); @@ -180,7 +189,35 @@ const insertChildVNodeAnnotations = ( } else if (childElm.nodeType === NODE_TYPE.CommentNode) { if (childElm['s-sr']) { const slotName = childElm['s-sn'] || ''; - const slotNodeId = `${SLOT_NODE_ID}.${childId}.${slotName}`; + const fallBackText = vnodeChild.$children$ + ?.filter((c) => c.$elm$?.nodeType === NODE_TYPE.TextNode) + .map((ce) => { + ce.$elm$['s-sf'] = true; + return ce.$text$; + }) + .join(' '); + const slotNodeId = `${SLOT_NODE_ID}.${childId}.${slotName}.${childElm['s-hsf'] ? '1' : '0'}.${ + childElm['s-sfc'] || fallBackText ? '1' : '0' + }`; + childElm.nodeValue = slotNodeId; + + // this mock slot node has fallback text + // add the content to a comment node + if (childElm['s-sfc'] || fallBackText) { + const parentNode = childElm.parentNode; + const commentBeforeFallbackTextNode = doc.createComment(childElm['s-sfc'] || fallBackText); + parentNode.insertBefore(commentBeforeFallbackTextNode, childElm); + } + + // this mock slot node has fallback nodes + // add the mock slot id as an serializable attribute + if (childElm['s-hsf'] && vnodeChild.$children$ && vnodeChild.$children$.length) { + vnodeChild.$children$.forEach((vNode) => { + if (vNode.$elm$.nodeType === NODE_TYPE.ElementNode) { + vNode.$elm$.setAttribute(HYDRATED_SLOT_FALLBACK_ID, slotNodeId); + } + }); + } childElm.nodeValue = slotNodeId; } } diff --git a/src/runtime/vdom/vdom-render.ts b/src/runtime/vdom/vdom-render.ts index a4e6fe77d8a..38282df5643 100644 --- a/src/runtime/vdom/vdom-render.ts +++ b/src/runtime/vdom/vdom-render.ts @@ -13,6 +13,7 @@ import { CMP_FLAGS, HTML_NS, isDef, SVG_NS } from '@utils'; import type * as d from '../../declarations'; import { NODE_TYPE, PLATFORM_FLAGS, VNODE_FLAGS } from '../runtime-constants'; import { h, isHost, newVNode } from './h'; +import { updateFallbackSlotVisibility } from './render-slot-fallback'; import { updateElement } from './update-element'; let scopeId: string; @@ -73,7 +74,7 @@ const createElm = (oldParentVNode: d.VNode, newParentVNode: d.VNode, childIndex: if (BUILD.vdomText && newVNode.$text$ !== null) { // create text node elm = newVNode.$elm$ = doc.createTextNode(newVNode.$text$) as any; - } else if (BUILD.slotRelocation && newVNode.$flags$ & VNODE_FLAGS.isSlotReference) { + } else if (BUILD.slotRelocation && newVNode.$flags$ & (VNODE_FLAGS.isSlotReference | VNODE_FLAGS.isSlotFallback)) { // create a slot reference node elm = newVNode.$elm$ = BUILD.isDebug || BUILD.hydrateServerSide ? slotReferenceDebugNode(newVNode) : (doc.createTextNode('') as any); @@ -84,17 +85,8 @@ const createElm = (oldParentVNode: d.VNode, newParentVNode: d.VNode, childIndex: // create element elm = newVNode.$elm$ = ( BUILD.svg - ? doc.createElementNS( - isSvgMode ? SVG_NS : HTML_NS, - BUILD.slotRelocation && newVNode.$flags$ & VNODE_FLAGS.isSlotFallback - ? 'slot-fb' - : (newVNode.$tag$ as string) - ) - : doc.createElement( - BUILD.slotRelocation && newVNode.$flags$ & VNODE_FLAGS.isSlotFallback - ? 'slot-fb' - : (newVNode.$tag$ as string) - ) + ? doc.createElementNS(isSvgMode ? SVG_NS : HTML_NS, newVNode.$tag$ as string) + : doc.createElement(newVNode.$tag$ as string) ) as any; if (BUILD.svg && isSvgMode && newVNode.$tag$ === 'foreignObject') { @@ -119,7 +111,7 @@ const createElm = (oldParentVNode: d.VNode, newParentVNode: d.VNode, childIndex: // return node could have been null if (childNode) { // append our new node - elm.appendChild(childNode); + elm.__appendChild ? elm.__appendChild(childNode) : elm.appendChild(childNode); } } } @@ -139,7 +131,7 @@ const createElm = (oldParentVNode: d.VNode, newParentVNode: d.VNode, childIndex: elm['s-hn'] = hostTagName; if (newVNode.$flags$ & (VNODE_FLAGS.isSlotFallback | VNODE_FLAGS.isSlotReference)) { - // remember the content reference comment + // this is a slot reference node elm['s-sr'] = true; // remember the content reference comment @@ -148,6 +140,48 @@ const createElm = (oldParentVNode: d.VNode, newParentVNode: d.VNode, childIndex: // remember the slot name, or empty string for default slot elm['s-sn'] = newVNode.$name$ || ''; + // if this slot is nested within another parent slot, add that slot's name. + // (used in 'renderSlotFallbackContent') + if (newParentVNode.$name$) { + elm['s-psn'] = newParentVNode.$name$; + } + + if (newVNode.$flags$ & VNODE_FLAGS.isSlotFallback) { + if (newVNode.$children$) { + // this slot has fallback nodes + + for (i = 0; i < newVNode.$children$.length; ++i) { + // create the node + let containerElm = elm.nodeType === NODE_TYPE.ElementNode ? elm : parentElm; + while (containerElm.nodeType !== NODE_TYPE.ElementNode) { + containerElm = containerElm.parentNode as d.RenderNode; + } + childNode = createElm(oldParentVNode, newVNode, i, containerElm); + + // add new node meta. + // slot has fallback and childnode is slot fallback + childNode['s-sf'] = elm['s-hsf'] = true; + + if (typeof childNode['s-sn'] === 'undefined') { + childNode['s-sn'] = newVNode.$name$ || ''; + } + + if (childNode.nodeType === NODE_TYPE.TextNode) { + childNode['s-sfc'] = childNode.textContent; + } + + // make sure a node was created + // and we don't have a node already present + // (if a node is already attached, we'll just patch it) + if (childNode && (!oldParentVNode || !oldParentVNode.$children$)) { + // append our new node + containerElm.appendChild(childNode); + } + } + } + if (oldParentVNode && oldParentVNode.$children$) patch(oldParentVNode, newVNode); + } + // check if we've got an old vnode for this slot oldVNode = oldParentVNode && oldParentVNode.$children$ && oldParentVNode.$children$[childIndex]; if (oldVNode && oldVNode.$tag$ === newVNode.$tag$ && oldParentVNode.$elm$) { @@ -164,7 +198,7 @@ const createElm = (oldParentVNode: d.VNode, newParentVNode: d.VNode, childIndex: const putBackInOriginalLocation = (parentElm: Node, recursive: boolean) => { plt.$flags$ |= PLATFORM_FLAGS.isTmpDisconnected; - const oldSlotChildNodes = parentElm.childNodes; + const oldSlotChildNodes = (parentElm as d.RenderNode).__childNodes || parentElm.childNodes; for (let i = oldSlotChildNodes.length - 1; i >= 0; i--) { const childNode = oldSlotChildNodes[i] as any; if (childNode['s-hn'] !== hostTagName && childNode['s-ol']) { @@ -232,6 +266,24 @@ const addVnodes = ( } }; +const saveSlottedNodes = (elm: d.RenderNode) => { + // by removing the hostname reference + // any current slotted elements will be 'reset' and re-slotted + const childNodes = (elm as d.RenderNode).__childNodes || elm.childNodes; + let childNode: d.RenderNode; + let i: number; + let ilen: number; + + for (i = 0, ilen = childNodes.length; i < ilen; i++) { + childNode = childNodes[i] as d.RenderNode; + if (childNode['s-ol']) { + if (childNode['s-hn']) childNode['s-hn'] = undefined; + } else { + saveSlottedNodes(childNode); + } + } +}; + /** * Remove the DOM elements corresponding to a list of {@link d.VNode} objects. * This can be used to, for instance, clean up after a list of children which @@ -250,20 +302,19 @@ const removeVnodes = (vnodes: d.VNode[], startIdx: number, endIdx: number) => { const elm = vnode.$elm$; nullifyVNodeRefs(vnode); - if (elm) { - if (BUILD.slotRelocation) { - // we're removing this element - // so it's possible we need to show slot fallback content now - checkSlotFallbackVisibility = true; - - if (elm['s-ol']) { - // remove the original location comment - elm['s-ol'].remove(); - } else { - // it's possible that child nodes of the node - // that's being removed are slot nodes - putBackInOriginalLocation(elm, true); - } + if (elm && BUILD.slotRelocation) { + // we're removing this element + // so it's possible we need to show slot fallback content now + checkSlotFallbackVisibility = true; + saveSlottedNodes(elm); + + if (elm['s-ol']) { + // remove the original location comment + elm['s-ol'].remove(); + } else { + // it's possible that child nodes of the node + // that's being removed are slot nodes + putBackInOriginalLocation(elm, true); } // remove the vnode's element from the dom @@ -342,10 +393,13 @@ const removeVnodes = (vnodes: d.VNode[], startIdx: number, endIdx: number) => { * @param newCh the new children of the parent node */ const updateChildren = (parentElm: d.RenderNode, oldCh: d.VNode[], newVNode: d.VNode, newCh: d.VNode[]) => { + const fbSlots: d.RenderNode[] = []; + const fbNodes: { [name: string]: d.RenderNode[] } = {}; let oldStartIdx = 0; let newStartIdx = 0; let idxInOld = 0; let i = 0; + let j = 0; let oldEndIdx = oldCh.length - 1; let oldStartVnode = oldCh[0]; let oldEndVnode = oldCh[oldEndIdx]; @@ -354,6 +408,13 @@ const updateChildren = (parentElm: d.RenderNode, oldCh: d.VNode[], newVNode: d.V let newEndVnode = newCh[newEndIdx]; let node: Node; let elmToMove: d.VNode; + let fbParentNodes: NodeList; + let fbParentNodesIdx: number; + let fbSlotsIdx: number; + let fbNodesIdx: number; + let fbChildNode: d.RenderNode; + let fbSlot: d.RenderNode; + let fbNode: d.RenderNode; while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) { if (oldStartVnode == null) { @@ -519,6 +580,37 @@ const updateChildren = (parentElm: d.RenderNode, oldCh: d.VNode[], newVNode: d.V // relevant DOM nodes) removeVnodes(oldCh, oldStartIdx, oldEndIdx); } + + // reorder fallback slot nodes + if (parentElm.parentNode && newVNode.$elm$['s-hsf']) { + fbParentNodes = (parentElm.parentNode as d.RenderNode).__childNodes || parentElm.parentNode.childNodes; + fbParentNodesIdx = fbParentNodes.length - 1; + + for (i = 0; i <= fbParentNodesIdx; ++i) { + fbChildNode = fbParentNodes[i] as d.RenderNode; + if (fbChildNode['s-hsf']) { + fbSlots.push(fbChildNode); + continue; + } + if (fbChildNode['s-sf']) { + if (!fbNodes[fbChildNode['s-sn']]) fbNodes[fbChildNode['s-sn']] = []; + fbNodes[fbChildNode['s-sn']].push(fbChildNode); + } + } + + fbSlotsIdx = fbSlots.length - 1; + for (i = 0; i <= fbSlotsIdx; ++i) { + fbSlot = fbSlots[i]; + if (typeof fbNodes[fbSlot['s-sn']] === 'undefined') continue; + + fbNodesIdx = fbNodes[fbSlot['s-sn']].length - 1; + for (j = 0; j <= fbNodesIdx; ++j) { + fbNode = fbNodes[fbSlot['s-sn']][j]; + fbSlot.parentNode.insertBefore(fbNode, fbSlot); + } + } + checkSlotFallbackVisibility = true; + } }; /** @@ -574,7 +666,7 @@ const parentReferenceNode = (node: d.RenderNode) => (node['s-ol'] ? node['s-ol'] * @param newVNode a new VNode representing an updated version of the old one */ export const patch = (oldVNode: d.VNode, newVNode: d.VNode) => { - const elm = (newVNode.$elm$ = oldVNode.$elm$); + const elm: d.RenderNode = (newVNode.$elm$ = oldVNode.$elm$); const oldChildren = oldVNode.$children$; const newChildren = newVNode.$children$; const tag = newVNode.$tag$; @@ -625,60 +717,10 @@ export const patch = (oldVNode: d.VNode, newVNode: d.VNode) => { } else if (BUILD.vdomText && oldVNode.$text$ !== text) { // update the text content for the text only vnode // and also only if the text is different than before - elm.data = text; - } -}; - -const updateFallbackSlotVisibility = (elm: d.RenderNode) => { - // tslint:disable-next-line: prefer-const - const childNodes: d.RenderNode[] = elm.childNodes as any; - let childNode: d.RenderNode; - let i: number; - let ilen: number; - let j: number; - let slotNameAttr: string; - let nodeType: number; - - for (i = 0, ilen = childNodes.length; i < ilen; i++) { - childNode = childNodes[i]; - - if (childNode.nodeType === NODE_TYPE.ElementNode) { - if (childNode['s-sr']) { - // this is a slot fallback node - - // get the slot name for this slot reference node - slotNameAttr = childNode['s-sn']; - - // by default always show a fallback slot node - // then hide it if there are other slots in the light dom - childNode.hidden = false; - - for (j = 0; j < ilen; j++) { - nodeType = childNodes[j].nodeType; - - if (childNodes[j]['s-hn'] !== childNode['s-hn'] || slotNameAttr !== '') { - // this sibling node is from a different component OR is a named fallback slot node - if (nodeType === NODE_TYPE.ElementNode && slotNameAttr === childNodes[j].getAttribute('slot')) { - childNode.hidden = true; - break; - } - } else { - // this is a default fallback slot node - // any element or text node (with content) - // should hide the default fallback slot node - if ( - nodeType === NODE_TYPE.ElementNode || - (nodeType === NODE_TYPE.TextNode && childNodes[j].textContent.trim() !== '') - ) { - childNode.hidden = true; - break; - } - } - } - } + elm.textContent = text; - // keep drilling down - updateFallbackSlotVisibility(childNode); + if (elm['s-sf']) { + elm['s-sfc'] = text; } } }; @@ -694,16 +736,19 @@ const relocateSlotContent = (elm: d.RenderNode) => { let relocateNodeData: RelocateNodeData; let j; let i = 0; - const childNodes: d.RenderNode[] = elm.childNodes as any; + const childNodes: d.RenderNode[] = (elm.__childNodes || elm.childNodes) as any; const ilen = childNodes.length; for (; i < ilen; i++) { childNode = childNodes[i]; if (childNode['s-sr'] && (node = childNode['s-cr']) && node.parentNode) { + if (childNode['s-hsf']) { + checkSlotFallbackVisibility = true; + } // first got the content reference comment node // then we got it's parent, which is where all the host content is in now - hostContentNodes = node.parentNode.childNodes; + hostContentNodes = (node.parentNode as d.RenderNode).__childNodes || node.parentNode.childNodes; slotNameAttr = childNode['s-sn']; for (j = hostContentNodes.length - 1; j >= 0; j--) { @@ -873,6 +918,7 @@ render() { let parentNodeRef: Node; let insertBeforeNode: Node; let refNode: d.RenderNode; + let ogInsertBeforeNode: Node; let i = 0; for (; i < relocateNodes.length; i++) { @@ -900,13 +946,17 @@ render() { // by default we're just going to insert it directly // after the slot reference node parentNodeRef = relocateData.$slotRefNode$.parentNode; - insertBeforeNode = relocateData.$slotRefNode$.nextSibling; + insertBeforeNode = + (relocateData.$slotRefNode$ as any).__nextSibling || relocateData.$slotRefNode$.nextSibling; orgLocationNode = nodeToRelocate['s-ol'] as any; + ogInsertBeforeNode = insertBeforeNode; - while ((orgLocationNode = orgLocationNode.previousSibling as any)) { + while ( + (orgLocationNode = ((orgLocationNode as any).__previousSibling || orgLocationNode.previousSibling) as any) + ) { refNode = orgLocationNode['s-nr']; if (refNode && refNode['s-sn'] === nodeToRelocate['s-sn'] && parentNodeRef === refNode.parentNode) { - refNode = refNode.nextSibling as any; + refNode = (refNode as any).__nextSibling || refNode.nextSibling; if (!refNode || !refNode['s-nr']) { insertBeforeNode = refNode; break; @@ -916,7 +966,7 @@ render() { if ( (!insertBeforeNode && parentNodeRef !== nodeToRelocate.parentNode) || - nodeToRelocate.nextSibling !== insertBeforeNode + ((nodeToRelocate as any).__nextSibling || nodeToRelocate.nextSibling) !== insertBeforeNode ) { // we've checked that it's worth while to relocate // since that the node to relocate @@ -929,6 +979,10 @@ render() { } // add it back to the dom but in its new home parentNodeRef.insertBefore(nodeToRelocate, insertBeforeNode); + // the node may have been hidden from when it didn't have a home. Re-show. + nodeToRelocate.hidden = false; + } else { + parentNodeRef.insertBefore(nodeToRelocate, ogInsertBeforeNode); } } } else { diff --git a/src/testing/reset-build-conditionals.ts b/src/testing/reset-build-conditionals.ts index 1b66137efc9..051f8fcc23e 100644 --- a/src/testing/reset-build-conditionals.ts +++ b/src/testing/reset-build-conditionals.ts @@ -46,7 +46,6 @@ export function resetBuildConditionals(b: d.BuildConditionals) { b.hydratedAttribute = false; b.hydratedClass = true; b.invisiblePrehydration = true; - b.appendChildSlotFix = false; b.cloneNodeFix = false; // TODO(STENCIL-661): Remove code related to the dynamic import shim b.dynamicImportShim = false; @@ -54,6 +53,4 @@ export function resetBuildConditionals(b: d.BuildConditionals) { // TODO(STENCIL-663): Remove code related to deprecated `safari10` field. b.safari10 = false; b.scriptDataOpts = false; - b.scopedSlotTextContentFix = false; - b.slotChildNodesFix = false; } diff --git a/test/end-to-end/package-lock.json b/test/end-to-end/package-lock.json index 13f6181a1dc..f423adab7f6 100644 --- a/test/end-to-end/package-lock.json +++ b/test/end-to-end/package-lock.json @@ -1,7 +1,4071 @@ { "name": "@stencil/end-to-end", + "lockfileVersion": 2, "requires": true, - "lockfileVersion": 1, + "packages": { + "": { + "name": "@stencil/end-to-end", + "devDependencies": { + "@stencil/react-output-target": "^0.0.9", + "@types/file-saver": "^2.0.1", + "@types/lodash": "^4.14.165", + "@types/lodash-es": "^4.17.4", + "@types/video.js": "^7.3.11", + "file-saver": "^2.0.2", + "linaria": "^1.3.3", + "lodash": "^4.17.20", + "lodash-es": "^4.17.15", + "rollup-plugin-css-only": "^2.1.0", + "rollup-plugin-node-builtins": "^2.1.2", + "video.js": "^7.10.2", + "why-is-node-running": "^2.2.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/core": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.1.tgz", + "integrity": "sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.0", + "@babel/helper-module-transforms": "^7.11.0", + "@babel/helpers": "^7.10.4", + "@babel/parser": "^7.11.1", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.11.0", + "@babel/types": "^7.11.0", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/core/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz", + "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", + "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", + "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/types": "^7.11.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/helper-module-transforms/node_modules/lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "node_modules/@babel/helpers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.11.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.3.tgz", + "integrity": "sha512-REo8xv7+sDxkKvoxEywIdsNFiZLybwdI7hcT5uEPyQrSMB4YQ973BfC9OOrD/81MaIjh6UxdulIQXkjmiH3PcA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz", + "integrity": "sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", + "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "node_modules/@babel/register": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.10.5.tgz", + "integrity": "sha512-eYHdLv43nyvmPn9bfNfrcC4+iYNwdQ8Pxk1MFJuU/U5LpSYl/PH4dFMazCYZDFVi8ueG3shvO+AQfLrxpYulQw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^2.0.0", + "lodash": "^4.17.19", + "make-dir": "^2.1.0", + "pirates": "^4.0.0", + "source-map-support": "^0.5.16" + } + }, + "node_modules/@babel/register/node_modules/lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/traverse": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz", + "integrity": "sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.0", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.0", + "@babel/types": "^7.11.0", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/traverse/node_modules/lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, + "node_modules/@babel/types": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.0.tgz", + "integrity": "sha512-O53yME4ZZI0jO1EVGtF1ePGl0LHirG4P1ibcD80XyzZcKhcMFeCXmh4Xb1ifGBIV233Qg12x4rBfQgA+tmOukA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@babel/types/node_modules/lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", + "dev": true + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.7.3.tgz", + "integrity": "sha512-uxJqm/sqwXw3YPA5GXX365OBcJGFtxUVkB6WyezqFHlNe9jqUWH5ur2O2M8dGBz61kn1g3ZBlzUunFQXQIClhA==", + "dev": true, + "dependencies": { + "@emotion/memoize": "0.7.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.1.tgz", + "integrity": "sha512-Qv4LTqO11jepd5Qmlp3M1YEjBumoTHcHFdgPTQ+sFlIL5myi/7xu/POwP7IRu6odBdmLXdtIs1D6TuW6kbwbbg==", + "dev": true + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@rollup/pluginutils/node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "node_modules/@stencil/react-output-target": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/@stencil/react-output-target/-/react-output-target-0.0.9.tgz", + "integrity": "sha512-t2sSkm/VGftBqewK47eZonaHIXW7CYWlsDy6Ln4jqNVpr93CuPWkg7rsnPiZrJrU1NBuTgA0hC2xoRcAJVm7Sw==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "node_modules/@types/file-saver": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.1.tgz", + "integrity": "sha512-g1QUuhYVVAamfCifK7oB7G3aIl4BbOyzDOqVyUfEr4tfBKrXfeH+M+Tg7HKCXSrbzxYdhyCP7z9WbKo0R2hBCw==", + "dev": true + }, + "node_modules/@types/lodash": { + "version": "4.14.165", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.165.tgz", + "integrity": "sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg==", + "dev": true + }, + "node_modules/@types/lodash-es": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.4.tgz", + "integrity": "sha512-BBz79DCJbD2CVYZH67MBeHZRX++HF+5p8Mo5MzjZi64Wac39S3diedJYHZtScbRVf4DjZyN6LzA0SB0zy+HSSQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/video.js": { + "version": "7.3.11", + "resolved": "https://registry.npmjs.org/@types/video.js/-/video.js-7.3.11.tgz", + "integrity": "sha512-9KpJkt6zsy6xRiHZjzjKxCEySqt3TgPgl0XegszwJfaLO4+n4rELS5rbsHUgLJxZaMgbJtyTPXk1HkCsJ5kRiA==", + "dev": true + }, + "node_modules/@videojs/http-streaming": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.2.4.tgz", + "integrity": "sha512-gzT46RpAEegOhMId/zZ6uXCVGDMPOv8qmoTykBuvd6/4lVM3lZ1ZJCq0kytAkisDuDKipy93gP46oZEtonlc/Q==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@videojs/vhs-utils": "^2.2.1", + "aes-decrypter": "3.1.0", + "global": "^4.3.2", + "m3u8-parser": "4.5.0", + "mpd-parser": "0.14.0", + "mux.js": "5.6.7", + "video.js": "^6 || ^7" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/@videojs/vhs-utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-2.3.0.tgz", + "integrity": "sha512-ThSmm91S7tuIJ757ON50K4y7S/bvKN4+B0tu303gCOxaG57PoP1UvPfMQZ90XGhxwNgngexVojOqbBHhTvXVHQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "global": "^4.3.2", + "url-toolkit": "^2.1.6" + }, + "engines": { + "node": ">=8", + "npm": ">=5" + } + }, + "node_modules/@videojs/xhr": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.5.1.tgz", + "integrity": "sha512-wV9nGESHseSK+S9ePEru2+OJZ1jq/ZbbzniGQ4weAmTIepuBMSYPx5zrxxQA0E786T5ykpO8ts+LayV+3/oI2w==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "global": "~4.4.0", + "is-function": "^1.0.1" + } + }, + "node_modules/@videojs/xhr/node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/@videojs/xhr/node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/abstract-leveldown": { + "version": "0.12.4", + "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-0.12.4.tgz", + "integrity": "sha1-KeGOYy5g5OIh1YECR4UqY9ey5BA=", + "dev": true, + "dependencies": { + "xtend": "~3.0.0" + } + }, + "node_modules/abstract-leveldown/node_modules/xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/aes-decrypter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.0.tgz", + "integrity": "sha512-wL1NFwP2yNrJG4InpXYFhhYe9TfonnDyhyxMq2+K9/qt+SrZzUieOpviN6pkDly7GawTqw5feehk0rn5iYo00g==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@videojs/vhs-utils": "^2.2.1", + "global": "^4.3.2", + "pkcs7": "^1.0.4" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/bl": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-0.8.2.tgz", + "integrity": "sha1-yba8oI0bwuoA/Ir7Txpf0eHGbk4=", + "dev": true, + "dependencies": { + "readable-stream": "~1.0.26" + } + }, + "node_modules/bl/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/bl/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-fs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/browserify-fs/-/browserify-fs-1.0.0.tgz", + "integrity": "sha1-8HWqinKdTRcW0GZiDjhvzBMRqW8=", + "dev": true, + "dependencies": { + "level-filesystem": "^1.0.1", + "level-js": "^2.1.3", + "levelup": "^0.18.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "dependencies": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "node_modules/buffer-es6": { + "version": "4.9.3", + "resolved": "https://registry.npmjs.org/buffer-es6/-/buffer-es6-4.9.3.tgz", + "integrity": "sha1-8mNHuC33b9N+GLy1KIxJcM/VxAQ=", + "dev": true + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dev": true, + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dev": true, + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/clone": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/clone/-/clone-0.1.19.tgz", + "integrity": "sha1-YT+2hjmyaklKxTJT4Vsaa9iK2oU=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-js": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz", + "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA==", + "dev": true, + "hasInstallScript": true + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "node_modules/deferred-leveldown": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-0.2.0.tgz", + "integrity": "sha1-LO8fER4cV4cNi7uK8mUOWHzS9bQ=", + "dev": true, + "dependencies": { + "abstract-leveldown": "~0.12.1" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties/node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "dev": true, + "dependencies": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/enhanced-resolve": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", + "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estree-walker": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", + "integrity": "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==", + "dev": true + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/file-saver": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.2.tgz", + "integrity": "sha512-Wz3c3XQ5xroCxd1G8b7yL0Ehkf0TC9oYC6buPFkNnU9EnaPlifeAFCyCh+iewXTyFRcg0a6j3J7FmJsIhlhBdw==", + "dev": true + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-yarn-workspace-root": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-1.2.1.tgz", + "integrity": "sha512-dVtfb0WuQG+8Ag2uWkbG79hOUzEsRrhBzgfn86g2sJPkzmcpGdghbNTfUKGTxymFrY/tLIodDzLoW9nOJ4FY8Q==", + "dev": true, + "dependencies": { + "fs-extra": "^4.0.3", + "micromatch": "^3.1.4" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/fwd-stream": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/fwd-stream/-/fwd-stream-1.0.4.tgz", + "integrity": "sha1-7Sgcq+1G/uz5Ie4y3ExQs3KsfPo=", + "dev": true, + "dependencies": { + "readable-stream": "~1.0.26-4" + } + }, + "node_modules/fwd-stream/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/fwd-stream/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/fwd-stream/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", + "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", + "dev": true, + "dependencies": { + "min-document": "^2.19.0", + "process": "~0.5.1" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/idb-wrapper": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/idb-wrapper/-/idb-wrapper-1.7.2.tgz", + "integrity": "sha512-zfNREywMuf0NzDo9mVsL0yegjsirJxHpKHvWcyRozIqQy89g0a3U+oBPOCN4cc0oCiOuYgZHimzaW/R46G1Mpg==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dev": true, + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "node_modules/individual": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz", + "integrity": "sha1-gzsJfa0jKU52EXqY+zjg2a1hu5c=", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/is/-/is-0.2.7.tgz", + "integrity": "sha1-OzSixI81mXLzUEKEkZOucmS2NWI=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==", + "dev": true + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-object": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-0.1.2.tgz", + "integrity": "sha1-AO+8CIFsM8/ErIJR0TLhDcZQmNc=", + "dev": true + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isbuffer": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/isbuffer/-/isbuffer-0.0.0.tgz", + "integrity": "sha1-OMFG2d9Si4v5sHAcPUPPEt8/w5s=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/keycode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz", + "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/level-blobs": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/level-blobs/-/level-blobs-0.1.7.tgz", + "integrity": "sha1-mrm5e7mfHtv594o0M+Ie1WOGva8=", + "dev": true, + "dependencies": { + "level-peek": "1.0.6", + "once": "^1.3.0", + "readable-stream": "^1.0.26-4" + } + }, + "node_modules/level-blobs/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/level-blobs/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/level-blobs/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/level-filesystem": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/level-filesystem/-/level-filesystem-1.2.0.tgz", + "integrity": "sha1-oArKmRnEpN+v3KaoEI0iWq3/Y7M=", + "dev": true, + "dependencies": { + "concat-stream": "^1.4.4", + "errno": "^0.1.1", + "fwd-stream": "^1.0.4", + "level-blobs": "^0.1.7", + "level-peek": "^1.0.6", + "level-sublevel": "^5.2.0", + "octal": "^1.0.0", + "once": "^1.3.0", + "xtend": "^2.2.0" + } + }, + "node_modules/level-fix-range": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/level-fix-range/-/level-fix-range-1.0.2.tgz", + "integrity": "sha1-vxW5Fa422EcMgh6IPd95zRZCCCg=", + "dev": true + }, + "node_modules/level-hooks": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/level-hooks/-/level-hooks-4.5.0.tgz", + "integrity": "sha1-G5rmGSKTDzMF0aYfxNg8gQLA3ZM=", + "dev": true, + "dependencies": { + "string-range": "~1.2" + } + }, + "node_modules/level-js": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/level-js/-/level-js-2.2.4.tgz", + "integrity": "sha1-vAVfQYBjXUSJtWHJSG+jcOjBFpc=", + "dev": true, + "dependencies": { + "abstract-leveldown": "~0.12.0", + "idb-wrapper": "^1.5.0", + "isbuffer": "~0.0.0", + "ltgt": "^2.1.2", + "typedarray-to-buffer": "~1.0.0", + "xtend": "~2.1.2" + } + }, + "node_modules/level-js/node_modules/object-keys": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.4.0.tgz", + "integrity": "sha1-KKaq50KN0sOpLz2V8hM13SBOAzY=", + "dev": true + }, + "node_modules/level-js/node_modules/xtend": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.1.2.tgz", + "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", + "dev": true, + "dependencies": { + "object-keys": "~0.4.0" + }, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/level-peek": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/level-peek/-/level-peek-1.0.6.tgz", + "integrity": "sha1-vsUccqgu5GTTNkNMfIdsP8vM538=", + "dev": true, + "dependencies": { + "level-fix-range": "~1.0.2" + } + }, + "node_modules/level-sublevel": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/level-sublevel/-/level-sublevel-5.2.3.tgz", + "integrity": "sha1-dEwSxy0ucr543eO5tc2E1iGRQTo=", + "dev": true, + "dependencies": { + "level-fix-range": "2.0", + "level-hooks": ">=4.4.0 <5", + "string-range": "~1.2.1", + "xtend": "~2.0.4" + } + }, + "node_modules/level-sublevel/node_modules/level-fix-range": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/level-fix-range/-/level-fix-range-2.0.0.tgz", + "integrity": "sha1-xBfWIVlEIVGhnZojZ4aPFyTC1Ug=", + "dev": true, + "dependencies": { + "clone": "~0.1.9" + } + }, + "node_modules/level-sublevel/node_modules/xtend": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.0.6.tgz", + "integrity": "sha1-XqZXptukRwacLlnFihE4ywxebO4=", + "dev": true, + "dependencies": { + "is-object": "~0.1.2", + "object-keys": "~0.2.0" + }, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/levelup": { + "version": "0.18.6", + "resolved": "https://registry.npmjs.org/levelup/-/levelup-0.18.6.tgz", + "integrity": "sha1-5qAcsIlhbI7MApHCqb0/DETj5es=", + "dev": true, + "dependencies": { + "bl": "~0.8.1", + "deferred-leveldown": "~0.2.0", + "errno": "~0.1.1", + "prr": "~0.0.0", + "readable-stream": "~1.0.26", + "semver": "~2.3.1", + "xtend": "~3.0.0" + } + }, + "node_modules/levelup/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/levelup/node_modules/prr": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", + "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=", + "dev": true + }, + "node_modules/levelup/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/levelup/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/levelup/node_modules/xtend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz", + "integrity": "sha1-XM50B7r2Qsunvs2laBEcST9ZZlo=", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/linaria": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/linaria/-/linaria-1.3.3.tgz", + "integrity": "sha512-CoDZ7mrXNHLXGRfaYCSVKQr94rvzn6KIir4dTwaq6o0VlDp9TkKOg2WHdMS7I2WhQTefdLJEdPYE/1TckAnVRw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.3.3", + "@babel/generator": "^7.3.3", + "@babel/plugin-proposal-export-namespace-from": "^7.2.0", + "@babel/plugin-syntax-dynamic-import": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.2.0", + "@babel/register": "^7.0.0", + "@emotion/is-prop-valid": "^0.7.3", + "core-js": "^3.6.3", + "cosmiconfig": "^5.1.0", + "dedent": "^0.7.0", + "enhanced-resolve": "^4.1.0", + "find-yarn-workspace-root": "^1.2.1", + "glob": "^7.1.3", + "loader-utils": "^1.2.3", + "mkdirp": "^0.5.1", + "normalize-path": "^3.0.0", + "postcss": "^7.0.14", + "react-is": "^16.8.3", + "rollup-pluginutils": "^2.4.1", + "source-map": "^0.7.3", + "strip-ansi": "^5.0.0", + "stylis": "^3.5.4", + "yargs": "^13.2.1" + }, + "bin": { + "linaria": "bin/linaria.js" + } + }, + "node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/loader-utils/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz", + "integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ==", + "dev": true + }, + "node_modules/ltgt": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz", + "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU=", + "dev": true + }, + "node_modules/m3u8-parser": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.5.0.tgz", + "integrity": "sha512-RGm/1WVCX3o1bSWbJGmJUu4zTbtJy8lImtgHM4CESFvJRXYztr1j6SW/q9/ghYOrUjgH7radsIar+z1Leln0sA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@videojs/vhs-utils": "^2.2.1", + "global": "^4.3.2" + } + }, + "node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mpd-parser": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.14.0.tgz", + "integrity": "sha512-HqXQS3WLofcnYFcxv5oWdlciddUaEnN3NasXLVQ793mdnZRrinjz2Yk1DsUYPDYOUWf6ZBBqbFhaJT5LiT2ouA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5", + "@videojs/vhs-utils": "^2.2.1", + "global": "^4.3.2", + "xmldom": "^0.1.27" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mux.js": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.6.7.tgz", + "integrity": "sha512-YSr6B8MUgE4S18MptbY2XM+JKGbw9JDkgs7YkuE/T2fpDKjOhZfb/nD6vmsVxvLYOExWNaQn1UGBp6PGsnTtew==", + "dev": true + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-keys": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-0.2.0.tgz", + "integrity": "sha1-zd7AKZiwkb5CvxA1rjLknxy26mc=", + "dev": true, + "dependencies": { + "foreach": "~2.0.1", + "indexof": "~0.0.1", + "is": "~0.2.6" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign/node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/octal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/octal/-/octal-1.0.0.tgz", + "integrity": "sha1-Y+cWKmjvvrniE1iNWOmJ0eXEUws=", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "dependencies": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "node_modules/pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "dependencies": { + "node-modules-regexp": "^1.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkcs7": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz", + "integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.5.5" + }, + "bin": { + "pkcs7": "bin/cli.js" + } + }, + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "7.0.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz", + "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/postcss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/process": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", + "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-es6": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/process-es6/-/process-es6-0.11.6.tgz", + "integrity": "sha1-xrs4n5qVH4K9TrFpYAEFvS/5x3g=", + "dev": true + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rollup-plugin-css-only": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-css-only/-/rollup-plugin-css-only-2.1.0.tgz", + "integrity": "sha512-pfdcqAWEmRMFy+ABXAQPA/DKyPqLuBTOf+lWSOgtrVs1v/q7DSXzYa9QZg4myd8/1F7NHcdvPkWnfWqMxq9vrw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^3.0.0", + "fs-extra": "^9.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/rollup-plugin-css-only/node_modules/fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/rollup-plugin-css-only/node_modules/jsonfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz", + "integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.6", + "universalify": "^1.0.0" + } + }, + "node_modules/rollup-plugin-css-only/node_modules/universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/rollup-plugin-node-builtins": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-node-builtins/-/rollup-plugin-node-builtins-2.1.2.tgz", + "integrity": "sha1-JKH+1KQyV7a2Q3HYq8bOGrFFl+k=", + "dev": true, + "dependencies": { + "browserify-fs": "^1.0.0", + "buffer-es6": "^4.9.2", + "crypto-browserify": "^3.11.0", + "process-es6": "^0.11.2" + } + }, + "node_modules/rollup-pluginutils": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz", + "integrity": "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==", + "dev": true, + "dependencies": { + "estree-walker": "^0.6.1" + } + }, + "node_modules/rust-result": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz", + "integrity": "sha1-NMdbLm3Dn+WHXlveyFteD5FTb3I=", + "dev": true, + "dependencies": { + "individual": "^2.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safe-json-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz", + "integrity": "sha1-fA9XjPzNEtM6ccDgVBPi7KFx6qw=", + "dev": true, + "dependencies": { + "rust-result": "^1.0.0" + } + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/semver": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-2.3.2.tgz", + "integrity": "sha1-uYSPJdbPNjMwc+ye+IVtQvEjPlI=", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha1-Gsig2Ug4SNFpXkGLbQMaPDzmjjs=", + "dev": true + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-range": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/string-range/-/string-range-1.2.2.tgz", + "integrity": "sha1-qJPtNH5yKZvIO++78qaSqNI51d0=", + "dev": true + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stylis": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-3.5.4.tgz", + "integrity": "sha512-8/3pSmthWM7lsPBKv7NXkzn2Uc9W7NotcwGNpJaa3k7WMM1XDCA4MgT5k/8BIexd5ydZdboXtU90XH9Ec4Bv/Q==", + "dev": true + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-1.0.4.tgz", + "integrity": "sha1-m7i6DoQfs/TPH+fCRenz+opf6Zw=", + "dev": true + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "node_modules/url-toolkit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.1.tgz", + "integrity": "sha512-8+DzgrtDZYZGhHaAop5WGVghMdCfOLGbhcArsJD0qDll71FXa7EeKxi2hilPIscn2nwMz4PRjML32Sz4JTN0Xw==", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/video.js": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.10.2.tgz", + "integrity": "sha512-kJTTrqcQn2MhPzWR8zQs6W3HPJWpowO/ZGZcKt2dcJeJdJT0dEDLYtiFdjV37SylCmu66V0flRnV8cipbthveQ==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.9.2", + "@videojs/http-streaming": "2.2.4", + "@videojs/xhr": "2.5.1", + "global": "4.3.2", + "keycode": "^2.2.0", + "safe-json-parse": "4.0.0", + "videojs-font": "3.2.0", + "videojs-vtt.js": "^0.15.2" + } + }, + "node_modules/videojs-font": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz", + "integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==", + "dev": true + }, + "node_modules/videojs-vtt.js": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.2.tgz", + "integrity": "sha512-kEo4hNMvu+6KhPvVYPKwESruwhHC3oFis133LwhXHO9U7nRnx0RiJYMiqbgwjgazDEXHR6t8oGJiHM6wq5XlAw==", + "dev": true, + "dependencies": { + "global": "^4.3.1" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/why-is-node-running": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.0.tgz", + "integrity": "sha512-rxtN9D0lJaYyP92BR5yoyWecK2txBKmBIuS7GRbOPP5bXsT37/hBqcmTrlrt25DBr9p4WJb6c9LuYSJd89vHRQ==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/xmldom": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", + "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==", + "dev": true, + "engines": { + "node": ">=0.1" + } + }, + "node_modules/xtend": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-2.2.0.tgz", + "integrity": "sha1-7vax8ZjByN6vrYsXZaBNrUoBxak=", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.10.4", @@ -3216,6 +7280,15 @@ } } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "string-range": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/string-range/-/string-range-1.2.2.tgz", @@ -3233,15 +7306,6 @@ "strip-ansi": "^5.1.0" } }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", diff --git a/test/karma/stencil.config.ts b/test/karma/stencil.config.ts index 77b1ab2e012..22d8cb415ee 100644 --- a/test/karma/stencil.config.ts +++ b/test/karma/stencil.config.ts @@ -29,16 +29,13 @@ export const config: Config = { plugins: [nodePolyfills(), sass()], buildEs5: true, extras: { - appendChildSlotFix: true, cloneNodeFix: true, cssVarsShim: true, dynamicImportShim: true, lifecycleDOMEvents: true, safari10: true, - scopedSlotTextContentFix: true, scriptDataOpts: true, shadowDomShim: true, - slotChildNodesFix: true, }, devServer: { // when running `npm start`, serve from the root directory, rather than the `www` output target location diff --git a/test/karma/test-app/slot-array-basic/karma.spec.ts b/test/karma/test-app/slot-array-basic/karma.spec.ts index b721b341188..8d9cbb9a43e 100644 --- a/test/karma/test-app/slot-array-basic/karma.spec.ts +++ b/test/karma/test-app/slot-array-basic/karma.spec.ts @@ -1,3 +1,4 @@ +import type { HTMLStencilElement } from '../../../../internal'; import { setupDomTests } from '../util'; describe('slot array basic', () => { @@ -10,41 +11,41 @@ describe('slot array basic', () => { afterEach(tearDownDom); it('renders slotted content between header/footer', async () => { - let elm = app.querySelector('.results1'); - expect(elm.children[0].nodeName.toLowerCase()).toContain('header'); - expect(elm.children[0].textContent.trim()).toBe('Header'); - expect(elm.children[1].nodeName.toLowerCase()).toContain('footer'); - expect(elm.children[1].textContent.trim()).toBe('Footer'); + let elm = app.querySelector('.results1') as HTMLStencilElement; + expect(elm.__children[0].nodeName.toLowerCase()).toContain('header'); + expect(elm.__children[0].textContent.trim()).toBe('Header'); + expect(elm.__children[1].nodeName.toLowerCase()).toContain('footer'); + expect(elm.__children[1].textContent.trim()).toBe('Footer'); - elm = app.querySelector('.results2'); - expect(elm.children[0].nodeName.toLowerCase()).toContain('header'); - expect(elm.children[0].textContent.trim()).toBe('Header'); - expect(elm.children[1].nodeName.toLowerCase()).toContain('content-top'); - expect(elm.children[1].textContent.trim()).toBe('Content'); - expect(elm.children[2].nodeName.toLowerCase()).toContain('footer'); - expect(elm.children[2].textContent.trim()).toBe('Footer'); + elm = app.querySelector('.results2') as HTMLStencilElement; + expect(elm.__children[0].nodeName.toLowerCase()).toContain('header'); + expect(elm.__children[0].textContent.trim()).toBe('Header'); + expect(elm.__children[1].nodeName.toLowerCase()).toContain('content-top'); + expect(elm.__children[1].textContent.trim()).toBe('Content'); + expect(elm.__children[2].nodeName.toLowerCase()).toContain('footer'); + expect(elm.__children[2].textContent.trim()).toBe('Footer'); - elm = app.querySelector('.results3'); - expect(elm.children[0].nodeName.toLowerCase()).toContain('header'); - expect(elm.children[0].textContent.trim()).toBe('Header'); - expect(elm.children[1].nodeName.toLowerCase()).toContain('content-top'); - expect(elm.children[1].textContent.trim()).toBe('Content Top'); - expect(elm.children[2].nodeName.toLowerCase()).toContain('content-bottom'); - expect(elm.children[2].textContent.trim()).toBe('Content Bottom'); - expect(elm.children[3].nodeName.toLowerCase()).toContain('footer'); - expect(elm.children[3].textContent.trim()).toBe('Footer'); + elm = app.querySelector('.results3') as HTMLStencilElement; + expect(elm.__children[0].nodeName.toLowerCase()).toContain('header'); + expect(elm.__children[0].textContent.trim()).toBe('Header'); + expect(elm.__children[1].nodeName.toLowerCase()).toContain('content-top'); + expect(elm.__children[1].textContent.trim()).toBe('Content Top'); + expect(elm.__children[2].nodeName.toLowerCase()).toContain('content-bottom'); + expect(elm.__children[2].textContent.trim()).toBe('Content Bottom'); + expect(elm.__children[3].nodeName.toLowerCase()).toContain('footer'); + expect(elm.__children[3].textContent.trim()).toBe('Footer'); - elm = app.querySelector('.results4'); - expect(elm.children[0].nodeName.toLowerCase()).toContain('header'); - expect(elm.children[0].textContent.trim()).toBe('Header'); - expect(elm.children[1].nodeName.toLowerCase()).toContain('content-top'); - expect(elm.children[1].textContent.trim()).toBe('Content Top'); - expect(elm.children[2].nodeName.toLowerCase()).toContain('content-middle'); - expect(elm.children[2].textContent.trim()).toBe('Content Middle'); - expect(elm.children[3].nodeName.toLowerCase()).toContain('content-bottom'); - expect(elm.children[3].textContent.trim()).toBe('Content Bottom'); - expect(elm.children[4].nodeName.toLowerCase()).toContain('footer'); - expect(elm.children[4].textContent.trim()).toBe('Footer'); + elm = app.querySelector('.results4') as HTMLStencilElement; + expect(elm.__children[0].nodeName.toLowerCase()).toContain('header'); + expect(elm.__children[0].textContent.trim()).toBe('Header'); + expect(elm.__children[1].nodeName.toLowerCase()).toContain('content-top'); + expect(elm.__children[1].textContent.trim()).toBe('Content Top'); + expect(elm.__children[2].nodeName.toLowerCase()).toContain('content-middle'); + expect(elm.__children[2].textContent.trim()).toBe('Content Middle'); + expect(elm.__children[3].nodeName.toLowerCase()).toContain('content-bottom'); + expect(elm.__children[3].textContent.trim()).toBe('Content Bottom'); + expect(elm.__children[4].nodeName.toLowerCase()).toContain('footer'); + expect(elm.__children[4].textContent.trim()).toBe('Footer'); const hiddenCmp = app.querySelector('[hidden]'); expect(hiddenCmp).toBe(null); diff --git a/test/karma/test-app/slot-array-complex/karma.spec.ts b/test/karma/test-app/slot-array-complex/karma.spec.ts index f12a94a9a65..04704628dc8 100644 --- a/test/karma/test-app/slot-array-complex/karma.spec.ts +++ b/test/karma/test-app/slot-array-complex/karma.spec.ts @@ -11,9 +11,9 @@ describe('slot array complex', () => { it('renders slotted content', async () => { let result = app.querySelector('main slot-array-complex'); - expect(result.children[0].textContent.trim()).toBe('slot - start'); - expect(result.children[1].textContent.trim()).toBe('slot - default'); - expect(result.children[2].textContent.trim()).toBe('slot - end'); + expect(result.childNodes[0].textContent.trim()).toBe('slot - start'); + expect(result.childNodes[1].textContent.trim()).toBe('slot - default'); + expect(result.childNodes[2].textContent.trim()).toBe('slot - end'); const hiddenCmp = app.querySelector('[hidden]'); expect(hiddenCmp).toBe(null); diff --git a/test/karma/test-app/slot-fallback/karma.spec.ts b/test/karma/test-app/slot-fallback/karma.spec.ts index af4348678cf..375a01a4f74 100644 --- a/test/karma/test-app/slot-fallback/karma.spec.ts +++ b/test/karma/test-app/slot-fallback/karma.spec.ts @@ -1,7 +1,6 @@ import { setupDomTests, waitForChanges } from '../util'; -// TODO(STENCIL-18) Restore this test and fix the underlying issue. -xdescribe('slot-fallback', () => { +describe('slot-fallback', () => { const { setupDom, tearDownDom } = setupDomTests(document); let app: HTMLElement; @@ -21,42 +20,32 @@ xdescribe('slot-fallback', () => { buttonChangeSlotContent = app.querySelector('button.change-slot-content'); // show fallback content - result = app.querySelector('.results1 slot-fb[name="start"]:not([hidden])'); - expect(result.textContent).toBe('slot start fallback 0'); + result = app.querySelector('.results1 div'); + expect(result.textContent).toBe('slot start fallback 0slot default fallback 0slot end fallback 0'); - result = app.querySelector('.results1 section slot-fb:not([hidden])'); + result = app.querySelector('.results1 section'); expect(result.textContent).toBe('slot default fallback 0'); - result = app.querySelector('.results1 article span slot-fb[name="end"]:not([hidden])'); + result = app.querySelector('.results1 article span'); expect(result.textContent).toBe('slot end fallback 0'); // update fallback content buttonChangeFallbackContent.click(); await waitForChanges(); - result = app.querySelector('.results1 slot-fb[name="start"]:not([hidden])'); - expect(result.textContent).toBe('slot start fallback 1'); + result = app.querySelector('.results1 div'); + expect(result.textContent).toBe('slot start fallback 1slot default fallback 1slot end fallback 1'); - result = app.querySelector('.results1 section slot-fb:not([hidden])'); + result = app.querySelector('.results1 section'); expect(result.textContent).toBe('slot default fallback 1'); - result = app.querySelector('.results1 article span slot-fb[name="end"]:not([hidden])'); + result = app.querySelector('.results1 article span'); expect(result.textContent).toBe('slot end fallback 1'); // set light dom instead and hide fallback content buttonChangeLightDom.click(); await waitForChanges(); - // fallback content hidden but still the same - result = app.querySelector('.results1 slot-fb[name="start"][hidden]'); - expect(result.textContent).toBe('slot start fallback 1'); - - result = app.querySelector('.results1 section slot-fb[hidden]'); - expect(result.textContent).toBe('slot default fallback 1'); - - result = app.querySelector('.results1 article span slot-fb[name="end"][hidden]'); - expect(result.textContent).toBe('slot end fallback 1'); - // light dom content rendered result = app.querySelector('.results1 content-start[slot="start"]'); expect(result.textContent).toBe('slot light dom 0 : start'); @@ -71,24 +60,17 @@ xdescribe('slot-fallback', () => { buttonChangeSlotContent.click(); await waitForChanges(); - // fallback content hidden and updated content - result = app.querySelector('.results1 slot-fb[name="start"][hidden]'); - expect(result.textContent).toBe('slot start fallback 2'); - - result = app.querySelector('.results1 section slot-fb[hidden]'); - expect(result.textContent).toBe('slot default fallback 2'); + // fallback content is removed. Light dom is updated + result = app.querySelector('.results1 div'); + expect(result.textContent).toBe('slot light dom 1 : startslot light dom 1 : defaultslot light dom 1 : end'); - result = app.querySelector('.results1 article span slot-fb[name="end"][hidden]'); - expect(result.textContent).toBe('slot end fallback 2'); - - // light dom content updated result = app.querySelector('.results1 content-start[slot="start"]'); expect(result.textContent).toBe('slot light dom 1 : start'); - result = app.querySelector('.results1 section content-default'); + result = app.querySelector('.results1 section'); expect(result.textContent).toBe('slot light dom 1 : default'); - result = app.querySelector('.results1 article span content-end'); + result = app.querySelector('.results1 article span'); expect(result.textContent).toBe('slot light dom 1 : end'); // change back to fallback content @@ -96,13 +78,13 @@ xdescribe('slot-fallback', () => { await waitForChanges(); // fallback content should not be hidden - result = app.querySelector('.results1 slot-fb[name="start"]:not([hidden])'); - expect(result.textContent).toBe('slot start fallback 2'); + result = app.querySelector('.results1 div'); + expect(result.textContent).toBe('slot start fallback 2slot default fallback 2slot end fallback 2'); - result = app.querySelector('.results1 section slot-fb:not([hidden])'); + result = app.querySelector('.results1 section'); expect(result.textContent).toBe('slot default fallback 2'); - result = app.querySelector('.results1 article span slot-fb[name="end"]:not([hidden])'); + result = app.querySelector('.results1 article span'); expect(result.textContent).toBe('slot end fallback 2'); // light dom content should not exist @@ -121,13 +103,13 @@ xdescribe('slot-fallback', () => { await waitForChanges(); // fallback content should not be hidden - result = app.querySelector('.results1 slot-fb[name="start"]:not([hidden])'); - expect(result.textContent).toBe('slot start fallback 3'); + result = app.querySelector('.results1 div'); + expect(result.textContent).toBe('slot start fallback 3slot default fallback 3slot end fallback 3'); - result = app.querySelector('.results1 section slot-fb:not([hidden])'); + result = app.querySelector('.results1 section'); expect(result.textContent).toBe('slot default fallback 3'); - result = app.querySelector('.results1 article span slot-fb[name="end"]:not([hidden])'); + result = app.querySelector('.results1 article span'); expect(result.textContent).toBe('slot end fallback 3'); // light dom content should not exist @@ -144,17 +126,10 @@ xdescribe('slot-fallback', () => { buttonChangeLightDom.click(); await waitForChanges(); - // fallback content hidden and updated content - result = app.querySelector('.results1 slot-fb[name="start"][hidden]'); - expect(result.textContent).toBe('slot start fallback 3'); - - result = app.querySelector('.results1 section slot-fb[hidden]'); - expect(result.textContent).toBe('slot default fallback 3'); - - result = app.querySelector('.results1 article span slot-fb[name="end"][hidden]'); - expect(result.textContent).toBe('slot end fallback 3'); + // fallback content is removed. Light dom is updated + result = app.querySelector('.results1 div'); + expect(result.textContent).toBe('slot light dom 2 : startslot light dom 2 : defaultslot light dom 2 : end'); - // light dom content updated result = app.querySelector('.results1 content-start[slot="start"]'); expect(result.textContent).toBe('slot light dom 2 : start'); diff --git a/test/karma/test-app/slot-nested-order/karma.spec.ts b/test/karma/test-app/slot-nested-order/karma.spec.ts index d660ff16707..0a0063ecc49 100644 --- a/test/karma/test-app/slot-nested-order/karma.spec.ts +++ b/test/karma/test-app/slot-nested-order/karma.spec.ts @@ -1,3 +1,4 @@ +import type { HTMLStencilElement } from '../../../../internal'; import { setupDomTests } from '../util'; describe('slot-nested-order', function () { @@ -10,9 +11,9 @@ describe('slot-nested-order', function () { afterEach(tearDownDom); it('correct nested order', async () => { - const root = app.querySelector('slot-nested-order-parent'); + const root = app.querySelector('slot-nested-order-parent') as HTMLStencilElement; - expect(root.textContent).toBe('123456'); + expect(root.__textContent).toBe('123456'); const hiddenCmp = root.querySelector('[hidden]'); expect(hiddenCmp).toBe(null); diff --git a/test/karma/test-app/slot-reorder/karma.spec.ts b/test/karma/test-app/slot-reorder/karma.spec.ts index af95e46b99a..a2a84f5e8dd 100644 --- a/test/karma/test-app/slot-reorder/karma.spec.ts +++ b/test/karma/test-app/slot-reorder/karma.spec.ts @@ -17,52 +17,40 @@ describe('slot-reorder', () => { r = app.querySelector('.results1 div'); expect(r.children[0].textContent.trim()).toBe('fallback default'); expect(r.children[0].hasAttribute('hidden')).toBe(false); - expect(r.children[0].getAttribute('name')).toBe(null); expect(r.children[1].textContent.trim()).toBe('fallback slot-a'); expect(r.children[1].hasAttribute('hidden')).toBe(false); - expect(r.children[1].getAttribute('name')).toBe('slot-a'); expect(r.children[2].textContent.trim()).toBe('fallback slot-b'); expect(r.children[2].hasAttribute('hidden')).toBe(false); - expect(r.children[2].getAttribute('name')).toBe('slot-b'); r = app.querySelector('.results2 div'); expect(r.children[0].textContent.trim()).toBe('fallback default'); expect(r.children[0].hasAttribute('hidden')).toBe(true); - expect(r.children[0].getAttribute('name')).toBe(null); expect(r.children[1].textContent.trim()).toBe('default content'); expect(r.children[2].textContent.trim()).toBe('fallback slot-a'); expect(r.children[2].hasAttribute('hidden')).toBe(false); - expect(r.children[2].getAttribute('name')).toBe('slot-a'); expect(r.children[3].textContent.trim()).toBe('fallback slot-b'); expect(r.children[3].hasAttribute('hidden')).toBe(false); - expect(r.children[3].getAttribute('name')).toBe('slot-b'); r = app.querySelector('.results3 div'); expect(r.children[0].textContent.trim()).toBe('fallback default'); expect(r.children[0].hasAttribute('hidden')).toBe(true); - expect(r.children[0].getAttribute('name')).toBe(null); expect(r.children[1].textContent.trim()).toBe('default content'); expect(r.children[2].textContent.trim()).toBe('fallback slot-a'); expect(r.children[2].hasAttribute('hidden')).toBe(true); - expect(r.children[2].getAttribute('name')).toBe('slot-a'); expect(r.children[3].textContent.trim()).toBe('slot-a content'); expect(r.children[4].textContent.trim()).toBe('fallback slot-b'); expect(r.children[4].hasAttribute('hidden')).toBe(true); - expect(r.children[4].getAttribute('name')).toBe('slot-b'); expect(r.children[5].textContent.trim()).toBe('slot-b content'); r = app.querySelector('.results4 div'); expect(r.children[0].textContent.trim()).toBe('fallback default'); expect(r.children[0].hasAttribute('hidden')).toBe(true); - expect(r.children[0].getAttribute('name')).toBe(null); expect(r.children[1].textContent.trim()).toBe('default content'); expect(r.children[2].textContent.trim()).toBe('fallback slot-a'); expect(r.children[2].hasAttribute('hidden')).toBe(true); - expect(r.children[2].getAttribute('name')).toBe('slot-a'); expect(r.children[3].textContent.trim()).toBe('slot-a content'); expect(r.children[4].textContent.trim()).toBe('fallback slot-b'); expect(r.children[4].hasAttribute('hidden')).toBe(true); - expect(r.children[4].getAttribute('name')).toBe('slot-b'); expect(r.children[5].textContent.trim()).toBe('slot-b content'); } @@ -70,52 +58,40 @@ describe('slot-reorder', () => { r = app.querySelector('.results1 div'); expect(r.children[0].textContent.trim()).toBe('fallback slot-b'); expect(r.children[0].hasAttribute('hidden')).toBe(false); - expect(r.children[0].getAttribute('name')).toBe('slot-b'); expect(r.children[1].textContent.trim()).toBe('fallback default'); expect(r.children[1].hasAttribute('hidden')).toBe(false); - expect(r.children[1].getAttribute('name')).toBe(null); expect(r.children[2].textContent.trim()).toBe('fallback slot-a'); expect(r.children[2].hasAttribute('hidden')).toBe(false); - expect(r.children[2].getAttribute('name')).toBe('slot-a'); r = app.querySelector('.results2 div'); expect(r.children[0].textContent.trim()).toBe('fallback slot-b'); expect(r.children[0].hasAttribute('hidden')).toBe(false); - expect(r.children[0].getAttribute('name')).toBe('slot-b'); expect(r.children[1].textContent.trim()).toBe('fallback default'); expect(r.children[1].hasAttribute('hidden')).toBe(true); - expect(r.children[1].getAttribute('name')).toBe(null); expect(r.children[2].textContent.trim()).toBe('default content'); expect(r.children[3].textContent.trim()).toBe('fallback slot-a'); expect(r.children[3].hasAttribute('hidden')).toBe(false); - expect(r.children[3].getAttribute('name')).toBe('slot-a'); r = app.querySelector('.results3 div'); expect(r.children[0].textContent.trim()).toBe('fallback slot-b'); expect(r.children[0].hasAttribute('hidden')).toBe(true); - expect(r.children[0].getAttribute('name')).toBe('slot-b'); expect(r.children[1].textContent.trim()).toBe('slot-b content'); expect(r.children[2].textContent.trim()).toBe('fallback default'); expect(r.children[2].hasAttribute('hidden')).toBe(true); - expect(r.children[2].getAttribute('name')).toBe(null); expect(r.children[3].textContent.trim()).toBe('default content'); expect(r.children[4].textContent.trim()).toBe('fallback slot-a'); expect(r.children[4].hasAttribute('hidden')).toBe(true); - expect(r.children[4].getAttribute('name')).toBe('slot-a'); expect(r.children[5].textContent.trim()).toBe('slot-a content'); r = app.querySelector('.results4 div'); expect(r.children[0].textContent.trim()).toBe('fallback slot-b'); expect(r.children[0].hasAttribute('hidden')).toBe(true); - expect(r.children[0].getAttribute('name')).toBe('slot-b'); expect(r.children[1].textContent.trim()).toBe('slot-b content'); expect(r.children[2].textContent.trim()).toBe('fallback default'); expect(r.children[2].hasAttribute('hidden')).toBe(true); - expect(r.children[2].getAttribute('name')).toBe(null); expect(r.children[3].textContent.trim()).toBe('default content'); expect(r.children[4].textContent.trim()).toBe('fallback slot-a'); expect(r.children[4].hasAttribute('hidden')).toBe(true); - expect(r.children[4].getAttribute('name')).toBe('slot-a'); expect(r.children[5].textContent.trim()).toBe('slot-a content'); }