mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
extract more information from package.json files; add tests (#710)
This commit is contained in:
parent
0ec138653e
commit
c81ace882e
@ -1,70 +1,228 @@
|
|||||||
/**
|
|
||||||
@overview
|
|
||||||
@author Michael Mathews <micmath@gmail.com>
|
|
||||||
@license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
|
||||||
*/
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
var logger = require('jsdoc/util/logger');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@module jsdoc/package
|
* Provides access to information about a JavaScript package.
|
||||||
@see http://wiki.commonjs.org/wiki/Packages/1.0
|
*
|
||||||
|
* @module jsdoc/package
|
||||||
|
* @see https://www.npmjs.org/doc/files/package.json.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Collect all of the license information from a `package.json` file.
|
||||||
|
function getLicenses(packageInfo) {
|
||||||
|
var licenses = packageInfo.licenses ? packageInfo.licenses.slice(0) : [];
|
||||||
|
|
||||||
|
if (packageInfo.license) {
|
||||||
|
licenses.push({ type: packageInfo.license });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (licenses.length) {
|
||||||
|
return licenses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about where to report bugs in the package.
|
||||||
|
*
|
||||||
|
* @typedef {Object} module:jsdoc/package.Package~BugInfo
|
||||||
|
* @property {string} email - The email address for reporting bugs.
|
||||||
|
* @property {string} url - The URL for reporting bugs.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@class
|
* Information about a package's software license.
|
||||||
@classdesc Represents a JavaScript package.
|
*
|
||||||
@param {string} json - The contents of package.json.
|
* @typedef {Object} module:jsdoc/package.Package~LicenseInfo
|
||||||
|
* @property {string} type - An identifier for the type of license.
|
||||||
|
* @property {string} url - The URL for the complete text of the license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a package author or contributor.
|
||||||
|
*
|
||||||
|
* @typedef {Object} module:jsdoc/package.Package~PersonInfo
|
||||||
|
* @property {string} name - The person's full name.
|
||||||
|
* @property {string} email - The person's email address.
|
||||||
|
* @property {string} url - The URL of the person's website.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a package's version-control repository.
|
||||||
|
*
|
||||||
|
* @typedef {Object} module:jsdoc/package.Package~RepositoryInfo
|
||||||
|
* @property {string} type - The type of version-control system that the repository uses (for
|
||||||
|
* example, `git` or `svn`).
|
||||||
|
* @property {string} url - The URL for the repository.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about a JavaScript package. JSDoc can extract package information from
|
||||||
|
* `package.json` files that follow the
|
||||||
|
* [npm specification](https://www.npmjs.org/doc/files/package.json.html).
|
||||||
|
*
|
||||||
|
* **Note**: JSDoc does not validate or normalize the contents of `package.json` files. If your
|
||||||
|
* `package.json` file does not follow the npm specification, some properties of the `Package`
|
||||||
|
* object may not use the format documented here.
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
* @param {string} json - The contents of the `package.json` file.
|
||||||
*/
|
*/
|
||||||
exports.Package = function(json) {
|
exports.Package = function(json) {
|
||||||
json = json || '{}';
|
var packageInfo;
|
||||||
|
|
||||||
/** The source files associated with this package.
|
/**
|
||||||
@type {Array<String>}
|
* The string identifier that is shared by all `Package` objects.
|
||||||
|
*
|
||||||
|
* @readonly
|
||||||
|
* @default
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.kind = 'package';
|
||||||
|
|
||||||
|
try {
|
||||||
|
packageInfo = JSON.parse(json || '{}');
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
logger.error('Unable to parse the package file: %s', e.message);
|
||||||
|
packageInfo = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The package name.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.name = packageInfo.name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique longname for this `Package` object.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.longname = this.kind + ':' + this.name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The author of this package. Contains either a
|
||||||
|
* {@link module:jsdoc/package.Package~PersonInfo PersonInfo} object or a string with
|
||||||
|
* information about the author.
|
||||||
|
*
|
||||||
|
* @type {(module:jsdoc/package.Package~PersonInfo|string)}
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
this.author = packageInfo.author;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information about where to report bugs in the project. May contain a URL, as a string, or
|
||||||
|
* an object with more detailed information.
|
||||||
|
*
|
||||||
|
* @type {(string|module:jsdoc/package.Package~BugInfo)}
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
this.bugs = packageInfo.bugs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The contributors to this package.
|
||||||
|
*
|
||||||
|
* @type {Array.<(module:jsdoc/package.Package~PersonInfo|string)>}
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
this.contributors = packageInfo.contributors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dependencies for this package.
|
||||||
|
*
|
||||||
|
* @type {Object}
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
this.dependencies = packageInfo.dependencies;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A brief description of the package.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
this.description = packageInfo.description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The development dependencies for this package.
|
||||||
|
*
|
||||||
|
* @type {Object}
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
this.devDependencies = packageInfo.devDependencies;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JavaScript engines that this package supports. Each key is a string that identifies the
|
||||||
|
* engine (for example, `node`). Each value is a
|
||||||
|
* [semver](https://www.npmjs.org/doc/misc/semver.html)-compliant version number for the engine.
|
||||||
|
*
|
||||||
|
* @type {Object}
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
this.engines = packageInfo.engines;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The source files associated with the package.
|
||||||
|
*
|
||||||
|
* New `Package` objects always contain an empty array, regardless of whether the `package.json`
|
||||||
|
* file includes a `files` property.
|
||||||
|
*
|
||||||
|
* After JSDoc parses your input files, it sets this property to a list of paths to your input
|
||||||
|
* files.
|
||||||
|
*
|
||||||
|
* @type {Array.<string>}
|
||||||
*/
|
*/
|
||||||
this.files = [];
|
this.files = [];
|
||||||
|
|
||||||
/** The kind of this package.
|
|
||||||
@readonly
|
|
||||||
@default
|
|
||||||
@type {string}
|
|
||||||
*/
|
|
||||||
this.kind = 'package';
|
|
||||||
|
|
||||||
json = JSON.parse(json);
|
|
||||||
|
|
||||||
/** The name of this package.
|
|
||||||
This value is found in the package.json file passed in as a command line option.
|
|
||||||
@type {string}
|
|
||||||
*/
|
|
||||||
this.name = json.name;
|
|
||||||
|
|
||||||
/** The longname of this package.
|
|
||||||
@type {string}
|
|
||||||
*/
|
|
||||||
this.longname = this.kind + ':' + this.name;
|
|
||||||
|
|
||||||
/** The description of this package.
|
|
||||||
@type {string}
|
|
||||||
*/
|
|
||||||
this.description = json.description;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The hash summary of the source file.
|
* The URL for the package's homepage.
|
||||||
@type {string}
|
*
|
||||||
@since 3.2.0
|
* @type {string}
|
||||||
*/
|
* @since 3.3.0
|
||||||
this.version = json.version;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The licenses of this package.
|
|
||||||
* @type {Array<Object>}
|
|
||||||
* @example
|
|
||||||
* "licenses": [
|
|
||||||
* {
|
|
||||||
* "type": "GPLv2",
|
|
||||||
* "url": "http://www.example.com/licenses/gpl.html"
|
|
||||||
* }
|
|
||||||
* ]
|
|
||||||
*/
|
*/
|
||||||
this.licenses = json.licenses;
|
this.homepage = packageInfo.homepage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keywords to help users find the package.
|
||||||
|
*
|
||||||
|
* @type {Array.<string>}
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
this.keywords = packageInfo.keywords;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The licenses used by this package. Combines information from the `package.json` file's
|
||||||
|
* `license` property and the deprecated `licenses` property.
|
||||||
|
*
|
||||||
|
* @type {Array.<module:jsdoc/package.Package~LicenseInfo>}
|
||||||
|
*/
|
||||||
|
this.licenses = getLicenses(packageInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The module ID that provides the primary entry point to the package. For example, if your
|
||||||
|
* package is a CommonJS module, and the value of this property is `foo`, users should be able
|
||||||
|
* to load your module with `require('foo')`.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
this.main = packageInfo.main;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The version-control repository for the package.
|
||||||
|
*
|
||||||
|
* @type {module:jsdoc/package.Package~RepositoryInfo}
|
||||||
|
* @since 3.3.0
|
||||||
|
*/
|
||||||
|
this.repository = packageInfo.repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [semver](https://www.npmjs.org/doc/misc/semver.html)-compliant version number of the
|
||||||
|
* package.
|
||||||
|
*
|
||||||
|
* @type {string}
|
||||||
|
* @since 3.2.0
|
||||||
|
*/
|
||||||
|
this.version = packageInfo.version;
|
||||||
};
|
};
|
||||||
|
|||||||
259
test/specs/jsdoc/package.js
Normal file
259
test/specs/jsdoc/package.js
Normal file
@ -0,0 +1,259 @@
|
|||||||
|
/*global beforeEach, describe, expect, it, spyOn */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('jsdoc/package', function() {
|
||||||
|
var emptyPackage;
|
||||||
|
var jsdocPackage = require('jsdoc/package');
|
||||||
|
var logger = require('jsdoc/util/logger');
|
||||||
|
var Package = jsdocPackage.Package;
|
||||||
|
|
||||||
|
function checkPackageProperty(name, value) {
|
||||||
|
var myPackage;
|
||||||
|
var obj = {};
|
||||||
|
|
||||||
|
obj[name] = value;
|
||||||
|
myPackage = new Package( JSON.stringify(obj) );
|
||||||
|
|
||||||
|
// use toEqual so we can test array/object values
|
||||||
|
expect(myPackage[name]).toEqual(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should exist', function() {
|
||||||
|
expect(jsdocPackage).toBeDefined();
|
||||||
|
expect(typeof jsdocPackage).toBe('object');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should export a "Package" constructor', function() {
|
||||||
|
expect(Package).toBeDefined();
|
||||||
|
expect(typeof Package).toBe('function');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Package', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
emptyPackage = new Package();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should accept a JSON-format string', function() {
|
||||||
|
function newPackage() {
|
||||||
|
return new Package('{"foo": "bar"}');
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(newPackage).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work when called with no arguments', function() {
|
||||||
|
function newPackage() {
|
||||||
|
return new Package();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(newPackage).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log an error when called with bad input', function() {
|
||||||
|
function newPackage() {
|
||||||
|
return new Package('abcdefg');
|
||||||
|
}
|
||||||
|
|
||||||
|
spyOn(logger, 'error');
|
||||||
|
|
||||||
|
expect(newPackage).not.toThrow();
|
||||||
|
expect(logger.error).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('author', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.author).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('author', { name: 'Jane Smith', email: 'jsmith@example.com' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('bugs', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.bugs).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('bugs', { url: 'http://example.com/bugs' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('contributors', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.contributors).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('contributors', [{
|
||||||
|
name: 'Jane Smith',
|
||||||
|
email: 'jsmith@example.com'
|
||||||
|
}]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('dependencies', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.dependencies).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('dependencies', { bar: '~1.1.0' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('description', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.description).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('description', 'My package.');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('devDependencies', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.devDependencies).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('devDependencies', { baz: '~3.4.5' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('engines', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.engines).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('engines', { node: '>=0.10.3' });
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('files', function() {
|
||||||
|
it('should contain an empty array by default', function() {
|
||||||
|
expect(emptyPackage.files).toBeDefined();
|
||||||
|
expect(emptyPackage.files).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore the value from the package file', function() {
|
||||||
|
var myPackage = new Package('{"files": ["foo", "bar"]}');
|
||||||
|
|
||||||
|
expect(myPackage.files.length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('homepage', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.homepage).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('homepage', 'http://example.com/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('keywords', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.keywords).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('keywords', ['foo', 'bar']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('licenses', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.licenses).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('licenses', [{
|
||||||
|
type: 'My Open-Source License',
|
||||||
|
url: 'http://example.com/oss'
|
||||||
|
}]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value of "license" from the package file', function() {
|
||||||
|
var myPackage = new Package('{"license": "My-OSS-License"}');
|
||||||
|
|
||||||
|
expect(myPackage.license).not.toBeDefined();
|
||||||
|
expect(myPackage.licenses).toBeDefined();
|
||||||
|
expect(myPackage.licenses.length).toBe(1);
|
||||||
|
expect(myPackage.licenses[0].type).toBe('My-OSS-License');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should combine the "license" and "licenses" properties', function() {
|
||||||
|
var packageInfo = {
|
||||||
|
license: 'My-OSS-License',
|
||||||
|
licenses: [{
|
||||||
|
type: 'My Open-Source License',
|
||||||
|
url: 'http://example.com/oss'
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
var myPackage = new Package( JSON.stringify(packageInfo) );
|
||||||
|
|
||||||
|
expect(myPackage.licenses.length).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('longname', function() {
|
||||||
|
it('should default to "package:undefined"', function() {
|
||||||
|
expect(emptyPackage.longname).toBe('package:undefined');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reflect the value of the "name" property', function() {
|
||||||
|
var myPackage = new Package('{"name": "foo"}');
|
||||||
|
|
||||||
|
expect(myPackage.longname).toBe('package:foo');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('main', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.main).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('main', 'foo');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('name', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.name).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('name', 'foo');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('repository', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.repository).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('repository', {
|
||||||
|
type: 'git',
|
||||||
|
url: 'git@example.org:foo/bar/baz.git'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('version', function() {
|
||||||
|
it('should be undefined by default', function() {
|
||||||
|
expect(emptyPackage.version).not.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain the value from the package file', function() {
|
||||||
|
checkPackageProperty('version', '0.1.2');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user