@levischuck/tiny-html 0.0.1
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.txt +21 -0
- package/README.md +220 -0
- package/dist/async-utils.d.ts +10 -0
- package/dist/constants.d.ts +11 -0
- package/dist/convert.d.ts +10 -0
- package/dist/entities.d.ts +15 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +733 -0
- package/dist/parser.d.ts +2 -0
- package/dist/types.d.ts +54 -0
- package/dist/utils.d.ts +34 -0
- package/dist/writer.d.ts +2 -0
- package/package.json +45 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Levi Schuck
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# tiny-html
|
|
2
|
+
|
|
3
|
+
A minimal, dependency-free TypeScript HTML parser and renderer that is easily compatible with react, hono, preact.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
### Basic Parsing and Rendering
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
import { readHtml, writeHtml, awaitHtmlNode } from '@levischuck/tiny-html';
|
|
11
|
+
|
|
12
|
+
// Parse HTML into HtmlNode structure
|
|
13
|
+
const result = readHtml('<div class="container"><h1>Hello</h1></div>');
|
|
14
|
+
console.log(result.node); // HtmlNode structure
|
|
15
|
+
console.log(result.doctype); // DOCTYPE if present
|
|
16
|
+
console.log(result.xml); // XML declaration if present
|
|
17
|
+
|
|
18
|
+
// Render HtmlNode back to HTML
|
|
19
|
+
const html = writeHtml(result);
|
|
20
|
+
// Output: <div className="container"><h1>Hello</h1></div>
|
|
21
|
+
|
|
22
|
+
// Render with options
|
|
23
|
+
const xhtml = writeHtml(result, { voidTrailingSlash: true });
|
|
24
|
+
|
|
25
|
+
// You can also render HtmlNode directly (without parsing first)
|
|
26
|
+
const node = { type: 'div', props: { children: 'Hello World' } };
|
|
27
|
+
const output = writeHtml(node);
|
|
28
|
+
// Output: <div>Hello World</div>
|
|
29
|
+
|
|
30
|
+
// Handle async HtmlNode trees (with Promise children)
|
|
31
|
+
const asyncNode = {
|
|
32
|
+
type: 'div',
|
|
33
|
+
props: {
|
|
34
|
+
children: [
|
|
35
|
+
Promise.resolve({ type: 'span', props: { children: 'Async content' } }),
|
|
36
|
+
'Regular content'
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const resolved = await awaitHtmlNode(asyncNode);
|
|
41
|
+
const asyncHtml = writeHtml(resolved);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Converting to Framework Elements
|
|
45
|
+
|
|
46
|
+
Use `htmlNodeTo` to convert HtmlNode structures to React, Preact, or other framework elements:
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { createElement } from 'react';
|
|
50
|
+
import type { ReactNode } from 'react';
|
|
51
|
+
import { readHtml, htmlNodeTo } from '@levischuck/tiny-html';
|
|
52
|
+
|
|
53
|
+
const result = readHtml('<div><span>Hello React!</span></div>');
|
|
54
|
+
const reactElement: ReactNode = htmlNodeTo(result.node, createElement);
|
|
55
|
+
// Now you can render reactElement in your React component
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This package provides a simple HTML parser and renderer with a structure compatible with React elements, making it easy to integrate with React-based rendering pipelines.
|
|
59
|
+
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
### `readHtml(html: string): ParseResult`
|
|
63
|
+
|
|
64
|
+
Parses an HTML string into a ParseResult containing HtmlNode elements.
|
|
65
|
+
|
|
66
|
+
**Returns:**
|
|
67
|
+
```typescript
|
|
68
|
+
interface ParseResult {
|
|
69
|
+
xml?: string; // XML declaration if present
|
|
70
|
+
doctype?: string; // DOCTYPE declaration if present
|
|
71
|
+
node: HtmlNode | HtmlNode[]; // Parsed content as HtmlNode
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### `writeHtml(input: HtmlNode | ParseResult, options?: WriterOptions): string`
|
|
76
|
+
|
|
77
|
+
Renders a HtmlNode or ParseResult back to an HTML string.
|
|
78
|
+
|
|
79
|
+
**Parameters:**
|
|
80
|
+
- `input: HtmlNode | ParseResult` - The content to render
|
|
81
|
+
- `options?: WriterOptions` - Rendering options (see WriterOptions below)
|
|
82
|
+
|
|
83
|
+
**Returns:** HTML string
|
|
84
|
+
|
|
85
|
+
### `awaitHtmlNode(node: HtmlNode | Promise<HtmlNode>): Promise<HtmlNode>`
|
|
86
|
+
|
|
87
|
+
Recursively awaits all Promise children in a HtmlNode tree. Useful for handling async content.
|
|
88
|
+
|
|
89
|
+
**Parameters:**
|
|
90
|
+
- `node: HtmlNode | Promise<HtmlNode>` - The node tree to resolve
|
|
91
|
+
|
|
92
|
+
**Returns:** A new HtmlNode with all promises resolved
|
|
93
|
+
|
|
94
|
+
**Note:** Incompatible types (functions, symbols) are dropped during resolution.
|
|
95
|
+
|
|
96
|
+
### `htmlNodeTo<T>(node: HtmlNode, createElement: CreateElementFn<T>): T | null`
|
|
97
|
+
|
|
98
|
+
Generic converter that transforms HtmlNode structures into any element type using a provided createElement function.
|
|
99
|
+
|
|
100
|
+
**Parameters:**
|
|
101
|
+
- `node: HtmlNode` - The HtmlNode to convert
|
|
102
|
+
- `createElement: CreateElementFn<T>` - Function that creates elements of type T
|
|
103
|
+
- Signature: `(type: string, props: CreateElementProps, ...children: T[]) => T`
|
|
104
|
+
|
|
105
|
+
**Returns:** Converted element of type T, or null
|
|
106
|
+
|
|
107
|
+
**Example with React:**
|
|
108
|
+
```typescript
|
|
109
|
+
import { createElement } from 'react';
|
|
110
|
+
import type { ReactNode } from 'react';
|
|
111
|
+
import { readHtml, htmlNodeTo } from '@levischuck/tiny-html';
|
|
112
|
+
|
|
113
|
+
const result = readHtml('<div><span>Hello</span></div>');
|
|
114
|
+
const reactElement = htmlNodeTo<ReactNode>(result.node, createElement);
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Example with Preact:**
|
|
118
|
+
```typescript
|
|
119
|
+
import { h } from 'preact';
|
|
120
|
+
import { readHtml, htmlNodeTo } from '@levischuck/tiny-html';
|
|
121
|
+
|
|
122
|
+
const result = readHtml('<div><span>Hello</span></div>');
|
|
123
|
+
const preactElement = htmlNodeTo(result.node, h);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Types
|
|
127
|
+
|
|
128
|
+
### `HtmlNode`
|
|
129
|
+
|
|
130
|
+
The core type representing parsed HTML content:
|
|
131
|
+
- HTML element: `{ type: string, props: HtmlProps }`
|
|
132
|
+
- Primitives: `string`, `number`, `boolean`, `null`, `undefined`, `bigint`
|
|
133
|
+
- Arrays: `HtmlNode[]`
|
|
134
|
+
|
|
135
|
+
### `HtmlElement`
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
interface HtmlElement {
|
|
139
|
+
type: string;
|
|
140
|
+
props: HtmlProps;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### `HtmlProps`
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
interface HtmlProps {
|
|
148
|
+
[key: string]: string | number | boolean | HtmlStyle | HtmlNode | Promise<HtmlNode>;
|
|
149
|
+
children?: HtmlNode | Promise<HtmlNode>;
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### `HtmlStyle`
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
interface HtmlStyle {
|
|
157
|
+
[key: string]: string;
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### `CreateElementFn<T>`
|
|
162
|
+
|
|
163
|
+
Type for createElement functions used with `htmlNodeTo`.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
type CreateElementFn<T> = (
|
|
167
|
+
type: string,
|
|
168
|
+
props: CreateElementProps,
|
|
169
|
+
...children: T[]
|
|
170
|
+
) => T;
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `CreateElementProps`
|
|
174
|
+
|
|
175
|
+
Props object passed to createElement functions.
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
type CreateElementProps = Record<string, any>;
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### `ParseResult`
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
interface ParseResult {
|
|
185
|
+
xml?: string;
|
|
186
|
+
doctype?: string;
|
|
187
|
+
node: HtmlNode | HtmlNode[];
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### `WriterOptions`
|
|
192
|
+
|
|
193
|
+
Options for controlling HTML output formatting.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
interface WriterOptions {
|
|
197
|
+
useCDataForScripts?: boolean; // Wrap <script> content in CDATA
|
|
198
|
+
useCDataForStyles?: boolean; // Wrap <style> content in CDATA
|
|
199
|
+
xml?: string; // XML declaration to prepend
|
|
200
|
+
doctype?: string; // DOCTYPE declaration to prepend
|
|
201
|
+
voidTrailingSlash?: boolean; // Add trailing slash to void elements (e.g., <br />)
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Options:**
|
|
206
|
+
- `useCDataForScripts?: boolean` - When true, wraps `<script>` content in CDATA sections. Useful for XHTML output. Default: `false`
|
|
207
|
+
- `useCDataForStyles?: boolean` - When true, wraps `<style>` content in CDATA sections. Useful for XHTML output. Default: `false`
|
|
208
|
+
- `xml?: string` - XML declaration to prepend to the output (e.g., `<?xml version="1.0" encoding="UTF-8"?>`)
|
|
209
|
+
- `doctype?: string` - DOCTYPE declaration to prepend to the output (e.g., `<!DOCTYPE html>`)
|
|
210
|
+
- `voidTrailingSlash?: boolean` - When true, adds trailing slash to void elements like `<br/>`, `<img/>`. Useful for XHTML compatibility. Default: `false`
|
|
211
|
+
|
|
212
|
+
## Why use this?
|
|
213
|
+
|
|
214
|
+
There are many other great libraries to parse HTML.
|
|
215
|
+
I need to process things on the edge and I can rely on this being fast and available on every platform I want to use it.
|
|
216
|
+
Also.. I'm tired of writing little parsers here and there just to put them into a hono-jsx like format for post-processing.
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
MIT Licensed.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HtmlNode } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Recursively awaits all Promise children in a HtmlNode tree
|
|
4
|
+
* Returns a new HtmlNode with all promises resolved
|
|
5
|
+
* Incompatible types (functions, symbols, etc.) are dropped
|
|
6
|
+
*
|
|
7
|
+
* @param node - A HtmlNode that may contain promises
|
|
8
|
+
* @returns An HtmlNode with all promises resolved
|
|
9
|
+
*/
|
|
10
|
+
export declare function awaitReactNode(node: HtmlNode | Promise<HtmlNode>): Promise<HtmlNode>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const NAMESPACE_HTML = "http://www.w3.org/1999/xhtml";
|
|
2
|
+
export declare const NAMESPACE_SVG = "http://www.w3.org/2000/svg";
|
|
3
|
+
export declare const NAMESPACE_MATHML = "http://www.w3.org/1998/Math/MathML";
|
|
4
|
+
export declare const VOID_ELEMENTS: Set<string>;
|
|
5
|
+
export declare const NEVER_SELF_CLOSE: Set<string>;
|
|
6
|
+
export declare const AUTO_CLOSING_SIBLINGS: Map<string, Set<string>>;
|
|
7
|
+
export declare const WHITESPACE_SENSITIVE: Set<string>;
|
|
8
|
+
export declare const SVG_TAG_CASE_MAP: Map<string, string>;
|
|
9
|
+
export declare const SVG_ATTR_CASE_MAP: Map<string, string>;
|
|
10
|
+
export declare const HTML_ENTITIES: Record<string, string>;
|
|
11
|
+
export declare const CHAR_TO_ENTITY: Record<string, string>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { HtmlNode } from './types.ts';
|
|
2
|
+
export type CreateElementProps = Record<string, any>;
|
|
3
|
+
export type CreateElementFn<T> = (type: string, props: CreateElementProps, ...children: any[]) => T;
|
|
4
|
+
/**
|
|
5
|
+
* Generic converter from HtmlNode to any element type T
|
|
6
|
+
* @param node - The HtmlNode to convert
|
|
7
|
+
* @param createElement - Function that creates elements of type T
|
|
8
|
+
* @returns Converted element of type T, or null
|
|
9
|
+
*/
|
|
10
|
+
export declare function htmlNodeTo<T>(node: HtmlNode, createElement: CreateElementFn<T>): T | null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decodes HTML entities to their UTF-8 representation
|
|
3
|
+
* Handles named entities (<, >, &, etc.), decimal (<), and hex (<) entities
|
|
4
|
+
*/
|
|
5
|
+
export declare function decodeHtmlEntities(text: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Encodes special characters as HTML entities
|
|
8
|
+
* @param text - The text to encode
|
|
9
|
+
* @param inAttribute - If true, also encode quotes
|
|
10
|
+
*/
|
|
11
|
+
export declare function encodeHtmlEntities(text: string, inAttribute?: boolean): string;
|
|
12
|
+
/**
|
|
13
|
+
* Escape CDATA content - split ]]> into ]]]]><![CDATA[>
|
|
14
|
+
*/
|
|
15
|
+
export declare function escapeCData(content: string): string;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ParseResult, HtmlNode, WriterOptions } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Parses HTML string into a ParseResult containing HtmlNode
|
|
4
|
+
*/
|
|
5
|
+
export declare function readHtml(html: string): ParseResult;
|
|
6
|
+
/**
|
|
7
|
+
* Renders HtmlNode or ParseResult to HTML string
|
|
8
|
+
*/
|
|
9
|
+
export declare function writeHtml(input: HtmlNode | ParseResult, options?: WriterOptions): string;
|
|
10
|
+
/**
|
|
11
|
+
* Recursively awaits all Promise children in a HtmlNode tree
|
|
12
|
+
* Returns a new HtmlNode with all promises resolved
|
|
13
|
+
*/
|
|
14
|
+
export declare function awaitHtmlNode(node: HtmlNode | Promise<HtmlNode>): Promise<HtmlNode>;
|
|
15
|
+
export { htmlNodeTo } from './convert.ts';
|
|
16
|
+
export type { CreateElementFn, CreateElementProps } from './convert.ts';
|
|
17
|
+
export type { WriterOptions, ParseResult, HtmlNode, HtmlElement, HtmlProps, HtmlStyle } from './types.ts';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,733 @@
|
|
|
1
|
+
const F = /* @__PURE__ */ new Set([
|
|
2
|
+
"area",
|
|
3
|
+
"base",
|
|
4
|
+
"br",
|
|
5
|
+
"col",
|
|
6
|
+
"embed",
|
|
7
|
+
"hr",
|
|
8
|
+
"img",
|
|
9
|
+
"input",
|
|
10
|
+
"link",
|
|
11
|
+
"meta",
|
|
12
|
+
"param",
|
|
13
|
+
"source",
|
|
14
|
+
"track",
|
|
15
|
+
"wbr"
|
|
16
|
+
]), Q = /* @__PURE__ */ new Set([
|
|
17
|
+
// Containers
|
|
18
|
+
"div",
|
|
19
|
+
"span",
|
|
20
|
+
"p",
|
|
21
|
+
"section",
|
|
22
|
+
"article",
|
|
23
|
+
"aside",
|
|
24
|
+
"header",
|
|
25
|
+
"footer",
|
|
26
|
+
"nav",
|
|
27
|
+
"main",
|
|
28
|
+
// Forms
|
|
29
|
+
"button",
|
|
30
|
+
"textarea",
|
|
31
|
+
"select",
|
|
32
|
+
"label",
|
|
33
|
+
"form",
|
|
34
|
+
"fieldset",
|
|
35
|
+
"legend",
|
|
36
|
+
"optgroup",
|
|
37
|
+
// Lists
|
|
38
|
+
"ul",
|
|
39
|
+
"ol",
|
|
40
|
+
"li",
|
|
41
|
+
"dl",
|
|
42
|
+
"dt",
|
|
43
|
+
"dd",
|
|
44
|
+
// Script/style
|
|
45
|
+
"script",
|
|
46
|
+
"style",
|
|
47
|
+
// Formatting
|
|
48
|
+
"a",
|
|
49
|
+
"b",
|
|
50
|
+
"i",
|
|
51
|
+
"strong",
|
|
52
|
+
"em",
|
|
53
|
+
"u",
|
|
54
|
+
"s",
|
|
55
|
+
"del",
|
|
56
|
+
"ins",
|
|
57
|
+
"mark",
|
|
58
|
+
"small",
|
|
59
|
+
"sub",
|
|
60
|
+
"sup",
|
|
61
|
+
"code",
|
|
62
|
+
"kbd",
|
|
63
|
+
"samp",
|
|
64
|
+
"var",
|
|
65
|
+
"abbr",
|
|
66
|
+
"cite",
|
|
67
|
+
"dfn",
|
|
68
|
+
"q",
|
|
69
|
+
"time",
|
|
70
|
+
// Graphics
|
|
71
|
+
"canvas",
|
|
72
|
+
"svg",
|
|
73
|
+
// Tables
|
|
74
|
+
"table",
|
|
75
|
+
"tr",
|
|
76
|
+
"td",
|
|
77
|
+
"th",
|
|
78
|
+
"thead",
|
|
79
|
+
"tbody",
|
|
80
|
+
"tfoot",
|
|
81
|
+
"caption",
|
|
82
|
+
"colgroup",
|
|
83
|
+
// Headings
|
|
84
|
+
"h1",
|
|
85
|
+
"h2",
|
|
86
|
+
"h3",
|
|
87
|
+
"h4",
|
|
88
|
+
"h5",
|
|
89
|
+
"h6",
|
|
90
|
+
// Media
|
|
91
|
+
"video",
|
|
92
|
+
"audio",
|
|
93
|
+
"picture",
|
|
94
|
+
"figure",
|
|
95
|
+
"figcaption",
|
|
96
|
+
// Interactive
|
|
97
|
+
"details",
|
|
98
|
+
"summary",
|
|
99
|
+
"dialog",
|
|
100
|
+
// Other
|
|
101
|
+
"blockquote",
|
|
102
|
+
"pre",
|
|
103
|
+
"address",
|
|
104
|
+
"noscript",
|
|
105
|
+
"iframe",
|
|
106
|
+
"object",
|
|
107
|
+
"map",
|
|
108
|
+
"html",
|
|
109
|
+
"head",
|
|
110
|
+
"body",
|
|
111
|
+
"title",
|
|
112
|
+
"meta"
|
|
113
|
+
]), q = /* @__PURE__ */ new Map([
|
|
114
|
+
["p", /* @__PURE__ */ new Set(["p"])],
|
|
115
|
+
["li", /* @__PURE__ */ new Set(["li"])],
|
|
116
|
+
["dt", /* @__PURE__ */ new Set(["dt", "dd"])],
|
|
117
|
+
["dd", /* @__PURE__ */ new Set(["dt", "dd"])],
|
|
118
|
+
["option", /* @__PURE__ */ new Set(["option"])],
|
|
119
|
+
["optgroup", /* @__PURE__ */ new Set(["optgroup"])],
|
|
120
|
+
["thead", /* @__PURE__ */ new Set(["tbody", "tfoot"])],
|
|
121
|
+
["tbody", /* @__PURE__ */ new Set(["thead", "tfoot"])],
|
|
122
|
+
["tfoot", /* @__PURE__ */ new Set(["thead", "tbody"])],
|
|
123
|
+
["tr", /* @__PURE__ */ new Set(["tr"])],
|
|
124
|
+
["td", /* @__PURE__ */ new Set(["td", "th"])],
|
|
125
|
+
["th", /* @__PURE__ */ new Set(["td", "th"])]
|
|
126
|
+
]), V = /* @__PURE__ */ new Map([
|
|
127
|
+
["altglyph", "altGlyph"],
|
|
128
|
+
["altglyphdef", "altGlyphDef"],
|
|
129
|
+
["altglyphitem", "altGlyphItem"],
|
|
130
|
+
["animatecolor", "animateColor"],
|
|
131
|
+
["animatemotion", "animateMotion"],
|
|
132
|
+
["animatetransform", "animateTransform"],
|
|
133
|
+
["clippath", "clipPath"],
|
|
134
|
+
["feblend", "feBlend"],
|
|
135
|
+
["fecolormatrix", "feColorMatrix"],
|
|
136
|
+
["fecomponenttransfer", "feComponentTransfer"],
|
|
137
|
+
["fecomposite", "feComposite"],
|
|
138
|
+
["feconvolvematrix", "feConvolveMatrix"],
|
|
139
|
+
["fediffuselighting", "feDiffuseLighting"],
|
|
140
|
+
["fedisplacementmap", "feDisplacementMap"],
|
|
141
|
+
["fedistantlight", "feDistantLight"],
|
|
142
|
+
["fedropshadow", "feDropShadow"],
|
|
143
|
+
["feflood", "feFlood"],
|
|
144
|
+
["fefunca", "feFuncA"],
|
|
145
|
+
["fefuncb", "feFuncB"],
|
|
146
|
+
["fefuncg", "feFuncG"],
|
|
147
|
+
["fefuncr", "feFuncR"],
|
|
148
|
+
["fegaussianblur", "feGaussianBlur"],
|
|
149
|
+
["feimage", "feImage"],
|
|
150
|
+
["femerge", "feMerge"],
|
|
151
|
+
["femergenode", "feMergeNode"],
|
|
152
|
+
["femorphology", "feMorphology"],
|
|
153
|
+
["feoffset", "feOffset"],
|
|
154
|
+
["fepointlight", "fePointLight"],
|
|
155
|
+
["fespecularlighting", "feSpecularLighting"],
|
|
156
|
+
["fespotlight", "feSpotLight"],
|
|
157
|
+
["fetile", "feTile"],
|
|
158
|
+
["feturbulence", "feTurbulence"],
|
|
159
|
+
["foreignobject", "foreignObject"],
|
|
160
|
+
["glyphref", "glyphRef"],
|
|
161
|
+
["lineargradient", "linearGradient"],
|
|
162
|
+
["radialgradient", "radialGradient"],
|
|
163
|
+
["textpath", "textPath"]
|
|
164
|
+
]), z = /* @__PURE__ */ new Map([
|
|
165
|
+
["attributename", "attributeName"],
|
|
166
|
+
["attributetype", "attributeType"],
|
|
167
|
+
["basefrequency", "baseFrequency"],
|
|
168
|
+
["baseprofile", "baseProfile"],
|
|
169
|
+
["calcmode", "calcMode"],
|
|
170
|
+
["clippathunits", "clipPathUnits"],
|
|
171
|
+
["diffuseconstant", "diffuseConstant"],
|
|
172
|
+
["edgemode", "edgeMode"],
|
|
173
|
+
["filterunits", "filterUnits"],
|
|
174
|
+
["glyphref", "glyphRef"],
|
|
175
|
+
["gradienttransform", "gradientTransform"],
|
|
176
|
+
["gradientunits", "gradientUnits"],
|
|
177
|
+
["kernelmatrix", "kernelMatrix"],
|
|
178
|
+
["kernelunitlength", "kernelUnitLength"],
|
|
179
|
+
["keypoints", "keyPoints"],
|
|
180
|
+
["keysplines", "keySplines"],
|
|
181
|
+
["keytimes", "keyTimes"],
|
|
182
|
+
["lengthadjust", "lengthAdjust"],
|
|
183
|
+
["limitingconeangle", "limitingConeAngle"],
|
|
184
|
+
["markerheight", "markerHeight"],
|
|
185
|
+
["markerunits", "markerUnits"],
|
|
186
|
+
["markerwidth", "markerWidth"],
|
|
187
|
+
["maskcontentunits", "maskContentUnits"],
|
|
188
|
+
["maskunits", "maskUnits"],
|
|
189
|
+
["numoctaves", "numOctaves"],
|
|
190
|
+
["pathlength", "pathLength"],
|
|
191
|
+
["patterncontentunits", "patternContentUnits"],
|
|
192
|
+
["patterntransform", "patternTransform"],
|
|
193
|
+
["patternunits", "patternUnits"],
|
|
194
|
+
["pointsatx", "pointsAtX"],
|
|
195
|
+
["pointsaty", "pointsAtY"],
|
|
196
|
+
["pointsatz", "pointsAtZ"],
|
|
197
|
+
["preservealpha", "preserveAlpha"],
|
|
198
|
+
["preserveaspectratio", "preserveAspectRatio"],
|
|
199
|
+
["primitiveunits", "primitiveUnits"],
|
|
200
|
+
["refx", "refX"],
|
|
201
|
+
["refy", "refY"],
|
|
202
|
+
["repeatcount", "repeatCount"],
|
|
203
|
+
["repeatdur", "repeatDur"],
|
|
204
|
+
["requiredextensions", "requiredExtensions"],
|
|
205
|
+
["requiredfeatures", "requiredFeatures"],
|
|
206
|
+
["specularconstant", "specularConstant"],
|
|
207
|
+
["specularexponent", "specularExponent"],
|
|
208
|
+
["spreadmethod", "spreadMethod"],
|
|
209
|
+
["startoffset", "startOffset"],
|
|
210
|
+
["stddeviation", "stdDeviation"],
|
|
211
|
+
["stitchtiles", "stitchTiles"],
|
|
212
|
+
["surfacescale", "surfaceScale"],
|
|
213
|
+
["systemlanguage", "systemLanguage"],
|
|
214
|
+
["tablevalues", "tableValues"],
|
|
215
|
+
["targetx", "targetX"],
|
|
216
|
+
["targety", "targetY"],
|
|
217
|
+
["textlength", "textLength"],
|
|
218
|
+
["viewbox", "viewBox"],
|
|
219
|
+
["viewtarget", "viewTarget"],
|
|
220
|
+
["xchannelselector", "xChannelSelector"],
|
|
221
|
+
["ychannelselector", "yChannelSelector"],
|
|
222
|
+
["zoomandpan", "zoomAndPan"]
|
|
223
|
+
]), I = {
|
|
224
|
+
lt: "<",
|
|
225
|
+
gt: ">",
|
|
226
|
+
amp: "&",
|
|
227
|
+
quot: '"',
|
|
228
|
+
apos: "'",
|
|
229
|
+
nbsp: " ",
|
|
230
|
+
iexcl: "¡",
|
|
231
|
+
cent: "¢",
|
|
232
|
+
pound: "£",
|
|
233
|
+
curren: "¤",
|
|
234
|
+
yen: "¥",
|
|
235
|
+
brvbar: "¦",
|
|
236
|
+
sect: "§",
|
|
237
|
+
uml: "¨",
|
|
238
|
+
copy: "©",
|
|
239
|
+
ordf: "ª",
|
|
240
|
+
laquo: "«",
|
|
241
|
+
not: "¬",
|
|
242
|
+
shy: "",
|
|
243
|
+
reg: "®",
|
|
244
|
+
macr: "¯",
|
|
245
|
+
deg: "°",
|
|
246
|
+
plusmn: "±",
|
|
247
|
+
sup2: "²",
|
|
248
|
+
sup3: "³",
|
|
249
|
+
acute: "´",
|
|
250
|
+
micro: "µ",
|
|
251
|
+
para: "¶",
|
|
252
|
+
middot: "·",
|
|
253
|
+
cedil: "¸",
|
|
254
|
+
sup1: "¹",
|
|
255
|
+
ordm: "º",
|
|
256
|
+
raquo: "»",
|
|
257
|
+
frac14: "¼",
|
|
258
|
+
frac12: "½",
|
|
259
|
+
frac34: "¾",
|
|
260
|
+
iquest: "¿",
|
|
261
|
+
times: "×",
|
|
262
|
+
divide: "÷",
|
|
263
|
+
ndash: "–",
|
|
264
|
+
mdash: "—",
|
|
265
|
+
lsquo: "‘",
|
|
266
|
+
rsquo: "’",
|
|
267
|
+
sbquo: "‚",
|
|
268
|
+
ldquo: "“",
|
|
269
|
+
rdquo: "”",
|
|
270
|
+
bdquo: "„",
|
|
271
|
+
dagger: "†",
|
|
272
|
+
Dagger: "‡",
|
|
273
|
+
bull: "•",
|
|
274
|
+
hellip: "…",
|
|
275
|
+
permil: "‰",
|
|
276
|
+
prime: "′",
|
|
277
|
+
Prime: "″",
|
|
278
|
+
lsaquo: "‹",
|
|
279
|
+
rsaquo: "›",
|
|
280
|
+
oline: "‾",
|
|
281
|
+
frasl: "⁄",
|
|
282
|
+
euro: "€",
|
|
283
|
+
trade: "™",
|
|
284
|
+
larr: "←",
|
|
285
|
+
uarr: "↑",
|
|
286
|
+
rarr: "→",
|
|
287
|
+
darr: "↓",
|
|
288
|
+
harr: "↔",
|
|
289
|
+
lArr: "⇐",
|
|
290
|
+
uArr: "⇑",
|
|
291
|
+
rArr: "⇒",
|
|
292
|
+
dArr: "⇓",
|
|
293
|
+
hArr: "⇔"
|
|
294
|
+
}, B = {};
|
|
295
|
+
for (const [e, r] of Object.entries(I))
|
|
296
|
+
B[r] || (B[r] = e);
|
|
297
|
+
function v(e) {
|
|
298
|
+
return !e || typeof e != "string" || !e.includes("&") ? e : e.replace(/&(?:#[xX]([0-9a-fA-F]+)|#(\d+)|([a-zA-Z][a-zA-Z0-9]*));/g, (r, n, u, f) => {
|
|
299
|
+
if (n) {
|
|
300
|
+
const a = parseInt(n, 16);
|
|
301
|
+
return String.fromCodePoint(a);
|
|
302
|
+
} else if (u) {
|
|
303
|
+
const a = parseInt(u, 10);
|
|
304
|
+
return String.fromCodePoint(a);
|
|
305
|
+
} else if (f && I[f])
|
|
306
|
+
return I[f];
|
|
307
|
+
return r;
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
function G(e, r = !1) {
|
|
311
|
+
if (!e || typeof e != "string")
|
|
312
|
+
return e;
|
|
313
|
+
let n = e;
|
|
314
|
+
return n = n.replace(/&/g, "&"), n = n.replace(/</g, "<"), n = n.replace(/>/g, ">"), r && (n = n.replace(/"/g, """)), n;
|
|
315
|
+
}
|
|
316
|
+
function Z(e) {
|
|
317
|
+
return e.replace(/\]\]>/g, "]]]]></g, (r, n) => n.toUpperCase());
|
|
321
|
+
}
|
|
322
|
+
function $(e) {
|
|
323
|
+
return e.replace(/[A-Z]/g, (r) => `-${r.toLowerCase()}`);
|
|
324
|
+
}
|
|
325
|
+
function y(e, r, n) {
|
|
326
|
+
return new TextDecoder("utf-8").decode(e.slice(r, n));
|
|
327
|
+
}
|
|
328
|
+
function S(e) {
|
|
329
|
+
return e === 32 || e === 9 || e === 10 || e === 13;
|
|
330
|
+
}
|
|
331
|
+
function N(e) {
|
|
332
|
+
return e >= 97 && e <= 122 || // a-z
|
|
333
|
+
e >= 65 && e <= 90 || // A-Z
|
|
334
|
+
e >= 48 && e <= 57 || // 0-9
|
|
335
|
+
e === 45 || // -
|
|
336
|
+
e === 95 || // _
|
|
337
|
+
e === 58;
|
|
338
|
+
}
|
|
339
|
+
function K(e) {
|
|
340
|
+
const n = new TextEncoder().encode(e), u = {
|
|
341
|
+
node: []
|
|
342
|
+
}, f = [], a = [];
|
|
343
|
+
let c = "HTML", i = "TEXT", t = 0, p = 0, g = 0, A = 0, E = 0, d = "", P = 0, h = null;
|
|
344
|
+
function M() {
|
|
345
|
+
return a.length > 0 ? a[a.length - 1].children : f;
|
|
346
|
+
}
|
|
347
|
+
function X(s, o) {
|
|
348
|
+
if (s >= o) return;
|
|
349
|
+
const l = y(n, s, o), T = v(l);
|
|
350
|
+
T.length > 0 && M().push(T);
|
|
351
|
+
}
|
|
352
|
+
function U(s, o) {
|
|
353
|
+
if (s >= o) return;
|
|
354
|
+
const l = y(n, s, o);
|
|
355
|
+
l.length > 0 && M().push(l);
|
|
356
|
+
}
|
|
357
|
+
function C(s, o) {
|
|
358
|
+
const l = s.toLowerCase();
|
|
359
|
+
return o === "SVG" && V.has(l) ? V.get(l) : l;
|
|
360
|
+
}
|
|
361
|
+
function _(s, o) {
|
|
362
|
+
const l = s.toLowerCase();
|
|
363
|
+
if (l === "class") return "className";
|
|
364
|
+
if (l === "for") return "htmlFor";
|
|
365
|
+
if (o === "SVG")
|
|
366
|
+
return z.has(l) ? z.get(l) : s;
|
|
367
|
+
if (o === "HTML") {
|
|
368
|
+
const T = k(l);
|
|
369
|
+
return l === "class" || l === "for" ? l === "class" ? "className" : "htmlFor" : T;
|
|
370
|
+
}
|
|
371
|
+
return l;
|
|
372
|
+
}
|
|
373
|
+
function R(s) {
|
|
374
|
+
const o = C(s, c);
|
|
375
|
+
for (let l = a.length - 1; l >= 0; l--)
|
|
376
|
+
if (a[l].type === o) {
|
|
377
|
+
for (let T = a.length - 1; T >= l; T--) {
|
|
378
|
+
const m = a.pop(), b = {
|
|
379
|
+
type: m.type,
|
|
380
|
+
props: {
|
|
381
|
+
...m.props,
|
|
382
|
+
children: m.children.length === 1 ? m.children[0] : m.children
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
a.length > 0 ? a[a.length - 1].children.push(b) : f.push(b), (m.type === "svg" || m.type === "math") && (c = "HTML");
|
|
386
|
+
}
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function w(s, o, l) {
|
|
391
|
+
const T = C(s, c);
|
|
392
|
+
if (a.length > 0 && q.has(T)) {
|
|
393
|
+
const b = q.get(T), j = a[a.length - 1].type;
|
|
394
|
+
b.has(j) && R(j);
|
|
395
|
+
}
|
|
396
|
+
let m = c;
|
|
397
|
+
if (T === "svg" ? m = "SVG" : T === "math" && (m = "MATHML"), F.has(T) || l) {
|
|
398
|
+
const b = {
|
|
399
|
+
type: T,
|
|
400
|
+
props: o
|
|
401
|
+
};
|
|
402
|
+
M().push(b);
|
|
403
|
+
} else {
|
|
404
|
+
const b = {
|
|
405
|
+
type: T,
|
|
406
|
+
props: o,
|
|
407
|
+
children: [],
|
|
408
|
+
namespace: m
|
|
409
|
+
};
|
|
410
|
+
a.push(b), c = m;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
for (; t < n.length; ) {
|
|
414
|
+
const s = n[t];
|
|
415
|
+
switch (i) {
|
|
416
|
+
case "TEXT":
|
|
417
|
+
s === 60 && (X(p, t), i = "TAG_OPEN"), t++;
|
|
418
|
+
break;
|
|
419
|
+
case "TAG_OPEN":
|
|
420
|
+
s === 33 ? n[t + 1] === 45 && n[t + 2] === 45 ? (i = "COMMENT", t += 3) : n[t + 1] === 68 || n[t + 1] === 100 ? y(n, t, Math.min(t + 20, n.length)).toLowerCase().startsWith("!doctype") ? (i = "DOCTYPE", g = t, t++) : (p = t - 1, i = "TEXT") : n[t + 1] === 91 && n[t + 2] === 67 && y(n, t, Math.min(t + 9, n.length)).startsWith("![CDATA[") ? (i = "CDATA", p = t + 8, t += 8) : (p = t - 1, i = "TEXT") : s === 63 ? (i = "PROCESSING_INSTRUCTION", g = t - 1, t++) : s === 47 ? (i = "TAG_CLOSE_START", t++) : N(s) ? (g = t, i = "TAG_NAME", h = null, t++) : (p = t - 1, i = "TEXT");
|
|
421
|
+
break;
|
|
422
|
+
case "TAG_NAME":
|
|
423
|
+
if (S(s)) {
|
|
424
|
+
const o = y(n, g, t), l = o.toLowerCase();
|
|
425
|
+
h = {
|
|
426
|
+
type: o,
|
|
427
|
+
props: {},
|
|
428
|
+
children: [],
|
|
429
|
+
namespace: l === "svg" ? "SVG" : l === "math" ? "MATHML" : c
|
|
430
|
+
}, i = "ATTRIBUTES", t++;
|
|
431
|
+
} else if (s === 62) {
|
|
432
|
+
const o = y(n, g, t);
|
|
433
|
+
w(o, {}, !1);
|
|
434
|
+
const l = C(o, c);
|
|
435
|
+
l === "script" ? (i = "SCRIPT_CONTENT", p = t + 1) : l === "style" ? (i = "STYLE_CONTENT", p = t + 1) : (i = "TEXT", p = t + 1), t++;
|
|
436
|
+
} else s === 47 ? (i = "TAG_CLOSE_SELF", t++) : N(s) ? t++ : (p = g - 1, i = "TEXT");
|
|
437
|
+
break;
|
|
438
|
+
case "ATTRIBUTES":
|
|
439
|
+
if (S(s))
|
|
440
|
+
t++;
|
|
441
|
+
else if (s === 62) {
|
|
442
|
+
const o = h.type;
|
|
443
|
+
w(o, h.props, !1);
|
|
444
|
+
const l = C(o, c);
|
|
445
|
+
l === "script" ? (i = "SCRIPT_CONTENT", p = t + 1) : l === "style" ? (i = "STYLE_CONTENT", p = t + 1) : (i = "TEXT", p = t + 1), t++;
|
|
446
|
+
} else s === 47 ? (i = "TAG_CLOSE_SELF", t++) : N(s) ? (A = t, i = "ATTRIBUTE_NAME", t++) : (p = g - 1, i = "TEXT");
|
|
447
|
+
break;
|
|
448
|
+
case "ATTRIBUTE_NAME":
|
|
449
|
+
if (S(s)) {
|
|
450
|
+
d = y(n, A, t);
|
|
451
|
+
const o = _(d, h.namespace);
|
|
452
|
+
h.props[o] = !0, d = "", i = "ATTRIBUTES", t++;
|
|
453
|
+
} else if (s === 61)
|
|
454
|
+
d = y(n, A, t), i = "ATTRIBUTE_VALUE_START", t++;
|
|
455
|
+
else if (s === 62) {
|
|
456
|
+
d = y(n, A, t);
|
|
457
|
+
const o = _(d, h.namespace);
|
|
458
|
+
h.props[o] = !0, d = "";
|
|
459
|
+
const l = h.type;
|
|
460
|
+
w(l, h.props, !1);
|
|
461
|
+
const T = C(l, c);
|
|
462
|
+
T === "script" ? (i = "SCRIPT_CONTENT", p = t + 1) : T === "style" ? (i = "STYLE_CONTENT", p = t + 1) : (i = "TEXT", p = t + 1), t++;
|
|
463
|
+
} else if (s === 47) {
|
|
464
|
+
d = y(n, A, t);
|
|
465
|
+
const o = _(d, h.namespace);
|
|
466
|
+
h.props[o] = !0, d = "", i = "TAG_CLOSE_SELF", t++;
|
|
467
|
+
} else N(s) ? t++ : (p = g - 1, i = "TEXT");
|
|
468
|
+
break;
|
|
469
|
+
case "ATTRIBUTE_VALUE_START":
|
|
470
|
+
S(s) ? t++ : s === 34 || s === 39 ? (P = s, E = t + 1, i = "ATTRIBUTE_VALUE_QUOTED", t++) : (E = t, i = "ATTRIBUTE_VALUE_UNQUOTED");
|
|
471
|
+
break;
|
|
472
|
+
case "ATTRIBUTE_VALUE_QUOTED":
|
|
473
|
+
if (s === P) {
|
|
474
|
+
const o = y(n, E, t), l = v(o), T = _(d, h.namespace);
|
|
475
|
+
T === "style" ? h.props[T] = D(l) : h.props[T] = l, d = "", i = "ATTRIBUTES", t++;
|
|
476
|
+
} else
|
|
477
|
+
t++;
|
|
478
|
+
break;
|
|
479
|
+
case "ATTRIBUTE_VALUE_UNQUOTED":
|
|
480
|
+
if (S(s) || s === 62 || s === 47) {
|
|
481
|
+
const o = y(n, E, t), l = v(o), T = _(d, h.namespace);
|
|
482
|
+
T === "style" ? h.props[T] = D(l) : h.props[T] = l, d = "", i = "ATTRIBUTES";
|
|
483
|
+
} else
|
|
484
|
+
t++;
|
|
485
|
+
break;
|
|
486
|
+
case "TAG_CLOSE_SELF":
|
|
487
|
+
if (s === 62) {
|
|
488
|
+
const o = h.type;
|
|
489
|
+
w(o, h.props, !0), i = "TEXT", p = t + 1, t++;
|
|
490
|
+
} else
|
|
491
|
+
p = g - 1, i = "TEXT";
|
|
492
|
+
break;
|
|
493
|
+
case "TAG_CLOSE_START":
|
|
494
|
+
N(s) ? (g = t, i = "TAG_CLOSE_NAME", t++) : (p = t - 2, i = "TEXT");
|
|
495
|
+
break;
|
|
496
|
+
case "TAG_CLOSE_NAME":
|
|
497
|
+
if (s === 62) {
|
|
498
|
+
const o = y(n, g, t);
|
|
499
|
+
R(o), i = "TEXT", p = t + 1, t++;
|
|
500
|
+
} else S(s) || N(s) ? t++ : (p = g - 2, i = "TEXT");
|
|
501
|
+
break;
|
|
502
|
+
case "COMMENT":
|
|
503
|
+
s === 45 && n[t + 1] === 45 && n[t + 2] === 62 ? (i = "TEXT", p = t + 3, t += 3) : t++;
|
|
504
|
+
break;
|
|
505
|
+
case "DOCTYPE":
|
|
506
|
+
if (s === 62) {
|
|
507
|
+
const o = y(n, g, t + 1);
|
|
508
|
+
u.doctype = "<" + o, i = "TEXT", p = t + 1, t++;
|
|
509
|
+
} else
|
|
510
|
+
t++;
|
|
511
|
+
break;
|
|
512
|
+
case "CDATA":
|
|
513
|
+
s === 93 && n[t + 1] === 93 && n[t + 2] === 62 ? (U(p, t), i = "TEXT", p = t + 3, t += 3) : t++;
|
|
514
|
+
break;
|
|
515
|
+
case "PROCESSING_INSTRUCTION":
|
|
516
|
+
if (s === 63 && n[t + 1] === 62) {
|
|
517
|
+
const o = y(n, g, t + 2);
|
|
518
|
+
u.xml = o, i = "TEXT", p = t + 2, t += 2;
|
|
519
|
+
} else
|
|
520
|
+
t++;
|
|
521
|
+
break;
|
|
522
|
+
case "SCRIPT_CONTENT":
|
|
523
|
+
case "STYLE_CONTENT":
|
|
524
|
+
if (s === 60 && n[t + 1] === 47) {
|
|
525
|
+
const o = i === "SCRIPT_CONTENT" ? "script" : "style", l = "</" + o, T = y(n, t, Math.min(t + l.length + 1, n.length)).toLowerCase();
|
|
526
|
+
if (T.startsWith(l) && (T[l.length] === ">" || S(T.charCodeAt(l.length)))) {
|
|
527
|
+
U(p, t);
|
|
528
|
+
let m = t + l.length;
|
|
529
|
+
for (; m < n.length && n[m] !== 62; ) m++;
|
|
530
|
+
R(o), i = "TEXT", p = m + 1, t = m + 1;
|
|
531
|
+
} else
|
|
532
|
+
t++;
|
|
533
|
+
} else
|
|
534
|
+
t++;
|
|
535
|
+
break;
|
|
536
|
+
default:
|
|
537
|
+
t++;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
for (i === "TEXT" ? X(p, t) : (i === "SCRIPT_CONTENT" || i === "STYLE_CONTENT") && U(p, t); a.length > 0; ) {
|
|
541
|
+
const s = a.pop(), o = {
|
|
542
|
+
type: s.type,
|
|
543
|
+
props: {
|
|
544
|
+
...s.props,
|
|
545
|
+
children: s.children.length === 1 ? s.children[0] : s.children
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
a.length > 0 ? a[a.length - 1].children.push(o) : f.push(o);
|
|
549
|
+
}
|
|
550
|
+
return f.length === 0 ? u.node = null : f.length === 1 ? u.node = f[0] : u.node = f, u;
|
|
551
|
+
}
|
|
552
|
+
function D(e) {
|
|
553
|
+
const r = {}, u = v(e).split(/;(?![^(]*\))/);
|
|
554
|
+
for (const f of u) {
|
|
555
|
+
const a = f.indexOf(":");
|
|
556
|
+
if (a === -1) continue;
|
|
557
|
+
const c = f.substring(0, a).trim(), i = f.substring(a + 1).trim();
|
|
558
|
+
c && i && (r[k(c)] = i);
|
|
559
|
+
}
|
|
560
|
+
return r;
|
|
561
|
+
}
|
|
562
|
+
function H(e, r = {}) {
|
|
563
|
+
const n = [];
|
|
564
|
+
let u, f, a;
|
|
565
|
+
if (e && typeof e == "object" && "node" in e) {
|
|
566
|
+
const p = e;
|
|
567
|
+
u = p.node, f = p.xml ?? r.xml, a = p.doctype ?? r.doctype;
|
|
568
|
+
} else
|
|
569
|
+
u = e, f = r.xml, a = r.doctype;
|
|
570
|
+
f && (n.push(f), f.endsWith(`
|
|
571
|
+
`) || n.push(`
|
|
572
|
+
`)), a && (n.push(a), a.endsWith(`
|
|
573
|
+
`) || n.push(`
|
|
574
|
+
`));
|
|
575
|
+
const c = r.useCDataForScripts ?? !1, i = r.useCDataForStyles ?? !1, t = r.voidTrailingSlash ?? !0;
|
|
576
|
+
return O(u, n, "HTML", c, i, t), n.join("");
|
|
577
|
+
}
|
|
578
|
+
function O(e, r, n, u, f, a) {
|
|
579
|
+
if (e != null) {
|
|
580
|
+
if (typeof e == "string") {
|
|
581
|
+
r.push(G(e, !1));
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
if (typeof e == "number" || typeof e == "bigint") {
|
|
585
|
+
r.push(String(e));
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if (typeof e == "boolean") {
|
|
589
|
+
r.push(String(e));
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
if (Array.isArray(e)) {
|
|
593
|
+
for (const c of e)
|
|
594
|
+
O(c, r, n, u, f, a);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
if (typeof e != "function" && typeof e != "symbol" && !(e && typeof e == "object" && "then" in e && typeof e.then == "function") && e && typeof e == "object" && "type" in e && "props" in e) {
|
|
598
|
+
J(e, r, n, u, f, a);
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function J(e, r, n, u, f, a) {
|
|
604
|
+
var g;
|
|
605
|
+
const c = e.type;
|
|
606
|
+
let i = n;
|
|
607
|
+
if (c === "svg" ? i = "SVG" : c === "math" && (i = "MATHML"), r.push("<"), r.push(c), e.props) {
|
|
608
|
+
for (const [A, E] of Object.entries(e.props))
|
|
609
|
+
if (A !== "children" && !(E === !1 || E === null || E === void 0))
|
|
610
|
+
if (E === !0)
|
|
611
|
+
r.push(" "), r.push(A);
|
|
612
|
+
else if (A === "style" && typeof E == "object") {
|
|
613
|
+
const d = ee(E);
|
|
614
|
+
d && (r.push(' style="'), r.push(G(d, !0)), r.push('"'));
|
|
615
|
+
} else
|
|
616
|
+
r.push(" "), r.push(A), r.push('="'), r.push(G(String(E), !0)), r.push('"');
|
|
617
|
+
}
|
|
618
|
+
const t = (g = e.props) == null ? void 0 : g.children;
|
|
619
|
+
let p;
|
|
620
|
+
if (t && typeof t == "object" && "then" in t && typeof t.then == "function" ? p = !1 : p = t != null && (Array.isArray(t) && t.length > 0 || !Array.isArray(t) && t !== !1), F.has(c))
|
|
621
|
+
a ? r.push(" />") : r.push(">");
|
|
622
|
+
else if (p) {
|
|
623
|
+
r.push(">");
|
|
624
|
+
const A = t;
|
|
625
|
+
c === "script" && u || c === "style" && f ? (r.push("<![CDATA["), x(A, r, i, u, f, a), r.push("]]>")) : c === "script" || c === "style" ? W(A, r) : O(A, r, i, u, f, a), r.push("</"), r.push(c), r.push(">");
|
|
626
|
+
} else Q.has(c), r.push("></"), r.push(c), r.push(">");
|
|
627
|
+
}
|
|
628
|
+
function x(e, r, n, u, f, a, c) {
|
|
629
|
+
if (e != null) {
|
|
630
|
+
if (typeof e == "string") {
|
|
631
|
+
r.push(Z(e));
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
if (typeof e == "number" || typeof e == "bigint" || typeof e == "boolean") {
|
|
635
|
+
r.push(String(e));
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
if (Array.isArray(e)) {
|
|
639
|
+
for (const i of e)
|
|
640
|
+
x(i, r, n, u, f, a);
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
O(e, r, n, u, f, a);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
function W(e, r) {
|
|
647
|
+
if (e != null) {
|
|
648
|
+
if (typeof e == "string") {
|
|
649
|
+
r.push(e);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
if (typeof e == "number" || typeof e == "bigint" || typeof e == "boolean") {
|
|
653
|
+
r.push(String(e));
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
if (Array.isArray(e)) {
|
|
657
|
+
for (const n of e)
|
|
658
|
+
W(n, r);
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
function ee(e) {
|
|
664
|
+
const r = [];
|
|
665
|
+
for (const [n, u] of Object.entries(e))
|
|
666
|
+
if (u) {
|
|
667
|
+
const f = $(n);
|
|
668
|
+
r.push(`${f}: ${u}`);
|
|
669
|
+
}
|
|
670
|
+
return r.join("; ");
|
|
671
|
+
}
|
|
672
|
+
async function L(e) {
|
|
673
|
+
if (e == null)
|
|
674
|
+
return e;
|
|
675
|
+
if (e && typeof e == "object" && "then" in e && typeof e.then == "function") {
|
|
676
|
+
const r = await e;
|
|
677
|
+
return L(r);
|
|
678
|
+
}
|
|
679
|
+
if (typeof e == "string" || typeof e == "number" || typeof e == "boolean" || typeof e == "bigint")
|
|
680
|
+
return e;
|
|
681
|
+
if (typeof e != "function" && typeof e != "symbol") {
|
|
682
|
+
if (Array.isArray(e))
|
|
683
|
+
return await Promise.all(
|
|
684
|
+
e.filter((n) => !(n == null || typeof n == "function" || typeof n == "symbol")).map((n) => L(n))
|
|
685
|
+
);
|
|
686
|
+
if (e && typeof e == "object" && "type" in e && "props" in e) {
|
|
687
|
+
const r = e, n = {};
|
|
688
|
+
for (const [u, f] of Object.entries(r.props))
|
|
689
|
+
if (u === "children") {
|
|
690
|
+
const a = await L(f);
|
|
691
|
+
a != null && (n.children = a);
|
|
692
|
+
} else {
|
|
693
|
+
if (typeof f == "function" || typeof f == "symbol")
|
|
694
|
+
continue;
|
|
695
|
+
f != null && (n[u] = f);
|
|
696
|
+
}
|
|
697
|
+
return {
|
|
698
|
+
type: r.type,
|
|
699
|
+
props: n
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
function Y(e, r) {
|
|
705
|
+
if (e == null || typeof e == "string" || typeof e == "number" || typeof e == "boolean" || typeof e == "bigint")
|
|
706
|
+
return e;
|
|
707
|
+
if (Array.isArray(e))
|
|
708
|
+
return e.map((n) => Y(n, r));
|
|
709
|
+
if (typeof e == "object" && "type" in e && "props" in e) {
|
|
710
|
+
const { type: n, props: u } = e, { children: f, ...a } = u;
|
|
711
|
+
if (f !== void 0) {
|
|
712
|
+
const c = Y(f, r);
|
|
713
|
+
return c === null ? r(n, a) : Array.isArray(c) ? r(n, a, ...c) : r(n, a, c);
|
|
714
|
+
}
|
|
715
|
+
return r(n, a);
|
|
716
|
+
}
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
function te(e) {
|
|
720
|
+
return K(e);
|
|
721
|
+
}
|
|
722
|
+
function re(e, r = {}) {
|
|
723
|
+
return e && typeof e == "object" && "node" in e ? H(e, r) : e === void 0 ? "" : H(e, r);
|
|
724
|
+
}
|
|
725
|
+
async function ne(e) {
|
|
726
|
+
return await L(e);
|
|
727
|
+
}
|
|
728
|
+
export {
|
|
729
|
+
ne as awaitHtmlNode,
|
|
730
|
+
Y as htmlNodeTo,
|
|
731
|
+
te as readHtml,
|
|
732
|
+
re as writeHtml
|
|
733
|
+
};
|
package/dist/parser.d.ts
ADDED
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export interface HtmlStyle {
|
|
2
|
+
[key: string]: string;
|
|
3
|
+
}
|
|
4
|
+
export interface HtmlElement {
|
|
5
|
+
type: string;
|
|
6
|
+
props: HtmlProps;
|
|
7
|
+
}
|
|
8
|
+
export interface HtmlProps {
|
|
9
|
+
[key: string]: string | number | boolean | HtmlStyle | HtmlNode | Promise<HtmlNode>;
|
|
10
|
+
children?: HtmlNode | Promise<HtmlNode>;
|
|
11
|
+
}
|
|
12
|
+
export type HtmlNode = HtmlElement | string | number | bigint | boolean | null | undefined | HtmlNode[];
|
|
13
|
+
export declare enum ParserState {
|
|
14
|
+
TEXT = "TEXT",
|
|
15
|
+
TAG_OPEN = "TAG_OPEN",
|
|
16
|
+
TAG_NAME = "TAG_NAME",
|
|
17
|
+
ATTRIBUTES = "ATTRIBUTES",
|
|
18
|
+
ATTRIBUTE_NAME = "ATTRIBUTE_NAME",
|
|
19
|
+
ATTRIBUTE_VALUE_START = "ATTRIBUTE_VALUE_START",
|
|
20
|
+
ATTRIBUTE_VALUE_QUOTED = "ATTRIBUTE_VALUE_QUOTED",
|
|
21
|
+
ATTRIBUTE_VALUE_UNQUOTED = "ATTRIBUTE_VALUE_UNQUOTED",
|
|
22
|
+
TAG_CLOSE_SELF = "TAG_CLOSE_SELF",
|
|
23
|
+
TAG_CLOSE_START = "TAG_CLOSE_START",
|
|
24
|
+
TAG_CLOSE_NAME = "TAG_CLOSE_NAME",
|
|
25
|
+
COMMENT = "COMMENT",
|
|
26
|
+
DOCTYPE = "DOCTYPE",
|
|
27
|
+
CDATA = "CDATA",
|
|
28
|
+
PROCESSING_INSTRUCTION = "PROCESSING_INSTRUCTION",
|
|
29
|
+
SCRIPT_CONTENT = "SCRIPT_CONTENT",
|
|
30
|
+
STYLE_CONTENT = "STYLE_CONTENT"
|
|
31
|
+
}
|
|
32
|
+
export declare enum Namespace {
|
|
33
|
+
HTML = "HTML",
|
|
34
|
+
SVG = "SVG",
|
|
35
|
+
MATHML = "MATHML"
|
|
36
|
+
}
|
|
37
|
+
export interface ElementStackEntry {
|
|
38
|
+
type: string;
|
|
39
|
+
props: Partial<HtmlProps>;
|
|
40
|
+
children: HtmlNode[];
|
|
41
|
+
namespace: Namespace;
|
|
42
|
+
}
|
|
43
|
+
export interface ParseResult {
|
|
44
|
+
xml?: string;
|
|
45
|
+
doctype?: string;
|
|
46
|
+
node: HtmlNode | HtmlNode[];
|
|
47
|
+
}
|
|
48
|
+
export interface WriterOptions {
|
|
49
|
+
useCDataForScripts?: boolean;
|
|
50
|
+
useCDataForStyles?: boolean;
|
|
51
|
+
xml?: string;
|
|
52
|
+
doctype?: string;
|
|
53
|
+
voidTrailingSlash?: boolean;
|
|
54
|
+
}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Converts a kebab-case or snake_case string to camelCase
|
|
3
|
+
* @example toCamelCase("foo-bar") => "fooBar"
|
|
4
|
+
* @example toCamelCase("background-color") => "backgroundColor"
|
|
5
|
+
*/
|
|
6
|
+
export declare function toCamelCase(str: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Converts a camelCase string to kebab-case
|
|
9
|
+
* @example toKebabCase("fooBar") => "foo-bar"
|
|
10
|
+
* @example toKebabCase("backgroundColor") => "background-color"
|
|
11
|
+
*/
|
|
12
|
+
export declare function toKebabCase(str: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Efficient string builder using array accumulation
|
|
15
|
+
*/
|
|
16
|
+
export declare class StringBuilder {
|
|
17
|
+
private chunks;
|
|
18
|
+
append(str: string): void;
|
|
19
|
+
toString(): string;
|
|
20
|
+
clear(): void;
|
|
21
|
+
get length(): number;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Decodes a UTF-8 byte sequence to a string
|
|
25
|
+
*/
|
|
26
|
+
export declare function decodeUtf8(bytes: Uint8Array, start: number, end: number): string;
|
|
27
|
+
/**
|
|
28
|
+
* Checks if a character code is whitespace
|
|
29
|
+
*/
|
|
30
|
+
export declare function isWhitespace(code: number): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Checks if a character code is valid for tag/attribute names
|
|
33
|
+
*/
|
|
34
|
+
export declare function isNameChar(code: number): boolean;
|
package/dist/writer.d.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@levischuck/tiny-html",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/LeviSchuck/tiny-packages",
|
|
18
|
+
"directory": "packages/tiny-html"
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE.txt"
|
|
27
|
+
],
|
|
28
|
+
"keywords": [
|
|
29
|
+
"html",
|
|
30
|
+
"parser",
|
|
31
|
+
"react"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "vite build",
|
|
35
|
+
"type-check": "bunx tsc --noEmit",
|
|
36
|
+
"build:jsr": "echo Nothing to build",
|
|
37
|
+
"lint": "oxlint -c ../../.oxlintrc.json"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/bun": "latest"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"typescript": "^5"
|
|
44
|
+
}
|
|
45
|
+
}
|