Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Downgrade to semver compatible with Node v8 #1575

Merged
merged 2 commits into from Jul 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
207 changes: 206 additions & 1 deletion lib/rules/no-unsupported-features.js
Expand Up @@ -129,7 +129,7 @@ module.exports = {
* @returns {boolean} `true` if it's supporting.
*/
function isNotSupportingVersion(aCase) {
return !semver.subset(versionRange, getSemverRange(aCase.supported))
return !semverSubset(versionRange, getSemverRange(aCase.supported))
}

/** @type {TemplateListener} */
Expand Down Expand Up @@ -163,3 +163,208 @@ module.exports = {
)
}
}

// TODO replace semver.subset() in the major version.
/**
* semver.subset()
*
* We need to use a copy of the semver source code until a major version upgrade.
*
* @see https://github.com/npm/node-semver/blob/e79ac3a450e8bb504e78b8159e3efc70895699b8/ranges/subset.js#L43
* @license ISC at Isaac Z. Schlueter and Contributors
* https://github.com/npm/node-semver/blob/master/LICENSE
*
* @param {semver.Range} sub
* @param {semver.Range} dom
*/
function semverSubset(sub, dom) {
if (sub === dom) return true

sub = new semver.Range(sub)
dom = new semver.Range(dom)
let sawNonNull = false

// eslint-disable-next-line no-labels
OUTER: for (const simpleSub of sub.set) {
for (const simpleDom of dom.set) {
const isSub = simpleSubset(simpleSub, simpleDom)
sawNonNull = sawNonNull || isSub !== null
// eslint-disable-next-line no-labels
if (isSub) continue OUTER
}
if (sawNonNull) return false
}
return true
}

/**
* @license ISC at Isaac Z. Schlueter and Contributors
* https://github.com/npm/node-semver/blob/master/LICENSE
* @param {readonly semver.Comparator[]} sub
* @param {readonly semver.Comparator[]} dom
*/
function simpleSubset(sub, dom) {
if (sub === dom) return true

/**
* @param {semver.Comparator} c
*/
function isAny(c) {
return Object.keys(c.semver).length === 0
}

if (sub.length === 1 && isAny(sub[0])) {
if (dom.length === 1 && isAny(dom[0])) return true
else sub = [new semver.Comparator('>=0.0.0')]
}

if (dom.length === 1 && isAny(dom[0])) {
dom = [new semver.Comparator('>=0.0.0')]
}

const eqSet = new Set()
let gt, lt
for (const c of sub) {
if (c.operator === '>' || c.operator === '>=') gt = higherGT(gt, c)
else if (c.operator === '<' || c.operator === '<=') lt = lowerLT(lt, c)
else eqSet.add(c.semver)
}

if (eqSet.size > 1) return null

let gtltComp
if (gt && lt) {
gtltComp = semver.compare(gt.semver, lt.semver)
if (gtltComp > 0) return null
else if (gtltComp === 0 && (gt.operator !== '>=' || lt.operator !== '<='))
return null
}

// will iterate one or zero times
for (const eq of eqSet) {
if (gt && !semver.satisfies(eq, String(gt))) return null

if (lt && !semver.satisfies(eq, String(lt))) return null

for (const c of dom) {
if (!semver.satisfies(eq, String(c))) return false
}

return true
}

let higher, lower
let hasDomLT, hasDomGT
// if the subset has a prerelease, we need a comparator in the superset
// with the same tuple and a prerelease, or it's not a subset
let needDomLTPre = lt && lt.semver.prerelease.length ? lt.semver : false
let needDomGTPre = gt && gt.semver.prerelease.length ? gt.semver : false
// exception: <1.2.3-0 is the same as <1.2.3
if (
needDomLTPre &&
needDomLTPre.prerelease.length === 1 &&
lt &&
lt.operator === '<' &&
needDomLTPre.prerelease[0] === 0
) {
needDomLTPre = false
}

for (const c of dom) {
hasDomGT = hasDomGT || c.operator === '>' || c.operator === '>='
hasDomLT = hasDomLT || c.operator === '<' || c.operator === '<='
if (gt) {
if (needDomGTPre) {
if (
c.semver.prerelease &&
c.semver.prerelease.length &&
c.semver.major === needDomGTPre.major &&
c.semver.minor === needDomGTPre.minor &&
c.semver.patch === needDomGTPre.patch
) {
needDomGTPre = false
}
}
if (c.operator === '>' || c.operator === '>=') {
higher = higherGT(gt, c)
if (higher === c && higher !== gt) return false
} else if (
gt.operator === '>=' &&
!semver.satisfies(gt.semver, String(c))
)
return false
}
if (lt) {
if (needDomLTPre) {
if (
c.semver.prerelease &&
c.semver.prerelease.length &&
c.semver.major === needDomLTPre.major &&
c.semver.minor === needDomLTPre.minor &&
c.semver.patch === needDomLTPre.patch
) {
needDomLTPre = false
}
}
if (c.operator === '<' || c.operator === '<=') {
lower = lowerLT(lt, c)
if (lower === c && lower !== lt) return false
} else if (
lt.operator === '<=' &&
!semver.satisfies(lt.semver, String(c))
)
return false
}
if (!c.operator && (lt || gt) && gtltComp !== 0) return false
}

// if there was a < or >, and nothing in the dom, then must be false
// UNLESS it was limited by another range in the other direction.
// Eg, >1.0.0 <1.0.1 is still a subset of <2.0.0
if (gt && hasDomLT && !lt && gtltComp !== 0) return false

if (lt && hasDomGT && !gt && gtltComp !== 0) return false

// we needed a prerelease range in a specific tuple, but didn't get one
// then this isn't a subset. eg >=1.2.3-pre is not a subset of >=1.0.0,
// because it includes prereleases in the 1.2.3 tuple
if (needDomGTPre || needDomLTPre) return false

return true
}

/**
* @license ISC at Isaac Z. Schlueter and Contributors
* https://github.com/npm/node-semver/blob/master/LICENSE
* @param {semver.Comparator | void} a
* @param {semver.Comparator} b
*/
const higherGT = (a, b) => {
if (!a) return b
const comp = semver.compare(a.semver, b.semver)
return comp > 0
? a
: comp < 0
? b
: b.operator === '>' && a.operator === '>='
? b
: a
}

/**
* @license ISC at Isaac Z. Schlueter and Contributors
* https://github.com/npm/node-semver/blob/master/LICENSE
* @param {semver.Comparator | void} a
* @param {semver.Comparator} b
*/
const lowerLT = (a, b) => {
if (!a) return b
const comp = semver.compare(a.semver, b.semver)
return comp < 0
? a
: comp > 0
? b
: b.operator === '<' && a.operator === '<='
? b
: a
}
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -55,7 +55,7 @@
"dependencies": {
"eslint-utils": "^2.1.0",
"natural-compare": "^1.4.0",
"semver": "^7.3.2",
"semver": "^6.3.0",
"vue-eslint-parser": "^7.8.0"
},
"devDependencies": {
Expand Down