First commit

This commit is contained in:
2026-01-12 13:12:46 +01:00
parent b2d9501f6d
commit a1fbd8acf5
4413 changed files with 1245183 additions and 0 deletions

170
node_modules/find-my-way/lib/constrainer.js generated vendored Normal file
View File

@@ -0,0 +1,170 @@
'use strict'
const acceptVersionStrategy = require('./strategies/accept-version')
const acceptHostStrategy = require('./strategies/accept-host')
const assert = require('node:assert')
class Constrainer {
constructor (customStrategies) {
this.strategies = {
version: acceptVersionStrategy,
host: acceptHostStrategy
}
this.strategiesInUse = new Set()
this.asyncStrategiesInUse = new Set()
// validate and optimize prototypes of given custom strategies
if (customStrategies) {
for (const strategy of Object.values(customStrategies)) {
this.addConstraintStrategy(strategy)
}
}
}
isStrategyUsed (strategyName) {
return this.strategiesInUse.has(strategyName) ||
this.asyncStrategiesInUse.has(strategyName)
}
hasConstraintStrategy (strategyName) {
const customConstraintStrategy = this.strategies[strategyName]
if (customConstraintStrategy !== undefined) {
return customConstraintStrategy.isCustom ||
this.isStrategyUsed(strategyName)
}
return false
}
addConstraintStrategy (strategy) {
assert(typeof strategy.name === 'string' && strategy.name !== '', 'strategy.name is required.')
assert(strategy.storage && typeof strategy.storage === 'function', 'strategy.storage function is required.')
assert(strategy.deriveConstraint && typeof strategy.deriveConstraint === 'function', 'strategy.deriveConstraint function is required.')
if (this.strategies[strategy.name] && this.strategies[strategy.name].isCustom) {
throw new Error(`There already exists a custom constraint with the name ${strategy.name}.`)
}
if (this.isStrategyUsed(strategy.name)) {
throw new Error(`There already exists a route with ${strategy.name} constraint.`)
}
strategy.isCustom = true
strategy.isAsync = strategy.deriveConstraint.length === 3
this.strategies[strategy.name] = strategy
if (strategy.mustMatchWhenDerived) {
this.noteUsage({ [strategy.name]: strategy })
}
}
deriveConstraints (req, ctx, done) {
const constraints = this.deriveSyncConstraints(req, ctx)
if (done === undefined) {
return constraints
}
this.deriveAsyncConstraints(constraints, req, ctx, done)
}
deriveSyncConstraints (req, ctx) {
return undefined
}
// When new constraints start getting used, we need to rebuild the deriver to derive them. Do so if we see novel constraints used.
noteUsage (constraints) {
if (constraints) {
const beforeSize = this.strategiesInUse.size
for (const key in constraints) {
const strategy = this.strategies[key]
if (strategy.isAsync) {
this.asyncStrategiesInUse.add(key)
} else {
this.strategiesInUse.add(key)
}
}
if (beforeSize !== this.strategiesInUse.size) {
this._buildDeriveConstraints()
}
}
}
newStoreForConstraint (constraint) {
if (!this.strategies[constraint]) {
throw new Error(`No strategy registered for constraint key ${constraint}`)
}
return this.strategies[constraint].storage()
}
validateConstraints (constraints) {
for (const key in constraints) {
const value = constraints[key]
if (typeof value === 'undefined') {
throw new Error('Can\'t pass an undefined constraint value, must pass null or no key at all')
}
const strategy = this.strategies[key]
if (!strategy) {
throw new Error(`No strategy registered for constraint key ${key}`)
}
if (strategy.validate) {
strategy.validate(value)
}
}
}
deriveAsyncConstraints (constraints, req, ctx, done) {
let asyncConstraintsCount = this.asyncStrategiesInUse.size
if (asyncConstraintsCount === 0) {
done(null, constraints)
return
}
constraints = constraints || {}
for (const key of this.asyncStrategiesInUse) {
const strategy = this.strategies[key]
strategy.deriveConstraint(req, ctx, (err, constraintValue) => {
if (err !== null) {
done(err)
return
}
constraints[key] = constraintValue
if (--asyncConstraintsCount === 0) {
done(null, constraints)
}
})
}
}
// Optimization: build a fast function for deriving the constraints for all the strategies at once. We inline the definitions of the version constraint and the host constraint for performance.
// If no constraining strategies are in use (no routes constrain on host, or version, or any custom strategies) then we don't need to derive constraints for each route match, so don't do anything special, and just return undefined
// This allows us to not allocate an object to hold constraint values if no constraints are defined.
_buildDeriveConstraints () {
if (this.strategiesInUse.size === 0) return
const lines = ['return {']
for (const key of this.strategiesInUse) {
const strategy = this.strategies[key]
// Optimization: inline the derivation for the common built in constraints
if (!strategy.isCustom) {
if (key === 'version') {
lines.push(' version: req.headers[\'accept-version\'],')
} else {
lines.push(' host: req.headers.host || req.headers[\':authority\'],')
}
} else {
lines.push(` ${strategy.name}: this.strategies.${key}.deriveConstraint(req, ctx),`)
}
}
lines.push('}')
this.deriveSyncConstraints = new Function('req', 'ctx', lines.join('\n')).bind(this) // eslint-disable-line
}
}
module.exports = Constrainer

