src/vs/platform/url/common/urlGlob.ts
163 LOC · 161 covered · 2 uncovered · 35 ranges · 82 concepts · 15 introducers · 64 tests
File neighbourhood
The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.
Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file
In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.
Graph controls are ready.
Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.
/*---------------------------------------------------------------------------------------------
urlGlob.ts ×4
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { URI } from '../../../base/common/uri.js';
/**
* Normalizes a URL by removing trailing slashes and query/fragment components.
* @param url The URL to normalize.
* @returns URI - The normalized URI object.
*/
const uri = typeof url === 'string' ? URI.parse(url) : url;
return uri.with({
// Remove trailing slashes
path: uri.path.replace(/\/+$/, ''),
// Remove query and fragment
query: null,
fragment: null,
});
}
/**
* Checks if a given URL matches a glob URL pattern.
* The glob URL pattern can contain wildcards (*) and subdomain matching (*.)
* @param uri The URL to check.
* @param globUrl The glob URL pattern to match against.
* @returns boolean - True if the URL matches the glob URL pattern, false otherwise.
*/
export function testUrlMatchesGlob(uri: string | URI, globUrl: string): boolean {
let normalizedGlobUrl: URI;
const globHasScheme = /^[^./:]*:\/\//.test(globUrl);
// if the glob does not have a scheme we assume the scheme is http or https
// so if the url doesn't have a scheme of http or https we return false
if (!globHasScheme) {
}
}
return (
doMemoUrlMatch(normalizedUrl.scheme, normalizedGlobUrl.scheme) &&
doMemoUrlMatch(normalizedUrl.authority, normalizedGlobUrl.authority, true) &&
//
normalizedGlobUrl.path === '/' ||
);
}
/**
* @param normalizedUrlPart The normalized URL part to match.
* @param normalizedGlobUrlPart The normalized glob URL part to match against.
* @param includePortLogic Whether to include port logic in the matching process.
* @returns boolean - True if the URL part matches the glob URL part, false otherwise.
*/
normalizedUrlPart: string,
normalizedGlobUrlPart: string,
includePortLogic: boolean = false,
) {
const memo = Array.from({ length: normalizedUrlPart.length + 1 }).map(() =>
Array.from({ length: normalizedGlobUrlPart.length + 1 }).map(() => undefined),
);
return doUrlPartMatch(memo, includePortLogic, normalizedUrlPart, normalizedGlobUrlPart, 0, 0);
}
/**
* Recursively checks if a URL part matches a glob URL part.
* This function uses memoization to avoid recomputing results for the same inputs.
* It handles various cases such as exact matches, wildcard matches, and port logic.
* @param memo A memoization table to avoid recomputing results for the same inputs.
* @param includePortLogic Whether to include port logic in the matching process.
* @param urlPart The URL part to match with.
* @param globUrlPart The glob URL part to match against.
* @param urlOffset The current offset in the URL part.
* @param globUrlOffset The current offset in the glob URL part.
* @returns boolean - True if the URL part matches the glob URL part, false otherwise.
*/
memo: (boolean | undefined)[][],
includePortLogic: boolean,
urlPart: string,
globUrlPart: string,
urlOffset: number,
globUrlOffset: number
): boolean {
if (memo[urlOffset]?.[globUrlOffset] !== undefined) {
}
const options = [];
// We've reached the end of the url.
if (urlOffset === urlPart.length) {
// We're also at the end of the glob url as well so we have an exact match.
if (globUrlOffset === globUrlPart.length) {
}
if (includePortLogic && globUrlPart[globUrlOffset] + globUrlPart[globUrlOffset + 1] === ':*') {
urlGlob.ts ×14
// any port match. Consume a port if it exists otherwise nothing. Always consume the base.
urlGlob.ts ×1
return globUrlOffset + 2 === globUrlPart.length;
}
return false;
}
// Some path remaining in url
if (globUrlOffset === globUrlPart.length) {
return remaining[0] === '/';
}
if (urlPart[urlOffset] === globUrlPart[globUrlOffset]) {
// Exact match.
options.push(doUrlPartMatch(memo, includePortLogic, urlPart, globUrlPart, urlOffset + 1, globUrlOffset + 1));
}
if (globUrlPart[globUrlOffset] + globUrlPart[globUrlOffset + 1] === '*.') {
// Any subdomain match. Either consume one thing that's not a / or : and don't advance base or consume nothing and do.
urlGlob.ts ×2
if (!['/', ':'].includes(urlPart[urlOffset])) {
options.push(doUrlPartMatch(memo, includePortLogic, urlPart, globUrlPart, urlOffset + 1, globUrlOffset));
}
// Only skip *. if we're at the start (bare domain) or at a dot boundary
if (urlOffset === 0 || urlPart[urlOffset - 1] === '.') {
options.push(doUrlPartMatch(memo, includePortLogic, urlPart, globUrlPart, urlOffset, globUrlOffset + 2));
}
}
if (globUrlPart[globUrlOffset] === '*') {
// Any match. Either consume one thing and don't advance base or consume nothing and do.
urlGlob.ts ×1
if (urlOffset + 1 === urlPart.length) {
// If we're at the end of the input url consume one from both.
options.push(doUrlPartMatch(memo, includePortLogic, urlPart, globUrlPart, urlOffset + 1, globUrlOffset + 1));
} else {
options.push(doUrlPartMatch(memo, includePortLogic, urlPart, globUrlPart, urlOffset + 1, globUrlOffset));
}
options.push(doUrlPartMatch(memo, includePortLogic, urlPart, globUrlPart, urlOffset, globUrlOffset + 1));
}
if (includePortLogic && globUrlPart[globUrlOffset] + globUrlPart[globUrlOffset + 1] === ':*') {
// any port match. Consume a port if it exists otherwise nothing. Always consume the base.
urlGlob.ts ×2
if (urlPart[urlOffset] === ':') {
let endPortIndex = urlOffset + 1;
do { endPortIndex++; } while (/[0-9]/.test(urlPart[endPortIndex]));
options.push(doUrlPartMatch(memo, includePortLogic, urlPart, globUrlPart, endPortIndex, globUrlOffset + 2));
} else {
options.push(doUrlPartMatch(memo, includePortLogic, urlPart, globUrlPart, urlOffset, globUrlOffset + 2));
}
return (memo[urlOffset][globUrlOffset] = options.some(a => a === true));
}