1
0
Fork 0
toolkit/packages/glob/src/internal-path.ts

114 lines
2.9 KiB
TypeScript

import * as path from 'path'
import * as pathHelper from './internal-path-helper'
import assert from 'assert'
const IS_WINDOWS = process.platform === 'win32'
/**
* Helper class for parsing paths into segments
*/
export class Path {
segments: string[] = []
/**
* Constructs a Path
* @param itemPath Path or array of segments
*/
constructor(itemPath: string | string[]) {
// String
if (typeof itemPath === 'string') {
assert(itemPath, `Parameter 'itemPath' must not be empty`)
// Normalize slashes and trim unnecessary trailing slash
itemPath = pathHelper.safeTrimTrailingSeparator(itemPath)
// Not rooted
if (!pathHelper.hasRoot(itemPath)) {
this.segments = itemPath.split(path.sep)
}
// Rooted
else {
// Add all segments, while not at the root
let remaining = itemPath
let dir = pathHelper.dirname(remaining)
while (dir !== remaining) {
// Add the segment
const basename = path.basename(remaining)
this.segments.unshift(basename)
// Truncate the last segment
remaining = dir
dir = pathHelper.dirname(remaining)
}
// Remainder is the root
this.segments.unshift(remaining)
}
}
// Array
else {
// Must not be empty
assert(
itemPath.length > 0,
`Parameter 'itemPath' must not be an empty array`
)
// Each segment
for (let i = 0; i < itemPath.length; i++) {
let segment = itemPath[i]
// Must not be empty
assert(
segment,
`Parameter 'itemPath' must not contain any empty segments`
)
// Normalize slashes
segment = pathHelper.normalizeSeparators(itemPath[i])
// Root segment
if (i === 0 && pathHelper.hasRoot(segment)) {
segment = pathHelper.safeTrimTrailingSeparator(segment)
assert(
segment === pathHelper.dirname(segment),
`Parameter 'itemPath' root segment contains information for multiple segments`
)
this.segments.push(segment)
}
// All other segments
else {
// Must not contain slash
assert(
!segment.includes(path.sep),
`Parameter 'itemPath' contains unexpected path separators`
)
this.segments.push(segment)
}
}
}
}
/**
* Converts the path to it's string representation
*/
toString(): string {
// First segment
let result = this.segments[0]
// All others
let skipSlash =
result.endsWith(path.sep) || (IS_WINDOWS && /^[A-Z]:$/i.test(result))
for (let i = 1; i < this.segments.length; i++) {
if (skipSlash) {
skipSlash = false
} else {
result += path.sep
}
result += this.segments[i]
}
return result
}
}