You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

161 lines
4.1 KiB

// spdx.js
// =======
// SPDX License Expression Syntax parser
// Validation
// ----------
// Require the generated parser.
var parser = require('./parser.generated.js').parser;
exports.parse = function(argument) {
return parser.parse(argument);
};
var containsRepeatedSpace = /\s{2,}/;
exports.valid = function(argument) {
if (
argument.trim() !== argument ||
containsRepeatedSpace.test(argument)
) {
return false;
}
try {
parser.parse(argument);
return true;
} catch (e) {
// jison generates parsers that throw errors, while this function
// mimics `semver.valid` by returning null.
return null;
}
};
// Comparison
// ----------
var ranges = require('./ranges.json');
var notALicenseIdentifier = ' is not a simple license identifier';
var rangeComparison = function(comparison) {
return function(first, second) {
var firstAST = exports.parse(first);
if (!firstAST.hasOwnProperty('license')) {
throw new Error('"' + first + '"' + notALicenseIdentifier);
}
var secondAST = exports.parse(second);
if (!secondAST.hasOwnProperty('license')) {
throw new Error('"' + second + '"' + notALicenseIdentifier);
}
return ranges.some(function(range) {
var indexOfFirst = range.indexOf(firstAST.license);
if (indexOfFirst < 0) {
return false;
}
var indexOfSecond = range.indexOf(secondAST.license);
if (indexOfSecond < 0) {
return false;
}
return comparison(indexOfFirst, indexOfSecond);
});
};
};
exports.gt = rangeComparison(function(first, second) {
return first > second;
});
exports.lt = rangeComparison(function(first, second) {
return first < second;
});
exports.satisfies = (function() {
var rangesAreCompatible = function(first, second) {
return (
first.license === second.license ||
ranges.some(function(range) {
return (
range.indexOf(first.license) > -1 &&
range.indexOf(second.license)
);
})
);
};
var identifierInRange = function(identifier, range) {
return (
identifier.license === range.license ||
exports.gt(identifier.license, range.license)
);
};
var licensesAreCompatible = function(first, second) {
if (first.exception !== second.exception) {
return false;
} else if (second.hasOwnProperty('license')) {
if (second.hasOwnProperty('plus')) {
if (first.hasOwnProperty('plus')) {
// first+, second+
return rangesAreCompatible(first, second);
} else {
// first, second+
return identifierInRange(first, second);
}
} else {
if (first.hasOwnProperty('plus')) {
// first+, second
return identifierInRange(second, first);
} else {
// first, second
return first.license === second.license;
}
}
}
};
var recurseLeftAndRight = function(first, second) {
var firstConjunction = first.conjunction;
if (firstConjunction === 'and') {
return (
recurse(first.left, second) &&
recurse(first.right, second)
);
} else if (firstConjunction === 'or') {
return (
recurse(first.left, second) ||
recurse(first.right, second)
);
}
};
var recurse = function(first, second) {
if (first.hasOwnProperty('conjunction')) {
return recurseLeftAndRight(first, second);
} else if (second.hasOwnProperty('conjunction')) {
return recurseLeftAndRight(second, first);
} else {
return licensesAreCompatible(first, second);
}
};
return function(first, second) {
return recurse(parser.parse(first), parser.parse(second));
};
})();
// Reference Data
// --------------
// Require the same license and exception data used by the parser.
exports.licenses = require('spdx-license-ids');
exports.exceptions = require('./exceptions.json');
// Version Metadata
// ----------------
// The License Expression Syntax version
exports.specificationVersion = '2.0';
// This module's semantic version
exports.implementationVersion = '0.4.1';