164
node_modules/find-my-way/lib/handler-storage.js generated vendored Normal file
View File

@@ -0,0 +1,164 @@
'use strict'
const httpMethodStrategy = require('./strategies/http-method')
class HandlerStorage {
constructor () {
this.unconstrainedHandler = null // optimized reference to the handler that will match most of the time
this.constraints = []
this.handlers = [] // unoptimized list of handler objects for which the fast matcher function will be compiled
this.constrainedHandlerStores = null
}
// This is the hot path for node handler finding -- change with care!
getMatchingHandler (derivedConstraints) {
if (derivedConstraints === undefined) {
return this.unconstrainedHandler
}
return this._getHandlerMatchingConstraints(derivedConstraints)
}
addHandler (constrainer, route) {
const params = route.params
const constraints = route.opts.constraints || {}
const handlerObject = {
params,
constraints,
handler: route.handler,
store: route.store || null,
_createParamsObject: this._compileCreateParamsObject(params)
}
const constraintsNames = Object.keys(constraints)
if (constraintsNames.length === 0) {
this.unconstrainedHandler = handlerObject
}
for (const constraint of constraintsNames) {
if (!this.constraints.includes(constraint)) {
if (constraint === 'version') {
// always check the version constraint first as it is the most selective
this.constraints.unshift(constraint)
} else {
this.constraints.push(constraint)
}
}
}
const isMergedTree = constraintsNames.includes(httpMethodStrategy.name)
if (!isMergedTree && this.handlers.length >= 31) {
throw new Error('find-my-way supports a maximum of 31 route handlers per node when there are constraints, limit reached')
}
this.handlers.push(handlerObject)
// Sort the most constrained handlers to the front of the list of handlers so they are tested first.
this.handlers.sort((a, b) => Object.keys(a.constraints).length - Object.keys(b.constraints).length)
if (!isMergedTree) {
this._compileGetHandlerMatchingConstraints(constrainer, constraints)
}
}
_compileCreateParamsObject (params) {
const lines = []
for (let i = 0; i < params.length; i++) {
lines.push(`'${params[i]}': paramsArray[${i}]`)
}
return new Function('paramsArray', `return {${lines.join(',')}}`) // eslint-disable-line
}
_getHandlerMatchingConstraints () {
return null
}
// Builds a store object that maps from constraint values to a bitmap of handler indexes which pass the constraint for a value
// So for a host constraint, this might look like { "fastify.io": 0b0010, "google.ca": 0b0101 }, meaning the 3rd handler is constrainted to fastify.io, and the 2nd and 4th handlers are constrained to google.ca.
// The store's implementation comes from the strategies provided to the Router.
_buildConstraintStore (store, constraint) {
for (let i = 0; i < this.handlers.length; i++) {
const handler = this.handlers[i]
const constraintValue = handler.constraints[constraint]
if (constraintValue !== undefined) {
let indexes = store.get(constraintValue) || 0
indexes |= 1 << i // set the i-th bit for the mask because this handler is constrained by this value https://stackoverflow.com/questions/1436438/how-do-you-set-clear-and-toggle-a-single-bit-in-javascrip
store.set(constraintValue, indexes)
}
}
}
// Builds a bitmask for a given constraint that has a bit for each handler index that is 0 when that handler *is* constrained and 1 when the handler *isnt* constrainted. This is opposite to what might be obvious, but is just for convienience when doing the bitwise operations.
_constrainedIndexBitmask (constraint) {
let mask = 0
for (let i = 0; i < this.handlers.length; i++) {
const handler = this.handlers[i]
const constraintValue = handler.constraints[constraint]
if (constraintValue !== undefined) {
mask |= 1 << i
}
}
return ~mask
}
// Compile a fast function to match the handlers for this node
// The function implements a general case multi-constraint matching algorithm.
// The general idea is this: we have a bunch of handlers, each with a potentially different set of constraints, and sometimes none at all. We're given a list of constraint values and we have to use the constraint-value-comparison strategies to see which handlers match the constraint values passed in.
// We do this by asking each constraint store which handler indexes match the given constraint value for each store. Trickily, the handlers that a store says match are the handlers constrained by that store, but handlers that aren't constrained at all by that store could still match just fine. So, each constraint store can only describe matches for it, and it won't have any bearing on the handlers it doesn't care about. For this reason, we have to ask each stores which handlers match and track which have been matched (or not cared about) by all of them.
// We use bitmaps to represent these lists of matches so we can use bitwise operations to implement this efficiently. Bitmaps are cheap to allocate, let us implement this masking behaviour in one CPU instruction, and are quite compact in memory. We start with a bitmap set to all 1s representing every handler that is a match candidate, and then for each constraint, see which handlers match using the store, and then mask the result by the mask of handlers that that store applies to, and bitwise AND with the candidate list. Phew.
// We consider all this compiling function complexity to be worth it, because the naive implementation that just loops over the handlers asking which stores match is quite a bit slower.
_compileGetHandlerMatchingConstraints (constrainer) {
this.constrainedHandlerStores = {}
for (const constraint of this.constraints) {
const store = constrainer.newStoreForConstraint(constraint)
this.constrainedHandlerStores[constraint] = store
this._buildConstraintStore(store, constraint)
}
const lines = []
lines.push(`
let candidates = ${(1 << this.handlers.length) - 1}
let mask, matches
`)
for (const constraint of this.constraints) {
// Setup the mask for indexes this constraint applies to. The mask bits are set to 1 for each position if the constraint applies.
lines.push(`
mask = ${this._constrainedIndexBitmask(constraint)}
value = derivedConstraints.${constraint}
`)
// If there's no constraint value, none of the handlers constrained by this constraint can match. Remove them from the candidates.
// If there is a constraint value, get the matching indexes bitmap from the store, and mask it down to only the indexes this constraint applies to, and then bitwise and with the candidates list to leave only matching candidates left.
const strategy = constrainer.strategies[constraint]
const matchMask = strategy.mustMatchWhenDerived ? 'matches' : '(matches | mask)'
lines.push(`
if (value === undefined) {
candidates &= mask
} else {
matches = this.constrainedHandlerStores.${constraint}.get(value) || 0
candidates &= ${matchMask}
}
if (candidates === 0) return null;
`)
}
// There are some constraints that can be derived and marked as "must match", where if they are derived, they only match routes that actually have a constraint on the value, like the SemVer version constraint.
// An example: a request comes in for version 1.x, and this node has a handler that matches the path, but there's no version constraint. For SemVer, the find-my-way semantics do not match this handler to that request.
// This function is used by Nodes with handlers to match when they don't have any constrained routes to exclude request that do have must match derived constraints present.
for (const constraint in constrainer.strategies) {
const strategy = constrainer.strategies[constraint]
if (strategy.mustMatchWhenDerived && !this.constraints.includes(constraint)) {
lines.push(`if (derivedConstraints.${constraint} !== undefined) return null`)
}
}
// Return the first handler who's bit is set in the candidates https://stackoverflow.com/questions/18134985/how-to-find-index-of-first-set-bit
lines.push('return this.handlers[Math.floor(Math.log2(candidates))]')
this._getHandlerMatchingConstraints = new Function('derivedConstraints', lines.join('\n')) // eslint-disable-line
}
}
module.exports = HandlerStorage

