svg-toolbox 1.1.12 → 1.2.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/README.md +105 -87
- package/es/analyze/paths.js +14 -0
- package/es/analyze/paths.js.map +1 -1
- package/es/compare/__tests__/diff.test.d.ts +1 -0
- package/es/compare/__tests__/diff.test.js +64 -0
- package/es/compare/__tests__/diff.test.js.map +1 -0
- package/es/compare/diff.js +13 -7
- package/es/compare/diff.js.map +1 -1
- package/es/convert/image.js +10 -5
- package/es/convert/image.js.map +1 -1
- package/es/optimize/__tests__/cleanup.test.js +29 -0
- package/es/optimize/__tests__/cleanup.test.js.map +1 -1
- package/es/optimize/cleanup.d.ts +8 -0
- package/es/optimize/cleanup.js +38 -1
- package/es/optimize/cleanup.js.map +1 -1
- package/es/utils/__tests__/path-validation.test.d.ts +1 -0
- package/es/utils/__tests__/path-validation.test.js +64 -0
- package/es/utils/__tests__/path-validation.test.js.map +1 -0
- package/es/utils/path-validation.d.ts +29 -0
- package/es/utils/path-validation.js +101 -0
- package/es/utils/path-validation.js.map +1 -0
- package/lib/analyze/paths.js +14 -0
- package/lib/analyze/paths.js.map +1 -1
- package/lib/compare/__tests__/diff.test.d.ts +1 -0
- package/lib/compare/__tests__/diff.test.js +128 -0
- package/lib/compare/__tests__/diff.test.js.map +1 -0
- package/lib/compare/diff.js +12 -8
- package/lib/compare/diff.js.map +1 -1
- package/lib/convert/image.js +10 -7
- package/lib/convert/image.js.map +1 -1
- package/lib/optimize/__tests__/cleanup.test.js +29 -0
- package/lib/optimize/__tests__/cleanup.test.js.map +1 -1
- package/lib/optimize/cleanup.d.ts +8 -0
- package/lib/optimize/cleanup.js +38 -1
- package/lib/optimize/cleanup.js.map +1 -1
- package/lib/utils/__tests__/path-validation.test.d.ts +1 -0
- package/lib/utils/__tests__/path-validation.test.js +69 -0
- package/lib/utils/__tests__/path-validation.test.js.map +1 -0
- package/lib/utils/path-validation.d.ts +29 -0
- package/lib/utils/path-validation.js +109 -0
- package/lib/utils/path-validation.js.map +1 -0
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -1,196 +1,214 @@
|
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
<br/>
|
|
3
|
+
<img width="260" alt="SVG Toolbox Logo" src="https://github.com/user-attachments/assets/fcb0c4f5-8094-44d2-bfca-e4b5f5120f73" />
|
|
4
|
+
<br/>
|
|
5
|
+
</h1>
|
|
6
|
+
|
|
1
7
|
# SVG Toolbox
|
|
2
8
|
|
|
3
|
-
|
|
9
|
+
A comprehensive SVG manipulation and analysis library providing capabilities for creating, converting, optimizing, comparing, and analyzing SVG elements.
|
|
4
10
|
|
|
5
11
|
[](https://www.npmjs.com/package/svg-toolbox)
|
|
6
12
|
[](https://www.npmjs.com/package/svg-toolbox)
|
|
7
13
|
[](https://www.npmjs.com/package/svg-toolbox)
|
|
8
14
|
|
|
9
|
-
##
|
|
15
|
+
## Installation
|
|
10
16
|
|
|
11
17
|
```bash
|
|
12
18
|
npm install svg-toolbox
|
|
13
19
|
```
|
|
14
20
|
|
|
15
|
-
##
|
|
21
|
+
## Use Cases
|
|
22
|
+
|
|
23
|
+
### 1. SVG Element Manipulation
|
|
16
24
|
|
|
17
|
-
|
|
25
|
+
When you need to create, clone, or merge SVG elements in Node.js environments:
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
- **Dynamic SVG Generation**: Create SVG elements dynamically based on data
|
|
28
|
+
- **SVG Template Reuse**: Clone existing SVG elements as templates
|
|
29
|
+
- **Combine Multiple SVGs**: Merge multiple independent SVG graphics into one
|
|
20
30
|
|
|
21
|
-
|
|
22
|
-
- **SVG 模板复用**:克隆现有 SVG 元素作为模板
|
|
23
|
-
- **组合多个 SVG**:将多个独立的 SVG 图形合并为一个
|
|
31
|
+
### 2. Format Conversion
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
When you need to convert SVG to other formats or perform encoding conversions:
|
|
26
34
|
|
|
27
|
-
|
|
35
|
+
- **Web Application Embedding**: Convert SVG to Base64 data URI for easy embedding in HTML/CSS
|
|
36
|
+
- **Image Export**: Convert SVG to PNG, JPG, or WebP formats for download or sharing
|
|
37
|
+
- **Cross-platform Compatibility**: Use Base64 encoding when transferring SVG data between different systems
|
|
28
38
|
|
|
29
|
-
|
|
30
|
-
- **图片导出**:将 SVG 转换为 PNG、JPG 或 WebP 格式用于下载或分享
|
|
31
|
-
- **跨平台兼容**:在不同系统间传输 SVG 数据时使用 Base64 编码
|
|
39
|
+
### 3. Visual Regression Testing
|
|
32
40
|
|
|
33
|
-
|
|
41
|
+
When you need to compare SVG rendering results to ensure visual consistency:
|
|
34
42
|
|
|
35
|
-
|
|
43
|
+
- **Automated Testing**: Detect SVG rendering changes in CI/CD pipelines
|
|
44
|
+
- **Version Comparison**: Compare differences between different versions of SVG files
|
|
45
|
+
- **Quality Assurance**: Ensure SVG modifications don't introduce unexpected visual changes
|
|
36
46
|
|
|
37
|
-
|
|
38
|
-
- **版本对比**:比较不同版本的 SVG 文件差异
|
|
39
|
-
- **质量保证**:确保 SVG 修改不会引入意外的视觉变化
|
|
47
|
+
### 4. SVG Optimization
|
|
40
48
|
|
|
41
|
-
|
|
49
|
+
When you need to clean and optimize SVG code:
|
|
42
50
|
|
|
43
|
-
|
|
51
|
+
- **Performance Optimization**: Remove invalid coordinates and empty attributes to reduce file size
|
|
52
|
+
- **Code Cleanup**: Remove comments and excess whitespace to improve readability
|
|
53
|
+
- **Data Repair**: Fix path data containing NaN or invalid values
|
|
44
54
|
|
|
45
|
-
|
|
46
|
-
- **代码清理**:移除注释和多余空白,提高可读性
|
|
47
|
-
- **数据修复**:修复包含 NaN 或无效值的路径数据
|
|
55
|
+
### 5. SVG Analysis
|
|
48
56
|
|
|
49
|
-
|
|
57
|
+
When you need to gain insights into SVG content, the analysis features can help you:
|
|
50
58
|
|
|
51
|
-
|
|
59
|
+
#### Color Extraction Use Cases
|
|
60
|
+
- **Design System Building**: Batch analyze SVG icon libraries, extract all used colors, and establish color standards for design systems
|
|
61
|
+
- **Theme Adaptation**: Identify colors in SVG and automatically generate dark/light theme versions
|
|
62
|
+
- **Accessibility Checking**: Verify that SVG colors meet WCAG contrast requirements
|
|
63
|
+
- **Brand Consistency Verification**: Verify that SVG icons use brand standard colors
|
|
64
|
+
- **Automated Color Replacement**: Identify colors that need replacement and batch update SVG files
|
|
52
65
|
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
66
|
+
#### Path Analysis Use Cases
|
|
67
|
+
- **SVG Optimization Decisions**: Analyze path complexity to determine if simplification or optimization is needed
|
|
68
|
+
- **Performance Analysis**: Count path commands to evaluate SVG rendering performance
|
|
69
|
+
- **Format Conversion Preparation**: Understand path structure to prepare for conversion to other formats
|
|
70
|
+
- **Animation Creation**: Analyze path command types to determine suitable animation methods (e.g., path stroke animation)
|
|
71
|
+
- **Quality Detection**: Detect if SVG contains overly complex paths (which may cause performance issues)
|
|
72
|
+
- **Path Editing Tools**: Provide path parsing and editing capabilities for SVG editors
|
|
73
|
+
- **Learning and Teaching**: Analyze SVG path structure to help understand SVG drawing principles
|
|
56
74
|
|
|
57
|
-
##
|
|
75
|
+
## Feature Modules
|
|
58
76
|
|
|
59
|
-
###
|
|
77
|
+
### Core Functions
|
|
60
78
|
|
|
61
|
-
|
|
79
|
+
Provides basic SVG element manipulation capabilities:
|
|
62
80
|
|
|
63
|
-
- `createSVGElement` -
|
|
64
|
-
- `cloneSVGElement` -
|
|
65
|
-
- `mergeSVGElements` -
|
|
66
|
-
- `getSVGDimensions` -
|
|
81
|
+
- `createSVGElement` - Create SVG element from string
|
|
82
|
+
- `cloneSVGElement` - Deep clone SVG element
|
|
83
|
+
- `mergeSVGElements` - Merge multiple SVG elements
|
|
84
|
+
- `getSVGDimensions` - Get SVG dimensions
|
|
67
85
|
|
|
68
|
-
###
|
|
86
|
+
### Conversion Functions
|
|
69
87
|
|
|
70
|
-
|
|
88
|
+
Provides format conversion and encoding capabilities:
|
|
71
89
|
|
|
72
|
-
- `convertSVGToBase64` - SVG
|
|
73
|
-
- `convertBase64ToSVG` - Base64
|
|
74
|
-
- `svgToImage` - SVG
|
|
75
|
-
- `svg2Png` - SVG
|
|
90
|
+
- `convertSVGToBase64` - Convert SVG to Base64 encoding
|
|
91
|
+
- `convertBase64ToSVG` - Decode Base64 to SVG
|
|
92
|
+
- `svgToImage` - Convert SVG to image formats (PNG/JPG/WebP)
|
|
93
|
+
- `svg2Png` - Convert SVG to PNG (legacy API compatibility)
|
|
76
94
|
|
|
77
|
-
###
|
|
95
|
+
### Comparison Functions
|
|
78
96
|
|
|
79
|
-
|
|
97
|
+
Provides image comparison and difference detection:
|
|
80
98
|
|
|
81
|
-
- `diffImages` -
|
|
82
|
-
- `pixelLevelDiff` -
|
|
83
|
-
- `diffSvg` - SVG
|
|
99
|
+
- `diffImages` - Compare two image files and generate diff image
|
|
100
|
+
- `pixelLevelDiff` - Pixel-level image difference comparison
|
|
101
|
+
- `diffSvg` - SVG difference comparison (legacy API compatibility)
|
|
84
102
|
|
|
85
|
-
###
|
|
103
|
+
### Optimization Functions
|
|
86
104
|
|
|
87
|
-
|
|
105
|
+
Provides SVG code optimization and cleanup:
|
|
88
106
|
|
|
89
|
-
- `removeNanCoordinates` -
|
|
90
|
-
- `removeEmptyAttributes` -
|
|
91
|
-
- `removeComments` -
|
|
92
|
-
- `normalizeWhitespace` -
|
|
93
|
-
- `optimizeSVG` -
|
|
107
|
+
- `removeNanCoordinates` - Remove NaN coordinates from paths
|
|
108
|
+
- `removeEmptyAttributes` - Remove empty attributes
|
|
109
|
+
- `removeComments` - Remove comments
|
|
110
|
+
- `normalizeWhitespace` - Normalize whitespace characters
|
|
111
|
+
- `optimizeSVG` - Comprehensive SVG code optimization
|
|
94
112
|
|
|
95
|
-
###
|
|
113
|
+
### Analysis Functions
|
|
96
114
|
|
|
97
|
-
|
|
115
|
+
Provides SVG content analysis:
|
|
98
116
|
|
|
99
|
-
- `extractColors` -
|
|
100
|
-
- `parsePathData` -
|
|
101
|
-
- `analyzePaths` -
|
|
102
|
-
- `getPathStatistics` -
|
|
117
|
+
- `extractColors` - Extract colors used in SVG
|
|
118
|
+
- `parsePathData` - Parse path data
|
|
119
|
+
- `analyzePaths` - Analyze all path elements
|
|
120
|
+
- `getPathStatistics` - Get path statistics
|
|
103
121
|
|
|
104
|
-
##
|
|
122
|
+
## Usage Examples
|
|
105
123
|
|
|
106
|
-
###
|
|
124
|
+
### Basic Operations
|
|
107
125
|
|
|
108
126
|
```typescript
|
|
109
127
|
import { createSVGElement, cloneSVGElement, mergeSVGElements } from 'svg-toolbox';
|
|
110
128
|
|
|
111
|
-
//
|
|
129
|
+
// Create SVG element
|
|
112
130
|
const svg = createSVGElement('<svg><circle cx="50" cy="50" r="40" /></svg>');
|
|
113
131
|
|
|
114
|
-
//
|
|
132
|
+
// Clone element
|
|
115
133
|
const cloned = cloneSVGElement(svg);
|
|
116
134
|
|
|
117
|
-
//
|
|
135
|
+
// Merge multiple elements
|
|
118
136
|
const merged = mergeSVGElements([svg, cloned]);
|
|
119
137
|
```
|
|
120
138
|
|
|
121
|
-
###
|
|
139
|
+
### Format Conversion
|
|
122
140
|
|
|
123
141
|
```typescript
|
|
124
142
|
import { convertSVGToBase64, svgToImage } from 'svg-toolbox';
|
|
125
143
|
|
|
126
|
-
//
|
|
144
|
+
// Convert to Base64
|
|
127
145
|
const base64 = convertSVGToBase64('<svg>...</svg>');
|
|
128
146
|
|
|
129
|
-
//
|
|
147
|
+
// Convert to PNG
|
|
130
148
|
const pngBuffer = await svgToImage('input.svg', { scale: 2, format: 'png' });
|
|
131
149
|
|
|
132
|
-
//
|
|
150
|
+
// Convert to WebP
|
|
133
151
|
const webpBuffer = await svgToImage('input.svg', { format: 'webp', quality: 90 });
|
|
134
152
|
```
|
|
135
153
|
|
|
136
|
-
###
|
|
154
|
+
### Image Comparison
|
|
137
155
|
|
|
138
156
|
```typescript
|
|
139
157
|
import { diffImages } from 'svg-toolbox';
|
|
140
158
|
|
|
141
|
-
//
|
|
159
|
+
// Compare two images and generate diff image
|
|
142
160
|
const result = await diffImages('image1.svg', 'image2.svg', 'diff.png');
|
|
143
|
-
console.log(
|
|
161
|
+
console.log(`Number of different pixels: ${result.numDiffPixels}`);
|
|
144
162
|
```
|
|
145
163
|
|
|
146
|
-
### SVG
|
|
164
|
+
### SVG Optimization
|
|
147
165
|
|
|
148
166
|
```typescript
|
|
149
167
|
import { optimizeSVG, removeNanCoordinates } from 'svg-toolbox';
|
|
150
168
|
|
|
151
|
-
//
|
|
169
|
+
// Comprehensive optimization
|
|
152
170
|
const optimized = optimizeSVG('<svg><!-- comment --><path d="M 10,20 nan L 30,40" /></svg>');
|
|
153
171
|
|
|
154
|
-
//
|
|
172
|
+
// Remove NaN coordinates
|
|
155
173
|
const cleaned = removeNanCoordinates('<svg><path d="M 10,20 nan L 30,40" /></svg>');
|
|
156
174
|
```
|
|
157
175
|
|
|
158
|
-
###
|
|
176
|
+
### Content Analysis
|
|
159
177
|
|
|
160
178
|
```typescript
|
|
161
179
|
import { extractColors, getPathStatistics } from 'svg-toolbox';
|
|
162
180
|
|
|
163
|
-
//
|
|
181
|
+
// Extract colors
|
|
164
182
|
const colors = extractColors('<svg><circle fill="red" stroke="blue" /></svg>');
|
|
165
183
|
|
|
166
|
-
//
|
|
184
|
+
// Get path statistics
|
|
167
185
|
const stats = getPathStatistics('<svg><path d="M 10,20 L 30,40 Z" /></svg>');
|
|
168
|
-
console.log(
|
|
186
|
+
console.log(`Paths: ${stats.totalPaths}, Commands: ${stats.totalCommands}`);
|
|
169
187
|
```
|
|
170
188
|
|
|
171
|
-
## API
|
|
189
|
+
## API Documentation
|
|
172
190
|
|
|
173
|
-
|
|
191
|
+
For detailed API documentation, please refer to [TypeScript type definitions](./src/types/index.ts) and source code comments.
|
|
174
192
|
|
|
175
|
-
##
|
|
193
|
+
## Development
|
|
176
194
|
|
|
177
195
|
```bash
|
|
178
|
-
#
|
|
196
|
+
# Install dependencies
|
|
179
197
|
npm install
|
|
180
198
|
|
|
181
|
-
#
|
|
199
|
+
# Run tests
|
|
182
200
|
npm test
|
|
183
201
|
|
|
184
|
-
#
|
|
202
|
+
# Build project
|
|
185
203
|
npm run build
|
|
186
204
|
|
|
187
|
-
#
|
|
205
|
+
# Watch mode testing
|
|
188
206
|
npm run test:watch
|
|
189
207
|
|
|
190
|
-
#
|
|
208
|
+
# Generate coverage report
|
|
191
209
|
npm run test:coverage
|
|
192
210
|
```
|
|
193
211
|
|
|
194
|
-
##
|
|
212
|
+
## License
|
|
195
213
|
|
|
196
214
|
MIT License
|
package/es/analyze/paths.js
CHANGED
|
@@ -4,15 +4,29 @@
|
|
|
4
4
|
import { JSDOM } from 'jsdom';
|
|
5
5
|
import { serializeSVG } from '../core/element';
|
|
6
6
|
import { isValidSvgString } from '../utils/validation';
|
|
7
|
+
/**
|
|
8
|
+
* Maximum allowed path data length to prevent ReDoS attacks
|
|
9
|
+
*/
|
|
10
|
+
const MAX_PATH_DATA_LENGTH = 100000; // 100KB should be sufficient for most SVG paths
|
|
7
11
|
/**
|
|
8
12
|
* Parses the 'd' attribute of a path element into command objects
|
|
9
13
|
*/
|
|
10
14
|
export function parsePathData(pathData) {
|
|
15
|
+
// Validate input length to prevent ReDoS attacks
|
|
16
|
+
if (pathData.length > MAX_PATH_DATA_LENGTH) {
|
|
17
|
+
throw new Error(`Path data length exceeds maximum allowed length of ${MAX_PATH_DATA_LENGTH} characters`);
|
|
18
|
+
}
|
|
11
19
|
const commands = [];
|
|
12
20
|
// Split by path commands (M, L, H, V, C, S, Q, T, A, Z)
|
|
13
21
|
const commandRegex = /([MmLlHhVvCcSsQqTtAaZz])((?:\s*-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\s*,?\s*)*)/g;
|
|
14
22
|
let match;
|
|
23
|
+
let iterations = 0;
|
|
24
|
+
const MAX_ITERATIONS = 10000; // Prevent infinite loops
|
|
15
25
|
while ((match = commandRegex.exec(pathData)) !== null) {
|
|
26
|
+
iterations++;
|
|
27
|
+
if (iterations > MAX_ITERATIONS) {
|
|
28
|
+
throw new Error('Path parsing exceeded maximum iterations. Path data may be malformed.');
|
|
29
|
+
}
|
|
16
30
|
const type = match[1];
|
|
17
31
|
const paramsStr = match[2].trim();
|
|
18
32
|
if (type.toLowerCase() === 'z') {
|
package/es/analyze/paths.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/analyze/paths.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAqB,MAAM,qBAAqB,CAAC;AAG1E;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,QAAQ,GAAkB,EAAE,CAAC;IAEnC,wDAAwD;IACxD,MAAM,YAAY,GAAG,6EAA6E,CAAC;IACnG,IAAI,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/analyze/paths.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { diffImages } from '../diff';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
describe('Image Diff', () => {
|
|
5
|
+
const fixturesDir = path.join(__dirname, '../../../test-fixtures');
|
|
6
|
+
const test1Path = path.join(fixturesDir, 'test1.svg');
|
|
7
|
+
const test2Path = path.join(fixturesDir, 'test2.svg');
|
|
8
|
+
const outputDir = path.join(fixturesDir, 'diff-output');
|
|
9
|
+
const diffImagePath = path.join(outputDir, 'diff-test1-test2.png');
|
|
10
|
+
beforeAll(() => {
|
|
11
|
+
// Ensure output directory exists
|
|
12
|
+
if (!fs.existsSync(outputDir)) {
|
|
13
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
afterAll(() => {
|
|
17
|
+
// Clean up: optionally remove the diff image after tests
|
|
18
|
+
// Uncomment the following line if you want to clean up after tests
|
|
19
|
+
// if (fs.existsSync(diffImagePath)) {
|
|
20
|
+
// fs.unlinkSync(diffImagePath);
|
|
21
|
+
// }
|
|
22
|
+
});
|
|
23
|
+
it('should generate diff image between two similar but different SVGs', async () => {
|
|
24
|
+
// Verify test fixtures exist
|
|
25
|
+
expect(fs.existsSync(test1Path)).toBe(true);
|
|
26
|
+
expect(fs.existsSync(test2Path)).toBe(true);
|
|
27
|
+
// Generate diff image
|
|
28
|
+
const result = await diffImages(test1Path, test2Path, diffImagePath, 0.1);
|
|
29
|
+
// Verify diff image was created
|
|
30
|
+
expect(fs.existsSync(diffImagePath)).toBe(true);
|
|
31
|
+
// Verify result contains expected properties
|
|
32
|
+
expect(result).toHaveProperty('diffPngBuffer');
|
|
33
|
+
expect(result).toHaveProperty('numDiffPixels');
|
|
34
|
+
expect(result.diffPngBuffer).toBeInstanceOf(Buffer);
|
|
35
|
+
expect(typeof result.numDiffPixels).toBe('number');
|
|
36
|
+
// Since the SVGs are different, there should be some differences
|
|
37
|
+
expect(result.numDiffPixels).toBeGreaterThan(0);
|
|
38
|
+
// Verify the saved file matches the buffer
|
|
39
|
+
const savedFile = fs.readFileSync(diffImagePath);
|
|
40
|
+
expect(savedFile.equals(result.diffPngBuffer)).toBe(true);
|
|
41
|
+
// Verify file size is reasonable (not empty)
|
|
42
|
+
expect(savedFile.length).toBeGreaterThan(0);
|
|
43
|
+
console.log(`Diff image saved to: ${diffImagePath}`);
|
|
44
|
+
console.log(`Number of different pixels: ${result.numDiffPixels}`);
|
|
45
|
+
});
|
|
46
|
+
it('should handle identical SVGs (no differences)', async () => {
|
|
47
|
+
const identicalDiffPath = path.join(outputDir, 'diff-identical.png');
|
|
48
|
+
// Compare test1 with itself
|
|
49
|
+
const result = await diffImages(test1Path, test1Path, identicalDiffPath, 0.1);
|
|
50
|
+
// Should have no differences
|
|
51
|
+
expect(result.numDiffPixels).toBe(0);
|
|
52
|
+
expect(fs.existsSync(identicalDiffPath)).toBe(true);
|
|
53
|
+
console.log(`Identical comparison diff saved to: ${identicalDiffPath}`);
|
|
54
|
+
console.log(`Number of different pixels: ${result.numDiffPixels}`);
|
|
55
|
+
});
|
|
56
|
+
it('should generate diff without saving to file', async () => {
|
|
57
|
+
const result = await diffImages(test1Path, test2Path, undefined, 0.1);
|
|
58
|
+
// Should still return result even without file path
|
|
59
|
+
expect(result).toHaveProperty('diffPngBuffer');
|
|
60
|
+
expect(result).toHaveProperty('numDiffPixels');
|
|
61
|
+
expect(result.numDiffPixels).toBeGreaterThan(0);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=diff.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.test.js","sourceRoot":"","sources":["../../../src/compare/__tests__/diff.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IACxD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;IAEnE,SAAS,CAAC,GAAG,EAAE;QACb,iCAAiC;QACjC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC9B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,GAAG,EAAE;QACZ,yDAAyD;QACzD,mEAAmE;QACnE,sCAAsC;QACtC,kCAAkC;QAClC,IAAI;IACN,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,KAAK,IAAI,EAAE;QACjF,6BAA6B;QAC7B,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE5C,sBAAsB;QACtB,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,CAAC,CAAC;QAE1E,gCAAgC;QAChC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhD,6CAA6C;QAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QACpD,MAAM,CAAC,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAEnD,iEAAiE;QACjE,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAEhD,2CAA2C;QAC3C,MAAM,SAAS,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;QACjD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE1D,6CAA6C;QAC7C,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAE5C,OAAO,CAAC,GAAG,CAAC,wBAAwB,aAAa,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,+BAA+B,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC7D,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;QAErE,4BAA4B;QAC5B,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAC;QAE9E,6BAA6B;QAC7B,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEpD,OAAO,CAAC,GAAG,CAAC,uCAAuC,iBAAiB,EAAE,CAAC,CAAC;QACxE,OAAO,CAAC,GAAG,CAAC,+BAA+B,MAAM,CAAC,aAAa,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;QAC3D,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,CAAC,CAAC;QAEtE,oDAAoD;QACpD,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAC/C,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/es/compare/diff.js
CHANGED
|
@@ -6,6 +6,7 @@ import path from 'path';
|
|
|
6
6
|
import sharp from 'sharp';
|
|
7
7
|
import { PNG } from 'pngjs';
|
|
8
8
|
import pixelmatch from 'pixelmatch';
|
|
9
|
+
import { validateReadPath, validateWritePath } from '../utils/path-validation';
|
|
9
10
|
/**
|
|
10
11
|
* Compares two PNG images at the pixel level and generates a diff image
|
|
11
12
|
*/
|
|
@@ -28,22 +29,27 @@ export function pixelLevelDiff(pngA, pngB, threshold = 0.1) {
|
|
|
28
29
|
* Compares two image files (SVG or PNG) and generates a diff image
|
|
29
30
|
*/
|
|
30
31
|
export async function diffImages(pathA, pathB, diffFilePath, threshold = 0.1) {
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
// Validate and normalize file paths to prevent path traversal
|
|
33
|
+
const validatedPathA = validateReadPath(pathA, ['.svg', '.png', '.jpg', '.jpeg', '.webp']);
|
|
34
|
+
const validatedPathB = validateReadPath(pathB, ['.svg', '.png', '.jpg', '.jpeg', '.webp']);
|
|
35
|
+
if (!fs.existsSync(validatedPathA)) {
|
|
36
|
+
throw new Error(`File not found: ${validatedPathA}`);
|
|
33
37
|
}
|
|
34
|
-
if (!fs.existsSync(
|
|
35
|
-
throw new Error(`File not found: ${
|
|
38
|
+
if (!fs.existsSync(validatedPathB)) {
|
|
39
|
+
throw new Error(`File not found: ${validatedPathB}`);
|
|
36
40
|
}
|
|
37
41
|
// Convert both images to PNG buffers
|
|
38
|
-
const pngA = await sharp(
|
|
39
|
-
const pngB = await sharp(
|
|
42
|
+
const pngA = await sharp(validatedPathA).png().toBuffer();
|
|
43
|
+
const pngB = await sharp(validatedPathB).png().toBuffer();
|
|
40
44
|
const result = pixelLevelDiff(pngA, pngB, threshold);
|
|
41
45
|
if (diffFilePath) {
|
|
42
46
|
const ext = path.extname(diffFilePath);
|
|
43
47
|
if (!ext) {
|
|
44
48
|
throw new Error('Diff file path must have a file extension');
|
|
45
49
|
}
|
|
46
|
-
|
|
50
|
+
// Validate write path to prevent path traversal
|
|
51
|
+
const validatedWritePath = validateWritePath(diffFilePath, ['.png']);
|
|
52
|
+
fs.writeFileSync(validatedWritePath, result.diffPngBuffer);
|
|
47
53
|
}
|
|
48
54
|
return result;
|
|
49
55
|
}
|
package/es/compare/diff.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/compare/diff.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC;AAC5B,OAAO,UAAU,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/compare/diff.ts"],"names":[],"mappings":"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"}
|
package/es/convert/image.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import fs from 'fs';
|
|
5
5
|
import sharp from 'sharp';
|
|
6
6
|
import { getSVGDimensions } from '../core/dimensions';
|
|
7
|
+
import { validateReadPath, validateWritePath } from '../utils/path-validation';
|
|
7
8
|
/**
|
|
8
9
|
* Converts an SVG file to PNG format
|
|
9
10
|
*
|
|
@@ -13,17 +14,19 @@ import { getSVGDimensions } from '../core/dimensions';
|
|
|
13
14
|
*/
|
|
14
15
|
export async function svgToImage(svgPath, options = {}) {
|
|
15
16
|
const { scale = 2, format = 'png', quality = 90 } = options;
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
// Validate and normalize the file path to prevent path traversal
|
|
18
|
+
const validatedPath = validateReadPath(svgPath, ['.svg']);
|
|
19
|
+
if (!fs.existsSync(validatedPath)) {
|
|
20
|
+
throw new Error(`SVG file not found: ${validatedPath}`);
|
|
18
21
|
}
|
|
19
|
-
const svgContent = fs.readFileSync(
|
|
22
|
+
const svgContent = fs.readFileSync(validatedPath, 'utf8');
|
|
20
23
|
const dimensions = getSVGDimensions(svgContent);
|
|
21
24
|
if (!dimensions.width || !dimensions.height) {
|
|
22
25
|
throw new Error('SVG must have width and height or viewBox');
|
|
23
26
|
}
|
|
24
27
|
const width = scale * dimensions.width;
|
|
25
28
|
const height = scale * dimensions.height;
|
|
26
|
-
let sharpInstance = sharp(
|
|
29
|
+
let sharpInstance = sharp(validatedPath).resize(width, height);
|
|
27
30
|
switch (format) {
|
|
28
31
|
case 'jpg':
|
|
29
32
|
case 'jpeg':
|
|
@@ -50,7 +53,9 @@ export async function svg2Png(svgPath, pngPath, scale) {
|
|
|
50
53
|
}
|
|
51
54
|
const buffer = await svgToImage(svgPath, { scale: scale ?? 2, format: 'png' });
|
|
52
55
|
if (pngPath) {
|
|
53
|
-
|
|
56
|
+
// Validate write path to prevent path traversal
|
|
57
|
+
const validatedWritePath = validateWritePath(pngPath, ['.png']);
|
|
58
|
+
fs.writeFileSync(validatedWritePath, buffer);
|
|
54
59
|
return;
|
|
55
60
|
}
|
|
56
61
|
return buffer;
|
package/es/convert/image.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/convert/image.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/convert/image.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE/E;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,OAAe,EACf,UAA6B,EAAE;IAE/B,MAAM,EAAE,KAAK,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC;IAE5D,iEAAiE;IACjE,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAE1D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,uBAAuB,aAAa,EAAE,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,UAAU,GAAG,EAAE,CAAC,YAAY,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IAC1D,MAAM,UAAU,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;IAEhD,IAAI,CAAC,UAAU,CAAC,KAAK,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QAC5C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC;IACvC,MAAM,MAAM,GAAG,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC;IAEzC,IAAI,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAE/D,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK,CAAC;QACX,KAAK,MAAM;YACT,aAAa,GAAG,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;YAChD,MAAM;QACR,KAAK,MAAM;YACT,aAAa,GAAG,aAAa,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;YAChD,MAAM;QACR,KAAK,KAAK,CAAC;QACX;YACE,aAAa,GAAG,aAAa,CAAC,GAAG,EAAE,CAAC;YACpC,MAAM;IACV,CAAC;IAED,OAAO,aAAa,CAAC,QAAQ,EAAE,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAe,EACf,OAAgB,EAChB,KAAc;IAEd,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IAE/E,IAAI,OAAO,EAAE,CAAC;QACZ,gDAAgD;QAChD,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QAChE,EAAE,CAAC,aAAa,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;QAC7C,OAAO;IACT,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -31,6 +31,35 @@ describe('SVG Cleanup', () => {
|
|
|
31
31
|
const result = removeComments(svgContent);
|
|
32
32
|
expect(result).not.toContain('Comment');
|
|
33
33
|
});
|
|
34
|
+
it('should handle nested comments correctly', () => {
|
|
35
|
+
// This tests the incomplete sanitization fix
|
|
36
|
+
// Input: "<!--<!-- comment -->-->" should become "" not "<!-- comment -->"
|
|
37
|
+
const svgContent = '<svg><!--<!-- nested comment -->--><circle /></svg>';
|
|
38
|
+
const result = removeComments(svgContent);
|
|
39
|
+
expect(result).not.toContain('<!--');
|
|
40
|
+
expect(result).not.toContain('-->');
|
|
41
|
+
expect(result).not.toContain('nested comment');
|
|
42
|
+
expect(result).toContain('circle');
|
|
43
|
+
});
|
|
44
|
+
it('should handle deeply nested comments', () => {
|
|
45
|
+
const svgContent = '<svg><!--<!--<!-- triple nested -->-->--><circle /></svg>';
|
|
46
|
+
const result = removeComments(svgContent);
|
|
47
|
+
expect(result).not.toContain('<!--');
|
|
48
|
+
expect(result).not.toContain('-->');
|
|
49
|
+
expect(result).toContain('circle');
|
|
50
|
+
});
|
|
51
|
+
it('should throw error for content exceeding maximum length', () => {
|
|
52
|
+
const largeContent = '<!--' + 'x'.repeat(10000001) + '-->';
|
|
53
|
+
expect(() => removeComments(largeContent)).toThrow('exceeds maximum allowed length');
|
|
54
|
+
});
|
|
55
|
+
it('should handle comments with newlines', () => {
|
|
56
|
+
const svgContent = '<svg><!--\nMulti-line\ncomment\n--><circle /></svg>';
|
|
57
|
+
const result = removeComments(svgContent);
|
|
58
|
+
expect(result).not.toContain('<!--');
|
|
59
|
+
expect(result).not.toContain('-->');
|
|
60
|
+
expect(result).not.toContain('Multi-line');
|
|
61
|
+
expect(result).toContain('circle');
|
|
62
|
+
});
|
|
34
63
|
});
|
|
35
64
|
describe('normalizeWhitespace', () => {
|
|
36
65
|
it('should normalize whitespace', () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cleanup.test.js","sourceRoot":"","sources":["../../../src/optimize/__tests__/cleanup.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cleanup.test.js","sourceRoot":"","sources":["../../../src/optimize/__tests__/cleanup.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACrG,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;QACrC,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,UAAU,GAAG,iEAAiE,CAAC;YACrF,MAAM,MAAM,GAAG,qBAAqB,CAAC,UAAU,CAAC,CAAC;YAEjD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YACvC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,UAAU,GAAG,yDAAyD,CAAC;YAC7E,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;YAE9C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;QAC9B,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,UAAU,GAAG,wEAAwE,CAAC;YAC5F,MAAM,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;YACzC,MAAM,UAAU,GAAG,2DAA2D,CAAC;YAC/E,MAAM,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,6CAA6C;YAC7C,2EAA2E;YAC3E,MAAM,UAAU,GAAG,qDAAqD,CAAC;YACzE,MAAM,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;YAC/C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,UAAU,GAAG,2DAA2D,CAAC;YAC/E,MAAM,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YACjE,MAAM,YAAY,GAAG,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC;YAC3D,MAAM,CAAC,GAAG,EAAE,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;QACvF,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC9C,MAAM,UAAU,GAAG,qDAAqD,CAAC;YACzE,MAAM,MAAM,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;YAE1C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;YAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACnC,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,UAAU,GAAG,mDAAmD,CAAC;YACvE,MAAM,MAAM,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;YAE/C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YACpC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;YAC/C,MAAM,UAAU,GAAG,yCAAyC,CAAC;YAC7D,MAAM,MAAM,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;YAE/C,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,UAAU,GAAG,0EAA0E,CAAC;YAC9F,MAAM,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,CAAC;YAEvC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YACrC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YACtC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;YACnC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;YAC5C,MAAM,UAAU,GAAG,+CAA+C,CAAC;YACnE,MAAM,OAAO,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;YAC7C,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;YAEpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
package/es/optimize/cleanup.d.ts
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
export declare function removeEmptyAttributes(svgContent: Element | string): string;
|
|
8
8
|
/**
|
|
9
9
|
* Removes comments from SVG content
|
|
10
|
+
*
|
|
11
|
+
* This function uses iterative replacement to handle nested comments correctly
|
|
12
|
+
* and includes input length validation to prevent ReDoS attacks.
|
|
13
|
+
*
|
|
14
|
+
* The function handles cases like:
|
|
15
|
+
* - Simple comments: <!-- comment -->
|
|
16
|
+
* - Nested comments: <!--<!-- inner -->-->
|
|
17
|
+
* - Multiple comments: <!-- one --><!-- two -->
|
|
10
18
|
*/
|
|
11
19
|
export declare function removeComments(svgContent: string): string;
|
|
12
20
|
/**
|