Skip to content

Commit ddf2aa3

Browse files
committed
#241 Improved NPM model with correct owners and authors
1 parent a976008 commit ddf2aa3

File tree

4 files changed

+599
-2321
lines changed

4 files changed

+599
-2321
lines changed

src/packagedcode/npm.py

Lines changed: 63 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,7 @@
3535
from commoncode import filetype
3636
from commoncode import fileutils
3737

38-
from packagedcode.models import AssertedLicense
39-
from packagedcode.models import Dependency
40-
from packagedcode.models import Package
41-
from packagedcode.models import Party
42-
from packagedcode.models import Repository
43-
from packagedcode.models import Versioning
44-
from schematics.types import StringType
45-
from schematics.types.compound import ModelType
38+
from packagedcode import models
4639

4740
"""
4841
Handle Node.js NPM packages
@@ -61,6 +54,20 @@
6154
# logger.setLevel(logging.DEBUG)
6255

6356

57+
class NpmPackage(models.Package):
58+
metafiles = ('package.json', 'npm-shrinkwrap.json')
59+
filetypes = ('.tgz',)
60+
mimetypes = ('application/x-tar',)
61+
repo_types = (models.repo_npm,)
62+
63+
type = models.StringType(default='npm')
64+
primary_language = models.StringType(default='JavaScript')
65+
66+
@staticmethod
67+
def recognize(location):
68+
return parse(location)
69+
70+
6471
def is_package_json(location):
6572
return (filetype.is_file(location)
6673
and fileutils.file_name(location).lower() == 'package.json')
@@ -71,27 +78,9 @@ def is_node_modules(location):
7178
and fileutils.file_name(location).lower() == 'node_modules')
7279

7380

74-
class NpmVersion(Versioning):
75-
version = StringType()
76-
77-
78-
class NpmPackage(Package):
79-
type = StringType(default='npm')
80-
versioning = ModelType(NpmVersion)
81-
metafiles = ('package.json',)
82-
primary_language = StringType(default='JavaScript')
83-
filetypes = ('.tgz',)
84-
mimetypes = ('application/x-tar',)
85-
repo_types = (Repository.repo_type_npm,)
86-
87-
@staticmethod
88-
def getPackage(location):
89-
return parse(location)
90-
91-
9281
def parse(location):
9382
"""
94-
Return a Package object from a package.json
83+
Return a Package object from a package.json file or None.
9584
"""
9685
if not is_package_json(location):
9786
return
@@ -104,8 +93,8 @@ def parse(location):
10493
('homepage', 'homepage_url'),
10594
])
10695

107-
# mapping of top level package.json items to a function accepting as arguments:
108-
# - the package.json element value and a Package Object to update
96+
# mapping of top level package.json items to a function accepting as arguments
97+
# the package.json element value and returning an iterable of key, values Package Object to update
10998
field_mappers = OrderedDict([
11099
('author', author_mapper),
111100
('bugs', bugs_mapper),
@@ -129,11 +118,13 @@ def parse(location):
129118
# a package.json without name and version is not a usable NPM package
130119
return
131120

121+
package = NpmPackage()
132122
# a package.json is at the root of an NPM package
133123
base_dir = fileutils.parent_directory(location)
134-
package = NpmPackage()
124+
package.location = base_dir
125+
# for now we only recognize a pcakge.json, not a node_modules directory yet
135126
package.metafile_locations = [location]
136-
package.versioning = NpmVersion(version=data.get('version'))
127+
package.version = data.get('version')
137128
for source, target in plain_fields.items():
138129
value = data.get(source)
139130
if value:
@@ -151,7 +142,7 @@ def parse(location):
151142
if value:
152143
func(value, package)
153144

154-
package.download_urls.append(public_download_url(package.name, package.versioning.version))
145+
package.download_urls.append(public_download_url(package.name, package.version))
155146
package.metafile_locations.append(location)
156147
return package
157148

@@ -172,7 +163,7 @@ def licensing_mapper(licenses, package):
172163
return package
173164

174165
if isinstance(licenses, basestring):
175-
package.asserted_licenses.append(AssertedLicense(license=licenses))
166+
package.asserted_licenses.append(models.AssertedLicense(license=licenses))
176167

177168
elif isinstance(licenses, dict):
178169
"""
@@ -181,7 +172,7 @@ def licensing_mapper(licenses, package):
181172
"url": "http://github.com/kriskowal/q/raw/master/LICENSE"
182173
}
183174
"""
184-
package.asserted_licenses.append(AssertedLicense(license=licenses.get('type'),
175+
package.asserted_licenses.append(models.AssertedLicense(license=licenses.get('type'),
185176
url=licenses.get('url')))
186177

187178
elif isinstance(licenses, list):
@@ -194,18 +185,18 @@ def licensing_mapper(licenses, package):
194185
# TODO: handle multiple values
195186
for lic in licenses:
196187
if isinstance(lic, basestring):
197-
package.asserted_licenses.append(AssertedLicense(license=lic))
188+
package.asserted_licenses.append(models.AssertedLicense(license=lic))
198189
elif isinstance(lic, dict):
199-
package.asserted_licenses.append(AssertedLicense(license=lic.get('type'),
190+
package.asserted_licenses.append(models.AssertedLicense(license=lic.get('type'),
200191
url=lic.get('url')))
201192
else:
202193
# use the bare repr
203194
if lic:
204-
package.asserted_licenses.append(AssertedLicense(license=repr(lic)))
195+
package.asserted_licenses.append(models.AssertedLicense(license=repr(lic)))
205196

206197
else:
207198
# use the bare repr
208-
package.asserted_licenses.append(AssertedLicense(license=repr(licenses)))
199+
package.asserted_licenses.append(models.AssertedLicense(license=repr(licenses)))
209200

210201
return package
211202

@@ -217,10 +208,7 @@ def author_mapper(author, package):
217208
The "author" is one person.
218209
"""
219210
name, email, url = parse_person(author)
220-
package.authors = [Party(type=Party.party_person,
221-
name=name,
222-
email=email,
223-
url=url)]
211+
package.authors = [models.Party(type=models.party_person, name=name, email=email, url=url)]
224212
return package
225213

