ghtml 3.0.7 → 3.0.9

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Gürgün Dayıoğlu
3
+ Copyright (c) 2023 Gürgün Dayıoğlu
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/bench/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  /* eslint-disable no-unused-vars */
2
- import { html } from "../src/index.js";
2
+ import { html } from "ghtml";
3
3
  import { Bench } from "tinybench";
4
4
  import { writeFileSync } from "node:fs";
5
5
  import { Buffer } from "node:buffer";
6
6
 
7
- let result = "";
8
7
  const bench = new Bench({ time: 500 });
8
+ let result = "";
9
9
 
10
10
  bench.add("simple HTML formatting", () => {
11
11
  result = html`<div>Hello, world!</div>`;
@@ -112,7 +112,7 @@ await bench.warmup();
112
112
  await bench.run();
113
113
 
114
114
  const table = bench.table();
115
- console.table(table);
115
+ globalThis.console.table(table);
116
116
 
117
117
  writeFileSync(
118
118
  "bench/results.json",
package/bin/README.md CHANGED
@@ -5,7 +5,7 @@ Append unique hashes to assets referenced in your views to aggressively cache th
5
5
  Running the following command will scan asset files found in the `roots` path(s) and replace their references in the `refs` path(s) with hashed versions:
6
6
 
7
7
  ```sh
8
- npx ghtml --roots="base/path/to/scan/assets/1/,base/path/to/scan/assets/2/" --refs="views/path/to/append/hashes/1/,views/path/to/append/hashes/2/"
8
+ npx ghtml --roots="base/path/to/scan/assets/1/,base/path/to/scan/assets/2/" --refs="views/path/to/append/hashes/1/,views/path/to/append/hashes/2/" --prefix="/optional/prefix/"
9
9
  ```
10
10
 
11
11
  ## Example (Fastify)
@@ -1 +1 @@
1
- console.warn("Hello World!");
1
+ globalThis.console.log("Hello World!");
@@ -6,8 +6,8 @@
6
6
  "build": "ghtml --roots=assets/ --refs=routes/ --prefix=/p/assets/"
7
7
  },
8
8
  "dependencies": {
9
- "@fastify/static": "^7.0.1",
10
- "fastify": "^4.26.1",
9
+ "@fastify/static": "^8.0.1",
10
+ "fastify": "^5.0.0",
11
11
  "ghtml": "file:../../"
12
12
  }
13
13
  }
@@ -19,7 +19,7 @@ export default async (fastify) => {
19
19
  <body>
20
20
  !${inner}
21
21
  </body>
22
- </html> `;
22
+ </html>`;
23
23
  });
24
24
 
