You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

95 lines
2.5 KiB
JavaScript

"use strict";
const sax = require("sax");
const unreachable = require("@joepie91/unreachable")("detect-svg-scripts");
const { validateArguments } = require("@validatem/core");
const either = require("@validatem/either");
const required = require("@validatem/required");
const isString = require("@validatem/is-string");
const isBuffer = require("@validatem/is-buffer");
const isNodeStream = require("@validatem/is-node-stream");
module.exports = function detectSVGScripts(svgFile) {
validateArguments(arguments, {
svgFile: [ required, either([ isString, isBuffer, isNodeStream.anyReadable ]) ]
});
let parser = sax.createStream(false);
if (typeof svgFile === "string" || Buffer.isBuffer(svgFile)) {
// Make sure that all event listeners have been attached before we feed in any data
process.nextTick(() => {
parser.end(svgFile);
});
} else {
svgFile.pipe(parser);
}
return new Promise((resolve, reject) => {
let occurrences = [];
function detachListeners() {
parser.removeListener("end", onEnd);
parser.removeListener("error", onError);
parser.removeListener("opentag", onTag);
}
function onEnd() {
resolve(occurrences);
detachListeners();
}
function onError(error) {
reject(error);
detachListeners();
}
function onTag(tag) {
let normalizedTag = tag.name
.toLowerCase()
.replace(/.+:([^:]+)$/, (_, actualTag) => actualTag);
let normalizedAttributes = Object.entries(tag.attributes)
.map(([ attribute, value ]) => [ attribute.toLowerCase(), value ]);
if (normalizedTag === "script") {
let externalSources = normalizedAttributes
.filter(([ attribute, _value ]) => attribute === "src")
.map(([ _attribute, value ]) => value);
if (externalSources.length === 1) {
occurrences.push({
type: "externalScriptFile",
tag: tag,
file: externalSources[0]
});
} else if (externalSources.length === 0) {
occurrences.push({
type: "inlineScriptTag",
tag: tag
});
} else {
unreachable("Encountered more than one 'src' key");
}
}
// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/Events
let eventHandlers = normalizedAttributes
.filter(([ attribute, _value ]) => attribute.startsWith("on"));
for (let [ attribute, _value ] of eventHandlers) {
occurrences.push({
type: "eventHandler",
tag: tag,
attribute: attribute
});
}
}
parser.on("error", onError);
parser.on("end", onEnd);
parser.on("opentag", onTag);
});
};