226214

@@ -234,16 +222,13 @@ def contributors_mapper(contributors, package):
234222
if isinstance(contributors, list):
235223
for contrib in contributors:
236224
name, email, url = parse_person(contrib)
237-
contribs.append(Party(type=Party.party_person,
238-
name=name,
239-
email=email,
240-
url=url))
225+
226+
contribs.append(models.Party(type=models.party_person, name=name, email=email, url=url))
227+
241228
else: # a string or dict
242229
name, email, url = parse_person(contributors)
243-
contribs.append(Party(type=Party.party_person,
244-
name=name,
245-
email=email,
246-
url=url))
230+
contribs.append(models.Party(type=models.party_person, name=name, email=email, url=url))
231+
247232
package.contributors = contribs
248233
return package
249234

@@ -259,16 +244,10 @@ def maintainers_mapper(maintainers, package):
259244
if isinstance(maintainers, list):
260245
for contrib in maintainers:
261246
name, email, url = parse_person(contrib)
262-
maintains.append(Party(type=Party.party_person,
263-
name=name,
264-
email=email,
265-
url=url))
247+
maintains.append(models.Party(type=models.party_person, name=name, email=email, url=url))
266248
else: # a string or dict
267249
name, email, url = parse_person(maintainers)
268-
maintains.append(Party(type=Party.party_person,
269-
name=name,
270-
email=email,
271-
url=url))
250+
maintains.append(models.Party(type=models.party_person, name=name, email=email, url=url))
272251
package.maintainers = maintains
273252
return package
274253

@@ -338,10 +317,12 @@ def repository_mapper(repo, package):
338317

