fabric8-analytics-lsp-server
Advanced tools
Comparing version 0.4.16 to 0.4.17
257
collector.js
@@ -6,227 +6,48 @@ /* -------------------------------------------------------------------------------------------- | ||
'use strict'; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.GomodDependencyCollector = exports.ReqDependencyCollector = exports.PackageJsonCollector = void 0; | ||
const jsonAst = require("json-to-ast"); | ||
const types_1 = require("./types"); | ||
const utils_1 = require("./utils"); | ||
const config_1 = require("./config"); | ||
const child_process_1 = require("child_process"); | ||
/* Please note :: There was issue with semverRegex usage in the code. During run time, it extracts | ||
* version with 'v' prefix, but this is not be behavior of semver in CLI and test environment. | ||
* At the moment, using regex directly to extract version information without 'v' prefix. */ | ||
//import semverRegex = require('semver-regex'); | ||
function semVerRegExp(line) { | ||
const regExp = /(?<=^v?|\sv?)(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|[\da-z-]*[a-z-][\da-z-]*)(?:\.(?:0|[1-9]\d*|[\da-z-]*[a-z-][\da-z-]*))*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?(?=$|\s)/ig; | ||
return regExp.exec(line); | ||
} | ||
class NaivePyParser { | ||
constructor(contents) { | ||
this.dependencies = NaivePyParser.parseDependencies(contents); | ||
exports.Dependency = exports.ValueType = exports.Variant = exports.KeyValueEntry = void 0; | ||
/* Determine what is the value */ | ||
var ValueType; | ||
(function (ValueType) { | ||
ValueType[ValueType["Invalid"] = 0] = "Invalid"; | ||
ValueType[ValueType["String"] = 1] = "String"; | ||
ValueType[ValueType["Integer"] = 2] = "Integer"; | ||
ValueType[ValueType["Float"] = 3] = "Float"; | ||
ValueType[ValueType["Array"] = 4] = "Array"; | ||
ValueType[ValueType["Object"] = 5] = "Object"; | ||
ValueType[ValueType["Boolean"] = 6] = "Boolean"; | ||
ValueType[ValueType["Null"] = 7] = "Null"; | ||
})(ValueType || (ValueType = {})); | ||
exports.ValueType = ValueType; | ||
; | ||
; | ||
; | ||
class KeyValueEntry { | ||
constructor(k, pos) { | ||
this.key = k; | ||
this.key_position = pos; | ||
} | ||
static parseDependencies(contents) { | ||
const requirements = contents.split("\n"); | ||
return requirements.reduce((dependencies, req, index) => { | ||
// skip any text after # | ||
if (req.includes('#')) { | ||
req = req.split('#')[0]; | ||
} | ||
const parsedRequirement = req.split(/[==,>=,<=]+/); | ||
const pkgName = (parsedRequirement[0] || '').trim(); | ||
// skip empty lines | ||
if (pkgName.length > 0) { | ||
const version = (parsedRequirement[1] || '').trim(); | ||
const entry = new types_1.KeyValueEntry(pkgName, { line: 0, column: 0 }); | ||
entry.value = new types_1.Variant(types_1.ValueType.String, version); | ||
entry.value_position = { line: index + 1, column: req.indexOf(version) + 1 }; | ||
dependencies.push(new types_1.Dependency(entry)); | ||
} | ||
return dependencies; | ||
}, []); | ||
} | ||
parse() { | ||
return this.dependencies; | ||
} | ||
} | ||
/* Process entries found in the txt files and collect all dependency | ||
* related information */ | ||
class ReqDependencyCollector { | ||
constructor(classes = ["dependencies"]) { | ||
this.classes = classes; | ||
exports.KeyValueEntry = KeyValueEntry; | ||
class Variant { | ||
constructor(type, object) { | ||
this.type = type; | ||
this.object = object; | ||
} | ||
collect(contents) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let parser = new NaivePyParser(contents); | ||
return parser.parse(); | ||
}); | ||
} | ||
} | ||
exports.ReqDependencyCollector = ReqDependencyCollector; | ||
class NaiveGomodParser { | ||
constructor(contents, goImports) { | ||
this.dependencies = NaiveGomodParser.parseDependencies(contents, goImports); | ||
exports.Variant = Variant; | ||
/* Dependency class that can be created from `IKeyValueEntry` */ | ||
class Dependency { | ||
constructor(dependency) { | ||
this.name = { | ||
value: dependency.key, | ||
position: dependency.key_position | ||
}; | ||
this.version = { | ||
value: dependency.value.object, | ||
position: dependency.value_position | ||
}; | ||
} | ||
static getReplaceMap(line, index) { | ||
// split the replace statements by '=>' | ||
const parts = line.replace('replace', '').replace('(', '').replace(')', '').trim().split('=>'); | ||
const replaceWithVersion = semVerRegExp(parts[1]); | ||
// Skip lines without final version string | ||
if (replaceWithVersion && replaceWithVersion.length > 0) { | ||
const replaceTo = (parts[0] || '').trim().split(' '); | ||
const replaceToVersion = semVerRegExp(replaceTo[1]); | ||
const replaceWith = (parts[1] || '').trim().split(' '); | ||
const replaceWithIndex = line.lastIndexOf(parts[1]); | ||
const replaceEntry = new types_1.KeyValueEntry(replaceWith[0].trim(), { line: 0, column: 0 }); | ||
replaceEntry.value = new types_1.Variant(types_1.ValueType.String, 'v' + replaceWithVersion[0]); | ||
replaceEntry.value_position = { line: index + 1, column: (replaceWithIndex + replaceWithVersion.index) }; | ||
const replaceDependency = new types_1.Dependency(replaceEntry); | ||
const isReplaceToVersion = replaceToVersion && replaceToVersion.length > 0; | ||
return { key: replaceTo[0].trim() + (isReplaceToVersion ? ('@v' + replaceToVersion[0]) : ''), value: replaceDependency }; | ||
} | ||
return null; | ||
} | ||
static applyReplaceMap(dep, replaceMap) { | ||
let replaceDependency = replaceMap.get(dep.name.value + "@" + dep.version.value); | ||
if (replaceDependency === undefined) { | ||
replaceDependency = replaceMap.get(dep.name.value); | ||
if (replaceDependency === undefined) { | ||
return dep; | ||
} | ||
} | ||
return replaceDependency; | ||
} | ||
static parseDependencies(contents, goImports) { | ||
let replaceMap = new Map(); | ||
let goModDeps = contents.split("\n").reduce((dependencies, line, index) => { | ||
// skip any text after '//' | ||
if (line.includes("//")) { | ||
line = line.split("//")[0]; | ||
} | ||
if (line.includes("=>")) { | ||
let replaceEntry = NaiveGomodParser.getReplaceMap(line, index); | ||
if (replaceEntry) { | ||
replaceMap.set(replaceEntry.key, replaceEntry.value); | ||
} | ||
} | ||
else { | ||
// Not using semver directly, look at comment on import statement. | ||
//const version = semverRegex().exec(line) | ||
const version = semVerRegExp(line); | ||
// Skip lines without version string | ||
if (version && version.length > 0) { | ||
const parts = line.replace('require', '').replace('(', '').replace(')', '').trim().split(' '); | ||
const pkgName = (parts[0] || '').trim(); | ||
// Ignore line starting with replace clause and empty package | ||
if (pkgName.length > 0) { | ||
const entry = new types_1.KeyValueEntry(pkgName, { line: 0, column: 0 }); | ||
entry.value = new types_1.Variant(types_1.ValueType.String, 'v' + version[0]); | ||
entry.value_position = { line: index + 1, column: version.index }; | ||
// Push all direct and indirect modules present in go.mod (manifest) | ||
dependencies.push(new types_1.Dependency(entry)); | ||
} | ||
} | ||
} | ||
return dependencies; | ||
}, []); | ||
let goPackageDeps = []; | ||
goImports.forEach(importStatement => { | ||
let exactMatchDep = null; | ||
let moduleMatchDep = null; | ||
goModDeps.forEach(goModDep => { | ||
if (importStatement == goModDep.name.value) { | ||
// Software stack uses the module | ||
exactMatchDep = goModDep; | ||
} | ||
else if (importStatement.startsWith(goModDep.name.value + "/")) { | ||
// Find longest module name that matches the import statement | ||
if (moduleMatchDep == null) { | ||
moduleMatchDep = goModDep; | ||
} | ||
else if (moduleMatchDep.name.value.length < goModDep.name.value.length) { | ||
moduleMatchDep = goModDep; | ||
} | ||
} | ||
}); | ||
if (exactMatchDep == null && moduleMatchDep != null) { | ||
// Software stack uses a package from the module | ||
let replaceDependency = NaiveGomodParser.applyReplaceMap(moduleMatchDep, replaceMap); | ||
if (replaceDependency !== moduleMatchDep) { | ||
importStatement = importStatement.replace(moduleMatchDep.name.value, replaceDependency.name.value); | ||
} | ||
const entry = new types_1.KeyValueEntry(importStatement + '@' + replaceDependency.name.value, replaceDependency.name.position); | ||
entry.value = new types_1.Variant(types_1.ValueType.String, replaceDependency.version.value); | ||
entry.value_position = replaceDependency.version.position; | ||
goPackageDeps.push(new types_1.Dependency(entry)); | ||
} | ||
}); | ||
goModDeps = goModDeps.map(goModDep => NaiveGomodParser.applyReplaceMap(goModDep, replaceMap)); | ||
// Return modules present in go.mod and packages used in imports. | ||
return [...goModDeps, ...goPackageDeps]; | ||
} | ||
parse() { | ||
return this.dependencies; | ||
} | ||
} | ||
/* Process entries found in the go.mod file and collect all dependency | ||
* related information */ | ||
class GomodDependencyCollector { | ||
constructor(manifestFile, classes = ["dependencies"]) { | ||
this.manifestFile = manifestFile; | ||
this.classes = classes; | ||
this.manifestFile = manifestFile; | ||
} | ||
collect(contents) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let promiseExec = new Promise((resolve, reject) => { | ||
const vscodeRootpath = this.manifestFile.replace("file://", "").replace("/go.mod", ""); | ||
child_process_1.exec(utils_1.getGoLangImportsCmd(), { shell: process.env["SHELL"], windowsHide: true, cwd: vscodeRootpath, maxBuffer: 1024 * 1200 }, (error, stdout, stderr) => { | ||
if (error) { | ||
console.error(`Command failed, environment SHELL: [${process.env["SHELL"]}] PATH: [${process.env["PATH"]}] CWD: [${process.env["CWD"]}]`); | ||
if (error.code == 127) { // Invalid command, go executable not found | ||
reject(`Unable to locate '${config_1.config.golang_executable}'`); | ||
} | ||
else { | ||
reject(`Unable to execute '${config_1.config.golang_executable} list' command, run '${config_1.config.golang_executable} mod tidy' to know more`); | ||
} | ||
} | ||
else { | ||
resolve(new Set(stdout.toString().split("\n"))); | ||
} | ||
}); | ||
}); | ||
const goImports = yield promiseExec; | ||
let parser = new NaiveGomodParser(contents, goImports); | ||
return parser.parse(); | ||
}); | ||
} | ||
} | ||
exports.GomodDependencyCollector = GomodDependencyCollector; | ||
class PackageJsonCollector { | ||
constructor(classes = ["dependencies"]) { | ||
this.classes = classes; | ||
} | ||
collect(contents) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const ast = jsonAst(contents); | ||
return ast.children. | ||
filter(c => this.classes.includes(c.key.value)). | ||
flatMap(c => c.value.children). | ||
map(c => { | ||
let entry = new types_1.KeyValueEntry(c.key.value, { line: c.key.loc.start.line, column: c.key.loc.start.column + 1 }); | ||
entry.value = new types_1.Variant(types_1.ValueType.String, c.value.value); | ||
entry.value_position = { line: c.value.loc.start.line, column: c.value.loc.start.column + 1 }; | ||
return new types_1.Dependency(entry); | ||
}); | ||
}); | ||
} | ||
} | ||
exports.PackageJsonCollector = PackageJsonCollector; | ||
exports.Dependency = Dependency; | ||
//# sourceMappingURL=collector.js.map |
{ | ||
"name": "fabric8-analytics-lsp-server", | ||
"description": "LSP Server for Dependency Analytics", | ||
"version": "0.4.16", | ||
"version": "0.4.17", | ||
"author": "Pavel Odvody", | ||
@@ -6,0 +6,0 @@ "contributors": [ |
@@ -19,4 +19,6 @@ /* -------------------------------------------------------------------------------------------- | ||
const vscode_languageserver_1 = require("vscode-languageserver"); | ||
const collector_1 = require("./collector"); | ||
const maven_collector_1 = require("./maven.collector"); | ||
const go_mod_1 = require("./collector/go.mod"); | ||
const package_json_1 = require("./collector/package.json"); | ||
const pom_xml_1 = require("./collector/pom.xml"); | ||
const requirements_txt_1 = require("./collector/requirements.txt"); | ||
const consumers_1 = require("./consumers"); | ||
@@ -266,13 +268,13 @@ const aggregators_1 = require("./aggregators"); | ||
files.on(EventStream.Diagnostics, "^package\\.json$", (uri, name, contents) => { | ||
sendDiagnostics('npm', uri, contents, new collector_1.PackageJsonCollector()); | ||
sendDiagnostics('npm', uri, contents, new package_json_1.DependencyCollector()); | ||
}); | ||
files.on(EventStream.Diagnostics, "^pom\\.xml$", (uri, name, contents) => { | ||
sendDiagnostics('maven', uri, contents, new maven_collector_1.PomXmlDependencyCollector()); | ||
sendDiagnostics('maven', uri, contents, new pom_xml_1.DependencyCollector()); | ||
}); | ||
files.on(EventStream.Diagnostics, "^requirements\\.txt$", (uri, name, contents) => { | ||
sendDiagnostics('pypi', uri, contents, new collector_1.ReqDependencyCollector()); | ||
sendDiagnostics('pypi', uri, contents, new requirements_txt_1.DependencyCollector()); | ||
}); | ||
files.on(EventStream.Diagnostics, "^go\\.mod$", (uri, name, contents) => { | ||
connection.console.log("Using golang executable: " + config_1.config.golang_executable); | ||
sendDiagnostics('golang', uri, contents, new collector_1.GomodDependencyCollector(uri)); | ||
sendDiagnostics('golang', uri, contents, new go_mod_1.DependencyCollector(uri)); | ||
}); | ||
@@ -279,0 +281,0 @@ let checkDelay; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
105002
26
1060