diff options
author | Florian Dold <florian.dold@gmail.com> | 2017-05-03 15:35:00 +0200 |
---|---|---|
committer | Florian Dold <florian.dold@gmail.com> | 2017-05-03 15:35:00 +0200 |
commit | de98e0b232509d5f40c135d540a70e415272ff85 (patch) | |
tree | a79222a5b58484ab3b80d18efcaaa7ccc4769b33 /node_modules/fbjs/lib/VersionRange.js.flow | |
parent | e0c9d480a73fa629c1e4a47d3e721f1d2d345406 (diff) |
node_modules
Diffstat (limited to 'node_modules/fbjs/lib/VersionRange.js.flow')
-rw-r--r-- | node_modules/fbjs/lib/VersionRange.js.flow | 373 |
1 files changed, 373 insertions, 0 deletions
diff --git a/node_modules/fbjs/lib/VersionRange.js.flow b/node_modules/fbjs/lib/VersionRange.js.flow new file mode 100644 index 000000000..6aa27ed47 --- /dev/null +++ b/node_modules/fbjs/lib/VersionRange.js.flow @@ -0,0 +1,373 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule VersionRange + */ + +'use strict'; + +const invariant = require('./invariant'); + +const componentRegex = /\./; +const orRegex = /\|\|/; +const rangeRegex = /\s+\-\s+/; +const modifierRegex = /^(<=|<|=|>=|~>|~|>|)?\s*(.+)/; +const numericRegex = /^(\d*)(.*)/; + +/** + * Splits input `range` on "||" and returns true if any subrange matches + * `version`. + * + * @param {string} range + * @param {string} version + * @returns {boolean} + */ +function checkOrExpression(range, version) { + const expressions = range.split(orRegex); + + if (expressions.length > 1) { + return expressions.some(range => VersionRange.contains(range, version)); + } else { + range = expressions[0].trim(); + return checkRangeExpression(range, version); + } +} + +/** + * Splits input `range` on " - " (the surrounding whitespace is required) and + * returns true if version falls between the two operands. + * + * @param {string} range + * @param {string} version + * @returns {boolean} + */ +function checkRangeExpression(range, version) { + const expressions = range.split(rangeRegex); + + invariant(expressions.length > 0 && expressions.length <= 2, 'the "-" operator expects exactly 2 operands'); + + if (expressions.length === 1) { + return checkSimpleExpression(expressions[0], version); + } else { + const [startVersion, endVersion] = expressions; + invariant(isSimpleVersion(startVersion) && isSimpleVersion(endVersion), 'operands to the "-" operator must be simple (no modifiers)'); + + return checkSimpleExpression('>=' + startVersion, version) && checkSimpleExpression('<=' + endVersion, version); + } +} + +/** + * Checks if `range` matches `version`. `range` should be a "simple" range (ie. + * not a compound range using the " - " or "||" operators). + * + * @param {string} range + * @param {string} version + * @returns {boolean} + */ +function checkSimpleExpression(range, version) { + range = range.trim(); + if (range === '') { + return true; + } + + const versionComponents = version.split(componentRegex); + const { modifier, rangeComponents } = getModifierAndComponents(range); + switch (modifier) { + case '<': + return checkLessThan(versionComponents, rangeComponents); + case '<=': + return checkLessThanOrEqual(versionComponents, rangeComponents); + case '>=': + return checkGreaterThanOrEqual(versionComponents, rangeComponents); + case '>': + return checkGreaterThan(versionComponents, rangeComponents); + case '~': + case '~>': + return checkApproximateVersion(versionComponents, rangeComponents); + default: + return checkEqual(versionComponents, rangeComponents); + } +} + +/** + * Checks whether `a` is less than `b`. + * + * @param {array<string>} a + * @param {array<string>} b + * @returns {boolean} + */ +function checkLessThan(a, b) { + return compareComponents(a, b) === -1; +} + +/** + * Checks whether `a` is less than or equal to `b`. + * + * @param {array<string>} a + * @param {array<string>} b + * @returns {boolean} + */ +function checkLessThanOrEqual(a, b) { + const result = compareComponents(a, b); + return result === -1 || result === 0; +} + +/** + * Checks whether `a` is equal to `b`. + * + * @param {array<string>} a + * @param {array<string>} b + * @returns {boolean} + */ +function checkEqual(a, b) { + return compareComponents(a, b) === 0; +} + +/** + * Checks whether `a` is greater than or equal to `b`. + * + * @param {array<string>} a + * @param {array<string>} b + * @returns {boolean} + */ +function checkGreaterThanOrEqual(a, b) { + const result = compareComponents(a, b); + return result === 1 || result === 0; +} + +/** + * Checks whether `a` is greater than `b`. + * + * @param {array<string>} a + * @param {array<string>} b + * @returns {boolean} + */ +function checkGreaterThan(a, b) { + return compareComponents(a, b) === 1; +} + +/** + * Checks whether `a` is "reasonably close" to `b` (as described in + * https://www.npmjs.org/doc/misc/semver.html). For example, if `b` is "1.3.1" + * then "reasonably close" is defined as ">= 1.3.1 and < 1.4". + * + * @param {array<string>} a + * @param {array<string>} b + * @returns {boolean} + */ +function checkApproximateVersion(a, b) { + const lowerBound = b.slice(); + const upperBound = b.slice(); + + if (upperBound.length > 1) { + upperBound.pop(); + } + const lastIndex = upperBound.length - 1; + const numeric = parseInt(upperBound[lastIndex], 10); + if (isNumber(numeric)) { + upperBound[lastIndex] = numeric + 1 + ''; + } + + return checkGreaterThanOrEqual(a, lowerBound) && checkLessThan(a, upperBound); +} + +/** + * Extracts the optional modifier (<, <=, =, >=, >, ~, ~>) and version + * components from `range`. + * + * For example, given `range` ">= 1.2.3" returns an object with a `modifier` of + * `">="` and `components` of `[1, 2, 3]`. + * + * @param {string} range + * @returns {object} + */ +function getModifierAndComponents(range) { + const rangeComponents = range.split(componentRegex); + const matches = rangeComponents[0].match(modifierRegex); + invariant(matches, 'expected regex to match but it did not'); + + return { + modifier: matches[1], + rangeComponents: [matches[2]].concat(rangeComponents.slice(1)) + }; +} + +/** + * Determines if `number` is a number. + * + * @param {mixed} number + * @returns {boolean} + */ +function isNumber(number) { + return !isNaN(number) && isFinite(number); +} + +/** + * Tests whether `range` is a "simple" version number without any modifiers + * (">", "~" etc). + * + * @param {string} range + * @returns {boolean} + */ +function isSimpleVersion(range) { + return !getModifierAndComponents(range).modifier; +} + +/** + * Zero-pads array `array` until it is at least `length` long. + * + * @param {array} array + * @param {number} length + */ +function zeroPad(array, length) { + for (let i = array.length; i < length; i++) { + array[i] = '0'; + } +} + +/** + * Normalizes `a` and `b` in preparation for comparison by doing the following: + * + * - zero-pads `a` and `b` + * - marks any "x", "X" or "*" component in `b` as equivalent by zero-ing it out + * in both `a` and `b` + * - marks any final "*" component in `b` as a greedy wildcard by zero-ing it + * and all of its successors in `a` + * + * @param {array<string>} a + * @param {array<string>} b + * @returns {array<array<string>>} + */ +function normalizeVersions(a, b) { + a = a.slice(); + b = b.slice(); + + zeroPad(a, b.length); + + // mark "x" and "*" components as equal + for (let i = 0; i < b.length; i++) { + const matches = b[i].match(/^[x*]$/i); + if (matches) { + b[i] = a[i] = '0'; + + // final "*" greedily zeros all remaining components + if (matches[0] === '*' && i === b.length - 1) { + for (let j = i; j < a.length; j++) { + a[j] = '0'; + } + } + } + } + + zeroPad(b, a.length); + + return [a, b]; +} + +/** + * Returns the numerical -- not the lexicographical -- ordering of `a` and `b`. + * + * For example, `10-alpha` is greater than `2-beta`. + * + * @param {string} a + * @param {string} b + * @returns {number} -1, 0 or 1 to indicate whether `a` is less than, equal to, + * or greater than `b`, respectively + */ +function compareNumeric(a, b) { + const aPrefix = a.match(numericRegex)[1]; + const bPrefix = b.match(numericRegex)[1]; + const aNumeric = parseInt(aPrefix, 10); + const bNumeric = parseInt(bPrefix, 10); + + if (isNumber(aNumeric) && isNumber(bNumeric) && aNumeric !== bNumeric) { + return compare(aNumeric, bNumeric); + } else { + return compare(a, b); + } +} + +/** + * Returns the ordering of `a` and `b`. + * + * @param {string|number} a + * @param {string|number} b + * @returns {number} -1, 0 or 1 to indicate whether `a` is less than, equal to, + * or greater than `b`, respectively + */ +function compare(a, b) { + invariant(typeof a === typeof b, '"a" and "b" must be of the same type'); + + if (a > b) { + return 1; + } else if (a < b) { + return -1; + } else { + return 0; + } +} + +/** + * Compares arrays of version components. + * + * @param {array<string>} a + * @param {array<string>} b + * @returns {number} -1, 0 or 1 to indicate whether `a` is less than, equal to, + * or greater than `b`, respectively + */ +function compareComponents(a, b) { + const [aNormalized, bNormalized] = normalizeVersions(a, b); + + for (let i = 0; i < bNormalized.length; i++) { + const result = compareNumeric(aNormalized[i], bNormalized[i]); + if (result) { + return result; + } + } + + return 0; +} + +var VersionRange = { + /** + * Checks whether `version` satisfies the `range` specification. + * + * We support a subset of the expressions defined in + * https://www.npmjs.org/doc/misc/semver.html: + * + * version Must match version exactly + * =version Same as just version + * >version Must be greater than version + * >=version Must be greater than or equal to version + * <version Must be less than version + * <=version Must be less than or equal to version + * ~version Must be at least version, but less than the next significant + * revision above version: + * "~1.2.3" is equivalent to ">= 1.2.3 and < 1.3" + * ~>version Equivalent to ~version + * 1.2.x Must match "1.2.x", where "x" is a wildcard that matches + * anything + * 1.2.* Similar to "1.2.x", but "*" in the trailing position is a + * "greedy" wildcard, so will match any number of additional + * components: + * "1.2.*" will match "1.2.1", "1.2.1.1", "1.2.1.1.1" etc + * * Any version + * "" (Empty string) Same as * + * v1 - v2 Equivalent to ">= v1 and <= v2" + * r1 || r2 Passes if either r1 or r2 are satisfied + * + * @param {string} range + * @param {string} version + * @returns {boolean} + */ + contains(range, version) { + return checkOrExpression(range.trim(), version.trim()); + } +}; + +module.exports = VersionRange;
\ No newline at end of file |