38 lines
1.2 KiB
JavaScript
38 lines
1.2 KiB
JavaScript
import { parse, parseFragment } from 'parse5';
|
|
import { SaxesParser } from 'saxes';
|
|
|
|
function visit(node, callback, insideSvg = false) {
|
|
callback(node, insideSvg);
|
|
const childInsideSvg = insideSvg || node.tagName === 'svg';
|
|
for (const child of node.childNodes || []) visit(child, callback, childInsideSvg);
|
|
if (node.content) visit(node.content, callback, childInsideSvg);
|
|
}
|
|
|
|
export function parseXml(source) {
|
|
return new SaxesParser({ xmlns: true }).write(source).close();
|
|
}
|
|
|
|
export function extractSvgs(markup, fragment = false) {
|
|
const document = fragment
|
|
? parseFragment(markup, { sourceCodeLocationInfo: true })
|
|
: parse(markup, { sourceCodeLocationInfo: true });
|
|
const direct = [];
|
|
const srcdocs = [];
|
|
|
|
visit(document, (node, insideSvg) => {
|
|
if (node.tagName === 'svg' && !insideSvg && node.sourceCodeLocation) {
|
|
direct.push(markup.slice(node.sourceCodeLocation.startOffset, node.sourceCodeLocation.endOffset));
|
|
}
|
|
const srcdoc = node.attrs?.find((attribute) => attribute.name === 'srcdoc');
|
|
if (srcdoc) srcdocs.push(srcdoc.value);
|
|
});
|
|
|
|
return {
|
|
direct,
|
|
embedded: srcdocs.flatMap((srcdoc) => {
|
|
const nested = extractSvgs(srcdoc, true);
|
|
return [...nested.direct, ...nested.embedded];
|
|
}),
|
|
};
|
|
}
|