UNPKG

perlite

Version:

[![perlite logo](/docs/logo.svg)]()

1 lines 178 kB
{"version":3,"file":"perlite.min.mjs","sources":["../node_modules/hyperactiv/src/tools.js","../node_modules/hyperactiv/src/data.js","../node_modules/hyperactiv/src/batcher.js","../node_modules/hyperactiv/src/observe.js","../node_modules/hyperactiv/src/computed.js","../node_modules/hyperactiv/src/index.js","../node_modules/hyperactiv/src/dispose.js","../node_modules/lit-html/src/lib/directive.ts","../node_modules/lit-html/src/lib/dom.ts","../node_modules/lit-html/src/lib/part.ts","../node_modules/lit-html/src/lib/template.ts","../node_modules/lit-html/src/lib/template-instance.ts","../node_modules/lit-html/src/lib/template-result.ts","../node_modules/lit-html/src/lib/parts.ts","../node_modules/lit-html/src/lib/default-template-processor.ts","../node_modules/lit-html/src/lib/template-factory.ts","../node_modules/lit-html/src/lib/render.ts","../node_modules/lit-html/src/lit-html.ts","../src/utils.ts","../node_modules/lit-html/src/directives/repeat.ts","../node_modules/lit-html/src/directives/cache.ts","../node_modules/lit-html/src/directives/until.ts","../node_modules/lit-html/src/directives/live.ts","../node_modules/lit-html/src/directives/guard.ts","../node_modules/lit-html/src/directives/class-map.ts","../node_modules/lit-html/src/directives/style-map.ts","../node_modules/lit-html/src/directives/if-defined.ts","../node_modules/lit-html/src/directives/async-append.ts","../node_modules/lit-html/src/directives/async-replace.ts","../node_modules/lit-html/src/directives/template-content.ts","../node_modules/lit-html/src/directives/unsafe-html.ts","../node_modules/lit-html/src/directives/unsafe-svg.ts","../src/directives/each.ts","../src/directives/ref.ts","../src/directives/decorator.ts","../src/directives/bind.ts","../src/directives/call.ts","../src/directives/capture.ts","../src/directives/once.ts","../src/directives/passive.ts","../src/directives/prevent.ts","../src/directives/stop.ts","../src/directives/self.ts","../src/index.ts"],"sourcesContent":["const BIND_IGNORED = [\n 'String',\n 'Number',\n 'Object',\n 'Array',\n 'Boolean',\n 'Date'\n]\n\nexport function isObj(object) { return object && typeof object === 'object' }\nexport function setHiddenKey(object, key, value) {\n Object.defineProperty(object, key, { value, enumerable: false, configurable: true })\n}\nexport function defineBubblingProperties(object, key, parent) {\n setHiddenKey(object, '__key', key)\n setHiddenKey(object, '__parent', parent)\n}\nexport function getInstanceMethodKeys(object) {\n return (\n Object\n .getOwnPropertyNames(object)\n .concat(\n Object.getPrototypeOf(object) &&\n BIND_IGNORED.indexOf(Object.getPrototypeOf(object).constructor.name) < 0 ?\n Object.getOwnPropertyNames(Object.getPrototypeOf(object)) :\n []\n )\n .filter(prop => prop !== 'constructor' && typeof object[prop] === 'function')\n )\n}\n","export const data = {\n computedStack: [],\n observersMap: new WeakMap(),\n computedDependenciesTracker: new WeakMap()\n}\n","let timeout = null\nconst queue = new Set()\nfunction process() {\n for(const task of queue) {\n task()\n }\n queue.clear()\n timeout = null\n}\n\nexport function enqueue(task, batch) {\n if(timeout === null)\n timeout = setTimeout(process, batch === true ? 0 : batch)\n queue.add(task)\n}\n\n","import {\n isObj,\n defineBubblingProperties,\n getInstanceMethodKeys,\n setHiddenKey\n} from './tools'\nimport { data } from './data'\nimport { enqueue } from './batcher'\n\nconst { observersMap, computedStack, computedDependenciesTracker } = data\n\nexport function observe(obj, options = {}) {\n // 'deep' is slower but reasonable; 'shallow' a performance enhancement but with side-effects\n const {\n props,\n ignore,\n batch,\n deep = true,\n bubble,\n bind\n } = options\n\n // Ignore if the object is already observed\n if(obj.__observed) {\n return obj\n }\n\n // If the prop is explicitely not excluded\n const isWatched = prop => (!props || props.includes(prop)) && (!ignore || !ignore.includes(prop))\n\n // Add the object to the observers map.\n // observersMap signature : Map<Object, Map<Property, Set<Computed function>>>\n // In other words, observersMap is a map of observed objects.\n // For each observed object, each property is mapped with a set of computed functions depending on this property.\n // Whenever a property is set, we re-run each one of the functions stored inside the matching Set.\n observersMap.set(obj, new Map())\n\n // If the deep flag is set, observe nested objects/arrays\n if(deep) {\n Object.entries(obj).forEach(function([key, val]) {\n if(isObj(val)) {\n obj[key] = observe(val, options)\n // If bubble is set, we add keys to the object used to bubble up the mutation\n if(bubble) {\n defineBubblingProperties(obj[key], key, obj)\n }\n }\n })\n }\n\n // Proxify the object in order to intercept get/set on props\n const proxy = new Proxy(obj, {\n get(_, prop) {\n if(prop === '__observed')\n return true\n\n // If the prop is watched\n if(isWatched(prop)) {\n // If a computed function is being run\n if(computedStack.length) {\n const propertiesMap = observersMap.get(obj)\n if(!propertiesMap.has(prop))\n propertiesMap.set(prop, new Set())\n // Tracks object and properties accessed during the function call\n const tracker = computedDependenciesTracker.get(computedStack[0])\n if(tracker) {\n if(!tracker.has(obj)) {\n tracker.set(obj, new Set())\n }\n tracker.get(obj).add(prop)\n }\n // Link the computed function and the property being accessed\n propertiesMap.get(prop).add(computedStack[0])\n }\n }\n\n return obj[prop]\n },\n set(_, prop, value) {\n if(prop === '__handler') {\n // Don't track bubble handlers\n setHiddenKey(obj, '__handler', value)\n } else if(!isWatched(prop)) {\n // If the prop is ignored\n obj[prop] = value\n } else if(Array.isArray(obj) && prop === 'length' || obj[prop] !== value) {\n // If the new/old value are not equal\n const deeper = deep && isObj(value)\n const propertiesMap = observersMap.get(obj)\n\n // Remove bubbling infrastructure and pass old value to handlers\n const oldValue = obj[prop]\n if(isObj(oldValue))\n delete obj[prop]\n\n // If the deep flag is set we observe the newly set value\n obj[prop] = deeper ? observe(value, options) : value\n\n // Co-opt assigned object into bubbling if appropriate\n if(deeper && bubble) {\n defineBubblingProperties(obj[prop], prop, obj)\n }\n\n const ancestry = [ prop ]\n let parent = obj\n while(parent) {\n // If a handler explicitly returns 'false' then stop propagation\n if(parent.__handler && parent.__handler(ancestry, value, oldValue, proxy) === false) {\n break\n }\n // Continue propagation, traversing the mutated property's object hierarchy & call any __handlers along the way\n if(parent.__key && parent.__parent) {\n ancestry.unshift(parent.__key)\n parent = parent.__parent\n } else {\n parent = null\n }\n }\n\n const dependents = propertiesMap.get(prop)\n if(dependents) {\n // Retrieve the computed functions depending on the prop\n for(const dependent of dependents) {\n const tracker = computedDependenciesTracker.get(dependent)\n // If the function has been disposed or if the prop has not been used\n // during the latest function call, delete the function reference\n if(dependent.__disposed || tracker && (!tracker.has(obj) || !tracker.get(obj).has(prop))) {\n dependents.delete(dependent)\n } else if(dependent !== computedStack[0]) {\n // Run the computed function\n if(batch) {\n enqueue(dependent, batch)\n } else {\n dependent()\n }\n }\n }\n }\n }\n\n return true\n }\n })\n\n if(bind) {\n // Need this for binding es6 classes methods which are stored in the object prototype\n getInstanceMethodKeys(obj).forEach(key => obj[key] = obj[key].bind(proxy))\n }\n\n return proxy\n}\n","import { data } from './data'\nconst { computedStack, computedDependenciesTracker } = data\n\nexport function computed(wrappedFunction, { autoRun = true, callback, bind, disableTracking = false } = {}) {\n // Proxify the function in order to intercept the calls\n const proxy = new Proxy(wrappedFunction, {\n apply(target, thisArg, argsList) {\n function observeComputation(fun) {\n // Track object and object properties accessed during this function call\n if(!disableTracking) {\n computedDependenciesTracker.set(callback || proxy, new WeakMap())\n }\n // Store into the stack a reference to the computed function\n computedStack.unshift(callback || proxy)\n // Run the computed function - or the async function\n const result = fun ?\n fun() :\n target.apply(bind || thisArg, argsList)\n // Remove the reference\n computedStack.shift()\n // Return the result\n return result\n }\n\n // Inject the computeAsync argument which is used to manually declare when the computation takes part\n argsList.push({\n computeAsync: function(target) { return observeComputation(target) }\n })\n\n return observeComputation()\n }\n })\n\n // If autoRun, then call the function at once\n if(autoRun) {\n proxy()\n }\n\n return proxy\n}\n","import { observe } from './observe'\nimport { computed } from './computed'\nimport { dispose } from './dispose'\n\nexport default {\n observe,\n computed,\n dispose\n}\n","import { data } from './data'\n\n// The disposed flag which is used to remove a computed function reference pointer\nexport function dispose(computedFunction) {\n data.computedDependenciesTracker.delete(computedFunction)\n return computedFunction.__disposed = true\n}\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\nimport {Part} from './part.js';\n\nconst directives = new WeakMap<object, true>();\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type DirectiveFactory = (...args: any[]) => object;\n\nexport type DirectiveFn = (part: Part) => void;\n\n/**\n * Brands a function as a directive factory function so that lit-html will call\n * the function during template rendering, rather than passing as a value.\n *\n * A _directive_ is a function that takes a Part as an argument. It has the\n * signature: `(part: Part) => void`.\n *\n * A directive _factory_ is a function that takes arguments for data and\n * configuration and returns a directive. Users of directive usually refer to\n * the directive factory as the directive. For example, \"The repeat directive\".\n *\n * Usually a template author will invoke a directive factory in their template\n * with relevant arguments, which will then return a directive function.\n *\n * Here's an example of using the `repeat()` directive factory that takes an\n * array and a function to render an item:\n *\n * ```js\n * html`<ul><${repeat(items, (item) => html`<li>${item}</li>`)}</ul>`\n * ```\n *\n * When `repeat` is invoked, it returns a directive function that closes over\n * `items` and the template function. When the outer template is rendered, the\n * return directive function is called with the Part for the expression.\n * `repeat` then performs it's custom logic to render multiple items.\n *\n * @param f The directive factory function. Must be a function that returns a\n * function of the signature `(part: Part) => void`. The returned function will\n * be called with the part object.\n *\n * @example\n *\n * import {directive, html} from 'lit-html';\n *\n * const immutable = directive((v) => (part) => {\n * if (part.value !== v) {\n * part.setValue(v)\n * }\n * });\n */\nexport const directive = <F extends DirectiveFactory>(f: F): F =>\n ((...args: unknown[]) => {\n const d = f(...args);\n directives.set(d, true);\n return d;\n }) as F;\n\nexport const isDirective = (o: unknown): o is DirectiveFn => {\n return typeof o === 'function' && directives.has(o);\n};\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\ninterface MaybePolyfilledCe extends CustomElementRegistry {\n readonly polyfillWrapFlushCallback?: object;\n}\n\n/**\n * True if the custom elements polyfill is in use.\n */\nexport const isCEPolyfill = typeof window !== 'undefined' &&\n window.customElements != null &&\n (window.customElements as MaybePolyfilledCe).polyfillWrapFlushCallback !==\n undefined;\n\n/**\n * Reparents nodes, starting from `start` (inclusive) to `end` (exclusive),\n * into another container (could be the same container), before `before`. If\n * `before` is null, it appends the nodes to the container.\n */\nexport const reparentNodes =\n (container: Node,\n start: Node|null,\n end: Node|null = null,\n before: Node|null = null): void => {\n while (start !== end) {\n const n = start!.nextSibling;\n container.insertBefore(start!, before);\n start = n;\n }\n };\n\n/**\n * Removes nodes, starting from `start` (inclusive) to `end` (exclusive), from\n * `container`.\n */\nexport const removeNodes =\n (container: Node, start: Node|null, end: Node|null = null): void => {\n while (start !== end) {\n const n = start!.nextSibling;\n container.removeChild(start!);\n start = n;\n }\n };\n","/**\n * @license\n * Copyright (c) 2018 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\n/**\n * The Part interface represents a dynamic part of a template instance rendered\n * by lit-html.\n */\nexport interface Part {\n readonly value: unknown;\n\n /**\n * Sets the current part value, but does not write it to the DOM.\n * @param value The value that will be committed.\n */\n setValue(value: unknown): void;\n\n /**\n * Commits the current part value, causing it to actually be written to the\n * DOM.\n *\n * Directives are run at the start of `commit`, so that if they call\n * `part.setValue(...)` synchronously that value will be used in the current\n * commit, and there's no need to call `part.commit()` within the directive.\n * If directives set a part value asynchronously, then they must call\n * `part.commit()` manually.\n */\n commit(): void;\n}\n\n/**\n * A sentinel value that signals that a value was handled by a directive and\n * should not be written to the DOM.\n */\nexport const noChange = {};\n\n/**\n * A sentinel value that signals a NodePart to fully clear its content.\n */\nexport const nothing = {};\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\nimport {TemplateResult} from './template-result.js';\n\n/**\n * An expression marker with embedded unique key to avoid collision with\n * possible text in templates.\n */\nexport const marker = `{{lit-${String(Math.random()).slice(2)}}}`;\n\n/**\n * An expression marker used text-positions, multi-binding attributes, and\n * attributes with markup-like text values.\n */\nexport const nodeMarker = `<!--${marker}-->`;\n\nexport const markerRegex = new RegExp(`${marker}|${nodeMarker}`);\n\n/**\n * Suffix appended to all bound attribute names.\n */\nexport const boundAttributeSuffix = '$lit$';\n\n/**\n * An updatable Template that tracks the location of dynamic parts.\n */\nexport class Template {\n readonly parts: TemplatePart[] = [];\n readonly element: HTMLTemplateElement;\n\n constructor(result: TemplateResult, element: HTMLTemplateElement) {\n this.element = element;\n\n const nodesToRemove: Node[] = [];\n const stack: Node[] = [];\n // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null\n const walker = document.createTreeWalker(\n element.content,\n 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */,\n null,\n false);\n // Keeps track of the last index associated with a part. We try to delete\n // unnecessary nodes, but we never want to associate two different parts\n // to the same index. They must have a constant node between.\n let lastPartIndex = 0;\n let index = -1;\n let partIndex = 0;\n const {strings, values: {length}} = result;\n while (partIndex < length) {\n const node = walker.nextNode() as Element | Comment | Text | null;\n if (node === null) {\n // We've exhausted the content inside a nested template element.\n // Because we still have parts (the outer for-loop), we know:\n // - There is a template in the stack\n // - The walker will find a nextNode outside the template\n walker.currentNode = stack.pop()!;\n continue;\n }\n index++;\n\n if (node.nodeType === 1 /* Node.ELEMENT_NODE */) {\n if ((node as Element).hasAttributes()) {\n const attributes = (node as Element).attributes;\n const {length} = attributes;\n // Per\n // https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap,\n // attributes are not guaranteed to be returned in document order.\n // In particular, Edge/IE can return them out of order, so we cannot\n // assume a correspondence between part index and attribute index.\n let count = 0;\n for (let i = 0; i < length; i++) {\n if (endsWith(attributes[i].name, boundAttributeSuffix)) {\n count++;\n }\n }\n while (count-- > 0) {\n // Get the template literal section leading up to the first\n // expression in this attribute\n const stringForPart = strings[partIndex];\n // Find the attribute name\n const name = lastAttributeNameRegex.exec(stringForPart)![2];\n // Find the corresponding attribute\n // All bound attributes have had a suffix added in\n // TemplateResult#getHTML to opt out of special attribute\n // handling. To look up the attribute value we also need to add\n // the suffix.\n const attributeLookupName =\n name.toLowerCase() + boundAttributeSuffix;\n const attributeValue =\n (node as Element).getAttribute(attributeLookupName)!;\n (node as Element).removeAttribute(attributeLookupName);\n const statics = attributeValue.split(markerRegex);\n this.parts.push({type: 'attribute', index, name, strings: statics});\n partIndex += statics.length - 1;\n }\n }\n if ((node as Element).tagName === 'TEMPLATE') {\n stack.push(node);\n walker.currentNode = (node as HTMLTemplateElement).content;\n }\n } else if (node.nodeType === 3 /* Node.TEXT_NODE */) {\n const data = (node as Text).data;\n if (data.indexOf(marker) >= 0) {\n const parent = node.parentNode!;\n const strings = data.split(markerRegex);\n const lastIndex = strings.length - 1;\n // Generate a new text node for each literal section\n // These nodes are also used as the markers for node parts\n for (let i = 0; i < lastIndex; i++) {\n let insert: Node;\n let s = strings[i];\n if (s === '') {\n insert = createMarker();\n } else {\n const match = lastAttributeNameRegex.exec(s);\n if (match !== null && endsWith(match[2], boundAttributeSuffix)) {\n s = s.slice(0, match.index) + match[1] +\n match[2].slice(0, -boundAttributeSuffix.length) + match[3];\n }\n insert = document.createTextNode(s);\n }\n parent.insertBefore(insert, node);\n this.parts.push({type: 'node', index: ++index});\n }\n // If there's no text, we must insert a comment to mark our place.\n // Else, we can trust it will stick around after cloning.\n if (strings[lastIndex] === '') {\n parent.insertBefore(createMarker(), node);\n nodesToRemove.push(node);\n } else {\n (node as Text).data = strings[lastIndex];\n }\n // We have a part for each match found\n partIndex += lastIndex;\n }\n } else if (node.nodeType === 8 /* Node.COMMENT_NODE */) {\n if ((node as Comment).data === marker) {\n const parent = node.parentNode!;\n // Add a new marker node to be the startNode of the Part if any of\n // the following are true:\n // * We don't have a previousSibling\n // * The previousSibling is already the start of a previous part\n if (node.previousSibling === null || index === lastPartIndex) {\n index++;\n parent.insertBefore(createMarker(), node);\n }\n lastPartIndex = index;\n this.parts.push({type: 'node', index});\n // If we don't have a nextSibling, keep this node so we have an end.\n // Else, we can remove it to save future costs.\n if (node.nextSibling === null) {\n (node as Comment).data = '';\n } else {\n nodesToRemove.push(node);\n index--;\n }\n partIndex++;\n } else {\n let i = -1;\n while ((i = (node as Comment).data.indexOf(marker, i + 1)) !== -1) {\n // Comment node has a binding marker inside, make an inactive part\n // The binding won't work, but subsequent bindings will\n // TODO (justinfagnani): consider whether it's even worth it to\n // make bindings in comments work\n this.parts.push({type: 'node', index: -1});\n partIndex++;\n }\n }\n }\n }\n\n // Remove text binding nodes after the walk to not disturb the TreeWalker\n for (const n of nodesToRemove) {\n n.parentNode!.removeChild(n);\n }\n }\n}\n\nconst endsWith = (str: string, suffix: string): boolean => {\n const index = str.length - suffix.length;\n return index >= 0 && str.slice(index) === suffix;\n};\n\n/**\n * A placeholder for a dynamic expression in an HTML template.\n *\n * There are two built-in part types: AttributePart and NodePart. NodeParts\n * always represent a single dynamic expression, while AttributeParts may\n * represent as many expressions are contained in the attribute.\n *\n * A Template's parts are mutable, so parts can be replaced or modified\n * (possibly to implement different template semantics). The contract is that\n * parts can only be replaced, not removed, added or reordered, and parts must\n * always consume the correct number of values in their `update()` method.\n *\n * TODO(justinfagnani): That requirement is a little fragile. A\n * TemplateInstance could instead be more careful about which values it gives\n * to Part.update().\n */\nexport type TemplatePart = {\n readonly type: 'node'; index: number;\n}|{\n readonly type: 'attribute';\n index: number;\n readonly name: string;\n readonly strings: ReadonlyArray<string>;\n};\n\nexport const isTemplatePartActive = (part: TemplatePart) => part.index !== -1;\n\n// Allows `document.createComment('')` to be renamed for a\n// small manual size-savings.\nexport const createMarker = () => document.createComment('');\n\n/**\n * This regex extracts the attribute name preceding an attribute-position\n * expression. It does this by matching the syntax allowed for attributes\n * against the string literal directly preceding the expression, assuming that\n * the expression is in an attribute-value position.\n *\n * See attributes in the HTML spec:\n * https://www.w3.org/TR/html5/syntax.html#elements-attributes\n *\n * \" \\x09\\x0a\\x0c\\x0d\" are HTML space characters:\n * https://www.w3.org/TR/html5/infrastructure.html#space-characters\n *\n * \"\\0-\\x1F\\x7F-\\x9F\" are Unicode control characters, which includes every\n * space character except \" \".\n *\n * So an attribute is:\n * * The name: any character except a control character, space character, ('),\n * (\"), \">\", \"=\", or \"/\"\n * * Followed by zero or more space characters\n * * Followed by \"=\"\n * * Followed by zero or more space characters\n * * Followed by:\n * * Any character except space, ('), (\"), \"<\", \">\", \"=\", (`), or\n * * (\") then any non-(\"), or\n * * (') then any non-(')\n */\nexport const lastAttributeNameRegex =\n // eslint-disable-next-line no-control-regex\n /([ \\x09\\x0a\\x0c\\x0d])([^\\0-\\x1F\\x7F-\\x9F \"'>=/]+)([ \\x09\\x0a\\x0c\\x0d]*=[ \\x09\\x0a\\x0c\\x0d]*(?:[^ \\x09\\x0a\\x0c\\x0d\"'`<>=]*|\"[^\"]*|'[^']*))$/;\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\nimport {isCEPolyfill} from './dom.js';\nimport {Part} from './part.js';\nimport {RenderOptions} from './render-options.js';\nimport {TemplateProcessor} from './template-processor.js';\nimport {isTemplatePartActive, Template, TemplatePart} from './template.js';\n\n/**\n * An instance of a `Template` that can be attached to the DOM and updated\n * with new values.\n */\nexport class TemplateInstance {\n private readonly __parts: Array<Part|undefined> = [];\n readonly processor: TemplateProcessor;\n readonly options: RenderOptions;\n readonly template: Template;\n\n constructor(\n template: Template, processor: TemplateProcessor,\n options: RenderOptions) {\n this.template = template;\n this.processor = processor;\n this.options = options;\n }\n\n update(values: readonly unknown[]) {\n let i = 0;\n for (const part of this.__parts) {\n if (part !== undefined) {\n part.setValue(values[i]);\n }\n i++;\n }\n for (const part of this.__parts) {\n if (part !== undefined) {\n part.commit();\n }\n }\n }\n\n _clone(): DocumentFragment {\n // There are a number of steps in the lifecycle of a template instance's\n // DOM fragment:\n // 1. Clone - create the instance fragment\n // 2. Adopt - adopt into the main document\n // 3. Process - find part markers and create parts\n // 4. Upgrade - upgrade custom elements\n // 5. Update - set node, attribute, property, etc., values\n // 6. Connect - connect to the document. Optional and outside of this\n // method.\n //\n // We have a few constraints on the ordering of these steps:\n // * We need to upgrade before updating, so that property values will pass\n // through any property setters.\n // * We would like to process before upgrading so that we're sure that the\n // cloned fragment is inert and not disturbed by self-modifying DOM.\n // * We want custom elements to upgrade even in disconnected fragments.\n //\n // Given these constraints, with full custom elements support we would\n // prefer the order: Clone, Process, Adopt, Upgrade, Update, Connect\n //\n // But Safari does not implement CustomElementRegistry#upgrade, so we\n // can not implement that order and still have upgrade-before-update and\n // upgrade disconnected fragments. So we instead sacrifice the\n // process-before-upgrade constraint, since in Custom Elements v1 elements\n // must not modify their light DOM in the constructor. We still have issues\n // when co-existing with CEv0 elements like Polymer 1, and with polyfills\n // that don't strictly adhere to the no-modification rule because shadow\n // DOM, which may be created in the constructor, is emulated by being placed\n // in the light DOM.\n //\n // The resulting order is on native is: Clone, Adopt, Upgrade, Process,\n // Update, Connect. document.importNode() performs Clone, Adopt, and Upgrade\n // in one step.\n //\n // The Custom Elements v1 polyfill supports upgrade(), so the order when\n // polyfilled is the more ideal: Clone, Process, Adopt, Upgrade, Update,\n // Connect.\n\n const fragment = isCEPolyfill ?\n this.template.element.content.cloneNode(true) as DocumentFragment :\n document.importNode(this.template.element.content, true);\n\n const stack: Node[] = [];\n const parts = this.template.parts;\n // Edge needs all 4 parameters present; IE11 needs 3rd parameter to be null\n const walker = document.createTreeWalker(\n fragment,\n 133 /* NodeFilter.SHOW_{ELEMENT|COMMENT|TEXT} */,\n null,\n false);\n let partIndex = 0;\n let nodeIndex = 0;\n let part: TemplatePart;\n let node = walker.nextNode();\n // Loop through all the nodes and parts of a template\n while (partIndex < parts.length) {\n part = parts[partIndex];\n if (!isTemplatePartActive(part)) {\n this.__parts.push(undefined);\n partIndex++;\n continue;\n }\n\n // Progress the tree walker until we find our next part's node.\n // Note that multiple parts may share the same node (attribute parts\n // on a single element), so this loop may not run at all.\n while (nodeIndex < part.index) {\n nodeIndex++;\n if (node!.nodeName === 'TEMPLATE') {\n stack.push(node!);\n walker.currentNode = (node as HTMLTemplateElement).content;\n }\n if ((node = walker.nextNode()) === null) {\n // We've exhausted the content inside a nested template element.\n // Because we still have parts (the outer for-loop), we know:\n // - There is a template in the stack\n // - The walker will find a nextNode outside the template\n walker.currentNode = stack.pop()!;\n node = walker.nextNode();\n }\n }\n\n // We've arrived at our part's node.\n if (part.type === 'node') {\n const part = this.processor.handleTextExpression(this.options);\n part.insertAfterNode(node!.previousSibling!);\n this.__parts.push(part);\n } else {\n this.__parts.push(...this.processor.handleAttributeExpressions(\n node as Element, part.name, part.strings, this.options));\n }\n partIndex++;\n }\n\n if (isCEPolyfill) {\n document.adoptNode(fragment);\n customElements.upgrade(fragment);\n }\n return fragment;\n }\n}\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\n/**\n * @module lit-html\n */\n\nimport {reparentNodes} from './dom.js';\nimport {TemplateProcessor} from './template-processor.js';\nimport {boundAttributeSuffix, lastAttributeNameRegex, marker, nodeMarker} from './template.js';\n\ndeclare const trustedTypes: typeof window.trustedTypes;\n/**\n * Our TrustedTypePolicy for HTML which is declared using the html template\n * tag function.\n *\n * That HTML is a developer-authored constant, and is parsed with innerHTML\n * before any untrusted expressions have been mixed in. Therefor it is\n * considered safe by construction.\n */\nconst policy = window.trustedTypes &&\n trustedTypes!.createPolicy('lit-html', {createHTML: (s) => s});\n\nconst commentMarker = ` ${marker} `;\n\n/**\n * The return type of `html`, which holds a Template and the values from\n * interpolated expressions.\n */\nexport class TemplateResult {\n readonly strings: TemplateStringsArray;\n readonly values: readonly unknown[];\n readonly type: string;\n readonly processor: TemplateProcessor;\n\n constructor(\n strings: TemplateStringsArray, values: readonly unknown[], type: string,\n processor: TemplateProcessor) {\n this.strings = strings;\n this.values = values;\n this.type = type;\n this.processor = processor;\n }\n\n /**\n * Returns a string of HTML used to create a `<template>` element.\n */\n getHTML(): string {\n const l = this.strings.length - 1;\n let html = '';\n let isCommentBinding = false;\n\n for (let i = 0; i < l; i++) {\n const s = this.strings[i];\n // For each binding we want to determine the kind of marker to insert\n // into the template source before it's parsed by the browser's HTML\n // parser. The marker type is based on whether the expression is in an\n // attribute, text, or comment position.\n // * For node-position bindings we insert a comment with the marker\n // sentinel as its text content, like <!--{{lit-guid}}-->.\n // * For attribute bindings we insert just the marker sentinel for the\n // first binding, so that we support unquoted attribute bindings.\n // Subsequent bindings can use a comment marker because multi-binding\n // attributes must be quoted.\n // * For comment bindings we insert just the marker sentinel so we don't\n // close the comment.\n //\n // The following code scans the template source, but is *not* an HTML\n // parser. We don't need to track the tree structure of the HTML, only\n // whether a binding is inside a comment, and if not, if it appears to be\n // the first binding in an attribute.\n const commentOpen = s.lastIndexOf('<!--');\n // We're in comment position if we have a comment open with no following\n // comment close. Because <-- can appear in an attribute value there can\n // be false positives.\n isCommentBinding = (commentOpen > -1 || isCommentBinding) &&\n s.indexOf('-->', commentOpen + 1) === -1;\n // Check to see if we have an attribute-like sequence preceding the\n // expression. This can match \"name=value\" like structures in text,\n // comments, and attribute values, so there can be false-positives.\n const attributeMatch = lastAttributeNameRegex.exec(s);\n if (attributeMatch === null) {\n // We're only in this branch if we don't have a attribute-like\n // preceding sequence. For comments, this guards against unusual\n // attribute values like <div foo=\"<!--${'bar'}\">. Cases like\n // <!-- foo=${'bar'}--> are handled correctly in the attribute branch\n // below.\n html += s + (isCommentBinding ? commentMarker : nodeMarker);\n } else {\n // For attributes we use just a marker sentinel, and also append a\n // $lit$ suffix to the name to opt-out of attribute-specific parsing\n // that IE and Edge do for style and certain SVG attributes.\n html += s.substr(0, attributeMatch.index) + attributeMatch[1] +\n attributeMatch[2] + boundAttributeSuffix + attributeMatch[3] +\n marker;\n }\n }\n html += this.strings[l];\n return html;\n }\n\n getTemplateElement(): HTMLTemplateElement {\n const template = document.createElement('template');\n let value = this.getHTML();\n if (policy !== undefined) {\n // this is secure because `this.strings` is a TemplateStringsArray.\n // TODO: validate this when\n // https://github.com/tc39/proposal-array-is-template-object is\n // implemented.\n value = policy.createHTML(value) as unknown as string;\n }\n template.innerHTML = value;\n return template;\n }\n}\n\n/**\n * A TemplateResult for SVG fragments.\n *\n * This class wraps HTML in an `<svg>` tag in order to parse its contents in the\n * SVG namespace, then modifies the template to remove the `<svg>` tag so that\n * clones only container the original fragment.\n */\nexport class SVGTemplateResult extends TemplateResult {\n getHTML(): string {\n return `<svg>${super.getHTML()}</svg>`;\n }\n\n getTemplateElement(): HTMLTemplateElement {\n const template = super.getTemplateElement();\n const content = template.content;\n const svgElement = content.firstChild!;\n content.removeChild(svgElement);\n reparentNodes(content, svgElement.firstChild);\n return template;\n }\n}\n","/**\n * @license\n * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at\n * http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at\n * http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at\n * http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at\n * http://polymer.github.io/PATENTS.txt\n */\n\nimport {isDirective} from './directive.js';\nimport {removeNodes} from './dom.js';\nimport {noChange, nothing, Part} from './part.js';\nimport {RenderOptions} from './render-options.js';\nimport {TemplateInstance} from './template-instance.js';\nimport {TemplateResult} from './template-result.js';\nimport {createMarker} from './template.js';\n\n// https://tc39.github.io/ecma262/#sec-typeof-operator\nexport type Primitive = null|undefined|boolean|number|string|symbol|bigint;\nexport const isPrimitive = (value: unknown): value is Primitive => {\n return (\n value === null ||\n !(typeof value === 'object' || typeof value === 'function'));\n};\nexport const isIterable = (value: unknown): value is Iterable<unknown> => {\n return Array.isArray(value) ||\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n !!(value && (value as any)[Symbol.iterator]);\n};\n\n/**\n * Writes attribute values to the DOM for a group of AttributeParts bound to a\n * single attribute. The value is only set once even if there are multiple parts\n * for an attribute.\n */\nexport class AttributeCommitter {\n readonly element: Element;\n readonly name: string;\n readonly strings: ReadonlyArray<string>;\n readonly parts: ReadonlyArray<AttributePart>;\n dirty = true;\n\n constructor(element: Element, name: string, strings: ReadonlyArray<string>) {\n this.element = element;\n this.name = name;\n this.strings = strings;\n this.parts = [];\n for (let i = 0; i < strings.length - 1; i++) {\n (this.parts as AttributePart[])[i] = this._createPart();\n }\n }\n\n /**\n * Creates a single part. Override this to create a differnt type of part.\n */\n protected _createPart(): AttributePart {\n return new AttributePart(this);\n }\n\n protected _getValue(): unknown {\n const strings = this.strings;\n const l = strings.length - 1;\n const parts = this.parts;\n\n // If we're assigning an attribute via syntax like:\n // attr=\"${foo}\" or attr=${foo}\n // but not\n // attr=\"${foo} ${bar}\" or attr=\"${foo} baz\"\n // then we don't want to coerce the attribute value into one long\n // string. Instead we want to just return the value itself directly,\n // so that sanitizeDOMValue can get the actual value rather than\n // String(value)\n // The exception is if v is an array, in which case we do want to smash\n // it together into a string without calling String() on the array.\n //\n // This also allows trusted values (when using TrustedTypes) being\n // assigned to DOM sinks without being stringified in the process.\n if (l === 1 && strings[0] === '' && strings[1] === '') {\n const v = parts[0].value;\n if (typeof v === 'symbol') {\n return String(v);\n }\n if (typeof v === 'string' || !isIterable(v)) {\n return v;\n }\n }\n let text = '';\n\n for (let i = 0; i < l; i++) {\n text += strings[i];\n const part = parts[i];\n if (part !== undefined) {\n const v = part.value;\n if (isPrimitive(v) || !isIterable(v)) {\n text += typeof v === 'string' ? v : String(v);\n } else {\n for (const t of v) {\n text += typeof t === 'string' ? t : String(t);\n }\n }\n }\n }\n\n text += strings[l];\n return text;\n }\n\n commit(): void {\n if (this.dirty) {\n this.dirty = false;\n this.element.setAttribute(this.name, this._getValue() as string);\n }\n }\n}\n\n/**\n * A Part that controls all or part of an attribute value.\n */\nexport class AttributePart implements Part {\n readonly committer: AttributeCommitter;\n value: unknown = undefined;\n\n constructor(committer: AttributeCommitter) {\n this.committer = committer;\n }\n\n setValue(value: unknown): void {\n if (value !== noChange && (!isPrimitive(value) || value !== this.value)) {\n this.value = value;\n // If the value is a not a directive, dirty the committer so that it'll\n // call setAttribute. If the value is a directive, it'll dirty the\n // committer if it calls setValue().\n if (!isDirective(value)) {\n this.committer.dirty = true;\n }\n }\n }\n\n commit() {\n while (isDirective(this.value)) {\n const directive = this.value;\n this.value = noChange;\n directive(this);\n }\n if (this.value === noChange) {\n return;\n }\n this.committer.commit();\n }\n}\n\n/**\n * A Part that controls a location within a Node tree. Like a Range, NodePart\n * has start and end locations and can set and update the Nodes between those\n * locations.\n *\n * NodeParts support several value types: primitives, Nodes, TemplateResults,\n * as well as arrays and iterables of those types.\n */\nexport class NodePart implements Part {\n readonly options: RenderOptions;\n startNode!: Node;\n endNode!: Node;\n value: unknown = undefined;\n private __pendingValue: unknown = undefined;\n\n constructor(options: RenderOptions) {\n this.options = options;\n }\n\n /**\n * Appends this part into a container.\n *\n * This part must be empty, as its contents are not automatically moved.\n */\n appendInto(container: Node) {\n this.startNode = container.appendChild(createMarker());\n this.endNode = container.appendChild(createMarker());\n }\n\n /**\n * Inserts this part after the `ref` node (between `ref` and `ref`'s next\n * sibling). Both `ref` and its next sibling must be static, unchanging nodes\n * such as those that appear in a literal section of a template.\n *\n * This part must be empty, as its contents are not automatically moved.\n */\n insertAfterNode(ref: Node) {\n this.startNode = ref;\n this.endNode = ref.nextSibling!;\n }\n\n /**\n * Appends this part into a parent part.\n *\n * This part must be empty, as its contents are not automatically moved.\n */\n appendIntoPart(part: NodePart) {\n part.__insert(this.startNode = createMarker());\n part.__insert(this.endNode = createMarker());\n }\n\n /**\n * Inserts this part after the `ref` part.\n *\n * This part must be empty, as its contents are not automatically moved.\n */\n insertAfterPart(ref: NodePart) {\n ref.__insert(this.startNode = createMarker());\n this.endNode = ref.endNode;\n ref.endNode = this.startNode;\n }\n\n setValue(value: unknown): void {\n this.__pendingValue = value;\n }\n\n commit() {\n if (this.startNode.parentNode === null) {\n return;\n }\n while (isDirective(this.__pendingValue)) {\n const directive = this.__pendingValue;\n this.__pendingValue = noChange;\n directive(this);\n }\n const value = this.__pendingValue;\n if (value === noChange) {\n return;\n }\n if (isPrimitive(value)) {\n if (value !== this.value) {\n this.__commitText(value);\n }\n } else if (value instanceof TemplateResult) {\n this.__commitTemplateResult(value);\n } else if (value instanceof Node) {\n this.__commitNode(value);\n } else if (isIterable(value)) {\n this.__commitIterable(value);\n } else if (value === nothing) {\n this.value = nothing;\n this.clear();\n } else {\n // Fallback, will render the string representation\n this.__commitText(value);\n }\n }\n\n private __insert(node: Node) {\n this.endNode.parentNode!.insertBefore(node, this.endNode);\n }\n\n private __commitNode(value: Node): void {\n if (this.value === value) {\n return;\n }\n this.clear();\n this.__insert(value);\n this.value = value;\n }\n\n private __commitText(value: unknown): void {\n const node = this.startNode.nextSibling!;\n value = value == null ? '' : value;\n // If `value` isn't already a string, we explicitly convert it here in case\n // it can't be implicitly converted - i.e. it's a symbol.\n const valueAsString: string =\n typeof value === 'string' ? value : String(value);\n if (node === this.endNode.previousSibling &&\n node.nodeType === 3 /* Node.TEXT_NODE */) {\n // If we only have a single text node between the markers, we can just\n // set its value, rather than replacing it.\n // TODO(justinfagnani): Can we just check if this.value is primitive?\n (node as Text).data = valueAsString;\n } else {\n this.__commitNode(document.createTextNode(valueAsString));\n }\n this.value = value;\n }\n\n private __commitTemplateResult(value: TemplateResult): void {\n const template = this.options.templateFactory(value);\n if (this.value instanceof TemplateInstance &&\n this.value.template === template) {\n this.value.update(value.values);\n } else {\n // Make sure we propagate the template processor from the TemplateResult\n // so that we use its syntax ext