src/vs/base/common/uriTemplate.ts
305 LOC · 295 covered · 10 uncovered · 123 ranges · 181 concepts · 62 introducers · 100 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.
/*---------------------------------------------------------------------------------------------
uriTemplate.ts ×8
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface IUriTemplateVariable {
readonly explodable: boolean;
readonly name: string;
readonly optional: boolean;
readonly prefixLength?: number;
readonly repeatable: boolean;
}
interface IUriTemplateComponent {
readonly expression: string;
readonly operator: string;
readonly variables: readonly IUriTemplateVariable[];
}
/**
* Represents an RFC 6570 URI Template.
*/
export class UriTemplate {
/**
* The parsed template components (expressions).
*/
public readonly components: ReadonlyArray<IUriTemplateComponent | string>;
private constructor(
components: ReadonlyArray<IUriTemplateComponent | string>
) {
this.template = template;
this.components = components;
}
/**
* Parses a URI template string into a UriTemplate instance.
*/
public static parse(template: string): UriTemplate {
const regex = /\{([^{}]+)\}/g;
let match: RegExpExecArray | null;
let lastPos = 0;
while ((match = regex.exec(template))) {
const [expression, inner] = match;
components.push(template.slice(lastPos, match.index));
lastPos = match.index + expression.length;
// Handle escaped braces: treat '{{' and '}}' as literals, not expressions
if (template[match.index - 1] === '{' || template[lastPos] === '}') {
continue;
}
let operator = '';
let rest = inner;
if (rest.length > 0 && UriTemplate._isOperator(rest[0])) {
rest = rest.slice(1);
}
let name = v;
let explodable = false;
let repeatable = false;
let prefixLength: number | undefined = undefined;
let optional = false;
if (name.endsWith('*')) {
repeatable = true;
name = name.slice(0, -1);
}
if (prefixMatch) {
prefixLength = parseInt(prefixMatch[2], 10);
}
optional = true;
name = name.slice(0, -1);
}
});
components.push({ expression, operator, variables });
}
components.push(template.slice(lastPos));
return new UriTemplate(template, components);
}
private static _operators = ['+', '#', '.', '/', ';', '?', '&'] as const;
private static _isOperator(ch: string): boolean {
}
/**
* Resolves the template with the given variables.
*/
public resolve(variables: Record<string, unknown>): string {
for (const comp of this.components) {
if (typeof comp === 'string') {
result += comp;
} else {
}
return result;
}
private _expand(comp: IUriTemplateComponent, variables: Record<string, unknown>): string {
const varSpecs = comp.variables;
if (varSpecs.length === 0) {
return comp.expression;
}
const isNamed = op === ';' || op === '?' || op === '&';
const isReserved = op === '+' || op === '#';
const isFragment = op === '#';
const isLabel = op === '.';
const isPath = op === '/';
const isForm = op === '?';
const isFormCont = op === '&';
const isParam = op === ';';
let prefix = '';
if (op === '+') { prefix = ''; }
for (const v of varSpecs) {
const value = variables[v.name];
const defined = Object.prototype.hasOwnProperty.call(variables, v.name);
if (value === undefined || value === null || (Array.isArray(value) && value.length === 0)) {
if (defined && (value === null || value === undefined)) {
vals.push(v.name);
}
continue;
}
vals.push(UriTemplate._formPair(v.name, '', isNamed));
}
continue;
}
}
const pairs: string[] = [];
for (const k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
const thisVal = String((value as Record<string, unknown>)[k]);
if (isParam) {
}
}
if (isLabel) {
}
const pairs: string[] = [];
for (const k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
pairs.push(k);
pairs.push(String((value as Record<string, unknown>)[k]));
}
}
// For label, param, form, join as keys=semi,;,dot,.,comma,, (no encoding of , or ;)
const joined = pairs.join(',');
if (isLabel) {
}
}
if (isLabel) {
vals.push(value.map(x => '/' + UriTemplate._encode(x, isReserved)).join(''));
uriTemplate.ts ×1
}
if (isLabel) {
}
continue;
}
if (v.prefixLength !== undefined) {
}
// Only + and # are reserved
const enc = UriTemplate._encode(str, op === '+' || op === '#');
if (isParam) {
}
let joined = '';
if (isLabel) {
const filtered = vals.filter(v => v !== '');
joined = filtered.length ? prefix + filtered.join('.') : '';
const filtered = vals.filter(v => v !== '');
joined = filtered.length ? filtered.join('') : '';
if (joined && !joined.startsWith('/')) {
}
joined = vals.length ? prefix + vals.map(v => v.replace(/=\s*$/, '')).join(';') : '';
}
}
private static _encode(str: string, reserved: boolean): string {
}
private static _formPair(k: string, v: unknown, named: boolean): string {
return named ? k + '=' + encodeURIComponent(String(v)) : encodeURIComponent(String(v));
uriTemplate.ts ×2
}
let out = '';
for (let i = 0; i < str.length; i++) {
const chr = str.charCodeAt(i);
if (
// alphanum ranges:
(chr >= 0x30 && chr <= 0x39 || chr >= 0x41 && chr <= 0x5a || chr >= 0x61 && chr <= 0x7a) ||
(chr === 0x2d || chr === 0x2e || chr === 0x5f || chr === 0x7e)
out += str[i];
} else {
}
return out;
}