@speclynx/apidom-reference 6.1.2 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +12 -0
- package/dist/apidom-reference.browser.js +1073 -254
- package/dist/apidom-reference.browser.min.js +1 -1
- package/package.json +30 -30
- package/src/bundle/index.cjs +6 -4
- package/src/bundle/index.mjs +6 -4
- package/src/dereference/index.cjs +8 -5
- package/src/dereference/index.mjs +8 -5
- package/src/options/index.cjs +4 -0
- package/src/options/index.mjs +4 -0
- package/src/options/util.cjs +7 -1
- package/src/options/util.mjs +8 -2
- package/src/resolve/index.cjs +6 -3
- package/src/resolve/index.mjs +6 -3
- package/src/util/url.cjs +38 -8
- package/src/util/url.mjs +35 -6
- package/types/apidom-reference.d.ts +13 -0
- package/types/util/url.d.ts +11 -0
- package/LICENSES/AFL-3.0.txt +0 -182
- package/LICENSES/BSD-3-Clause.txt +0 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@speclynx/apidom-reference",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.2.0",
|
|
4
4
|
"description": "Advanced algorithms for semantic ApiDOM manipulations like dereferencing or resolution.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"apidom",
|
|
@@ -299,35 +299,35 @@
|
|
|
299
299
|
"author": "Vladimir Gorej",
|
|
300
300
|
"license": "Apache-2.0",
|
|
301
301
|
"dependencies": {
|
|
302
|
-
"@babel/runtime-corejs3": "^8.0
|
|
303
|
-
"@speclynx/apidom-core": "6.
|
|
304
|
-
"@speclynx/apidom-datamodel": "6.
|
|
305
|
-
"@speclynx/apidom-error": "6.
|
|
306
|
-
"@speclynx/apidom-json-pointer": "6.
|
|
307
|
-
"@speclynx/apidom-ns-arazzo-1": "6.
|
|
308
|
-
"@speclynx/apidom-ns-asyncapi-2": "6.
|
|
309
|
-
"@speclynx/apidom-ns-json-schema-2020-12": "6.
|
|
310
|
-
"@speclynx/apidom-ns-openapi-2": "6.
|
|
311
|
-
"@speclynx/apidom-ns-openapi-3-0": "6.
|
|
312
|
-
"@speclynx/apidom-ns-openapi-3-1": "6.
|
|
313
|
-
"@speclynx/apidom-ns-overlay-1": "6.
|
|
314
|
-
"@speclynx/apidom-parser-adapter-arazzo-json-1": "6.
|
|
315
|
-
"@speclynx/apidom-parser-adapter-arazzo-yaml-1": "6.
|
|
316
|
-
"@speclynx/apidom-parser-adapter-asyncapi-json-2": "6.
|
|
317
|
-
"@speclynx/apidom-parser-adapter-asyncapi-yaml-2": "6.
|
|
318
|
-
"@speclynx/apidom-parser-adapter-json": "6.
|
|
319
|
-
"@speclynx/apidom-parser-adapter-openapi-json-2": "6.
|
|
320
|
-
"@speclynx/apidom-parser-adapter-openapi-json-3-0": "6.
|
|
321
|
-
"@speclynx/apidom-parser-adapter-openapi-json-3-1": "6.
|
|
322
|
-
"@speclynx/apidom-parser-adapter-openapi-yaml-2": "6.
|
|
323
|
-
"@speclynx/apidom-parser-adapter-openapi-yaml-3-0": "6.
|
|
324
|
-
"@speclynx/apidom-parser-adapter-openapi-yaml-3-1": "6.
|
|
325
|
-
"@speclynx/apidom-parser-adapter-overlay-json-1": "6.
|
|
326
|
-
"@speclynx/apidom-parser-adapter-overlay-yaml-1": "6.
|
|
327
|
-
"@speclynx/apidom-parser-adapter-yaml-1-2": "6.
|
|
328
|
-
"@speclynx/apidom-traverse": "6.
|
|
302
|
+
"@babel/runtime-corejs3": "^8.1.0",
|
|
303
|
+
"@speclynx/apidom-core": "6.2.0",
|
|
304
|
+
"@speclynx/apidom-datamodel": "6.2.0",
|
|
305
|
+
"@speclynx/apidom-error": "6.2.0",
|
|
306
|
+
"@speclynx/apidom-json-pointer": "6.2.0",
|
|
307
|
+
"@speclynx/apidom-ns-arazzo-1": "6.2.0",
|
|
308
|
+
"@speclynx/apidom-ns-asyncapi-2": "6.2.0",
|
|
309
|
+
"@speclynx/apidom-ns-json-schema-2020-12": "6.2.0",
|
|
310
|
+
"@speclynx/apidom-ns-openapi-2": "6.2.0",
|
|
311
|
+
"@speclynx/apidom-ns-openapi-3-0": "6.2.0",
|
|
312
|
+
"@speclynx/apidom-ns-openapi-3-1": "6.2.0",
|
|
313
|
+
"@speclynx/apidom-ns-overlay-1": "6.2.0",
|
|
314
|
+
"@speclynx/apidom-parser-adapter-arazzo-json-1": "6.2.0",
|
|
315
|
+
"@speclynx/apidom-parser-adapter-arazzo-yaml-1": "6.2.0",
|
|
316
|
+
"@speclynx/apidom-parser-adapter-asyncapi-json-2": "6.2.0",
|
|
317
|
+
"@speclynx/apidom-parser-adapter-asyncapi-yaml-2": "6.2.0",
|
|
318
|
+
"@speclynx/apidom-parser-adapter-json": "6.2.0",
|
|
319
|
+
"@speclynx/apidom-parser-adapter-openapi-json-2": "6.2.0",
|
|
320
|
+
"@speclynx/apidom-parser-adapter-openapi-json-3-0": "6.2.0",
|
|
321
|
+
"@speclynx/apidom-parser-adapter-openapi-json-3-1": "6.2.0",
|
|
322
|
+
"@speclynx/apidom-parser-adapter-openapi-yaml-2": "6.2.0",
|
|
323
|
+
"@speclynx/apidom-parser-adapter-openapi-yaml-3-0": "6.2.0",
|
|
324
|
+
"@speclynx/apidom-parser-adapter-openapi-yaml-3-1": "6.2.0",
|
|
325
|
+
"@speclynx/apidom-parser-adapter-overlay-json-1": "6.2.0",
|
|
326
|
+
"@speclynx/apidom-parser-adapter-overlay-yaml-1": "6.2.0",
|
|
327
|
+
"@speclynx/apidom-parser-adapter-yaml-1-2": "6.2.0",
|
|
328
|
+
"@speclynx/apidom-traverse": "6.2.0",
|
|
329
329
|
"@swaggerexpert/arazzo-runtime-expression": "^3.2.0",
|
|
330
|
-
"axios": "^1.
|
|
330
|
+
"axios": "^1.21.0",
|
|
331
331
|
"picomatch": "^4.0.7",
|
|
332
332
|
"ramda": "~0.32.0",
|
|
333
333
|
"ramda-adjunct": "^6.1.0"
|
|
@@ -346,5 +346,5 @@
|
|
|
346
346
|
"README.md",
|
|
347
347
|
"CHANGELOG.md"
|
|
348
348
|
],
|
|
349
|
-
"gitHead": "
|
|
349
|
+
"gitHead": "13bd86fba1e6c36dd97423e195c48994901c5422"
|
|
350
350
|
}
|
package/src/bundle/index.cjs
CHANGED
|
@@ -22,20 +22,22 @@ const bundle = async (uri, options) => {
|
|
|
22
22
|
const {
|
|
23
23
|
refSet
|
|
24
24
|
} = options.bundle;
|
|
25
|
-
|
|
25
|
+
// strategies look up same-document references by a resolved, hence normalized, URI;
|
|
26
|
+
// the file is parsed as a whole document, so its URI has no fragment
|
|
27
|
+
const baseURI = url.normalize(url.stripHash(uri));
|
|
26
28
|
const mergedOptions = (0, _util.merge)(options, {
|
|
27
29
|
resolve: {
|
|
28
|
-
baseURI
|
|
30
|
+
baseURI
|
|
29
31
|
}
|
|
30
32
|
});
|
|
31
33
|
let parseResult;
|
|
32
34
|
|
|
33
35
|
// if refSet was provided, use it to avoid unnecessary parsing
|
|
34
|
-
if (refSet !== null && refSet.has(
|
|
36
|
+
if (refSet !== null && refSet.has(baseURI)) {
|
|
35
37
|
// @ts-ignore
|
|
36
38
|
({
|
|
37
39
|
value: parseResult
|
|
38
|
-
} = refSet.find((0, _ramda.propEq)(
|
|
40
|
+
} = refSet.find((0, _ramda.propEq)(baseURI, 'uri')));
|
|
39
41
|
} else {
|
|
40
42
|
parseResult = await (0, _index.default)(uri, mergedOptions);
|
|
41
43
|
}
|
package/src/bundle/index.mjs
CHANGED
|
@@ -14,20 +14,22 @@ const bundle = async (uri, options) => {
|
|
|
14
14
|
const {
|
|
15
15
|
refSet
|
|
16
16
|
} = options.bundle;
|
|
17
|
-
|
|
17
|
+
// strategies look up same-document references by a resolved, hence normalized, URI;
|
|
18
|
+
// the file is parsed as a whole document, so its URI has no fragment
|
|
19
|
+
const baseURI = url.normalize(url.stripHash(uri));
|
|
18
20
|
const mergedOptions = mergeOptions(options, {
|
|
19
21
|
resolve: {
|
|
20
|
-
baseURI
|
|
22
|
+
baseURI
|
|
21
23
|
}
|
|
22
24
|
});
|
|
23
25
|
let parseResult;
|
|
24
26
|
|
|
25
27
|
// if refSet was provided, use it to avoid unnecessary parsing
|
|
26
|
-
if (refSet !== null && refSet.has(
|
|
28
|
+
if (refSet !== null && refSet.has(baseURI)) {
|
|
27
29
|
// @ts-ignore
|
|
28
30
|
({
|
|
29
31
|
value: parseResult
|
|
30
|
-
} = refSet.find(propEq(
|
|
32
|
+
} = refSet.find(propEq(baseURI, 'uri')));
|
|
31
33
|
} else {
|
|
32
34
|
parseResult = await parse(uri, mergedOptions);
|
|
33
35
|
}
|
|
@@ -31,8 +31,10 @@ const dereferenceApiDOM = async (element, options) => {
|
|
|
31
31
|
parseResult = new _apidomDatamodel.ParseResultElement([elementClone]);
|
|
32
32
|
surrogateWrapping = true;
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
// strategies look up same-document references by a resolved, hence normalized, URI
|
|
34
36
|
const file = new _File.default({
|
|
35
|
-
uri: options.resolve.baseURI,
|
|
37
|
+
uri: url.normalize(options.resolve.baseURI),
|
|
36
38
|
parseResult,
|
|
37
39
|
mediaType: options.parse.mediaType
|
|
38
40
|
});
|
|
@@ -66,21 +68,22 @@ const dereference = async (uri, options) => {
|
|
|
66
68
|
const {
|
|
67
69
|
refSet
|
|
68
70
|
} = options.dereference;
|
|
69
|
-
|
|
71
|
+
// the file is parsed as a whole document, so its URI has no fragment
|
|
72
|
+
const baseURI = url.normalize(url.stripHash(uri));
|
|
70
73
|
let parseResult;
|
|
71
74
|
|
|
72
75
|
// if refSet was provided, use it to avoid unnecessary parsing
|
|
73
|
-
if (refSet !== null && refSet.has(
|
|
76
|
+
if (refSet !== null && refSet.has(baseURI)) {
|
|
74
77
|
// @ts-ignore
|
|
75
78
|
({
|
|
76
79
|
value: parseResult
|
|
77
|
-
} = refSet.find((0, _ramda.propEq)(
|
|
80
|
+
} = refSet.find((0, _ramda.propEq)(baseURI, 'uri')));
|
|
78
81
|
} else {
|
|
79
82
|
parseResult = await (0, _index.default)(uri, options);
|
|
80
83
|
}
|
|
81
84
|
const mergedOptions = (0, _util.merge)(options, {
|
|
82
85
|
resolve: {
|
|
83
|
-
baseURI
|
|
86
|
+
baseURI
|
|
84
87
|
},
|
|
85
88
|
dereference: {
|
|
86
89
|
// if refSet was not provided, then we can work in mutable mode
|
|
@@ -23,8 +23,10 @@ export const dereferenceApiDOM = async (element, options) => {
|
|
|
23
23
|
parseResult = new ParseResultElement([elementClone]);
|
|
24
24
|
surrogateWrapping = true;
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
// strategies look up same-document references by a resolved, hence normalized, URI
|
|
26
28
|
const file = new File({
|
|
27
|
-
uri: options.resolve.baseURI,
|
|
29
|
+
uri: url.normalize(options.resolve.baseURI),
|
|
28
30
|
parseResult,
|
|
29
31
|
mediaType: options.parse.mediaType
|
|
30
32
|
});
|
|
@@ -57,21 +59,22 @@ const dereference = async (uri, options) => {
|
|
|
57
59
|
const {
|
|
58
60
|
refSet
|
|
59
61
|
} = options.dereference;
|
|
60
|
-
|
|
62
|
+
// the file is parsed as a whole document, so its URI has no fragment
|
|
63
|
+
const baseURI = url.normalize(url.stripHash(uri));
|
|
61
64
|
let parseResult;
|
|
62
65
|
|
|
63
66
|
// if refSet was provided, use it to avoid unnecessary parsing
|
|
64
|
-
if (refSet !== null && refSet.has(
|
|
67
|
+
if (refSet !== null && refSet.has(baseURI)) {
|
|
65
68
|
// @ts-ignore
|
|
66
69
|
({
|
|
67
70
|
value: parseResult
|
|
68
|
-
} = refSet.find(propEq(
|
|
71
|
+
} = refSet.find(propEq(baseURI, 'uri')));
|
|
69
72
|
} else {
|
|
70
73
|
parseResult = await parse(uri, options);
|
|
71
74
|
}
|
|
72
75
|
const mergedOptions = mergeOptions(options, {
|
|
73
76
|
resolve: {
|
|
74
|
-
baseURI
|
|
77
|
+
baseURI
|
|
75
78
|
},
|
|
76
79
|
dereference: {
|
|
77
80
|
// if refSet was not provided, then we can work in mutable mode
|
package/src/options/index.cjs
CHANGED
|
@@ -68,6 +68,10 @@ const defaultOptions = {
|
|
|
68
68
|
resolve: {
|
|
69
69
|
/**
|
|
70
70
|
* baseURI serves as a base for all relative URL found in ApiDOM references.
|
|
71
|
+
* It must be absolute: a file system path, a file:// URL or an HTTP(S) URL.
|
|
72
|
+
* Defaults to the current working directory (the page URL in browsers).
|
|
73
|
+
* A fragment marks where the ApiDOM fragment is located in its document;
|
|
74
|
+
* leave it out when passing a whole document.
|
|
71
75
|
*/
|
|
72
76
|
baseURI: '',
|
|
73
77
|
/**
|
package/src/options/index.mjs
CHANGED
|
@@ -63,6 +63,10 @@ const defaultOptions = {
|
|
|
63
63
|
resolve: {
|
|
64
64
|
/**
|
|
65
65
|
* baseURI serves as a base for all relative URL found in ApiDOM references.
|
|
66
|
+
* It must be absolute: a file system path, a file:// URL or an HTTP(S) URL.
|
|
67
|
+
* Defaults to the current working directory (the page URL in browsers).
|
|
68
|
+
* A fragment marks where the ApiDOM fragment is located in its document;
|
|
69
|
+
* leave it out when passing a whole document.
|
|
66
70
|
*/
|
|
67
71
|
baseURI: '',
|
|
68
72
|
/**
|
package/src/options/util.cjs
CHANGED
|
@@ -12,7 +12,13 @@ var _url = require("../util/url.cjs");
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
const baseURILens = (0, _ramda.lens)((0, _ramda.path)(['resolve', 'baseURI']), (0, _ramda.assocPath)(['resolve', 'baseURI']));
|
|
15
|
-
|
|
15
|
+
// in Node cwd() is a raw file system path; encode it, so that it reads as a URI
|
|
16
|
+
// (in browsers it is the page URL, which may be an already encoded file:// URL)
|
|
17
|
+
const cwdURI = () => {
|
|
18
|
+
const dir = (0, _url.cwd)();
|
|
19
|
+
return (0, _url.isFileSystemPath)(dir) && (0, _url.getProtocol)(dir) !== 'file' ? (0, _url.fromFileSystemPath)(dir) : dir;
|
|
20
|
+
};
|
|
21
|
+
const baseURIDefault = baseURI => (0, _ramdaAdjunct.isEmptyString)(baseURI) ? cwdURI() : baseURI;
|
|
16
22
|
|
|
17
23
|
/**
|
|
18
24
|
* @public
|
package/src/options/util.mjs
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { mergeDeepRight, lens, path, assocPath, over } from 'ramda';
|
|
2
2
|
import { isEmptyString } from 'ramda-adjunct';
|
|
3
|
-
import { cwd } from "../util/url.mjs";
|
|
3
|
+
import { cwd, getProtocol, isFileSystemPath, fromFileSystemPath } from "../util/url.mjs";
|
|
4
4
|
/**
|
|
5
5
|
* Algorithm for deep merging options.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
const baseURILens = lens(path(['resolve', 'baseURI']), assocPath(['resolve', 'baseURI']));
|
|
9
|
-
|
|
9
|
+
// in Node cwd() is a raw file system path; encode it, so that it reads as a URI
|
|
10
|
+
// (in browsers it is the page URL, which may be an already encoded file:// URL)
|
|
11
|
+
const cwdURI = () => {
|
|
12
|
+
const dir = cwd();
|
|
13
|
+
return isFileSystemPath(dir) && getProtocol(dir) !== 'file' ? fromFileSystemPath(dir) : dir;
|
|
14
|
+
};
|
|
15
|
+
const baseURIDefault = baseURI => isEmptyString(baseURI) ? cwdURI() : baseURI;
|
|
10
16
|
|
|
11
17
|
/**
|
|
12
18
|
* @public
|
package/src/resolve/index.cjs
CHANGED
|
@@ -29,9 +29,10 @@ const resolveApiDOM = async (element, options) => {
|
|
|
29
29
|
elementClone.classes.push('result');
|
|
30
30
|
parseResult = new _apidomDatamodel.ParseResultElement([elementClone]);
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
|
|
33
|
+
// strategies look up same-document references by a resolved, hence normalized, URI
|
|
33
34
|
const file = new _File.default({
|
|
34
|
-
uri:
|
|
35
|
+
uri: url.normalize(options.resolve.baseURI),
|
|
35
36
|
parseResult,
|
|
36
37
|
mediaType: options.parse.mediaType
|
|
37
38
|
});
|
|
@@ -59,9 +60,11 @@ const resolveApiDOM = async (element, options) => {
|
|
|
59
60
|
exports.resolveApiDOM = resolveApiDOM;
|
|
60
61
|
const resolve = async (uri, options) => {
|
|
61
62
|
const parseResult = await (0, _index.default)(uri, options);
|
|
63
|
+
// the file is parsed as a whole document, so its URI has no fragment
|
|
64
|
+
const baseURI = url.normalize(url.stripHash(uri));
|
|
62
65
|
const mergedOptions = (0, _util.merge)(options, {
|
|
63
66
|
resolve: {
|
|
64
|
-
baseURI
|
|
67
|
+
baseURI
|
|
65
68
|
}
|
|
66
69
|
});
|
|
67
70
|
return resolveApiDOM(parseResult, mergedOptions);
|
package/src/resolve/index.mjs
CHANGED
|
@@ -21,9 +21,10 @@ export const resolveApiDOM = async (element, options) => {
|
|
|
21
21
|
elementClone.classes.push('result');
|
|
22
22
|
parseResult = new ParseResultElement([elementClone]);
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
// strategies look up same-document references by a resolved, hence normalized, URI
|
|
25
26
|
const file = new File({
|
|
26
|
-
uri:
|
|
27
|
+
uri: url.normalize(options.resolve.baseURI),
|
|
27
28
|
parseResult,
|
|
28
29
|
mediaType: options.parse.mediaType
|
|
29
30
|
});
|
|
@@ -50,9 +51,11 @@ export const resolveApiDOM = async (element, options) => {
|
|
|
50
51
|
*/
|
|
51
52
|
const resolve = async (uri, options) => {
|
|
52
53
|
const parseResult = await parse(uri, options);
|
|
54
|
+
// the file is parsed as a whole document, so its URI has no fragment
|
|
55
|
+
const baseURI = url.normalize(url.stripHash(uri));
|
|
53
56
|
const mergedOptions = mergeOptions(options, {
|
|
54
57
|
resolve: {
|
|
55
|
-
baseURI
|
|
58
|
+
baseURI
|
|
56
59
|
}
|
|
57
60
|
});
|
|
58
61
|
return resolveApiDOM(parseResult, mergedOptions);
|
package/src/util/url.cjs
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.unsanitize = exports.toFileSystemPath = exports.stripHash = exports.sanitize = exports.resolve = exports.relative = exports.isURI = exports.isHttpUrl = exports.isFileSystemPath = exports.hasProtocol = exports.getProtocol = exports.getHash = exports.getExtension = exports.getBasename = exports.fromFileSystemPath = exports.cwd = void 0;
|
|
6
|
+
exports.unsanitize = exports.toFileSystemPath = exports.stripHash = exports.sanitize = exports.resolve = exports.relative = exports.normalize = exports.isURI = exports.isHttpUrl = exports.isFileSystemPath = exports.hasProtocol = exports.getProtocol = exports.getHash = exports.getExtension = exports.getBasename = exports.fromFileSystemPath = exports.cwd = void 0;
|
|
7
7
|
var _ramda = require("ramda");
|
|
8
8
|
var _ramdaAdjunct = require("ramda-adjunct");
|
|
9
9
|
/**
|
|
@@ -118,21 +118,23 @@ exports.isURI = isURI;
|
|
|
118
118
|
*/
|
|
119
119
|
const toFileSystemPath = (uri, options) => {
|
|
120
120
|
// RegExp patterns to URL-decode special characters for local filesystem paths
|
|
121
|
-
const urlDecodePatterns = [/%23/g, '#', /%24/g, '$', /%26/g, '&', /%2C/g, ',', /%40/g, '@'];
|
|
121
|
+
const urlDecodePatterns = [/%23/g, '#', /%24/g, '$', /%26/g, '&', /%2C/g, ',', /%3F/g, '?', /%40/g, '@'];
|
|
122
122
|
const keepFileProtocol = (0, _ramda.propOr)(false, 'keepFileProtocol', options);
|
|
123
123
|
const isWindowsPredicate = (0, _ramda.propOr)(isWindows, 'isWindows', options);
|
|
124
124
|
|
|
125
|
-
// Step 1:
|
|
126
|
-
let path = decodeURI(uri);
|
|
127
|
-
|
|
128
|
-
// Step 2: Manually decode characters that are not decoded by `decodeURI`.
|
|
125
|
+
// Step 1: Manually decode characters that are not decoded by `decodeURI`.
|
|
129
126
|
// This includes characters such as "#" and "?", which have special meaning in URLs,
|
|
130
|
-
// but are just normal characters in a filesystem path.
|
|
127
|
+
// but are just normal characters in a filesystem path. It runs before `decodeURI`,
|
|
128
|
+
// so that an encoded "%" (e.g. "%253F") isn't decoded twice.
|
|
129
|
+
let path = uri;
|
|
131
130
|
for (let i = 0; i < urlDecodePatterns.length; i += 2) {
|
|
132
131
|
// @ts-ignore
|
|
133
132
|
path = path.replace(urlDecodePatterns[i], urlDecodePatterns[i + 1]);
|
|
134
133
|
}
|
|
135
134
|
|
|
135
|
+
// Step 2: `decodeURI` will decode characters such as Cyrillic characters, spaces, etc.
|
|
136
|
+
path = decodeURI(path);
|
|
137
|
+
|
|
136
138
|
// Step 3: If it's a "file://" URL, then format it consistently
|
|
137
139
|
// or convert it to a local filesystem path
|
|
138
140
|
let isFileUrl = path.substring(0, 7).toLowerCase() === 'file://';
|
|
@@ -278,6 +280,34 @@ const resolve = (from, to) => {
|
|
|
278
280
|
return resolvedUrl.toString();
|
|
279
281
|
};
|
|
280
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Normalizes a URI the way `resolve` normalizes its result (WHATWG URL normalization):
|
|
285
|
+
* lowercases the scheme and the host of an absolute URL, drops a default port and
|
|
286
|
+
* removes dot segments. This is not RFC 3986 syntax-based normalization: existing
|
|
287
|
+
* percent-encoding is left as is. A file system path is sanitized first, so characters
|
|
288
|
+
* not allowed in URLs (e.g. spaces, `[`, `?`) are percent-encoded; a `file://` URL has
|
|
289
|
+
* its path sanitized the same way and stays a URL. The fragment is kept as given.
|
|
290
|
+
* A URI that can't be normalized is returned unchanged.
|
|
291
|
+
* @public
|
|
292
|
+
*/
|
|
293
|
+
exports.resolve = resolve;
|
|
294
|
+
const normalize = uri => {
|
|
295
|
+
// getHash returns the root hash ('#') for a URI without fragment
|
|
296
|
+
const fragment = uri.includes('#') ? getHash(uri) : '';
|
|
297
|
+
const documentURI = stripHash(uri);
|
|
298
|
+
try {
|
|
299
|
+
let sanitizedURI = sanitize(documentURI);
|
|
300
|
+
// sanitize turns a file:// URL into a path; keep it a URL, as references
|
|
301
|
+
// resolved against it are, e.g. file:///C:/x.json rather than file://C:/x.json
|
|
302
|
+
if (getProtocol(documentURI) === 'file') {
|
|
303
|
+
sanitizedURI = `file://${sanitizedURI.startsWith('/') ? '' : '/'}${sanitizedURI}`;
|
|
304
|
+
}
|
|
305
|
+
return resolve('', sanitizedURI) + fragment;
|
|
306
|
+
} catch {
|
|
307
|
+
return uri;
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
281
311
|
/**
|
|
282
312
|
* Computes the URI reference that resolves to `to` against `from` — the inverse
|
|
283
313
|
* of `resolve`: `resolve(from, relative(from, to)) === to`. The reference is
|
|
@@ -287,7 +317,7 @@ const resolve = (from, to) => {
|
|
|
287
317
|
* returned unchanged.
|
|
288
318
|
* @public
|
|
289
319
|
*/
|
|
290
|
-
exports.
|
|
320
|
+
exports.normalize = normalize;
|
|
291
321
|
const relative = (from, to) => {
|
|
292
322
|
const fromURL = new URL(from, 'resolve://');
|
|
293
323
|
const toURL = new URL(to, 'resolve://');
|
package/src/util/url.mjs
CHANGED
|
@@ -108,21 +108,23 @@ export const isURI = uri => {
|
|
|
108
108
|
*/
|
|
109
109
|
export const toFileSystemPath = (uri, options) => {
|
|
110
110
|
// RegExp patterns to URL-decode special characters for local filesystem paths
|
|
111
|
-
const urlDecodePatterns = [/%23/g, '#', /%24/g, '$', /%26/g, '&', /%2C/g, ',', /%40/g, '@'];
|
|
111
|
+
const urlDecodePatterns = [/%23/g, '#', /%24/g, '$', /%26/g, '&', /%2C/g, ',', /%3F/g, '?', /%40/g, '@'];
|
|
112
112
|
const keepFileProtocol = propOr(false, 'keepFileProtocol', options);
|
|
113
113
|
const isWindowsPredicate = propOr(isWindows, 'isWindows', options);
|
|
114
114
|
|
|
115
|
-
// Step 1:
|
|
116
|
-
let path = decodeURI(uri);
|
|
117
|
-
|
|
118
|
-
// Step 2: Manually decode characters that are not decoded by `decodeURI`.
|
|
115
|
+
// Step 1: Manually decode characters that are not decoded by `decodeURI`.
|
|
119
116
|
// This includes characters such as "#" and "?", which have special meaning in URLs,
|
|
120
|
-
// but are just normal characters in a filesystem path.
|
|
117
|
+
// but are just normal characters in a filesystem path. It runs before `decodeURI`,
|
|
118
|
+
// so that an encoded "%" (e.g. "%253F") isn't decoded twice.
|
|
119
|
+
let path = uri;
|
|
121
120
|
for (let i = 0; i < urlDecodePatterns.length; i += 2) {
|
|
122
121
|
// @ts-ignore
|
|
123
122
|
path = path.replace(urlDecodePatterns[i], urlDecodePatterns[i + 1]);
|
|
124
123
|
}
|
|
125
124
|
|
|
125
|
+
// Step 2: `decodeURI` will decode characters such as Cyrillic characters, spaces, etc.
|
|
126
|
+
path = decodeURI(path);
|
|
127
|
+
|
|
126
128
|
// Step 3: If it's a "file://" URL, then format it consistently
|
|
127
129
|
// or convert it to a local filesystem path
|
|
128
130
|
let isFileUrl = path.substring(0, 7).toLowerCase() === 'file://';
|
|
@@ -263,6 +265,33 @@ export const resolve = (from, to) => {
|
|
|
263
265
|
return resolvedUrl.toString();
|
|
264
266
|
};
|
|
265
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Normalizes a URI the way `resolve` normalizes its result (WHATWG URL normalization):
|
|
270
|
+
* lowercases the scheme and the host of an absolute URL, drops a default port and
|
|
271
|
+
* removes dot segments. This is not RFC 3986 syntax-based normalization: existing
|
|
272
|
+
* percent-encoding is left as is. A file system path is sanitized first, so characters
|
|
273
|
+
* not allowed in URLs (e.g. spaces, `[`, `?`) are percent-encoded; a `file://` URL has
|
|
274
|
+
* its path sanitized the same way and stays a URL. The fragment is kept as given.
|
|
275
|
+
* A URI that can't be normalized is returned unchanged.
|
|
276
|
+
* @public
|
|
277
|
+
*/
|
|
278
|
+
export const normalize = uri => {
|
|
279
|
+
// getHash returns the root hash ('#') for a URI without fragment
|
|
280
|
+
const fragment = uri.includes('#') ? getHash(uri) : '';
|
|
281
|
+
const documentURI = stripHash(uri);
|
|
282
|
+
try {
|
|
283
|
+
let sanitizedURI = sanitize(documentURI);
|
|
284
|
+
// sanitize turns a file:// URL into a path; keep it a URL, as references
|
|
285
|
+
// resolved against it are, e.g. file:///C:/x.json rather than file://C:/x.json
|
|
286
|
+
if (getProtocol(documentURI) === 'file') {
|
|
287
|
+
sanitizedURI = `file://${sanitizedURI.startsWith('/') ? '' : '/'}${sanitizedURI}`;
|
|
288
|
+
}
|
|
289
|
+
return resolve('', sanitizedURI) + fragment;
|
|
290
|
+
} catch {
|
|
291
|
+
return uri;
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
266
295
|
/**
|
|
267
296
|
* Computes the URI reference that resolves to `to` against `from` — the inverse
|
|
268
297
|
* of `resolve`: `resolve(from, relative(from, to)) === to`. The reference is
|
|
@@ -359,6 +359,18 @@ export declare class MaximumResolveDepthError extends ResolveError {
|
|
|
359
359
|
*/
|
|
360
360
|
export declare const mergeOptions: (lObj: ApiDOMReferenceOptions, rObj: Record<string, any>) => ApiDOMReferenceOptions;
|
|
361
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Normalizes a URI the way `resolve` normalizes its result (WHATWG URL normalization):
|
|
364
|
+
* lowercases the scheme and the host of an absolute URL, drops a default port and
|
|
365
|
+
* removes dot segments. This is not RFC 3986 syntax-based normalization: existing
|
|
366
|
+
* percent-encoding is left as is. A file system path is sanitized first, so characters
|
|
367
|
+
* not allowed in URLs (e.g. spaces, `[`, `?`) are percent-encoded; a `file://` URL has
|
|
368
|
+
* its path sanitized the same way and stays a URL. The fragment is kept as given.
|
|
369
|
+
* A URI that can't be normalized is returned unchanged.
|
|
370
|
+
* @public
|
|
371
|
+
*/
|
|
372
|
+
declare const normalize: (uri: string) => string;
|
|
373
|
+
|
|
362
374
|
/**
|
|
363
375
|
* @public
|
|
364
376
|
*/
|
|
@@ -658,6 +670,7 @@ declare namespace url {
|
|
|
658
670
|
stripHash,
|
|
659
671
|
cwd,
|
|
660
672
|
resolve_2 as resolve,
|
|
673
|
+
normalize,
|
|
661
674
|
relative,
|
|
662
675
|
sanitize,
|
|
663
676
|
unsanitize
|
package/types/util/url.d.ts
CHANGED
|
@@ -96,6 +96,17 @@ export declare const cwd: () => string;
|
|
|
96
96
|
* @public
|
|
97
97
|
*/
|
|
98
98
|
export declare const resolve: (from: string, to: string) => string;
|
|
99
|
+
/**
|
|
100
|
+
* Normalizes a URI the way `resolve` normalizes its result (WHATWG URL normalization):
|
|
101
|
+
* lowercases the scheme and the host of an absolute URL, drops a default port and
|
|
102
|
+
* removes dot segments. This is not RFC 3986 syntax-based normalization: existing
|
|
103
|
+
* percent-encoding is left as is. A file system path is sanitized first, so characters
|
|
104
|
+
* not allowed in URLs (e.g. spaces, `[`, `?`) are percent-encoded; a `file://` URL has
|
|
105
|
+
* its path sanitized the same way and stays a URL. The fragment is kept as given.
|
|
106
|
+
* A URI that can't be normalized is returned unchanged.
|
|
107
|
+
* @public
|
|
108
|
+
*/
|
|
109
|
+
export declare const normalize: (uri: string) => string;
|
|
99
110
|
/**
|
|
100
111
|
* Computes the URI reference that resolves to `to` against `from` — the inverse
|
|
101
112
|
* of `resolve`: `resolve(from, relative(from, to)) === to`. The reference is
|