diff --git a/extensions/json/server/package.json b/extensions/json/server/package.json index 3b6e892cc42..d1ece9575d2 100644 --- a/extensions/json/server/package.json +++ b/extensions/json/server/package.json @@ -13,7 +13,8 @@ "vscode-json-languageservice": "^2.0.16", "vscode-languageserver": "3.4.0-next.6", "vscode-languageserver-protocol": "^3.1.1", - "vscode-nls": "^2.0.2" + "vscode-nls": "^2.0.2", + "vscode-uri": "^1.0.1" }, "devDependencies": { "@types/node": "^6.0.51" diff --git a/extensions/json/server/src/jsonServerMain.ts b/extensions/json/server/src/jsonServerMain.ts index 2fe428f717f..183d633ab7a 100644 --- a/extensions/json/server/src/jsonServerMain.ts +++ b/extensions/json/server/src/jsonServerMain.ts @@ -15,7 +15,7 @@ import { DocumentColorRequest, ServerCapabilities as CPServerCapabilities } from import { xhr, XHRResponse, configure as configureHttpRequests, getErrorStatusDescription } from 'request-light'; import path = require('path'); import fs = require('fs'); -import URI from './utils/uri'; +import URI from 'vscode-uri'; import * as URL from 'url'; import Strings = require('./utils/strings'); import { JSONDocument, JSONSchema, LanguageSettings, getLanguageService } from 'vscode-json-languageservice'; diff --git a/extensions/json/server/src/utils/uri.ts b/extensions/json/server/src/utils/uri.ts deleted file mode 100644 index 5cce7590977..00000000000 --- a/extensions/json/server/src/utils/uri.ts +++ /dev/null @@ -1,351 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -'use strict'; - -function _encode(ch: string): string { - return '%' + ch.charCodeAt(0).toString(16).toUpperCase(); -} - -// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent -function encodeURIComponent2(str: string): string { - return encodeURIComponent(str).replace(/[!'()*]/g, _encode); -} - -function encodeNoop(str: string): string { - return str; -} - - -/** - * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. - * This class is a simple parser which creates the basic component paths - * (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation - * and encoding. - * - * foo://example.com:8042/over/there?name=ferret#nose - * \_/ \______________/\_________/ \_________/ \__/ - * | | | | | - * scheme authority path query fragment - * | _____________________|__ - * / \ / \ - * urn:example:animal:ferret:nose - * - * - */ -export default class URI { - - private static _empty = ''; - private static _slash = '/'; - private static _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; - private static _driveLetterPath = /^\/[a-zA-z]:/; - private static _upperCaseDrive = /^(\/)?([A-Z]:)/; - - private _scheme: string; - private _authority: string; - private _path: string; - private _query: string; - private _fragment: string; - private _formatted: string; - private _fsPath: string; - - constructor() { - this._scheme = URI._empty; - this._authority = URI._empty; - this._path = URI._empty; - this._query = URI._empty; - this._fragment = URI._empty; - - this._formatted = null; - this._fsPath = null; - } - - /** - * scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'. - * The part before the first colon. - */ - get scheme() { - return this._scheme; - } - - /** - * authority is the 'www.msft.com' part of 'http://www.msft.com/some/path?query#fragment'. - * The part between the first double slashes and the next slash. - */ - get authority() { - return this._authority; - } - - /** - * path is the '/some/path' part of 'http://www.msft.com/some/path?query#fragment'. - */ - get path() { - return this._path; - } - - /** - * query is the 'query' part of 'http://www.msft.com/some/path?query#fragment'. - */ - get query() { - return this._query; - } - - /** - * fragment is the 'fragment' part of 'http://www.msft.com/some/path?query#fragment'. - */ - get fragment() { - return this._fragment; - } - - // ---- filesystem path ----------------------- - - /** - * Returns a string representing the corresponding file system path of this URI. - * Will handle UNC paths and normalize windows drive letters to lower-case. Also - * uses the platform specific path separator. Will *not* validate the path for - * invalid characters and semantics. Will *not* look at the scheme of this URI. - */ - get fsPath() { - if (!this._fsPath) { - var value: string; - if (this._authority && this.scheme === 'file') { - // unc path: file://shares/c$/far/boo - value = `//${this._authority}${this._path}`; - } else if (URI._driveLetterPath.test(this._path)) { - // windows drive letter: file:///c:/far/boo - value = this._path[1].toLowerCase() + this._path.substr(2); - } else { - // other path - value = this._path; - } - if (process.platform === 'win32') { - value = value.replace(/\//g, '\\'); - } - this._fsPath = value; - } - return this._fsPath; - } - - // ---- modify to new ------------------------- - - public with(scheme: string, authority: string, path: string, query: string, fragment: string): URI { - var ret = new URI(); - ret._scheme = scheme || this.scheme; - ret._authority = authority || this.authority; - ret._path = path || this.path; - ret._query = query || this.query; - ret._fragment = fragment || this.fragment; - URI._validate(ret); - return ret; - } - - public withScheme(value: string): URI { - return this.with(value, undefined, undefined, undefined, undefined); - } - - public withAuthority(value: string): URI { - return this.with(undefined, value, undefined, undefined, undefined); - } - - public withPath(value: string): URI { - return this.with(undefined, undefined, value, undefined, undefined); - } - - public withQuery(value: string): URI { - return this.with(undefined, undefined, undefined, value, undefined); - } - - public withFragment(value: string): URI { - return this.with(undefined, undefined, undefined, undefined, value); - } - - // ---- parse & validate ------------------------ - - public static parse(value: string): URI { - const ret = new URI(); - const data = URI._parseComponents(value); - ret._scheme = data.scheme; - ret._authority = decodeURIComponent(data.authority); - ret._path = decodeURIComponent(data.path); - ret._query = decodeURIComponent(data.query); - ret._fragment = decodeURIComponent(data.fragment); - URI._validate(ret); - return ret; - } - - public static file(path: string): URI { - - const ret = new URI(); - ret._scheme = 'file'; - - // normalize to fwd-slashes - path = path.replace(/\\/g, URI._slash); - - // check for authority as used in UNC shares - // or use the path as given - if (path[0] === URI._slash && path[0] === path[1]) { - let idx = path.indexOf(URI._slash, 2); - if (idx === -1) { - ret._authority = path.substring(2); - } else { - ret._authority = path.substring(2, idx); - ret._path = path.substring(idx); - } - } else { - ret._path = path; - } - - // Ensure that path starts with a slash - // or that it is at least a slash - if (ret._path[0] !== URI._slash) { - ret._path = URI._slash + ret._path; - } - - URI._validate(ret); - - return ret; - } - - private static _parseComponents(value: string): UriComponents { - - const ret: UriComponents = { - scheme: URI._empty, - authority: URI._empty, - path: URI._empty, - query: URI._empty, - fragment: URI._empty, - }; - - const match = URI._regexp.exec(value); - if (match) { - ret.scheme = match[2] || ret.scheme; - ret.authority = match[4] || ret.authority; - ret.path = match[5] || ret.path; - ret.query = match[7] || ret.query; - ret.fragment = match[9] || ret.fragment; - } - return ret; - } - - public static create(scheme?: string, authority?: string, path?: string, query?: string, fragment?: string): URI { - return new URI().with(scheme, authority, path, query, fragment); - } - - private static _validate(ret: URI): void { - - // validation - // path, http://tools.ietf.org/html/rfc3986#section-3.3 - // If a URI contains an authority component, then the path component - // must either be empty or begin with a slash ("/") character. If a URI - // does not contain an authority component, then the path cannot begin - // with two slash characters ("//"). - if (ret.authority && ret.path && ret.path[0] !== '/') { - throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character'); - } - if (!ret.authority && ret.path.indexOf('//') === 0) { - throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")'); - } - } - - // ---- printing/externalize --------------------------- - - /** - * - * @param skipEncoding Do not encode the result, default is `false` - */ - public toString(skipEncoding: boolean = false): string { - if (!skipEncoding) { - if (!this._formatted) { - this._formatted = URI._asFormatted(this, false); - } - return this._formatted; - } else { - // we don't cache that - return URI._asFormatted(this, true); - } - } - - private static _asFormatted(uri: URI, skipEncoding: boolean): string { - - const encoder = !skipEncoding - ? encodeURIComponent2 - : encodeNoop; - - const parts: string[] = []; - - let { scheme, authority, path, query, fragment } = uri; - if (scheme) { - parts.push(scheme, ':'); - } - if (authority || scheme === 'file') { - parts.push('//'); - } - if (authority) { - authority = authority.toLowerCase(); - let idx = authority.indexOf(':'); - if (idx === -1) { - parts.push(encoder(authority)); - } else { - parts.push(encoder(authority.substr(0, idx)), authority.substr(idx)); - } - } - if (path) { - // lower-case windown drive letters in /C:/fff - const m = URI._upperCaseDrive.exec(path); - if (m) { - path = m[1] + m[2].toLowerCase() + path.substr(m[1].length + m[2].length); - } - - // encode every segement but not slashes - // make sure that # and ? are always encoded - // when occurring in paths - otherwise the result - // cannot be parsed back again - let lastIdx = 0; - while (true) { - let idx = path.indexOf(URI._slash, lastIdx); - if (idx === -1) { - parts.push(encoder(path.substring(lastIdx)).replace(/[#?]/, _encode)); - break; - } - parts.push(encoder(path.substring(lastIdx, idx)).replace(/[#?]/, _encode), URI._slash); - lastIdx = idx + 1; - }; - } - if (query) { - parts.push('?', encoder(query)); - } - if (fragment) { - parts.push('#', encoder(fragment)); - } - - return parts.join(URI._empty); - } - - public toJSON(): any { - return { - scheme: this.scheme, - authority: this.authority, - path: this.path, - fsPath: this.fsPath, - query: this.query, - fragment: this.fragment, - external: this.toString(), - $mid: 1 - }; - } -} - -interface UriComponents { - scheme: string; - authority: string; - path: string; - query: string; - fragment: string; -} - -interface UriState extends UriComponents { - $mid: number; - fsPath: string; - external: string; -}