@prairielearn/html 3.1.6 → 4.0.0

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/.mocharc.cjs ADDED
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ require: ['tsx'],
3
+ };
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @prairielearn/html
2
2
 
3
+ ## 4.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 4f30b7e: Publish as native ESM
8
+
9
+ ## 3.1.7
10
+
11
+ ### Patch Changes
12
+
13
+ - c7e6553: Upgrade all JavaScript dependencies
14
+
3
15
  ## 3.1.6
4
16
 
5
17
  ### Patch Changes
package/README.md CHANGED
@@ -6,21 +6,21 @@ Utilities for easily rendering HTML from within JavaScript.
6
6
 
7
7
  The `html` tagged template literal can be used to render HTML while ensuring that any interpolated values are properly escaped.
8
8
 
9
- By convention, HTML templates are located in `*.html.tmpl.js` files.
9
+ By convention, HTML templates are located in `*.html.ts` files.
10
10
 
11
- ```js
12
- // Hello.html.tmpl.js
13
- const { hmtl } = require('@prairielearn/html');
11
+ ```ts
12
+ // Hello.html.ts
13
+ import { html } from '@prairielearn/html';
14
14
 
15
- module.exports.Hello = function Hello({ name }) {
15
+ export function Hello({ name }: { name: string }) {
16
16
  return html`<div>Hello, ${name}!</div>`;
17
- };
17
+ }
18
18
  ```
19
19
 
20
20
  This can then be used to render a string:
21
21
 
22
- ```js
23
- const { Hello } = require('./Hello');
22
+ ```ts
23
+ import { Hello } from './Hello.html.ts';
24
24
 
25
25
  console.log(Hello({ name: 'Anjali' }).toString());
26
26
  // Prints "<div>Hello, Anjali!</div>"
@@ -30,8 +30,8 @@ console.log(Hello({ name: 'Anjali' }).toString());
30
30
 
31
31
  If you want to pre-escape some HTML, you can wrap it in `escapeHtml` to avoid escaping it twice. This is useful if you want to inline some HTML into an attribute, for instance with a Bootstrap popover.
32
32
 
33
- ```js
34
- const { html, escapeHtml } = require('@prairielearn/html');
33
+ ```ts
34
+ import { html, escapeHtml } from '@prairielearn/html';
35
35
 
36
36
  console.log(html`
37
37
  <button data-bs-toggle="popover" data-bs-content="${escapeHtml(html`<div>Content here</div>`)}">
package/dist/index.js CHANGED
@@ -1,6 +1,3 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.joinHtml = exports.unsafeHtml = exports.escapeHtml = exports.html = exports.HtmlSafeString = void 0;
4
1
  const ENCODE_HTML_RULES = {
5
2
  '&': '&amp;',
6
3
  '<': '&lt;',
@@ -45,7 +42,7 @@ function escapeValue(value) {
45
42
  }
46
43
  }
47
44
  // Based on https://github.com/Janpot/escape-html-template-tag
48
- class HtmlSafeString {
45
+ export class HtmlSafeString {
49
46
  strings;
50
47
  values;
51
48
  constructor(strings, values) {
@@ -58,20 +55,17 @@ class HtmlSafeString {
58
55
  }, this.strings[0]);
59
56
  }
60
57
  }
