Skip to content

Commit

Permalink
Improve performance and accuracy
Browse files Browse the repository at this point in the history
  • Loading branch information
sindresorhus committed Mar 16, 2021
1 parent 1f34e79 commit 732fc72
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 39 deletions.
51 changes: 27 additions & 24 deletions index.js
@@ -1,37 +1,40 @@
'use strict';
const htmlCommentRegex = require('html-comment-regex');
const parser = require('fast-xml-parser');

const isBinary = buffer => {
const isBuffer = Buffer.isBuffer(buffer);
const isSvg = input => {
if (input === undefined || input === null) {
return false;
}

for (let i = 0; i < 24; i++) {
const characterCode = isBuffer ? buffer[i] : buffer.charCodeAt(i);
input = input.toString().trim();

if (characterCode === 65533 || characterCode <= 8) {
return true;
}
if (input.length === 0) {
return false;
}

return false;
};

const cleanEntities = svg => {
const entityRegex = /\s*<!Entity\s+\S*\s*(?:"|')[^"]+(?:"|')\s*>/img;
// Remove entities
return svg.replace(entityRegex, '');
};
// Has to be `!==` as it can also return an object with error info.
console.log('a', parser.validate(input));
if (parser.validate(input) !== true) {
return false;
}

const removeDtdMarkupDeclarations = svg => svg.replace(/\[?(?:\s*<![A-Z]+[^>]*>\s*)*\]?/g, '');
let jsonObject;
try {
jsonObject = parser.parse(input);
} catch (_) {
return false;
}

const clean = svg => {
svg = cleanEntities(svg);
svg = removeDtdMarkupDeclarations(svg);
return svg;
};
if (!jsonObject) {
return false;
}

const regex = /^\s*(?:<\?xml[^>]*>\s*)?(?:<!doctype svg[^>]*>\s*)?(?:<svg[^>]*>[^]*<\/svg>|<svg[^/>]*\/\s*>)\s*$/i;
if (!('svg' in jsonObject)) {
return false;
}

const isSvg = input => Boolean(input) && !isBinary(input) && regex.test(clean(input.toString()).replace(htmlCommentRegex, ''));
return true;
};

module.exports = isSvg;
// TODO: Remove this for the next major release
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -37,7 +37,7 @@
"buffer"
],
"dependencies": {
"html-comment-regex": "^1.1.2"
"fast-xml-parser": "^3.19.0"
},
"devDependencies": {
"@types/node": "^11.13.0",
Expand Down
8 changes: 0 additions & 8 deletions readme.md
Expand Up @@ -17,14 +17,6 @@ isSvg('<svg xmlns="http://www.w3.org/2000/svg"><path fill="#00CD9F"/></svg>');
//=> true
```

## Edge cases

This module performs a quick-and-dirty check. It's fast, but in certain cases it will give incorrect results.

- Returns `true` for an SVG-like string that isn't well-formed or valid: `<svg><div></svg>`

If you want to make certain that your SVG is *valid*, try parsing it with [libxmljs](https://github.com/polotek/libxmljs).

---

<div align="center">
Expand Down
15 changes: 9 additions & 6 deletions test.js
Expand Up @@ -24,16 +24,19 @@ test('valid SVGs', t => {

test('invalid SVGs', t => {
t.false(isSvg(fs.readFileSync('fixtures/fixture.jpg')));
t.false(isSvg('this is not svg, but it mentions <svg> tags'));
t.false(isSvg('<svg> hello I am an svg oops maybe not'));
t.false(isSvg('<svg></svg> this string starts with an svg'));
t.false(isSvg('this string ends with an svg <svg></svg>'));
t.false(isSvg('<div><svg></svg>'));
t.false(isSvg('<div><svg></svg></div>'));
t.false(isSvg('this string contains an svg <svg></svg> in the middle'));
t.false(isSvg(fs.readFileSync('readme.md')));
t.false(isSvg(fs.readFileSync('index.js')));
t.false(isSvg());
t.false(isSvg('this string contains an svg <svg></svg> in the middle'));
t.false(isSvg('<svg><div></svg>'));
t.false(isSvg('this string ends with an svg <svg></svg>'));
t.false(isSvg('<svg> hello I am an svg oops maybe not'));
t.false(isSvg('this is not svg, but it mentions <svg> tags'));
t.false(isSvg(fs.readFileSync('readme.md')));

// https://github.com/NaturalIntelligence/fast-xml-parser/issues/327
// t.false(isSvg('<svg></svg> this string starts with an svg'));
});

test('supports non-english characters', t => {
Expand Down

0 comments on commit 732fc72

Please sign in to comment.