achi-html-stream 1.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/LICENSE +21 -0
- package/README.md +382 -0
- package/dist/browser/index.d.mts +73 -0
- package/dist/browser/index.iife.js +2 -0
- package/dist/browser/index.iife.js.map +1 -0
- package/dist/browser/index.mjs +2 -0
- package/dist/browser/index.mjs.map +1 -0
- package/dist/node/index.cjs +2 -0
- package/dist/node/index.cjs.map +1 -0
- package/dist/node/index.d.cts +74 -0
- package/dist/node/index.d.mts +74 -0
- package/dist/node/index.mjs +2 -0
- package/dist/node/index.mjs.map +1 -0
- package/package.json +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License Copyright (c) 2026 Kimbugwe Mark
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free
|
|
4
|
+
of charge, to any person obtaining a copy of this software and associated
|
|
5
|
+
documentation files (the "Software"), to deal in the Software without
|
|
6
|
+
restriction, including without limitation the rights to use, copy, modify, merge,
|
|
7
|
+
publish, distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice
|
|
12
|
+
(including the next paragraph) shall be included in all copies or substantial
|
|
13
|
+
portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
|
16
|
+
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
18
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
19
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
20
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
# achi-html-stream
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://www.typescriptlang.org/)
|
|
5
|
+
|
|
6
|
+
**achi-html-stream** is an HTML streaming and templating library for multi-page Progressive Web Apps. It is designed to render HTML from a **service worker**, and also runs on **Node.js**, **Bun**, **Deno** and edge runtimes that support Web Streams.
|
|
7
|
+
|
|
8
|
+
It uses tagged template literals with automatic XSS escaping, async values, readable-stream embedding/piping and response, with zero runtime dependencies.
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Streaming by design**: HTML is flushed progressively as data resolves, without buffering whole pages.
|
|
13
|
+
- **Escaped by default**: interpolated strings and array items are HTML-escaped. Raw HTML is opt-in via `UnSafeHTML`.
|
|
14
|
+
- **Async and stream embedding**: interpolate `Promise`, `ReadableStream`, `Response` and `Request` values directly.
|
|
15
|
+
- **Cached compilation**:
|
|
16
|
+
- 🚀 **Cached Template Compilation** – `html` compiles template literals into optimized generator functions and caches them using `WeakMap` for maximum throughput.
|
|
17
|
+
- **Multi-runtime**: dedicated entry points for Web Standards (`achi-html-stream/browser`) and Node.js (`achi-html-stream/node`).
|
|
18
|
+
- **Zero dependencies**.
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install achi-html-stream
|
|
24
|
+
# or: pnpm add achi-html-stream / yarn add achi-html-stream / bun add achi-html-stream
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### CDN / `<script>`
|
|
28
|
+
|
|
29
|
+
````html
|
|
30
|
+
Pre-bundled builds expose `window.achiHTML`. ```html
|
|
31
|
+
<script src="https://unpkg.com/achi-html-stream"></script>
|
|
32
|
+
<!-- or -->
|
|
33
|
+
<script src="https://cdn.jsdelivr.net/npm/achi-html-stream"></script>
|
|
34
|
+
````
|
|
35
|
+
|
|
36
|
+
Pin a version in production, for example `https://unpkg.com/achi-html-stream@1.2.3`.
|
|
37
|
+
|
|
38
|
+
````
|
|
39
|
+
|
|
40
|
+
## Quick start
|
|
41
|
+
|
|
42
|
+
### Service worker
|
|
43
|
+
|
|
44
|
+
Return a streaming `Response` from a `fetch` handler:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { html, render } from 'achi-html-stream'
|
|
48
|
+
|
|
49
|
+
self.addEventListener('fetch', (event) => {
|
|
50
|
+
const url = new URL(event.request.url)
|
|
51
|
+
|
|
52
|
+
if (url.pathname === '/') {
|
|
53
|
+
event.respondWith(
|
|
54
|
+
render(
|
|
55
|
+
html`<!doctype html>
|
|
56
|
+
<html lang="en">
|
|
57
|
+
<head>
|
|
58
|
+
<meta charset="utf-8" />
|
|
59
|
+
<title>PWA Streaming</title>
|
|
60
|
+
</head>
|
|
61
|
+
<body>
|
|
62
|
+
<h1>Hello, ${'world'}!</h1>
|
|
63
|
+
</body>
|
|
64
|
+
</html>`,
|
|
65
|
+
{ 'Cache-Control': 'no-cache' }
|
|
66
|
+
)
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
````
|
|
71
|
+
|
|
72
|
+
`render()` sets `Content-Type: text/html; charset=utf-8` by default and streams the output through a native `Response`.
|
|
73
|
+
|
|
74
|
+
### Node.js
|
|
75
|
+
|
|
76
|
+
The Node entry point pipes the rendered stream into a `http.ServerResponse`:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { createServer } from "node:http";
|
|
80
|
+
import { html, render } from "achi-html-stream";
|
|
81
|
+
|
|
82
|
+
createServer((req, res) => {
|
|
83
|
+
render(
|
|
84
|
+
res,
|
|
85
|
+
html`<!doctype html>
|
|
86
|
+
<html>
|
|
87
|
+
<body>
|
|
88
|
+
<h1>Requested: ${req.url}</h1>
|
|
89
|
+
<p>Time: ${new Date().toISOString()}</p>
|
|
90
|
+
</body>
|
|
91
|
+
</html>`,
|
|
92
|
+
{ "X-Powered-By": "achi-html-stream" },
|
|
93
|
+
);
|
|
94
|
+
}).listen(3000);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Edge runtimes (Deno, Bun, Hono, ...)
|
|
98
|
+
|
|
99
|
+
Anything that accepts a Web `Response` works:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import { html, render } from "achi-html-stream";
|
|
103
|
+
//or import { html, render } from 'achi-html-stream/node' for node compatibility
|
|
104
|
+
|
|
105
|
+
export default {
|
|
106
|
+
async fetch(): Promise<Response> {
|
|
107
|
+
const user = fetch("https://api.example.com/user").then((r) => r.json());
|
|
108
|
+
|
|
109
|
+
return render(
|
|
110
|
+
html`<!doctype html>
|
|
111
|
+
<html>
|
|
112
|
+
<body>
|
|
113
|
+
<h1>Welcome, ${(async () => (await user).name)()}</h1>
|
|
114
|
+
</body>
|
|
115
|
+
</html>`,
|
|
116
|
+
);
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
> **Cloudflare Workers and strict CSP:** `html` generates its compiled function at runtime, which runtimes that block dynamic code evaluation reject. Use [`liveHTML`](#html-vs-livehtml) there.
|
|
122
|
+
|
|
123
|
+
### Render to a string
|
|
124
|
+
|
|
125
|
+
For SSG, static output or emails:
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { html, renderAsString } from "achi-html-stream";
|
|
129
|
+
|
|
130
|
+
const page = await renderAsString(
|
|
131
|
+
html`<main><h1>${"Hello Static HTML"}</h1></main>`,
|
|
132
|
+
);
|
|
133
|
+
// <main><h1>Hello Static HTML</h1></main>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Render to a stream
|
|
137
|
+
|
|
138
|
+
Use `renderStream()` when you want the raw `ReadableStream<string>` instead of a `Response`, for example to pipe it somewhere yourself, wrap it in your own `Response`, or transform it:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { html, renderStream } from "achi-html-stream";
|
|
142
|
+
|
|
143
|
+
const stream = renderStream(html`<h1>${"Hello"}</h1>`);
|
|
144
|
+
|
|
145
|
+
// Wrap it in your own Response
|
|
146
|
+
return new Response(stream.pipeThrough(new TextEncoderStream()), {
|
|
147
|
+
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Or read the chunks directly
|
|
151
|
+
for await (const chunk of stream) {
|
|
152
|
+
console.log(chunk);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Values and escaping
|
|
157
|
+
|
|
158
|
+
| Interpolated value | Handling |
|
|
159
|
+
| :------------------------- | :----------------------------------------------- |
|
|
160
|
+
| `string` | HTML-escaped (`&` `<` `>` `"` `'`) |
|
|
161
|
+
| `UnSafeHTML` | Inserted raw, unescaped |
|
|
162
|
+
| `number` | Inserted as-is |
|
|
163
|
+
| `Error` | Inserted as its string form (not escaped) |
|
|
164
|
+
| `Array` / iterable | Flattened; strings inside are escaped |
|
|
165
|
+
| `html` / `liveHTML` result | Inserted without being escaped twice |
|
|
166
|
+
| `Promise` | Awaited, then handled by these same rules |
|
|
167
|
+
| `Response` | Body streamed in as text (not escaped) |
|
|
168
|
+
| `Request` | Fetched, response body streamed in (not escaped) |
|
|
169
|
+
| `ReadableStream<string>` | Chunks piped in (not escaped) |
|
|
170
|
+
| `null` / `undefined` | Omitted |
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { html, renderAsString } from "achi-html-stream";
|
|
174
|
+
|
|
175
|
+
const unsafeText = '<script>alert("hello")</script>';
|
|
176
|
+
await renderAsString(html`<p>${unsafeText}</p>`);
|
|
177
|
+
// <p><script>alert("hello")</script></p>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Raw HTML with `UnSafeHTML`
|
|
181
|
+
|
|
182
|
+
For trusted or already-sanitized markup (SVG icons, sanitized Markdown):
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import { html, renderAsString, UnSafeHTML } from "achi-html-stream";
|
|
186
|
+
|
|
187
|
+
const icon = new UnSafeHTML(
|
|
188
|
+
'<svg aria-hidden="true" width="24" height="24">...</svg>',
|
|
189
|
+
);
|
|
190
|
+
const output = await renderAsString(html`<span>${icon}</span>`);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
> **Warning:** only pass trusted or previously sanitized content to `UnSafeHTML`.
|
|
194
|
+
|
|
195
|
+
## Streaming async data
|
|
196
|
+
|
|
197
|
+
Put promises and streams straight into a template. Everything before them is sent immediately, and each async part streams in when it is ready:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import { html, render } from "achi-html-stream/browser";
|
|
201
|
+
|
|
202
|
+
function userProfile(id: string) {
|
|
203
|
+
const user = fetch(`/api/users/${id}`).then((res) => res.json());
|
|
204
|
+
|
|
205
|
+
return render(html`
|
|
206
|
+
<div class="profile">
|
|
207
|
+
<!-- Sent immediately -->
|
|
208
|
+
<header><h1>User Profile</h1></header>
|
|
209
|
+
|
|
210
|
+
<!-- Streams in when the fetch resolves -->
|
|
211
|
+
<section><h2>${(async () => (await user).name)()}</h2></section>
|
|
212
|
+
|
|
213
|
+
<!-- Streams as chunks arrive from the network -->
|
|
214
|
+
<section class="activity">${fetch(`/api/users/${id}/activity`)}</section>
|
|
215
|
+
</div>
|
|
216
|
+
`);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
A raw `ReadableStream` must emit **strings**. If you have a byte stream (for example `response.body`), decode it first, or interpolate the `Response` itself:
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const text = response.body!.pipeThrough(new TextDecoderStream());
|
|
224
|
+
html`<section>${text}</section>`;
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## `html` vs `liveHTML`
|
|
228
|
+
|
|
229
|
+
- **`html`** (recommended): caches the compiled generator per template literal, so repeated renders with different values are fast.
|
|
230
|
+
- **`liveHTML`**: yields chunks directly on every call, with no compilation or caching. It works where dynamic code evaluation is blocked, and is useful for one-off templates or inspecting yielded chunks.
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { html, liveHTML, renderAsString } from "achi-html-stream";
|
|
234
|
+
|
|
235
|
+
const greeting = (name: string) => html`<p>Hello, ${name}!</p>`;
|
|
236
|
+
await renderAsString(greeting("Alice"));
|
|
237
|
+
await renderAsString(greeting("Bob"));
|
|
238
|
+
|
|
239
|
+
for (const chunk of liveHTML`<div>${"now"} ${Promise.resolve("later")}</div>`) {
|
|
240
|
+
// Send or process each chunk.
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## API reference
|
|
245
|
+
|
|
246
|
+
### Entry points
|
|
247
|
+
|
|
248
|
+
| Import | Targets |
|
|
249
|
+
| :------------------------- | :-------------------------------------------------------------------------------------------------- |
|
|
250
|
+
| `achi-html-stream` | Default. Resolves to Node.js, or to the browser build under `bun`, `deno` and `browser` conditions. |
|
|
251
|
+
| `achi-html-stream/browser` | Web Standards (`Response`, `ReadableStream`, `TextEncoderStream`). |
|
|
252
|
+
| `achi-html-stream/node` | Node.js (`http.ServerResponse`, `node:stream`). |
|
|
253
|
+
|
|
254
|
+
### `html(strings, ...values)`
|
|
255
|
+
|
|
256
|
+
Tagged template with cached generator compilation. Returns a generator of HTML chunks and deferred values.
|
|
257
|
+
|
|
258
|
+
### `liveHTML(strings, ...values)`
|
|
259
|
+
|
|
260
|
+
Tagged template generator without caching.
|
|
261
|
+
|
|
262
|
+
### `render(template, headers?, status?, statusText?)` (browser)
|
|
263
|
+
|
|
264
|
+
Returns a Web `Response` with a streaming UTF-8 body.
|
|
265
|
+
|
|
266
|
+
| Param | Default |
|
|
267
|
+
| :----------- | :------------------------------------------------------------------ |
|
|
268
|
+
| `template` | Generator from `html` or `liveHTML` |
|
|
269
|
+
| `headers` | `{ 'Content-Type': 'text/html; charset=utf-8' }`, merged with yours |
|
|
270
|
+
| `status` | `200` |
|
|
271
|
+
| `statusText` | `'OK'` |
|
|
272
|
+
|
|
273
|
+
### `render(response, template, headers?, status?, statusText?)` (Node.js)
|
|
274
|
+
|
|
275
|
+
Pipes the rendered output into a `http.ServerResponse`. Same defaults as above. Returns `void`.
|
|
276
|
+
|
|
277
|
+
### `renderStream(template)`
|
|
278
|
+
|
|
279
|
+
Returns `ReadableStream<string>` of rendered chunks.
|
|
280
|
+
|
|
281
|
+
### `renderAsString(template)`
|
|
282
|
+
|
|
283
|
+
Returns `Promise<string>` with the full rendered HTML.
|
|
284
|
+
|
|
285
|
+
### `new UnSafeHTML(rawHtml)`
|
|
286
|
+
|
|
287
|
+
Wraps a string so it bypasses escaping.
|
|
288
|
+
|
|
289
|
+
### `escapeHTML(value)`
|
|
290
|
+
|
|
291
|
+
Returns the string with `&`, `<`, `>`, `"` and `'` replaced by HTML entities.
|
|
292
|
+
|
|
293
|
+
## Security and caveats
|
|
294
|
+
|
|
295
|
+
- Escaping covers text content and **quoted** attribute values. Always quote attributes: `<a title="${title}">`.
|
|
296
|
+
- Escaping does not make URLs safe. Validate `href` and `src` values (for example, reject `javascript:`).
|
|
297
|
+
- Don't interpolate untrusted data inside `<script>` or `<style>`.
|
|
298
|
+
- `UnSafeHTML`, `Response`, `Request`, `ReadableStream` and `Error` values are **not** escaped. Keep untrusted input out of them.
|
|
299
|
+
- With `html`, each `${}` position should receive the same kind of value on every call (always a string, always an array, and so on), because the compiled template is cached. Use `liveHTML` if a position can change type.
|
|
300
|
+
ReadableStream must yield strings
|
|
301
|
+
|
|
302
|
+
## Editor support
|
|
303
|
+
|
|
304
|
+
Install the **[lit-plugin](https://marketplace.visualstudio.com/items?itemName=runem.lit-plugin)** extension for VS Code (by Rune Mehlsen, `runem.lit-plugin`). It recognizes the `html` tag and gives you HTML syntax highlighting, tag and attribute auto-completion, and diagnostics inside your templates in `.js` and `.ts` files.
|
|
305
|
+
|
|
306
|
+
lit-plugin is built for Lit, so Lit-specific features such as property and event bindings don't apply to achi-html-stream.
|
|
307
|
+
|
|
308
|
+
## Structuring components
|
|
309
|
+
|
|
310
|
+
Write components as functions that take a single props object and return an `html` template:
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
export function Header({ title }) {
|
|
314
|
+
return html`
|
|
315
|
+
<header>
|
|
316
|
+
<section>Home</section>
|
|
317
|
+
<section>${title}</section>
|
|
318
|
+
<section><a href="/about">about</a></section>
|
|
319
|
+
</header>
|
|
320
|
+
`;
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Compose them by calling them inside other templates:
|
|
325
|
+
|
|
326
|
+
```javascript
|
|
327
|
+
const page = html`
|
|
328
|
+
${Header({ title: "Welcome" })}
|
|
329
|
+
<main>...</main>
|
|
330
|
+
`;
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
This is better than positional arguments such as `Header(title, showNav, user)`:
|
|
334
|
+
|
|
335
|
+
- **Clearer call sites:** `Header({ title: 'Welcome' })` documents itself, and argument order never matters.
|
|
336
|
+
- **Easier to maintain:** adding or removing a prop doesn't break existing callers.
|
|
337
|
+
- **Simple defaults:** `function Header({ title = 'Untitled' })`.
|
|
338
|
+
- **Safe composition:** the returned template is inserted without being escaped twice, while string props are still escaped.
|
|
339
|
+
- **Examples:** check out the github repo for examples
|
|
340
|
+
|
|
341
|
+
## Runtime support
|
|
342
|
+
|
|
343
|
+
achi-html-stream relies on Web Streams (`ReadableStream`, `TextEncoderStream`, `TextDecoderStream`), the global `Response`, and ES2021 syntax, so it needs these minimum versions:
|
|
344
|
+
|
|
345
|
+
| Runtime | Minimum version | Import from |
|
|
346
|
+
| :----------------- | :--------------------------------- | :----------------------------------------------- |
|
|
347
|
+
| Node.js | 18+ | `achi-html-stream` or `achi-html-stream/node` |
|
|
348
|
+
| Bun | 1.x | `achi-html-stream` or `achi-html-stream/browser` |
|
|
349
|
+
| Deno | Current releases | `achi-html-stream` or `achi-html-stream/browser` |
|
|
350
|
+
| Chrome / Edge | 85+ | `achi-html-stream` |
|
|
351
|
+
| Firefox | 105+ | `achi-html-stream` |
|
|
352
|
+
| Safari | 14.1+ | `achi-html-stream` |
|
|
353
|
+
| Service workers | Same as the browser versions above | `achi-html-stream` |
|
|
354
|
+
| Cloudflare Workers | Current runtime, using `liveHTML` | `achi-html-stream` |
|
|
355
|
+
|
|
356
|
+
Notes:
|
|
357
|
+
|
|
358
|
+
- **Firefox 105** is the floor because earlier versions lack `TextEncoderStream` and `TextDecoderStream`.
|
|
359
|
+
- **Node.js** versions before 18 don't provide the global Web Streams and `Response` APIs. Use an actively supported LTS release.
|
|
360
|
+
- **Dynamic code evaluation:** `html` compiles templates at runtime. In environments that block it, such as Cloudflare Workers or pages with a strict CSP, use `liveHTML` instead.
|
|
361
|
+
- **Older browsers:** transpile the package and polyfill Web Streams, or render on the server.
|
|
362
|
+
|
|
363
|
+
To enforce the Node requirement, add this to `package.json`:
|
|
364
|
+
|
|
365
|
+
```json
|
|
366
|
+
"engines": {
|
|
367
|
+
"node": ">=18"
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Development
|
|
372
|
+
|
|
373
|
+
```bash
|
|
374
|
+
pnpm install # install dependencies
|
|
375
|
+
pnpm test # run unit tests (Vitest)
|
|
376
|
+
pnpm typecheck # type-check
|
|
377
|
+
pnpm build # build ESM, CJS and IIFE bundles
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
## License
|
|
381
|
+
|
|
382
|
+
[MIT](LICENSE) © [Kimbugwe Mark](mailto:markkimbugwe@gmail.com)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region src/html/cachehtml.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A function that renders an HTML template with caching capabilities. It checks if a compiled template function already exists in the cache for the given templates. If it does, it calls the cached function with the provided values and returns the result. If not, it compiles a new template function using the compileTemplate function, stores it in the cache, and then calls it with the provided values. This allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.
|
|
4
|
+
*
|
|
5
|
+
* @param {String[]} templates
|
|
6
|
+
* @param {...(String|UnSafeHTML|Error|number|Array|Iterable)} values
|
|
7
|
+
* @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.
|
|
8
|
+
*/
|
|
9
|
+
declare function cachableHTML(templates: TemplateStringsArray, ...values: TemplateValues[]): any;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/html/livehtml.d.ts
|
|
12
|
+
/**
|
|
13
|
+
* A generator function that processes an HTML template without caching. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.
|
|
14
|
+
*
|
|
15
|
+
* @export
|
|
16
|
+
* @param {String[]} templates
|
|
17
|
+
* @param {...TemplateValues} values
|
|
18
|
+
* @returns {Generator} A generator that yields processed HTML content as a stream.
|
|
19
|
+
*/
|
|
20
|
+
declare function liveHTML(templates: TemplateStringsArray, ...values: TemplateValues[]): Generator<any, void, any>;
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/utils/UnSafeHTML.d.ts
|
|
23
|
+
declare class UnSafeHTML {
|
|
24
|
+
html: string;
|
|
25
|
+
/**
|
|
26
|
+
* Creates unsafe html that will not be escaped
|
|
27
|
+
*
|
|
28
|
+
* @param {string} html - string containing unsafe html
|
|
29
|
+
*/
|
|
30
|
+
constructor(html: string);
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/html/html.d.ts
|
|
34
|
+
/**
|
|
35
|
+
* A function that renders an HTML template generator and returns a ReadableStream that yields the resulting HTML as a stream. It uses the processHTML generator function to process the template and handle various types of values, including promises and streams, while ensuring that string values are properly escaped to prevent XSS vulnerabilities.
|
|
36
|
+
*
|
|
37
|
+
* @param {Generator} generator - The HTML template generator to render.
|
|
38
|
+
* @returns {ReadableStream} A ReadableStream that yields the resulting HTML as a stream.
|
|
39
|
+
*/
|
|
40
|
+
declare function renderStream(generator: Generator): import("node:stream/web").ReadableStream<string>;
|
|
41
|
+
/**
|
|
42
|
+
* renders an HTML template generator and returns a promise that resolves to the resulting HTML as a string.
|
|
43
|
+
*
|
|
44
|
+
* @async
|
|
45
|
+
* @param {Generator} generator
|
|
46
|
+
* @returns {Promise<string>} A promise that resolves to the resulting HTML as a string.
|
|
47
|
+
*/
|
|
48
|
+
declare function renderAsString(generator: Generator): Promise<string>;
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/utils/escapehtml.d.ts
|
|
51
|
+
/**
|
|
52
|
+
* Escapes HTML special characters in a string to prevent XSS attacks and ensure proper rendering in HTML.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} str - The string to escape
|
|
55
|
+
*
|
|
56
|
+
* @returns {string} - The escaped string
|
|
57
|
+
*/
|
|
58
|
+
declare function escapeHTML(str: string): string;
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/index.browser.d.ts
|
|
61
|
+
/**
|
|
62
|
+
* Renders an HTML template and sends it as a response
|
|
63
|
+
*
|
|
64
|
+
* @param {HTMLTemplate} template - HTML template to render
|
|
65
|
+
* @param {{}} [headers={}] - Headers to send with the response
|
|
66
|
+
* @param {number} [status=200] - HTTP status code
|
|
67
|
+
* @param {string} [statusText='OK'] - HTTP status text
|
|
68
|
+
* @returns {Response} - The rendered HTML response
|
|
69
|
+
*/
|
|
70
|
+
declare function render(template: Generator, headers?: {}, status?: number, statusText?: string): Response;
|
|
71
|
+
//#endregion
|
|
72
|
+
export { UnSafeHTML, escapeHTML, cachableHTML as html, liveHTML, render, renderAsString, renderStream };
|
|
73
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var achiHTML=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});function t(e){return String(e).replace(/[&<>"']/g,e=>{switch(e){case`&`:return`&`;case`<`:return`<`;case`>`:return`>`;case`"`:return`"`;case`'`:return`'`;default:return e}})}function n(e){let n=e.length;for(;n--;){let r=e[n];typeof r==`string`&&(e[n]=t(r))}return e}var r=class{html;constructor(e){this.html=e}};let i=function*(){}.constructor,a=new WeakMap;function o(e,t){let n=`yield \`${e[0]}\``,i=t.length;for(let a=0;a<i;a++){let i=t[a];typeof i==`string`?n+=`+escapeHTML(args[${a}])+\`${e[a+1]}\``:i instanceof r?n+=`+args[${a}].html+\`${e[a+1]}\``:i instanceof Error||typeof i==`number`?n+=`+args[${a}]+\`${e[a+1]}\``:Array.isArray(i)?n+=`; yield * sanitizeArray(args[${a}]); yield \`${e[a+1]}\``:i?.[Symbol.iterator]?n+=`; yield * args[${a}]; yield \`${e[a+1]}\``:n+=`; yield args[${a}]; yield \`${e[a+1]}\``}return n}function s(e,t){let n=o(e,t);return new i(`escapeHTML`,`sanitizeArray`,`args`,n)}function c(e,...r){let i=a.get(e);return i?i(t,n,r):(i=s(e,r),a.set(e,i),i(t,n,r))}function*l(e,...i){let a=e[0],o=i.length;for(let s=0;s<o;s++){let o=i[s];typeof o==`string`?a+=t(o):o instanceof r?a+=o.html:o instanceof Error||typeof o==`number`?a+=o:Array.isArray(o)?(a&&=(yield a,``),yield*n(o)):o?.[Symbol.iterator]?(a&&=(yield a,``),yield*o):yield o,a+=e[s+1]}a&&=(yield a,``)}async function u(e){try{return await e}catch(e){return e instanceof Promise?u(e):e}}async function d(e,t){let n=e.getReader();try{for(;;){let e=await n.read();if(e.done)return;t.enqueue(e.value)}}catch(e){t.enqueue(e)}finally{n.releaseLock()}}function*f(e,i){let a=``;for(let o of e)if(typeof o==`string`)a+=o;else if(o instanceof r)a+=o.html;else if(o instanceof Error||typeof o==`number`)a+=o;else if(o instanceof Promise){a&&=(i.enqueue(a),``);let e=yield o;if(typeof e==`string`)a+=t(e);else if(e instanceof r)a+=e.html;else if(e instanceof Error||typeof e==`number`)a+=e;else if(Array.isArray(e))a&&=(i.enqueue(a),``),yield*f(n(e),i);else if(e?.[Symbol.iterator])a&&=(i.enqueue(a),``),yield*f(e,i);else if(e==null)continue;else a&&=(i.enqueue(a),``),yield e}else if(Array.isArray(o))a&&=(i.enqueue(a),``),yield*f(n(o),i);else if(o?.[Symbol.iterator])a&&=(i.enqueue(a),``),yield*f(o,i);else if(o==null)continue;else a&&=(i.enqueue(a),``),yield o;a&&=(i.enqueue(a),``)}function p(e){return new ReadableStream({start(t){let n=f(e,t);return r(n);async function r(e=void 0){let i=n.next(e);try{if(i.value instanceof Promise)return r(await u(i.value));if(i.value instanceof Response)return await d(i.value.body.pipeThrough(new TextDecoderStream),t),r();if(i.value instanceof ReadableStream)return await d(i.value,t),r();if(i.value instanceof Request){let e=(await fetch(i.value)).body;return e&&await d(e.pipeThrough(new TextDecoderStream),t),r()}}catch(e){return t.enqueue(e),r()}t.close()}}})}async function m(e){try{let t=p(e).getReader(),n=``;for(;;){let e=await t.read();if(e.done){t.releaseLock();break}n+=e.value}return n}catch(e){throw e}}function h(e,t={},n=200,r=`OK`){let i=Object.assign({"Content-Type":`text/html; charset=utf-8`},t);return new Response(p(e).pipeThrough(new TextEncoderStream),{headers:i,status:n,statusText:r})}return e.UnSafeHTML=r,e.escapeHTML=t,e.html=c,e.liveHTML=l,e.render=h,e.renderAsString=m,e.renderStream=p,e})({});
|
|
2
|
+
//# sourceMappingURL=index.iife.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.iife.js","names":[],"sources":["../../src/utils/escapehtml.ts","../../src/utils/sanitizeArray.ts","../../src/utils/UnSafeHTML.ts","../../src/html/cachehtml.ts","../../src/html/livehtml.ts","../../src/utils/promisedValue.ts","../../src/utils/streamHTML.ts","../../src/html/html.ts","../../src/index.browser.ts"],"sourcesContent":["/**\n * Escapes HTML special characters in a string to prevent XSS attacks and ensure proper rendering in HTML.\n *\n * @param {string} str - The string to escape\n *\n * @returns {string} - The escaped string\n */\nexport function escapeHTML(str: string): string {\n return String(str).replace(/[&<>\"']/g, (char: string) => {\n switch (char) {\n case \"&\":\n return \"&\";\n case \"<\":\n return \"<\";\n case \">\":\n return \">\";\n case '\"':\n return \""\";\n case \"'\":\n return \"'\";\n default:\n return char;\n }\n });\n}\n","import { escapeHTML } from \"./escapehtml\";\n\nexport function sanitizeArray(values: any[]): any[] {\n let index = values.length;\n while (index--) {\n let value = values[index];\n if (typeof value == \"string\") {\n values[index] = escapeHTML(value);\n }\n }\n return values;\n}\n","export class UnSafeHTML {\n public html: string;\n /**\n * Creates unsafe html that will not be escaped\n *\n * @param {string} html - string containing unsafe html\n */\n constructor(html: string) {\n this.html = html;\n }\n}\n","import { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\nimport { UnSafeHTML } from \"../utils/UnSafeHTML\";\n\ntype GeneratorFunctionConstructor = new (\n ...args: string[]\n) => (...args: any[]) => Generator<any, any, any>;\nconst TemplateConstructor = function* () {}\n .constructor as GeneratorFunctionConstructor,\n templateCache = new WeakMap();\n\n/**\n * A function that generates the source code for a compiled HTML template function.\n *\n * @param {String[]} templates\n * @param {Array} values\n * @returns {string} source code of the compiled template function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction generateTemplateSourceCode(\n templates: TemplateStringsArray,\n values: TemplateValues[],\n): string {\n let sourceCode = `yield \\`${templates[0]}\\``,\n length = values.length;\n for (let index = 0; index < length; index++) {\n let value = values[index];\n if (typeof value == \"string\") {\n sourceCode += `+escapeHTML(args[${index}])+\\`${templates[index + 1]}\\``;\n } else if (value instanceof UnSafeHTML) {\n sourceCode += `+args[${index}].html+\\`${templates[index + 1]}\\``;\n } else if (value instanceof Error || typeof value == \"number\") {\n sourceCode += `+args[${index}]+\\`${templates[index + 1]}\\``;\n } else if (Array.isArray(value)) {\n sourceCode += `; yield * sanitizeArray(args[${index}]); yield \\`${templates[index + 1]}\\``;\n } else if ((value as any)?.[Symbol.iterator]) {\n sourceCode += `; yield * args[${index}]; yield \\`${templates[index + 1]}\\``;\n } else {\n sourceCode += `; yield args[${index}]; yield \\`${templates[index + 1]}\\``;\n }\n }\n return sourceCode;\n}\n/**\n * compiles an HTML template into a function that can be cached and reused with different values. It generates source code for the template by processing the provided templates and values, handling various types of values such as strings, UnSafeHTML instances, errors, numbers, arrays, and iterables. The generated source code is then used to create a new function using the TemplateConstructor, which can be called with the appropriate arguments to produce the final HTML output. This approach allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {String[]} templates\n * @param {Array} values\n * @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction compileTemplate(\n templates: TemplateStringsArray,\n values: TemplateValues[],\n) {\n let sourceCode = generateTemplateSourceCode(templates, values);\n return new TemplateConstructor(\n \"escapeHTML\",\n \"sanitizeArray\",\n \"args\",\n sourceCode,\n );\n}\n/**\n * A function that renders an HTML template with caching capabilities. It checks if a compiled template function already exists in the cache for the given templates. If it does, it calls the cached function with the provided values and returns the result. If not, it compiles a new template function using the compileTemplate function, stores it in the cache, and then calls it with the provided values. This allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {String[]} templates\n * @param {...(String|UnSafeHTML|Error|number|Array|Iterable)} values\n * @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction cachableHTML(\n templates: TemplateStringsArray,\n ...values: TemplateValues[]\n) {\n let template = templateCache.get(templates);\n if (template) {\n return template(escapeHTML, sanitizeArray, values);\n }\n template = compileTemplate(templates, values);\n templateCache.set(templates, template);\n return template(escapeHTML, sanitizeArray, values);\n}\n\nexport { cachableHTML };\n","import { UnSafeHTML } from \"../utils/UnSafeHTML\";\nimport { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\n\n/**\n * A generator function that processes an HTML template without caching. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.\n *\n * @export\n * @param {String[]} templates\n * @param {...TemplateValues} values\n * @returns {Generator} A generator that yields processed HTML content as a stream.\n */\nexport function* liveHTML(\n templates: TemplateStringsArray,\n ...values: TemplateValues[]\n) {\n let cache = templates[0],\n length = values.length;\n for (let index = 0; index < length; index++) {\n let value = values[index];\n if (typeof value == \"string\") {\n cache += escapeHTML(value);\n } else if (value instanceof UnSafeHTML) {\n cache += value.html;\n } else if (value instanceof Error || typeof value == \"number\") {\n cache += value;\n } else if (Array.isArray(value)) {\n if (cache) {\n yield cache;\n cache = \"\";\n }\n yield* sanitizeArray(value);\n } else if ((value as any)?.[Symbol.iterator]) {\n if (cache) {\n yield cache;\n cache = \"\";\n }\n yield* value as Generator;\n } else {\n yield value;\n }\n cache += templates[index + 1];\n }\n if (cache) {\n yield cache;\n cache = \"\";\n }\n}\n","export async function promisedValue(value: Promise<any>): Promise<any> {\n try {\n return await value;\n } catch (error) {\n if (error instanceof Promise) {\n return promisedValue(error);\n } else {\n return error;\n }\n }\n}\n","export async function streamHTML(\n readable: ReadableStream<string>,\n controller: ReadableStreamDefaultController,\n) {\n const stream: ReadableStreamDefaultReader = readable.getReader();\n try {\n while (true) {\n let data = await stream.read();\n if (data.done) {\n return;\n }\n controller.enqueue(data.value);\n }\n } catch (error) {\n controller.enqueue(error);\n } finally {\n stream.releaseLock();\n }\n}\n","import { UnSafeHTML } from \"../utils/UnSafeHTML\";\nimport { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\nimport { promisedValue } from \"../utils/promisedValue\";\nimport { streamHTML } from \"../utils/streamHTML\";\n\n/**\n * A generator function that processes an HTML template with embedded values and yields the resulting HTML as a stream. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.\n *\n * @param {Generator} templateGenerator\n * @param {ReadableStreamDefaultController} controller\n * @returns {IterableIterator<string>} An iterator that yields the resulting HTML as a stream.\n */\nfunction* processHTML(\n templateGenerator: Generator | Array<TemplateValues>,\n controller: ReadableStreamDefaultController<string>,\n): any {\n let cache: string = \"\";\n for (const value of templateGenerator) {\n if (typeof value == \"string\") {\n cache += value;\n } else if (value instanceof UnSafeHTML) {\n cache += value.html;\n } else if (value instanceof Error || typeof value == \"number\") {\n cache += value;\n } else if (value instanceof Promise) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValue = yield value;\n if (typeof resolvedValue == \"string\") {\n cache += escapeHTML(resolvedValue);\n } else if (resolvedValue instanceof UnSafeHTML) {\n cache += resolvedValue.html;\n } else if (\n resolvedValue instanceof Error ||\n typeof resolvedValue == \"number\"\n ) {\n cache += resolvedValue;\n } else if (Array.isArray(resolvedValue)) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(sanitizeArray(resolvedValue), controller);\n } else if (resolvedValue?.[Symbol.iterator]) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(resolvedValue, controller);\n } else if (resolvedValue == undefined) {\n continue;\n } else {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValues = yield resolvedValue;\n void resolvedValues\n }\n } else if (Array.isArray(value)) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(sanitizeArray(value), controller);\n } else if (value?.[Symbol.iterator]) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(value, controller);\n } else if (value == undefined) {\n continue;\n } else {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValue = yield value;\n void resolvedValue\n }\n }\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n}\n\n/**\n * A function that renders an HTML template generator and returns a ReadableStream that yields the resulting HTML as a stream. It uses the processHTML generator function to process the template and handle various types of values, including promises and streams, while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {Generator} generator - The HTML template generator to render.\n * @returns {ReadableStream} A ReadableStream that yields the resulting HTML as a stream.\n */\nfunction renderStream(generator: Generator) {\n return new ReadableStream<string>({\n start(controller) {\n let templateGenerator = processHTML(generator, controller);\n return startHTMLStream(templateGenerator);\n async function startHTMLStream(\n value:\n | undefined\n | Promise<any>\n | Request\n | ReadableStream\n | Response = undefined,\n ) {\n let data = templateGenerator.next(value);\n try {\n if (data.value instanceof Promise) {\n let resolvedValue = await promisedValue(data.value);\n return startHTMLStream(resolvedValue);\n } else if (data.value instanceof Response) {\n await streamHTML(data.value.body.pipeThrough(new TextDecoderStream()), controller);\n return startHTMLStream();\n } else if (data.value instanceof ReadableStream) {\n await streamHTML(data.value, controller);\n return startHTMLStream();\n } else if (data.value instanceof Request) {\n let response:Response = await fetch(data.value),\n stream = response.body;\n if (stream) {\n await streamHTML(stream.pipeThrough(new TextDecoderStream()), controller);\n }\n return startHTMLStream();\n }\n } catch (error) {\n controller.enqueue(error as string);\n return startHTMLStream();\n }\n controller.close();\n }\n },\n });\n}\n/**\n * renders an HTML template generator and returns a promise that resolves to the resulting HTML as a string.\n *\n * @async\n * @param {Generator} generator\n * @returns {Promise<string>} A promise that resolves to the resulting HTML as a string.\n */\nasync function renderAsString(generator: Generator): Promise<string> {\n try {\n let readable = renderStream(generator).getReader(),\n html = \"\";\n while (true) {\n let data = await readable.read();\n if (data.done) {\n readable.releaseLock();\n break;\n }\n html += data.value;\n }\n return html;\n } catch (error) {\n throw error;\n }\n}\nexport { renderStream, renderAsString };\n","import { cachableHTML } from \"./html/cachehtml\";\nimport { liveHTML } from \"./html/livehtml\";\nimport { UnSafeHTML } from \"./utils/UnSafeHTML\";\nimport { renderStream, renderAsString } from \"./html/html\";\nimport { escapeHTML } from \"./utils/escapehtml\";\n\n/**\n * Renders an HTML template and sends it as a response\n *\n * @param {HTMLTemplate} template - HTML template to render\n * @param {{}} [headers={}] - Headers to send with the response\n * @param {number} [status=200] - HTTP status code\n * @param {string} [statusText='OK'] - HTTP status text\n * @returns {Response} - The rendered HTML response\n */\nfunction render(\n template: Generator,\n headers = {},\n status = 200,\n statusText = \"OK\",\n): Response {\n let responseHeaders = Object.assign(\n { \"Content-Type\": \"text/html; charset=utf-8\" },\n headers,\n );\n return new Response(\n renderStream(template).pipeThrough(new TextEncoderStream()),\n { headers: responseHeaders, status, statusText },\n );\n}\nexport {\n render,\n renderAsString,\n renderStream,\n liveHTML,\n cachableHTML as html,\n UnSafeHTML,\n escapeHTML,\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function e(e){return String(e).replace(/[&<>"']/g,e=>{switch(e){case`&`:return`&`;case`<`:return`<`;case`>`:return`>`;case`"`:return`"`;case`'`:return`'`;default:return e}})}function t(t){let n=t.length;for(;n--;){let r=t[n];typeof r==`string`&&(t[n]=e(r))}return t}var n=class{html;constructor(e){this.html=e}};const r=function*(){}.constructor,i=new WeakMap;function a(e,t){let r=`yield \`${e[0]}\``,i=t.length;for(let a=0;a<i;a++){let i=t[a];typeof i==`string`?r+=`+escapeHTML(args[${a}])+\`${e[a+1]}\``:i instanceof n?r+=`+args[${a}].html+\`${e[a+1]}\``:i instanceof Error||typeof i==`number`?r+=`+args[${a}]+\`${e[a+1]}\``:Array.isArray(i)?r+=`; yield * sanitizeArray(args[${a}]); yield \`${e[a+1]}\``:i?.[Symbol.iterator]?r+=`; yield * args[${a}]; yield \`${e[a+1]}\``:r+=`; yield args[${a}]; yield \`${e[a+1]}\``}return r}function o(e,t){let n=a(e,t);return new r(`escapeHTML`,`sanitizeArray`,`args`,n)}function s(n,...r){let a=i.get(n);return a?a(e,t,r):(a=o(n,r),i.set(n,a),a(e,t,r))}function*c(r,...i){let a=r[0],o=i.length;for(let s=0;s<o;s++){let o=i[s];typeof o==`string`?a+=e(o):o instanceof n?a+=o.html:o instanceof Error||typeof o==`number`?a+=o:Array.isArray(o)?(a&&=(yield a,``),yield*t(o)):o?.[Symbol.iterator]?(a&&=(yield a,``),yield*o):yield o,a+=r[s+1]}a&&=(yield a,``)}async function l(e){try{return await e}catch(e){return e instanceof Promise?l(e):e}}async function u(e,t){let n=e.getReader();try{for(;;){let e=await n.read();if(e.done)return;t.enqueue(e.value)}}catch(e){t.enqueue(e)}finally{n.releaseLock()}}function*d(r,i){let a=``;for(let o of r)if(typeof o==`string`)a+=o;else if(o instanceof n)a+=o.html;else if(o instanceof Error||typeof o==`number`)a+=o;else if(o instanceof Promise){a&&=(i.enqueue(a),``);let r=yield o;if(typeof r==`string`)a+=e(r);else if(r instanceof n)a+=r.html;else if(r instanceof Error||typeof r==`number`)a+=r;else if(Array.isArray(r))a&&=(i.enqueue(a),``),yield*d(t(r),i);else if(r?.[Symbol.iterator])a&&=(i.enqueue(a),``),yield*d(r,i);else if(r==null)continue;else a&&=(i.enqueue(a),``),yield r}else if(Array.isArray(o))a&&=(i.enqueue(a),``),yield*d(t(o),i);else if(o?.[Symbol.iterator])a&&=(i.enqueue(a),``),yield*d(o,i);else if(o==null)continue;else a&&=(i.enqueue(a),``),yield o;a&&=(i.enqueue(a),``)}function f(e){return new ReadableStream({start(t){let n=d(e,t);return r(n);async function r(e=void 0){let i=n.next(e);try{if(i.value instanceof Promise)return r(await l(i.value));if(i.value instanceof Response)return await u(i.value.body.pipeThrough(new TextDecoderStream),t),r();if(i.value instanceof ReadableStream)return await u(i.value,t),r();if(i.value instanceof Request){let e=(await fetch(i.value)).body;return e&&await u(e.pipeThrough(new TextDecoderStream),t),r()}}catch(e){return t.enqueue(e),r()}t.close()}}})}async function p(e){try{let t=f(e).getReader(),n=``;for(;;){let e=await t.read();if(e.done){t.releaseLock();break}n+=e.value}return n}catch(e){throw e}}function m(e,t={},n=200,r=`OK`){let i=Object.assign({"Content-Type":`text/html; charset=utf-8`},t);return new Response(f(e).pipeThrough(new TextEncoderStream),{headers:i,status:n,statusText:r})}export{n as UnSafeHTML,e as escapeHTML,s as html,c as liveHTML,m as render,p as renderAsString,f as renderStream};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/utils/escapehtml.ts","../../src/utils/sanitizeArray.ts","../../src/utils/UnSafeHTML.ts","../../src/html/cachehtml.ts","../../src/html/livehtml.ts","../../src/utils/promisedValue.ts","../../src/utils/streamHTML.ts","../../src/html/html.ts","../../src/index.browser.ts"],"sourcesContent":["/**\n * Escapes HTML special characters in a string to prevent XSS attacks and ensure proper rendering in HTML.\n *\n * @param {string} str - The string to escape\n *\n * @returns {string} - The escaped string\n */\nexport function escapeHTML(str: string): string {\n return String(str).replace(/[&<>\"']/g, (char: string) => {\n switch (char) {\n case \"&\":\n return \"&\";\n case \"<\":\n return \"<\";\n case \">\":\n return \">\";\n case '\"':\n return \""\";\n case \"'\":\n return \"'\";\n default:\n return char;\n }\n });\n}\n","import { escapeHTML } from \"./escapehtml\";\n\nexport function sanitizeArray(values: any[]): any[] {\n let index = values.length;\n while (index--) {\n let value = values[index];\n if (typeof value == \"string\") {\n values[index] = escapeHTML(value);\n }\n }\n return values;\n}\n","export class UnSafeHTML {\n public html: string;\n /**\n * Creates unsafe html that will not be escaped\n *\n * @param {string} html - string containing unsafe html\n */\n constructor(html: string) {\n this.html = html;\n }\n}\n","import { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\nimport { UnSafeHTML } from \"../utils/UnSafeHTML\";\n\ntype GeneratorFunctionConstructor = new (\n ...args: string[]\n) => (...args: any[]) => Generator<any, any, any>;\nconst TemplateConstructor = function* () {}\n .constructor as GeneratorFunctionConstructor,\n templateCache = new WeakMap();\n\n/**\n * A function that generates the source code for a compiled HTML template function.\n *\n * @param {String[]} templates\n * @param {Array} values\n * @returns {string} source code of the compiled template function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction generateTemplateSourceCode(\n templates: TemplateStringsArray,\n values: TemplateValues[],\n): string {\n let sourceCode = `yield \\`${templates[0]}\\``,\n length = values.length;\n for (let index = 0; index < length; index++) {\n let value = values[index];\n if (typeof value == \"string\") {\n sourceCode += `+escapeHTML(args[${index}])+\\`${templates[index + 1]}\\``;\n } else if (value instanceof UnSafeHTML) {\n sourceCode += `+args[${index}].html+\\`${templates[index + 1]}\\``;\n } else if (value instanceof Error || typeof value == \"number\") {\n sourceCode += `+args[${index}]+\\`${templates[index + 1]}\\``;\n } else if (Array.isArray(value)) {\n sourceCode += `; yield * sanitizeArray(args[${index}]); yield \\`${templates[index + 1]}\\``;\n } else if ((value as any)?.[Symbol.iterator]) {\n sourceCode += `; yield * args[${index}]; yield \\`${templates[index + 1]}\\``;\n } else {\n sourceCode += `; yield args[${index}]; yield \\`${templates[index + 1]}\\``;\n }\n }\n return sourceCode;\n}\n/**\n * compiles an HTML template into a function that can be cached and reused with different values. It generates source code for the template by processing the provided templates and values, handling various types of values such as strings, UnSafeHTML instances, errors, numbers, arrays, and iterables. The generated source code is then used to create a new function using the TemplateConstructor, which can be called with the appropriate arguments to produce the final HTML output. This approach allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {String[]} templates\n * @param {Array} values\n * @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction compileTemplate(\n templates: TemplateStringsArray,\n values: TemplateValues[],\n) {\n let sourceCode = generateTemplateSourceCode(templates, values);\n return new TemplateConstructor(\n \"escapeHTML\",\n \"sanitizeArray\",\n \"args\",\n sourceCode,\n );\n}\n/**\n * A function that renders an HTML template with caching capabilities. It checks if a compiled template function already exists in the cache for the given templates. If it does, it calls the cached function with the provided values and returns the result. If not, it compiles a new template function using the compileTemplate function, stores it in the cache, and then calls it with the provided values. This allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {String[]} templates\n * @param {...(String|UnSafeHTML|Error|number|Array|Iterable)} values\n * @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction cachableHTML(\n templates: TemplateStringsArray,\n ...values: TemplateValues[]\n) {\n let template = templateCache.get(templates);\n if (template) {\n return template(escapeHTML, sanitizeArray, values);\n }\n template = compileTemplate(templates, values);\n templateCache.set(templates, template);\n return template(escapeHTML, sanitizeArray, values);\n}\n\nexport { cachableHTML };\n","import { UnSafeHTML } from \"../utils/UnSafeHTML\";\nimport { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\n\n/**\n * A generator function that processes an HTML template without caching. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.\n *\n * @export\n * @param {String[]} templates\n * @param {...TemplateValues} values\n * @returns {Generator} A generator that yields processed HTML content as a stream.\n */\nexport function* liveHTML(\n templates: TemplateStringsArray,\n ...values: TemplateValues[]\n) {\n let cache = templates[0],\n length = values.length;\n for (let index = 0; index < length; index++) {\n let value = values[index];\n if (typeof value == \"string\") {\n cache += escapeHTML(value);\n } else if (value instanceof UnSafeHTML) {\n cache += value.html;\n } else if (value instanceof Error || typeof value == \"number\") {\n cache += value;\n } else if (Array.isArray(value)) {\n if (cache) {\n yield cache;\n cache = \"\";\n }\n yield* sanitizeArray(value);\n } else if ((value as any)?.[Symbol.iterator]) {\n if (cache) {\n yield cache;\n cache = \"\";\n }\n yield* value as Generator;\n } else {\n yield value;\n }\n cache += templates[index + 1];\n }\n if (cache) {\n yield cache;\n cache = \"\";\n }\n}\n","export async function promisedValue(value: Promise<any>): Promise<any> {\n try {\n return await value;\n } catch (error) {\n if (error instanceof Promise) {\n return promisedValue(error);\n } else {\n return error;\n }\n }\n}\n","export async function streamHTML(\n readable: ReadableStream<string>,\n controller: ReadableStreamDefaultController,\n) {\n const stream: ReadableStreamDefaultReader = readable.getReader();\n try {\n while (true) {\n let data = await stream.read();\n if (data.done) {\n return;\n }\n controller.enqueue(data.value);\n }\n } catch (error) {\n controller.enqueue(error);\n } finally {\n stream.releaseLock();\n }\n}\n","import { UnSafeHTML } from \"../utils/UnSafeHTML\";\nimport { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\nimport { promisedValue } from \"../utils/promisedValue\";\nimport { streamHTML } from \"../utils/streamHTML\";\n\n/**\n * A generator function that processes an HTML template with embedded values and yields the resulting HTML as a stream. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.\n *\n * @param {Generator} templateGenerator\n * @param {ReadableStreamDefaultController} controller\n * @returns {IterableIterator<string>} An iterator that yields the resulting HTML as a stream.\n */\nfunction* processHTML(\n templateGenerator: Generator | Array<TemplateValues>,\n controller: ReadableStreamDefaultController<string>,\n): any {\n let cache: string = \"\";\n for (const value of templateGenerator) {\n if (typeof value == \"string\") {\n cache += value;\n } else if (value instanceof UnSafeHTML) {\n cache += value.html;\n } else if (value instanceof Error || typeof value == \"number\") {\n cache += value;\n } else if (value instanceof Promise) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValue = yield value;\n if (typeof resolvedValue == \"string\") {\n cache += escapeHTML(resolvedValue);\n } else if (resolvedValue instanceof UnSafeHTML) {\n cache += resolvedValue.html;\n } else if (\n resolvedValue instanceof Error ||\n typeof resolvedValue == \"number\"\n ) {\n cache += resolvedValue;\n } else if (Array.isArray(resolvedValue)) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(sanitizeArray(resolvedValue), controller);\n } else if (resolvedValue?.[Symbol.iterator]) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(resolvedValue, controller);\n } else if (resolvedValue == undefined) {\n continue;\n } else {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValues = yield resolvedValue;\n void resolvedValues\n }\n } else if (Array.isArray(value)) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(sanitizeArray(value), controller);\n } else if (value?.[Symbol.iterator]) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(value, controller);\n } else if (value == undefined) {\n continue;\n } else {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValue = yield value;\n void resolvedValue\n }\n }\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n}\n\n/**\n * A function that renders an HTML template generator and returns a ReadableStream that yields the resulting HTML as a stream. It uses the processHTML generator function to process the template and handle various types of values, including promises and streams, while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {Generator} generator - The HTML template generator to render.\n * @returns {ReadableStream} A ReadableStream that yields the resulting HTML as a stream.\n */\nfunction renderStream(generator: Generator) {\n return new ReadableStream<string>({\n start(controller) {\n let templateGenerator = processHTML(generator, controller);\n return startHTMLStream(templateGenerator);\n async function startHTMLStream(\n value:\n | undefined\n | Promise<any>\n | Request\n | ReadableStream\n | Response = undefined,\n ) {\n let data = templateGenerator.next(value);\n try {\n if (data.value instanceof Promise) {\n let resolvedValue = await promisedValue(data.value);\n return startHTMLStream(resolvedValue);\n } else if (data.value instanceof Response) {\n await streamHTML(data.value.body.pipeThrough(new TextDecoderStream()), controller);\n return startHTMLStream();\n } else if (data.value instanceof ReadableStream) {\n await streamHTML(data.value, controller);\n return startHTMLStream();\n } else if (data.value instanceof Request) {\n let response:Response = await fetch(data.value),\n stream = response.body;\n if (stream) {\n await streamHTML(stream.pipeThrough(new TextDecoderStream()), controller);\n }\n return startHTMLStream();\n }\n } catch (error) {\n controller.enqueue(error as string);\n return startHTMLStream();\n }\n controller.close();\n }\n },\n });\n}\n/**\n * renders an HTML template generator and returns a promise that resolves to the resulting HTML as a string.\n *\n * @async\n * @param {Generator} generator\n * @returns {Promise<string>} A promise that resolves to the resulting HTML as a string.\n */\nasync function renderAsString(generator: Generator): Promise<string> {\n try {\n let readable = renderStream(generator).getReader(),\n html = \"\";\n while (true) {\n let data = await readable.read();\n if (data.done) {\n readable.releaseLock();\n break;\n }\n html += data.value;\n }\n return html;\n } catch (error) {\n throw error;\n }\n}\nexport { renderStream, renderAsString };\n","import { cachableHTML } from \"./html/cachehtml\";\nimport { liveHTML } from \"./html/livehtml\";\nimport { UnSafeHTML } from \"./utils/UnSafeHTML\";\nimport { renderStream, renderAsString } from \"./html/html\";\nimport { escapeHTML } from \"./utils/escapehtml\";\n\n/**\n * Renders an HTML template and sends it as a response\n *\n * @param {HTMLTemplate} template - HTML template to render\n * @param {{}} [headers={}] - Headers to send with the response\n * @param {number} [status=200] - HTTP status code\n * @param {string} [statusText='OK'] - HTTP status text\n * @returns {Response} - The rendered HTML response\n */\nfunction render(\n template: Generator,\n headers = {},\n status = 200,\n statusText = \"OK\",\n): Response {\n let responseHeaders = Object.assign(\n { \"Content-Type\": \"text/html; charset=utf-8\" },\n headers,\n );\n return new Response(\n renderStream(template).pipeThrough(new TextEncoderStream()),\n { headers: responseHeaders, status, statusText },\n );\n}\nexport {\n render,\n renderAsString,\n renderStream,\n liveHTML,\n cachableHTML as html,\n UnSafeHTML,\n escapeHTML,\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("node:stream");function t(e){return String(e).replace(/[&<>"']/g,e=>{switch(e){case`&`:return`&`;case`<`:return`<`;case`>`:return`>`;case`"`:return`"`;case`'`:return`'`;default:return e}})}function n(e){let n=e.length;for(;n--;){let r=e[n];typeof r==`string`&&(e[n]=t(r))}return e}var r=class{html;constructor(e){this.html=e}};const i=function*(){}.constructor,a=new WeakMap;function o(e,t){let n=`yield \`${e[0]}\``,i=t.length;for(let a=0;a<i;a++){let i=t[a];typeof i==`string`?n+=`+escapeHTML(args[${a}])+\`${e[a+1]}\``:i instanceof r?n+=`+args[${a}].html+\`${e[a+1]}\``:i instanceof Error||typeof i==`number`?n+=`+args[${a}]+\`${e[a+1]}\``:Array.isArray(i)?n+=`; yield * sanitizeArray(args[${a}]); yield \`${e[a+1]}\``:i?.[Symbol.iterator]?n+=`; yield * args[${a}]; yield \`${e[a+1]}\``:n+=`; yield args[${a}]; yield \`${e[a+1]}\``}return n}function s(e,t){let n=o(e,t);return new i(`escapeHTML`,`sanitizeArray`,`args`,n)}function c(e,...r){let i=a.get(e);return i?i(t,n,r):(i=s(e,r),a.set(e,i),i(t,n,r))}function*l(e,...i){let a=e[0],o=i.length;for(let s=0;s<o;s++){let o=i[s];typeof o==`string`?a+=t(o):o instanceof r?a+=o.html:o instanceof Error||typeof o==`number`?a+=o:Array.isArray(o)?(a&&=(yield a,``),yield*n(o)):o?.[Symbol.iterator]?(a&&=(yield a,``),yield*o):yield o,a+=e[s+1]}a&&=(yield a,``)}async function u(e){try{return await e}catch(e){return e instanceof Promise?u(e):e}}async function d(e,t){let n=e.getReader();try{for(;;){let e=await n.read();if(e.done)return;t.enqueue(e.value)}}catch(e){t.enqueue(e)}finally{n.releaseLock()}}function*f(e,i){let a=``;for(let o of e)if(typeof o==`string`)a+=o;else if(o instanceof r)a+=o.html;else if(o instanceof Error||typeof o==`number`)a+=o;else if(o instanceof Promise){a&&=(i.enqueue(a),``);let e=yield o;if(typeof e==`string`)a+=t(e);else if(e instanceof r)a+=e.html;else if(e instanceof Error||typeof e==`number`)a+=e;else if(Array.isArray(e))a&&=(i.enqueue(a),``),yield*f(n(e),i);else if(e?.[Symbol.iterator])a&&=(i.enqueue(a),``),yield*f(e,i);else if(e==null)continue;else a&&=(i.enqueue(a),``),yield e}else if(Array.isArray(o))a&&=(i.enqueue(a),``),yield*f(n(o),i);else if(o?.[Symbol.iterator])a&&=(i.enqueue(a),``),yield*f(o,i);else if(o==null)continue;else a&&=(i.enqueue(a),``),yield o;a&&=(i.enqueue(a),``)}function p(e){return new ReadableStream({start(t){let n=f(e,t);return r(n);async function r(e=void 0){let i=n.next(e);try{if(i.value instanceof Promise)return r(await u(i.value));if(i.value instanceof Response)return await d(i.value.body.pipeThrough(new TextDecoderStream),t),r();if(i.value instanceof ReadableStream)return await d(i.value,t),r();if(i.value instanceof Request){let e=(await fetch(i.value)).body;return e&&await d(e.pipeThrough(new TextDecoderStream),t),r()}}catch(e){return t.enqueue(e),r()}t.close()}}})}async function m(e){try{let t=p(e).getReader(),n=``;for(;;){let e=await t.read();if(e.done){t.releaseLock();break}n+=e.value}return n}catch(e){throw e}}function h(t,n,r={},i=200,a=`OK`){let o=e.Readable.fromWeb(p(n));t.writeHead(i,a,Object.assign({"Content-Type":`text/html; charset=utf-8`},r)),o.pipe(t)}exports.UnSafeHTML=r,exports.escapeHTML=t,exports.html=c,exports.liveHTML=l,exports.render=h,exports.renderAsString=m,exports.renderStream=p;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["Readable"],"sources":["../../src/utils/escapehtml.ts","../../src/utils/sanitizeArray.ts","../../src/utils/UnSafeHTML.ts","../../src/html/cachehtml.ts","../../src/html/livehtml.ts","../../src/utils/promisedValue.ts","../../src/utils/streamHTML.ts","../../src/html/html.ts","../../src/index.node.ts"],"sourcesContent":["/**\n * Escapes HTML special characters in a string to prevent XSS attacks and ensure proper rendering in HTML.\n *\n * @param {string} str - The string to escape\n *\n * @returns {string} - The escaped string\n */\nexport function escapeHTML(str: string): string {\n return String(str).replace(/[&<>\"']/g, (char: string) => {\n switch (char) {\n case \"&\":\n return \"&\";\n case \"<\":\n return \"<\";\n case \">\":\n return \">\";\n case '\"':\n return \""\";\n case \"'\":\n return \"'\";\n default:\n return char;\n }\n });\n}\n","import { escapeHTML } from \"./escapehtml\";\n\nexport function sanitizeArray(values: any[]): any[] {\n let index = values.length;\n while (index--) {\n let value = values[index];\n if (typeof value == \"string\") {\n values[index] = escapeHTML(value);\n }\n }\n return values;\n}\n","export class UnSafeHTML {\n public html: string;\n /**\n * Creates unsafe html that will not be escaped\n *\n * @param {string} html - string containing unsafe html\n */\n constructor(html: string) {\n this.html = html;\n }\n}\n","import { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\nimport { UnSafeHTML } from \"../utils/UnSafeHTML\";\n\ntype GeneratorFunctionConstructor = new (\n ...args: string[]\n) => (...args: any[]) => Generator<any, any, any>;\nconst TemplateConstructor = function* () {}\n .constructor as GeneratorFunctionConstructor,\n templateCache = new WeakMap();\n\n/**\n * A function that generates the source code for a compiled HTML template function.\n *\n * @param {String[]} templates\n * @param {Array} values\n * @returns {string} source code of the compiled template function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction generateTemplateSourceCode(\n templates: TemplateStringsArray,\n values: TemplateValues[],\n): string {\n let sourceCode = `yield \\`${templates[0]}\\``,\n length = values.length;\n for (let index = 0; index < length; index++) {\n let value = values[index];\n if (typeof value == \"string\") {\n sourceCode += `+escapeHTML(args[${index}])+\\`${templates[index + 1]}\\``;\n } else if (value instanceof UnSafeHTML) {\n sourceCode += `+args[${index}].html+\\`${templates[index + 1]}\\``;\n } else if (value instanceof Error || typeof value == \"number\") {\n sourceCode += `+args[${index}]+\\`${templates[index + 1]}\\``;\n } else if (Array.isArray(value)) {\n sourceCode += `; yield * sanitizeArray(args[${index}]); yield \\`${templates[index + 1]}\\``;\n } else if ((value as any)?.[Symbol.iterator]) {\n sourceCode += `; yield * args[${index}]; yield \\`${templates[index + 1]}\\``;\n } else {\n sourceCode += `; yield args[${index}]; yield \\`${templates[index + 1]}\\``;\n }\n }\n return sourceCode;\n}\n/**\n * compiles an HTML template into a function that can be cached and reused with different values. It generates source code for the template by processing the provided templates and values, handling various types of values such as strings, UnSafeHTML instances, errors, numbers, arrays, and iterables. The generated source code is then used to create a new function using the TemplateConstructor, which can be called with the appropriate arguments to produce the final HTML output. This approach allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {String[]} templates\n * @param {Array} values\n * @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction compileTemplate(\n templates: TemplateStringsArray,\n values: TemplateValues[],\n) {\n let sourceCode = generateTemplateSourceCode(templates, values);\n return new TemplateConstructor(\n \"escapeHTML\",\n \"sanitizeArray\",\n \"args\",\n sourceCode,\n );\n}\n/**\n * A function that renders an HTML template with caching capabilities. It checks if a compiled template function already exists in the cache for the given templates. If it does, it calls the cached function with the provided values and returns the result. If not, it compiles a new template function using the compileTemplate function, stores it in the cache, and then calls it with the provided values. This allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {String[]} templates\n * @param {...(String|UnSafeHTML|Error|number|Array|Iterable)} values\n * @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction cachableHTML(\n templates: TemplateStringsArray,\n ...values: TemplateValues[]\n) {\n let template = templateCache.get(templates);\n if (template) {\n return template(escapeHTML, sanitizeArray, values);\n }\n template = compileTemplate(templates, values);\n templateCache.set(templates, template);\n return template(escapeHTML, sanitizeArray, values);\n}\n\nexport { cachableHTML };\n","import { UnSafeHTML } from \"../utils/UnSafeHTML\";\nimport { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\n\n/**\n * A generator function that processes an HTML template without caching. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.\n *\n * @export\n * @param {String[]} templates\n * @param {...TemplateValues} values\n * @returns {Generator} A generator that yields processed HTML content as a stream.\n */\nexport function* liveHTML(\n templates: TemplateStringsArray,\n ...values: TemplateValues[]\n) {\n let cache = templates[0],\n length = values.length;\n for (let index = 0; index < length; index++) {\n let value = values[index];\n if (typeof value == \"string\") {\n cache += escapeHTML(value);\n } else if (value instanceof UnSafeHTML) {\n cache += value.html;\n } else if (value instanceof Error || typeof value == \"number\") {\n cache += value;\n } else if (Array.isArray(value)) {\n if (cache) {\n yield cache;\n cache = \"\";\n }\n yield* sanitizeArray(value);\n } else if ((value as any)?.[Symbol.iterator]) {\n if (cache) {\n yield cache;\n cache = \"\";\n }\n yield* value as Generator;\n } else {\n yield value;\n }\n cache += templates[index + 1];\n }\n if (cache) {\n yield cache;\n cache = \"\";\n }\n}\n","export async function promisedValue(value: Promise<any>): Promise<any> {\n try {\n return await value;\n } catch (error) {\n if (error instanceof Promise) {\n return promisedValue(error);\n } else {\n return error;\n }\n }\n}\n","export async function streamHTML(\n readable: ReadableStream<string>,\n controller: ReadableStreamDefaultController,\n) {\n const stream: ReadableStreamDefaultReader = readable.getReader();\n try {\n while (true) {\n let data = await stream.read();\n if (data.done) {\n return;\n }\n controller.enqueue(data.value);\n }\n } catch (error) {\n controller.enqueue(error);\n } finally {\n stream.releaseLock();\n }\n}\n","import { UnSafeHTML } from \"../utils/UnSafeHTML\";\nimport { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\nimport { promisedValue } from \"../utils/promisedValue\";\nimport { streamHTML } from \"../utils/streamHTML\";\n\n/**\n * A generator function that processes an HTML template with embedded values and yields the resulting HTML as a stream. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.\n *\n * @param {Generator} templateGenerator\n * @param {ReadableStreamDefaultController} controller\n * @returns {IterableIterator<string>} An iterator that yields the resulting HTML as a stream.\n */\nfunction* processHTML(\n templateGenerator: Generator | Array<TemplateValues>,\n controller: ReadableStreamDefaultController<string>,\n): any {\n let cache: string = \"\";\n for (const value of templateGenerator) {\n if (typeof value == \"string\") {\n cache += value;\n } else if (value instanceof UnSafeHTML) {\n cache += value.html;\n } else if (value instanceof Error || typeof value == \"number\") {\n cache += value;\n } else if (value instanceof Promise) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValue = yield value;\n if (typeof resolvedValue == \"string\") {\n cache += escapeHTML(resolvedValue);\n } else if (resolvedValue instanceof UnSafeHTML) {\n cache += resolvedValue.html;\n } else if (\n resolvedValue instanceof Error ||\n typeof resolvedValue == \"number\"\n ) {\n cache += resolvedValue;\n } else if (Array.isArray(resolvedValue)) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(sanitizeArray(resolvedValue), controller);\n } else if (resolvedValue?.[Symbol.iterator]) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(resolvedValue, controller);\n } else if (resolvedValue == undefined) {\n continue;\n } else {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValues = yield resolvedValue;\n void resolvedValues\n }\n } else if (Array.isArray(value)) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(sanitizeArray(value), controller);\n } else if (value?.[Symbol.iterator]) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(value, controller);\n } else if (value == undefined) {\n continue;\n } else {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValue = yield value;\n void resolvedValue\n }\n }\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n}\n\n/**\n * A function that renders an HTML template generator and returns a ReadableStream that yields the resulting HTML as a stream. It uses the processHTML generator function to process the template and handle various types of values, including promises and streams, while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {Generator} generator - The HTML template generator to render.\n * @returns {ReadableStream} A ReadableStream that yields the resulting HTML as a stream.\n */\nfunction renderStream(generator: Generator) {\n return new ReadableStream<string>({\n start(controller) {\n let templateGenerator = processHTML(generator, controller);\n return startHTMLStream(templateGenerator);\n async function startHTMLStream(\n value:\n | undefined\n | Promise<any>\n | Request\n | ReadableStream\n | Response = undefined,\n ) {\n let data = templateGenerator.next(value);\n try {\n if (data.value instanceof Promise) {\n let resolvedValue = await promisedValue(data.value);\n return startHTMLStream(resolvedValue);\n } else if (data.value instanceof Response) {\n await streamHTML(data.value.body.pipeThrough(new TextDecoderStream()), controller);\n return startHTMLStream();\n } else if (data.value instanceof ReadableStream) {\n await streamHTML(data.value, controller);\n return startHTMLStream();\n } else if (data.value instanceof Request) {\n let response:Response = await fetch(data.value),\n stream = response.body;\n if (stream) {\n await streamHTML(stream.pipeThrough(new TextDecoderStream()), controller);\n }\n return startHTMLStream();\n }\n } catch (error) {\n controller.enqueue(error as string);\n return startHTMLStream();\n }\n controller.close();\n }\n },\n });\n}\n/**\n * renders an HTML template generator and returns a promise that resolves to the resulting HTML as a string.\n *\n * @async\n * @param {Generator} generator\n * @returns {Promise<string>} A promise that resolves to the resulting HTML as a string.\n */\nasync function renderAsString(generator: Generator): Promise<string> {\n try {\n let readable = renderStream(generator).getReader(),\n html = \"\";\n while (true) {\n let data = await readable.read();\n if (data.done) {\n readable.releaseLock();\n break;\n }\n html += data.value;\n }\n return html;\n } catch (error) {\n throw error;\n }\n}\nexport { renderStream, renderAsString };\n","import { cachableHTML } from \"./html/cachehtml\";\nimport { liveHTML } from \"./html/livehtml\";\nimport { UnSafeHTML } from \"./utils/UnSafeHTML\";\nimport { renderStream, renderAsString } from \"./html/html\";\nimport { escapeHTML } from \"./utils/escapehtml\";\nimport { Readable } from \"node:stream\";\n\n/**\n * Renders an HTML template and sends it as a response\n *\n * @param {response} response - Node response object\n * @param {HTMLTemplate} template - HTML template to render\n * @param {{}} [headers={}] - Headers to send with the response\n * @param {number} [status=200] - HTTP status code\n * @param {string} [statusText='OK'] - HTTP status text\n * @returns {void}\n */\nfunction render(\n response: any,\n template: Generator,\n headers = {},\n status = 200,\n statusText = \"OK\",\n) {\n const readable = Readable.fromWeb(renderStream(template));\n response.writeHead(\n status,\n statusText,\n Object.assign({ \"Content-Type\": \"text/html; charset=utf-8\" }, headers),\n );\n readable.pipe(response);\n}\nexport {\n render,\n renderAsString,\n renderStream,\n liveHTML,\n cachableHTML as html,\n UnSafeHTML,\n escapeHTML,\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//#region src/html/cachehtml.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A function that renders an HTML template with caching capabilities. It checks if a compiled template function already exists in the cache for the given templates. If it does, it calls the cached function with the provided values and returns the result. If not, it compiles a new template function using the compileTemplate function, stores it in the cache, and then calls it with the provided values. This allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.
|
|
4
|
+
*
|
|
5
|
+
* @param {String[]} templates
|
|
6
|
+
* @param {...(String|UnSafeHTML|Error|number|Array|Iterable)} values
|
|
7
|
+
* @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.
|
|
8
|
+
*/
|
|
9
|
+
declare function cachableHTML(templates: TemplateStringsArray, ...values: TemplateValues[]): any;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/html/livehtml.d.ts
|
|
12
|
+
/**
|
|
13
|
+
* A generator function that processes an HTML template without caching. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.
|
|
14
|
+
*
|
|
15
|
+
* @export
|
|
16
|
+
* @param {String[]} templates
|
|
17
|
+
* @param {...TemplateValues} values
|
|
18
|
+
* @returns {Generator} A generator that yields processed HTML content as a stream.
|
|
19
|
+
*/
|
|
20
|
+
declare function liveHTML(templates: TemplateStringsArray, ...values: TemplateValues[]): Generator<any, void, any>;
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/utils/UnSafeHTML.d.ts
|
|
23
|
+
declare class UnSafeHTML {
|
|
24
|
+
html: string;
|
|
25
|
+
/**
|
|
26
|
+
* Creates unsafe html that will not be escaped
|
|
27
|
+
*
|
|
28
|
+
* @param {string} html - string containing unsafe html
|
|
29
|
+
*/
|
|
30
|
+
constructor(html: string);
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/html/html.d.ts
|
|
34
|
+
/**
|
|
35
|
+
* A function that renders an HTML template generator and returns a ReadableStream that yields the resulting HTML as a stream. It uses the processHTML generator function to process the template and handle various types of values, including promises and streams, while ensuring that string values are properly escaped to prevent XSS vulnerabilities.
|
|
36
|
+
*
|
|
37
|
+
* @param {Generator} generator - The HTML template generator to render.
|
|
38
|
+
* @returns {ReadableStream} A ReadableStream that yields the resulting HTML as a stream.
|
|
39
|
+
*/
|
|
40
|
+
declare function renderStream(generator: Generator): import("node:stream/web").ReadableStream<string>;
|
|
41
|
+
/**
|
|
42
|
+
* renders an HTML template generator and returns a promise that resolves to the resulting HTML as a string.
|
|
43
|
+
*
|
|
44
|
+
* @async
|
|
45
|
+
* @param {Generator} generator
|
|
46
|
+
* @returns {Promise<string>} A promise that resolves to the resulting HTML as a string.
|
|
47
|
+
*/
|
|
48
|
+
declare function renderAsString(generator: Generator): Promise<string>;
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/utils/escapehtml.d.ts
|
|
51
|
+
/**
|
|
52
|
+
* Escapes HTML special characters in a string to prevent XSS attacks and ensure proper rendering in HTML.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} str - The string to escape
|
|
55
|
+
*
|
|
56
|
+
* @returns {string} - The escaped string
|
|
57
|
+
*/
|
|
58
|
+
declare function escapeHTML(str: string): string;
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/index.node.d.ts
|
|
61
|
+
/**
|
|
62
|
+
* Renders an HTML template and sends it as a response
|
|
63
|
+
*
|
|
64
|
+
* @param {response} response - Node response object
|
|
65
|
+
* @param {HTMLTemplate} template - HTML template to render
|
|
66
|
+
* @param {{}} [headers={}] - Headers to send with the response
|
|
67
|
+
* @param {number} [status=200] - HTTP status code
|
|
68
|
+
* @param {string} [statusText='OK'] - HTTP status text
|
|
69
|
+
* @returns {void}
|
|
70
|
+
*/
|
|
71
|
+
declare function render(response: any, template: Generator, headers?: {}, status?: number, statusText?: string): void;
|
|
72
|
+
//#endregion
|
|
73
|
+
export { UnSafeHTML, escapeHTML, cachableHTML as html, liveHTML, render, renderAsString, renderStream };
|
|
74
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
//#region src/html/cachehtml.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A function that renders an HTML template with caching capabilities. It checks if a compiled template function already exists in the cache for the given templates. If it does, it calls the cached function with the provided values and returns the result. If not, it compiles a new template function using the compileTemplate function, stores it in the cache, and then calls it with the provided values. This allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.
|
|
4
|
+
*
|
|
5
|
+
* @param {String[]} templates
|
|
6
|
+
* @param {...(String|UnSafeHTML|Error|number|Array|Iterable)} values
|
|
7
|
+
* @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.
|
|
8
|
+
*/
|
|
9
|
+
declare function cachableHTML(templates: TemplateStringsArray, ...values: TemplateValues[]): any;
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/html/livehtml.d.ts
|
|
12
|
+
/**
|
|
13
|
+
* A generator function that processes an HTML template without caching. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.
|
|
14
|
+
*
|
|
15
|
+
* @export
|
|
16
|
+
* @param {String[]} templates
|
|
17
|
+
* @param {...TemplateValues} values
|
|
18
|
+
* @returns {Generator} A generator that yields processed HTML content as a stream.
|
|
19
|
+
*/
|
|
20
|
+
declare function liveHTML(templates: TemplateStringsArray, ...values: TemplateValues[]): Generator<any, void, any>;
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/utils/UnSafeHTML.d.ts
|
|
23
|
+
declare class UnSafeHTML {
|
|
24
|
+
html: string;
|
|
25
|
+
/**
|
|
26
|
+
* Creates unsafe html that will not be escaped
|
|
27
|
+
*
|
|
28
|
+
* @param {string} html - string containing unsafe html
|
|
29
|
+
*/
|
|
30
|
+
constructor(html: string);
|
|
31
|
+
}
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/html/html.d.ts
|
|
34
|
+
/**
|
|
35
|
+
* A function that renders an HTML template generator and returns a ReadableStream that yields the resulting HTML as a stream. It uses the processHTML generator function to process the template and handle various types of values, including promises and streams, while ensuring that string values are properly escaped to prevent XSS vulnerabilities.
|
|
36
|
+
*
|
|
37
|
+
* @param {Generator} generator - The HTML template generator to render.
|
|
38
|
+
* @returns {ReadableStream} A ReadableStream that yields the resulting HTML as a stream.
|
|
39
|
+
*/
|
|
40
|
+
declare function renderStream(generator: Generator): import("node:stream/web").ReadableStream<string>;
|
|
41
|
+
/**
|
|
42
|
+
* renders an HTML template generator and returns a promise that resolves to the resulting HTML as a string.
|
|
43
|
+
*
|
|
44
|
+
* @async
|
|
45
|
+
* @param {Generator} generator
|
|
46
|
+
* @returns {Promise<string>} A promise that resolves to the resulting HTML as a string.
|
|
47
|
+
*/
|
|
48
|
+
declare function renderAsString(generator: Generator): Promise<string>;
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/utils/escapehtml.d.ts
|
|
51
|
+
/**
|
|
52
|
+
* Escapes HTML special characters in a string to prevent XSS attacks and ensure proper rendering in HTML.
|
|
53
|
+
*
|
|
54
|
+
* @param {string} str - The string to escape
|
|
55
|
+
*
|
|
56
|
+
* @returns {string} - The escaped string
|
|
57
|
+
*/
|
|
58
|
+
declare function escapeHTML(str: string): string;
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/index.node.d.ts
|
|
61
|
+
/**
|
|
62
|
+
* Renders an HTML template and sends it as a response
|
|
63
|
+
*
|
|
64
|
+
* @param {response} response - Node response object
|
|
65
|
+
* @param {HTMLTemplate} template - HTML template to render
|
|
66
|
+
* @param {{}} [headers={}] - Headers to send with the response
|
|
67
|
+
* @param {number} [status=200] - HTTP status code
|
|
68
|
+
* @param {string} [statusText='OK'] - HTTP status text
|
|
69
|
+
* @returns {void}
|
|
70
|
+
*/
|
|
71
|
+
declare function render(response: any, template: Generator, headers?: {}, status?: number, statusText?: string): void;
|
|
72
|
+
//#endregion
|
|
73
|
+
export { UnSafeHTML, escapeHTML, cachableHTML as html, liveHTML, render, renderAsString, renderStream };
|
|
74
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{Readable as e}from"node:stream";function t(e){return String(e).replace(/[&<>"']/g,e=>{switch(e){case`&`:return`&`;case`<`:return`<`;case`>`:return`>`;case`"`:return`"`;case`'`:return`'`;default:return e}})}function n(e){let n=e.length;for(;n--;){let r=e[n];typeof r==`string`&&(e[n]=t(r))}return e}var r=class{html;constructor(e){this.html=e}};const i=function*(){}.constructor,a=new WeakMap;function o(e,t){let n=`yield \`${e[0]}\``,i=t.length;for(let a=0;a<i;a++){let i=t[a];typeof i==`string`?n+=`+escapeHTML(args[${a}])+\`${e[a+1]}\``:i instanceof r?n+=`+args[${a}].html+\`${e[a+1]}\``:i instanceof Error||typeof i==`number`?n+=`+args[${a}]+\`${e[a+1]}\``:Array.isArray(i)?n+=`; yield * sanitizeArray(args[${a}]); yield \`${e[a+1]}\``:i?.[Symbol.iterator]?n+=`; yield * args[${a}]; yield \`${e[a+1]}\``:n+=`; yield args[${a}]; yield \`${e[a+1]}\``}return n}function s(e,t){let n=o(e,t);return new i(`escapeHTML`,`sanitizeArray`,`args`,n)}function c(e,...r){let i=a.get(e);return i?i(t,n,r):(i=s(e,r),a.set(e,i),i(t,n,r))}function*l(e,...i){let a=e[0],o=i.length;for(let s=0;s<o;s++){let o=i[s];typeof o==`string`?a+=t(o):o instanceof r?a+=o.html:o instanceof Error||typeof o==`number`?a+=o:Array.isArray(o)?(a&&=(yield a,``),yield*n(o)):o?.[Symbol.iterator]?(a&&=(yield a,``),yield*o):yield o,a+=e[s+1]}a&&=(yield a,``)}async function u(e){try{return await e}catch(e){return e instanceof Promise?u(e):e}}async function d(e,t){let n=e.getReader();try{for(;;){let e=await n.read();if(e.done)return;t.enqueue(e.value)}}catch(e){t.enqueue(e)}finally{n.releaseLock()}}function*f(e,i){let a=``;for(let o of e)if(typeof o==`string`)a+=o;else if(o instanceof r)a+=o.html;else if(o instanceof Error||typeof o==`number`)a+=o;else if(o instanceof Promise){a&&=(i.enqueue(a),``);let e=yield o;if(typeof e==`string`)a+=t(e);else if(e instanceof r)a+=e.html;else if(e instanceof Error||typeof e==`number`)a+=e;else if(Array.isArray(e))a&&=(i.enqueue(a),``),yield*f(n(e),i);else if(e?.[Symbol.iterator])a&&=(i.enqueue(a),``),yield*f(e,i);else if(e==null)continue;else a&&=(i.enqueue(a),``),yield e}else if(Array.isArray(o))a&&=(i.enqueue(a),``),yield*f(n(o),i);else if(o?.[Symbol.iterator])a&&=(i.enqueue(a),``),yield*f(o,i);else if(o==null)continue;else a&&=(i.enqueue(a),``),yield o;a&&=(i.enqueue(a),``)}function p(e){return new ReadableStream({start(t){let n=f(e,t);return r(n);async function r(e=void 0){let i=n.next(e);try{if(i.value instanceof Promise)return r(await u(i.value));if(i.value instanceof Response)return await d(i.value.body.pipeThrough(new TextDecoderStream),t),r();if(i.value instanceof ReadableStream)return await d(i.value,t),r();if(i.value instanceof Request){let e=(await fetch(i.value)).body;return e&&await d(e.pipeThrough(new TextDecoderStream),t),r()}}catch(e){return t.enqueue(e),r()}t.close()}}})}async function m(e){try{let t=p(e).getReader(),n=``;for(;;){let e=await t.read();if(e.done){t.releaseLock();break}n+=e.value}return n}catch(e){throw e}}function h(t,n,r={},i=200,a=`OK`){let o=e.fromWeb(p(n));t.writeHead(i,a,Object.assign({"Content-Type":`text/html; charset=utf-8`},r)),o.pipe(t)}export{r as UnSafeHTML,t as escapeHTML,c as html,l as liveHTML,h as render,m as renderAsString,p as renderStream};
|
|
2
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/utils/escapehtml.ts","../../src/utils/sanitizeArray.ts","../../src/utils/UnSafeHTML.ts","../../src/html/cachehtml.ts","../../src/html/livehtml.ts","../../src/utils/promisedValue.ts","../../src/utils/streamHTML.ts","../../src/html/html.ts","../../src/index.node.ts"],"sourcesContent":["/**\n * Escapes HTML special characters in a string to prevent XSS attacks and ensure proper rendering in HTML.\n *\n * @param {string} str - The string to escape\n *\n * @returns {string} - The escaped string\n */\nexport function escapeHTML(str: string): string {\n return String(str).replace(/[&<>\"']/g, (char: string) => {\n switch (char) {\n case \"&\":\n return \"&\";\n case \"<\":\n return \"<\";\n case \">\":\n return \">\";\n case '\"':\n return \""\";\n case \"'\":\n return \"'\";\n default:\n return char;\n }\n });\n}\n","import { escapeHTML } from \"./escapehtml\";\n\nexport function sanitizeArray(values: any[]): any[] {\n let index = values.length;\n while (index--) {\n let value = values[index];\n if (typeof value == \"string\") {\n values[index] = escapeHTML(value);\n }\n }\n return values;\n}\n","export class UnSafeHTML {\n public html: string;\n /**\n * Creates unsafe html that will not be escaped\n *\n * @param {string} html - string containing unsafe html\n */\n constructor(html: string) {\n this.html = html;\n }\n}\n","import { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\nimport { UnSafeHTML } from \"../utils/UnSafeHTML\";\n\ntype GeneratorFunctionConstructor = new (\n ...args: string[]\n) => (...args: any[]) => Generator<any, any, any>;\nconst TemplateConstructor = function* () {}\n .constructor as GeneratorFunctionConstructor,\n templateCache = new WeakMap();\n\n/**\n * A function that generates the source code for a compiled HTML template function.\n *\n * @param {String[]} templates\n * @param {Array} values\n * @returns {string} source code of the compiled template function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction generateTemplateSourceCode(\n templates: TemplateStringsArray,\n values: TemplateValues[],\n): string {\n let sourceCode = `yield \\`${templates[0]}\\``,\n length = values.length;\n for (let index = 0; index < length; index++) {\n let value = values[index];\n if (typeof value == \"string\") {\n sourceCode += `+escapeHTML(args[${index}])+\\`${templates[index + 1]}\\``;\n } else if (value instanceof UnSafeHTML) {\n sourceCode += `+args[${index}].html+\\`${templates[index + 1]}\\``;\n } else if (value instanceof Error || typeof value == \"number\") {\n sourceCode += `+args[${index}]+\\`${templates[index + 1]}\\``;\n } else if (Array.isArray(value)) {\n sourceCode += `; yield * sanitizeArray(args[${index}]); yield \\`${templates[index + 1]}\\``;\n } else if ((value as any)?.[Symbol.iterator]) {\n sourceCode += `; yield * args[${index}]; yield \\`${templates[index + 1]}\\``;\n } else {\n sourceCode += `; yield args[${index}]; yield \\`${templates[index + 1]}\\``;\n }\n }\n return sourceCode;\n}\n/**\n * compiles an HTML template into a function that can be cached and reused with different values. It generates source code for the template by processing the provided templates and values, handling various types of values such as strings, UnSafeHTML instances, errors, numbers, arrays, and iterables. The generated source code is then used to create a new function using the TemplateConstructor, which can be called with the appropriate arguments to produce the final HTML output. This approach allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {String[]} templates\n * @param {Array} values\n * @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction compileTemplate(\n templates: TemplateStringsArray,\n values: TemplateValues[],\n) {\n let sourceCode = generateTemplateSourceCode(templates, values);\n return new TemplateConstructor(\n \"escapeHTML\",\n \"sanitizeArray\",\n \"args\",\n sourceCode,\n );\n}\n/**\n * A function that renders an HTML template with caching capabilities. It checks if a compiled template function already exists in the cache for the given templates. If it does, it calls the cached function with the provided values and returns the result. If not, it compiles a new template function using the compileTemplate function, stores it in the cache, and then calls it with the provided values. This allows for efficient rendering of HTML templates while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {String[]} templates\n * @param {...(String|UnSafeHTML|Error|number|Array|Iterable)} values\n * @returns {GeneratorFunction} A generator function that can be called with the appropriate arguments to produce the final HTML output based on the provided templates and values.\n */\nfunction cachableHTML(\n templates: TemplateStringsArray,\n ...values: TemplateValues[]\n) {\n let template = templateCache.get(templates);\n if (template) {\n return template(escapeHTML, sanitizeArray, values);\n }\n template = compileTemplate(templates, values);\n templateCache.set(templates, template);\n return template(escapeHTML, sanitizeArray, values);\n}\n\nexport { cachableHTML };\n","import { UnSafeHTML } from \"../utils/UnSafeHTML\";\nimport { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\n\n/**\n * A generator function that processes an HTML template without caching. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.\n *\n * @export\n * @param {String[]} templates\n * @param {...TemplateValues} values\n * @returns {Generator} A generator that yields processed HTML content as a stream.\n */\nexport function* liveHTML(\n templates: TemplateStringsArray,\n ...values: TemplateValues[]\n) {\n let cache = templates[0],\n length = values.length;\n for (let index = 0; index < length; index++) {\n let value = values[index];\n if (typeof value == \"string\") {\n cache += escapeHTML(value);\n } else if (value instanceof UnSafeHTML) {\n cache += value.html;\n } else if (value instanceof Error || typeof value == \"number\") {\n cache += value;\n } else if (Array.isArray(value)) {\n if (cache) {\n yield cache;\n cache = \"\";\n }\n yield* sanitizeArray(value);\n } else if ((value as any)?.[Symbol.iterator]) {\n if (cache) {\n yield cache;\n cache = \"\";\n }\n yield* value as Generator;\n } else {\n yield value;\n }\n cache += templates[index + 1];\n }\n if (cache) {\n yield cache;\n cache = \"\";\n }\n}\n","export async function promisedValue(value: Promise<any>): Promise<any> {\n try {\n return await value;\n } catch (error) {\n if (error instanceof Promise) {\n return promisedValue(error);\n } else {\n return error;\n }\n }\n}\n","export async function streamHTML(\n readable: ReadableStream<string>,\n controller: ReadableStreamDefaultController,\n) {\n const stream: ReadableStreamDefaultReader = readable.getReader();\n try {\n while (true) {\n let data = await stream.read();\n if (data.done) {\n return;\n }\n controller.enqueue(data.value);\n }\n } catch (error) {\n controller.enqueue(error);\n } finally {\n stream.releaseLock();\n }\n}\n","import { UnSafeHTML } from \"../utils/UnSafeHTML\";\nimport { escapeHTML } from \"../utils/escapehtml\";\nimport { sanitizeArray } from \"../utils/sanitizeArray\";\nimport { promisedValue } from \"../utils/promisedValue\";\nimport { streamHTML } from \"../utils/streamHTML\";\n\n/**\n * A generator function that processes an HTML template with embedded values and yields the resulting HTML as a stream. It handles various types of values, including strings, UnSafeHTML instances, errors, numbers, promises, arrays, and iterables. The function ensures that string values are properly escaped to prevent XSS vulnerabilities, while allowing UnSafeHTML instances to be included as-is. It also supports asynchronous values by yielding promises and waiting for their resolution before processing them further.\n *\n * @param {Generator} templateGenerator\n * @param {ReadableStreamDefaultController} controller\n * @returns {IterableIterator<string>} An iterator that yields the resulting HTML as a stream.\n */\nfunction* processHTML(\n templateGenerator: Generator | Array<TemplateValues>,\n controller: ReadableStreamDefaultController<string>,\n): any {\n let cache: string = \"\";\n for (const value of templateGenerator) {\n if (typeof value == \"string\") {\n cache += value;\n } else if (value instanceof UnSafeHTML) {\n cache += value.html;\n } else if (value instanceof Error || typeof value == \"number\") {\n cache += value;\n } else if (value instanceof Promise) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValue = yield value;\n if (typeof resolvedValue == \"string\") {\n cache += escapeHTML(resolvedValue);\n } else if (resolvedValue instanceof UnSafeHTML) {\n cache += resolvedValue.html;\n } else if (\n resolvedValue instanceof Error ||\n typeof resolvedValue == \"number\"\n ) {\n cache += resolvedValue;\n } else if (Array.isArray(resolvedValue)) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(sanitizeArray(resolvedValue), controller);\n } else if (resolvedValue?.[Symbol.iterator]) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(resolvedValue, controller);\n } else if (resolvedValue == undefined) {\n continue;\n } else {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValues = yield resolvedValue;\n void resolvedValues\n }\n } else if (Array.isArray(value)) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(sanitizeArray(value), controller);\n } else if (value?.[Symbol.iterator]) {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n yield* processHTML(value, controller);\n } else if (value == undefined) {\n continue;\n } else {\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n let resolvedValue = yield value;\n void resolvedValue\n }\n }\n if (cache) {\n controller.enqueue(cache);\n cache = \"\";\n }\n}\n\n/**\n * A function that renders an HTML template generator and returns a ReadableStream that yields the resulting HTML as a stream. It uses the processHTML generator function to process the template and handle various types of values, including promises and streams, while ensuring that string values are properly escaped to prevent XSS vulnerabilities.\n *\n * @param {Generator} generator - The HTML template generator to render.\n * @returns {ReadableStream} A ReadableStream that yields the resulting HTML as a stream.\n */\nfunction renderStream(generator: Generator) {\n return new ReadableStream<string>({\n start(controller) {\n let templateGenerator = processHTML(generator, controller);\n return startHTMLStream(templateGenerator);\n async function startHTMLStream(\n value:\n | undefined\n | Promise<any>\n | Request\n | ReadableStream\n | Response = undefined,\n ) {\n let data = templateGenerator.next(value);\n try {\n if (data.value instanceof Promise) {\n let resolvedValue = await promisedValue(data.value);\n return startHTMLStream(resolvedValue);\n } else if (data.value instanceof Response) {\n await streamHTML(data.value.body.pipeThrough(new TextDecoderStream()), controller);\n return startHTMLStream();\n } else if (data.value instanceof ReadableStream) {\n await streamHTML(data.value, controller);\n return startHTMLStream();\n } else if (data.value instanceof Request) {\n let response:Response = await fetch(data.value),\n stream = response.body;\n if (stream) {\n await streamHTML(stream.pipeThrough(new TextDecoderStream()), controller);\n }\n return startHTMLStream();\n }\n } catch (error) {\n controller.enqueue(error as string);\n return startHTMLStream();\n }\n controller.close();\n }\n },\n });\n}\n/**\n * renders an HTML template generator and returns a promise that resolves to the resulting HTML as a string.\n *\n * @async\n * @param {Generator} generator\n * @returns {Promise<string>} A promise that resolves to the resulting HTML as a string.\n */\nasync function renderAsString(generator: Generator): Promise<string> {\n try {\n let readable = renderStream(generator).getReader(),\n html = \"\";\n while (true) {\n let data = await readable.read();\n if (data.done) {\n readable.releaseLock();\n break;\n }\n html += data.value;\n }\n return html;\n } catch (error) {\n throw error;\n }\n}\nexport { renderStream, renderAsString };\n","import { cachableHTML } from \"./html/cachehtml\";\nimport { liveHTML } from \"./html/livehtml\";\nimport { UnSafeHTML } from \"./utils/UnSafeHTML\";\nimport { renderStream, renderAsString } from \"./html/html\";\nimport { escapeHTML } from \"./utils/escapehtml\";\nimport { Readable } from \"node:stream\";\n\n/**\n * Renders an HTML template and sends it as a response\n *\n * @param {response} response - Node response object\n * @param {HTMLTemplate} template - HTML template to render\n * @param {{}} [headers={}] - Headers to send with the response\n * @param {number} [status=200] - HTTP status code\n * @param {string} [statusText='OK'] - HTTP status text\n * @returns {void}\n */\nfunction render(\n response: any,\n template: Generator,\n headers = {},\n status = 200,\n statusText = \"OK\",\n) {\n const readable = Readable.fromWeb(renderStream(template));\n response.writeHead(\n status,\n statusText,\n Object.assign({ \"Content-Type\": \"text/html; charset=utf-8\" }, headers),\n );\n readable.pipe(response);\n}\nexport {\n render,\n renderAsString,\n renderStream,\n liveHTML,\n cachableHTML as html,\n UnSafeHTML,\n escapeHTML,\n};\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "achi-html-stream",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"description": "An HTML streaming library for multi-page progressive web apps that renders HTML in service workers and also works with Node.js and other JavaScript runtimes",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Kimbugwe Mark",
|
|
8
|
+
"email": "markkimbugwe@gmail.com"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"homepage": "https://github.com/kimbugwe-mark/achi-html#readme",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/kimbugwe-mark/achi-html.git"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"html templating",
|
|
18
|
+
"tagged template",
|
|
19
|
+
"template literals",
|
|
20
|
+
"server-side rendering",
|
|
21
|
+
"ssr",
|
|
22
|
+
"html rendering",
|
|
23
|
+
"streaming html",
|
|
24
|
+
"async rendering",
|
|
25
|
+
"xss protection",
|
|
26
|
+
"service worker rendering",
|
|
27
|
+
"html escaping",
|
|
28
|
+
"performance",
|
|
29
|
+
"html"
|
|
30
|
+
],
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/kimbugwe-mark/achi-html/issues"
|
|
33
|
+
},
|
|
34
|
+
"types": "./dist/node/index.d.mts",
|
|
35
|
+
"unpkg": "./dist/browser/index.iife.js",
|
|
36
|
+
"jsdelivr": "./dist/browser/index.iife.js",
|
|
37
|
+
"exports": {
|
|
38
|
+
".": {
|
|
39
|
+
"types": "./dist/node/index.d.mts",
|
|
40
|
+
"node": {
|
|
41
|
+
"import": "./dist/node/index.mjs",
|
|
42
|
+
"require": "./dist/node/index.cjs",
|
|
43
|
+
"types": "./dist/node/index.d.mts"
|
|
44
|
+
},
|
|
45
|
+
"bun": {
|
|
46
|
+
"import": "./dist/browser/index.mjs",
|
|
47
|
+
"types": "./dist/browser/index.d.mts"
|
|
48
|
+
},
|
|
49
|
+
"deno": {
|
|
50
|
+
"import": "./dist/browser/index.mjs",
|
|
51
|
+
"types": "./dist/browser/index.d.mts"
|
|
52
|
+
},
|
|
53
|
+
"browser": {
|
|
54
|
+
"import": "./dist/browser/index.mjs",
|
|
55
|
+
"types": "./dist/browser/index.d.mts"
|
|
56
|
+
},
|
|
57
|
+
"default": "./dist/browser/index.mjs"
|
|
58
|
+
},
|
|
59
|
+
"./node": {
|
|
60
|
+
"import": "./dist/node/index.mjs",
|
|
61
|
+
"require": "./dist/node/index.cjs",
|
|
62
|
+
"types": "./dist/node/index.d.mts"
|
|
63
|
+
},
|
|
64
|
+
"./browser": {
|
|
65
|
+
"import": "./dist/browser/index.mjs",
|
|
66
|
+
"types": "./dist/browser/index.d.mts"
|
|
67
|
+
},
|
|
68
|
+
"./package.json": "./package.json"
|
|
69
|
+
},
|
|
70
|
+
"files": [
|
|
71
|
+
"dist"
|
|
72
|
+
],
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@types/node": "^26.1.1",
|
|
75
|
+
"bumpp": "^11.1.0",
|
|
76
|
+
"es-check": "^9.7.1",
|
|
77
|
+
"es-check-min": "^1.0.11",
|
|
78
|
+
"tsdown": "^0.22.5",
|
|
79
|
+
"typescript": "^7.0.2",
|
|
80
|
+
"vitest": "^4.1.10"
|
|
81
|
+
},
|
|
82
|
+
"scripts": {
|
|
83
|
+
"build": "tsdown",
|
|
84
|
+
"dev": "tsdown --watch",
|
|
85
|
+
"test": "vitest",
|
|
86
|
+
"typecheck": "tsc --noEmit",
|
|
87
|
+
"release": "bumpp"
|
|
88
|
+
}
|
|
89
|
+
}
|