timepiece/node_modules/lit-html/development/static.js

142 lines
5.1 KiB
JavaScript

/**
* @license
* Copyright 2020 Google LLC
* SPDX-License-Identifier: BSD-3-Clause
*/
// Any new exports need to be added to the export statement in
// `packages/lit/src/index.all.ts`.
import { html as coreHtml, svg as coreSvg } from './lit-html.js';
/**
* Prevents JSON injection attacks.
*
* The goals of this brand:
* 1) fast to check
* 2) code is small on the wire
* 3) multiple versions of Lit in a single page will all produce mutually
* interoperable StaticValues
* 4) normal JSON.parse (without an unusual reviver) can not produce a
* StaticValue
*
* Symbols satisfy (1), (2), and (4). We use Symbol.for to satisfy (3), but
* we don't care about the key, so we break ties via (2) and use the empty
* string.
*/
const brand = Symbol.for('');
/** Safely extracts the string part of a StaticValue. */
const unwrapStaticValue = (value) => {
if ((value === null || value === void 0 ? void 0 : value.r) !== brand) {
return undefined;
}
return value === null || value === void 0 ? void 0 : value['_$litStatic$'];
};
/**
* 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) => ({
['_$litStatic$']: value,
r: brand,
});
const textFromStatic = (value) => {
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, ...values) => ({
['_$litStatic$']: values.reduce((acc, v, idx) => acc + textFromStatic(v) + strings[idx + 1], strings[0]),
r: brand,
});
const stringsCache = new Map();
/**
* Wraps a lit-html template tag (`html` or `svg`) to add static value support.
*/
export const withStatic = (coreTag) => (strings, ...values) => {
const l = values.length;
let staticValue;
let dynamicValue;
const staticStrings = [];
const dynamicValues = [];
let i = 0;
let hasStatics = false;
let s;
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 = unwrapStaticValue(dynamicValue))) !== undefined) {
s += staticValue + strings[++i];
hasStatics = true;
}
// If the last value is static, we don't need to push it.
if (i !== l) {
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) {
// Beware: in general this pattern is unsafe, and doing so may bypass
// lit's security checks and allow an attacker to execute arbitrary
// code and inject arbitrary content.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
staticStrings.raw = staticStrings;
stringsCache.set(key, (strings = staticStrings));
}
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);
//# sourceMappingURL=static.js.map