Skip to content

Commit b8cc7fd

Browse files
committed
feat: read target framework from project.assets.json
1 parent e7a3a28 commit b8cc7fd

22 files changed

+1776
-198
lines changed

lib/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
'use strict';
12
const path = require('path');
2-
const nugetParser = require('./nuget-parser/index');
3+
const nugetParser = require('./nuget-parser');
34
const paketParser = require('snyk-paket-parser');
45

56
function determineManifestType(filename) {

lib/nuget-parser/csproj-parser.js

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
'use strict';
12
const fs = require('fs');
23
const path = require('path');
34
const parseXML = require('xml2js').parseString;
45
const debug = require('debug')('snyk');
56
const _ = require('lodash');
67

7-
function determineDotnetVersions(rootDir) {
8+
function getTargetFrameworksFromProjFile(rootDir) {
89
debug('Looking for your .csproj file in ' + rootDir);
910
const csprojPath = findFile(rootDir, /.*\.csproj$/);
1011
if (!csprojPath) {
@@ -15,7 +16,7 @@ function determineDotnetVersions(rootDir) {
1516

1617
const csprojContents = fs.readFileSync(csprojPath);
1718

18-
var frameworks = [];
19+
let frameworks = [];
1920
parseXML(csprojContents, function (err, parsedCsprojContents) {
2021
if (err) {
2122
throw err;
@@ -27,16 +28,16 @@ function determineDotnetVersions(rootDir) {
2728
_.get(versionLoc, 'TargetFrameworks[0]', '').split(';')));
2829

2930
if (versions.length < 1) {
30-
throw new Error('Could not find TargetFrameworkVersion/TargetFramework' +
31+
debug('Could not find TargetFrameworkVersion/TargetFramework' +
3132
'/TargetFrameworks defined in the Project.PropertyGroup field of ' +
3233
'your .csproj file');
3334
}
3435
frameworks = _.compact(_.map(versions, toReadableFramework));
36+
if (versions.length > 1 && frameworks.length < 1) {
37+
throw new Error('Could not find valid/supported .NET version in csproj file located at' + csprojPath);
38+
}
3539
});
36-
if (frameworks.length < 1) {
37-
throw new Error('Could not find valid/supported .NET version');
38-
}
39-
return frameworks;
40+
return frameworks[0];
4041
}
4142

4243
function toReadableFramework(targetFramework) {
@@ -47,7 +48,7 @@ function toReadableFramework(targetFramework) {
4748
netcoreapp: '.NETCore',
4849
};
4950

50-
for (var type in typeMapping) {
51+
for (const type in typeMapping) {
5152
if (new RegExp(type + /\d.?\d(.?\d)?$/.source).test(targetFramework)) {
5253
return {
5354
framework: typeMapping[type],
@@ -63,13 +64,13 @@ function findFile(rootDir, filter) {
6364
throw new Error('No such path: ' + rootDir);
6465
}
6566
const files = fs.readdirSync(rootDir);
66-
for (var i = 0; i < files.length; i++) {
67-
var filename = path.resolve(rootDir, files[i]);
67+
for (let i = 0; i < files.length; i++) {
68+
const filename = path.resolve(rootDir, files[i]);
6869

6970
if (filter.test(filename)) {
7071
return filename;
7172
}
7273
}
7374
}
7475

75-
module.exports = determineDotnetVersions;
76+
module.exports = getTargetFrameworksFromProjFile;

lib/nuget-parser/dependency.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'use strict';
12
var debug = require('debug')('snyk');
23

34
function Dependency(name, version) {

lib/nuget-parser/dotnet-core-parser.js

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -84,36 +84,19 @@ function buildTreeRecursive(targetDeps, depName, parent, treeDepth) {
8484
});
8585
}
8686

87-
88-
function getFrameworkObjToRun(manifest) {
87+
function getFrameworkToRun(manifest) {
8988
const frameworks = _.get(manifest, 'project.frameworks');
90-
if (!frameworks) {
91-
throw new Error('No frameworks were found in project.assets.json');
92-
}
93-
94-
if (_.isEmpty(frameworks)) {
95-
throw new Error('0 frameworks were found in project.assets.json');
96-
}
9789

9890
debug(`Available frameworks: '${Object.keys(frameworks)}'`);
9991

10092
// not yet supporting multiple frameworks in the same assets file ->
10193
// taking only the first 1
10294
const selectedFrameworkKey = Object.keys(frameworks)[0];
10395
debug(`Selected framework: '${selectedFrameworkKey}'`);
104-
return frameworks[selectedFrameworkKey];
96+
return selectedFrameworkKey;
10597
}
10698

107-
10899
function getTargetObjToRun(manifest) {
109-
if (!manifest.targets) {
110-
throw new Error('No targets were found in project.assets.json');
111-
}
112-
113-
if (_.isEmpty(manifest.targets)) {
114-
throw new Error('0 targets were found in project.assets.json');
115-
}
116-
117100
debug(`Available targets: '${Object.keys(manifest.targets)}'`);
118101

119102
let selectedTargetKey = Object.keys(manifest.targets)[0];
@@ -123,21 +106,51 @@ function getTargetObjToRun(manifest) {
123106
return manifest.targets[selectedTargetKey];
124107
}
125108

109+
function validateManifest(manifest) {
110+
if (!manifest.project) {
111+
throw new Error('Project field was not found in project.assets.json');
112+
}
113+
114+
if (!manifest.project.frameworks) {
115+
throw new Error('No frameworks were found in project.assets.json');
116+
}
117+
118+
if (_.isEmpty(manifest.project.frameworks)) {
119+
throw new Error('0 frameworks were found in project.assets.json');
120+
}
121+
122+
if (!manifest.targets) {
123+
throw new Error('No targets were found in project.assets.json');
124+
}
125+
126+
if (_.isEmpty(manifest.targets)) {
127+
throw new Error('0 targets were found in project.assets.json');
128+
}
129+
}
130+
126131
module.exports = {
127-
parse: function (tree, fileContent, fileContentParser) {
128-
return new Promise(function parseFileContents(resolve) {
132+
parse: function (tree, manifest) {
133+
return new Promise(function parseFileContents(resolve, reject) {
129134
debug('Trying to parse dot-net-cli manifest');
130-
const manifest = fileContentParser.parse(fileContent);
131135

132-
if (!manifest.project) {
133-
throw new Error('Project field was not found in project.assets.json');
136+
try {
137+
validateManifest(manifest);
138+
} catch (err) {
139+
debug('Invalid project.assets.json manifest file');
140+
reject(err);
134141
}
135142

136143
if (manifest.project.version) {
137144
tree.version = manifest.project.version;
138145
}
139146

140-
const selectedFrameworkObj = getFrameworkObjToRun(manifest);
147+
// If a targetFramework was not found in the proj file, we will extract it from the lock file
148+
if (!tree.meta.targetFramework) {
149+
tree.meta.targetFramework = getFrameworkToRun(manifest);
150+
}
151+
const selectedFrameworkObj = manifest.project.frameworks[tree.meta.targetFramework];
152+
153+
// We currently ignore the found targetFramework when looking for target dependencies
141154
const selectedTargetObj = getTargetObjToRun(manifest);
142155

143156
initFreqDepsDict();
@@ -157,8 +170,6 @@ module.exports = {
157170
// JSON parse/stringify is used
158171
tree.dependencies = JSON.parse(JSON.stringify(tree.dependencies));
159172
resolve(tree);
160-
}).catch(function (err) {
161-
throw (err);
162173
});
163174
},
164175
};

lib/nuget-parser/dotnet-framework-parser.js

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const debug = require('debug')('snyk');
44
const path = require('path');
55
const Dependency = require('./dependency');
66
const parseNuspec = require('./nuspec-parser');
7+
const _ = require('lodash');
78

89
function injectPath(dep, packagesFolder) {
910
dep.path = dep.localPath ?
@@ -25,24 +26,30 @@ function scanInstalled(installedPackages, packagesFolder) {
2526
});
2627
try {
2728
debug('Scanning local installed folders');
28-
debug('Trying to read from installed packages folder: ' +
29-
packagesFolder);
29+
debug('Trying to read from installed packages folder: ' + packagesFolder);
3030
fs.readdirSync(packagesFolder)
3131
.map(function (folderName) {
32-
return Dependency.from.folderName(folderName);
32+
try {
33+
return Dependency.from.folderName(folderName);
34+
} catch (err) {
35+
debug('Unable to parse dependency from folder');
36+
debug(err);
37+
}
3338
})
3439
.forEach(function (dep) {
35-
injectPath(dep, packagesFolder);
36-
// only add a package from packages folder if version is different
37-
if (flattenedPackageList[dep.name] &&
38-
flattenedPackageList[dep.name].version !== dep.version) {
39-
// prefer found from packages folder (dep) over existing
40-
debug('For package ' + dep.name + ' the version ' +
41-
flattenedPackageList[dep.name].version +
42-
' was extracted from manifest file.' +
43-
'\nWe are overwriting it with version ' + dep.version +
44-
' from the packages folder');
45-
flattenedPackageList[dep.name] = dep;
40+
if (dep) {
41+
injectPath(dep, packagesFolder);
42+
// only add a package from packages folder if version is different
43+
if (flattenedPackageList[dep.name] &&
44+
flattenedPackageList[dep.name].version !== dep.version) {
45+
// prefer found from packages folder (dep) over existing
46+
debug('For package ' + dep.name + ' the version ' +
47+
flattenedPackageList[dep.name].version +
48+
' was extracted from manifest file.' +
49+
'\nWe are overwriting it with version ' + dep.version +
50+
' from the packages folder');
51+
flattenedPackageList[dep.name] = dep;
52+
}
4653
}
4754
});
4855
} catch (err) {
@@ -52,14 +59,14 @@ function scanInstalled(installedPackages, packagesFolder) {
5259
return flattenedPackageList;
5360
}
5461

55-
function fetchNugetInformationFromPackages(flattenedPackageList, dotnetVersions) {
62+
function fetchNugetInformationFromPackages(flattenedPackageList, targetFramework) {
5663
const nuspecParserChain = [];
5764
// begin collecting information from .nuget files on installed packages
5865
debug('Trying to analyze .nuspec files');
5966
for (const name in flattenedPackageList) {
6067
const dep = flattenedPackageList[name];
6168
debug('...' + name);
62-
nuspecParserChain.push(parseNuspec(dep, dotnetVersions));
69+
nuspecParserChain.push(parseNuspec(dep, targetFramework));
6370
}
6471
return Promise.all(nuspecParserChain);
6572
}
@@ -77,12 +84,13 @@ function processNugetInformation(nuspecResolutionChain) {
7784
}
7885

7986
module.exports = {
80-
parse: function (tree, fileContent, fileContentParser, dotnetVersions, packagesFolder) {
81-
tree.meta.targetFramework = dotnetVersions[0].original;
87+
parse: function (tree, manifest, targetFramework, packagesFolder) {
88+
if (!targetFramework) {
89+
throw new Error('No valid Dotnet target framework found');
90+
}
8291

83-
const installedPackages = fileContentParser.parse(fileContent, tree);
84-
const flattenedPackageList = scanInstalled(installedPackages, packagesFolder);
85-
return fetchNugetInformationFromPackages(flattenedPackageList, dotnetVersions)
92+
const flattenedPackageList = scanInstalled(manifest, packagesFolder);
93+
return fetchNugetInformationFromPackages(flattenedPackageList, targetFramework)
8694
.then(processNugetInformation)
8795
.then(function buildDependencyTree(nuspecResolutions) {
8896
// .nuget parsing is complete, returned as array of promise resolutions
@@ -127,8 +135,6 @@ module.exports = {
127135
}
128136
}
129137
return tree;
130-
}).catch(function (err) {
131-
throw (err);
132138
});
133139
},
134140
};

lib/nuget-parser/index.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
'use strict';
12
const fs = require('fs');
23
const path = require('path');
34
const debug = require('debug')('snyk');
4-
const determineDotnetVersions = require('./csproj-parser');
5+
const getTargetFrameworkFromProjFile = require('./csproj-parser');
56

67
const dotnetCoreParser = require('./dotnet-core-parser');
78
const dotnetFrameworkParser = require('./dotnet-framework-parser');
@@ -42,13 +43,13 @@ module.exports = {
4243
const projectRootFolder = path.resolve(fileContentPath, '../../');
4344
const packagesFolder = getPackagesFolder(packagesFolderPath, projectRootFolder);
4445

45-
let dotnetVersions;
46+
let targetFramework;
4647
try {
4748
if (manifestType === 'dotnet-core') {
48-
dotnetVersions = determineDotnetVersions(projectRootFolder);
49+
targetFramework = getTargetFrameworkFromProjFile(projectRootFolder);
4950
} else {
5051
// .csproj is in the same directory as packages.config or project.json
51-
dotnetVersions = determineDotnetVersions(path.resolve(fileContentPath, '../'));
52+
targetFramework = getTargetFrameworkFromProjFile(path.resolve(fileContentPath, '../'));
5253
}
5354
} catch (error) {
5455
return Promise.reject(error);
@@ -62,15 +63,15 @@ module.exports = {
6263
packageFormatVersion: 'nuget:0.0.0',
6364
dependencies: {},
6465
meta: {
65-
targetFramework: dotnetVersions[0].original, //TODO implement for more than one TF
66+
targetFramework: targetFramework ? targetFramework.original : undefined, //TODO implement for more than one TF
6667
},
6768
};
6869

6970
const parser = PARSERS[manifestType];
70-
return parser.depParser.parse(tree,
71-
fileContent,
72-
parser.fileContentParser,
73-
dotnetVersions,
71+
return parser.depParser.parse(
72+
tree,
73+
parser.fileContentParser.parse(fileContent, tree),
74+
targetFramework,
7475
packagesFolder);
7576
},
7677
};

lib/nuget-parser/nuspec-parser.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'use strict';
12
const JSZip = require('jszip');
23
const fs = require('fs');
34
const path = require('path');
@@ -8,7 +9,7 @@ const debug = require('debug')('snyk');
89

910
const targetFrameworkRegex = /([.a-zA-Z]+)([.0-9]+)/;
1011

11-
function parseNuspec(dep, targetFrameworks, sep) {
12+
function parseNuspec(dep, targetFramework, sep) {
1213
return Promise.resolve()
1314
.then(function () {
1415
const pathSep = sep || '.';
@@ -40,7 +41,7 @@ function parseNuspec(dep, targetFrameworks, sep) {
4041

4142
// Find and add target framework version specific dependencies
4243
const depsForTargetFramework =
43-
extractDepsForTargetFrameworks(rawDependency, targetFrameworks);
44+
extractDepsForTargetFramework(rawDependency, targetFramework);
4445

4546
if (depsForTargetFramework && depsForTargetFramework.group) {
4647
ownDeps = _.concat(ownDeps,
@@ -87,7 +88,7 @@ function extractDepsForPlainGroups(rawDependency) {
8788
});
8889
}
8990

90-
function extractDepsForTargetFrameworks(rawDependency, targetFrameworks) {
91+
function extractDepsForTargetFramework(rawDependency, targetFramework) {
9192
return rawDependency && _(rawDependency.group)
9293
.filter(function (group) {
9394
return group && group.$ && group.$.targetFramework &&
@@ -103,8 +104,8 @@ function extractDepsForTargetFrameworks(rawDependency, targetFrameworks) {
103104
})
104105
.orderBy(['framework', 'version'], ['asc', 'desc'])
105106
.find(function (group) {
106-
return targetFrameworks[0].framework === group.framework &&
107-
targetFrameworks[0].version >= group.version;
107+
return targetFramework.framework === group.framework &&
108+
targetFramework.version >= group.version;
108109
});
109110
}
110111

0 commit comments

Comments
 (0)