This commit is contained in:
Martin Aeschlimann 2020-09-28 12:22:15 +02:00
Родитель c7ef079610
Коммит b50824bd98
9 изменённых файлов: 3722 добавлений и 129 удалений

Просмотреть файл

@ -6,3 +6,4 @@ spec
tsconfig.json
.mocharc.json
.travis.yml
webpack.config.js

25
.vscode/launch.json поставляемый Normal file
Просмотреть файл

@ -0,0 +1,25 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Unit tests",
"skipFiles": [
"<node_internals>/**"
],
"program": "${workspaceRoot}/node_modules/mocha/bin/_mocha",
"args": [
"--timeout",
"999999",
"--colors"
],
"outFiles": [
"${workspaceRoot}/lib/umd/**"
],
}
]
}

3519
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -6,10 +6,13 @@
"main": "./lib/umd/index.js",
"typings": "./lib/umd/index",
"module": "./lib/esm/index.js",
"sideEffects": false,
"scripts": {
"compile": "tsc -p ./src && tsc -p ./src/tsconfig.esm.json",
"prepublish": "npm run test",
"test": "npm run compile && mocha"
"clean": "rimraf lib",
"pack-production": "webpack --mode=production",
"pack-dev": "webpack --mode=production",
"prepublish": "npm run test && npm run clean && npm run pack-production",
"test": "tsc -p ./src && npm run pack-dev && mocha"
},
"repository": {
"type": "git",
@ -21,9 +24,14 @@
},
"homepage": "https://github.com/Microsoft/vscode-uri#readme",
"devDependencies": {
"@purtuga/esm-webpack-plugin": "^1.4.0",
"@types/mocha": "^8.0.3",
"@types/node": "^10.12.21",
"typescript": "^3.6.4",
"mocha": "8.1.3"
"mocha": "8.1.3",
"rimraf": "^3.0.2",
"ts-loader": "^8.0.4",
"typescript": "^4.0.3",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12"
}
}

Просмотреть файл