13
node_modules/find-my-way/lib/http-methods.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
'use strict'
// defined by Node.js http module, a snapshot from Node.js 18.12.0
const httpMethods = [
'ACL', 'BIND', 'CHECKOUT', 'CONNECT', 'COPY', 'DELETE',
'GET', 'HEAD', 'LINK', 'LOCK', 'M-SEARCH', 'MERGE',
'MKACTIVITY', 'MKCALENDAR', 'MKCOL', 'MOVE', 'NOTIFY', 'OPTIONS',
'PATCH', 'POST', 'PROPFIND', 'PROPPATCH', 'PURGE', 'PUT',
'REBIND', 'REPORT', 'SEARCH', 'SOURCE', 'SUBSCRIBE', 'TRACE',
'UNBIND', 'UNLINK', 'UNLOCK', 'UNSUBSCRIBE'
]
module.exports = httpMethods

228
node_modules/find-my-way/lib/node.js generated vendored Normal file
View File

@@ -0,0 +1,228 @@
'use strict'
const HandlerStorage = require('./handler-storage')
const NODE_TYPES = {
STATIC: 0,
PARAMETRIC: 1,
WILDCARD: 2
}
class Node {
constructor () {
this.isLeafNode = false
this.routes = null
this.handlerStorage = null
}
addRoute (route, constrainer) {
if (this.routes === null) {
this.routes = []
}
if (this.handlerStorage === null) {
this.handlerStorage = new HandlerStorage()
}
this.isLeafNode = true
this.routes.push(route)
this.handlerStorage.addHandler(constrainer, route)
}
}
class ParentNode extends Node {
constructor () {
super()
this.staticChildren = {}
}
findStaticMatchingChild (path, pathIndex) {
const staticChild = this.staticChildren[path.charAt(pathIndex)]
if (staticChild === undefined || !staticChild.matchPrefix(path, pathIndex)) {
return null
}
return staticChild
}
getStaticChild (path, pathIndex = 0) {
if (path.length === pathIndex) {
return this
}
const staticChild = this.findStaticMatchingChild(path, pathIndex)
if (staticChild) {
return staticChild.getStaticChild(path, pathIndex + staticChild.prefix.length)
}
return null
}
createStaticChild (path) {
if (path.length === 0) {
return this
}
let staticChild = this.staticChildren[path.charAt(0)]
if (staticChild) {
let i = 1
for (; i < staticChild.prefix.length; i++) {
if (path.charCodeAt(i) !== staticChild.prefix.charCodeAt(i)) {
staticChild = staticChild.split(this, i)
break
}
}
return staticChild.createStaticChild(path.slice(i))
}
const label = path.charAt(0)
this.staticChildren[label] = new StaticNode(path)
return this.staticChildren[label]
}
}
class StaticNode extends ParentNode {
constructor (prefix) {
super()
this.prefix = prefix
this.wildcardChild = null
this.parametricChildren = []
this.kind = NODE_TYPES.STATIC
this._compilePrefixMatch()
}
getParametricChild (regex) {
const regexpSource = regex && regex.source
const parametricChild = this.parametricChildren.find(child => {
const childRegexSource = child.regex && child.regex.source
return childRegexSource === regexpSource
})
if (parametricChild) {
return parametricChild
}
return null
}
createParametricChild (regex, staticSuffix, nodePath) {
let parametricChild = this.getParametricChild(regex)
if (parametricChild) {
parametricChild.nodePaths.add(nodePath)
return parametricChild
}
parametricChild = new ParametricNode(regex, staticSuffix, nodePath)
this.parametricChildren.push(parametricChild)
this.parametricChildren.sort((child1, child2) => {
if (!child1.isRegex) return 1
if (!child2.isRegex) return -1
if (child1.staticSuffix === null) return 1
if (child2.staticSuffix === null) return -1
if (child2.staticSuffix.endsWith(child1.staticSuffix)) return 1
if (child1.staticSuffix.endsWith(child2.staticSuffix)) return -1
return 0
})
return parametricChild
}
getWildcardChild () {
return this.wildcardChild
}
createWildcardChild () {
this.wildcardChild = this.getWildcardChild() || new WildcardNode()
return this.wildcardChild
}
split (parentNode, length) {
const parentPrefix = this.prefix.slice(0, length)
const childPrefix = this.prefix.slice(length)
this.prefix = childPrefix
this._compilePrefixMatch()
const staticNode = new StaticNode(parentPrefix)
staticNode.staticChildren[childPrefix.charAt(0)] = this
parentNode.staticChildren[parentPrefix.charAt(0)] = staticNode
return staticNode
}
getNextNode (path, pathIndex, nodeStack, paramsCount) {
let node = this.findStaticMatchingChild(path, pathIndex)
let parametricBrotherNodeIndex = 0
if (node === null) {
if (this.parametricChildren.length === 0) {
return this.wildcardChild
}
node = this.parametricChildren[0]
parametricBrotherNodeIndex = 1
}
if (this.wildcardChild !== null) {
nodeStack.push({
paramsCount,
brotherPathIndex: pathIndex,
brotherNode: this.wildcardChild
})
}
for (let i = this.parametricChildren.length - 1; i >= parametricBrotherNodeIndex; i--) {
nodeStack.push({
paramsCount,
brotherPathIndex: pathIndex,
brotherNode: this.parametricChildren[i]
})
}
return node
}
_compilePrefixMatch () {
if (this.prefix.length === 1) {
this.matchPrefix = () => true
return
}
const lines = []
for (let i = 1; i < this.prefix.length; i++) {
const charCode = this.prefix.charCodeAt(i)
lines.push(`path.charCodeAt(i + ${i}) === ${charCode}`)
}
this.matchPrefix = new Function('path', 'i', `return ${lines.join(' && ')}`) // eslint-disable-line
}
}
class ParametricNode extends ParentNode {
constructor (regex, staticSuffix, nodePath) {
super()
this.isRegex = !!regex
this.regex = regex || null
this.staticSuffix = staticSuffix || null
this.kind = NODE_TYPES.PARAMETRIC
this.nodePaths = new Set([nodePath])
}
getNextNode (path, pathIndex) {
return this.findStaticMatchingChild(path, pathIndex)
}
}
class WildcardNode extends Node {
constructor () {
super()
this.kind = NODE_TYPES.WILDCARD
}
getNextNode () {
return null
}
}
module.exports = { StaticNode, ParametricNode, WildcardNode, NODE_TYPES }

