svg-eslint-parser 0.0.4 → 0.0.6
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/README.md +190 -6
- package/dist/chunk-CzXV76rE.js +18 -0
- package/dist/index.d.ts +624 -0
- package/dist/index.js +2491 -0
- package/package.json +21 -27
- package/dist/index.d.mts +0 -575
- package/dist/index.mjs +0 -2183
package/README.md
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
[](https://github.com/ntnyq/svg-eslint-parser/actions)
|
|
4
4
|
[](https://www.npmjs.com/package/svg-eslint-parser)
|
|
5
5
|
[](https://www.npmjs.com/package/svg-eslint-parser)
|
|
6
|
-
[](https://codecov.io/github/ntnyq/svg-eslint-parser)
|
|
7
6
|
[](https://github.com/ntnyq/svg-eslint-parser/blob/main/LICENSE)
|
|
8
7
|
|
|
9
8
|
> :package: An SVG parser that produces output compatible with ESLint.
|
|
@@ -11,28 +10,213 @@
|
|
|
11
10
|
> [!IMPORTANT]
|
|
12
11
|
> Status: Work In Progress, not ready for production.
|
|
13
12
|
>
|
|
14
|
-
> API is not
|
|
13
|
+
> API is not stable now, use at your own risk.
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- ✅ **ESLint Compatible**: Produces AST compatible with ESLint's parser interface
|
|
18
|
+
- 🎯 **Type Safe**: Full TypeScript support with comprehensive type definitions
|
|
19
|
+
- 🔍 **Rich Utilities**: Built-in functions for searching, traversing, and manipulating AST
|
|
20
|
+
- 📊 **Detailed AST**: 16 node types covering all SVG/XML constructs
|
|
21
|
+
- 🚀 **Zero Dependencies**: Minimal runtime dependencies for fast installation
|
|
22
|
+
- 🎪 **Interactive Playground**: Try it online at [svg-eslint-parser.ntnyq.com](https://svg-eslint-parser.ntnyq.com/play)
|
|
15
23
|
|
|
16
24
|
## Install
|
|
17
25
|
|
|
18
|
-
```
|
|
26
|
+
```shell
|
|
19
27
|
npm install svg-eslint-parser -D
|
|
20
28
|
```
|
|
21
29
|
|
|
22
|
-
```
|
|
30
|
+
```shell
|
|
23
31
|
yarn add svg-eslint-parser -D
|
|
24
32
|
```
|
|
25
33
|
|
|
26
|
-
```
|
|
34
|
+
```shell
|
|
27
35
|
pnpm add svg-eslint-parser -D
|
|
28
36
|
```
|
|
29
37
|
|
|
38
|
+
## Usage
|
|
39
|
+
|
|
40
|
+
### Basic Parsing
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
import { parse, parseForESLint } from 'svg-eslint-parser'
|
|
44
|
+
|
|
45
|
+
// For direct use
|
|
46
|
+
const document = parse('<svg><circle cx="50" cy="50" r="40" /></svg>')
|
|
47
|
+
console.log(document.type) // 'Document'
|
|
48
|
+
|
|
49
|
+
// For ESLint integration
|
|
50
|
+
const result = parseForESLint('<svg><circle cx="50" cy="50" r="40" /></svg>')
|
|
51
|
+
console.log(result.ast.type) // 'Program'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### With ESLint
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
import pluginSVG from 'eslint-plugin-svg'
|
|
58
|
+
import * as parserSVG from 'svg-eslint-parser'
|
|
59
|
+
|
|
60
|
+
export default [
|
|
61
|
+
{
|
|
62
|
+
name: 'svg/rules',
|
|
63
|
+
files: ['**/*.svg'],
|
|
64
|
+
plugins: {
|
|
65
|
+
svg: pluginSVG,
|
|
66
|
+
},
|
|
67
|
+
languageOptions: {
|
|
68
|
+
parser: parserSVG,
|
|
69
|
+
},
|
|
70
|
+
rules: {
|
|
71
|
+
'svg/no-empty-title': 'error',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Using Utilities
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import {
|
|
81
|
+
parseForESLint,
|
|
82
|
+
findNodeByType,
|
|
83
|
+
NodeTypes,
|
|
84
|
+
traverseAST,
|
|
85
|
+
} from 'svg-eslint-parser'
|
|
86
|
+
|
|
87
|
+
const { ast } = parseForESLint(svgSource)
|
|
88
|
+
const document = ast.body[0]
|
|
89
|
+
|
|
90
|
+
// Find all tag nodes
|
|
91
|
+
const tags = findNodeByType(document, NodeTypes.Tag)
|
|
92
|
+
console.log(`Found ${tags.length} tags`)
|
|
93
|
+
|
|
94
|
+
// Traverse with visitor pattern
|
|
95
|
+
traverseAST(document, {
|
|
96
|
+
enter(node, parent) {
|
|
97
|
+
console.log('Visiting:', node.type)
|
|
98
|
+
// Return false to skip children
|
|
99
|
+
if (node.type === 'Comment') return false
|
|
100
|
+
},
|
|
101
|
+
leave(node, parent) {
|
|
102
|
+
console.log('Leaving:', node.type)
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## API
|
|
108
|
+
|
|
109
|
+
### Parser Functions
|
|
110
|
+
|
|
111
|
+
#### `parseForESLint(code: string, options?: ParserOptions)`
|
|
112
|
+
|
|
113
|
+
Returns an ESLint-compatible result with AST, visitor keys, and services.
|
|
114
|
+
|
|
115
|
+
#### `parse(code: string, options?: ParserOptions)`
|
|
116
|
+
|
|
117
|
+
Returns a Document node directly.
|
|
118
|
+
|
|
119
|
+
### Utility Functions
|
|
120
|
+
|
|
121
|
+
#### Search & Traversal
|
|
122
|
+
|
|
123
|
+
- `findNodeByType<T>(node, type)` - Find all nodes of a specific type
|
|
124
|
+
- `findFirstNodeByType<T>(node, type)` - Find first node of a specific type
|
|
125
|
+
- `traverseAST(node, visitor)` - Visitor pattern traversal with enter/leave hooks
|
|
126
|
+
- `walkAST(node, callback)` - Simple traversal with callback
|
|
127
|
+
|
|
128
|
+
#### Validation
|
|
129
|
+
|
|
130
|
+
- `validateNode(node)` - Validate node structure
|
|
131
|
+
- `isNodeType<T>(node, type)` - Type guard function
|
|
132
|
+
|
|
133
|
+
#### Manipulation
|
|
134
|
+
|
|
135
|
+
- `cloneNode<T>(node)` - Deep clone without parent references
|
|
136
|
+
- `cloneNodeWithParent<T>(node, parent?)` - Clone preserving parent refs
|
|
137
|
+
- `filterNodes(node, predicate)` - Filter nodes by predicate
|
|
138
|
+
- `mapNodes<T>(node, mapper)` - Map over all nodes
|
|
139
|
+
|
|
140
|
+
#### Analysis
|
|
141
|
+
|
|
142
|
+
- `countNodes(node)` - Count total nodes
|
|
143
|
+
- `getNodeDepth(node)` - Get node depth (requires parent refs)
|
|
144
|
+
- `getParentChain(node)` - Get ancestor chain (requires parent refs)
|
|
145
|
+
|
|
146
|
+
### Node Types
|
|
147
|
+
|
|
148
|
+
The parser defines 34 node types:
|
|
149
|
+
|
|
150
|
+
**Document Structure**: `Program`, `Document`
|
|
151
|
+
|
|
152
|
+
**Elements**: `Tag`, `OpenTagStart`, `OpenTagEnd`, `CloseTag`
|
|
153
|
+
|
|
154
|
+
**Attributes**: `Attribute`, `AttributeKey`, `AttributeValue`, `AttributeValueWrapperStart`, `AttributeValueWrapperEnd`
|
|
155
|
+
|
|
156
|
+
**Text & Comments**: `Text`, `Comment`, `CommentOpen`, `CommentContent`, `CommentClose`
|
|
157
|
+
|
|
158
|
+
**XML Declaration**: `XMLDeclaration`, `XMLDeclarationOpen`, `XMLDeclarationClose`, `XMLDeclarationAttribute`, `XMLDeclarationAttributeKey`, `XMLDeclarationAttributeValue`, `XMLDeclarationAttributeValueWrapperStart`, `XMLDeclarationAttributeValueWrapperEnd`
|
|
159
|
+
|
|
160
|
+
**DOCTYPE**: `Doctype`, `DoctypeOpen`, `DoctypeClose`, `DoctypeAttribute`, `DoctypeAttributeValue`, `DoctypeAttributeWrapperStart`, `DoctypeAttributeWrapperEnd`
|
|
161
|
+
|
|
162
|
+
**Error Handling**: `Error`
|
|
163
|
+
|
|
164
|
+
## Documentation
|
|
165
|
+
|
|
166
|
+
Full documentation is available at [svg-eslint-parser.ntnyq.com](https://svg-eslint-parser.ntnyq.com):
|
|
167
|
+
|
|
168
|
+
- [API Documentation](https://svg-eslint-parser.ntnyq.com/api/)
|
|
169
|
+
- [AST Structure](https://svg-eslint-parser.ntnyq.com/api/ast)
|
|
170
|
+
- [Utilities Guide](https://svg-eslint-parser.ntnyq.com/api/utilities)
|
|
171
|
+
- [Migration Guide](https://svg-eslint-parser.ntnyq.com/guide/migration)
|
|
172
|
+
|
|
30
173
|
## Playground
|
|
31
174
|
|
|
32
|
-
You can try the parser in [playground](https://svg-eslint-parser.ntnyq.com/play).
|
|
175
|
+
You can try the parser in the [interactive playground](https://svg-eslint-parser.ntnyq.com/play).
|
|
33
176
|
|
|
34
177
|
Feel free to open an issue if you have any suggestions or find any bugs.
|
|
35
178
|
|
|
179
|
+
## Example: Finding All Circles
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { parseForESLint, findNodeByType, NodeTypes } from 'svg-eslint-parser'
|
|
183
|
+
|
|
184
|
+
const svgCode = `
|
|
185
|
+
<svg width="200" height="200">
|
|
186
|
+
<circle cx="50" cy="50" r="40" fill="red" />
|
|
187
|
+
<circle cx="150" cy="150" r="30" fill="blue" />
|
|
188
|
+
<rect x="10" y="10" width="50" height="50" />
|
|
189
|
+
</svg>
|
|
190
|
+
`
|
|
191
|
+
|
|
192
|
+
const { ast } = parseForESLint(svgCode)
|
|
193
|
+
const document = ast.body[0]
|
|
194
|
+
|
|
195
|
+
// Find all tags and filter for circles
|
|
196
|
+
const allTags = findNodeByType(document, NodeTypes.Tag)
|
|
197
|
+
const circles = allTags.filter(tag => tag.name === 'circle')
|
|
198
|
+
|
|
199
|
+
console.log(`Found ${circles.length} circles`)
|
|
200
|
+
|
|
201
|
+
circles.forEach((circle, i) => {
|
|
202
|
+
const cx = circle.attributes.find(attr => attr.key.value === 'cx')
|
|
203
|
+
const cy = circle.attributes.find(attr => attr.key.value === 'cy')
|
|
204
|
+
const r = circle.attributes.find(attr => attr.key.value === 'r')
|
|
205
|
+
|
|
206
|
+
console.log(
|
|
207
|
+
`Circle ${i + 1}: cx=${cx?.value?.value}, cy=${cy?.value?.value}, r=${r?.value?.value}`,
|
|
208
|
+
)
|
|
209
|
+
})
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Output:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
Found 2 circles
|
|
216
|
+
Circle 1: cx=50, cy=50, r=40
|
|
217
|
+
Circle 2: cx=150, cy=150, r=30
|
|
218
|
+
```
|
|
219
|
+
|
|
36
220
|
## Links
|
|
37
221
|
|
|
38
222
|
- [Scalable Vector Graphics (SVG) 2](https://www.w3.org/TR/SVG2/)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) {
|
|
6
|
+
__defProp(target, name, {
|
|
7
|
+
get: all[name],
|
|
8
|
+
enumerable: true
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
if (symbols) {
|
|
12
|
+
__defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
13
|
+
}
|
|
14
|
+
return target;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { __exportAll as t };
|