@ -9,6 +9,9 @@
// https://github.com/Microsoft/vscode/blob/master/src/vs/base/common/platform.ts
// https://github.com/Microsoft/vscode/blob/master/src/vs/base/common/charCode.ts
import * as nodePath from 'path';
const posixPath = nodePath.posix || nodePath;
declare const process: { platform: 'win32' };
declare const navigator: { userAgent: string };
let isWindows: boolean;
@ -1147,122 +1150,75 @@ function percentDecode(str: string): string {
}
/**
* Resolves a path against the path of a URI.
* In the paths '/' is recognized as the directory separation character.
* Resolves one or more paths against the path of a URI.
* '/' is used as the directory separation character.
*
* If the path is absolute (starting with '/'), the resolved path will be equal to the absolute path.
* If the path is not absolute, the resolved path will be a join of URI path and the input path.
*
* The resolved path is normalized:
* The resolved path will be normalized. That means:
* - all '..' and '.' segments are resolved.
* - multiple, sequential occurences of '/' are replaced by a single instance of '/'.
* - trailing separators are preserved.
* - trailing separators are removed.
*
* @param uri The input URI
* @param path The path to resolve against the path of URI
* @returns A URI with the resolved path. All other properties of the URI (scheme, authority, query, fragments, ...) will be copied from the input URI.
* @param uri The input URI.
* @param paths The paths to resolve against the path of URI.
* @returns A URI with the resolved path. All other properties of the URI (scheme, authority, query, fragments, ...) will be taken from the input URI.
*/
export function resolvePath(uri: URI, path: string): URI {
if (isAbsolutePath(path)) {
return uri.with({ path: normalizePath(path.split('/')) });
}
return joinPath(uri, path);
export function resolvePath(uri: URI, ...paths: string[]): URI {
return uri.with({ path: posixPath.resolve(uri.path, ...paths) });
}
/**
* Joins one or more input paths to the path of URI.
* In the paths '/' is recognized as the directory separation character.
* '/' is used as the directory separation character.
*
* The resolved path is normalized:
* The resolved path will be normalized. That means:
* - all '..' and '.' segments are resolved.
* - multiple, sequential occurences of '/' are replaced by a single instance of '/'.
* - trailing separators are preserved.
*
* @param uri The input URI
* @param paths The paths to be join with the path of URI
* @returns A URI with the joined path. All other properties of the URI (scheme, authority, query, fragments, ...) will be copied from the input URI.
* @param uri The input URI.
* @param paths The paths to be joined with the path of URI.
* @returns A URI with the joined path. All other properties of the URI (scheme, authority, query, fragments, ...) will be taken from the input URI.
*/
export function joinPath(uri: URI, ...paths: string[]): URI {
const parts = uri.path.split('/');
for (let path of paths) {
parts.push(...path.split('/'));
}
return uri.with({ path: normalizePath(parts) });
return uri.with({ path: posixPath.join(uri.path, ...paths) });
}
function isAbsolutePath(path: string) {
return path.charCodeAt(0) === CharCode.Slash;
}
function normalizePath(parts: string[]): string {
const newParts: string[] = [];
for (const part of parts) {
if (part.length === 0 || part.length === 1 && part.charCodeAt(0) === CharCode.Period) {
// ignore
} else if (part.length === 2 && part.charCodeAt(0) === CharCode.Period && part.charCodeAt(1) === CharCode.Period) {
newParts.pop();
} else {
newParts.push(part);
}
}
if (parts.length > 1 && parts[parts.length - 1].length === 0) {
newParts.push('');
}
let res = newParts.join('/');
if (parts[0].length === 0) {
res = '/' + res;
}
return res;
}
/**
* Returns the last segment of the path of a URI, similar to the Unix dirname command.
* Returns a URI where the path is the directory name of the input uri, similar to the Unix dirname command.
* In the path, '/' is recognized as the directory separation character. Trailing directory separators are ignored.
* The empty string is returned if the URI's path is empty or does not contain any path segments.
* The orignal URI is returned if the URIs path is empty or does not contain any path segments.
*
* @param uri The input URI
* @return The last segment of the URIs path
* @param uri The input URI.
* @return The last segment of the URIs path.
*/
export function dirname(uri: URI): URI {
let path = posixPath.dirname(uri.path);
if (path.length === 1 && path.charCodeAt(0) === CharCode.Period) {
return uri;
}
return uri.with({ path });
}
/**
* Returns the last segment of the path of a URI, similar to the Unix basename command.
* In the path, '/' is recognized as the directory separation character. Trailing directory separators are ignored.
* The empty string is returned if the URIs path is empty or does not contain any path segments.
*
* @param uri The input URI.
* @return The base name of the URIs path.
*/
export function basename(uri: URI): string {
const path = uri.path;
let lastSlash = path.length;
for (let i = path.length - 1; i >= 0; i--) {
const ch = path.charCodeAt(i);
if (ch === CharCode.Slash) {
if (i < lastSlash - 1) {
return path.substring(i + 1, lastSlash);
}
lastSlash = i;
}
}
return '';
return posixPath.basename(uri.path);
}
/**
* Returns the extension name of the path of a URI, similar to the Unix extname command.
* In the path, '/' is recognized as the directory separation character. Trailing directory separators are ignored.
* The empty string is returned if the URI's path is empty or does not contain any path segments.
* The empty string is returned if the URIs path is empty or does not contain any path segments.
*
* @param uri The input URI
* @param uri The input URI.
* @return The extension name of the URIs path.
*/
export function extname(uri: URI) : string {
const path = uri.path;
let lastSlash = path.length;
for (let i = path.length - 1; i >= 0; i--) {
const ch = path.charCodeAt(i);
if (ch === CharCode.Period) {
if (i > 0 && path.charCodeAt(i - 1) !== CharCode.Slash) {
return path.substring(i, lastSlash);
} else {
break;
}
} else if (ch === CharCode.Slash) {
if (i < lastSlash - 1) {
// there was content, but no dot
break;
}
lastSlash = i;
}
}
return '';
export function extname(uri: URI): string {
return posixPath.extname(uri.path);
}

Просмотреть файл

@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import { joinPath, resolvePath, extname, basename, URI } from '../index';
import { joinPath, resolvePath, extname, basename, dirname, URI } from '../index';
import { posix } from 'path';
suite('URI path operations', () => {
test('join', async function () {
function assertJoin(uri: string, paths: string[], expected: string, verifyAgainstNodeJS = true) {
const testUri = URI.parse(uri);
const testUri = URI.parse(uri);
assert.strictEqual(joinPath(testUri, ...paths).toString(), expected, uri);
if (verifyAgainstNodeJS) {
assert.strictEqual(posix.join(testUri.path || '/', ...paths), URI.parse(expected).path, testUri.path + ' (nodejs)');
@ -28,7 +28,7 @@ suite('URI path operations', () => {
test('resolve', async function () {
function assertResolve(uri: string, path: string, expected: string, verifyAgainstNodeJS = true) {
const testUri = URI.parse(uri);
const testUri = URI.parse(uri);
assert.strictEqual(resolvePath(testUri, path).toString(), expected, uri);
if (verifyAgainstNodeJS) {
assert.strictEqual(posix.resolve(testUri.path || '/', path), URI.parse(expected).path, testUri.path + ' (nodejs)');
@ -37,10 +37,10 @@ suite('URI path operations', () => {
assertResolve('foo://a/foo/bar', 'x', 'foo://a/foo/bar/x');
assertResolve('foo://a/foo/bar/', 'x', 'foo://a/foo/bar/x');
assertResolve('foo://a/foo/bar/', '/x', 'foo://a/x');
assertResolve('foo://a/foo/bar/', 'x/', 'foo://a/foo/bar/x/', false /*NodeJS removes trailing sep*/);
assertResolve('foo://a', 'x/', 'foo://a/x/', false /*NodeJS removes trailing sep*/);
assertResolve('foo://a', '/x/', 'foo://a/x/', false /*NodeJS removes trailing sep*/);
assertResolve('foo://a/foo/bar/', 'x/', 'foo://a/foo/bar/x');
assertResolve('foo://a', 'x/', 'foo://a/x');
assertResolve('foo://a', '/x/', 'foo://a/x');
assertResolve('foo://a/b', '/x/..//y/.', 'foo://a/y');
assertResolve('foo://a/b', 'x/..//y/.', 'foo://a/b/y');
@ -48,12 +48,12 @@ suite('URI path operations', () => {
test('normalize', async function () {
function assertNormalize(path: string, expected: string, verifyAgainstNodeJS = true) {
let testUri = URI.from({scheme: 'foo', path, authority: path.startsWith('/') ? 'bar' : undefined});
const actual = joinPath(testUri).path;
let testUri = URI.from({ scheme: 'foo', path, authority: path.startsWith('/') ? 'bar' : undefined });
const actual = joinPath(testUri).path;
assert.strictEqual(actual, expected, path);
if (verifyAgainstNodeJS) {
assert.strictEqual(posix.normalize(path), expected, path + ' (nodejs)');
}
}
}
assertNormalize('a', 'a');
assertNormalize('/a', '/a');
@ -67,7 +67,7 @@ suite('URI path operations', () => {
assertNormalize('a/foo/bar/x//', 'a/foo/bar/x/');
assertNormalize('//a/foo/bar/x//', '/a/foo/bar/x/');
assertNormalize('a/.', 'a');
assertNormalize('a/..', '', false /*NodeJS uses .*/);
assertNormalize('a/..', '.');
assertNormalize('a/./b', 'a/b');
assertNormalize('a/././b', 'a/b');
assertNormalize('a/n/../b', 'a/b');
@ -75,15 +75,17 @@ suite('URI path operations', () => {
assertNormalize('a/n/../', 'a/');
assertNormalize('/a/n/../..', '/');
assertNormalize('/a/n/../../..', '/');
assertNormalize('..', '', false /*NodeJS keeps ..*/);
assertNormalize('..', '..');
assertNormalize('/..', '/');
});
test('extname', async function () {
function assertExtName(input: string, expected: string) {
const testUri = URI.parse(input);
function assertExtName(input: string, expected: string, verifyAgainstNodeJS = true) {
const testUri = URI.parse(input);
assert.strictEqual(extname(testUri), expected, input);
assert.strictEqual(posix.extname(input), expected, input + ' (nodejs)');
if (verifyAgainstNodeJS) {
assert.strictEqual(posix.extname(input), expected, input + ' (nodejs)');
}
}
assertExtName('foo://a/foo/bar', '');
assertExtName('foo://a/foo/bar.foo', '.foo');
@ -94,10 +96,12 @@ suite('URI path operations', () => {
});
test('basename', () => {
function assertBasename(input: string, expected: string) {
const testUri = URI.parse(input);
function assertBasename(input: string, expected: string, verifyAgainstNodeJS = true) {
const testUri = URI.parse(input);
assert.strictEqual(basename(testUri), expected, input);
assert.strictEqual(posix.basename(testUri.path), expected, input + ' (nodejs)');
if (verifyAgainstNodeJS) {
assert.strictEqual(posix.basename(testUri.path), expected, input + ' (nodejs)');
}
}
assertBasename('foo://a/some/file/test.txt', 'test.txt');
@ -108,5 +112,23 @@ suite('URI path operations', () => {
assertBasename('foo://a/', '');
assertBasename('foo://a', '');
});
test('dirname', () => {
function assertDirname(input: string, expected: string, verifyAgainstNodeJS = true) {
const testUri = URI.parse(input);
assert.strictEqual(dirname(testUri).toString(), expected, input);
if (verifyAgainstNodeJS) {
assert.strictEqual(posix.dirname(testUri.path), URI.parse(expected).path, input + ' (nodejs)');
}
}
assertDirname('foo://a/some/file/test.txt', 'foo://a/some/file');
assertDirname('foo://a/some/file/', 'foo://a/some');
assertDirname('foo://a/some/file///', 'foo://a/some');
assertDirname('foo://a/some/file', 'foo://a/some');
assertDirname('foo://a/some', 'foo://a/');
assertDirname('foo://a/', 'foo://a/');
assertDirname('foo://a', 'foo://a', false);
assertDirname('foo://', 'foo:', false);
});
});

Просмотреть файл

@ -1,13 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"declaration": true,
"forceConsistentCasingInFileNames": true,
"noImplicitAny": true,
"module": "es6",
"lib": [
"es2015"
],
"outDir": "../lib/esm"
}
}

Просмотреть файл

@ -4,7 +4,6 @@
"declaration": true,
"forceConsistentCasingInFileNames": true,
"noImplicitAny": true,
"module": "umd",
"lib": [
"es2015"
],

84
webpack.config.js Normal file
Просмотреть файл

@ -0,0 +1,84 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path = require('path');
const EsmWebpackPlugin = require('@purtuga/esm-webpack-plugin');
module.exports = [
// UMD
{
mode: 'none',
entry: './src/index.ts',
resolve: {
mainFields: ['module', 'main'],
extensions: ['.ts', '.js'] // support ts-files and js-files
},
output: {
libraryTarget: 'umd',
globalObject: 'this',
path: path.resolve(__dirname, 'lib', 'umd'),
filename: 'index.js'
},
module: {
rules: [{
test: /\.ts$/,
exclude: /node_modules/,
use: [{
// configure TypeScript loader:
// * enable sources maps for end-to-end source maps
loader: 'ts-loader',
options: {
compilerOptions: {
'sourceMap': true,
}
}
}]
}]
},
devtool: 'source-map'
},
// ESM
{
mode: 'none',
entry: './src/index.ts',
resolve: {
mainFields: ['module', 'main'],
extensions: ['.ts', '.js'] // support ts-files and js-files
},
output: {
library: 'LIB',
libraryTarget: 'var',
path: path.resolve(__dirname, 'lib', 'esm'),
filename: 'index.js'
},
module: {
rules: [{
test: /\.ts$/,
exclude: /node_modules/,
use: [{
// configure TypeScript loader:
// * enable sources maps for end-to-end source maps
loader: 'ts-loader',
options: {
compilerOptions: {
sourceMap: true,
target: 'es5',
forceConsistentCasingInFileNames: true,
noImplicitAny: true,
module: 'es6',
lib: [
'es2015'
]
}
}
}]
}]
},
devtool: 'source-map',
plugins: [
new EsmWebpackPlugin()
]
}
]