339318
def parse_repo_url(repo_url):
340319
"""
341-
https://docs.npmjs.com/files/package.json#repository
342320
Validate a repo_ulr and handle shortcuts for GitHub, GitHub gist,
343321
Bitbucket, or GitLab repositories (same syntax as npm install):
344-
This is done here: https://github.com/npm/npm/blob/d3c858ce4cfb3aee515bb299eb034fe1b5e44344/node_modules/hosted-git-info/git-host-info.js
322+
323+
See https://docs.npmjs.com/files/package.json#repository
324+
This is done here in npm:
325+
https://github.com/npm/npm/blob/d3c858ce4cfb3aee515bb299eb034fe1b5e44344/node_modules/hosted-git-info/git-host-info.js
345326
346327
These should be resolved:
347328
npm/npm
@@ -394,8 +375,9 @@ def parse_repo_url(repo_url):
394375

395376
def url_mapper(url, package):
396377
"""
397-
a "url" fieldis a redirection to your package that has been published
398-
somewhere else than the public npm registry
378+
In a package.json, the "url" field is a redirection to a package download
379+
URL published somewhere else than on the public npm registry.
380+
We map it to a download url.
399381
"""
400382
if url:
401383
package.download_urls.append(url)
@@ -404,7 +386,7 @@ def url_mapper(url, package):
404386

405387
def dist_mapper(dist, package):
406388
"""
407-
only present in some package.json forms (as installed or from a registry?)
389+
Only present in some package.json forms (as installed or from a registry?)
408390
"dist": {
409391
"shasum": "a124386bce4a90506f28ad4b1d1a804a17baaf32",
410392
"tarball": "http://registry.npmjs.org/npm/-/npm-2.13.5.tgz"
@@ -422,11 +404,11 @@ def bundle_deps_mapper(bundle_deps, package):
422404
"""
423405
https://docs.npmjs.com/files/package.json#bundleddependencies
424406
"""
425-
package.dependencies[Package.dep_bundled] = bundle_deps
407+
package.dependencies[models.dep_bundled] = bundle_deps
426408
return package
427409

428410

429-
def _deps_mapper(deps, package, field_name):
411+
def deps_mapper(deps, package, field_name):
430412
"""
431413
Handle deps such as dependencies, devDependencies, peerDependencies, optionalDependencies
432414
return a tuple of (dep type, list of deps)
@@ -435,15 +417,16 @@ def _deps_mapper(deps, package, field_name):
435417
https://docs.npmjs.com/files/package.json#devdependencies
436418
https://docs.npmjs.com/files/package.json#optionaldependencies
437419
"""
438-
dep_types = {'dependencies': Package.dep_runtime,
439-
'devDependencies': Package.dep_dev,
440-
'peerDependencies': Package.dep_optional,
441-
'optionalDependencies': Package.dep_optional,
442-
}
420+
dep_types = {
421+
'dependencies': models.dep_runtime,
422+
'devDependencies': models.dep_dev,
423+
'peerDependencies': models.dep_optional,
424+
'optionalDependencies': models.dep_optional,
425+
}
443426
resolved_type = dep_types[field_name]
444427
dependencies = []
445-
for pid, version_constraint in deps.items():
446-
dep = Dependency(id=pid, version_constraint=version_constraint)
428+
for name, version_constraint in deps.items():
429+
dep = models.Dependency(name=name, version_constraint=version_constraint)
447430
dependencies.append(dep)
448431
if resolved_type in package.dependencies:
449432
package.dependencies[resolved_type].extend(dependencies)
@@ -452,10 +435,10 @@ def _deps_mapper(deps, package, field_name):
452435
return package
453436

454437

455-
dependencies_mapper = partial(_deps_mapper, field_name='dependencies')
456-
dev_dependencies_mapper = partial(_deps_mapper, field_name='devDependencies')
457-
peer_dependencies_mapper = partial(_deps_mapper, field_name='peerDependencies')
458-
optional_dependencies_mapper = partial(_deps_mapper, field_name='optionalDependencies')
438+
dependencies_mapper = partial(deps_mapper, field_name='dependencies')
439+
dev_dependencies_mapper = partial(deps_mapper, field_name='devDependencies')
440+
peer_dependencies_mapper = partial(deps_mapper, field_name='peerDependencies')
441+
optional_dependencies_mapper = partial(deps_mapper, field_name='optionalDependencies')
459442

460443

461444
person_parser = re.compile(
@@ -507,13 +490,15 @@ def parse_person(person):
507490

508491
def public_download_url(name, version, registry='https://registry.npmjs.org'):
509492
"""
510-
Return a package tarball download URL
493+
Return a package tarball download URL given a name, version and a base
494+
registry URL.
511495
"""
512496
return '%(registry)s/%(name)s/-/%(name)s-%(version)s.tgz' % locals()
513497

514498

515499
def public_package_data_url(name, version, registry='https://registry.npmjs.org'):
516500
"""
517-
Return a package metadata download URL
501+
Return a package metadata download URL given a name, version and a base
502+
registry URL.
518503
"""
519504
return '%(registry)s/%(name)s/%(version)s' % locals()
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
{
2+
"type": "npm",
3+
"name": "cookie-signature",
4+
"version": "1.0.3",
5+
"primary_language": "JavaScript",
6+
"packaging": null,
7+
"summary": "Sign and unsign cookies",
8+
"description": null,
9+
"payload_type": null,
10+
"authors": [
11+
{
12+
"type": "person",
13+
"name": "TJ Holowaychuk",
14+
"email": "tj@learnboost.com",
15+
"url": null
16+
}
17+
],
18+
"maintainers": [],
19+
"contributors": [],
20+
"owners": [],
21+
"packagers": [],
22+
"distributors": [],
23+
"vendors": [],
24+
"keywords": [
25+
"cookie",
26+
"sign",
27+
"unsign"
28+
],
29+
"keywords_doc_url": null,
30+
"metafile_locations": [
31+
"package.json",
32+
"package.json"
33+
],
34+
"metafile_urls": [],
35+
"homepage_url": null,
36+
"notes": null,
37+
"download_urls": [
38+
"https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.3.tgz"
39+
],
40+
"download_sha1": null,
41+
"download_sha256": null,
42+
"download_md5": null,
43+
"bug_tracking_url": "https://github.com/visionmedia/node-cookie-signature/issues",
44+
"support_contacts": [],
45+
"code_view_url": null,
46+
"vcs_tool": "git",
47+
"vcs_repository": "https://github.com/visionmedia/node-cookie-signature.git",
48+
"vcs_revision": null,
49+
"copyright_top_level": null,
50+
"copyrights": [],
51+
"asserted_licenses": [],
52+
"legal_file_locations": [],
53+
"license_expression": null,
54+
"license_texts": [],
55+
"notice_texts": [],
56+
"dependencies": {
57+
"development": [
58+
{
59+
"name": "mocha",
60+
"version": null,
61+
"version_constraint": "*"
62+
},
63+
{
64+
"name": "should",
65+
"version": null,
66+
"version_constraint": "*"
67+
}
68+
]
69+
},
70+
"related_packages": []
71+
}

0 commit comments

Comments
 (0)