mirror of
https://github.com/svg/svgo.git
synced 2025-07-29 20:21:14 +03:00
Add better parser errors (#1553)
Old SVGO errors were not very helpful. Packages like cssnano (postcss-svgo) had to deal with a lot of issues which are hard to debug with old errors. ``` Error: Error in parsing SVG: Unquoted attribute value Line: 1 Column: 29 Char: 6 File: input.svg ``` New errors are more informative and may solve many struggles ``` Error: SvgoParserError: input.svg:2:29: Unquoted attribute value 1 | <svg viewBox="0 0 120 120"> > 2 | <circle fill="#ff0000" cx=60.444444" cy="60" r="50"/> | ^ 3 | </svg> 4 | ```
This commit is contained in:
@ -29,7 +29,12 @@ const optimize = (input, config) => {
|
||||
}
|
||||
for (let i = 0; i < maxPassCount; i += 1) {
|
||||
info.multipassCount = i;
|
||||
svgjs = svg2js(input);
|
||||
// TODO throw this error in v3
|
||||
try {
|
||||
svgjs = svg2js(input, config.path);
|
||||
} catch (error) {
|
||||
return { error: error.toString(), modernError: error };
|
||||
}
|
||||
if (svgjs.error != null) {
|
||||
if (config.path != null) {
|
||||
svgjs.path = config.path;
|
||||
|
120
lib/svgo.test.js
120
lib/svgo.test.js
@ -12,12 +12,11 @@ test('allow to setup default preset', () => {
|
||||
<circle fill="#ff0000" cx="60" cy="60" r="50"/>
|
||||
</svg>
|
||||
`;
|
||||
expect(
|
||||
optimize(svg, {
|
||||
const { data } = optimize(svg, {
|
||||
plugins: ['preset-default'],
|
||||
js2svg: { pretty: true, indent: 2 },
|
||||
}).data
|
||||
).toMatchInlineSnapshot(`
|
||||
});
|
||||
expect(data).toMatchInlineSnapshot(`
|
||||
"<svg viewBox=\\"0 0 120 120\\">
|
||||
<circle fill=\\"red\\" cx=\\"60\\" cy=\\"60\\" r=\\"50\\"/>
|
||||
</svg>
|
||||
@ -35,8 +34,7 @@ test('allow to disable and customize plugins in preset', () => {
|
||||
<circle fill="#ff0000" cx="60" cy="60" r="50"/>
|
||||
</svg>
|
||||
`;
|
||||
expect(
|
||||
optimize(svg, {
|
||||
const { data } = optimize(svg, {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
@ -51,8 +49,8 @@ test('allow to disable and customize plugins in preset', () => {
|
||||
},
|
||||
],
|
||||
js2svg: { pretty: true, indent: 2 },
|
||||
}).data
|
||||
).toMatchInlineSnapshot(`
|
||||
});
|
||||
expect(data).toMatchInlineSnapshot(`
|
||||
"<?xml version=\\"1.0\\" encoding=\\"utf-8\\"?>
|
||||
<svg viewBox=\\"0 0 120 120\\">
|
||||
<desc>
|
||||
@ -186,8 +184,7 @@ test('allow to customize precision for preset', () => {
|
||||
<circle fill="#ff0000" cx="60.444444" cy="60" r="50"/>
|
||||
</svg>
|
||||
`;
|
||||
expect(
|
||||
optimize(svg, {
|
||||
const { data } = optimize(svg, {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
@ -197,8 +194,8 @@ test('allow to customize precision for preset', () => {
|
||||
},
|
||||
],
|
||||
js2svg: { pretty: true, indent: 2 },
|
||||
}).data
|
||||
).toMatchInlineSnapshot(`
|
||||
});
|
||||
expect(data).toMatchInlineSnapshot(`
|
||||
"<svg viewBox=\\"0 0 120 120\\">
|
||||
<circle fill=\\"red\\" cx=\\"60.4444\\" cy=\\"60\\" r=\\"50\\"/>
|
||||
</svg>
|
||||
@ -212,8 +209,7 @@ test('plugin precision should override preset precision', () => {
|
||||
<circle fill="#ff0000" cx="60.444444" cy="60" r="50"/>
|
||||
</svg>
|
||||
`;
|
||||
expect(
|
||||
optimize(svg, {
|
||||
const { data } = optimize(svg, {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
@ -228,11 +224,103 @@ test('plugin precision should override preset precision', () => {
|
||||
},
|
||||
],
|
||||
js2svg: { pretty: true, indent: 2 },
|
||||
}).data
|
||||
).toMatchInlineSnapshot(`
|
||||
});
|
||||
expect(data).toMatchInlineSnapshot(`
|
||||
"<svg viewBox=\\"0 0 120 120\\">
|
||||
<circle fill=\\"red\\" cx=\\"60.44444\\" cy=\\"60\\" r=\\"50\\"/>
|
||||
</svg>
|
||||
"
|
||||
`);
|
||||
});
|
||||
|
||||
test('provides informative error in result', () => {
|
||||
const svg = `<svg viewBox="0 0 120 120">
|
||||
<circle fill="#ff0000" cx=60.444444" cy="60" r="50"/>
|
||||
</svg>
|
||||
`;
|
||||
const { modernError: error } = optimize(svg, { path: 'test.svg' });
|
||||
expect(error.name).toEqual('SvgoParserError');
|
||||
expect(error.message).toEqual('test.svg:2:33: Unquoted attribute value');
|
||||
expect(error.reason).toEqual('Unquoted attribute value');
|
||||
expect(error.line).toEqual(2);
|
||||
expect(error.column).toEqual(33);
|
||||
expect(error.source).toEqual(svg);
|
||||
});
|
||||
|
||||
test('provides code snippet in rendered error', () => {
|
||||
const svg = `<svg viewBox="0 0 120 120">
|
||||
<circle fill="#ff0000" cx=60.444444" cy="60" r="50"/>
|
||||
</svg>
|
||||
`;
|
||||
const { modernError: error } = optimize(svg, { path: 'test.svg' });
|
||||
expect(error.toString())
|
||||
.toEqual(`SvgoParserError: test.svg:2:29: Unquoted attribute value
|
||||
|
||||
1 | <svg viewBox="0 0 120 120">
|
||||
> 2 | <circle fill="#ff0000" cx=60.444444" cy="60" r="50"/>
|
||||
| ^
|
||||
3 | </svg>
|
||||
4 |
|
||||
`);
|
||||
});
|
||||
|
||||
test('supports errors without path', () => {
|
||||
const svg = `<svg viewBox="0 0 120 120">
|
||||
<circle/>
|
||||
<circle/>
|
||||
<circle/>
|
||||
<circle/>
|
||||
<circle/>
|
||||
<circle/>
|
||||
<circle/>
|
||||
<circle/>
|
||||
<circle/>
|
||||
<circle fill="#ff0000" cx=60.444444" cy="60" r="50"/>
|
||||
</svg>
|
||||
`;
|
||||
const { modernError: error } = optimize(svg);
|
||||
expect(error.toString())
|
||||
.toEqual(`SvgoParserError: <input>:11:29: Unquoted attribute value
|
||||
|
||||
9 | <circle/>
|
||||
10 | <circle/>
|
||||
> 11 | <circle fill="#ff0000" cx=60.444444" cy="60" r="50"/>
|
||||
| ^
|
||||
12 | </svg>
|
||||
13 |
|
||||
`);
|
||||
});
|
||||
|
||||
test('slices long line in error code snippet', () => {
|
||||
const svg = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" viewBox="0 0 230 120">
|
||||
<path d="M318.198 551.135 530.33 918.56l-289.778-77.646 38.823-144.889c77.646-289.778 294.98-231.543 256.156-86.655s178.51 203.124 217.334 58.235q58.234-217.334 250.955 222.534t579.555 155.292z stroke-width="1.5" fill="red" stroke="red" />
|
||||
</svg>
|
||||
`;
|
||||
const { modernError: error } = optimize(svg);
|
||||
expect(error.toString())
|
||||
.toEqual(`SvgoParserError: <input>:2:211: Invalid attribute name
|
||||
|
||||
1 | …-0.dtd" viewBox="0 0 230 120">
|
||||
> 2 | …7.334 250.955 222.534t579.555 155.292z stroke-width="1.5" fill="red" strok…
|
||||
| ^
|
||||
3 |
|
||||
4 |
|
||||
`);
|
||||
});
|
||||
|
||||
test('provides legacy error message', () => {
|
||||
const svg = `<svg viewBox="0 0 120 120">
|
||||
<circle fill="#ff0000" cx=60.444444" cy="60" r="50"/>
|
||||
</svg>
|
||||
`;
|
||||
const { error } = optimize(svg, { path: 'test.svg' });
|
||||
expect(error)
|
||||
.toEqual(`SvgoParserError: test.svg:2:29: Unquoted attribute value
|
||||
|
||||
1 | <svg viewBox="0 0 120 120">
|
||||
> 2 | <circle fill="#ff0000" cx=60.444444" cy="60" r="50"/>
|
||||
| ^
|
||||
3 | </svg>
|
||||
4 |
|
||||
`);
|
||||
});
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
const FS = require('fs');
|
||||
const PATH = require('path');
|
||||
const { green } = require('colorette');
|
||||
const { green, red } = require('colorette');
|
||||
const { loadConfig, optimize } = require('../svgo-node.js');
|
||||
const pluginsMap = require('../../plugins/plugins.js');
|
||||
const PKG = require('../../package.json');
|
||||
@ -383,12 +383,9 @@ function processSVGData(config, info, data, output, input) {
|
||||
prevFileSize = Buffer.byteLength(data, 'utf8');
|
||||
|
||||
const result = optimize(data, { ...config, ...info });
|
||||
if (result.error) {
|
||||
let message = result.error;
|
||||
if (result.path != null) {
|
||||
message += `\nFile: ${result.path}`;
|
||||
}
|
||||
throw Error(message);
|
||||
if (result.modernError) {
|
||||
console.error(red(result.modernError.toString()));
|
||||
process.exit(1);
|
||||
}
|
||||
if (config.datauri) {
|
||||
result.data = encodeSVGDatauri(result.data, config.datauri);
|
||||
|
@ -4,6 +4,55 @@ const SAX = require('@trysound/sax');
|
||||
const JSAPI = require('./jsAPI.js');
|
||||
const { textElems } = require('../../plugins/_collections.js');
|
||||
|
||||
class SvgoParserError extends Error {
|
||||
constructor(message, line, column, source, file) {
|
||||
super(message);
|
||||
this.name = 'SvgoParserError';
|
||||
this.message = `${file || '<input>'}:${line}:${column}: ${message}`;
|
||||
this.reason = message;
|
||||
this.line = line;
|
||||
this.column = column;
|
||||
this.source = source;
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, SvgoParserError);
|
||||
}
|
||||
}
|
||||
toString() {
|
||||
const lines = this.source.split(/\r?\n/);
|
||||
const startLine = Math.max(this.line - 3, 0);
|
||||
const endLine = Math.min(this.line + 2, lines.length);
|
||||
const lineNumberWidth = String(endLine).length;
|
||||
const startColumn = Math.max(this.column - 54, 0);
|
||||
const endColumn = Math.max(this.column + 20, 80);
|
||||
const code = lines
|
||||
.slice(startLine, endLine)
|
||||
.map((line, index) => {
|
||||
const lineSlice = line.slice(startColumn, endColumn);
|
||||
let ellipsisPrefix = '';
|
||||
let ellipsisSuffix = '';
|
||||
if (startColumn !== 0) {
|
||||
ellipsisPrefix = startColumn > line.length - 1 ? ' ' : '…';
|
||||
}
|
||||
if (endColumn < line.length - 1) {
|
||||
ellipsisSuffix = '…';
|
||||
}
|
||||
const number = startLine + 1 + index;
|
||||
const gutter = ` ${number.toString().padStart(lineNumberWidth)} | `;
|
||||
if (number === this.line) {
|
||||
const gutterSpacing = gutter.replace(/[^|]/g, ' ');
|
||||
const lineSpacing = (
|
||||
ellipsisPrefix + line.slice(startColumn, this.column - 1)
|
||||
).replace(/[^\t]/g, ' ');
|
||||
const spacing = gutterSpacing + lineSpacing;
|
||||
return `>${gutter}${ellipsisPrefix}${lineSlice}${ellipsisSuffix}\n ${spacing}^`;
|
||||
}
|
||||
return ` ${gutter}${ellipsisPrefix}${lineSlice}${ellipsisSuffix}`;
|
||||
})
|
||||
.join('\n');
|
||||
return `${this.name}: ${this.message}\n\n${code}\n`;
|
||||
}
|
||||
}
|
||||
|
||||
const entityDeclaration = /<!ENTITY\s+(\S+)\s+(?:'([^']+)'|"([^"]+)")\s*>/g;
|
||||
|
||||
const config = {
|
||||
@ -20,7 +69,7 @@ const config = {
|
||||
*
|
||||
* @param {String} data input data
|
||||
*/
|
||||
module.exports = function (data) {
|
||||
module.exports = function (data, from) {
|
||||
const sax = SAX.parser(config.strict, config);
|
||||
const root = new JSAPI({ type: 'root', children: [] });
|
||||
let current = root;
|
||||
@ -115,16 +164,18 @@ module.exports = function (data) {
|
||||
};
|
||||
|
||||
sax.onerror = function (e) {
|
||||
e.message = 'Error in parsing SVG: ' + e.message;
|
||||
if (e.message.indexOf('Unexpected end') < 0) {
|
||||
throw e;
|
||||
const error = new SvgoParserError(
|
||||
e.reason,
|
||||
e.line + 1,
|
||||
e.column,
|
||||
data,
|
||||
from
|
||||
);
|
||||
if (e.message.indexOf('Unexpected end') === -1) {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
sax.write(data).close();
|
||||
return root;
|
||||
} catch (e) {
|
||||
return { error: e.message };
|
||||
}
|
||||
};
|
||||
|
79
package-lock.json
generated
79
package-lock.json
generated
@ -617,6 +617,17 @@
|
||||
"rimraf": "^3.0.0",
|
||||
"slash": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@jest/environment": {
|
||||
@ -867,9 +878,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@trysound/sax": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
|
||||
"integrity": "sha512-Z6DoceYb/1xSg5+e+ZlPZ9v0N16ZvZ+wYMraFue4HYrE4ttONKtsvruIRf6t9TBR0YvSOfi1hUU0fJfBLCDYow=="
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
|
||||
"integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA=="
|
||||
},
|
||||
"@types/babel__core": {
|
||||
"version": "7.1.15",
|
||||
@ -1403,6 +1414,17 @@
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"co": {
|
||||
@ -1852,6 +1874,15 @@
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
|
||||
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -3946,6 +3977,17 @@
|
||||
"requires": {
|
||||
"char-regex": "^1.0.2",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
@ -3957,6 +3999,17 @@
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"string_decoder": {
|
||||
@ -4059,6 +4112,15 @@
|
||||
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
|
||||
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
|
||||
"dev": true
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -4339,6 +4401,17 @@
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
|
@ -92,7 +92,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@trysound/sax": "0.1.1",
|
||||
"@trysound/sax": "0.2.0",
|
||||
"colorette": "^1.3.0",
|
||||
"commander": "^7.2.0",
|
||||
"css-select": "^4.1.3",
|
||||
@ -118,6 +118,7 @@
|
||||
"prettier": "^2.3.2",
|
||||
"rollup": "^2.56.3",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"tar-stream": "^2.2.0",
|
||||
"typescript": "^4.4.2"
|
||||
},
|
||||
|
33
test/cli/cli.test.js
Normal file
33
test/cli/cli.test.js
Normal file
@ -0,0 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
const { spawn } = require('child_process');
|
||||
const stripAnsi = require('strip-ansi');
|
||||
|
||||
test('should exit with 1 code on syntax error', async () => {
|
||||
const proc = spawn('node', ['../../bin/svgo', 'invalid.svg'], {
|
||||
cwd: __dirname,
|
||||
});
|
||||
const [code, stderr] = await Promise.all([
|
||||
new Promise((resolve) => {
|
||||
proc.on('close', (code) => {
|
||||
resolve(code);
|
||||
});
|
||||
}),
|
||||
new Promise((resolve) => {
|
||||
proc.stderr.on('data', (error) => {
|
||||
resolve(error.toString());
|
||||
});
|
||||
}),
|
||||
]);
|
||||
expect(code).toEqual(1);
|
||||
expect(stripAnsi(stderr))
|
||||
.toEqual(`SvgoParserError: invalid.svg:2:27: Unquoted attribute value
|
||||
|
||||
1 | <svg>
|
||||
> 2 | <rect x="0" y="0" width=10" height="20" />
|
||||
| ^
|
||||
3 | </svg>
|
||||
4 |
|
||||
|
||||
`);
|
||||
});
|
3
test/cli/invalid.svg
Normal file
3
test/cli/invalid.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg>
|
||||
<rect x="0" y="0" width=10" height="20" />
|
||||
</svg>
|
After Width: | Height: | Size: 58 B |
@ -341,46 +341,4 @@ describe('svg2js', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('malformed svg', function () {
|
||||
var filepath = PATH.resolve(__dirname, './test.bad.svg'),
|
||||
root,
|
||||
error;
|
||||
|
||||
beforeAll(function (done) {
|
||||
FS.readFile(filepath, 'utf8', function (err, data) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
try {
|
||||
root = SVG2JS(data);
|
||||
} catch (e) {
|
||||
error = e;
|
||||
}
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('root', function () {
|
||||
it('should have property "error"', function () {
|
||||
expect(root).toHaveProperty('error');
|
||||
});
|
||||
});
|
||||
|
||||
describe('root.error', function () {
|
||||
it('should be "Error in parsing SVG: Unexpected close tag"', function () {
|
||||
expect(root.error).toEqual(
|
||||
'Error in parsing SVG: Unexpected close tag\nLine: 10\nColumn: 15\nChar: >'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('error', function () {
|
||||
it('should not be thrown', function () {
|
||||
expect(error).not.toEqual(expect.anything());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="120px" height="120px" viewBox="0 0 120 120"
|
||||
enable-background="new 0 0 120 120" xml:space="preserve"
|
||||
>
|
||||
style type="text/css"><![CDATA[
|
||||
svg { fill: red; }
|
||||
]]></style>
|
||||
<g>
|
||||
<g>
|
||||
<circle fill="#ff0000" cx="60px" cy="60px" r="50px"/>
|
||||
<text>test</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 692 B |
@ -46,14 +46,6 @@ describe('svgo', () => {
|
||||
const result = optimize(original, { input: 'file', path: 'input.svg' });
|
||||
expect(normalize(result.data)).toEqual(expected);
|
||||
});
|
||||
it('should handle parse error', async () => {
|
||||
const fixture = await fs.promises.readFile(
|
||||
path.resolve(__dirname, 'invalid.svg')
|
||||
);
|
||||
const result = optimize(fixture, { input: 'file', path: 'input.svg' });
|
||||
expect(result.error).toMatch(/Error in parsing SVG/);
|
||||
expect(result.path).toEqual('input.svg');
|
||||
});
|
||||
it('should handle empty svg tag', async () => {
|
||||
const result = optimize('<svg />', { input: 'file', path: 'input.svg' });
|
||||
expect(result.data).toEqual('<svg/>');
|
||||
|
@ -10,7 +10,12 @@
|
||||
"resolveJsonModule": true,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": ["plugins/**/*", "lib/xast.test.js", "lib/path.test.js"],
|
||||
"include": [
|
||||
"plugins/**/*",
|
||||
"lib/xast.test.js",
|
||||
"lib/path.test.js",
|
||||
"test/cli/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"plugins/_applyTransforms.js",
|
||||
"plugins/collapseGroups.js",
|
||||
|
Reference in New Issue
Block a user