From 0837aa278853b4bf689a5045bd2403e6ee068f05 Mon Sep 17 00:00:00 2001 From: vince-fugnitto Date: Fri, 20 May 2022 15:34:37 -0400 Subject: [PATCH] plugin: removed glob.ts and paths.ts The commit removed both `glob.ts` and `paths.ts` as they are duplicated files from `core`. Signed-off-by: vince-fugnitto --- CHANGELOG.md | 1 + .../custom-editors/custom-editor-opener.tsx | 4 +- .../src/main/browser/custom-editors/glob.ts | 743 ------------------ .../src/main/browser/custom-editors/paths.ts | 250 ------ 4 files changed, 3 insertions(+), 995 deletions(-) delete mode 100644 packages/plugin-ext/src/main/browser/custom-editors/glob.ts delete mode 100644 packages/plugin-ext/src/main/browser/custom-editors/paths.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 299691b2d590b..b81c00b949d87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ - [output] removed `setVisibility` from `OutputChannelManager` []() - [output] removed deprecated const `OUTPUT_WIDGET_KIND` []() - [plugin-ext] deleted `untitled-resource.ts` []() +- [plugin-ext] deleted `glob.ts` and `paths.ts` []() - [preferences] removed deprecated `ContextMenuCallbacks` []() - [process] removed the deprecated getters `input`, `output` and `errorOutput` []() - [workspace] removed deprecated `getDefaultWorkspacePath` []() diff --git a/packages/plugin-ext/src/main/browser/custom-editors/custom-editor-opener.tsx b/packages/plugin-ext/src/main/browser/custom-editors/custom-editor-opener.tsx index aa5a15ade1972..3656bf6b6c69c 100644 --- a/packages/plugin-ext/src/main/browser/custom-editors/custom-editor-opener.tsx +++ b/packages/plugin-ext/src/main/browser/custom-editors/custom-editor-opener.tsx @@ -18,10 +18,10 @@ import { inject } from '@theia/core/shared/inversify'; import URI from '@theia/core/lib/common/uri'; import { ApplicationShell, OpenHandler, Widget, WidgetManager, WidgetOpenerOptions } from '@theia/core/lib/browser'; import { CustomEditor, CustomEditorPriority, CustomEditorSelector } from '../../../common'; -import * as glob from './glob'; import { CustomEditorWidget } from './custom-editor-widget'; import { v4 } from 'uuid'; import { Emitter } from '@theia/core'; +import { match } from '@theia/core/lib/common/glob'; export class CustomEditorOpener implements OpenHandler { @@ -96,7 +96,7 @@ export class CustomEditorOpener implements OpenHandler { selectorMatches(selector: CustomEditorSelector, resource: URI): boolean { if (selector.filenamePattern) { - if (glob.match(selector.filenamePattern.toLowerCase(), resource.path.name.toLowerCase() + resource.path.ext.toLowerCase())) { + if (match(selector.filenamePattern.toLowerCase(), resource.path.name.toLowerCase() + resource.path.ext.toLowerCase())) { return true; } } diff --git a/packages/plugin-ext/src/main/browser/custom-editors/glob.ts b/packages/plugin-ext/src/main/browser/custom-editors/glob.ts deleted file mode 100644 index 55fde51f8ff35..0000000000000 --- a/packages/plugin-ext/src/main/browser/custom-editors/glob.ts +++ /dev/null @@ -1,743 +0,0 @@ -// ***************************************************************************** -// Copyright (C) 2021 SAP SE or an SAP affiliate company and others. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0. -// -// This Source Code may also be made available under the following Secondary -// Licenses when the conditions for such availability set forth in the Eclipse -// Public License v. 2.0 are satisfied: GNU General Public License, version 2 -// with the GNU Classpath Exception which is available at -// https://www.gnu.org/software/classpath/license.html. -// -// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 -// ***************************************************************************** -// copied from https://github.com/Microsoft/vscode/blob/bf7ac9201e7a7d01741d4e6e64b5dc9f3197d97b/src/vs/base/common/glob.ts -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -import * as strings from '@theia/core/lib/common/strings'; -import * as paths from './paths'; -import { CharCode } from '@theia/core/lib/common/char-code'; - -/* eslint-disable @typescript-eslint/no-shadow, no-null/no-null */ - -export interface IExpression { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - [pattern: string]: boolean | SiblingClause | any; -} - -export interface IRelativePattern { - base: string; - pattern: string; - pathToRelative(from: string, to: string): string; -} - -export function getEmptyExpression(): IExpression { - return Object.create(null); -} - -export interface SiblingClause { - when: string; -} - -const GLOBSTAR = '**'; -const GLOB_SPLIT = '/'; -const PATH_REGEX = '[/\\\\]'; // any slash or backslash -const NO_PATH_REGEX = '[^/\\\\]'; // any non-slash and non-backslash -const ALL_FORWARD_SLASHES = /\//g; - -function starsToRegExp(starCount: number): string { - switch (starCount) { - case 0: - return ''; - case 1: - return `${NO_PATH_REGEX}*?`; // 1 star matches any number of characters except path separator (/ and \) - non greedy (?) - default: - // Matches: (Path Sep OR Path Val followed by Path Sep OR Path Sep followed by Path Val) 0-many times - // Group is non capturing because we don't need to capture at all (?:...) - // Overall we use non-greedy matching because it could be that we match too much - return `(?:${PATH_REGEX}|${NO_PATH_REGEX}+${PATH_REGEX}|${PATH_REGEX}${NO_PATH_REGEX}+)*?`; - } -} - -export function splitGlobAware(pattern: string, splitChar: string): string[] { - if (!pattern) { - return []; - } - - const segments: string[] = []; - - let inBraces = false; - let inBrackets = false; - - let char: string; - let curVal = ''; - for (let i = 0; i < pattern.length; i++) { - char = pattern[i]; - - switch (char) { - case splitChar: - if (!inBraces && !inBrackets) { - segments.push(curVal); - curVal = ''; - - continue; - } - break; - case '{': - inBraces = true; - break; - case '}': - inBraces = false; - break; - case '[': - inBrackets = true; - break; - case ']': - inBrackets = false; - break; - } - - curVal += char; - } - - // Tail - if (curVal) { - segments.push(curVal); - } - - return segments; -} - -function parseRegExp(pattern: string): string { - if (!pattern) { - return ''; - } - - let regEx = ''; - - // Split up into segments for each slash found - // eslint-disable-next-line prefer-const - let segments = splitGlobAware(pattern, GLOB_SPLIT); - - // Special case where we only have globstars - if (segments.every(s => s === GLOBSTAR)) { - regEx = '.*'; - } - - // Build regex over segments - // tslint:disable-next-line:one-line - else { - let previousSegmentWasGlobStar = false; - segments.forEach((segment, index) => { - - // Globstar is special - if (segment === GLOBSTAR) { - - // if we have more than one globstar after another, just ignore it - if (!previousSegmentWasGlobStar) { - regEx += starsToRegExp(2); - previousSegmentWasGlobStar = true; - } - - return; - } - - // States - let inBraces = false; - let braceVal = ''; - - let inBrackets = false; - let bracketVal = ''; - - let char: string; - for (let i = 0; i < segment.length; i++) { - char = segment[i]; - - // Support brace expansion - if (char !== '}' && inBraces) { - braceVal += char; - continue; - } - - // Support brackets - if (inBrackets && (char !== ']' || !bracketVal) /* ] is literally only allowed as first character in brackets to match it */) { - let res: string; - - // range operator - if (char === '-') { - res = char; - } - - // negation operator (only valid on first index in bracket) - // tslint:disable-next-line:one-line - else if ((char === '^' || char === '!') && !bracketVal) { - res = '^'; - } - - // glob split matching is not allowed within character ranges - // see http://man7.org/linux/man-pages/man7/glob.7.html - // tslint:disable-next-line:one-line - else if (char === GLOB_SPLIT) { - res = ''; - } - - // anything else gets escaped - // tslint:disable-next-line:one-line - else { - res = strings.escapeRegExpCharacters(char); - } - - bracketVal += res; - continue; - } - - switch (char) { - case '{': - inBraces = true; - continue; - - case '[': - inBrackets = true; - continue; - - case '}': - // eslint-disable-next-line prefer-const - let choices = splitGlobAware(braceVal, ','); - - // Converts {foo,bar} => [foo|bar] - // eslint-disable-next-line prefer-const - let braceRegExp = `(?:${choices.map(c => parseRegExp(c)).join('|')})`; - - regEx += braceRegExp; - - inBraces = false; - braceVal = ''; - - break; - - case ']': - regEx += ('[' + bracketVal + ']'); - - inBrackets = false; - bracketVal = ''; - - break; - - case '?': - regEx += NO_PATH_REGEX; // 1 ? matches any single character except path separator (/ and \) - continue; - - case '*': - regEx += starsToRegExp(1); - continue; - - default: - regEx += strings.escapeRegExpCharacters(char); - } - } - - // Tail: Add the slash we had split on if there is more to come and the remaining pattern is not a globstar - // For example if pattern: some/**/*.js we want the "/" after some to be included in the RegEx to prevent - // a folder called "something" to match as well. - // However, if pattern: some/**, we tolerate that we also match on "something" because our globstar behavior - // is to match 0-N segments. - if (index < segments.length - 1 && (segments[index + 1] !== GLOBSTAR || index + 2 < segments.length)) { - regEx += PATH_REGEX; - } - - // reset state - previousSegmentWasGlobStar = false; - }); - } - - return regEx; -} - -// regexes to check for trivial glob patterns that just check for String#endsWith -const T1 = /^\*\*\/\*\.[\w\.-]+$/; // **/*.something -const T2 = /^\*\*\/([\w\.-]+)\/?$/; // **/something -const T3 = /^{\*\*\/[\*\.]?[\w\.-]+\/?(,\*\*\/[\*\.]?[\w\.-]+\/?)*}$/; // {**/*.something,**/*.else} or {**/package.json,**/project.json} -const T3_2 = /^{\*\*\/[\*\.]?[\w\.-]+(\/(\*\*)?)?(,\*\*\/[\*\.]?[\w\.-]+(\/(\*\*)?)?)*}$/; // Like T3, with optional trailing /** -const T4 = /^\*\*((\/[\w\.-]+)+)\/?$/; // **/something/else -const T5 = /^([\w\.-]+(\/[\w\.-]+)*)\/?$/; // something/else - -export type ParsedPattern = (path: string, basename?: string) => boolean; - -// The ParsedExpression returns a Promise iff hasSibling returns a Promise. -// eslint-disable-next-line max-len -export type ParsedExpression = (path: string, basename?: string, hasSibling?: (name: string) => boolean | Promise) => string | Promise /* the matching pattern */; - -export interface IGlobOptions { - /** - * Simplify patterns for use as exclusion filters during tree traversal to skip entire subtrees. Cannot be used outside of a tree traversal. - */ - trimForExclusions?: boolean; -} - -interface ParsedStringPattern { - (path: string, basename: string): string | Promise /* the matching pattern */; - basenames?: string[]; - patterns?: string[]; - allBasenames?: string[]; - allPaths?: string[]; -} -interface ParsedExpressionPattern { - (path: string, basename: string, name: string, hasSibling: (name: string) => boolean | Promise): string | Promise /* the matching pattern */; - requiresSiblings?: boolean; - allBasenames?: string[]; - allPaths?: string[]; -} - -const CACHE = new Map(); // new LRUCache(10000); // bounded to 10000 elements - -const FALSE = function (): boolean { - return false; -}; - -const NULL = function (): string { - return null!; -}; - -function parsePattern(arg1: string | IRelativePattern, options: IGlobOptions): ParsedStringPattern { - if (!arg1) { - return NULL; - } - - // Handle IRelativePattern - let pattern: string; - if (typeof arg1 !== 'string') { - pattern = arg1.pattern; - } else { - pattern = arg1; - } - - // Whitespace trimming - pattern = pattern.trim(); - - // Check cache - const patternKey = `${pattern}_${!!options.trimForExclusions}`; - let parsedPattern = CACHE.get(patternKey); - if (parsedPattern) { - return wrapRelativePattern(parsedPattern, arg1); - } - - // Check for Trivias - let match: RegExpExecArray; - if (T1.test(pattern)) { // common pattern: **/*.txt just need endsWith check - const base = pattern.substr(4); // '**/*'.length === 4 - parsedPattern = function (path, basename): string { - return path && strings.endsWith(path, base) ? pattern : null!; - }; - } else if (match = T2.exec(trimForExclusions(pattern, options))!) { // common pattern: **/some.txt just need basename check - parsedPattern = trivia2(match[1], pattern); - } else if ((options.trimForExclusions ? T3_2 : T3).test(pattern)) { // repetition of common patterns (see above) {**/*.txt,**/*.png} - parsedPattern = trivia3(pattern, options); - } else if (match = T4.exec(trimForExclusions(pattern, options))!) { // common pattern: **/something/else just need endsWith check - parsedPattern = trivia4and5(match[1].substr(1), pattern, true); - } else if (match = T5.exec(trimForExclusions(pattern, options))!) { // common pattern: something/else just need equals check - parsedPattern = trivia4and5(match[1], pattern, false); - } - - // Otherwise convert to pattern - // tslint:disable-next-line:one-line - else { - parsedPattern = toRegExp(pattern); - } - - // Cache - CACHE.set(patternKey, parsedPattern); - - return wrapRelativePattern(parsedPattern, arg1); -} - -function wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | IRelativePattern): ParsedStringPattern { - if (typeof arg2 === 'string') { - return parsedPattern; - } - - return function (path, basename): string | Promise { - if (!paths.isEqualOrParent(path, arg2.base)) { - return null!; - } - - return parsedPattern(paths.normalize(arg2.pathToRelative(arg2.base, path)), basename); - }; -} - -function trimForExclusions(pattern: string, options: IGlobOptions): string { - return options.trimForExclusions && strings.endsWith(pattern, '/**') ? pattern.substr(0, pattern.length - 2) : pattern; // dropping **, tailing / is dropped later -} - -// common pattern: **/some.txt just need basename check -function trivia2(base: string, originalPattern: string): ParsedStringPattern { - const slashBase = `/${base}`; - const backslashBase = `\\${base}`; - const parsedPattern: ParsedStringPattern = function (path, basename): string { - if (!path) { - return null!; - } - if (basename) { - return basename === base ? originalPattern : null!; - } - return path === base || strings.endsWith(path, slashBase) || strings.endsWith(path, backslashBase) ? originalPattern : null!; - }; - const basenames = [base]; - parsedPattern.basenames = basenames; - parsedPattern.patterns = [originalPattern]; - parsedPattern.allBasenames = basenames; - return parsedPattern; -} - -// repetition of common patterns (see above) {**/*.txt,**/*.png} -function trivia3(pattern: string, options: IGlobOptions): ParsedStringPattern { - const parsedPatterns = aggregateBasenameMatches(pattern.slice(1, -1).split(',') - .map(pattern => parsePattern(pattern, options)) - .filter(pattern => pattern !== NULL), pattern); - const n = parsedPatterns.length; - if (!n) { - return NULL; - } - if (n === 1) { - return parsedPatterns[0]; - } - const parsedPattern: ParsedStringPattern = function (path: string, basename: string): string { - for (let i = 0, n = parsedPatterns.length; i < n; i++) { - if ((parsedPatterns[i])(path, basename)) { - return pattern; - } - } - return null!; - }; - const withBasenames = parsedPatterns.find(pattern => !!(pattern).allBasenames); - // const withBasenames = arrays.first(parsedPatterns, pattern => !!(pattern).allBasenames); - if (withBasenames) { - parsedPattern.allBasenames = (withBasenames).allBasenames; - } - const allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, []); - if (allPaths.length) { - parsedPattern.allPaths = allPaths; - } - return parsedPattern; -} - -// common patterns: **/something/else just need endsWith check, something/else just needs and equals check -function trivia4and5(path: string, pattern: string, matchPathEnds: boolean): ParsedStringPattern { - const nativePath = paths.nativeSep !== paths.sep ? path.replace(ALL_FORWARD_SLASHES, paths.nativeSep) : path; - const nativePathEnd = paths.nativeSep + nativePath; - // eslint-disable-next-line @typescript-eslint/no-shadow - const parsedPattern: ParsedStringPattern = matchPathEnds ? function (path, basename): string { - return path && (path === nativePath || strings.endsWith(path, nativePathEnd)) ? pattern : null!; - // eslint-disable-next-line @typescript-eslint/no-shadow - } : function (path, basename): string { - return path && path === nativePath ? pattern : null!; - }; - parsedPattern.allPaths = [(matchPathEnds ? '*/' : './') + path]; - return parsedPattern; -} - -function toRegExp(pattern: string): ParsedStringPattern { - try { - const regExp = new RegExp(`^${parseRegExp(pattern)}$`); - return function (path: string, basename: string): string { - regExp.lastIndex = 0; // reset RegExp to its initial state to reuse it! - return path && regExp.test(path) ? pattern : null!; - }; - } catch (error) { - return NULL; - } -} - -/** - * Simplified glob matching. Supports a subset of glob patterns: - * - * matches anything inside a path segment - * - ? matches 1 character inside a path segment - * - ** matches anything including an empty path segment - * - simple brace expansion ({js,ts} => js or ts) - * - character ranges (using [...]) - */ -export function match(pattern: string | IRelativePattern, path: string): boolean; -export function match(expression: IExpression, path: string, hasSibling?: (name: string) => boolean): string /* the matching pattern */; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function match(arg1: string | IExpression | IRelativePattern, path: string, hasSibling?: (name: string) => boolean): any { - if (!arg1 || !path) { - return false; - } - - return parse(arg1)(path, undefined, hasSibling); -} - -/** - * Simplified glob matching. Supports a subset of glob patterns: - * - * matches anything inside a path segment - * - ? matches 1 character inside a path segment - * - ** matches anything including an empty path segment - * - simple brace expansion ({js,ts} => js or ts) - * - character ranges (using [...]) - */ -export function parse(pattern: string | IRelativePattern, options?: IGlobOptions): ParsedPattern; -export function parse(expression: IExpression, options?: IGlobOptions): ParsedExpression; -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function parse(arg1: string | IExpression | IRelativePattern, options: IGlobOptions = {}): any { - if (!arg1) { - return FALSE; - } - - // Glob with String - if (typeof arg1 === 'string' || isRelativePattern(arg1)) { - const parsedPattern = parsePattern(arg1 as string | IRelativePattern, options); - if (parsedPattern === NULL) { - return FALSE; - } - const resultPattern = function (path: string, basename: string): boolean { - return !!parsedPattern(path, basename); - }; - if (parsedPattern.allBasenames) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (resultPattern).allBasenames = parsedPattern.allBasenames; - } - if (parsedPattern.allPaths) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (resultPattern).allPaths = parsedPattern.allPaths; - } - return resultPattern; - } - - // Glob with Expression - return parsedExpression(arg1, options); -} - -export function hasSiblingPromiseFn(siblingsFn?: () => Promise): ((name: string) => Promise) | undefined { - if (!siblingsFn) { - return undefined; - } - - let siblings: Promise>; - return (name: string) => { - if (!siblings) { - siblings = (siblingsFn() || Promise.resolve([])) - .then(list => list ? listToMap(list) : {}); - } - return siblings.then(map => !!map[name]); - }; -} - -export function hasSiblingFn(siblingsFn?: () => string[]): ((name: string) => boolean) | undefined { - if (!siblingsFn) { - return undefined; - } - - let siblings: Record; - return (name: string) => { - if (!siblings) { - const list = siblingsFn(); - siblings = list ? listToMap(list) : {}; - } - return !!siblings[name]; - }; -} - -function listToMap(list: string[]): Record { - const map: Record = {}; - for (const key of list) { - map[key] = true; - } - return map; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function isRelativePattern(obj: any): obj is IRelativePattern { - const rp = obj as IRelativePattern; - - return rp && typeof rp.base === 'string' && typeof rp.pattern === 'string' && typeof rp.pathToRelative === 'function'; -} - -/** - * Same as `parse`, but the ParsedExpression is guaranteed to return a Promise - */ -export function parseToAsync(expression: IExpression, options?: IGlobOptions): ParsedExpression { - // eslint-disable-next-line @typescript-eslint/no-shadow - const parsedExpression = parse(expression, options); - return (path: string, basename?: string, hasSibling?: (name: string) => boolean | Promise): string | Promise => { - const result = parsedExpression(path, basename, hasSibling); - return result instanceof Promise ? result : Promise.resolve(result); - }; -} - -export function getBasenameTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] { - return (patternOrExpression).allBasenames || []; -} - -export function getPathTerms(patternOrExpression: ParsedPattern | ParsedExpression): string[] { - return (patternOrExpression).allPaths || []; -} - -function parsedExpression(expression: IExpression, options: IGlobOptions): ParsedExpression { - const parsedPatterns = aggregateBasenameMatches(Object.getOwnPropertyNames(expression) - .map(pattern => parseExpressionPattern(pattern, expression[pattern], options)) - .filter(pattern => pattern !== NULL)); - - const n = parsedPatterns.length; - if (!n) { - return NULL; - } - - if (!parsedPatterns.some(parsedPattern => (parsedPattern).requiresSiblings!)) { - if (n === 1) { - return parsedPatterns[0]; - } - - // eslint-disable-next-line @typescript-eslint/no-shadow - const resultExpression: ParsedStringPattern = function (path: string, basename: string): string | Promise { - // eslint-disable-next-line @typescript-eslint/no-shadow - // tslint:disable-next-line:one-variable-per-declaration - for (let i = 0, n = parsedPatterns.length; i < n; i++) { - // Pattern matches path - const result = (parsedPatterns[i])(path, basename); - if (result) { - return result; - } - } - - return null!; - }; - - // eslint-disable-next-line @typescript-eslint/no-shadow - const withBasenames = parsedPatterns.find(pattern => !!(pattern).allBasenames); - if (withBasenames) { - resultExpression.allBasenames = (withBasenames).allBasenames; - } - - // eslint-disable-next-line @typescript-eslint/no-shadow - const allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, []); - if (allPaths.length) { - resultExpression.allPaths = allPaths; - } - - return resultExpression; - } - - const resultExpression: ParsedStringPattern = function (path: string, basename: string, hasSibling?: (name: string) => boolean | Promise): string | Promise { - let name: string = null!; - - // eslint-disable-next-line @typescript-eslint/no-shadow - for (let i = 0, n = parsedPatterns.length; i < n; i++) { - // Pattern matches path - const parsedPattern = (parsedPatterns[i]); - if (parsedPattern.requiresSiblings && hasSibling) { - if (!basename) { - basename = paths.basename(path); - } - if (!name) { - name = basename.substr(0, basename.length - paths.extname(path).length); - } - } - const result = parsedPattern(path, basename, name, hasSibling!); - if (result) { - return result; - } - } - - return null!; - }; - - const withBasenames = parsedPatterns.find(pattern => !!(pattern).allBasenames); - if (withBasenames) { - resultExpression.allBasenames = (withBasenames).allBasenames; - } - - const allPaths = parsedPatterns.reduce((all, current) => current.allPaths ? all.concat(current.allPaths) : all, []); - if (allPaths.length) { - resultExpression.allPaths = allPaths; - } - - return resultExpression; -} - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function parseExpressionPattern(pattern: string, value: any, options: IGlobOptions): (ParsedStringPattern | ParsedExpressionPattern) { - if (value === false) { - return NULL; // pattern is disabled - } - - const parsedPattern = parsePattern(pattern, options); - if (parsedPattern === NULL) { - return NULL; - } - - // Expression Pattern is - if (typeof value === 'boolean') { - return parsedPattern; - } - - // Expression Pattern is - if (value) { - const when = (value).when; - if (typeof when === 'string') { - const result: ParsedExpressionPattern = (path: string, basename: string, name: string, hasSibling: (name: string) => boolean | Promise) => { - if (!hasSibling || !parsedPattern(path, basename)) { - return null!; - } - - const clausePattern = when.replace('$(basename)', name); - const matched = hasSibling(clausePattern); - return matched instanceof Promise ? - matched.then(m => m ? pattern : null!) : - matched ? pattern : null!; - }; - result.requiresSiblings = true; - return result; - } - } - - // Expression is Anything - return parsedPattern; -} - -function aggregateBasenameMatches(parsedPatterns: (ParsedStringPattern | ParsedExpressionPattern)[], result?: string): (ParsedStringPattern | ParsedExpressionPattern)[] { - const basenamePatterns = parsedPatterns.filter(parsedPattern => !!(parsedPattern).basenames); - if (basenamePatterns.length < 2) { - return parsedPatterns; - } - - const basenames = basenamePatterns.reduce((all, current) => all.concat((current).basenames!), []); - let patterns: string[]; - if (result) { - patterns = []; - // tslint:disable-next-line:one-variable-per-declaration - for (let i = 0, n = basenames.length; i < n; i++) { - patterns.push(result); - } - } else { - patterns = basenamePatterns.reduce((all, current) => all.concat((current).patterns!), []); - } - const aggregate: ParsedStringPattern = function (path, basename): string { - if (!path) { - return null!; - } - if (!basename) { - let i: number; - for (i = path.length; i > 0; i--) { - const ch = path.charCodeAt(i - 1); - if (ch === CharCode.Slash || ch === CharCode.Backslash) { - break; - } - } - basename = path.substr(i); - } - const index = basenames.indexOf(basename); - return index !== -1 ? patterns[index] : null!; - }; - aggregate.basenames = basenames; - aggregate.patterns = patterns; - aggregate.allBasenames = basenames; - - const aggregatedPatterns = parsedPatterns.filter(parsedPattern => !(parsedPattern).basenames); - aggregatedPatterns.push(aggregate); - return aggregatedPatterns; -} diff --git a/packages/plugin-ext/src/main/browser/custom-editors/paths.ts b/packages/plugin-ext/src/main/browser/custom-editors/paths.ts deleted file mode 100644 index 2cd9e2d88fde8..0000000000000 --- a/packages/plugin-ext/src/main/browser/custom-editors/paths.ts +++ /dev/null @@ -1,250 +0,0 @@ -// ***************************************************************************** -// Copyright (C) 2021 SAP SE or an SAP affiliate company and others. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0. -// -// This Source Code may also be made available under the following Secondary -// Licenses when the conditions for such availability set forth in the Eclipse -// Public License v. 2.0 are satisfied: GNU General Public License, version 2 -// with the GNU Classpath Exception which is available at -// https://www.gnu.org/software/classpath/license.html. -// -// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 -// ***************************************************************************** - -// copied from https://github.com/Microsoft/vscode/blob/bf7ac9201e7a7d01741d4e6e64b5dc9f3197d97b/src/vs/base/common/paths.ts -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -/* eslint-disable no-void */ -/* eslint-disable no-null/no-null */ -'use strict'; -import { isWindows } from '@theia/core/lib/common/os'; -import { startsWithIgnoreCase } from '@theia/core/lib/common/strings'; -import { CharCode } from '@theia/core/lib/common/char-code'; - -/** - * The forward slash path separator. - */ -export const sep = '/'; - -/** - * The native path separator depending on the OS. - */ -export const nativeSep = isWindows ? '\\' : '/'; - -const _posixBadPath = /(\/\.\.?\/)|(\/\.\.?)$|^(\.\.?\/)|(\/\/+)|(\\)/; -const _winBadPath = /(\\\.\.?\\)|(\\\.\.?)$|^(\.\.?\\)|(\\\\+)|(\/)/; - -function _isNormal(path: string, win: boolean): boolean { - return win - ? !_winBadPath.test(path) - : !_posixBadPath.test(path); -} - -/** - * @returns the base name of a path. - */ -export function basename(path: string): string { - const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\'); - if (idx === 0) { - return path; - } else if (~idx === path.length - 1) { - return basename(path.substring(0, path.length - 1)); - } else { - return path.substr(~idx + 1); - } -} - -/** - * @returns `.far` from `boo.far` or the empty string. - */ -export function extname(path: string): string { - path = basename(path); - const idx = ~path.lastIndexOf('.'); - return idx ? path.substring(~idx) : ''; -} - -export function normalize(path: string, toOSPath?: boolean): string { - if (path === null || path === void 0) { - return path; - } - - const len = path.length; - if (len === 0) { - return '.'; - } - - const wantsBackslash = isWindows && toOSPath; - if (_isNormal(path, wantsBackslash!)) { - return path; - } - - // eslint-disable-next-line @typescript-eslint/no-shadow - const sep = wantsBackslash ? '\\' : '/'; - const root = getRoot(path, sep); - - // skip the root-portion of the path - let start = root.length; - let skip = false; - let res = ''; - - for (let end = root.length; end <= len; end++) { - - // either at the end or at a path-separator character - if (end === len || path.charCodeAt(end) === CharCode.Slash || path.charCodeAt(end) === CharCode.Backslash) { - - if (streql(path, start, end, '..')) { - // skip current and remove parent (if there is already something) - const prev_start = res.lastIndexOf(sep); - const prev_part = res.slice(prev_start + 1); - if ((root || prev_part.length > 0) && prev_part !== '..') { - res = prev_start === -1 ? '' : res.slice(0, prev_start); - skip = true; - } - } else if (streql(path, start, end, '.') && (root || res || end < len - 1)) { - // skip current (if there is already something or if there is more to come) - skip = true; - } - - if (!skip) { - const part = path.slice(start, end); - if (res !== '' && res[res.length - 1] !== sep) { - res += sep; - } - res += part; - } - start = end + 1; - skip = false; - } - } - - return root + res; -} -function streql(value: string, start: number, end: number, other: string): boolean { - return start + other.length === end && value.indexOf(other, start) === start; -} - -/** - * Computes the _root_ this path, like `getRoot('c:\files') === c:\`, - * `getRoot('files:///files/path') === files:///`, - * or `getRoot('\\server\shares\path') === \\server\shares\` - */ -// eslint-disable-next-line @typescript-eslint/no-shadow -export function getRoot(path: string, sep: string = '/'): string { - - if (!path) { - return ''; - } - - const len = path.length; - let code = path.charCodeAt(0); - if (code === CharCode.Slash || code === CharCode.Backslash) { - - code = path.charCodeAt(1); - if (code === CharCode.Slash || code === CharCode.Backslash) { - // UNC candidate \\localhost\shares\ddd - // ^^^^^^^^^^^^^^^^^^^ - code = path.charCodeAt(2); - if (code !== CharCode.Slash && code !== CharCode.Backslash) { - // eslint-disable-next-line @typescript-eslint/no-shadow - let pos = 3; - const start = pos; - for (; pos < len; pos++) { - code = path.charCodeAt(pos); - if (code === CharCode.Slash || code === CharCode.Backslash) { - break; - } - } - code = path.charCodeAt(pos + 1); - if (start !== pos && code !== CharCode.Slash && code !== CharCode.Backslash) { - pos += 1; - for (; pos < len; pos++) { - code = path.charCodeAt(pos); - if (code === CharCode.Slash || code === CharCode.Backslash) { - return path.slice(0, pos + 1) // consume this separator - .replace(/[\\/]/g, sep); - } - } - } - } - } - - // /user/far - // ^ - return sep; - - } else if ((code >= CharCode.A && code <= CharCode.Z) || (code >= CharCode.a && code <= CharCode.z)) { - // check for windows drive letter c:\ or c: - - if (path.charCodeAt(1) === CharCode.Colon) { - code = path.charCodeAt(2); - if (code === CharCode.Slash || code === CharCode.Backslash) { - // 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++) { - code = path.charCodeAt(pos); - if (code === CharCode.Slash || code === CharCode.Backslash) { - return path.slice(0, pos + 1); // consume this separator - } - } - } - - return ''; -} - -export function isEqualOrParent(path: string, candidate: string, ignoreCase?: boolean): boolean { - if (path === candidate) { - return true; - } - - if (!path || !candidate) { - return false; - } - - if (candidate.length > path.length) { - return false; - } - - if (ignoreCase) { - const beginsWith = startsWithIgnoreCase(path, candidate); - if (!beginsWith) { - return false; - } - - if (candidate.length === path.length) { - return true; // same path, different casing - } - - let sepOffset = candidate.length; - if (candidate.charAt(candidate.length - 1) === nativeSep) { - sepOffset--; // adjust the expected sep offset in case our candidate already ends in separator character - } - - return path.charAt(sepOffset) === nativeSep; - } - - if (candidate.charAt(candidate.length - 1) !== nativeSep) { - candidate += nativeSep; - } - - return path.indexOf(candidate) === 0; -}