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.

197 lines
5.1 KiB
JavaScript

'use strict';
const regexExecAll = require("./regex/exec-all");
function isMissingBuildEnvironment(code) {
return /Windows SDK version [0-9.]+ was not found/.test(code);
}
function isBrokenBuildEnvironment(code) {
// ex. https://stackoverflow.com/questions/31936170/npm-the-ld-library-not-found-for-lgcc-s-10-5-on-on-os-x-el-capitain
return (code.indexOf("library not found for -lgcc_s.10.5") !== -1);
}
function isMissingPython(code) {
// testcases/1.txt
return (
code.indexOf("Can't find Python executable") !== -1 ||
/Command failed:.+python\.exe/i.test(code)
);
}
function isWrongPython(code) {
return /Python executable "[^"]*" is v[^,]+, which is not supported by gyp./.test(code);
}
function isBindingSyntaxError(code) {
// ex. https://github.com/nodejs/node-gyp/issues/979
return /File "binding.gyp",[\s\S]+SyntaxError: invalid syntax/.test(code);
}
function isMissingNodeHeaders(code) {
return (code.indexOf("common.gypi not found") !== -1);
}
function isGCCVersionError(code) {
// ex. https://github.com/nodejs/node-gyp/issues/233#issuecomment-181912859
return (code.indexOf("requires a C++11 compiler") !== -1);
}
function isNanError(code) {
// ex. http://pastebin.com/SzdS5YBa
return (code.indexOf("NanNew") !== -1) || /Nan::[a-zA-Z]+/.test(code);
}
function isV8Error(code) {
return /V8::[a-zA-Z]+/i.test(code);
}
function isSymlinkIssue(code) {
// ex. http://pastebin.com/ASxGthw2
return /npm ERR\!.+\.bin'/.test(code);
}
function isNPMBug(code) {
return (code.indexOf("file already exists, mkdir") !== -1);
}
function isUnmetDependency(code) {
// ex. http://pastebin.com/ASxGthw2
return (code.indexOf("UNMET DEPENDENCY") !== -1);
}
function isUnmetPeerDependency(code) {
// ex. http://pastebin.com/ASxGthw2
return (code.indexOf("UNMET PEER DEPENDENCY") !== -1);
}
let missingLibraryRegex = /(?:(?:fatal error|warning): ([^\.]+\.h): No such file or directory|Package (.+) was not found in the pkg-config search path)/g
let missingDependencyRegex = /UNMET DEPENDENCY ([^@]+)@(.+)/g
let missingPeerDependencyRegex = /UNMET PEER DEPENDENCY ([^@]+)@(.+)/g
function isLibraryMissingError(code) {
// ex. https://github.com/JustinTulloss/zeromq.node/issues/456
// ex. https://github.com/Automattic/node-canvas/issues/246
return missingLibraryRegex.test(code);
}
function getMissingLibraries(code) {
// alternatively: include <([^>]+)>
return regexExecAll(missingLibraryRegex, code).map((match) => match[1] || match[2]);
}
function getMissingDependencies(code) {
// ex. http://pastebin.com/ASxGthw2
return regexExecAll(missingDependencyRegex, code).map((match) => {
return {
name: match[1],
version: match[2]
};
});
}
function getMissingPeerDependencies(code) {
// ex. http://pastebin.com/ASxGthw2
return regexExecAll(missingPeerDependencyRegex, code).map((match) => {
return {
name: match[1],
version: match[2]
};
});
}
function isLibraryVersionError(code) {
return /binding.cc:[0-9]+: error/.test(code);
}
function getOffendingModule(code) {
let match = /Failed at the ([^@]+)@[^\s]+ install script '.+'.\n/.exec(code);
if (match != null) {
return match[1];
} else {
// Try to determine the offending module from the node-gyp working directory.
// This is useful if eg. the user only copied the `gyp` part of the output.
let match = /gyp ERR! cwd .+[\/\\]node_modules[\/\\]([^\/\\\n]+).*\n/.exec(code);
if (match != null) {
return match[1];
} else {
throw new Error("Could not determine the offending module");
}
}
}
function getErrorType(code) {
if (isMissingBuildEnvironment(code)) {
return "missingEnvironment";
} else if (isBrokenBuildEnvironment(code)) {
return "brokenEnvironment";
} else if (isMissingPython(code)) {
return "missingPython";
} else if (isWrongPython(code)) {
return "wrongPython";
} else if (isBindingSyntaxError(code)) {
return "bindingSyntax";
} else if (isMissingNodeHeaders(code)) {
return "headers";
} else if (isGCCVersionError(code)) {
return "gcc";
} else if (isLibraryMissingError(code)) {
return "missingLibrary";
} else if (isNanError(code)) {
return "nan";
} else if (isV8Error(code)) {
return "v8";
} else if (isLibraryVersionError(code)) {
return "libraryVersion";
} else if (isSymlinkIssue(code)) {
return "symlinkIssue";
} else if (isNPMBug(code)) {
return "npmBug";
} else if (isUnmetDependency(code)) {
return "unmetDependency";
} else if (isUnmetPeerDependency(code)) {
return "unmetPeerDependency";
} else {
throw new Error("Unknown error");
}
}
module.exports = function(code) {
let type = getErrorType(code);
let errorObject = {
type: type,
data: {}
}
if (type === "missingLibrary") {
Object.assign(errorObject.data, {
missingLibraries: getMissingLibraries(code)
});
}
if (type === "unmetDependency") {
Object.assign(errorObject.data, {
missingModules: getMissingDependencies(code)
});
}
if (type === "unmetPeerDependency") {
Object.assign(errorObject.data, {
missingModules: getMissingPeerDependencies(code)
});
}
try {
Object.assign(errorObject.data, {
offendingModule: getOffendingModule(code)
});
} catch (err) {
// do nothing...
}
return errorObject;
}