@pkerschbaum/code-oss-file-service
Version:
VS Code ([microsoft/vscode](https://github.com/microsoft/vscode)) includes a rich "`FileService`" and "`DiskFileSystemProvider`" abstraction built on top of Node.js core modules (`fs`, `path`) and Electron's `shell` module. This package allows to use that
341 lines • 12.7 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.randomPath = exports.parseLineAndColumnAware = exports.indexOfPath = exports.getDriveLetter = exports.hasDriveLetter = exports.isRootOrDriveLetter = exports.sanitizeFilePath = exports.isWindowsDriveLetter = exports.isEqualOrParent = exports.isEqual = exports.isValidBasename = exports.isUNC = exports.getRoot = exports.toPosixPath = exports.toSlashes = exports.isPathSeparator = void 0;
const path_1 = require("../../base/common/path");
const platform_1 = require("../../base/common/platform");
const strings_1 = require("../../base/common/strings");
const types_1 = require("../../base/common/types");
function isPathSeparator(code) {
return code === 47 /* Slash */ || code === 92 /* Backslash */;
}
exports.isPathSeparator = isPathSeparator;
/**
* Takes a Windows OS path and changes backward slashes to forward slashes.
* This should only be done for OS paths from Windows (or user provided paths potentially from Windows).
* Using it on a Linux or MaxOS path might change it.
*/
function toSlashes(osPath) {
return osPath.replace(/[\\/]/g, path_1.posix.sep);
}
exports.toSlashes = toSlashes;
/**
* Takes a Windows OS path (using backward or forward slashes) and turns it into a posix path:
* - turns backward slashes into forward slashes
* - makes it absolute if it starts with a drive letter
* This should only be done for OS paths from Windows (or user provided paths potentially from Windows).
* Using it on a Linux or MaxOS path might change it.
*/
function toPosixPath(osPath) {
if (osPath.indexOf('/') === -1) {
osPath = toSlashes(osPath);
}
if (/^[a-zA-Z]:(\/|$)/.test(osPath)) { // starts with a drive letter
osPath = '/' + osPath;
}
return osPath;
}
exports.toPosixPath = toPosixPath;
/**
* Computes the _root_ this path, like `getRoot('c:\files') === c:\`,
* `getRoot('files:///files/path') === files:///`,
* or `getRoot('\\server\shares\path') === \\server\shares\`
*/
function getRoot(path, sep = path_1.posix.sep) {
if (!path) {
return '';
}
const len = path.length;
const firstLetter = path.charCodeAt(0);
if (isPathSeparator(firstLetter)) {
if (isPathSeparator(path.charCodeAt(1))) {
// UNC candidate \\localhost\shares\ddd
// ^^^^^^^^^^^^^^^^^^^
if (!isPathSeparator(path.charCodeAt(2))) {
let pos = 3;
const start = pos;
for (; pos < len; pos++) {
if (isPathSeparator(path.charCodeAt(pos))) {
break;
}
}
if (start !== pos && !isPathSeparator(path.charCodeAt(pos + 1))) {
pos += 1;
for (; pos < len; pos++) {
if (isPathSeparator(path.charCodeAt(pos))) {
return path.slice(0, pos + 1) // consume this separator
.replace(/[\\/]/g, sep);
}
}
}
}
}
// /user/far
// ^
return sep;
}
else if (isWindowsDriveLetter(firstLetter)) {
// check for windows drive letter c:\ or c:
if (path.charCodeAt(1) === 58 /* Colon */) {
if (isPathSeparator(path.charCodeAt(2))) {
// C:\fff
// ^^^
return path.slice(0, 2) + sep;
}
else {
// C:
// ^^
return path.slice(0, 2);
}
}
}
// check for URI
// scheme://authority/path
// ^^^^^^^^^^^^^^^^^^^
let pos = path.indexOf('://');
if (pos !== -1) {
pos += 3; // 3 -> "://".length
for (; pos < len; pos++) {
if (isPathSeparator(path.charCodeAt(pos))) {
return path.slice(0, pos + 1); // consume this separator
}
}
}
return '';
}
exports.getRoot = getRoot;
/**
* Check if the path follows this pattern: `\\hostname\sharename`.
*
* @see https://msdn.microsoft.com/en-us/library/gg465305.aspx
* @return A boolean indication if the path is a UNC path, on none-windows
* always false.
*/
function isUNC(path) {
if (!platform_1.isWindows) {
// UNC is a windows concept
return false;
}
if (!path || path.length < 5) {
// at least \\a\b
return false;
}
let code = path.charCodeAt(0);
if (code !== 92 /* Backslash */) {
return false;
}
code = path.charCodeAt(1);
if (code !== 92 /* Backslash */) {
return false;
}
let pos = 2;
const start = pos;
for (; pos < path.length; pos++) {
code = path.charCodeAt(pos);
if (code === 92 /* Backslash */) {
break;
}
}
if (start === pos) {
return false;
}
code = path.charCodeAt(pos + 1);
if (isNaN(code) || code === 92 /* Backslash */) {
return false;
}
return true;
}
exports.isUNC = isUNC;
// Reference: https://en.wikipedia.org/wiki/Filename
const WINDOWS_INVALID_FILE_CHARS = /[\\/:\*\?"<>\|]/g;
const UNIX_INVALID_FILE_CHARS = /[\\/]/g;
const WINDOWS_FORBIDDEN_NAMES = /^(con|prn|aux|clock\$|nul|lpt[0-9]|com[0-9])(\.(.*?))?$/i;
function isValidBasename(name, isWindowsOS = platform_1.isWindows) {
const invalidFileChars = isWindowsOS ? WINDOWS_INVALID_FILE_CHARS : UNIX_INVALID_FILE_CHARS;
if (!name || name.length === 0 || /^\s+$/.test(name)) {
return false; // require a name that is not just whitespace
}
invalidFileChars.lastIndex = 0; // the holy grail of software development
if (invalidFileChars.test(name)) {
return false; // check for certain invalid file characters
}
if (isWindowsOS && WINDOWS_FORBIDDEN_NAMES.test(name)) {
return false; // check for certain invalid file names
}
if (name === '.' || name === '..') {
return false; // check for reserved values
}
if (isWindowsOS && name[name.length - 1] === '.') {
return false; // Windows: file cannot end with a "."
}
if (isWindowsOS && name.length !== name.trim().length) {
return false; // Windows: file cannot end with a whitespace
}
if (name.length > 255) {
return false; // most file systems do not allow files > 255 length
}
return true;
}
exports.isValidBasename = isValidBasename;
function isEqual(pathA, pathB, ignoreCase) {
const identityEquals = (pathA === pathB);
if (!ignoreCase || identityEquals) {
return identityEquals;
}
if (!pathA || !pathB) {
return false;
}
return (0, strings_1.equalsIgnoreCase)(pathA, pathB);
}
exports.isEqual = isEqual;
function isEqualOrParent(base, parentCandidate, ignoreCase, separator = path_1.sep) {
if (base === parentCandidate) {
return true;
}
if (!base || !parentCandidate) {
return false;
}
if (parentCandidate.length > base.length) {
return false;
}
if (ignoreCase) {
const beginsWith = (0, strings_1.startsWithIgnoreCase)(base, parentCandidate);
if (!beginsWith) {
return false;
}
if (parentCandidate.length === base.length) {
return true; // same path, different casing
}
let sepOffset = parentCandidate.length;
if (parentCandidate.charAt(parentCandidate.length - 1) === separator) {
sepOffset--; // adjust the expected sep offset in case our candidate already ends in separator character
}
return base.charAt(sepOffset) === separator;
}
if (parentCandidate.charAt(parentCandidate.length - 1) !== separator) {
parentCandidate += separator;
}
return base.indexOf(parentCandidate) === 0;
}
exports.isEqualOrParent = isEqualOrParent;
function isWindowsDriveLetter(char0) {
return char0 >= 65 /* A */ && char0 <= 90 /* Z */ || char0 >= 97 /* a */ && char0 <= 122 /* z */;
}
exports.isWindowsDriveLetter = isWindowsDriveLetter;
function sanitizeFilePath(candidate, cwd) {
// Special case: allow to open a drive letter without trailing backslash
if (platform_1.isWindows && candidate.endsWith(':')) {
candidate += path_1.sep;
}
// Ensure absolute
if (!(0, path_1.isAbsolute)(candidate)) {
candidate = (0, path_1.join)(cwd, candidate);
}
// Ensure normalized
candidate = (0, path_1.normalize)(candidate);
// Ensure no trailing slash/backslash
if (platform_1.isWindows) {
candidate = (0, strings_1.rtrim)(candidate, path_1.sep);
// Special case: allow to open drive root ('C:\')
if (candidate.endsWith(':')) {
candidate += path_1.sep;
}
}
else {
candidate = (0, strings_1.rtrim)(candidate, path_1.sep);
// Special case: allow to open root ('/')
if (!candidate) {
candidate = path_1.sep;
}
}
return candidate;
}
exports.sanitizeFilePath = sanitizeFilePath;
function isRootOrDriveLetter(path) {
const pathNormalized = (0, path_1.normalize)(path);
if (platform_1.isWindows) {
if (path.length > 3) {
return false;
}
return hasDriveLetter(pathNormalized) &&
(path.length === 2 || pathNormalized.charCodeAt(2) === 92 /* Backslash */);
}
return pathNormalized === path_1.posix.sep;
}
exports.isRootOrDriveLetter = isRootOrDriveLetter;
function hasDriveLetter(path, continueAsWindows) {
const isWindowsPath = ((continueAsWindows !== undefined) ? continueAsWindows : platform_1.isWindows);
if (isWindowsPath) {
return isWindowsDriveLetter(path.charCodeAt(0)) && path.charCodeAt(1) === 58 /* Colon */;
}
return false;
}
exports.hasDriveLetter = hasDriveLetter;
function getDriveLetter(path) {
return hasDriveLetter(path) ? path[0] : undefined;
}
exports.getDriveLetter = getDriveLetter;
function indexOfPath(path, candidate, ignoreCase) {
if (candidate.length > path.length) {
return -1;
}
if (path === candidate) {
return 0;
}
if (ignoreCase) {
path = path.toLowerCase();
candidate = candidate.toLowerCase();
}
return path.indexOf(candidate);
}
exports.indexOfPath = indexOfPath;
function parseLineAndColumnAware(rawPath) {
const segments = rawPath.split(':'); // C:\file.txt:<line>:<column>
let path = undefined;
let line = undefined;
let column = undefined;
for (const segment of segments) {
const segmentAsNumber = Number(segment);
if (!(0, types_1.isNumber)(segmentAsNumber)) {
path = !!path ? [path, segment].join(':') : segment; // a colon can well be part of a path (e.g. C:\...)
}
else if (line === undefined) {
line = segmentAsNumber;
}
else if (column === undefined) {
column = segmentAsNumber;
}
}
if (!path) {
throw new Error('Format for `--goto` should be: `FILE:LINE(:COLUMN)`');
}
return {
path,
line: line !== undefined ? line : undefined,
column: column !== undefined ? column : line !== undefined ? 1 : undefined // if we have a line, make sure column is also set
};
}
exports.parseLineAndColumnAware = parseLineAndColumnAware;
const pathChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
function randomPath(parent, prefix, randomLength = 8) {
let suffix = '';
for (let i = 0; i < randomLength; i++) {
suffix += pathChars.charAt(Math.floor(Math.random() * pathChars.length));
}
let randomFileName;
if (prefix) {
randomFileName = `${prefix}-${suffix}`;
}
else {
randomFileName = suffix;
}
if (parent) {
return (0, path_1.join)(parent, randomFileName);
}
return randomFileName;
}
exports.randomPath = randomPath;
//# sourceMappingURL=extpath.js.map
;