168
node_modules/find-my-way/lib/pretty-print.js generated vendored Normal file
View File

@@ -0,0 +1,168 @@
'use strict'
const deepEqual = require('fast-deep-equal')
const httpMethodStrategy = require('./strategies/http-method')
const treeDataSymbol = Symbol('treeData')
function printObjectTree (obj, parentPrefix = '') {
let tree = ''
const keys = Object.keys(obj)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const value = obj[key]
const isLast = i === keys.length - 1
const nodePrefix = isLast ? '└── ' : '├── '
const childPrefix = isLast ? ' ' : '│ '
const nodeData = value[treeDataSymbol] || ''
const prefixedNodeData = nodeData.split('\n').join('\n' + parentPrefix + childPrefix)
tree += parentPrefix + nodePrefix + key + prefixedNodeData + '\n'
tree += printObjectTree(value, parentPrefix + childPrefix)
}
return tree
}
function parseFunctionName (fn) {
let fName = fn.name || ''
fName = fName.replace('bound', '').trim()
fName = (fName || 'anonymous') + '()'
return fName
}
function parseMeta (meta) {
if (Array.isArray(meta)) return meta.map(m => parseMeta(m))
if (typeof meta === 'symbol') return meta.toString()
if (typeof meta === 'function') return parseFunctionName(meta)
return meta
}
function getRouteMetaData (route, options) {
if (!options.includeMeta) return {}
const metaDataObject = options.buildPrettyMeta(route)
const filteredMetaData = {}
let includeMetaKeys = options.includeMeta
if (!Array.isArray(includeMetaKeys)) {
includeMetaKeys = Reflect.ownKeys(metaDataObject)
}
for (const metaKey of includeMetaKeys) {
if (!Object.prototype.hasOwnProperty.call(metaDataObject, metaKey)) continue
const serializedKey = metaKey.toString()
const metaValue = metaDataObject[metaKey]
if (metaValue !== undefined && metaValue !== null) {
const serializedValue = JSON.stringify(parseMeta(metaValue))
filteredMetaData[serializedKey] = serializedValue
}
}
return filteredMetaData
}
function serializeMetaData (metaData) {
let serializedMetaData = ''
for (const [key, value] of Object.entries(metaData)) {
serializedMetaData += `\n• (${key}) ${value}`
}
return serializedMetaData
}
// get original merged tree node route
function normalizeRoute (route) {
const constraints = { ...route.opts.constraints }
const method = constraints[httpMethodStrategy.name]
delete constraints[httpMethodStrategy.name]
return { ...route, method, opts: { constraints } }
}
function serializeRoute (route) {
let serializedRoute = ` (${route.method})`
const constraints = route.opts.constraints || {}
if (Object.keys(constraints).length !== 0) {
serializedRoute += ' ' + JSON.stringify(constraints)
}
serializedRoute += serializeMetaData(route.metaData)
return serializedRoute
}
function mergeSimilarRoutes (routes) {
return routes.reduce((mergedRoutes, route) => {
for (const nodeRoute of mergedRoutes) {
if (
deepEqual(route.opts.constraints, nodeRoute.opts.constraints) &&
deepEqual(route.metaData, nodeRoute.metaData)
) {
nodeRoute.method += ', ' + route.method
return mergedRoutes
}
}
mergedRoutes.push(route)
return mergedRoutes
}, [])
}
function serializeNode (node, prefix, options) {
let routes = node.routes
if (options.method === undefined) {
routes = routes.map(normalizeRoute)
}
routes = routes.map(route => {
route.metaData = getRouteMetaData(route, options)
return route
})
if (options.method === undefined) {
routes = mergeSimilarRoutes(routes)
}
return routes.map(serializeRoute).join(`\n${prefix}`)
}
function buildObjectTree (node, tree, prefix, options) {
if (node.isLeafNode || options.commonPrefix !== false) {
prefix = prefix || '(empty root node)'
tree = tree[prefix] = {}
if (node.isLeafNode) {
tree[treeDataSymbol] = serializeNode(node, prefix, options)
}
prefix = ''
}
if (node.staticChildren) {
for (const child of Object.values(node.staticChildren)) {
buildObjectTree(child, tree, prefix + child.prefix, options)
}
}
if (node.parametricChildren) {
for (const child of Object.values(node.parametricChildren)) {
const childPrefix = Array.from(child.nodePaths).join('|')
buildObjectTree(child, tree, prefix + childPrefix, options)
}
}
if (node.wildcardChild) {
buildObjectTree(node.wildcardChild, tree, '*', options)
}
}
function prettyPrintTree (root, options) {
const objectTree = {}
buildObjectTree(root, objectTree, root.prefix, options)
return printObjectTree(objectTree)
}
module.exports = { prettyPrintTree }

