UNPKG

5.13 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright 2020 Google LLC
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6// Any new exports need to be added to the export statement in
7// `packages/lit/src/index.all.ts`.
8import { html as coreHtml, svg as coreSvg } from './lit-html.js';
9/**
10 * Prevents JSON injection attacks.
11 *
12 * The goals of this brand:
13 * 1) fast to check
14 * 2) code is small on the wire
15 * 3) multiple versions of Lit in a single page will all produce mutually
16 * interoperable StaticValues
17 * 4) normal JSON.parse (without an unusual reviver) can not produce a
18 * StaticValue
19 *
20 * Symbols satisfy (1), (2), and (4). We use Symbol.for to satisfy (3), but
21 * we don't care about the key, so we break ties via (2) and use the empty
22 * string.
23 */
24const brand = Symbol.for('');
25/** Safely extracts the string part of a StaticValue. */
26const unwrapStaticValue = (value) => {
27 if (value?.r !== brand) {
28 return undefined;
29 }
30 return value?.['_$litStatic$'];
31};
32/**
33 * Wraps a string so that it behaves like part of the static template
34 * strings instead of a dynamic value.
35 *
36 * Users must take care to ensure that adding the static string to the template
37 * results in well-formed HTML, or else templates may break unexpectedly.
38 *
39 * Note that this function is unsafe to use on untrusted content, as it will be
40 * directly parsed into HTML. Do not pass user input to this function
41 * without sanitizing it.
42 *
43 * Static values can be changed, but they will cause a complete re-render
44 * since they effectively create a new template.
45 */
46export const unsafeStatic = (value) => ({
47 ['_$litStatic$']: value,
48 r: brand,
49});
50const textFromStatic = (value) => {
51 if (value['_$litStatic$'] !== undefined) {
52 return value['_$litStatic$'];
53 }
54 else {
55 throw new Error(`Value passed to 'literal' function must be a 'literal' result: ${value}. Use 'unsafeStatic' to pass non-literal values, but
56 take care to ensure page security.`);
57 }
58};
59/**
60 * Tags a string literal so that it behaves like part of the static template
61 * strings instead of a dynamic value.
62 *
63 * The only values that may be used in template expressions are other tagged
64 * `literal` results or `unsafeStatic` values (note that untrusted content
65 * should never be passed to `unsafeStatic`).
66 *
67 * Users must take care to ensure that adding the static string to the template
68 * results in well-formed HTML, or else templates may break unexpectedly.
69 *
70 * Static values can be changed, but they will cause a complete re-render since
71 * they effectively create a new template.
72 */
73export const literal = (strings, ...values) => ({
74 ['_$litStatic$']: values.reduce((acc, v, idx) => acc + textFromStatic(v) + strings[idx + 1], strings[0]),
75 r: brand,
76});
77const stringsCache = new Map();
78/**
79 * Wraps a lit-html template tag (`html` or `svg`) to add static value support.
80 */
81export const withStatic = (coreTag) => (strings, ...values) => {
82 const l = values.length;
83 let staticValue;
84 let dynamicValue;
85 const staticStrings = [];
86 const dynamicValues = [];
87 let i = 0;
88 let hasStatics = false;
89 let s;
90 while (i < l) {
91 s = strings[i];
92 // Collect any unsafeStatic values, and their following template strings
93 // so that we treat a run of template strings and unsafe static values as
94 // a single template string.
95 while (i < l &&
96 ((dynamicValue = values[i]),
97 (staticValue = unwrapStaticValue(dynamicValue))) !== undefined) {
98 s += staticValue + strings[++i];
99 hasStatics = true;
100 }
101 // If the last value is static, we don't need to push it.
102 if (i !== l) {
103 dynamicValues.push(dynamicValue);
104 }
105 staticStrings.push(s);
106 i++;
107 }
108 // If the last value isn't static (which would have consumed the last
109 // string), then we need to add the last string.
110 if (i === l) {
111 staticStrings.push(strings[l]);
112 }
113 if (hasStatics) {
114 const key = staticStrings.join('$$lit$$');
115 strings = stringsCache.get(key);
116 if (strings === undefined) {
117 // Beware: in general this pattern is unsafe, and doing so may bypass
118 // lit's security checks and allow an attacker to execute arbitrary
119 // code and inject arbitrary content.
120 // eslint-disable-next-line @typescript-eslint/no-explicit-any
121 staticStrings.raw = staticStrings;
122 stringsCache.set(key, (strings = staticStrings));
123 }
124 values = dynamicValues;
125 }
126 return coreTag(strings, ...values);
127};
128/**
129 * Interprets a template literal as an HTML template that can efficiently
130 * render to and update a container.
131 *
132 * Includes static value support from `lit-html/static.js`.
133 */
134export const html = withStatic(coreHtml);
135/**
136 * Interprets a template literal as an SVG template that can efficiently
137 * render to and update a container.
138 *
139 * Includes static value support from `lit-html/static.js`.
140 */
141export const svg = withStatic(coreSvg);
142//# sourceMappingURL=static.js.map
\No newline at end of file