UNPKG

@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
"use strict"; /*--------------------------------------------------------------------------------------------- * 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