61
- exports.HtmlSafeString = HtmlSafeString;
62
- function html(strings, ...values) {
58
+ export function html(strings, ...values) {
63
59
  return new HtmlSafeString(strings, values);
64
60
  }
65
- exports.html = html;
66
61
  /**
67
62
  * Pre-escapes the rendered HTML. Useful for when you want to inline the HTML
68
63
  * in something else, for instance in a `data-content` attribute for a Bootstrap
69
64
  * popover.
70
65
  */
71
- function escapeHtml(html) {
66
+ export function escapeHtml(html) {
72
67
  return unsafeHtml(escapeHtmlRaw(html.toString()));
73
68
  }
74
- exports.escapeHtml = escapeHtml;
75
69
  /**
76
70
  * Will render the provided value without any additional escaping. Use carefully
77
71
  * with user-provided data.
@@ -79,18 +73,16 @@ exports.escapeHtml = escapeHtml;
79
73
  * @param value The value to render.
80
74
  * @returns An {@link HtmlSafeString} representing the provided value.
81
75
  */
82
- function unsafeHtml(value) {
76
+ export function unsafeHtml(value) {
83
77
  return new HtmlSafeString([value], []);
84
78
  }
85
- exports.unsafeHtml = unsafeHtml;
86
79
  /**
87
80
  * Joins a list of HTML values with a separator.
88
81
  *
89
82
  * @param values The values to join.
90
83
  * @param separator The separator to use between values.
91
84
  */
92
- function joinHtml(values, separator = '') {
85
+ export function joinHtml(values, separator = '') {
93
86
  return unsafeHtml(values.map(escapeValue).join(escapeValue(separator)));
94
87
  }
95
- exports.joinHtml = joinHtml;
96
88
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["const ENCODE_HTML_RULES: Record<string, string> = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&#34;',\n \"'\": '&#39;',\n};\nconst MATCH_HTML = /[&<>'\"]/g;\n\nfunction encodeCharacter(c: string) {\n return ENCODE_HTML_RULES[c] || c;\n}\n\n/**\n * Based on the `escapeXML` function from the `ejs` library.\n */\nfunction escapeHtmlRaw(value: string): string {\n return value == null ? '' : String(value).replace(MATCH_HTML, encodeCharacter);\n}\n\nfunction escapeValue(value: unknown): string {\n if (value instanceof HtmlSafeString) {\n // Already escaped!\n return value.toString();\n } else if (Array.isArray(value)) {\n return value.map((val) => escapeValue(val)).join('');\n } else if (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'bigint' ||\n typeof value === 'boolean'\n ) {\n return escapeHtmlRaw(String(value));\n } else if (value == null) {\n // undefined or null -- render nothing\n return '';\n } else if (typeof value === 'object') {\n throw new Error(`Cannot interpolate object in template: ${JSON.stringify(value)}`);\n } else {\n // There shouldn't be any other types\n throw new Error(\n `Unexpected type in template: ${typeof value} for value ${JSON.stringify(value)}`,\n );\n }\n}\n\n// Based on https://github.com/Janpot/escape-html-template-tag\nexport class HtmlSafeString {\n private readonly strings: readonly string[];\n private readonly values: unknown[];\n\n constructor(strings: readonly string[], values: unknown[]) {\n this.strings = strings;\n this.values = values;\n }\n\n toString(): string {\n return this.values.reduce<string>((acc, val, i) => {\n return acc + escapeValue(val) + this.strings[i + 1];\n }, this.strings[0]);\n }\n}\n\nexport type HtmlValue =\n | string\n | number\n | boolean\n | bigint\n | HtmlSafeString\n | undefined\n | null\n | HtmlValue[];\n\nexport function html(strings: TemplateStringsArray, ...values: HtmlValue[]): HtmlSafeString {\n return new HtmlSafeString(strings, values);\n}\n\n/**\n * Pre-escapes the rendered HTML. Useful for when you want to inline the HTML\n * in something else, for instance in a `data-content` attribute for a Bootstrap\n * popover.\n */\nexport function escapeHtml(html: HtmlSafeString): HtmlSafeString {\n return unsafeHtml(escapeHtmlRaw(html.toString()));\n}\n\n/**\n * Will render the provided value without any additional escaping. Use carefully\n * with user-provided data.\n *\n * @param value The value to render.\n * @returns An {@link HtmlSafeString} representing the provided value.\n */\nexport function unsafeHtml(value: string): HtmlSafeString {\n return new HtmlSafeString([value], []);\n}\n\n/**\n * Joins a list of HTML values with a separator.\n *\n * @param values The values to join.\n * @param separator The separator to use between values.\n */\nexport function joinHtml(values: HtmlValue[], separator: HtmlValue = ''): HtmlSafeString {\n return unsafeHtml(values.map(escapeValue).join(escapeValue(separator)));\n}\n"]}
@@ -1,51 +1,49 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const chai_1 = require("chai");
4
- const index_1 = require("./index");
1
+ import { assert } from 'chai';
2
+ import { escapeHtml, html } from './index.js';
5
3
  describe('html', () => {
6
4
  it('escapes string value', () => {
7
- chai_1.assert.equal((0, index_1.html) `<p>${'<script>'}</p>`.toString(), '<p>&lt;script&gt;</p>');
5
+ assert.equal(html `<p>${'<script>'}</p>`.toString(), '<p>&lt;script&gt;</p>');
8
6
  });
9
7
  it('interpolates multiple values', () => {
10
- chai_1.assert.equal((0, index_1.html) `<p>${'cats'} and ${'dogs'}</p>`.toString(), '<p>cats and dogs</p>');
8
+ assert.equal(html `<p>${'cats'} and ${'dogs'}</p>`.toString(), '<p>cats and dogs</p>');
11
9
  });
12
10
  it('interpolates a number', () => {
13
- chai_1.assert.equal((0, index_1.html) `<p>${123}</p>`.toString(), '<p>123</p>');
11
+ assert.equal(html `<p>${123}</p>`.toString(), '<p>123</p>');
14
12
  });
15
13
  it('interpolates a bigint', () => {
16
- chai_1.assert.equal((0, index_1.html) `<p>${123n}</p>`.toString(), '<p>123</p>');
14
+ assert.equal(html `<p>${123n}</p>`.toString(), '<p>123</p>');
17
15
  });
18
16
  it('interpolates a boolean', () => {
19
- chai_1.assert.equal((0, index_1.html) `<p>${true}</p>`.toString(), '<p>true</p>');
20
- chai_1.assert.equal((0, index_1.html) `<p>${false}</p>`.toString(), '<p>false</p>');
17
+ assert.equal(html `<p>${true}</p>`.toString(), '<p>true</p>');
18
+ assert.equal(html `<p>${false}</p>`.toString(), '<p>false</p>');
21
19
  });
22
20
  it('escapes values when rendering array', () => {
23
21
  const arr = ['cats>', '<dogs'];
24
- chai_1.assert.equal(
22
+ assert.equal(
25
23
  // prettier-ignore
26
- (0, index_1.html) `<ul>${arr}</ul>`.toString(), '<ul>cats&gt;&lt;dogs</ul>');
24
+ html `<ul>${arr}</ul>`.toString(), '<ul>cats&gt;&lt;dogs</ul>');
27
25
  });
28
26
  it('does not double-escape values when rendering array', () => {
29
27
  const arr = ['cats', 'dogs'];
30
- chai_1.assert.equal(
28
+ assert.equal(
31
29
  // prettier-ignore
32
- (0, index_1.html) `<ul>${arr.map((e) => (0, index_1.html) `<li>${e}</li>`)}</ul>`.toString(), '<ul><li>cats</li><li>dogs</li></ul>');
30
+ html `<ul>${arr.map((e) => html `<li>${e}</li>`)}</ul>`.toString(), '<ul><li>cats</li><li>dogs</li></ul>');
33
31
  });
34
32
  it('errors when interpolating object', () => {
35
- chai_1.assert.throws(
33
+ assert.throws(
36
34
  // @ts-expect-error -- Testing runtime behavior of bad input.
37
- () => (0, index_1.html) `<p>${{ foo: 'bar' }}</p>`.toString(), 'Cannot interpolate object in template');
35
+ () => html `<p>${{ foo: 'bar' }}</p>`.toString(), 'Cannot interpolate object in template');
38
36
  });
39
37
  it('omits nullish values from template', () => {
40
- chai_1.assert.equal((0, index_1.html) `<p>${null}${undefined}</p>`.toString(), '<p></p>');
38
+ assert.equal(html `<p>${null}${undefined}</p>`.toString(), '<p></p>');
41
39
  });
42
40
  });
43
41
  describe('escapeHtml', () => {
44
42
  it('escapes rendered HTML', () => {
45
- chai_1.assert.equal((0, index_1.escapeHtml)((0, index_1.html) `<p>Hello</p>`).toString(), '&lt;p&gt;Hello&lt;/p&gt;');
43
+ assert.equal(escapeHtml(html `<p>Hello</p>`).toString(), '&lt;p&gt;Hello&lt;/p&gt;');
46
44
  });
47
45
  it('works when nested inside html tag', () => {
48
- chai_1.assert.equal((0, index_1.html) `a${(0, index_1.escapeHtml)((0, index_1.html) `<p></p>`)}b`.toString(), 'a&lt;p&gt;&lt;/p&gt;b');
46
+ assert.equal(html `a${escapeHtml(html `<p></p>`)}b`.toString(), 'a&lt;p&gt;&lt;/p&gt;b');
49
47
  });
50
48
  });
51
49
  //# sourceMappingURL=index.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { assert } from 'chai';\n\nimport { escapeHtml, html } from './index.js';\n\ndescribe('html', () => {\n it('escapes string value', () => {\n assert.equal(html`<p>${'<script>'}</p>`.toString(), '<p>&lt;script&gt;</p>');\n });\n\n it('interpolates multiple values', () => {\n assert.equal(html`<p>${'cats'} and ${'dogs'}</p>`.toString(), '<p>cats and dogs</p>');\n });\n\n it('interpolates a number', () => {\n assert.equal(html`<p>${123}</p>`.toString(), '<p>123</p>');\n });\n\n it('interpolates a bigint', () => {\n assert.equal(html`<p>${123n}</p>`.toString(), '<p>123</p>');\n });\n\n it('interpolates a boolean', () => {\n assert.equal(html`<p>${true}</p>`.toString(), '<p>true</p>');\n assert.equal(html`<p>${false}</p>`.toString(), '<p>false</p>');\n });\n\n it('escapes values when rendering array', () => {\n const arr = ['cats>', '<dogs'];\n assert.equal(\n // prettier-ignore\n html`<ul>${arr}</ul>`.toString(),\n '<ul>cats&gt;&lt;dogs</ul>',\n );\n });\n\n it('does not double-escape values when rendering array', () => {\n const arr = ['cats', 'dogs'];\n assert.equal(\n // prettier-ignore\n html`<ul>${arr.map((e) => html`<li>${e}</li>`)}</ul>`.toString(),\n '<ul><li>cats</li><li>dogs</li></ul>',\n );\n });\n\n it('errors when interpolating object', () => {\n assert.throws(\n // @ts-expect-error -- Testing runtime behavior of bad input.\n () => html`<p>${{ foo: 'bar' }}</p>`.toString(),\n 'Cannot interpolate object in template',\n );\n });\n\n it('omits nullish values from template', () => {\n assert.equal(html`<p>${null}${undefined}</p>`.toString(), '<p></p>');\n });\n});\n\ndescribe('escapeHtml', () => {\n it('escapes rendered HTML', () => {\n assert.equal(escapeHtml(html`<p>Hello</p>`).toString(), '&lt;p&gt;Hello&lt;/p&gt;');\n });\n\n it('works when nested inside html tag', () => {\n assert.equal(html`a${escapeHtml(html`<p></p>`)}b`.toString(), 'a&lt;p&gt;&lt;/p&gt;b');\n });\n});\n"]}
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@prairielearn/html",
3
- "version": "3.1.6",
3
+ "version": "4.0.0",
4
+ "type": "module",
4
5
  "main": "dist/index.js",
5
6
  "sideEffects": false,
6
7
  "repository": {
@@ -11,14 +12,14 @@
11
12
  "scripts": {
12
13
  "build": "tsc",
13
14
  "dev": "tsc --watch --preserveWatchOutput",
14
- "test": "mocha --no-config --require tsx src/index.test.ts"
15
+ "test": "mocha src/**/*.test.ts"
15
16
  },
16
17
  "devDependencies": {
17
18
  "@prairielearn/tsconfig": "^0.0.0",
18
- "@types/node": "^20.11.30",
19
+ "@types/node": "^20.12.2",
19
20
  "chai": "^4.4.1",
20
21
  "mocha": "^10.4.0",
21
- "tsx": "^4.7.1",
22
+ "tsx": "^4.9.3",
22
23
  "typescript": "^5.4.3"
23
24
  }
24
25
  }
package/src/index.test.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { assert } from 'chai';
2
2
 
3
- import { escapeHtml, html } from './index';
3
+ import { escapeHtml, html } from './index.js';
4
4
 
5
5
  describe('html', () => {
6
6
  it('escapes string value', () => {