<commit_before>/*---------------------------------------------------------------------------------------------
 *  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 marshalling = require('vs/base/common/marshalling');
import platform = require('vs/base/common/platform');

// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
function fixedEncodeURIComponent(str: string): string {
	return encodeURIComponent(str).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase());
}

/**
 * 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 _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
	private static _driveLetterPath = /^\/[a-zA-z]:/;
	private static _driveLetter = /^[a-zA-z]:/;

	private _scheme: string;
	private _authority: string;
	private _path: string;
	private _query: string;
	private _fragment: string;

	constructor() {
		this._scheme = URI._empty;
		this._authority = URI._empty;
		this._path = URI._empty;
		this._query = URI._empty;
		this._fragment = URI._empty;
	}

	/**
	 * 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 -----------------------

	private _fsPath: string;

	/**
	 * 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 (platform.isWindows) {
				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 {
		var ret = URI._parse(value);
		ret = ret.with(undefined,
			decodeURIComponent(ret.authority),
			decodeURIComponent(ret.path),
			decodeURIComponent(ret.query),
			decodeURIComponent(ret.fragment));

		return ret;
	}

	public static file(path: string): URI {
		path = path.replace(/\\/g, '/');
		path = path.replace(/%/g, '%25');
		path = path.replace(/#/g, '%23');
		path = path.replace(/\?/g, '%3F');
		path = URI._driveLetter.test(path)
			? '/' + path
			: path;

		var ret = URI._parse(path);
		if (ret.scheme || ret.fragment || ret.query) {
			throw new Error();
		}

		ret = ret.with('file', undefined,
			decodeURIComponent(ret.path),
			undefined, undefined);

		return ret;
	}

	private static _parse(value: string): URI {
		var ret = new URI();
		var 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;
		};
		URI._validate(ret);
		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);<commit_msg>uri: improve error message when can not convert to file uri.<commit_after>/*---------------------------------------------------------------------------------------------
 *  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 marshalling = require('vs/base/common/marshalling');
import platform = require('vs/base/common/platform');

// see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
function fixedEncodeURIComponent(str: string): string {
	return encodeURIComponent(str).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase());
}

/**
 * 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 _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
	private static _driveLetterPath = /^\/[a-zA-z]:/;
	private static _driveLetter = /^[a-zA-z]:/;

	private _scheme: string;
	private _authority: string;
	private _path: string;
	private _query: string;
	private _fragment: string;

	constructor() {
		this._scheme = URI._empty;
		this._authority = URI._empty;
		this._path = URI._empty;
		this._query = URI._empty;
		this._fragment = URI._empty;
	}

	/**
	 * 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 -----------------------

	private _fsPath: string;

	/**
	 * 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 (platform.isWindows) {
				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 {
		var ret = URI._parse(value);
		ret = ret.with(undefined,
			decodeURIComponent(ret.authority),
			decodeURIComponent(ret.path),
			decodeURIComponent(ret.query),
			decodeURIComponent(ret.fragment));

		return ret;
	}

	public static file(path: string): URI {
		path = path.replace(/\\/g, '/');
		path = path.replace(/%/g, '%25');
		path = path.replace(/#/g, '%23');
		path = path.replace(/\?/g, '%3F');
		path = URI._driveLetter.test(path)
			? '/' + path
			: path;

		var ret = URI._parse(path);
		if (ret.scheme || ret.fragment || ret.query) {
			throw new Error(`Path ${ path } contains a scheme, fragment or a query. Can not convert it to a file uri.`);
		}

		ret = ret.with('file', undefined,
			decodeURIComponent(ret.path),
			undefined, undefined);

		return ret;
	}

	private static _parse(value: string): URI {
		var ret = new URI();
		var 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;
		};
		URI._validate(ret);
		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);
{'fraction_non_alphanumeric': 0.19499061760626582, 'fraction_numerical': 0.004568817818389492, 'mean_word_length': 2.683293269230769, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 2, 'lorem ipsum': 0, 'www.': 12, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5868938', 'n_tokens_mistral': 4119, 'n_tokens_neox': 3759, 'n_words': 973}