36
node_modules/find-my-way/lib/strategies/accept-host.js generated vendored Normal file
View File

@@ -0,0 +1,36 @@
'use strict'
const assert = require('node:assert')
function HostStorage () {
const hosts = {}
const regexHosts = []
return {
get: (host) => {
const exact = hosts[host]
if (exact) {
return exact
}
for (const regex of regexHosts) {
if (regex.host.test(host)) {
return regex.value
}
}
},
set: (host, value) => {
if (host instanceof RegExp) {
regexHosts.push({ host, value })
} else {
hosts[host] = value
}
}
}
}
module.exports = {
name: 'host',
mustMatchWhenDerived: false,
storage: HostStorage,
validate (value) {
assert(typeof value === 'string' || Object.prototype.toString.call(value) === '[object RegExp]', 'Host should be a string or a RegExp')
}
}

View File

@@ -0,0 +1,65 @@
'use strict'
const assert = require('node:assert')
function SemVerStore () {
if (!(this instanceof SemVerStore)) {
return new SemVerStore()
}
this.store = {}
this.maxMajor = 0
this.maxMinors = {}
this.maxPatches = {}
}
SemVerStore.prototype.set = function (version, store) {
if (typeof version !== 'string') {
throw new TypeError('Version should be a string')
}
let [major, minor, patch] = version.split('.')
if (isNaN(major)) {
throw new TypeError('Major version must be a numeric value')
}
major = Number(major)
minor = Number(minor) || 0
patch = Number(patch) || 0
if (major >= this.maxMajor) {
this.maxMajor = major
this.store.x = store
this.store['*'] = store
this.store['x.x'] = store
this.store['x.x.x'] = store
}
if (minor >= (this.maxMinors[major] || 0)) {
this.maxMinors[major] = minor
this.store[`${major}.x`] = store
this.store[`${major}.x.x`] = store
}
if (patch >= (this.maxPatches[`${major}.${minor}`] || 0)) {
this.maxPatches[`${major}.${minor}`] = patch
this.store[`${major}.${minor}.x`] = store
}
this.store[`${major}.${minor}.${patch}`] = store
return this
}
SemVerStore.prototype.get = function (version) {
return this.store[version]
}
module.exports = {
name: 'version',
mustMatchWhenDerived: true,
storage: SemVerStore,
validate (value) {
assert(typeof value === 'string', 'Version should be a string')
}
}

