UNPKG

chrome-devtools-frontend

Version:
133 lines (122 loc) 4.09 kB
/** * @license * Copyright 2020 Google LLC * SPDX-License-Identifier: BSD-3-Clause */ import {html as coreHtml, svg as coreSvg, TemplateResult} from './lit-html.js'; /** * Wraps a string so that it behaves like part of the static template * strings instead of a dynamic value. * * Users must take care to ensure that adding the static string to the template * results in well-formed HTML, or else templates may break unexpectedly. * * Note that this function is unsafe to use on untrusted content, as it will be * directly parsed into HTML. Do not pass user input to this function * without sanitizing it. * * Static values can be changed, but they will cause a complete re-render * since they effectively create a new template. */ export const unsafeStatic = (value: string) => ({ _$litStatic$: value, }); const textFromStatic = (value: StaticValue) => { if (value._$litStatic$ !== undefined) { return value._$litStatic$; } else { throw new Error( `Value passed to 'literal' function must be a 'literal' result: ${value}. Use 'unsafeStatic' to pass non-literal values, but take care to ensure page security.` ); } }; /** * Tags a string literal so that it behaves like part of the static template * strings instead of a dynamic value. * * The only values that may be used in template expressions are other tagged * `literal` results or `unsafeStatic` values (note that untrusted content * should never be passed to `unsafeStatic`). * * Users must take care to ensure that adding the static string to the template * results in well-formed HTML, or else templates may break unexpectedly. * * Static values can be changed, but they will cause a complete re-render since * they effectively create a new template. */ export const literal = ( strings: TemplateStringsArray, ...values: unknown[] ) => ({ _$litStatic$: values.reduce( (acc, v, idx) => acc + textFromStatic(v as StaticValue) + strings[idx + 1], strings[0] ), }); type StaticValue = ReturnType<typeof unsafeStatic>; const stringsCache = new Map<string, TemplateStringsArray>(); /** * Wraps a lit-html template tag (`html` or `svg`) to add static value support. */ export const withStatic = (coreTag: typeof coreHtml | typeof coreSvg) => ( strings: TemplateStringsArray, ...values: unknown[] ): TemplateResult => { const l = values.length; let staticValue: string | undefined; let dynamicValue: unknown; const staticStrings: Array<string> = []; const dynamicValues: Array<unknown> = []; let i = 0; let hasStatics = false; let s: string; while (i < l) { s = strings[i]; // Collect any unsafeStatic values, and their following template strings // so that we treat a run of template strings and unsafe static values as // a single template string. while ( i < l && ((dynamicValue = values[i]), (staticValue = (dynamicValue as StaticValue)?._$litStatic$)) !== undefined ) { s += staticValue + strings[++i]; hasStatics = true; } dynamicValues.push(dynamicValue); staticStrings.push(s); i++; } // If the last value isn't static (which would have consumed the last // string), then we need to add the last string. if (i === l) { staticStrings.push(strings[l]); } if (hasStatics) { const key = staticStrings.join('$$lit$$'); strings = stringsCache.get(key)!; if (strings === undefined) { stringsCache.set( key, (strings = (staticStrings as unknown) as TemplateStringsArray) ); } values = dynamicValues; } return coreTag(strings, ...values); }; /** * Interprets a template literal as an HTML template that can efficiently * render to and update a container. * * Includes static value support from `lit-html/static.js`. */ export const html = withStatic(coreHtml); /** * Interprets a template literal as an SVG template that can efficiently * render to and update a container. * * Includes static value support from `lit-html/static.js`. */ export const svg = withStatic(coreSvg);