@contrast/contrast 1.0.4 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.prettierignore +0 -3
- package/dist/audit/autodetection/autoDetectLanguage.js +32 -0
- package/dist/audit/catalogueApplication/catalogueApplication.js +2 -11
- package/dist/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +4 -2
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/dist/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- package/dist/audit/languageAnalysisEngine/languageAnalysisFactory.js +6 -2
- package/dist/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +39 -1
- package/dist/audit/languageAnalysisEngine/report/commonReportingFunctions.js +69 -30
- package/dist/audit/languageAnalysisEngine/report/models/reportOutputModel.js +24 -0
- package/dist/audit/languageAnalysisEngine/report/models/reportSeverityModel.js +3 -1
- package/dist/audit/languageAnalysisEngine/report/models/severityCountModel.js +13 -0
- package/dist/audit/languageAnalysisEngine/report/reportingFeature.js +2 -2
- package/dist/audit/languageAnalysisEngine/report/utils/reportUtils.js +56 -45
- package/dist/audit/languageAnalysisEngine/sendSnapshot.js +65 -17
- package/dist/commands/audit/auditConfig.js +8 -2
- package/dist/commands/audit/auditController.js +9 -3
- package/dist/commands/audit/processAudit.js +1 -1
- package/dist/commands/scan/processScan.js +7 -4
- package/dist/commands/scan/sca/scaAnalysis.js +60 -0
- package/dist/common/HTTPClient.js +50 -16
- package/dist/common/errorHandling.js +11 -16
- package/dist/common/versionChecker.js +1 -1
- package/dist/constants/constants.js +24 -2
- package/dist/constants/locales.js +31 -36
- package/dist/constants.js +20 -0
- package/dist/lambda/analytics.js +11 -0
- package/dist/lambda/lambda.js +35 -4
- package/dist/lambda/types.js +13 -0
- package/dist/scaAnalysis/common/formatMessage.js +35 -0
- package/dist/scaAnalysis/common/treeUpload.js +29 -0
- package/dist/scaAnalysis/go/goAnalysis.js +17 -0
- package/dist/scaAnalysis/go/goParseDeps.js +158 -0
- package/dist/scaAnalysis/go/goReadDepFile.js +23 -0
- package/dist/scaAnalysis/java/analysis.js +105 -0
- package/dist/scaAnalysis/java/index.js +18 -0
- package/dist/scaAnalysis/java/javaBuildDepsParser.js +339 -0
- package/dist/scaAnalysis/python/analysis.js +41 -0
- package/dist/scaAnalysis/python/index.js +10 -0
- package/dist/scaAnalysis/ruby/analysis.js +226 -0
- package/dist/scaAnalysis/ruby/index.js +10 -0
- package/dist/scan/autoDetection.js +50 -1
- package/dist/scan/fileUtils.js +80 -1
- package/dist/scan/formatScanOutput.js +213 -0
- package/dist/scan/help.js +3 -1
- package/dist/scan/models/groupedResultsModel.js +2 -1
- package/dist/scan/models/scanResultsModel.js +3 -1
- package/dist/scan/populateProjectIdAndProjectName.js +2 -1
- package/dist/scan/scan.js +6 -99
- package/dist/scan/scanConfig.js +6 -1
- package/dist/scan/scanController.js +26 -7
- package/dist/scan/scanResults.js +20 -20
- package/dist/utils/commonApi.js +4 -1
- package/dist/utils/oraWrapper.js +5 -1
- package/package.json +12 -7
- package/src/audit/autodetection/autoDetectLanguage.ts +40 -0
- package/src/audit/catalogueApplication/catalogueApplication.js +3 -16
- package/src/audit/javaAnalysisEngine/parseMavenProjectFileContents.js +11 -8
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedLanguages.js +2 -1
- package/src/audit/languageAnalysisEngine/checkForMultipleIdentifiedProjectFiles.js +2 -1
- package/src/audit/languageAnalysisEngine/checkIdentifiedLanguageHasProjectFile.js +2 -1
- package/src/audit/languageAnalysisEngine/languageAnalysisFactory.js +17 -5
- package/src/audit/languageAnalysisEngine/reduceIdentifiedLanguages.js +76 -3
- package/src/audit/languageAnalysisEngine/report/commonReportingFunctions.ts +122 -40
- package/src/audit/languageAnalysisEngine/report/models/reportLibraryModel.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/models/reportListModel.ts +15 -11
- package/src/audit/languageAnalysisEngine/report/models/reportOutputModel.ts +29 -0
- package/src/audit/languageAnalysisEngine/report/models/reportSeverityModel.ts +12 -3
- package/src/audit/languageAnalysisEngine/report/models/severityCountModel.ts +16 -0
- package/src/audit/languageAnalysisEngine/report/reportingFeature.ts +3 -3
- package/src/audit/languageAnalysisEngine/report/utils/reportUtils.ts +87 -65
- package/src/audit/languageAnalysisEngine/sendSnapshot.js +78 -25
- package/src/commands/audit/auditConfig.ts +12 -3
- package/src/commands/audit/auditController.ts +9 -3
- package/src/commands/audit/processAudit.ts +4 -1
- package/src/commands/scan/processScan.js +10 -4
- package/src/commands/scan/sca/scaAnalysis.js +83 -0
- package/src/common/HTTPClient.js +65 -25
- package/src/common/errorHandling.ts +14 -22
- package/src/common/versionChecker.ts +1 -1
- package/src/constants/constants.js +24 -2
- package/src/constants/locales.js +33 -50
- package/src/constants.js +22 -0
- package/src/lambda/analytics.ts +9 -0
- package/src/lambda/arn.ts +2 -1
- package/src/lambda/lambda.ts +37 -17
- package/src/lambda/types.ts +35 -0
- package/src/lambda/utils.ts +2 -7
- package/src/scaAnalysis/common/formatMessage.js +38 -0
- package/src/scaAnalysis/common/treeUpload.js +30 -0
- package/src/scaAnalysis/go/goAnalysis.js +19 -0
- package/src/scaAnalysis/go/goParseDeps.js +203 -0
- package/src/scaAnalysis/go/goReadDepFile.js +32 -0
- package/src/scaAnalysis/java/analysis.js +142 -0
- package/src/scaAnalysis/java/index.js +21 -0
- package/src/scaAnalysis/java/javaBuildDepsParser.js +404 -0
- package/src/scaAnalysis/python/analysis.js +48 -0
- package/src/scaAnalysis/python/index.js +11 -0
- package/src/scaAnalysis/ruby/analysis.js +282 -0
- package/src/scaAnalysis/ruby/index.js +11 -0
- package/src/scan/autoDetection.js +58 -1
- package/src/scan/fileUtils.js +99 -1
- package/src/scan/formatScanOutput.ts +249 -0
- package/src/scan/help.js +3 -1
- package/src/scan/models/groupedResultsModel.ts +7 -5
- package/src/scan/models/resultContentModel.ts +2 -2
- package/src/scan/models/scanResultsModel.ts +5 -2
- package/src/scan/populateProjectIdAndProjectName.js +3 -1
- package/src/scan/scan.ts +8 -136
- package/src/scan/scanConfig.js +5 -1
- package/src/scan/scanController.js +30 -10
- package/src/scan/scanResults.js +31 -18
- package/src/utils/commonApi.js +4 -1
- package/src/utils/oraWrapper.js +6 -1
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const i18n = require('i18n');
|
|
3
|
+
const StringBuilder = require('string-builder');
|
|
4
|
+
let sb = new StringBuilder();
|
|
5
|
+
const parseBuildDeps = (config, input) => {
|
|
6
|
+
const { mvnDependancyTreeOutput, projectType } = input;
|
|
7
|
+
try {
|
|
8
|
+
return parseGradle(mvnDependancyTreeOutput, config, projectType);
|
|
9
|
+
}
|
|
10
|
+
catch (err) {
|
|
11
|
+
throw new Error(i18n.__('javaParseProjectFile') + `${err.message}`);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const preParser = shavedOutput => {
|
|
15
|
+
let obj = [];
|
|
16
|
+
for (let dep in shavedOutput) {
|
|
17
|
+
obj.push(shavedOutput[dep]
|
|
18
|
+
.replace('+-', '+---')
|
|
19
|
+
.replace('[INFO]', '')
|
|
20
|
+
.replace('\\-', '\\---')
|
|
21
|
+
.replace(':jar:', ':')
|
|
22
|
+
.replace(':test', '')
|
|
23
|
+
.replace(':compile', '')
|
|
24
|
+
.replace(' +', '+')
|
|
25
|
+
.replace(' |', '|')
|
|
26
|
+
.replace(' \\', '\\')
|
|
27
|
+
.replace(':runtime', ''));
|
|
28
|
+
}
|
|
29
|
+
let depTree = [];
|
|
30
|
+
for (let x in obj) {
|
|
31
|
+
let nodeLevel = computeRelationToLastElement(obj[x]);
|
|
32
|
+
let notLastLevel = obj[x].startsWith('|') ||
|
|
33
|
+
obj[x].startsWith('+') ||
|
|
34
|
+
obj[x].startsWith('\\');
|
|
35
|
+
if (notLastLevel) {
|
|
36
|
+
if (nodeLevel === 0) {
|
|
37
|
+
depTree.push(obj[x]);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
let level = computeLevel(nodeLevel);
|
|
41
|
+
let validatedLevel = addIndentation(nodeLevel === 2 ? 5 : level, obj[x]);
|
|
42
|
+
depTree.push(validatedLevel);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
let level = computeLevel(nodeLevel);
|
|
47
|
+
let validatedLevel = addIndentation(nodeLevel === 3 ? 5 : level, obj[x]);
|
|
48
|
+
depTree.push(validatedLevel);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return depTree;
|
|
52
|
+
};
|
|
53
|
+
const shaveOutput = (gradleDependencyTreeOutput, projectType) => {
|
|
54
|
+
let shavedOutput = gradleDependencyTreeOutput.split('\n');
|
|
55
|
+
if (projectType === 'maven') {
|
|
56
|
+
shavedOutput = preParser(shavedOutput);
|
|
57
|
+
}
|
|
58
|
+
let obj = [];
|
|
59
|
+
for (let key in shavedOutput) {
|
|
60
|
+
if (shavedOutput[key].includes('project :')) {
|
|
61
|
+
}
|
|
62
|
+
else if (shavedOutput[key].includes('+---') ||
|
|
63
|
+
shavedOutput[key].includes('\\---')) {
|
|
64
|
+
obj.push(shavedOutput[key]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return obj;
|
|
68
|
+
};
|
|
69
|
+
const computeIndentation = element => {
|
|
70
|
+
let hasPlus = element.includes('+');
|
|
71
|
+
let hasSlash = element.includes('\\');
|
|
72
|
+
if (hasPlus) {
|
|
73
|
+
return element.substring(element.indexOf('+'));
|
|
74
|
+
}
|
|
75
|
+
if (hasSlash) {
|
|
76
|
+
return element.substring(element.indexOf('\\'));
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const computeLevel = nodeLevel => {
|
|
80
|
+
let num = [5, 8, 11, 14, 17, 20];
|
|
81
|
+
for (let z in num) {
|
|
82
|
+
if (num[z] === nodeLevel) {
|
|
83
|
+
let n = parseInt(z);
|
|
84
|
+
return 5 * (n + 2);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const addIndentation = (number, str) => {
|
|
89
|
+
str = computeIndentation(str);
|
|
90
|
+
sb.clear();
|
|
91
|
+
for (let j = 0; j < number; j++) {
|
|
92
|
+
sb.append(' ');
|
|
93
|
+
}
|
|
94
|
+
sb.append(str);
|
|
95
|
+
return sb.toString();
|
|
96
|
+
};
|
|
97
|
+
const computeRelationToLastElement = element => {
|
|
98
|
+
let hasPlus = element.includes('+---');
|
|
99
|
+
let hasSlash = element.includes('\\---');
|
|
100
|
+
if (hasPlus) {
|
|
101
|
+
return element.split('+---')[0].length;
|
|
102
|
+
}
|
|
103
|
+
if (hasSlash) {
|
|
104
|
+
return element.split('\\---')[0].length;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const stripElement = element => {
|
|
108
|
+
return element
|
|
109
|
+
.replace(/[|]/g, '')
|
|
110
|
+
.replace('+---', '')
|
|
111
|
+
.replace('\\---', '')
|
|
112
|
+
.replace(/[' ']/g, '')
|
|
113
|
+
.replace('(c)', '')
|
|
114
|
+
.replace('->', '@')
|
|
115
|
+
.replace('(*)', '');
|
|
116
|
+
};
|
|
117
|
+
const checkVersion = element => {
|
|
118
|
+
let version = element.split(':');
|
|
119
|
+
return version[version.length - 1];
|
|
120
|
+
};
|
|
121
|
+
const createElement = (element, isRoot) => {
|
|
122
|
+
let tree;
|
|
123
|
+
let cleanElement = stripElement(element);
|
|
124
|
+
let splitGroupName = cleanElement.split(':');
|
|
125
|
+
let validateVersion = false;
|
|
126
|
+
if (!element.includes('->')) {
|
|
127
|
+
validateVersion = true;
|
|
128
|
+
}
|
|
129
|
+
tree = {
|
|
130
|
+
artifactID: splitGroupName[1],
|
|
131
|
+
group: splitGroupName[0],
|
|
132
|
+
version: validateVersion
|
|
133
|
+
? checkVersion(cleanElement)
|
|
134
|
+
: splitGroupName[splitGroupName.length - 1],
|
|
135
|
+
scope: 'compile',
|
|
136
|
+
type: isRoot ? 'direct' : 'transitive',
|
|
137
|
+
edges: {}
|
|
138
|
+
};
|
|
139
|
+
return tree;
|
|
140
|
+
};
|
|
141
|
+
const getElementHeader = element => {
|
|
142
|
+
let elementHeader = stripElement(element);
|
|
143
|
+
elementHeader = elementHeader.replace(':', '/');
|
|
144
|
+
elementHeader = elementHeader.replace(':', '@');
|
|
145
|
+
return elementHeader;
|
|
146
|
+
};
|
|
147
|
+
const buildElement = (element, rootElement, parentOfCurrent, tree, isRoot) => {
|
|
148
|
+
let childElement = createElement(element, isRoot);
|
|
149
|
+
let elementHeader = getElementHeader(element);
|
|
150
|
+
let levelsArray = [rootElement, parentOfCurrent];
|
|
151
|
+
const treeNode = getNestedObject(tree, levelsArray);
|
|
152
|
+
const rootNode = getNestedObject(tree, [rootElement]);
|
|
153
|
+
if (!rootNode.hasOwnProperty(elementHeader)) {
|
|
154
|
+
tree[rootElement][elementHeader] = childElement;
|
|
155
|
+
}
|
|
156
|
+
treeNode.edges[elementHeader] = elementHeader;
|
|
157
|
+
};
|
|
158
|
+
const hasChildren = (nextNodeLevel, nodeLevel) => {
|
|
159
|
+
if (nextNodeLevel > nodeLevel) {
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const lastChild = (nextNodeLevel, nodeLevel) => {
|
|
164
|
+
if (nextNodeLevel < nodeLevel) {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
const calculateLevels = (nextNodeLevel, nodeLevel) => {
|
|
169
|
+
return (nodeLevel - nextNodeLevel) / 5;
|
|
170
|
+
};
|
|
171
|
+
const buildTree = shavedOutput => {
|
|
172
|
+
let tree = {};
|
|
173
|
+
let rootElement;
|
|
174
|
+
let levelNodes = [];
|
|
175
|
+
shavedOutput.forEach((element, index) => {
|
|
176
|
+
if (index === 0) {
|
|
177
|
+
let cleanElement = stripElement(element);
|
|
178
|
+
let elementHeader = getElementHeader(cleanElement);
|
|
179
|
+
let splitElement = element.split(' ');
|
|
180
|
+
let splitGroupName = splitElement[1].split(':');
|
|
181
|
+
let validateVersion = false;
|
|
182
|
+
if (!element.includes('->')) {
|
|
183
|
+
validateVersion = true;
|
|
184
|
+
}
|
|
185
|
+
tree[splitGroupName[0]] = {};
|
|
186
|
+
tree[splitGroupName[0]][elementHeader] = {
|
|
187
|
+
artifactID: splitGroupName[1],
|
|
188
|
+
group: splitGroupName[0],
|
|
189
|
+
version: validateVersion
|
|
190
|
+
? checkVersion(cleanElement)
|
|
191
|
+
: splitElement[splitElement.length - 1],
|
|
192
|
+
scope: 'compile',
|
|
193
|
+
type: 'direct',
|
|
194
|
+
edges: {}
|
|
195
|
+
};
|
|
196
|
+
rootElement = splitGroupName[0];
|
|
197
|
+
levelNodes.push(elementHeader);
|
|
198
|
+
}
|
|
199
|
+
if (shavedOutput.length - 1 === index) {
|
|
200
|
+
const parentOfCurrent = levelNodes[levelNodes.length - 1];
|
|
201
|
+
let nodeLevel = computeRelationToLastElement(element);
|
|
202
|
+
let validateVersion = false;
|
|
203
|
+
if (!element.includes('->')) {
|
|
204
|
+
validateVersion = true;
|
|
205
|
+
}
|
|
206
|
+
if (nodeLevel === 0) {
|
|
207
|
+
let cleanElement = stripElement(element);
|
|
208
|
+
let elementHeader = getElementHeader(cleanElement);
|
|
209
|
+
let splitElement = element.split(' ');
|
|
210
|
+
let splitGroupName = splitElement[1].split(':');
|
|
211
|
+
tree[rootElement][elementHeader] = {
|
|
212
|
+
artifactID: splitGroupName[1],
|
|
213
|
+
group: splitGroupName[0],
|
|
214
|
+
version: validateVersion
|
|
215
|
+
? checkVersion(cleanElement)
|
|
216
|
+
: splitElement[splitElement.length - 1],
|
|
217
|
+
scope: 'compile',
|
|
218
|
+
type: 'direct',
|
|
219
|
+
edges: {}
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
buildElement(element, rootElement, parentOfCurrent, tree);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (index >= 1 && index < shavedOutput.length - 1) {
|
|
227
|
+
let nodeLevel = computeRelationToLastElement(element);
|
|
228
|
+
let nextNodeLevel = computeRelationToLastElement(shavedOutput[index + 1]);
|
|
229
|
+
const parentOfCurrent = levelNodes[levelNodes.length - 1];
|
|
230
|
+
let isRoot = false;
|
|
231
|
+
if (nodeLevel === 0) {
|
|
232
|
+
isRoot = true;
|
|
233
|
+
}
|
|
234
|
+
if (isRoot) {
|
|
235
|
+
let cleanElement = stripElement(element);
|
|
236
|
+
let elementHeader = getElementHeader(cleanElement);
|
|
237
|
+
let splitElement = element.split(' ');
|
|
238
|
+
let splitGroupName = splitElement[1].split(':');
|
|
239
|
+
let validateVersion = false;
|
|
240
|
+
if (!element.includes('->')) {
|
|
241
|
+
validateVersion = true;
|
|
242
|
+
}
|
|
243
|
+
tree[rootElement][elementHeader] = {
|
|
244
|
+
artifactID: splitGroupName[1],
|
|
245
|
+
group: splitGroupName[0],
|
|
246
|
+
version: validateVersion
|
|
247
|
+
? checkVersion(cleanElement)
|
|
248
|
+
: splitElement[splitElement.length - 1],
|
|
249
|
+
scope: 'compile',
|
|
250
|
+
type: 'direct',
|
|
251
|
+
edges: {}
|
|
252
|
+
};
|
|
253
|
+
levelNodes.push(elementHeader);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
let elementHeader = getElementHeader(element);
|
|
257
|
+
buildElement(element, rootElement, parentOfCurrent, tree, isRoot);
|
|
258
|
+
if (hasChildren(nextNodeLevel, nodeLevel)) {
|
|
259
|
+
buildElement(element, rootElement, parentOfCurrent, tree, isRoot);
|
|
260
|
+
levelNodes.push(elementHeader);
|
|
261
|
+
}
|
|
262
|
+
if (lastChild(nextNodeLevel, nodeLevel)) {
|
|
263
|
+
let levelDifference = calculateLevels(nextNodeLevel, nodeLevel);
|
|
264
|
+
if (levelDifference === 0) {
|
|
265
|
+
levelNodes.pop();
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
let i;
|
|
269
|
+
for (i = 0; i < levelDifference; i++) {
|
|
270
|
+
levelNodes.pop();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
});
|
|
276
|
+
return tree;
|
|
277
|
+
};
|
|
278
|
+
const getNestedObject = (nestedObj, pathArr) => {
|
|
279
|
+
return pathArr.reduce((obj, key) => (obj && obj[key] !== 'undefined' ? obj[key] : undefined), nestedObj);
|
|
280
|
+
};
|
|
281
|
+
const parseSubProject = shavedOutput => {
|
|
282
|
+
let obj = [];
|
|
283
|
+
for (let key in shavedOutput) {
|
|
284
|
+
if (!shavedOutput[key].includes('project')) {
|
|
285
|
+
obj.push(shavedOutput[key]);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return obj;
|
|
289
|
+
};
|
|
290
|
+
const validateIndentation = shavedOutput => {
|
|
291
|
+
let validatedTree = [];
|
|
292
|
+
shavedOutput.forEach((element, index) => {
|
|
293
|
+
let nextNodeLevel;
|
|
294
|
+
let nodeLevel = computeRelationToLastElement(element);
|
|
295
|
+
if (shavedOutput[index + 1] !== undefined) {
|
|
296
|
+
nextNodeLevel = computeRelationToLastElement(shavedOutput[index + 1]);
|
|
297
|
+
}
|
|
298
|
+
if (index === 0) {
|
|
299
|
+
validatedTree.push(shavedOutput[index]);
|
|
300
|
+
validatedTree.push(shavedOutput[index + 1]);
|
|
301
|
+
}
|
|
302
|
+
else if (nextNodeLevel > nodeLevel + 5) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
else {
|
|
306
|
+
validatedTree.push(shavedOutput[index + 1]);
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
validatedTree.pop();
|
|
310
|
+
return validatedTree;
|
|
311
|
+
};
|
|
312
|
+
const parseGradle = (gradleDependencyTreeOutput, config, projectType) => {
|
|
313
|
+
let shavedOutput = shaveOutput(gradleDependencyTreeOutput, projectType);
|
|
314
|
+
if (config.subProject) {
|
|
315
|
+
let subProject = parseSubProject(shavedOutput);
|
|
316
|
+
let validatedOutput = validateIndentation(subProject);
|
|
317
|
+
return buildTree(validatedOutput);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
let validatedOutput = validateIndentation(shavedOutput);
|
|
321
|
+
return buildTree(validatedOutput);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
module.exports = {
|
|
325
|
+
parseBuildDeps,
|
|
326
|
+
shaveOutput,
|
|
327
|
+
validateIndentation,
|
|
328
|
+
calculateLevels,
|
|
329
|
+
lastChild,
|
|
330
|
+
hasChildren,
|
|
331
|
+
getElementHeader,
|
|
332
|
+
createElement,
|
|
333
|
+
stripElement,
|
|
334
|
+
checkVersion,
|
|
335
|
+
computeRelationToLastElement,
|
|
336
|
+
addIndentation,
|
|
337
|
+
computeLevel,
|
|
338
|
+
computeIndentation
|
|
339
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const multiReplace = require('string-multiple-replace');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const readAndParseProjectFile = projectPath => {
|
|
5
|
+
const filePath = filePathForWindows(projectPath + '/Pipfile');
|
|
6
|
+
const pipFile = fs.readFileSync(filePath, 'utf8');
|
|
7
|
+
const matcherObj = { '"': '' };
|
|
8
|
+
const sequencer = ['"'];
|
|
9
|
+
const parsedPipfile = multiReplace(pipFile, matcherObj, sequencer);
|
|
10
|
+
const pythonArray = parsedPipfile.split('\n');
|
|
11
|
+
return pythonArray.filter(element => element !== '' && !element.includes('#'));
|
|
12
|
+
};
|
|
13
|
+
const readAndParseLockFile = projectPath => {
|
|
14
|
+
const filePath = filePathForWindows(projectPath + '/Pipfile.lock');
|
|
15
|
+
const lockFile = fs.readFileSync(filePath, 'utf8');
|
|
16
|
+
let parsedPipLock = JSON.parse(lockFile);
|
|
17
|
+
parsedPipLock['defaults'] = parsedPipLock['default'];
|
|
18
|
+
return parsedPipLock;
|
|
19
|
+
};
|
|
20
|
+
const getPythonDeps = config => {
|
|
21
|
+
try {
|
|
22
|
+
const parseProject = readAndParseProjectFile(config.projectPath);
|
|
23
|
+
const parsePip = readAndParseLockFile(config.projectPath);
|
|
24
|
+
return { pipfileLock: parseProject, pipfilDependanceies: parsePip };
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
console.log(err.message.toString());
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const filePathForWindows = path => {
|
|
32
|
+
if (process.platform === 'win32') {
|
|
33
|
+
path = path.replace(/\//g, '\\');
|
|
34
|
+
}
|
|
35
|
+
return path;
|
|
36
|
+
};
|
|
37
|
+
module.exports = {
|
|
38
|
+
getPythonDeps,
|
|
39
|
+
readAndParseProjectFile,
|
|
40
|
+
readAndParseLockFile
|
|
41
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { createPythonTSMessage } = require('../common/formatMessage');
|
|
3
|
+
const { getPythonDeps } = require('./analysis');
|
|
4
|
+
const pythonAnalysis = (config, languageFiles) => {
|
|
5
|
+
const pythonDeps = getPythonDeps(config, languageFiles.PYTHON);
|
|
6
|
+
return createPythonTSMessage(pythonDeps);
|
|
7
|
+
};
|
|
8
|
+
module.exports = {
|
|
9
|
+
pythonAnalysis
|
|
10
|
+
};
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const readAndParseGemfile = projectPath => {
|
|
4
|
+
const fileName = filePathForWindows(projectPath + '/Gemfile');
|
|
5
|
+
const gemFile = fs.readFileSync(fileName, 'utf8');
|
|
6
|
+
const rubyArray = gemFile.split('\n');
|
|
7
|
+
let filteredRubyDep = rubyArray.filter(element => {
|
|
8
|
+
return (!element.includes('#') &&
|
|
9
|
+
element.includes('gem') &&
|
|
10
|
+
!element.includes('source'));
|
|
11
|
+
});
|
|
12
|
+
for (let i = 0; i < filteredRubyDep.length; i++) {
|
|
13
|
+
filteredRubyDep[i] = filteredRubyDep[i].trim();
|
|
14
|
+
}
|
|
15
|
+
return filteredRubyDep;
|
|
16
|
+
};
|
|
17
|
+
const readAndParseGemLockFile = projectPath => {
|
|
18
|
+
const fileName = filePathForWindows(projectPath + '/Gemfile.lock');
|
|
19
|
+
const lockFile = fs.readFileSync(fileName, 'utf8');
|
|
20
|
+
const dependencyRegEx = /^\s*([A-Za-z0-9.!@#$%\-^&*_+]*)\s*(\((.*?)\))/;
|
|
21
|
+
const lines = lockFile.split('\n');
|
|
22
|
+
return {
|
|
23
|
+
dependencies: getDirectDependencies(lines, dependencyRegEx),
|
|
24
|
+
runtimeDetails: getLockFileRuntimeInfo(lines),
|
|
25
|
+
sources: getSourceArray(lines, dependencyRegEx)
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
const nonDependencyKeys = (line, sourceObject) => {
|
|
29
|
+
const GEMFILE_KEY_VALUE = /^\s*([^:(]*)\s*\s*(.*)/;
|
|
30
|
+
let parts = GEMFILE_KEY_VALUE.exec(line);
|
|
31
|
+
let key = parts[1].trim();
|
|
32
|
+
let value = parts[2] || '';
|
|
33
|
+
sourceObject[key] = value;
|
|
34
|
+
return sourceObject;
|
|
35
|
+
};
|
|
36
|
+
const populateResolveAndPlatform = (version, sourceObject) => {
|
|
37
|
+
const depArr = version.split('-');
|
|
38
|
+
sourceObject.resolved = depArr[0];
|
|
39
|
+
sourceObject.platform = depArr.length > 1 ? depArr[1] : 'UNSPECIFIED';
|
|
40
|
+
return sourceObject;
|
|
41
|
+
};
|
|
42
|
+
const isUpperCase = str => {
|
|
43
|
+
return str === str.toUpperCase();
|
|
44
|
+
};
|
|
45
|
+
const getDirectDependencies = (lines, dependencyRegEx) => {
|
|
46
|
+
const dependencies = {};
|
|
47
|
+
let depIndex = 0;
|
|
48
|
+
for (let i = 0; i < lines.length; i++) {
|
|
49
|
+
if (lines[i] === 'DEPENDENCIES') {
|
|
50
|
+
depIndex = i;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const getDepArray = lines.slice(depIndex);
|
|
54
|
+
for (let j = 1; j < getDepArray.length; j++) {
|
|
55
|
+
const element = getDepArray[j];
|
|
56
|
+
if (!isUpperCase(element)) {
|
|
57
|
+
const isDependencyWithVersion = dependencyRegEx.test(element);
|
|
58
|
+
if (isDependencyWithVersion) {
|
|
59
|
+
const dependency = dependencyRegEx.exec(element);
|
|
60
|
+
let name = dependency[1];
|
|
61
|
+
name = name.replace('!', '');
|
|
62
|
+
dependencies[name.trim()] = dependency[3];
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
let name = element;
|
|
66
|
+
name = name.replace('!', ' ');
|
|
67
|
+
dependencies[name.trim()] = 'UNSPECIFIED';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return dependencies;
|
|
72
|
+
};
|
|
73
|
+
const getLockFileRuntimeInfo = lines => {
|
|
74
|
+
let rubVersionIndex = 0;
|
|
75
|
+
for (let i = 0; i < lines.length; i++) {
|
|
76
|
+
if (lines[i] === 'RUBY VERSION') {
|
|
77
|
+
rubVersionIndex = i;
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const runtimeDetails = {};
|
|
82
|
+
if (rubVersionIndex !== 0) {
|
|
83
|
+
const getRubyVersionArray = lines.slice(rubVersionIndex);
|
|
84
|
+
for (let element of getRubyVersionArray) {
|
|
85
|
+
if (!isUpperCase(element)) {
|
|
86
|
+
runtimeDetails['version'] = getVersion(element);
|
|
87
|
+
runtimeDetails['patchLevel'] = getPatchLevel(element);
|
|
88
|
+
if (element.includes('engine')) {
|
|
89
|
+
let splitElement = element.split(' ');
|
|
90
|
+
runtimeDetails[splitElement[0]] = splitElement[1];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return runtimeDetails;
|
|
96
|
+
};
|
|
97
|
+
const getVersion = element => {
|
|
98
|
+
const versionRegex = /^([ruby\s0-9.*]+)/;
|
|
99
|
+
if (versionRegex.test(element)) {
|
|
100
|
+
let version = versionRegex.exec(element)[0];
|
|
101
|
+
if (version.includes('ruby')) {
|
|
102
|
+
return trimWhiteSpace(version.replace('ruby', ''));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const getPatchLevel = element => {
|
|
107
|
+
const patchLevelRegex = /(p\d+)/;
|
|
108
|
+
if (patchLevelRegex.test(element)) {
|
|
109
|
+
return patchLevelRegex.exec(element)[0];
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const formatSourceArr = sourceArr => {
|
|
113
|
+
return sourceArr.map(element => {
|
|
114
|
+
if (element.sourceType === 'GIT') {
|
|
115
|
+
delete element.specs;
|
|
116
|
+
}
|
|
117
|
+
if (element.sourceType === 'GEM') {
|
|
118
|
+
delete element.branch;
|
|
119
|
+
delete element.revision;
|
|
120
|
+
delete element.depthLevel;
|
|
121
|
+
delete element.specs;
|
|
122
|
+
}
|
|
123
|
+
if (element.sourceType === 'PATH') {
|
|
124
|
+
delete element.branch;
|
|
125
|
+
delete element.revision;
|
|
126
|
+
delete element.depthLevel;
|
|
127
|
+
delete element.specs;
|
|
128
|
+
delete element.platform;
|
|
129
|
+
}
|
|
130
|
+
return element;
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
const getSourceArray = (lines, dependencyRegEx) => {
|
|
134
|
+
const sourceObject = {
|
|
135
|
+
dependencies: {}
|
|
136
|
+
};
|
|
137
|
+
const whitespaceRegx = /^(\s*)/;
|
|
138
|
+
let index = 0;
|
|
139
|
+
let line = 0;
|
|
140
|
+
const sources = [];
|
|
141
|
+
while ((line = lines[index++]) !== undefined) {
|
|
142
|
+
let currentWS = whitespaceRegx.exec(line)[1].length;
|
|
143
|
+
if (!line.includes(' bundler (')) {
|
|
144
|
+
if (currentWS === 0 && !line.includes(':') && line !== '') {
|
|
145
|
+
sourceObject.sourceType = line;
|
|
146
|
+
}
|
|
147
|
+
if (currentWS !== 0 && line.includes(':')) {
|
|
148
|
+
nonDependencyKeys(line, sourceObject);
|
|
149
|
+
}
|
|
150
|
+
if (currentWS > 2) {
|
|
151
|
+
let nexlineWS = whitespaceRegx.exec(lines[index])[1].length;
|
|
152
|
+
sourceObject.dependencies = buildSourceDependencyWithVersion(whitespaceRegx, dependencyRegEx, line, currentWS, sourceObject.name, sourceObject.dependencies);
|
|
153
|
+
if (currentWS === 4 && sourceObject.depthLevel === undefined) {
|
|
154
|
+
const dependency = dependencyRegEx.exec(line);
|
|
155
|
+
sourceObject.name = dependency[1];
|
|
156
|
+
sourceObject.depthLevel = currentWS;
|
|
157
|
+
populateResolveAndPlatform(dependency[3], sourceObject);
|
|
158
|
+
}
|
|
159
|
+
if (currentWS === 4 && sourceObject.depthLevel) {
|
|
160
|
+
const dependency = dependencyRegEx.exec(line);
|
|
161
|
+
sourceObject.name = dependency[1];
|
|
162
|
+
sourceObject.depthLevel = currentWS;
|
|
163
|
+
populateResolveAndPlatform(dependency[3], sourceObject);
|
|
164
|
+
}
|
|
165
|
+
if ((currentWS === 4 && nexlineWS === 4) ||
|
|
166
|
+
(currentWS === 6 && nexlineWS === 4) ||
|
|
167
|
+
nexlineWS === '') {
|
|
168
|
+
let newObj = {};
|
|
169
|
+
newObj = JSON.parse(JSON.stringify(sourceObject));
|
|
170
|
+
sources.push(newObj);
|
|
171
|
+
sourceObject.dependencies = {};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return formatSourceArr(sources);
|
|
177
|
+
};
|
|
178
|
+
const buildSourceDependencyWithVersion = (whitespaceRegx, dependencyRegEx, line, currentWhiteSpace, name, dependencies) => {
|
|
179
|
+
const isDependencyWithVersion = dependencyRegEx.test(line);
|
|
180
|
+
if (currentWhiteSpace === 6) {
|
|
181
|
+
const dependency = dependencyRegEx.exec(line);
|
|
182
|
+
if (isDependencyWithVersion) {
|
|
183
|
+
if (name !== dependency[1]) {
|
|
184
|
+
dependencies[dependency[1]] = dependency[3];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
dependencies[line.trim()] = 'UNSPECIFIED';
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return dependencies;
|
|
192
|
+
};
|
|
193
|
+
const getRubyDeps = config => {
|
|
194
|
+
try {
|
|
195
|
+
const parsedGem = readAndParseGemfile(config.projectPath);
|
|
196
|
+
const parsedLock = readAndParseGemLockFile(config.projectPath);
|
|
197
|
+
return { gemfilesDependanceies: parsedGem, gemfileLock: parsedLock };
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
console.log(err.message);
|
|
201
|
+
process.exit(1);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
const trimWhiteSpace = string => {
|
|
205
|
+
return string.replace(/\s+/g, '');
|
|
206
|
+
};
|
|
207
|
+
const filePathForWindows = path => {
|
|
208
|
+
if (process.platform === 'win32') {
|
|
209
|
+
path = path.replace(/\//g, '\\');
|
|
210
|
+
}
|
|
211
|
+
return path;
|
|
212
|
+
};
|
|
213
|
+
module.exports = {
|
|
214
|
+
getRubyDeps,
|
|
215
|
+
readAndParseGemfile,
|
|
216
|
+
readAndParseGemLockFile,
|
|
217
|
+
nonDependencyKeys,
|
|
218
|
+
populateResolveAndPlatform,
|
|
219
|
+
isUpperCase,
|
|
220
|
+
getDirectDependencies,
|
|
221
|
+
getLockFileRuntimeInfo,
|
|
222
|
+
getVersion,
|
|
223
|
+
getPatchLevel,
|
|
224
|
+
formatSourceArr,
|
|
225
|
+
getSourceArray
|
|
226
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const { getRubyDeps } = require('./analysis');
|
|
3
|
+
const { createRubyTSMessage } = require('../common/formatMessage');
|
|
4
|
+
const rubyAnalysis = (config, languageFiles) => {
|
|
5
|
+
const rubyDeps = getRubyDeps(config, languageFiles.RUBY);
|
|
6
|
+
return createRubyTSMessage(rubyDeps);
|
|
7
|
+
};
|
|
8
|
+
module.exports = {
|
|
9
|
+
rubyAnalysis
|
|
10
|
+
};
|