svg-toolbox 1.1.11 → 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 +156 -118
- package/es/analyze/__tests__/colors.test.d.ts +1 -0
- package/es/analyze/__tests__/colors.test.js +44 -0
- package/es/analyze/__tests__/colors.test.js.map +1 -0
- package/es/analyze/__tests__/paths.test.d.ts +1 -0
- package/es/analyze/__tests__/paths.test.js +71 -0
- package/es/analyze/__tests__/paths.test.js.map +1 -0
- package/es/analyze/colors.d.ts +8 -0
- package/es/analyze/colors.js +55 -0
- package/es/analyze/colors.js.map +1 -0
- package/es/analyze/paths.d.ts +20 -0
- package/es/analyze/paths.js +92 -0
- package/es/analyze/paths.js.map +1 -0
- 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.d.ts +18 -0
- package/es/compare/diff.js +70 -0
- package/es/compare/diff.js.map +1 -0
- package/es/convert/__tests__/base64.test.d.ts +1 -0
- package/es/convert/__tests__/base64.test.js +49 -0
- package/es/convert/__tests__/base64.test.js.map +1 -0
- package/es/convert/base64.d.ts +11 -0
- package/es/convert/base64.js +38 -0
- package/es/convert/base64.js.map +1 -0
- package/es/convert/image.d.ts +18 -0
- package/es/convert/image.js +63 -0
- package/es/convert/image.js.map +1 -0
- package/es/core/__tests__/dimensions.test.d.ts +1 -0
- package/es/core/__tests__/dimensions.test.js +40 -0
- package/es/core/__tests__/dimensions.test.js.map +1 -0
- package/es/core/__tests__/element.test.d.ts +1 -0
- package/es/core/__tests__/element.test.js +79 -0
- package/es/core/__tests__/element.test.js.map +1 -0
- package/es/core/dimensions.d.ts +8 -0
- package/es/core/dimensions.js +34 -0
- package/es/core/dimensions.js.map +1 -0
- package/es/core/element.d.ts +24 -0
- package/es/core/element.js +52 -0
- package/es/core/element.js.map +1 -0
- package/es/index.d.ts +15 -10
- package/es/index.js +21 -10
- package/es/index.js.map +1 -1
- package/es/optimize/__tests__/cleanup.test.d.ts +1 -0
- package/es/optimize/__tests__/cleanup.test.js +95 -0
- package/es/optimize/__tests__/cleanup.test.js.map +1 -0
- package/es/optimize/__tests__/path.test.d.ts +1 -0
- package/es/optimize/__tests__/path.test.js +41 -0
- package/es/optimize/__tests__/path.test.js.map +1 -0
- package/es/optimize/cleanup.d.ts +27 -0
- package/es/optimize/cleanup.js +100 -0
- package/es/optimize/cleanup.js.map +1 -0
- package/es/optimize/path.d.ts +7 -0
- package/es/optimize/path.js +58 -0
- package/es/optimize/path.js.map +1 -0
- package/es/types/index.d.ts +31 -0
- package/es/types/index.js +5 -0
- package/es/types/index.js.map +1 -0
- 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/__tests__/validation.test.d.ts +1 -0
- package/es/utils/__tests__/validation.test.js +42 -0
- package/es/utils/__tests__/validation.test.js.map +1 -0
- package/es/utils/dom.d.ts +23 -0
- package/es/utils/dom.js +25 -0
- package/es/utils/dom.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/es/utils/validation.d.ts +11 -0
- package/es/utils/validation.js +30 -0
- package/es/utils/validation.js.map +1 -0
- package/lib/analyze/__tests__/colors.test.d.ts +1 -0
- package/lib/analyze/__tests__/colors.test.js +46 -0
- package/lib/analyze/__tests__/colors.test.js.map +1 -0
- package/lib/analyze/__tests__/paths.test.d.ts +1 -0
- package/lib/analyze/__tests__/paths.test.js +73 -0
- package/lib/analyze/__tests__/paths.test.js.map +1 -0
- package/lib/analyze/colors.d.ts +8 -0
- package/lib/analyze/colors.js +58 -0
- package/lib/analyze/colors.js.map +1 -0
- package/lib/analyze/paths.d.ts +20 -0
- package/lib/analyze/paths.js +97 -0
- package/lib/analyze/paths.js.map +1 -0
- 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.d.ts +18 -0
- package/lib/compare/diff.js +134 -0
- package/lib/compare/diff.js.map +1 -0
- package/lib/convert/__tests__/base64.test.d.ts +1 -0
- package/lib/convert/__tests__/base64.test.js +51 -0
- package/lib/convert/__tests__/base64.test.js.map +1 -0
- package/lib/convert/base64.d.ts +11 -0
- package/lib/convert/base64.js +42 -0
- package/lib/convert/base64.js.map +1 -0
- package/lib/convert/image.d.ts +18 -0
- package/lib/{extra-apply/applySvg2Png.js → convert/image.js} +62 -53
- package/lib/convert/image.js.map +1 -0
- package/lib/core/__tests__/dimensions.test.d.ts +1 -0
- package/lib/core/__tests__/dimensions.test.js +42 -0
- package/lib/core/__tests__/dimensions.test.js.map +1 -0
- package/lib/core/__tests__/element.test.d.ts +1 -0
- package/lib/core/__tests__/element.test.js +81 -0
- package/lib/core/__tests__/element.test.js.map +1 -0
- package/lib/core/dimensions.d.ts +8 -0
- package/lib/core/dimensions.js +37 -0
- package/lib/core/dimensions.js.map +1 -0
- package/lib/core/element.d.ts +24 -0
- package/lib/core/element.js +58 -0
- package/lib/core/element.js.map +1 -0
- package/lib/index.d.ts +15 -10
- package/lib/index.js +48 -20
- package/lib/index.js.map +1 -1
- package/lib/optimize/__tests__/cleanup.test.d.ts +1 -0
- package/lib/optimize/__tests__/cleanup.test.js +97 -0
- package/lib/optimize/__tests__/cleanup.test.js.map +1 -0
- package/lib/optimize/__tests__/path.test.d.ts +1 -0
- package/lib/optimize/__tests__/path.test.js +43 -0
- package/lib/optimize/__tests__/path.test.js.map +1 -0
- package/lib/optimize/cleanup.d.ts +27 -0
- package/lib/optimize/cleanup.js +106 -0
- package/lib/optimize/cleanup.js.map +1 -0
- package/lib/optimize/path.d.ts +7 -0
- package/lib/optimize/path.js +63 -0
- package/lib/optimize/path.js.map +1 -0
- package/lib/types/index.d.ts +31 -0
- package/lib/types/index.js +6 -0
- package/lib/types/index.js.map +1 -0
- 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/__tests__/validation.test.d.ts +1 -0
- package/lib/utils/__tests__/validation.test.js +44 -0
- package/lib/utils/__tests__/validation.test.js.map +1 -0
- package/lib/utils/dom.d.ts +23 -0
- package/lib/utils/dom.js +31 -0
- package/lib/utils/dom.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/lib/utils/validation.d.ts +11 -0
- package/lib/utils/validation.js +35 -0
- package/lib/utils/validation.js.map +1 -0
- package/package.json +17 -4
- package/es/common.d.ts +0 -68
- package/es/common.js +0 -110
- package/es/common.js.map +0 -1
- package/es/extra-apply/applyDiffSvg.d.ts +0 -11
- package/es/extra-apply/applyDiffSvg.js +0 -63
- package/es/extra-apply/applyDiffSvg.js.map +0 -1
- package/es/extra-apply/applyRemoveNanCoordinates.d.ts +0 -6
- package/es/extra-apply/applyRemoveNanCoordinates.js +0 -75
- package/es/extra-apply/applyRemoveNanCoordinates.js.map +0 -1
- package/es/extra-apply/applySvg2Png.d.ts +0 -16
- package/es/extra-apply/applySvg2Png.js +0 -64
- package/es/extra-apply/applySvg2Png.js.map +0 -1
- package/es/utils/pixelLevelDiffPng.d.ts +0 -4
- package/es/utils/pixelLevelDiffPng.js +0 -29
- package/es/utils/pixelLevelDiffPng.js.map +0 -1
- package/es/validate.d.ts +0 -14
- package/es/validate.js +0 -44
- package/es/validate.js.map +0 -1
- package/lib/common.d.ts +0 -68
- package/lib/common.js +0 -117
- package/lib/common.js.map +0 -1
- package/lib/extra-apply/applyDiffSvg.d.ts +0 -11
- package/lib/extra-apply/applyDiffSvg.js +0 -116
- package/lib/extra-apply/applyDiffSvg.js.map +0 -1
- package/lib/extra-apply/applyRemoveNanCoordinates.d.ts +0 -6
- package/lib/extra-apply/applyRemoveNanCoordinates.js +0 -78
- package/lib/extra-apply/applyRemoveNanCoordinates.js.map +0 -1
- package/lib/extra-apply/applySvg2Png.d.ts +0 -16
- package/lib/extra-apply/applySvg2Png.js.map +0 -1
- package/lib/utils/pixelLevelDiffPng.d.ts +0 -4
- package/lib/utils/pixelLevelDiffPng.js +0 -36
- package/lib/utils/pixelLevelDiffPng.js.map +0 -1
- package/lib/validate.d.ts +0 -14
- package/lib/validate.js +0 -48
- package/lib/validate.js.map +0 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { validateFilePath, validateReadPath, validateWritePath } from '../path-validation';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import os from 'os';
|
|
5
|
+
describe('Path Validation', () => {
|
|
6
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'svg-toolbox-test-'));
|
|
7
|
+
afterAll(() => {
|
|
8
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
9
|
+
});
|
|
10
|
+
describe('validateFilePath', () => {
|
|
11
|
+
it('should normalize valid paths', () => {
|
|
12
|
+
const result = validateFilePath('./test.svg');
|
|
13
|
+
expect(path.isAbsolute(result)).toBe(true);
|
|
14
|
+
});
|
|
15
|
+
it('should reject paths with .. traversal', () => {
|
|
16
|
+
expect(() => validateFilePath('../etc/passwd')).toThrow('Path traversal detected');
|
|
17
|
+
expect(() => validateFilePath('../../secret')).toThrow('Path traversal detected');
|
|
18
|
+
});
|
|
19
|
+
it('should reject empty paths', () => {
|
|
20
|
+
expect(() => validateFilePath('')).toThrow('File path must be a non-empty string');
|
|
21
|
+
expect(() => validateFilePath(null)).toThrow('File path must be a non-empty string');
|
|
22
|
+
});
|
|
23
|
+
it('should restrict paths to base directory when provided', () => {
|
|
24
|
+
const baseDir = tempDir;
|
|
25
|
+
const validPath = path.join(baseDir, 'test.svg');
|
|
26
|
+
expect(() => validateFilePath(validPath, baseDir)).not.toThrow();
|
|
27
|
+
expect(() => validateFilePath('/etc/passwd', baseDir)).toThrow('Path is outside the allowed directory');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
describe('validateReadPath', () => {
|
|
31
|
+
it('should validate file extensions', () => {
|
|
32
|
+
expect(() => validateReadPath('test.svg', ['.svg'])).not.toThrow();
|
|
33
|
+
expect(() => validateReadPath('test.png', ['.svg'])).toThrow('File extension .png is not allowed');
|
|
34
|
+
});
|
|
35
|
+
it('should accept multiple allowed extensions', () => {
|
|
36
|
+
expect(() => validateReadPath('test.svg', ['.svg', '.png'])).not.toThrow();
|
|
37
|
+
expect(() => validateReadPath('test.png', ['.svg', '.png'])).not.toThrow();
|
|
38
|
+
});
|
|
39
|
+
it('should be case-insensitive for extensions', () => {
|
|
40
|
+
expect(() => validateReadPath('test.SVG', ['.svg'])).not.toThrow();
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('validateWritePath', () => {
|
|
44
|
+
it('should validate file extensions', () => {
|
|
45
|
+
const writePath = path.join(tempDir, 'test.png');
|
|
46
|
+
expect(() => validateWritePath(writePath, ['.png'])).not.toThrow();
|
|
47
|
+
expect(() => validateWritePath(writePath, ['.svg'])).toThrow('File extension .png is not allowed');
|
|
48
|
+
});
|
|
49
|
+
it('should create directory if it does not exist', () => {
|
|
50
|
+
const newDir = path.join(tempDir, 'new-dir');
|
|
51
|
+
const writePath = path.join(newDir, 'test.png');
|
|
52
|
+
expect(fs.existsSync(newDir)).toBe(false);
|
|
53
|
+
validateWritePath(writePath, ['.png']);
|
|
54
|
+
expect(fs.existsSync(newDir)).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
it('should restrict writes to base directory when provided', () => {
|
|
57
|
+
const baseDir = tempDir;
|
|
58
|
+
const validPath = path.join(baseDir, 'test.png');
|
|
59
|
+
expect(() => validateWritePath(validPath, ['.png'], baseDir)).not.toThrow();
|
|
60
|
+
expect(() => validateWritePath('/tmp/test.png', ['.png'], baseDir)).toThrow('Path is outside the allowed directory');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
//# sourceMappingURL=path-validation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-validation.test.js","sourceRoot":"","sources":["../../../src/utils/__tests__/path-validation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { isValidSvgString, isValidSvgElement } from '../validation';
|
|
2
|
+
import { createSVGElement } from '../../core/element';
|
|
3
|
+
describe('Validation', () => {
|
|
4
|
+
describe('isValidSvgString', () => {
|
|
5
|
+
it('should return true for valid SVG string', () => {
|
|
6
|
+
const svgString = '<svg><circle cx="50" cy="50" r="40" /></svg>';
|
|
7
|
+
expect(isValidSvgString(svgString)).toBe(true);
|
|
8
|
+
});
|
|
9
|
+
it('should return false for non-string input', () => {
|
|
10
|
+
expect(isValidSvgString(null)).toBe(false);
|
|
11
|
+
expect(isValidSvgString(123)).toBe(false);
|
|
12
|
+
expect(isValidSvgString({})).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
it('should return false for invalid SVG string', () => {
|
|
15
|
+
expect(isValidSvgString('<div></div>')).toBe(false);
|
|
16
|
+
expect(isValidSvgString('not svg')).toBe(false);
|
|
17
|
+
expect(isValidSvgString('')).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
it('should handle malformed XML', () => {
|
|
20
|
+
expect(isValidSvgString('<svg><unclosed></svg>')).toBe(false);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('isValidSvgElement', () => {
|
|
24
|
+
it('should return true for valid SVG element', () => {
|
|
25
|
+
const svgString = '<svg><circle /></svg>';
|
|
26
|
+
const element = createSVGElement(svgString);
|
|
27
|
+
expect(isValidSvgElement(element)).toBe(true);
|
|
28
|
+
});
|
|
29
|
+
it('should return false for non-element input', () => {
|
|
30
|
+
expect(isValidSvgElement(null)).toBe(false);
|
|
31
|
+
expect(isValidSvgElement('string')).toBe(false);
|
|
32
|
+
expect(isValidSvgElement({})).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
it('should return false for non-SVG element', () => {
|
|
35
|
+
const { JSDOM } = require('jsdom');
|
|
36
|
+
const dom = new JSDOM(`<!DOCTYPE html><html><body><div></div></body></html>`);
|
|
37
|
+
const div = dom.window.document.querySelector('div');
|
|
38
|
+
expect(isValidSvgElement(div)).toBe(false);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
//# sourceMappingURL=validation.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.test.js","sourceRoot":"","sources":["../../../src/utils/__tests__/validation.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC1B,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAChC,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,SAAS,GAAG,8CAA8C,CAAC;YACjE,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3C,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1C,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YACpD,MAAM,CAAC,gBAAgB,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACpD,MAAM,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;YACrC,MAAM,CAAC,gBAAgB,CAAC,uBAAuB,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAChE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;YAClD,MAAM,SAAS,GAAG,uBAAuB,CAAC;YAC1C,MAAM,OAAO,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAC;YAC5C,MAAM,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACnD,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5C,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAChD,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;YACnC,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;YAC9E,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAErD,MAAM,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM utility functions for SVG manipulation
|
|
3
|
+
*/
|
|
4
|
+
export declare const document: Document;
|
|
5
|
+
export declare const DOMParser: {
|
|
6
|
+
new (): DOMParser;
|
|
7
|
+
prototype: DOMParser;
|
|
8
|
+
}, XMLSerializer: {
|
|
9
|
+
new (): XMLSerializer;
|
|
10
|
+
prototype: XMLSerializer;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Creates a new DOM parser instance
|
|
14
|
+
*/
|
|
15
|
+
export declare function createDOMParser(): DOMParser;
|
|
16
|
+
/**
|
|
17
|
+
* Creates a new XML serializer instance
|
|
18
|
+
*/
|
|
19
|
+
export declare function createXMLSerializer(): XMLSerializer;
|
|
20
|
+
/**
|
|
21
|
+
* Gets the SVG namespace URI
|
|
22
|
+
*/
|
|
23
|
+
export declare const SVG_NAMESPACE = "http://www.w3.org/2000/svg";
|
package/es/utils/dom.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM utility functions for SVG manipulation
|
|
3
|
+
*/
|
|
4
|
+
import { JSDOM } from 'jsdom';
|
|
5
|
+
// Create a singleton virtual DOM environment
|
|
6
|
+
const dom = new JSDOM(`<!DOCTYPE html><html><body></body></html>`);
|
|
7
|
+
export const { document } = dom.window;
|
|
8
|
+
export const { DOMParser, XMLSerializer } = dom.window;
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new DOM parser instance
|
|
11
|
+
*/
|
|
12
|
+
export function createDOMParser() {
|
|
13
|
+
return new dom.window.DOMParser();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new XML serializer instance
|
|
17
|
+
*/
|
|
18
|
+
export function createXMLSerializer() {
|
|
19
|
+
return new dom.window.XMLSerializer();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Gets the SVG namespace URI
|
|
23
|
+
*/
|
|
24
|
+
export const SVG_NAMESPACE = 'http://www.w3.org/2000/svg';
|
|
25
|
+
//# sourceMappingURL=dom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/utils/dom.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B,6CAA6C;AAC7C,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;AACnE,MAAM,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;AACvC,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC;AAEvD;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;AACpC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC;AACxC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path validation utilities to prevent path traversal attacks
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Validates and normalizes a file path to prevent directory traversal attacks
|
|
6
|
+
*
|
|
7
|
+
* @param filePath - The file path to validate
|
|
8
|
+
* @param baseDirectory - Optional base directory to restrict paths to
|
|
9
|
+
* @returns Normalized absolute path
|
|
10
|
+
* @throws Error if path is invalid or contains traversal sequences
|
|
11
|
+
*/
|
|
12
|
+
export declare function validateFilePath(filePath: string, baseDirectory?: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Validates that a file path is safe for reading
|
|
15
|
+
*
|
|
16
|
+
* @param filePath - The file path to validate
|
|
17
|
+
* @param allowedExtensions - Optional array of allowed file extensions (e.g., ['.svg', '.png'])
|
|
18
|
+
* @returns Normalized absolute path
|
|
19
|
+
*/
|
|
20
|
+
export declare function validateReadPath(filePath: string, allowedExtensions?: string[]): string;
|
|
21
|
+
/**
|
|
22
|
+
* Validates that a file path is safe for writing
|
|
23
|
+
*
|
|
24
|
+
* @param filePath - The file path to validate
|
|
25
|
+
* @param allowedExtensions - Optional array of allowed file extensions
|
|
26
|
+
* @param baseDirectory - Optional base directory to restrict writes to
|
|
27
|
+
* @returns Normalized absolute path
|
|
28
|
+
*/
|
|
29
|
+
export declare function validateWritePath(filePath: string, allowedExtensions?: string[], baseDirectory?: string): string;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path validation utilities to prevent path traversal attacks
|
|
3
|
+
*/
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
/**
|
|
7
|
+
* Maximum allowed path length to prevent buffer overflow attacks
|
|
8
|
+
*/
|
|
9
|
+
const MAX_PATH_LENGTH = 4096;
|
|
10
|
+
/**
|
|
11
|
+
* Validates and normalizes a file path to prevent directory traversal attacks
|
|
12
|
+
*
|
|
13
|
+
* @param filePath - The file path to validate
|
|
14
|
+
* @param baseDirectory - Optional base directory to restrict paths to
|
|
15
|
+
* @returns Normalized absolute path
|
|
16
|
+
* @throws Error if path is invalid or contains traversal sequences
|
|
17
|
+
*/
|
|
18
|
+
export function validateFilePath(filePath, baseDirectory) {
|
|
19
|
+
if (!filePath || typeof filePath !== 'string') {
|
|
20
|
+
throw new Error('File path must be a non-empty string');
|
|
21
|
+
}
|
|
22
|
+
// Check path length to prevent buffer overflow attacks
|
|
23
|
+
if (filePath.length > MAX_PATH_LENGTH) {
|
|
24
|
+
throw new Error(`Path length exceeds maximum allowed length of ${MAX_PATH_LENGTH} characters`);
|
|
25
|
+
}
|
|
26
|
+
// Check for null bytes which can be used in path traversal attacks
|
|
27
|
+
if (filePath.includes('\0')) {
|
|
28
|
+
throw new Error('Path contains null bytes which are not allowed');
|
|
29
|
+
}
|
|
30
|
+
// Check for path traversal sequences BEFORE normalization
|
|
31
|
+
// This catches attempts like ../, ..\, etc.
|
|
32
|
+
if (filePath.includes('..')) {
|
|
33
|
+
throw new Error('Path traversal detected: paths containing ".." are not allowed');
|
|
34
|
+
}
|
|
35
|
+
// Resolve to absolute path first, then normalize
|
|
36
|
+
// This ensures that . sequences are resolved
|
|
37
|
+
const absolutePath = path.isAbsolute(filePath)
|
|
38
|
+
? path.resolve(filePath)
|
|
39
|
+
: path.resolve(process.cwd(), filePath);
|
|
40
|
+
// Normalize the resolved path
|
|
41
|
+
const normalizedPath = path.normalize(absolutePath);
|
|
42
|
+
// Additional safety check: ensure the normalized path doesn't contain .. after resolution
|
|
43
|
+
if (normalizedPath.includes('..')) {
|
|
44
|
+
throw new Error('Path traversal detected: paths containing ".." are not allowed');
|
|
45
|
+
}
|
|
46
|
+
// If base directory is provided, ensure the path is within it
|
|
47
|
+
if (baseDirectory) {
|
|
48
|
+
const baseDir = path.isAbsolute(baseDirectory)
|
|
49
|
+
? path.resolve(path.normalize(baseDirectory))
|
|
50
|
+
: path.resolve(process.cwd(), baseDirectory);
|
|
51
|
+
const resolvedPath = path.resolve(normalizedPath);
|
|
52
|
+
// Use path.relative to check if path is within base directory
|
|
53
|
+
const relativePath = path.relative(baseDir, resolvedPath);
|
|
54
|
+
// If relative path starts with .. or is absolute, it's outside the base directory
|
|
55
|
+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
56
|
+
throw new Error('Path is outside the allowed directory');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return normalizedPath;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Validates that a file path is safe for reading
|
|
63
|
+
*
|
|
64
|
+
* @param filePath - The file path to validate
|
|
65
|
+
* @param allowedExtensions - Optional array of allowed file extensions (e.g., ['.svg', '.png'])
|
|
66
|
+
* @returns Normalized absolute path
|
|
67
|
+
*/
|
|
68
|
+
export function validateReadPath(filePath, allowedExtensions) {
|
|
69
|
+
const validatedPath = validateFilePath(filePath);
|
|
70
|
+
if (allowedExtensions && allowedExtensions.length > 0) {
|
|
71
|
+
const ext = path.extname(validatedPath).toLowerCase();
|
|
72
|
+
if (!allowedExtensions.includes(ext)) {
|
|
73
|
+
throw new Error(`File extension ${ext} is not allowed. Allowed extensions: ${allowedExtensions.join(', ')}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return validatedPath;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Validates that a file path is safe for writing
|
|
80
|
+
*
|
|
81
|
+
* @param filePath - The file path to validate
|
|
82
|
+
* @param allowedExtensions - Optional array of allowed file extensions
|
|
83
|
+
* @param baseDirectory - Optional base directory to restrict writes to
|
|
84
|
+
* @returns Normalized absolute path
|
|
85
|
+
*/
|
|
86
|
+
export function validateWritePath(filePath, allowedExtensions, baseDirectory) {
|
|
87
|
+
const validatedPath = validateFilePath(filePath, baseDirectory);
|
|
88
|
+
if (allowedExtensions && allowedExtensions.length > 0) {
|
|
89
|
+
const ext = path.extname(validatedPath).toLowerCase();
|
|
90
|
+
if (!allowedExtensions.includes(ext)) {
|
|
91
|
+
throw new Error(`File extension ${ext} is not allowed. Allowed extensions: ${allowedExtensions.join(', ')}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Ensure the directory exists
|
|
95
|
+
const dir = path.dirname(validatedPath);
|
|
96
|
+
if (!fs.existsSync(dir)) {
|
|
97
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
98
|
+
}
|
|
99
|
+
return validatedPath;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=path-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-validation.js","sourceRoot":"","sources":["../../src/utils/path-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation utilities for SVG content
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Validates whether the provided content is a valid SVG string
|
|
6
|
+
*/
|
|
7
|
+
export declare function isValidSvgString(content: unknown): content is string;
|
|
8
|
+
/**
|
|
9
|
+
* Validates whether the provided content is a valid SVG element
|
|
10
|
+
*/
|
|
11
|
+
export declare function isValidSvgElement(content: unknown): content is Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validation utilities for SVG content
|
|
3
|
+
*/
|
|
4
|
+
import { JSDOM } from 'jsdom';
|
|
5
|
+
/**
|
|
6
|
+
* Validates whether the provided content is a valid SVG string
|
|
7
|
+
*/
|
|
8
|
+
export function isValidSvgString(content) {
|
|
9
|
+
if (typeof content !== 'string') {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const dom = new JSDOM(content);
|
|
14
|
+
const rootNode = new dom.window.DOMParser().parseFromString(content, 'image/svg+xml').documentElement;
|
|
15
|
+
return rootNode.nodeName.toLowerCase() === 'svg';
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Validates whether the provided content is a valid SVG element
|
|
23
|
+
*/
|
|
24
|
+
export function isValidSvgElement(content) {
|
|
25
|
+
return (content !== null &&
|
|
26
|
+
typeof content === 'object' &&
|
|
27
|
+
'tagName' in content &&
|
|
28
|
+
content.tagName?.toLowerCase() === 'svg');
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAE9B;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;QAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC,eAAe,CAAC;QACtG,OAAO,QAAQ,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO,CACL,OAAO,KAAK,IAAI;QAChB,OAAO,OAAO,KAAK,QAAQ;QAC3B,SAAS,IAAI,OAAO;QACnB,OAAmB,CAAC,OAAO,EAAE,WAAW,EAAE,KAAK,KAAK,CACtD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var colors_1 = require("../colors");
|
|
4
|
+
var element_1 = require("../../core/element");
|
|
5
|
+
describe('Color Analysis', function () {
|
|
6
|
+
describe('extractColors', function () {
|
|
7
|
+
it('should extract fill colors', function () {
|
|
8
|
+
var svgContent = '<svg><circle fill="red" /><rect fill="blue" /></svg>';
|
|
9
|
+
var colors = (0, colors_1.extractColors)(svgContent);
|
|
10
|
+
expect(colors.length).toBeGreaterThan(0);
|
|
11
|
+
expect(colors.some(function (c) { return c.fill === 'red'; })).toBe(true);
|
|
12
|
+
expect(colors.some(function (c) { return c.fill === 'blue'; })).toBe(true);
|
|
13
|
+
});
|
|
14
|
+
it('should extract stroke colors', function () {
|
|
15
|
+
var svgContent = '<svg><path stroke="green" stroke-width="2" /></svg>';
|
|
16
|
+
var colors = (0, colors_1.extractColors)(svgContent);
|
|
17
|
+
expect(colors.some(function (c) { return c.stroke === 'green'; })).toBe(true);
|
|
18
|
+
});
|
|
19
|
+
it('should extract opacity values', function () {
|
|
20
|
+
var svgContent = '<svg><circle fill="red" opacity="0.5" /></svg>';
|
|
21
|
+
var colors = (0, colors_1.extractColors)(svgContent);
|
|
22
|
+
var redColor = colors.find(function (c) { return c.fill === 'red'; });
|
|
23
|
+
expect(redColor === null || redColor === void 0 ? void 0 : redColor.opacity).toBe(0.5);
|
|
24
|
+
});
|
|
25
|
+
it('should ignore transparent and none values', function () {
|
|
26
|
+
var svgContent = '<svg><circle fill="none" stroke="transparent" /><rect fill="red" /></svg>';
|
|
27
|
+
var colors = (0, colors_1.extractColors)(svgContent);
|
|
28
|
+
expect(colors.some(function (c) { return c.fill === 'none'; })).toBe(false);
|
|
29
|
+
expect(colors.some(function (c) { return c.stroke === 'transparent'; })).toBe(false);
|
|
30
|
+
expect(colors.some(function (c) { return c.fill === 'red'; })).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
it('should work with SVG element input', function () {
|
|
33
|
+
var svgContent = '<svg><circle fill="purple" /></svg>';
|
|
34
|
+
var element = (0, element_1.createSVGElement)(svgContent);
|
|
35
|
+
var colors = (0, colors_1.extractColors)(element);
|
|
36
|
+
expect(colors.some(function (c) { return c.fill === 'purple'; })).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
it('should handle nested elements', function () {
|
|
39
|
+
var svgContent = '<svg><g><circle fill="red" /><rect fill="blue" /></g></svg>';
|
|
40
|
+
var colors = (0, colors_1.extractColors)(svgContent);
|
|
41
|
+
expect(colors.some(function (c) { return c.fill === 'red'; })).toBe(true);
|
|
42
|
+
expect(colors.some(function (c) { return c.fill === 'blue'; })).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=colors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colors.test.js","sourceRoot":"","sources":["../../../src/analyze/__tests__/colors.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
var paths_1 = require("../paths");
|
|
4
|
+
var element_1 = require("../../core/element");
|
|
5
|
+
describe('Path Analysis', function () {
|
|
6
|
+
describe('parsePathData', function () {
|
|
7
|
+
it('should parse simple path commands', function () {
|
|
8
|
+
var pathData = 'M 10,20 L 30,40 Z';
|
|
9
|
+
var commands = (0, paths_1.parsePathData)(pathData);
|
|
10
|
+
expect(commands.length).toBe(3);
|
|
11
|
+
expect(commands[0].type).toBe('M');
|
|
12
|
+
expect(commands[0].params).toEqual([10, 20]);
|
|
13
|
+
expect(commands[1].type).toBe('L');
|
|
14
|
+
expect(commands[2].type).toBe('Z');
|
|
15
|
+
});
|
|
16
|
+
it('should handle lowercase commands', function () {
|
|
17
|
+
var pathData = 'm 10,20 l 30,40 z';
|
|
18
|
+
var commands = (0, paths_1.parsePathData)(pathData);
|
|
19
|
+
expect(commands.length).toBe(3);
|
|
20
|
+
expect(commands[0].type).toBe('m');
|
|
21
|
+
});
|
|
22
|
+
it('should handle multiple parameters', function () {
|
|
23
|
+
var pathData = 'M 10,20 L 30,40 50,60';
|
|
24
|
+
var commands = (0, paths_1.parsePathData)(pathData);
|
|
25
|
+
expect(commands[1].params.length).toBe(4);
|
|
26
|
+
});
|
|
27
|
+
it('should handle cubic bezier commands', function () {
|
|
28
|
+
var pathData = 'M 10,20 C 20,30 40,50 60,70';
|
|
29
|
+
var commands = (0, paths_1.parsePathData)(pathData);
|
|
30
|
+
expect(commands.length).toBe(2);
|
|
31
|
+
expect(commands[1].type).toBe('C');
|
|
32
|
+
expect(commands[1].params.length).toBe(6);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe('analyzePaths', function () {
|
|
36
|
+
it('should analyze all paths in SVG', function () {
|
|
37
|
+
var svgContent = '<svg><path id="path1" d="M 10,20 L 30,40" /><path id="path2" d="M 50,60 L 70,80" /></svg>';
|
|
38
|
+
var analysis = (0, paths_1.analyzePaths)(svgContent);
|
|
39
|
+
expect(analysis.size).toBe(2);
|
|
40
|
+
expect(analysis.has('path1')).toBe(true);
|
|
41
|
+
expect(analysis.has('path2')).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
it('should use index as id if path has no id', function () {
|
|
44
|
+
var svgContent = '<svg><path d="M 10,20" /><path d="M 30,40" /></svg>';
|
|
45
|
+
var analysis = (0, paths_1.analyzePaths)(svgContent);
|
|
46
|
+
expect(analysis.has('path-0')).toBe(true);
|
|
47
|
+
expect(analysis.has('path-1')).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
it('should work with SVG element input', function () {
|
|
50
|
+
var svgContent = '<svg><path d="M 10,20 L 30,40" /></svg>';
|
|
51
|
+
var element = (0, element_1.createSVGElement)(svgContent);
|
|
52
|
+
var analysis = (0, paths_1.analyzePaths)(element);
|
|
53
|
+
expect(analysis.size).toBe(1);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
describe('getPathStatistics', function () {
|
|
57
|
+
it('should return correct statistics', function () {
|
|
58
|
+
var svgContent = '<svg><path d="M 10,20 L 30,40 Z" /><path d="M 50,60 L 70,80" /></svg>';
|
|
59
|
+
var stats = (0, paths_1.getPathStatistics)(svgContent);
|
|
60
|
+
expect(stats.totalPaths).toBe(2);
|
|
61
|
+
expect(stats.totalCommands).toBeGreaterThan(0);
|
|
62
|
+
expect(stats.commandTypes['M']).toBeGreaterThan(0);
|
|
63
|
+
expect(stats.commandTypes['L']).toBeGreaterThan(0);
|
|
64
|
+
});
|
|
65
|
+
it('should count command types correctly', function () {
|
|
66
|
+
var svgContent = '<svg><path d="M 10,20 M 30,40 L 50,60 L 70,80" /></svg>';
|
|
67
|
+
var stats = (0, paths_1.getPathStatistics)(svgContent);
|
|
68
|
+
expect(stats.commandTypes['M']).toBe(2);
|
|
69
|
+
expect(stats.commandTypes['L']).toBe(2);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
//# sourceMappingURL=paths.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.test.js","sourceRoot":"","sources":["../../../src/analyze/__tests__/paths.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* SVG color analysis utilities
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.extractColors = extractColors;
|
|
7
|
+
var jsdom_1 = require("jsdom");
|
|
8
|
+
var element_1 = require("../core/element");
|
|
9
|
+
var validation_1 = require("../utils/validation");
|
|
10
|
+
/**
|
|
11
|
+
* Extracts all colors used in an SVG
|
|
12
|
+
*/
|
|
13
|
+
function extractColors(svgContent) {
|
|
14
|
+
var svgString = (0, validation_1.isValidSvgString)(svgContent)
|
|
15
|
+
? svgContent
|
|
16
|
+
: (0, element_1.serializeSVG)(svgContent);
|
|
17
|
+
var dom = new jsdom_1.JSDOM(svgString, {
|
|
18
|
+
contentType: 'image/svg+xml'
|
|
19
|
+
});
|
|
20
|
+
var document = dom.window.document;
|
|
21
|
+
var svgElement = document.querySelector('svg');
|
|
22
|
+
if (!svgElement) {
|
|
23
|
+
throw new Error('No SVG element found in the provided content.');
|
|
24
|
+
}
|
|
25
|
+
var colors = [];
|
|
26
|
+
var colorSet = new Set();
|
|
27
|
+
function extractFromElement(element) {
|
|
28
|
+
var fill = element.getAttribute('fill');
|
|
29
|
+
var stroke = element.getAttribute('stroke');
|
|
30
|
+
var opacity = element.getAttribute('opacity');
|
|
31
|
+
if (fill && fill !== 'none' && fill !== 'transparent') {
|
|
32
|
+
var colorKey = "".concat(fill, "-").concat(opacity || '1');
|
|
33
|
+
if (!colorSet.has(colorKey)) {
|
|
34
|
+
colorSet.add(colorKey);
|
|
35
|
+
colors.push({
|
|
36
|
+
fill: fill,
|
|
37
|
+
opacity: opacity ? parseFloat(opacity) : undefined
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (stroke && stroke !== 'none' && stroke !== 'transparent') {
|
|
42
|
+
var colorKey = "stroke-".concat(stroke, "-").concat(opacity || '1');
|
|
43
|
+
if (!colorSet.has(colorKey)) {
|
|
44
|
+
colorSet.add(colorKey);
|
|
45
|
+
colors.push({
|
|
46
|
+
stroke: stroke,
|
|
47
|
+
opacity: opacity ? parseFloat(opacity) : undefined
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
Array.from(element.children).forEach(function (child) {
|
|
52
|
+
extractFromElement(child);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
extractFromElement(svgElement);
|
|
56
|
+
return colors;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=colors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"colors.js","sourceRoot":"","sources":["../../src/analyze/colors.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAUH,sCAsDC;AA9DD,+BAA8B;AAC9B,2CAA+C;AAC/C,kDAA0E;AAG1E;;GAEG;AACH,SAAgB,aAAa,CAAC,UAA4B;IACxD,IAAM,SAAS,GAAG,IAAA,6BAAgB,EAAC,UAAU,CAAC;QAC5C,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC,IAAA,sBAAY,EAAC,UAAU,CAAC,CAAC;IAE7B,IAAM,GAAG,GAAG,IAAI,aAAK,CAAC,SAAS,EAAE;QAC/B,WAAW,EAAE,eAAe;KAC7B,CAAC,CAAC;IAEH,IAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC;IACrC,IAAM,UAAU,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAEjD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IAED,IAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,IAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IAEnC,SAAS,kBAAkB,CAAC,OAAgB;QAC1C,IAAM,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC;QAEhD,IAAI,IAAI,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YACtD,IAAM,QAAQ,GAAG,UAAG,IAAI,cAAI,OAAO,IAAI,GAAG,CAAE,CAAC;YAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC;oBACV,IAAI,MAAA;oBACJ,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;iBACnD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,MAAM,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;YAC5D,IAAM,QAAQ,GAAG,iBAAU,MAAM,cAAI,OAAO,IAAI,GAAG,CAAE,CAAC;YACtD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC5B,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACvB,MAAM,CAAC,IAAI,CAAC;oBACV,MAAM,QAAA;oBACN,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS;iBACnD,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,UAAA,KAAK;YACxC,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAE/B,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVG path analysis utilities
|
|
3
|
+
*/
|
|
4
|
+
import { PathCommand } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Parses the 'd' attribute of a path element into command objects
|
|
7
|
+
*/
|
|
8
|
+
export declare function parsePathData(pathData: string): PathCommand[];
|
|
9
|
+
/**
|
|
10
|
+
* Analyzes all paths in an SVG and returns their command structures
|
|
11
|
+
*/
|
|
12
|
+
export declare function analyzePaths(svgContent: Element | string): Map<string, PathCommand[]>;
|
|
13
|
+
/**
|
|
14
|
+
* Gets statistics about paths in an SVG
|
|
15
|
+
*/
|
|
16
|
+
export declare function getPathStatistics(svgContent: Element | string): {
|
|
17
|
+
totalPaths: number;
|
|
18
|
+
totalCommands: number;
|
|
19
|
+
commandTypes: Record<string, number>;
|
|
20
|
+
};
|