14
node_modules/find-my-way/lib/strategies/http-method.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
'use strict'
module.exports = {
name: '__fmw_internal_strategy_merged_tree_http_method__',
storage: function () {
const handlers = {}
return {
get: (type) => { return handlers[type] || null },
set: (type, store) => { handlers[type] = store }
}
},
deriveConstraint: /* istanbul ignore next */ (req) => req.method,
mustMatchWhenDerived: true
}

96
node_modules/find-my-way/lib/url-sanitizer.js generated vendored Normal file
View File

@@ -0,0 +1,96 @@
'use strict'
// It must spot all the chars where decodeURIComponent(x) !== decodeURI(x)
// The chars are: # $ & + , / : ; = ? @
function decodeComponentChar (highCharCode, lowCharCode) {
if (highCharCode === 50) {
if (lowCharCode === 53) return '%'
if (lowCharCode === 51) return '#'
if (lowCharCode === 52) return '$'
if (lowCharCode === 54) return '&'
if (lowCharCode === 66) return '+'
if (lowCharCode === 98) return '+'
if (lowCharCode === 67) return ','
if (lowCharCode === 99) return ','
if (lowCharCode === 70) return '/'
if (lowCharCode === 102) return '/'
return null
}
if (highCharCode === 51) {
if (lowCharCode === 65) return ':'
if (lowCharCode === 97) return ':'
if (lowCharCode === 66) return ';'
if (lowCharCode === 98) return ';'
if (lowCharCode === 68) return '='
if (lowCharCode === 100) return '='
if (lowCharCode === 70) return '?'
if (lowCharCode === 102) return '?'
return null
}
if (highCharCode === 52 && lowCharCode === 48) {
return '@'
}
return null
}
function safeDecodeURI (path, useSemicolonDelimiter) {
let shouldDecode = false
let shouldDecodeParam = false
let querystring = ''
for (let i = 1; i < path.length; i++) {
const charCode = path.charCodeAt(i)
if (charCode === 37) {
const highCharCode = path.charCodeAt(i + 1)
const lowCharCode = path.charCodeAt(i + 2)
if (decodeComponentChar(highCharCode, lowCharCode) === null) {
shouldDecode = true
} else {
shouldDecodeParam = true
// %25 - encoded % char. We need to encode one more time to prevent double decoding
if (highCharCode === 50 && lowCharCode === 53) {
shouldDecode = true
path = path.slice(0, i + 1) + '25' + path.slice(i + 1)
i += 2
}
i += 2
}
// Some systems do not follow RFC and separate the path and query
// string with a `;` character (code 59), e.g. `/foo;jsessionid=123456`.
// Thus, we need to split on `;` as well as `?` and `#` if the useSemicolonDelimiter option is enabled.
} else if (charCode === 63 || charCode === 35 || (charCode === 59 && useSemicolonDelimiter)) {
querystring = path.slice(i + 1)
path = path.slice(0, i)
break
}
}
const decodedPath = shouldDecode ? decodeURI(path) : path
return { path: decodedPath, querystring, shouldDecodeParam }
}
function safeDecodeURIComponent (uriComponent) {
const startIndex = uriComponent.indexOf('%')
if (startIndex === -1) return uriComponent
let decoded = ''
let lastIndex = startIndex
for (let i = startIndex; i < uriComponent.length; i++) {
if (uriComponent.charCodeAt(i) === 37) {
const highCharCode = uriComponent.charCodeAt(i + 1)
const lowCharCode = uriComponent.charCodeAt(i + 2)
const decodedChar = decodeComponentChar(highCharCode, lowCharCode)
decoded += uriComponent.slice(lastIndex, i) + decodedChar
lastIndex = i + 3
}
}
return uriComponent.slice(0, startIndex) + decoded + uriComponent.slice(lastIndex)
}
module.exports = { safeDecodeURI, safeDecodeURIComponent }