Socket
Socket
Sign inDemoInstall

bcp-47-match

Package Overview
Dependencies
0
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.3 to 2.0.0

index.d.ts

269

index.js

@@ -1,132 +0,197 @@

'use strict'
/**
* See https://tools.ietf.org/html/rfc4647#section-3.1
* for more information on the algorithms.
*/
// See https://tools.ietf.org/html/rfc4647#section-3.1
// for more information on the algorithms.
/**
* @typedef {string} Tag
* @typedef {Array.<Tag>} Tags
* @typedef {string} Range
* @typedef {Array.<Range>} Ranges
* @typedef {function(Tag, Range): boolean} Check
* @typedef {function(Tag|Tags, Range|Ranges=): Tags} Filter
* @typedef {function(Tag|Tags, Range|Ranges=): Tag} Lookup
*/
exports.basicFilter = factory(basic, true)
exports.extendedFilter = factory(extended, true)
exports.lookup = factory(lookup)
/**
* Factory to perform a filter or a lookup.
* This factory creates a function that accepts a list of tags and a list of
* ranges, and contains logic to exit early for lookups.
* `check` just has to deal with one tag and one range.
* This match function iterates over ranges, and for each range,
* iterates over tags. That way, earlier ranges matching any tag have
* precedence over later ranges.
*
* @type {{
* (check: Check, filter: true): Filter
* (check: Check, filter?: false): Lookup
* }}
*/
// prettier-ignore
var factory = (
/**
* @param {Check} check
* @param {boolean} [filter=false]
*/
function (check, filter) {
return match
// Basic Filtering (Section 3.3.1) matches a language priority list consisting
// of basic language ranges (Section 2.1) to sets of language tags.
function basic(tag, range) {
return range === '*' || tag === range || tag.indexOf(range + '-') > -1
}
/**
* @param {Tag|Tags} tags
* @param {Range|Ranges} [ranges='*']
* @returns {Tag|Tags}
*/
function match(tags, ranges) {
var left = cast(tags, 'tag')
var right = cast(
ranges === null || ranges === undefined ? '*' : ranges,
'range'
)
/** @type {Tags} */
var matches = []
var rightIndex = -1
/** @type {Range} */
var range
/** @type {number} */
var leftIndex
/** @type {Tags} */
var next
// Extended Filtering (Section 3.3.2) matches a language priority list
// consisting of extended language ranges (Section 2.2) to sets of language
// tags.
function extended(tag, range) {
// 3.3.2.1
var left = tag.split('-')
var right = range.split('-')
var leftIndex = 0
var rightIndex = 0
while (++rightIndex < right.length) {
range = right[rightIndex].toLowerCase()
// 3.3.2.2
if (right[rightIndex] !== '*' && left[leftIndex] !== right[rightIndex]) {
return false
}
// Ignore wildcards in lookup mode.
if (!filter && range === '*') continue
leftIndex++
rightIndex++
leftIndex = -1
next = []
// 3.3.2.3
while (rightIndex < right.length) {
// 3.3.2.3.A
if (right[rightIndex] === '*') {
rightIndex++
continue
}
while (++leftIndex < left.length) {
if (check(left[leftIndex].toLowerCase(), range)) {
// Exit if this is a lookup and we have a match.
if (!filter) return left[leftIndex]
matches.push(left[leftIndex])
} else {
next.push(left[leftIndex])
}
}
// 3.3.2.3.B
if (!left[leftIndex]) return false
left = next
}
// 3.3.2.3.C
if (left[leftIndex] === right[rightIndex]) {
leftIndex++
rightIndex++
continue
// If this is a filter, return the list. If it’s a lookup, we didn’t find
// a match, so return `undefined`.
return filter ? matches : undefined
}
}
)
// 3.3.2.3.D
if (left[leftIndex].length === 1) return false
/**
* Basic Filtering (Section 3.3.1) matches a language priority list consisting
* of basic language ranges (Section 2.1) to sets of language tags.
* @param {Tag|Tags} tags
* @param {Range|Ranges} [ranges]
* @returns {Tags}
*/
export var basicFilter = factory(
/** @type {Check} */
function (tag, range) {
return range === '*' || tag === range || tag.includes(range + '-')
},
true
)
// 3.3.2.3.E
leftIndex++
}
/**
* Extended Filtering (Section 3.3.2) matches a language priority list
* consisting of extended language ranges (Section 2.2) to sets of language
* tags.
* @param {Tag|Tags} tags
* @param {Range|Ranges} [ranges]
* @returns {Tags}
*/
export var extendedFilter = factory(
/** @type {Check} */
function (tag, range) {
// 3.3.2.1
var left = tag.split('-')
var right = range.split('-')
var leftIndex = 0
var rightIndex = 0
// 3.3.2.4
return true
}
// 3.3.2.2
if (right[rightIndex] !== '*' && left[leftIndex] !== right[rightIndex]) {
return false
}
// Lookup (Section 3.4) matches a language priority list consisting of basic
// language ranges to sets of language tags to find the one exact language tag
// that best matches the range.
function lookup(tag, range) {
var right = range
var index
leftIndex++
rightIndex++
/* eslint-disable-next-line no-constant-condition */
while (true) {
if (right === '*' || tag === right) return true
// 3.3.2.3
while (rightIndex < right.length) {
// 3.3.2.3.A
if (right[rightIndex] === '*') {
rightIndex++
continue
}
index = right.lastIndexOf('-')
// 3.3.2.3.B
if (!left[leftIndex]) return false
if (index < 0) return false
// 3.3.2.3.C
if (left[leftIndex] === right[rightIndex]) {
leftIndex++
rightIndex++
continue
}
if (right.charAt(index - 2) === '-') index -= 2
// 3.3.2.3.D
if (left[leftIndex].length === 1) return false
right = right.slice(0, index)
}
}
// 3.3.2.3.E
leftIndex++
}
// Factory to perform a filter or a lookup.
// This factory creates a function that accepts a list of tags and a list of
// ranges, and contains logic to exit early for lookups.
// `check` just has to deal with one tag and one range.
// This match function iterates over ranges, and for each range,
// iterates over tags. That way, earlier ranges matching any tag have
// precedence over later ranges.
function factory(check, filter) {
return match
// 3.3.2.4
return true
},
true
)
function match(tags, ranges) {
var left = cast(tags, 'tag')
var right = cast(ranges == null ? '*' : ranges, 'range')
var matches = []
var rightIndex = -1
var range
var leftIndex
var next
/**
* Lookup (Section 3.4) matches a language priority list consisting of basic
* language ranges to sets of language tags to find the one exact language tag
* that best matches the range.
* @param {Tag|Tags} tags
* @param {Range|Ranges} [ranges]
* @returns {Tag}
*/
export var lookup = factory(
/** @type {Check} */
function (tag, range) {
var right = range
/** @type {number} */
var index
while (++rightIndex < right.length) {
range = right[rightIndex].toLowerCase()
/* eslint-disable-next-line no-constant-condition */
while (true) {
if (right === '*' || tag === right) return true
// Ignore wildcards in lookup mode.
if (!filter && range === '*') continue
index = right.lastIndexOf('-')
leftIndex = -1
next = []
if (index < 0) return false
while (++leftIndex < left.length) {
if (check(left[leftIndex].toLowerCase(), range)) {
// Exit if this is a lookup and we have a match.
if (!filter) return left[leftIndex]
matches.push(left[leftIndex])
} else {
next.push(left[leftIndex])
}
}
if (right.charAt(index - 2) === '-') index -= 2
left = next
right = right.slice(0, index)
}
// If this is a filter, return the list. If it’s a lookup, we didn’t find
// a match, so return `undefined`.
return filter ? matches : undefined
}
}
)
// Validate tags or ranges, and cast them to arrays.
/**
* Validate tags or ranges, and cast them to arrays.
*
* @param {string|Array.<string>} values
* @param {string} name
* @returns {Array.<string>}
*/
function cast(values, name) {

@@ -133,0 +198,0 @@ var value = values && typeof values === 'string' ? [values] : values

{
"name": "bcp-47-match",
"version": "1.0.3",
"version": "2.0.0",
"description": "Match BCP 47 language tags with language ranges per RFC 4647",

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

"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
},
"type": "github",
"url": "https://github.com/sponsors/wooorm"
},
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",

@@ -30,25 +30,30 @@ "contributors": [

],
"sideEffects": false,
"type": "module",
"main": "index.js",
"types": "index.d.ts",
"files": [
"index.d.ts",
"index.js"
],
"dependencies": {},
"devDependencies": {
"browserify": "^17.0.0",
"@types/tape": "^4.0.0",
"c8": "^7.0.0",
"chalk": "^4.0.0",
"nyc": "^15.0.0",
"prettier": "^2.0.0",
"remark-cli": "^9.0.0",
"remark-preset-wooorm": "^8.0.0",
"rimraf": "^3.0.0",
"tape": "^5.0.0",
"tinyify": "^3.0.0",
"xo": "^0.34.0"
"type-coverage": "^2.0.0",
"typescript": "^4.0.0",
"xo": "^0.38.0"
},
"scripts": {
"prepack": "npm run build && npm run format",
"build": "rimraf \"*.d.ts\" && tsc && type-coverage",
"format": "remark . -qfo && prettier . -w --loglevel warn && xo --fix",
"build-bundle": "browserify index.js -s bcp47Match -o bcp-47-match.js",
"build-mangle": "browserify index.js -s bcp47Match -p tinyify -o bcp-47-match.min.js",
"build": "npm run build-bundle && npm run build-mangle",
"test-api": "node test",
"test-coverage": "nyc --reporter lcov tape test.js",
"test": "npm run format && npm run build && npm run test-coverage"
"test-api": "node test.js",
"test-coverage": "c8 --check-coverage --branches 100 --functions 100 --lines 100 --statements 100 --reporter lcov node test.js",
"test": "npm run build && npm run format && npm run test-coverage"
},

@@ -65,21 +70,8 @@ "prettier": {

"prettier": true,
"esnext": false,
"rules": {
"eqeqeq": [
"error",
"always",
{
"null": "ignore"
}
],
"no-eq-null": "off",
"unicorn/prefer-includes": "off"
"import/no-mutable-exports": "off",
"no-var": "off",
"prefer-arrow-callback": "off"
}
},
"nyc": {
"check-coverage": true,
"lines": 100,
"functions": 100,
"branches": 100
},
"remarkConfig": {

@@ -99,3 +91,8 @@ "plugins": [

]
},
"typeCoverage": {
"atLeast": 100,
"detail": true,
"strict": true
}
}

@@ -21,5 +21,5 @@ <!--lint disable no-html-->

* [API](#api)
* [`match.basicFilter(tags[, ranges])`](#matchbasicfiltertags-ranges)
* [`match.extendedFilter(tags[, ranges])`](#matchextendedfiltertags-ranges)
* [`match.lookup(tags, ranges)`](#matchlookuptags-ranges)
* [`basicFilter(tags[, ranges='*'])`](#basicfiltertags-ranges)
* [`extendedFilter(tags[, ranges='*'])`](#extendedfiltertags-ranges)
* [`lookup(tags, ranges)`](#lookuptags-ranges)
* [Related](#related)

@@ -30,2 +30,5 @@ * [License](#license)

This package is ESM only: Node 12+ is needed to use it and it must be `import`ed
instead of `require`d.
[npm][]:

@@ -40,22 +43,18 @@

```js
var match = require('bcp-47-match')
import {basicFilter, extendedFilter, lookup} from 'bcp-47-match'
var basic = match.basicFilter
var extended = match.extendedFilter
var lookup = match.lookup
var tags = ['en-GB', 'de-CH', 'en', 'de']
console.log(basic(tags, '*')) // => [ 'en-GB', 'de-CH', 'en', 'de' ]
console.log(basic(tags, 'en')) // => [ 'en-GB', 'en' ]
console.log(basic(tags, 'en-GB')) // => [ 'en-GB' ]
console.log(basic(tags, ['en-GB', 'en'])) // => [ 'en-GB', 'en' ]
console.log(basic(tags, 'jp')) // => []
console.log(basicFilter(tags, '*')) // => [ 'en-GB', 'de-CH', 'en', 'de' ]
console.log(basicFilter(tags, 'en')) // => [ 'en-GB', 'en' ]
console.log(basicFilter(tags, 'en-GB')) // => [ 'en-GB' ]
console.log(basicFilter(tags, ['en-GB', 'en'])) // => [ 'en-GB', 'en' ]
console.log(basicFilter(tags, 'jp')) // => []
console.log(extended(tags, '*')) // => [ 'en-GB', 'de-CH', 'en', 'de' ]
console.log(extended(tags, 'en')) // => [ 'en-GB', 'en' ]
console.log(extended(tags, 'en-GB')) // => [ 'en-GB' ]
console.log(extended(tags, '*-GB')) // => [ 'en-GB' ]
console.log(extended(tags, ['en-GB', 'en'])) // => [ 'en-GB', 'en' ]
console.log(extended(tags, 'jp')) // => []
console.log(extendedFilter(tags, '*')) // => [ 'en-GB', 'de-CH', 'en', 'de' ]
console.log(extendedFilter(tags, 'en')) // => [ 'en-GB', 'en' ]
console.log(extendedFilter(tags, 'en-GB')) // => [ 'en-GB' ]
console.log(extendedFilter(tags, '*-GB')) // => [ 'en-GB' ]
console.log(extendedFilter(tags, ['en-GB', 'en'])) // => [ 'en-GB', 'en' ]
console.log(extendedFilter(tags, 'jp')) // => []

@@ -71,4 +70,8 @@ console.log(lookup(tags, 'en')) // => 'en'

### `match.basicFilter(tags[, ranges])`
This package exports the following identifiers: `basicFilter`, `extendedFilter`,
`lookup`.
There is no default export.
### `basicFilter(tags[, ranges='*'])`
> [See Basic Filtering spec](https://tools.ietf.org/html/rfc4647#section-3.3.1)

@@ -117,3 +120,3 @@

### `match.extendedFilter(tags[, ranges])`
### `extendedFilter(tags[, ranges='*'])`

@@ -162,3 +165,3 @@ > [See Extended Filtering spec](https://tools.ietf.org/html/rfc4647#section-3.3.2)

### `match.lookup(tags, ranges)`
### `lookup(tags, ranges)`

@@ -229,5 +232,5 @@ > [See Lookup spec](https://tools.ietf.org/html/rfc4647#section-3.4)

[build-badge]: https://img.shields.io/travis/wooorm/bcp-47-match.svg
[build-badge]: https://github.com/wooorm/bcp-47-match/workflows/main/badge.svg
[build]: https://travis-ci.org/wooorm/bcp-47-match
[build]: https://github.com/wooorm/bcp-47-match/actions

@@ -234,0 +237,0 @@ [coverage-badge]: https://img.shields.io/codecov/c/github/wooorm/bcp-47-match.svg

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