Buckets:
| 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 } | |
Xet Storage Details
- Size:
- 5.58 kB
- Xet hash:
- 0281c31a61d32797a35d0c990ce740dcd5f551667f564181029e761e013f34e9
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.