25
25
  fastify.get("/", async (request, reply) => {
@@ -4,7 +4,7 @@ const fastify = Fastify();
4
4
 
5
5
  // Plugins
6
6
  await fastify.register(import("@fastify/static"), {
7
- root: new URL("assets/", import.meta.url).pathname,
7
+ root: new globalThis.URL("assets/", import.meta.url).pathname,
8
8
  prefix: "/p/assets/",
9
9
  wildcard: false,
10
10
  index: false,
@@ -15,10 +15,7 @@ await fastify.register(import("@fastify/static"), {
15
15
  // Routes
16
16
  fastify.register(import("./routes/index.js"));
17
17
 
18
- fastify.listen({ port: 5050 }, (err, address) => {
19
- if (err) {
20
- throw err;
21
- }
18
+ // Listen
19
+ const address = await fastify.listen({ port: 5050 });
22
20
 
23
- console.warn(`Server listening at ${address}`);
24
- });
21
+ globalThis.console.log(`Server listening at ${address}`);
package/bin/src/index.js CHANGED
@@ -18,7 +18,7 @@ const parseArguments = (args) => {
18
18
  }
19
19
 
20
20
  if (!roots || !refs) {
21
- console.error(
21
+ globalThis.console.log(
22
22
  'Usage: npx ghtml --roots="base/path/to/scan/assets/1/,base/path/to/scan/assets/2/" --refs="views/path/to/append/hashes/1/,views/path/to/append/hashes/2/" [--prefix="/optional/prefix/"]',
23
23
  );
24
24
  process.exit(1);
@@ -31,10 +31,10 @@ const main = async () => {
31
31
  const { roots, refs, prefix } = parseArguments(process.argv.slice(2));
32
32
 
33
33
  try {
34
- console.warn(`Generating hashes and updating file paths...`);
35
- console.warn(`Scanning files in: ${roots}`);
36
- console.warn(`Updating files in: ${refs}`);
37
- console.warn(`Using prefix: ${prefix}`);
34
+ globalThis.console.log(`Generating hashes and updating file paths...`);
35
+ globalThis.console.log(`Scanning files in: ${roots}`);
36
+ globalThis.console.log(`Updating files in: ${refs}`);
37
+ globalThis.console.log(`Using prefix: ${prefix}`);
38
38
 
39
39
  await generateHashesAndReplace({
40
40
  roots,
@@ -42,9 +42,11 @@ const main = async () => {
42
42
  prefix,
43
43
  });
44
44
 
45
- console.warn("Hash generation and file updates completed successfully.");
45
+ globalThis.console.log(
46
+ "Hash generation and file updates completed successfully.",
47
+ );
46
48
  } catch (error) {
47
- console.error(`Error occurred: ${error.message}`);
49
+ globalThis.console.log(`Error occurred: ${error.message}`);
48
50
  process.exit(1);
49
51
  }
50
52
  };
package/bin/src/utils.js CHANGED
@@ -6,11 +6,13 @@ import { win32, posix } from "node:path";
6
6
  const generateFileHash = async (filePath) => {
7
7
  try {
8
8
  const fileBuffer = await readFile(filePath);
9
+
9
10
  return createHash("md5").update(fileBuffer).digest("hex").slice(0, 16);
10
11
  } catch (err) {
11
12
  if (err.code !== "ENOENT") {
12
13
  throw err;
13
14
  }
15
+
14
16
  return "";
15
17
  }
16
18
  };
@@ -24,6 +26,7 @@ const updateFilePathsWithHashes = async (
24
26
  ) => {
25
27
  for (let ref of refs) {
26
28
  ref = ref.replaceAll(win32.sep, posix.sep);
29
+
27
30
  if (!ref.endsWith("/")) {
28
31
  ref += "/";
29
32
  }
@@ -44,12 +47,12 @@ const updateFilePathsWithHashes = async (
44
47
  for (const [path, hash] of fileHashes) {
45
48
  const fullPath = prefix + path;
46
49
  const escapedPath = fullPath.replace(
47
- /[$()*+.?[\\\]^{|}]/g,
50
+ /[$()*+.?[\\\]^{|}]/gu,
48
51
  String.raw`\$&`,
49
52
  );
50
53
  const regex = new RegExp(
51
54
  `(?<path>${escapedPath})(\\?(?<queryString>[^#"'\`]*))?`,
52
- "g",
55
+ "gu",
53
56
  );
54
57
 
55
58
  content = content.replace(
@@ -82,11 +85,13 @@ export const generateHashesAndReplace = async ({
82
85
  skipPatterns = ["**/node_modules/**"],
83
86
  }) => {
84
87
  const fileHashes = new Map();
88
+
85
89
  roots = Array.isArray(roots) ? roots : [roots];
86
90
  refs = Array.isArray(refs) ? refs : [refs];
87
91
 
88
92
  for (let root of roots) {
89
93
  root = root.replaceAll(win32.sep, posix.sep);
94
+
90
95
  if (!root.endsWith("/")) {
91
96
  root += "/";
92
97
  }
@@ -112,6 +117,7 @@ export const generateHashesAndReplace = async ({
112
117
 
113
118
  for (let i = 0; i < files.length; ++i) {
114
119
  const fileRelativePath = posix.relative(root, files[i]);
120
+
115
121
  fileHashes.set(fileRelativePath, hashes[i]);
116
122
  }
117
123
  }
@@ -0,0 +1,14 @@
1
+ import grules from "grules";
2
+
3
+ export default [
4
+ ...grules,
5
+ {
6
+ rules: {
7
+ "no-await-in-loop": "off",
8
+ "require-unicode-regexp": "off",
9
+ },
10
+ },
11
+ {
12
+ ignores: ["bin/example/**/*.js"],
13
+ },
14
+ ];
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Replace your template engine with fast JavaScript by leveraging the power of tagged templates.",
4
4
  "author": "Gürgün Dayıoğlu",
5
5
  "license": "MIT",
6
- "version": "3.0.7",
6
+ "version": "3.0.9",
7
7
  "type": "module",
8
8
  "bin": "./bin/src/index.js",
9
9
  "main": "./src/index.js",
@@ -19,7 +19,7 @@
19
19
  "test": "npm run lint && c8 --100 node --test test/*.js",
20
20
  "lint": "eslint . && prettier --check .",
21
21
  "lint:fix": "eslint --fix . && prettier --write .",
22
- "typescript": "tsc src/*.js --allowJs --declaration --emitDeclarationOnly"
22
+ "typescript": "tsc src/*.js --allowJs --declaration --emitDeclarationOnly --skipLibCheck"
23
23
  },
24
24
  "dependencies": {
25
25
  "glob": "^10.4.5"
@@ -27,9 +27,9 @@
27
27
  "devDependencies": {
28
28
  "@fastify/pre-commit": "^2.1.0",
29
29
  "c8": "^10.1.2",
30
- "grules": "^0.23.3",
30
+ "grules": "^0.25.3",
31
31
  "tinybench": "^2.9.0",
32
- "typescript": ">=5.5.4"
32
+ "typescript": ">=5.6.2"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",
@@ -3,8 +3,8 @@ import { readFileSync } from "node:fs";
3
3
  const cache = new Map();
4
4
 
5
5
  /**
6
- * @param {string} path The path to the file to render.
7
- * @returns {string} The content of the file.
6
+ * @param {string} path path
7
+ * @returns {string} string
8
8
  */
9
9
  export const includeFile = (path) => {
10
10
  let file = cache.get(path);
package/src/index.d.ts CHANGED
@@ -1 +1,3 @@
1
- export { html, htmlGenerator, htmlAsyncGenerator } from "./html.js";
1
+ export function html(literals: TemplateStringsArray, ...expressions: any[]): string;
2
+ export function htmlGenerator(literals: TemplateStringsArray, ...expressions: any[]): Generator<string, void, void>;
3
+ export function htmlAsyncGenerator(literals: TemplateStringsArray, ...expressions: any[]): AsyncGenerator<string, void, void>;
package/src/index.js CHANGED
@@ -1 +1,246 @@
1
- export { html, htmlGenerator, htmlAsyncGenerator } from "./html.js";
1
+ const escapeRegExp = /["&'<=>]/g;
2
+
3
+ const escapeFunction = (string) => {
4
+ let escaped = "";
5
+ let start = 0;
6
+
7
+ while (escapeRegExp.test(string)) {
8
+ const i = escapeRegExp.lastIndex - 1;
9
+
10
+ switch (string.charCodeAt(i)) {
11
+ case 34:
12
+ escaped += string.slice(start, i) + "&#34;"; // "
13
+ break;
14
+ case 38:
15
+ escaped += string.slice(start, i) + "&#38;"; // &
16
+ break;
17
+ case 39:
18
+ escaped += string.slice(start, i) + "&#39;"; // '
19
+ break;
20
+ case 60:
21
+ escaped += string.slice(start, i) + "&#60;"; // <
22
+ break;
23
+ case 61:
24
+ escaped += string.slice(start, i) + "&#61;"; // =
25
+ break;
26
+ default: {
27
+ escaped += string.slice(start, i) + "&#62;"; // >
28
+ }
29
+ }
30
+
31
+ start = escapeRegExp.lastIndex;
32
+ }
33
+
34
+ return escaped + string.slice(start);
35
+ };
36
+
37
+ /**
38
+ * @param {TemplateStringsArray} literals literals
39
+ * @param {...any} expressions expressions
40
+ * @returns {string} string
41
+ */
42
+ export const html = (literals, ...expressions) => {
43
+ let accumulator = "";
44
+
45
+ for (let i = 0; i !== expressions.length; ++i) {
46
+ let literal = literals.raw[i];
47
+ let string = Array.isArray(expressions[i])
48
+ ? expressions[i].join("")
49
+ : String(expressions[i] ?? "");
50
+
51
+ if (literal && literal.charCodeAt(literal.length - 1) === 33) {
52
+ literal = literal.slice(0, -1);
53
+ } else {
54
+ string &&= escapeFunction(string);
55
+ }
56
+
57
+ accumulator += literal + string;
58
+ }
59
+
60
+ return accumulator + literals.raw[expressions.length];
61
+ };
62
+
63
+ /**
64
+ * @param {TemplateStringsArray} literals literals
65
+ * @param {...any} expressions expressions
66
+ * @yields {string} string
67
+ * @returns {Generator<string, void, void>} Generator<string, void, void>
68
+ */
69
+ export const htmlGenerator = function* (literals, ...expressions) {
70
+ for (let i = 0; i !== expressions.length; ++i) {
71
+ let expression = expressions[i];
72
+ let literal = literals.raw[i];
73
+ let string;
74
+
75
+ if (typeof expression === "string") {
76
+ string = expression;
77
+ } else if (expression === undefined || expression === null) {
78
+ string = "";
79
+ } else {
80
+ if (expression[Symbol.iterator]) {
81
+ const isRaw =
82
+ Boolean(literal) && literal.charCodeAt(literal.length - 1) === 33;
83
+
84
+ if (isRaw) {
85
+ literal = literal.slice(0, -1);
86
+ }
87
+
88
+ if (literal) {
89
+ yield literal;
90
+ }
91
+
92
+ for (expression of expression) {
93
+ if (typeof expression === "string") {
94
+ string = expression;
95
+ } else {
96
+ if (expression === undefined || expression === null) {
97
+ continue;
98
+ }
99
+
100
+ if (expression[Symbol.iterator]) {
101
+ for (expression of expression) {
102
+ if (expression === undefined || expression === null) {
103
+ continue;
104
+ }
105
+
106
+ string = String(expression);
107
+
108
+ if (string) {
109
+ if (!isRaw) {
110
+ string = escapeFunction(string);
111
+ }
112
+
113
+ yield string;
114
+ }
115
+ }
116
+
117
+ continue;
118
+ }
119
+
120
+ string = String(expression);
121
+ }
122
+
123
+ if (string) {
124
+ if (!isRaw) {
125
+ string = escapeFunction(string);
126
+ }
127
+
128
+ yield string;
129
+ }
130
+ }
131
+
132
+ continue;
133
+ }
134
+
135
+ string = String(expression);
136
+ }
137
+
138
+ if (literal && literal.charCodeAt(literal.length - 1) === 33) {
139
+ literal = literal.slice(0, -1);
140
+ } else {
141
+ string &&= escapeFunction(string);
142
+ }
143
+
144
+ if (literal || string) {
145
+ yield literal + string;
146
+ }
147
+ }
148
+
149
+ if (literals.raw[expressions.length]) {
150
+ yield literals.raw[expressions.length];
151
+ }
152
+ };
153
+
154
+ /**
155
+ * @param {TemplateStringsArray} literals literals
156
+ * @param {...any} expressions expressions
157
+ * @yields {string} string
158
+ * @returns {AsyncGenerator<string, void, void>} AsyncGenerator<string, void, void>
159
+ */
160
+ export const htmlAsyncGenerator = async function* (literals, ...expressions) {
161
+ for (let i = 0; i !== expressions.length; ++i) {
162
+ let expression = await expressions[i];
163
+ let literal = literals.raw[i];
164
+ let string;
165
+
166
+ if (typeof expression === "string") {
167
+ string = expression;
168
+ } else if (expression === undefined || expression === null) {
169
+ string = "";
170
+ } else {
171
+ if (expression[Symbol.iterator] || expression[Symbol.asyncIterator]) {
172
+ const isRaw =
173
+ Boolean(literal) && literal.charCodeAt(literal.length - 1) === 33;
174
+
175
+ if (isRaw) {
176
+ literal = literal.slice(0, -1);
177
+ }
178
+
179
+ if (literal) {
180
+ yield literal;
181
+ }
182
+
183
+ for await (expression of expression) {
184
+ if (typeof expression === "string") {
185
+ string = expression;
186
+ } else {
187
+ if (expression === undefined || expression === null) {
188
+ continue;
189
+ }
190
+
191
+ if (
192
+ expression[Symbol.iterator] ||
193
+ expression[Symbol.asyncIterator]
194
+ ) {
195
+ for await (expression of expression) {
196
+ if (expression === undefined || expression === null) {
197
+ continue;
198
+ }
199
+
200
+ string = String(expression);
201
+
202
+ if (string) {
203
+ if (!isRaw) {
204
+ string = escapeFunction(string);
205
+ }
206
+
207
+ yield string;
208
+ }
209
+ }
210
+
211
+ continue;
212
+ }
213
+
214
+ string = String(expression);
215
+ }
216
+
217
+ if (string) {
218
+ if (!isRaw) {
219
+ string = escapeFunction(string);
220
+ }
221
+
222
+ yield string;
223
+ }
224
+ }
225
+
226
+ continue;
227
+ }
228
+
229
+ string = String(expression);
230
+ }
231
+
232
+ if (literal && literal.charCodeAt(literal.length - 1) === 33) {
233
+ literal = literal.slice(0, -1);
234
+ } else {
235
+ string &&= escapeFunction(string);
236
+ }
237
+
238
+ if (literal || string) {
239
+ yield literal + string;
240
+ }
241
+ }
242
+
243
+ if (literals.raw[expressions.length]) {
244
+ yield literals.raw[expressions.length];
245
+ }
246
+ };
package/test/index.js CHANGED
@@ -22,6 +22,11 @@ const generatorExample = function* () {
22
22
  yield "</p>";
23
23
  };
24
24
 
25
+ const generatorExample2 = function* () {
26
+ yield ["", "<p>"];
27
+ yield "";
28
+ };
29
+
25
30
  const generatorPromiseExample = function* () {
26
31
  yield [
27
32
  new Promise((resolve) => {
@@ -33,6 +38,17 @@ const generatorPromiseExample = function* () {
33
38
  yield;
34
39
  };
35
40
 
41
+ const generatorPromiseExample2 = function* () {
42
+ yield [
43
+ new Promise((resolve) => {
44
+ resolve("<p>");
45
+ }),
46
+ null,
47
+ "",
48
+ ];
49
+ yield "";
50
+ };
51
+
36
52
  test("renders empty input", () => {
37
53
  assert.strictEqual(html({ raw: [""] }), "");
38
54
  });
@@ -204,6 +220,18 @@ test("htmlGenerator works with other generators (raw)", () => {
204
220
  assert.strictEqual(generator.next().done, true);
205
221
  });
206
222
 
223
+ test("htmlGenerator works with other generators (raw) /2", () => {
224
+ const generator = htmlGenerator`<div>!${generatorExample2()}</div>`;
225
+ let accumulator = "";
226
+
227
+ for (const value of generator) {
228
+ accumulator += value;
229
+ }
230
+
231
+ assert.strictEqual(accumulator, "<div><p></div>");
232
+ assert.strictEqual(generator.next().done, true);
233
+ });
234
+
207
235
  test("htmlGenerator works with other generators (escaped)", () => {
208
236
  const generator = htmlGenerator`<div>${generatorExample()}</div>`;
209
237
  let accumulator = "";
@@ -291,6 +319,17 @@ test("htmlAsyncGenerator works with other generators (raw)", async () => {
291
319
  );
292
320
  });
293
321
 
322
+ test("htmlAsyncGenerator works with other generators (raw) /2", async () => {
323
+ const generator = htmlAsyncGenerator`<div>!${generatorPromiseExample2()}</div>`;
324
+ let accumulator = "";
325
+
326
+ for await (const value of generator) {
327
+ accumulator += value;
328
+ }
329
+
330
+ assert.strictEqual(accumulator, "<div><p></div>");
331
+ });
332
+
294
333
  test("htmlAsyncGenerator works with other generators (escaped)", async () => {
295
334
  const generator = htmlAsyncGenerator`<div>${generatorExample()}</div>`;
296
335
  let accumulator = "";
package/.eslintrc.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "root": true,
3
- "extends": ["plugin:grules/all"],
4
- "rules": {
5
- "no-await-in-loop": "off",
6
- "require-unicode-regexp": "off"
7
- }
8
- }
@@ -1,6 +0,0 @@
1
- {
2
- "rules": {
3
- "require-await": "off",
4
- "n/no-missing-import": "off"
5
- }
6
- }
package/src/html.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export function html(literals: TemplateStringsArray, ...expressions: any[]): string;
2
- export function htmlGenerator(literals: TemplateStringsArray, ...expressions: any[]): Generator<string, void, void>;
3
- export function htmlAsyncGenerator(literals: TemplateStringsArray, ...expressions: any[]): AsyncGenerator<string, void, void>;
package/src/html.js DELETED
@@ -1,262 +0,0 @@
1
- const escapeRegExp = /["&'<=>]/g;
2
-
3
- const escapeFunction = (string) => {
4
- let escaped = "";
5
- let start = 0;
6
-
7
- while (escapeRegExp.test(string)) {
8
- const i = escapeRegExp.lastIndex - 1;
9
-
10
- switch (string.charCodeAt(i)) {
11
- case 34: // "
12
- escaped += string.slice(start, i) + "&#34;";
13
- break;
14
- case 38: // &
15
- escaped += string.slice(start, i) + "&#38;";
16
- break;
17
- case 39: // '
18
- escaped += string.slice(start, i) + "&#39;";
19
- break;
20
- case 60: // <
21
- escaped += string.slice(start, i) + "&#60;";
22
- break;
23
- case 61: // =
24
- escaped += string.slice(start, i) + "&#61;";
25
- break;
26
- case 62: // >
27
- escaped += string.slice(start, i) + "&#62;";
28
- break;
29
- }
30
-
31
- start = escapeRegExp.lastIndex;
32
- }
33
-
34
- return escaped + string.slice(start);
35
- };
36
-
37
- /**
38
- * The `html` function is designed to tag template literals and automatically escape their expressions.
39
- * @param {TemplateStringsArray} literals Tagged template literals.
40
- * @param {...any} expressions Expressions to interpolate.
41
- * @returns {string} The processed HTML string.
42
- */
43
- export const html = (literals, ...expressions) => {
44
- let accumulator = "";
45
-
46
- for (let i = 0; i !== expressions.length; ++i) {
47
- let literal = literals.raw[i];
48
- let string =
49
- typeof expressions[i] === "string"
50
- ? expressions[i]
51
- : expressions[i] == null
52
- ? ""
53
- : Array.isArray(expressions[i])
54
- ? expressions[i].join("")
55
- : `${expressions[i]}`;
56
-
57
- if (literal && literal.charCodeAt(literal.length - 1) === 33) {
58
- literal = literal.slice(0, -1);
59
- } else {
60
- string &&= escapeFunction(string);
61
- }
62
-
63
- accumulator += literal + string;
64
- }
65
-
66
- return accumulator + literals.raw[expressions.length];
67
- };
68
-
69
- /**
70
- * The `htmlGenerator` function acts as the generator version of the `html` function.
71
- * @param {TemplateStringsArray} literals Tagged template literals.
72
- * @param {...any} expressions Expressions to interpolate.
73
- * @yields Processed HTML strings.
74
- * @returns {Generator<string, void, void>} The HTML generator.
75
- */
76
- export const htmlGenerator = function* (literals, ...expressions) {
77
- for (let i = 0; i !== expressions.length; ++i) {
78
- let expression = expressions[i];
79
- let literal = literals.raw[i];
80
- let string;
81
-
82
- if (typeof expression === "string") {
83
- string = expression;
84
- } else if (expression == null) {
85
- string = "";
86
- } else {
87
- if (expression[Symbol.iterator]) {
88
- const isRaw =
89
- literal !== "" && literal.charCodeAt(literal.length - 1) === 33;
90
-
91
- if (isRaw) {
92
- literal = literal.slice(0, -1);
93
- }
94
-
95
- if (literal) {
96
- yield literal;
97
- }
98
-
99
- for (expression of expression) {
100
- if (typeof expression === "string") {
101
- string = expression;
102
- } else {
103
- if (expression == null) {
104
- continue;
105
- }
106
-
107
- if (expression[Symbol.iterator]) {
108
- for (expression of expression) {
109
- if (typeof expression === "string") {
110
- string = expression;
111
- } else {
112
- if (expression == null) {
113
- continue;
114
- }
115
-
116
- string = `${expression}`;
117
- }
118
-
119
- if (string) {
120
- if (!isRaw) {
121
- string = escapeFunction(string);
122
- }
123
-
124
- yield string;
125
- }
126
- }
127
-
128
- continue;
129
- }
130
-
131
- string = `${expression}`;
132
- }
133
-
134
- if (string) {
135
- if (!isRaw) {
136
- string = escapeFunction(string);
137
- }
138
-
139
- yield string;
140
- }
141
- }
142
-
143
- continue;
144
- }
145
-
146
- string = `${expression}`;
147
- }
148
-
149
- if (literal && literal.charCodeAt(literal.length - 1) === 33) {
150
- literal = literal.slice(0, -1);
151
- } else {
152
- string &&= escapeFunction(string);
153
- }
154
-
155
- if (literal || string) {
156
- yield literal + string;
157
- }
158
- }
159
-
160
- if (literals.raw[expressions.length]) {
161
- yield literals.raw[expressions.length];
162
- }
163
- };
164
-
165
- /**
166
- * This version of HTML generator should be preferred for asynchronous and streaming use cases.
167
- * @param {TemplateStringsArray} literals Tagged template literals.
168
- * @param {...any} expressions Expressions to interpolate.
169
- * @yields Processed HTML strings.
170
- * @returns {AsyncGenerator<string, void, void>} The HTML generator.
171
- */
172
- export const htmlAsyncGenerator = async function* (literals, ...expressions) {
173
- for (let i = 0; i !== expressions.length; ++i) {
174
- let expression = await expressions[i];
175
- let literal = literals.raw[i];
176
- let string;
177
-
178
- if (typeof expression === "string") {
179
- string = expression;
180
- } else if (expression == null) {
181
- string = "";
182
- } else {
183
- if (expression[Symbol.iterator] || expression[Symbol.asyncIterator]) {
184
- const isRaw =
185
- literal !== "" && literal.charCodeAt(literal.length - 1) === 33;
186
-
187
- if (isRaw) {
188
- literal = literal.slice(0, -1);
189
- }
190
-
191
- if (literal) {
192
- yield literal;
193
- }
194
-
195
- for await (expression of expression) {
196
- if (typeof expression === "string") {
197
- string = expression;
198
- } else {
199
- if (expression == null) {
200
- continue;
201
- }
202
-
203
- if (
204
- expression[Symbol.iterator] ||
205
- expression[Symbol.asyncIterator]
206
- ) {
207
- for await (expression of expression) {
208
- if (typeof expression === "string") {
209
- string = expression;
210
- } else {
211
- if (expression == null) {
212
- continue;
213
- }
214
-
215
- string = `${expression}`;
216
- }
217
-
218
- if (string) {
219
- if (!isRaw) {
220
- string = escapeFunction(string);
221
- }
222
-
223
- yield string;
224
- }
225
- }
226
-
227
- continue;
228
- }
229
-
230
- string = `${expression}`;
231
- }
232
-
233
- if (string) {
234
- if (!isRaw) {
235
- string = escapeFunction(string);
236
- }
237
-
238
- yield string;
239
- }
240
- }
241
-
242
- continue;
243
- }
244
-
245
- string = `${expression}`;
246
- }
247
-
248
- if (literal && literal.charCodeAt(literal.length - 1) === 33) {
249
- literal = literal.slice(0, -1);
250
- } else {
251
- string &&= escapeFunction(string);
252
- }
253
-
254
- if (literal || string) {
255
- yield literal + string;
256
- }
257
- }
258
-
259
- if (literals.raw[expressions.length]) {
260
- yield literals.raw[expressions.length];
261
- }
262
- };