Initial Commit
This commit is contained in:
87
packages/devtools/docs/compress-svg/src/parser/svg/svg.md
Normal file
87
packages/devtools/docs/compress-svg/src/parser/svg/svg.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# svg-parser — SVG Parser and Serializer
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
## Purpose
|
||||
|
||||
`parseSvg` and `serializeSvg` are the low-level I/O layer for `@suaveplan/compress-svg`. The parser is a pure-TypeScript push parser that processes SVG strings character-by-character without requiring `DOMParser`, making it safe to use in Node.js, Bun, edge runtimes, and workers. `serializeSvg` produces compact, whitespace-free output optimised for minimum byte count.
|
||||
|
||||
## Features
|
||||
|
||||
- `parseSvg(svg)` — converts an SVG string to an `SvgNode` tree; no DOM dependency; handles element, text, comment, CDATA, and doctype nodes
|
||||
- `serializeSvg(node)` — converts an `SvgNode` tree back to a compact SVG string; self-closing tags for empty elements
|
||||
- Handles XML declarations (`<?xml ...?>`) by silently skipping them (irrelevant to the SVG tree)
|
||||
- Decodes HTML/XML character entities (`&`, `<`, `>`, `"`, `'`, numeric `&#...;` and `&#x...;`)
|
||||
- Throws `SvgCompressError(SVG_COMPRESS_PARSE_FAILED)` with a descriptive message on malformed input
|
||||
- Supports both double-quoted and single-quoted attribute values
|
||||
- Supports boolean (value-less) attributes
|
||||
|
||||
## Usage: Basic Example
|
||||
|
||||
```typescript
|
||||
import { parseSvg, serializeSvg } from '@suaveplan/compress-svg';
|
||||
|
||||
const node = parseSvg('<svg xmlns="http://www.w3.org/2000/svg"><circle r="40"/></svg>');
|
||||
console.log(node.name); // 'svg'
|
||||
console.log(node.children![0]!.name); // 'circle'
|
||||
|
||||
const output = serializeSvg(node);
|
||||
// '<svg xmlns="http://www.w3.org/2000/svg"><circle r="40"/></svg>'
|
||||
```
|
||||
|
||||
## Usage: Advanced Example
|
||||
|
||||
```typescript
|
||||
import { parseSvg, serializeSvg } from '@suaveplan/compress-svg';
|
||||
import { SvgCompressError, SVG_COMPRESS_CODES } from '@suaveplan/compress-svg';
|
||||
|
||||
function safeRoundTrip(svg: string): string | null {
|
||||
try {
|
||||
return serializeSvg(parseSvg(svg));
|
||||
} catch (e) {
|
||||
if (e instanceof SvgCompressError && e.code === SVG_COMPRESS_CODES.PARSE_FAILED) {
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// Handles comments, CDATA, and nested structures
|
||||
const svg = `
|
||||
<?xml version="1.0"?>
|
||||
<!-- icon -->
|
||||
<svg><![CDATA[raw]]><g><rect/></g></svg>
|
||||
`;
|
||||
const output = safeRoundTrip(svg.trim());
|
||||
// '<svg><![CDATA[raw]]><g><rect/></g></svg>'
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `parseSvg(svg: string): SvgNode`
|
||||
|
||||
Parses an SVG string into a tree of `SvgNode` objects. The returned node is always the root element. XML declarations are silently skipped. Doctype nodes are captured as children of the virtual root but not returned as the root element — the root is always the first element node.
|
||||
|
||||
**Throws:** `SvgCompressError(SVG_COMPRESS_PARSE_FAILED)` when:
|
||||
|
||||
- Input is empty or all whitespace
|
||||
- A tag is left unclosed
|
||||
- A closing tag does not match the open tag
|
||||
- There is no root element in the input
|
||||
|
||||
### `serializeSvg(node: SvgNode): string`
|
||||
|
||||
Serializes a single `SvgNode` (and all its descendants) to a compact SVG string. Empty element nodes (no children) are serialized as self-closing (`<rect/>`). No whitespace or newlines are added between elements.
|
||||
|
||||
| Node type | Output format |
|
||||
|------------|---------------------------------------|
|
||||
| `element` | `<name attrs>children</name>` or `<name attrs/>` |
|
||||
| `text` | Raw text value |
|
||||
| `comment` | `<!--value-->` |
|
||||
| `cdata` | `<![CDATA[value]]>` |
|
||||
| `doctype` | `<!DOCTYPE value>` |
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
The parser is a single-pass, index-advancing loop over the input string. It maintains an explicit stack of open elements rather than recursing, so deeply nested SVGs do not risk stack overflow. Attribute parsing uses a single regex that correctly handles double-quoted, single-quoted, and unquoted values. The `findTagEnd` helper handles `>` characters inside attribute values by tracking quote state. Entity decoding covers the five XML predefined entities plus numeric decimal and hexadecimal code points. The serializer uses a switch statement over node type, making it branch-exhaustive with TypeScript's `never` check at compile time.
|
||||
Reference in New Issue
Block a user