Socket
Socket
Sign inDemoInstall

airtap-match-browsers

Package Overview
Dependencies
65
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.2 to 0.1.0

215

index.js

@@ -8,3 +8,6 @@ 'use strict'

const names = require('browser-names')
const defaults = { version: 'latest' }
const prerelease = /[^\d.]/
const numeric = /^\d+$/

@@ -24,3 +27,3 @@ module.exports = matchAll

for (const manifest of available) {
const name = lower(manifest.name)
const name = manifest.name

@@ -34,23 +37,22 @@ if (groups.has(name)) {

// Presort versions and add aliases
for (const [name, group] of groups) {
group.sort((a, b) => cmpVersion(a.version, b.version))
for (const w of wanted) {
const explicit = new Set()
for (const alias of names(name)) {
if (alias !== name) groups.set(alias, group)
// Match by name
let group = findName(groups, w.name) || []
// Lazily sort by version
if (!group.sorted) {
group.sort((a, b) => cmpVersion(a.version, b.version))
group.sorted = true
}
}
for (const w of wanted) {
const explicit = new Set()
// Match by other properties
const skip = ['name', 'version']
group = group.filter(m => match(m, w, explicit, skip))
// Match by name and version
let group = groups.get(w.name) || []
// Match by version
w.version = lower(w.version)
group = filterVersions(group, w.version)
// Match by properties other than name and version
const skip = ['name', 'version']
group = group.filter(m => match(m, w, explicit, skip))
if (group.length === 0) {

@@ -63,3 +65,3 @@ throw new Error('Zero matches for ' + JSON.stringify(w, null, 2))

const a = group[i]
const alternatives = [a]
let winner = a

@@ -70,3 +72,4 @@ for (let j = i + 1; j < group.length; j++) {

if (same(a, b, explicit)) {
alternatives.push(b)
// Last manifest wins (for no particular reason)
winner = b
group.splice(j--, 1)

@@ -76,25 +79,2 @@ }

// Pick winner by preferredOver rules (or short of that, the last manifest)
let winner = alternatives[alternatives.length - 1]
let max = 0
// TODO: optimize by merging logic into above loop
// TODO: find a simpler solution to deduplication overall
for (let x = 0; x < alternatives.length; x++) {
for (let y = x + 1; y < alternatives.length; y++) {
const weightX = preferredOver(alternatives[x], alternatives[y])
const weightY = preferredOver(alternatives[y], alternatives[x])
if (weightX > max) {
max = weightX
winner = alternatives[x]
}
if (weightY > max) {
max = weightY
winner = alternatives[y]
}
}
}
// Don't merge options into the manifest yet, so that we can

@@ -111,2 +91,14 @@ // perform fast deduplication by object identity (below). We

function findName (groups, name) {
if (groups.has(name)) {
return groups.get(name)
}
for (const alias of names(name)) {
if (alias !== name && groups.has(alias)) {
return groups.get(alias)
}
}
}
function consolidate (matches) {

@@ -150,3 +142,3 @@ for (let i = 0; i < matches.length; i++) {

if (typeof manifest.name !== 'string' || manifest.name === '') {
throw new TypeError('Browser "name" is required')
throw new TypeError('Manifest "name" is required')
}

@@ -171,24 +163,2 @@

function preferredOver (a, b) {
let weight = 0
if (a.preferredOver) {
for (const k of Object.keys(a.preferredOver)) {
const values = a.preferredOver[k].map(lower)
const value = deep(b, k)
if (value == null) {
continue
} else if (values.includes(lower(value))) {
// A specific value has more weight than "any"
weight += 1e3
} else if (values.includes('any')) {
weight += 1
}
}
}
return weight
}
function lower (value) {

@@ -202,4 +172,6 @@ return value != null ? String(value).toLowerCase() : ''

} else if (Array.isArray(wanted)) {
throw new Error('Array is not yet supported on ' + key)
// TODO: explode into multiple browsers, instead of this "oneof" behavior
return wanted.some(el => match(available, el, explicit, skip, key))
// return wanted.some(el => match(available, el, explicit, skip, key))
} else if (isObject(wanted)) {

@@ -212,3 +184,3 @@ if (!isObject(available)) return false

if (!hasOwnProperty.call(wanted, k)) continue
if (fqk === 'options' || fqk === 'preferredOver') continue
if (fqk === 'options') continue
if (!match(available[k], wanted[k], explicit, skip, fqk)) return false

@@ -247,45 +219,51 @@ }

function filterVersions (manifests, version) {
const [gte, lte] = range(version, manifests)
let start = 0
let end = manifests.length
if (gte) {
while (start < end && cmpVersion(manifests[start].version, gte) < 0) {
start++
}
if (!matchVersion(gte, manifests[start] && manifests[start].version)) {
throw new Error(`Version not found: ${gte}`)
}
if (manifests.length === 0) {
return manifests
}
if (lte) {
while (end > start && cmpVersion(manifests[end - 1].version, lte) > 0) {
end--
}
const test = range(version, manifests)
const result = []
if (!matchVersion(lte, manifests[end - 1] && manifests[end - 1].version)) {
throw new Error(`Version not found: ${lte}`)
for (const m of manifests) {
if (test(m.version)) {
result.push(m)
} else if (result.length) {
break
}
}
return manifests.slice(start, end)
return result
}
// Assumes manifests are sorted by version.
function range (version, manifests) {
const arr = version.split('..')
let gte
let lte
if (arr.length === 1) {
arr.push(arr[0])
if (version.indexOf('..') === -1) {
gte = lte = resolve(version || 'latest')
} else {
const arr = version.split('..')
gte = resolve(arr[0] || 'oldest')
lte = resolve(arr[1] || 'latest')
}
return arr.map(function (v) {
if (!manifests.length) return
return function test (v) {
const c1 = cmpRange(v, gte, false)
if (c1 < 0) return false
const c2 = cmpRange(v, lte, true)
if (c2 > 0) return false
return true
}
function resolve (v) {
if (v === 'oldest') return manifests[0].version
if (v === 'latest') return latest(manifests, 0)
if (!isNaN(v) && v < 0) return latest(manifests, v * -1)
if (/^-\d+$/.test(v) && v < 0) return latest(manifests, v * -1)
return v
})
}
}

@@ -295,3 +273,3 @@

for (let i = manifests.length - 1; i >= 0; i--) {
if (!isBeta(manifests[i].version) && !n--) {
if (!isPrerelease(manifests[i].version) && (!n-- || i === 0)) {
return manifests[i].version

@@ -301,28 +279,51 @@ }

return manifests[0].version
// All are prereleases, return the last
return manifests[manifests.length - 1].version
}
function isBeta (version) {
return version && isNaN(version)
function isPrerelease (version) {
return !version || prerelease.test(version)
}
function matchVersion (wanted, available) {
if (!available) return false
if (isBeta(available)) return available === wanted
return available.startsWith(wanted)
function cmpVersion (a, b) {
return cmpRange(a, b, false)
}
function cmpVersion (a, b) {
if (a == null) return b == null ? 0 : 1
if (b == null) return -1
function cmpRange (a, b, prefixOnly) {
// Missing version behaves like last prerelease
if (!a) return !b ? 0 : 1
if (!b) return -1
if (isNaN(a)) return isNaN(b) ? a.localeCompare(b) : 1
if (isNaN(b)) return -1
const ap = isPrerelease(a)
const bp = isPrerelease(b)
return Number(a) - Number(b)
if (ap !== bp) return ap ? 1 : -1
const av = a.split('.')
const bv = b.split('.')
for (let i = 0; i < Math.min(av.length, bv.length); i++) {
const cmp = cmpElement(av[i], bv[i])
if (cmp > 0) return 1
if (cmp < 0) return -1
}
if (prefixOnly || av.length === bv.length) {
return 0
} else {
return av.length > bv.length ? 1 : -1
}
}
function cmpElement (a, b) {
if (numeric.test(a) && numeric.test(b)) {
return a - b
} else {
return a.localeCompare(b)
}
}
function isObject (o) {
return typeof o === 'object' && o !== null && !Array.isArray(o)
}
{
"name": "airtap-match-browsers",
"version": "0.0.2",
"version": "0.1.0",
"description": "Match browser manifests to a desired set of browsers",

@@ -5,0 +5,0 @@ "license": "MIT",

# airtap-match-browsers
> **Match [browser manifests](https://github.com/airtap/browser-manifest) to a desired set of browsers.**
> Intended to replace [`sauce-browsers`](https://github.com/lpinca/sauce-browsers) in conjunction with [`airtap-sauce-browsers`](https://github.com/airtap/sauce-browsers).
> Replaces [`sauce-browsers`](https://github.com/lpinca/sauce-browsers) in conjunction with [`airtap-sauce-browsers`](https://github.com/airtap/sauce-browsers).

@@ -45,6 +45,6 @@ [![npm status](http://img.shields.io/npm/v/airtap-match-browsers.svg)](https://www.npmjs.org/package/airtap-match-browsers)

- A negative range in the form of `-<n>..latest`, for example `-1..latest` which means the last 2 numeric versions.
- A non-numeric version like "dev" and "beta". Such versions sort after numeric versions, so that `oldest..latest` excludes "dev" and `latest..dev` includes latest, "beta" and "dev".
- A prerelease version like "dev", "beta", "80.0a1". Such versions sort after numeric versions, so that `oldest..latest` excludes "dev" and `latest..dev` includes e.g. latest, "beta" and "dev".
- An array of versions.
If a version is not found (including the start and end of ranges) an error is thrown.
If a manifest doesn't have a `version`, it behaves like a prerelease.

@@ -51,0 +51,0 @@ ### `platform` and any other (nested) property

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc