@localnerve/web-component-build 3.3.0 → 3.4.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +2 -1
- package/lib/browser/index.js +9 -0
- package/lib/browser/trusted-types.js +75 -0
- package/lib/build.js +2 -2
- package/lib/index.js +1 -1
- package/package.json +13 -10
package/index.js
CHANGED
|
@@ -6,4 +6,5 @@
|
|
|
6
6
|
* Copyright (c) 2023 - 2025 Alex Grant (@localnerve), LocalNerve LLC
|
|
7
7
|
* Copyrights licensed under the BSD License. See the accompanying LICENSE file for terms.
|
|
8
8
|
*/
|
|
9
|
-
export {build, build as default} from './lib/index.js';
|
|
9
|
+
export { build, build as default } from './lib/index.js';
|
|
10
|
+
export * as browser from './lib/browser/index.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser api helper exports
|
|
3
|
+
* Exports code that would be duplicated across web components interfacing with browser apis.
|
|
4
|
+
*
|
|
5
|
+
* Copyright (c) 2023 - 2026 Alex Grant (@localnerve), LocalNerve LLC
|
|
6
|
+
* Copyrights licensed under the BSD License. See the accompanying LICENSE file for terms.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export { escapeHtml, getTrustedPolicy, trustedHtml } from './trusted-types.js';
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trusted Types runtime helpers for web components.
|
|
3
|
+
*
|
|
4
|
+
* Lets a component be authored so it works both with and without Trusted
|
|
5
|
+
* Types enforcement (CSP `require-trusted-types-for 'script'`):
|
|
6
|
+
*
|
|
7
|
+
* - static, author-controlled markup (shadow DOM templates, static snippets)
|
|
8
|
+
* is registered once through the component's own named policy and handed
|
|
9
|
+
* to sinks as a trusted value;
|
|
10
|
+
* - dynamic, user-influenced values are escaped with escapeHtml() before
|
|
11
|
+
* being composed into markup;
|
|
12
|
+
* - in browsers without Trusted Types (or when CSP is not enforced) every
|
|
13
|
+
* helper degrades to a plain-string passthrough, so components keep
|
|
14
|
+
* working unchanged.
|
|
15
|
+
*
|
|
16
|
+
* The component MUST list its policy name in the site's CSP `trusted-types`
|
|
17
|
+
* directive, e.g. `trusted-types default my-component;`. A build step can
|
|
18
|
+
* compute that allowlist from the sources (see @localnerve/trusted-types-rules).
|
|
19
|
+
*
|
|
20
|
+
* Copyright (c) 2023 - 2026 Alex Grant (@localnerve), LocalNerve LLC
|
|
21
|
+
* Copyrights licensed under the BSD License. See the accompanying LICENSE file for terms.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// per-module policy cache: a name may only be created once without the CSP
|
|
25
|
+
// 'allow-duplicates' keyword, so repeated calls must reuse the instance
|
|
26
|
+
const policies = new Map();
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Escape a value for safe interpolation into HTML markup (text or attribute).
|
|
30
|
+
*
|
|
31
|
+
* @param {Any} input - The value to escape
|
|
32
|
+
* @returns {String} The escaped string. null/undefined yield ''.
|
|
33
|
+
*/
|
|
34
|
+
export function escapeHtml (input) {
|
|
35
|
+
if (input === null || typeof input === 'undefined') return '';
|
|
36
|
+
return String(input)
|
|
37
|
+
.replace(/&/g, '&')
|
|
38
|
+
.replace(/</g, '<')
|
|
39
|
+
.replace(/>/g, '>')
|
|
40
|
+
.replace(/"/g, '"')
|
|
41
|
+
.replace(/'/g, ''');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Get (creating once) a named Trusted Type policy.
|
|
46
|
+
*
|
|
47
|
+
* @param {String} name - The policy name. Must be allowlisted in the CSP trusted-types directive when enforcement is active.
|
|
48
|
+
* @param {Object} [hooks] - Policy hooks. Defaults to pass-through createHTML/createScriptURL, appropriate for author-controlled content that has already been escaped where needed.
|
|
49
|
+
* @returns {TrustedTypePolicy|null} The policy, or null when Trusted Types is unavailable (passthrough mode).
|
|
50
|
+
*/
|
|
51
|
+
export function getTrustedPolicy (name, hooks = {
|
|
52
|
+
createHTML: input => String(input),
|
|
53
|
+
createScriptURL: input => String(input)
|
|
54
|
+
}) {
|
|
55
|
+
if (!(typeof window !== 'undefined' && 'trustedTypes' in window)) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (!policies.has(name)) {
|
|
59
|
+
policies.set(name, trustedTypes.createPolicy(name, hooks));
|
|
60
|
+
}
|
|
61
|
+
return policies.get(name);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Convert author-controlled (or pre-escaped) markup into a value that is safe
|
|
66
|
+
* to pass to an HTML injection sink under Trusted Types enforcement.
|
|
67
|
+
*
|
|
68
|
+
* @param {String} policyName - The named policy to use (must be CSP allowlisted).
|
|
69
|
+
* @param {String} html - Author-controlled or already-escaped markup.
|
|
70
|
+
* @returns {TrustedHTML|String} A trusted value when enforced, otherwise the input string unchanged (passthrough for dev builds / browsers without Trusted Types).
|
|
71
|
+
*/
|
|
72
|
+
export function trustedHtml (policyName, html) {
|
|
73
|
+
const policy = getTrustedPolicy(policyName);
|
|
74
|
+
return policy ? policy.createHTML(html) : html;
|
|
75
|
+
}
|
package/lib/build.js
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
import * as path from 'node:path';
|
|
9
9
|
import * as fs from 'node:fs/promises';
|
|
10
10
|
import CleanCss from 'clean-css';
|
|
11
|
-
import {minify as _minifyHtml} from 'html-minifier-terser';
|
|
12
|
-
import {minify as _minifyJs} from 'terser';
|
|
11
|
+
import { minify as _minifyHtml } from 'html-minifier-terser';
|
|
12
|
+
import { minify as _minifyJs } from 'terser';
|
|
13
13
|
|
|
14
14
|
export const defaultHtmlMinifyOptions = {
|
|
15
15
|
minifyJS: true,
|
package/lib/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@localnerve/web-component-build",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0-rc.2",
|
|
4
4
|
"description": "A library to help build web components",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"scripts": {
|
|
12
12
|
"lint": "eslint .",
|
|
13
13
|
"pretest": "node -e \"const fs=require('fs');fs.rmSync('./coverage',{recursive:true,force:true});fs.mkdirSync('./coverage',{recursive:true})\"",
|
|
14
|
-
"test": "node --test --experimental-test-coverage --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-coverage-exclude=\"__tests__/**\" ./__tests__/*.js"
|
|
14
|
+
"test": "node --test --experimental-test-coverage --test-reporter=spec --test-reporter-destination=stdout --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-coverage-exclude=\"__tests__/**\" ./__tests__/*.spec.js"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
17
|
"lib"
|
|
@@ -33,11 +33,13 @@
|
|
|
33
33
|
"email": "alex@localnerve.com",
|
|
34
34
|
"url": "https://www.localnerve.com"
|
|
35
35
|
},
|
|
36
|
-
"maintainers": [
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
"maintainers": [
|
|
37
|
+
{
|
|
38
|
+
"name": "Alex Grant",
|
|
39
|
+
"email": "alex@localnerve.com",
|
|
40
|
+
"url": "https://www.localnerve.com"
|
|
41
|
+
}
|
|
42
|
+
],
|
|
41
43
|
"license": "BSD-3-Clause",
|
|
42
44
|
"bugs": {
|
|
43
45
|
"url": "https://github.com/localnerve/web-component-build/issues"
|
|
@@ -47,13 +49,14 @@
|
|
|
47
49
|
"cheerio": "^1.2.0",
|
|
48
50
|
"clean-css": "^5.3.3",
|
|
49
51
|
"html-minifier-terser": "^7.2.0",
|
|
50
|
-
"terser": "^5.51.
|
|
52
|
+
"terser": "^5.51.2"
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|
|
53
|
-
"eslint": "^10.9.1",
|
|
54
55
|
"@eslint/js": "^10.0.1",
|
|
56
|
+
"eslint": "^10.9.1",
|
|
55
57
|
"eslint-plugin-n": "^18.3.0",
|
|
56
|
-
"globals": "^17.
|
|
58
|
+
"globals": "^17.12.0",
|
|
59
|
+
"jsdom": "^30.0.1",
|
|
57
60
|
"tempy": "^3.2.0"
|
|
58
61
|
},
|
|
59
62
|
"overrides": {
|