Skip to content

Instantly share code, notes, and snippets.

@dead-claudia
Last active April 29, 2016 19:17
Show Gist options
  • Save dead-claudia/0d53b10f7525e11620b8eb5dcebca0fa to your computer and use it in GitHub Desktop.
Save dead-claudia/0d53b10f7525e11620b8eb5dcebca0fa to your computer and use it in GitHub Desktop.
Path list to tree for easy lookup.
// Add and check that a path exists in a tree.
//
// Notes:
// 1. The comparison algorithms assume the paths are already resolved.
// 2. `matchEnd` is a sentinel to mark a leaf end of the cache tree.
// 3. Windows drive letters are intentionally included in the cache.
const path = require("path")
const hasOwn = Object.prototype.hasOwnProperty
// The cache also intentionally includes Windows drive letters.
const cache = {}
const matchEnd = {}
function getStart(dir) {
let start = 0
let ch = dir.charCodeAt(0)
// Ignore preceding slashes when getting the path start.
while (start !== dir.length && ch === 92/*\*/ || ch === 47/*/*/) {
ch = dir.charCodeAt(++start)
}
return start
}
exports.addPath = function (dir) {
// Ignore preceding slashes. Also, `last` always points to the last
// potential path start.
let last = getStart(dir)
let node = cache
for (let i = last; i < dir.length; i++) {
const code = dir.charCodeAt(i)
if (code === 92/*\*/ || code === 47/*/*/) {
const entry = dir.slice(last, i)
if (node === matchEnd) {
node = node[entry] = {}
} else if (!hasOwn.call(node, entry)) {
node = node[entry] = matchEnd
} else {
node = node[entry]
}
last = i + 1
}
}
// If we didn't stop at the end, we still have one last known file to add.
if (last - 1 !== dir.length) {
const entry = dir.slice(last - 1)
if (!hasOwn.call(node, entry)) {
node[entry] = matchEnd
}
}
}
exports.hasPath = function (file) {
let node = cache
let last = getStart(dir)
for (let i = 0; i < dir.length; i++) {
const code = dir.charCodeAt(i)
if (code === 92/*\*/ || code === 47/*/*/) {
if (node === matchEnd) {
return true
}
const entry = dir.slice(last, i + 1)
if (!hasOwn.call(node, entry)) {
return false
}
node = node[entry]
last = i + 1
}
}
// If there's a trailing slash or we've reached the end, it's okay.
return last - 1 === dir.length ||
// If the last part is exact, it's okay (i.e. the directory is cached)
node === matchEnd ||
// Check the last part.
hasOwn.call(node, dir.slice(start, last))
}
// Add and check that a path exists in a tree.
//
// Notes:
// 1. The comparison algorithms assume the paths are already resolved.
// 2. `matchEnd` is a sentinel to mark a leaf end of the cache tree.
// 3. Windows drive letters are intentionally included in the cache.
const path = require("path")
const hasOwn = Object.prototype.hasOwnProperty
// The cache also intentionally includes Windows drive letters.
const cache = {}
const matchEnd = {}
const splitPath = dir => dir.replace(/^[\\\/]+/, "").split(/[\\\/]+/)
exports.addPath = function (dir) {
let parts = splitPath(dir)
let node = cache
for (const entry of parts) {
if (node === matchEnd) {
node = node[entry] = {}
} else if (!hasOwn.call(node, entry)) {
node = node[entry] = matchEnd
} else {
node = node[entry]
}
}
}
exports.hasPath = function (file) {
let node = cache
for (const entry of splitPath(dir)) {
if (node === matchEnd) {
return true
} else if (!hasOwn.call(node, entry)) {
return false
} else {
node = node[entry]
}
}
return node === matchEnd
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment