'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 isMissingLibtool(code) { // testcases/3.txt return (code.includes("Can't exec \"libtoolize\": No such file or directory")); } 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 (isMissingLibtool(code)) { return "missingLibtool"; } 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; }