@speclynx/apidom-reference 5.2.6 → 6.0.1
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 +22 -0
- package/README.md +23 -1
- package/dist/apidom-reference.browser.js +64934 -64041
- package/dist/apidom-reference.browser.min.js +1 -1
- package/package.json +28 -29
- package/src/dereference/strategies/overlay-1/extends.cjs +5 -1
- package/src/dereference/strategies/overlay-1/extends.mjs +5 -1
- package/src/dereference/strategies/overlay-1/index.cjs +20 -0
- package/src/dereference/strategies/overlay-1/index.mjs +15 -0
- package/src/dereference/strategies/overlay-1/visitor.cjs +148 -0
- package/src/dereference/strategies/overlay-1/visitor.mjs +140 -0
- package/src/parse/parsers/overlay-json-1/extends.cjs +5 -1
- package/src/parse/parsers/overlay-json-1/extends.mjs +5 -1
- package/src/util/url.cjs +10 -7
- package/src/util/url.mjs +9 -5
- package/types/dereference/strategies/overlay-1/index.d.ts +3 -0
- package/types/dereference/strategies/overlay-1/visitor.d.ts +21 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@speclynx/apidom-reference",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.1",
|
|
4
4
|
"description": "Advanced algorithms for semantic ApiDOM manipulations like dereferencing or resolution.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"apidom",
|
|
@@ -299,36 +299,35 @@
|
|
|
299
299
|
"license": "Apache-2.0",
|
|
300
300
|
"dependencies": {
|
|
301
301
|
"@babel/runtime-corejs3": "^8.0.5",
|
|
302
|
-
"@speclynx/apidom-core": "
|
|
303
|
-
"@speclynx/apidom-datamodel": "
|
|
304
|
-
"@speclynx/apidom-error": "
|
|
305
|
-
"@speclynx/apidom-json-pointer": "
|
|
306
|
-
"@speclynx/apidom-ns-arazzo-1": "
|
|
307
|
-
"@speclynx/apidom-ns-asyncapi-2": "
|
|
308
|
-
"@speclynx/apidom-ns-json-schema-2020-12": "
|
|
309
|
-
"@speclynx/apidom-ns-openapi-2": "
|
|
310
|
-
"@speclynx/apidom-ns-openapi-3-0": "
|
|
311
|
-
"@speclynx/apidom-ns-openapi-3-1": "
|
|
312
|
-
"@speclynx/apidom-ns-overlay-1": "
|
|
313
|
-
"@speclynx/apidom-parser-adapter-arazzo-json-1": "
|
|
314
|
-
"@speclynx/apidom-parser-adapter-arazzo-yaml-1": "
|
|
315
|
-
"@speclynx/apidom-parser-adapter-asyncapi-json-2": "
|
|
316
|
-
"@speclynx/apidom-parser-adapter-asyncapi-yaml-2": "
|
|
317
|
-
"@speclynx/apidom-parser-adapter-json": "
|
|
318
|
-
"@speclynx/apidom-parser-adapter-openapi-json-2": "
|
|
319
|
-
"@speclynx/apidom-parser-adapter-openapi-json-3-0": "
|
|
320
|
-
"@speclynx/apidom-parser-adapter-openapi-json-3-1": "
|
|
321
|
-
"@speclynx/apidom-parser-adapter-openapi-yaml-2": "
|
|
322
|
-
"@speclynx/apidom-parser-adapter-openapi-yaml-3-0": "
|
|
323
|
-
"@speclynx/apidom-parser-adapter-openapi-yaml-3-1": "
|
|
324
|
-
"@speclynx/apidom-parser-adapter-overlay-json-1": "
|
|
325
|
-
"@speclynx/apidom-parser-adapter-overlay-yaml-1": "
|
|
326
|
-
"@speclynx/apidom-parser-adapter-yaml-1-2": "
|
|
327
|
-
"@speclynx/apidom-traverse": "
|
|
302
|
+
"@speclynx/apidom-core": "6.0.1",
|
|
303
|
+
"@speclynx/apidom-datamodel": "6.0.1",
|
|
304
|
+
"@speclynx/apidom-error": "6.0.1",
|
|
305
|
+
"@speclynx/apidom-json-pointer": "6.0.1",
|
|
306
|
+
"@speclynx/apidom-ns-arazzo-1": "6.0.1",
|
|
307
|
+
"@speclynx/apidom-ns-asyncapi-2": "6.0.1",
|
|
308
|
+
"@speclynx/apidom-ns-json-schema-2020-12": "6.0.1",
|
|
309
|
+
"@speclynx/apidom-ns-openapi-2": "6.0.1",
|
|
310
|
+
"@speclynx/apidom-ns-openapi-3-0": "6.0.1",
|
|
311
|
+
"@speclynx/apidom-ns-openapi-3-1": "6.0.1",
|
|
312
|
+
"@speclynx/apidom-ns-overlay-1": "6.0.1",
|
|
313
|
+
"@speclynx/apidom-parser-adapter-arazzo-json-1": "6.0.1",
|
|
314
|
+
"@speclynx/apidom-parser-adapter-arazzo-yaml-1": "6.0.1",
|
|
315
|
+
"@speclynx/apidom-parser-adapter-asyncapi-json-2": "6.0.1",
|
|
316
|
+
"@speclynx/apidom-parser-adapter-asyncapi-yaml-2": "6.0.1",
|
|
317
|
+
"@speclynx/apidom-parser-adapter-json": "6.0.1",
|
|
318
|
+
"@speclynx/apidom-parser-adapter-openapi-json-2": "6.0.1",
|
|
319
|
+
"@speclynx/apidom-parser-adapter-openapi-json-3-0": "6.0.1",
|
|
320
|
+
"@speclynx/apidom-parser-adapter-openapi-json-3-1": "6.0.1",
|
|
321
|
+
"@speclynx/apidom-parser-adapter-openapi-yaml-2": "6.0.1",
|
|
322
|
+
"@speclynx/apidom-parser-adapter-openapi-yaml-3-0": "6.0.1",
|
|
323
|
+
"@speclynx/apidom-parser-adapter-openapi-yaml-3-1": "6.0.1",
|
|
324
|
+
"@speclynx/apidom-parser-adapter-overlay-json-1": "6.0.1",
|
|
325
|
+
"@speclynx/apidom-parser-adapter-overlay-yaml-1": "6.0.1",
|
|
326
|
+
"@speclynx/apidom-parser-adapter-yaml-1-2": "6.0.1",
|
|
327
|
+
"@speclynx/apidom-traverse": "6.0.1",
|
|
328
328
|
"@swaggerexpert/arazzo-runtime-expression": "^3.2.0",
|
|
329
329
|
"axios": "^1.20.0",
|
|
330
330
|
"picomatch": "^4.0.7",
|
|
331
|
-
"process": "^0.11.10",
|
|
332
331
|
"ramda": "~0.32.0",
|
|
333
332
|
"ramda-adjunct": "^6.1.0"
|
|
334
333
|
},
|
|
@@ -346,5 +345,5 @@
|
|
|
346
345
|
"README.md",
|
|
347
346
|
"CHANGELOG.md"
|
|
348
347
|
],
|
|
349
|
-
"gitHead": "
|
|
348
|
+
"gitHead": "d2ea4f01cac54a0d5e1030386e3b0b60664c9619"
|
|
350
349
|
}
|
|
@@ -45,8 +45,12 @@ async function dereferenceExtends(parseResult, parseResultRetrievalURI, options)
|
|
|
45
45
|
if (!(0, _apidomDatamodel.isStringElement)(extendsElement)) {
|
|
46
46
|
return;
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
// Overlay 1.2.0: `$self` (itself resolved against the retrieval URI) is the base URI
|
|
50
|
+
const selfElement = api.get('$self');
|
|
51
|
+
const baseURI = (0, _apidomDatamodel.isStringElement)(selfElement) ? url.resolve(file.uri, (0, _apidomCore.toValue)(selfElement)) : file.uri;
|
|
48
52
|
const extendsURI = (0, _apidomCore.toValue)(extendsElement);
|
|
49
|
-
const retrievalURI = url.sanitize(url.stripHash(url.resolve(
|
|
53
|
+
const retrievalURI = url.sanitize(url.stripHash(url.resolve(baseURI, extendsURI)));
|
|
50
54
|
const extendsDereferenceResult = new _apidomDatamodel.ParseResultElement();
|
|
51
55
|
extendsDereferenceResult.classes.push('extends');
|
|
52
56
|
extendsDereferenceResult.setMetaProperty('retrievalURI', retrievalURI);
|
|
@@ -37,8 +37,12 @@ export async function dereferenceExtends(parseResult, parseResultRetrievalURI, o
|
|
|
37
37
|
if (!isStringElement(extendsElement)) {
|
|
38
38
|
return;
|
|
39
39
|
}
|
|
40
|
+
|
|
41
|
+
// Overlay 1.2.0: `$self` (itself resolved against the retrieval URI) is the base URI
|
|
42
|
+
const selfElement = api.get('$self');
|
|
43
|
+
const baseURI = isStringElement(selfElement) ? url.resolve(file.uri, toValue(selfElement)) : file.uri;
|
|
40
44
|
const extendsURI = toValue(extendsElement);
|
|
41
|
-
const retrievalURI = url.sanitize(url.stripHash(url.resolve(
|
|
45
|
+
const retrievalURI = url.sanitize(url.stripHash(url.resolve(baseURI, extendsURI)));
|
|
42
46
|
const extendsDereferenceResult = new ParseResultElement();
|
|
43
47
|
extendsDereferenceResult.classes.push('extends');
|
|
44
48
|
extendsDereferenceResult.setMetaProperty('retrievalURI', retrievalURI);
|
|
@@ -4,6 +4,12 @@ var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequ
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
+
Object.defineProperty(exports, "Overlay1DereferenceVisitor", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () {
|
|
10
|
+
return _visitor.default;
|
|
11
|
+
}
|
|
12
|
+
});
|
|
7
13
|
exports.default = void 0;
|
|
8
14
|
Object.defineProperty(exports, "dereferenceExtends", {
|
|
9
15
|
enumerable: true,
|
|
@@ -13,10 +19,12 @@ Object.defineProperty(exports, "dereferenceExtends", {
|
|
|
13
19
|
});
|
|
14
20
|
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
15
21
|
var _apidomNsOverlay = require("@speclynx/apidom-ns-overlay-1");
|
|
22
|
+
var _apidomTraverse = require("@speclynx/apidom-traverse");
|
|
16
23
|
var _DereferenceStrategy = _interopRequireDefault(require("../DereferenceStrategy.cjs"));
|
|
17
24
|
var _Reference = _interopRequireDefault(require("../../../Reference.cjs"));
|
|
18
25
|
var _ReferenceSet = _interopRequireDefault(require("../../../ReferenceSet.cjs"));
|
|
19
26
|
var _extends = require("./extends.cjs");
|
|
27
|
+
var _visitor = _interopRequireDefault(require("./visitor.cjs"));
|
|
20
28
|
/**
|
|
21
29
|
* @public
|
|
22
30
|
*/
|
|
@@ -68,6 +76,18 @@ class Overlay1DereferenceStrategy extends _DereferenceStrategy.default {
|
|
|
68
76
|
}
|
|
69
77
|
const dereferencedElement = reference.value;
|
|
70
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Reusable Action References only occur within `actions`, so the root element is never
|
|
81
|
+
* replaced and traversing it keeps reported locations relative to the document.
|
|
82
|
+
*/
|
|
83
|
+
const visitor = new _visitor.default({
|
|
84
|
+
reference,
|
|
85
|
+
options
|
|
86
|
+
});
|
|
87
|
+
await (0, _apidomTraverse.traverseAsync)(dereferencedElement.result, visitor, {
|
|
88
|
+
mutable: true
|
|
89
|
+
});
|
|
90
|
+
|
|
71
91
|
/**
|
|
72
92
|
* Dereference extends target if option is enabled.
|
|
73
93
|
*/
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { cloneDeep } from '@speclynx/apidom-datamodel';
|
|
2
2
|
import { isOverlay1Element, mediaTypes } from '@speclynx/apidom-ns-overlay-1';
|
|
3
|
+
import { traverseAsync } from '@speclynx/apidom-traverse';
|
|
3
4
|
import DereferenceStrategy from "../DereferenceStrategy.mjs";
|
|
4
5
|
import Reference from "../../../Reference.mjs";
|
|
5
6
|
import ReferenceSet from "../../../ReferenceSet.mjs";
|
|
6
7
|
import { dereferenceExtends } from "./extends.mjs";
|
|
8
|
+
import Overlay1DereferenceVisitor from "./visitor.mjs";
|
|
7
9
|
/**
|
|
8
10
|
* @public
|
|
9
11
|
*/
|
|
@@ -54,6 +56,18 @@ class Overlay1DereferenceStrategy extends DereferenceStrategy {
|
|
|
54
56
|
}
|
|
55
57
|
const dereferencedElement = reference.value;
|
|
56
58
|
|
|
59
|
+
/**
|
|
60
|
+
* Reusable Action References only occur within `actions`, so the root element is never
|
|
61
|
+
* replaced and traversing it keeps reported locations relative to the document.
|
|
62
|
+
*/
|
|
63
|
+
const visitor = new Overlay1DereferenceVisitor({
|
|
64
|
+
reference,
|
|
65
|
+
options
|
|
66
|
+
});
|
|
67
|
+
await traverseAsync(dereferencedElement.result, visitor, {
|
|
68
|
+
mutable: true
|
|
69
|
+
});
|
|
70
|
+
|
|
57
71
|
/**
|
|
58
72
|
* Dereference extends target if option is enabled.
|
|
59
73
|
*/
|
|
@@ -84,4 +98,5 @@ class Overlay1DereferenceStrategy extends DereferenceStrategy {
|
|
|
84
98
|
}
|
|
85
99
|
}
|
|
86
100
|
export { dereferenceExtends } from "./extends.mjs";
|
|
101
|
+
export { Overlay1DereferenceVisitor };
|
|
87
102
|
export default Overlay1DereferenceStrategy;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.default = void 0;
|
|
8
|
+
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
9
|
+
var _apidomCore = require("@speclynx/apidom-core");
|
|
10
|
+
var _apidomError = require("@speclynx/apidom-error");
|
|
11
|
+
var _apidomJsonPointer = require("@speclynx/apidom-json-pointer");
|
|
12
|
+
var _apidomNsOverlay = require("@speclynx/apidom-ns-overlay-1");
|
|
13
|
+
var _UnresolvableReferenceError = _interopRequireDefault(require("../../../errors/UnresolvableReferenceError.cjs"));
|
|
14
|
+
/**
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @public
|
|
20
|
+
*/
|
|
21
|
+
class Overlay1DereferenceVisitor {
|
|
22
|
+
reference;
|
|
23
|
+
options;
|
|
24
|
+
constructor({
|
|
25
|
+
reference,
|
|
26
|
+
options
|
|
27
|
+
}) {
|
|
28
|
+
this.reference = reference;
|
|
29
|
+
this.options = options;
|
|
30
|
+
}
|
|
31
|
+
ReusableActionReferenceElement(path) {
|
|
32
|
+
const referencingElement = path.node;
|
|
33
|
+
|
|
34
|
+
// ignore if resolve.internal is false (Reusable Action References are internal references only)
|
|
35
|
+
if (!this.options.resolve.internal) {
|
|
36
|
+
path.skip();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const $ref = (0, _apidomCore.toValue)(referencingElement.$ref);
|
|
40
|
+
const overlayElement = this.reference.value.result;
|
|
41
|
+
const actionElement = new _apidomNsOverlay.ActionElement();
|
|
42
|
+
try {
|
|
43
|
+
if (typeof $ref !== 'string') {
|
|
44
|
+
throw new _apidomError.ApiDOMStructuredError('Reusable Action Reference "$ref" field must be a string');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// only `target`, `description` and extensions may accompany `$ref`
|
|
48
|
+
const disallowedField = ['update', 'copy', 'remove'].find(field => referencingElement.hasKey(field));
|
|
49
|
+
if (disallowedField !== undefined) {
|
|
50
|
+
throw new _apidomError.ApiDOMStructuredError(`Reusable Action Reference "${$ref}" must not define "${disallowedField}"`, {
|
|
51
|
+
$ref
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// same-document reference only; external references are not supported
|
|
56
|
+
if (!$ref.startsWith('#')) {
|
|
57
|
+
throw new _apidomError.ApiDOMStructuredError(`Reusable Action Reference "${$ref}" must be a same-document reference`, {
|
|
58
|
+
$ref
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Only entries of `components.actions` are refracted as Reusable Actions,
|
|
64
|
+
* so the element type alone proves the pointer leads there.
|
|
65
|
+
*/
|
|
66
|
+
let reusableAction;
|
|
67
|
+
try {
|
|
68
|
+
reusableAction = (0, _apidomJsonPointer.evaluate)(overlayElement, _apidomJsonPointer.URIFragmentIdentifier.from($ref));
|
|
69
|
+
} catch {
|
|
70
|
+
reusableAction = undefined;
|
|
71
|
+
}
|
|
72
|
+
if (!(0, _apidomNsOverlay.isReusableActionElement)(reusableAction)) {
|
|
73
|
+
throw new _apidomError.ApiDOMStructuredError(`Reusable Action Reference "${$ref}" cannot be resolved`, {
|
|
74
|
+
$ref
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const {
|
|
78
|
+
fields
|
|
79
|
+
} = reusableAction;
|
|
80
|
+
if (fields !== undefined && !(0, _apidomNsOverlay.isActionElement)(fields)) {
|
|
81
|
+
throw new _apidomError.ApiDOMStructuredError(`Reusable Action "${$ref}" must define "fields" as an object`, {
|
|
82
|
+
$ref
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if ((0, _apidomNsOverlay.isActionElement)(fields) && fields.hasKey('target')) {
|
|
86
|
+
throw new _apidomError.ApiDOMStructuredError(`Reusable Action "${$ref}" must not define "target" in its "fields"`, {
|
|
87
|
+
$ref
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// the reference supplies `target` and its `description` takes precedence over the one in `fields`
|
|
92
|
+
const {
|
|
93
|
+
target,
|
|
94
|
+
description
|
|
95
|
+
} = referencingElement;
|
|
96
|
+
if (target !== undefined) {
|
|
97
|
+
actionElement.set('target', (0, _apidomDatamodel.cloneDeep)(target));
|
|
98
|
+
}
|
|
99
|
+
if ((0, _apidomNsOverlay.isActionElement)(fields)) {
|
|
100
|
+
fields.forEach((value, keyElement) => {
|
|
101
|
+
actionElement.set((0, _apidomCore.toValue)(keyElement), (0, _apidomDatamodel.cloneDeep)(value));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if (description !== undefined) {
|
|
105
|
+
actionElement.set('description', (0, _apidomDatamodel.cloneDeep)(description));
|
|
106
|
+
}
|
|
107
|
+
} catch (error) {
|
|
108
|
+
const {
|
|
109
|
+
continueOnError
|
|
110
|
+
} = this.options.dereference;
|
|
111
|
+
const unresolvedError = new _UnresolvableReferenceError.default(`Error while dereferencing Reusable Action Reference "${$ref}": ${error.message}`, {
|
|
112
|
+
cause: error,
|
|
113
|
+
type: referencingElement.element,
|
|
114
|
+
uri: this.reference.uri,
|
|
115
|
+
location: path.formatPath(),
|
|
116
|
+
codeFrame: (0, _apidomCore.toYAML)(referencingElement),
|
|
117
|
+
refFieldName: '$ref',
|
|
118
|
+
refFieldValue: $ref,
|
|
119
|
+
trace: []
|
|
120
|
+
});
|
|
121
|
+
if (continueOnError === false) throw unresolvedError;
|
|
122
|
+
if (typeof continueOnError === 'function') continueOnError(unresolvedError);
|
|
123
|
+
path.skip();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// the action takes the place of the reference in `actions`, so it inherits its source position
|
|
128
|
+
if ((0, _apidomDatamodel.hasElementSourceMap)(referencingElement)) {
|
|
129
|
+
_apidomDatamodel.SourceMapElement.transfer(referencingElement, actionElement);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// annotate with info about original referencing element
|
|
133
|
+
actionElement.meta.set('ref-fields', {
|
|
134
|
+
$ref,
|
|
135
|
+
description: (0, _apidomCore.toValue)(referencingElement.description)
|
|
136
|
+
});
|
|
137
|
+
// annotate with info about origin
|
|
138
|
+
actionElement.meta.set('ref-origin', this.reference.uri);
|
|
139
|
+
actionElement.meta.set('ref-type', referencingElement.element);
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Transclude referencing element with resolved Action Object.
|
|
143
|
+
*/
|
|
144
|
+
path.replaceWith(actionElement);
|
|
145
|
+
path.skip();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
var _default = exports.default = Overlay1DereferenceVisitor;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { SourceMapElement, cloneDeep, hasElementSourceMap } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import { toValue, toYAML } from '@speclynx/apidom-core';
|
|
3
|
+
import { ApiDOMStructuredError } from '@speclynx/apidom-error';
|
|
4
|
+
import { evaluate as jsonPointerEvaluate, URIFragmentIdentifier } from '@speclynx/apidom-json-pointer';
|
|
5
|
+
import { ActionElement, isActionElement, isReusableActionElement } from '@speclynx/apidom-ns-overlay-1';
|
|
6
|
+
import UnresolvableReferenceError from "../../../errors/UnresolvableReferenceError.mjs";
|
|
7
|
+
/**
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
class Overlay1DereferenceVisitor {
|
|
14
|
+
reference;
|
|
15
|
+
options;
|
|
16
|
+
constructor({
|
|
17
|
+
reference,
|
|
18
|
+
options
|
|
19
|
+
}) {
|
|
20
|
+
this.reference = reference;
|
|
21
|
+
this.options = options;
|
|
22
|
+
}
|
|
23
|
+
ReusableActionReferenceElement(path) {
|
|
24
|
+
const referencingElement = path.node;
|
|
25
|
+
|
|
26
|
+
// ignore if resolve.internal is false (Reusable Action References are internal references only)
|
|
27
|
+
if (!this.options.resolve.internal) {
|
|
28
|
+
path.skip();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const $ref = toValue(referencingElement.$ref);
|
|
32
|
+
const overlayElement = this.reference.value.result;
|
|
33
|
+
const actionElement = new ActionElement();
|
|
34
|
+
try {
|
|
35
|
+
if (typeof $ref !== 'string') {
|
|
36
|
+
throw new ApiDOMStructuredError('Reusable Action Reference "$ref" field must be a string');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// only `target`, `description` and extensions may accompany `$ref`
|
|
40
|
+
const disallowedField = ['update', 'copy', 'remove'].find(field => referencingElement.hasKey(field));
|
|
41
|
+
if (disallowedField !== undefined) {
|
|
42
|
+
throw new ApiDOMStructuredError(`Reusable Action Reference "${$ref}" must not define "${disallowedField}"`, {
|
|
43
|
+
$ref
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// same-document reference only; external references are not supported
|
|
48
|
+
if (!$ref.startsWith('#')) {
|
|
49
|
+
throw new ApiDOMStructuredError(`Reusable Action Reference "${$ref}" must be a same-document reference`, {
|
|
50
|
+
$ref
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Only entries of `components.actions` are refracted as Reusable Actions,
|
|
56
|
+
* so the element type alone proves the pointer leads there.
|
|
57
|
+
*/
|
|
58
|
+
let reusableAction;
|
|
59
|
+
try {
|
|
60
|
+
reusableAction = jsonPointerEvaluate(overlayElement, URIFragmentIdentifier.from($ref));
|
|
61
|
+
} catch {
|
|
62
|
+
reusableAction = undefined;
|
|
63
|
+
}
|
|
64
|
+
if (!isReusableActionElement(reusableAction)) {
|
|
65
|
+
throw new ApiDOMStructuredError(`Reusable Action Reference "${$ref}" cannot be resolved`, {
|
|
66
|
+
$ref
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
const {
|
|
70
|
+
fields
|
|
71
|
+
} = reusableAction;
|
|
72
|
+
if (fields !== undefined && !isActionElement(fields)) {
|
|
73
|
+
throw new ApiDOMStructuredError(`Reusable Action "${$ref}" must define "fields" as an object`, {
|
|
74
|
+
$ref
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
if (isActionElement(fields) && fields.hasKey('target')) {
|
|
78
|
+
throw new ApiDOMStructuredError(`Reusable Action "${$ref}" must not define "target" in its "fields"`, {
|
|
79
|
+
$ref
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// the reference supplies `target` and its `description` takes precedence over the one in `fields`
|
|
84
|
+
const {
|
|
85
|
+
target,
|
|
86
|
+
description
|
|
87
|
+
} = referencingElement;
|
|
88
|
+
if (target !== undefined) {
|
|
89
|
+
actionElement.set('target', cloneDeep(target));
|
|
90
|
+
}
|
|
91
|
+
if (isActionElement(fields)) {
|
|
92
|
+
fields.forEach((value, keyElement) => {
|
|
93
|
+
actionElement.set(toValue(keyElement), cloneDeep(value));
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (description !== undefined) {
|
|
97
|
+
actionElement.set('description', cloneDeep(description));
|
|
98
|
+
}
|
|
99
|
+
} catch (error) {
|
|
100
|
+
const {
|
|
101
|
+
continueOnError
|
|
102
|
+
} = this.options.dereference;
|
|
103
|
+
const unresolvedError = new UnresolvableReferenceError(`Error while dereferencing Reusable Action Reference "${$ref}": ${error.message}`, {
|
|
104
|
+
cause: error,
|
|
105
|
+
type: referencingElement.element,
|
|
106
|
+
uri: this.reference.uri,
|
|
107
|
+
location: path.formatPath(),
|
|
108
|
+
codeFrame: toYAML(referencingElement),
|
|
109
|
+
refFieldName: '$ref',
|
|
110
|
+
refFieldValue: $ref,
|
|
111
|
+
trace: []
|
|
112
|
+
});
|
|
113
|
+
if (continueOnError === false) throw unresolvedError;
|
|
114
|
+
if (typeof continueOnError === 'function') continueOnError(unresolvedError);
|
|
115
|
+
path.skip();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// the action takes the place of the reference in `actions`, so it inherits its source position
|
|
120
|
+
if (hasElementSourceMap(referencingElement)) {
|
|
121
|
+
SourceMapElement.transfer(referencingElement, actionElement);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// annotate with info about original referencing element
|
|
125
|
+
actionElement.meta.set('ref-fields', {
|
|
126
|
+
$ref,
|
|
127
|
+
description: toValue(referencingElement.description)
|
|
128
|
+
});
|
|
129
|
+
// annotate with info about origin
|
|
130
|
+
actionElement.meta.set('ref-origin', this.reference.uri);
|
|
131
|
+
actionElement.meta.set('ref-type', referencingElement.element);
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Transclude referencing element with resolved Action Object.
|
|
135
|
+
*/
|
|
136
|
+
path.replaceWith(actionElement);
|
|
137
|
+
path.skip();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export default Overlay1DereferenceVisitor;
|
|
@@ -40,8 +40,12 @@ async function parseExtends(parseResult, parseResultRetrievalURI, options) {
|
|
|
40
40
|
if (!(0, _apidomDatamodel.isStringElement)(extendsElement)) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
// Overlay 1.2.0: `$self` (itself resolved against the retrieval URI) is the base URI
|
|
45
|
+
const selfElement = api.get('$self');
|
|
46
|
+
const baseURI = (0, _apidomDatamodel.isStringElement)(selfElement) ? url.resolve(file.uri, (0, _apidomCore.toValue)(selfElement)) : file.uri;
|
|
43
47
|
const extendsURI = (0, _apidomCore.toValue)(extendsElement);
|
|
44
|
-
const retrievalURI = url.sanitize(url.stripHash(url.resolve(
|
|
48
|
+
const retrievalURI = url.sanitize(url.stripHash(url.resolve(baseURI, extendsURI)));
|
|
45
49
|
const extendsParseResult = new _apidomDatamodel.ParseResultElement();
|
|
46
50
|
extendsParseResult.classes.push('extends');
|
|
47
51
|
extendsParseResult.setMetaProperty('retrievalURI', retrievalURI);
|
|
@@ -32,8 +32,12 @@ export async function parseExtends(parseResult, parseResultRetrievalURI, options
|
|
|
32
32
|
if (!isStringElement(extendsElement)) {
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
|
+
|
|
36
|
+
// Overlay 1.2.0: `$self` (itself resolved against the retrieval URI) is the base URI
|
|
37
|
+
const selfElement = api.get('$self');
|
|
38
|
+
const baseURI = isStringElement(selfElement) ? url.resolve(file.uri, toValue(selfElement)) : file.uri;
|
|
35
39
|
const extendsURI = toValue(extendsElement);
|
|
36
|
-
const retrievalURI = url.sanitize(url.stripHash(url.resolve(
|
|
40
|
+
const retrievalURI = url.sanitize(url.stripHash(url.resolve(baseURI, extendsURI)));
|
|
37
41
|
const extendsParseResult = new ParseResultElement();
|
|
38
42
|
extendsParseResult.classes.push('extends');
|
|
39
43
|
extendsParseResult.setMetaProperty('retrievalURI', retrievalURI);
|
package/src/util/url.cjs
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
3
|
Object.defineProperty(exports, "__esModule", {
|
|
5
4
|
value: true
|
|
6
5
|
});
|
|
7
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;
|
|
8
|
-
var _process = _interopRequireDefault(require("process"));
|
|
9
7
|
var _ramda = require("ramda");
|
|
10
8
|
var _ramdaAdjunct = require("ramda-adjunct");
|
|
11
9
|
/**
|
|
@@ -18,7 +16,7 @@ var _ramdaAdjunct = require("ramda-adjunct");
|
|
|
18
16
|
* @public
|
|
19
17
|
*/
|
|
20
18
|
|
|
21
|
-
const isWindows = () => (0, _ramda.pathSatisfies)((0, _ramda.test)(/^win/), ['platform'],
|
|
19
|
+
const isWindows = () => (0, _ramda.pathSatisfies)((0, _ramda.test)(/^win/), ['platform'], globalThis.process);
|
|
22
20
|
|
|
23
21
|
/**
|
|
24
22
|
* Returns the protocol of the given URL, or `undefined` if it has no protocol.
|
|
@@ -244,11 +242,15 @@ const stripHash = uri => {
|
|
|
244
242
|
*/
|
|
245
243
|
exports.stripHash = stripHash;
|
|
246
244
|
const cwd = () => {
|
|
245
|
+
const {
|
|
246
|
+
process
|
|
247
|
+
} = globalThis;
|
|
248
|
+
|
|
247
249
|
// @ts-ignore
|
|
248
|
-
if (
|
|
250
|
+
if (typeof process?.cwd !== 'function' || process.browser) {
|
|
249
251
|
return stripHash(globalThis.location.href);
|
|
250
252
|
}
|
|
251
|
-
const path =
|
|
253
|
+
const path = process.cwd();
|
|
252
254
|
const lastChar = (0, _ramda.last)(path);
|
|
253
255
|
if (['/', '\\'].includes(lastChar)) {
|
|
254
256
|
return path;
|
|
@@ -264,13 +266,14 @@ exports.cwd = cwd;
|
|
|
264
266
|
const resolve = (from, to) => {
|
|
265
267
|
const resolvedUrl = new URL(to, new URL(from, 'resolve://'));
|
|
266
268
|
if (resolvedUrl.protocol === 'resolve:') {
|
|
267
|
-
// `from` is a relative URL
|
|
269
|
+
// `from` is a relative URL; a network-path reference (`//host/path`) keeps its authority
|
|
268
270
|
const {
|
|
271
|
+
host,
|
|
269
272
|
pathname,
|
|
270
273
|
search,
|
|
271
274
|
hash
|
|
272
275
|
} = resolvedUrl;
|
|
273
|
-
return pathname + search + hash;
|
|
276
|
+
return (host ? `//${host}` : '') + pathname + search + hash;
|
|
274
277
|
}
|
|
275
278
|
return resolvedUrl.toString();
|
|
276
279
|
};
|
package/src/util/url.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import process from 'process';
|
|
2
1
|
import { pathSatisfies, propOr, pipe, test, last } from 'ramda';
|
|
3
2
|
import { isUndefined, replaceAll, isNotUndefined, trimCharsEnd } from 'ramda-adjunct';
|
|
4
3
|
|
|
@@ -12,7 +11,7 @@ import { isUndefined, replaceAll, isNotUndefined, trimCharsEnd } from 'ramda-adj
|
|
|
12
11
|
* @public
|
|
13
12
|
*/
|
|
14
13
|
|
|
15
|
-
const isWindows = () => pathSatisfies(test(/^win/), ['platform'], process);
|
|
14
|
+
const isWindows = () => pathSatisfies(test(/^win/), ['platform'], globalThis.process);
|
|
16
15
|
|
|
17
16
|
/**
|
|
18
17
|
* Returns the protocol of the given URL, or `undefined` if it has no protocol.
|
|
@@ -229,8 +228,12 @@ export const stripHash = uri => {
|
|
|
229
228
|
* @public
|
|
230
229
|
*/
|
|
231
230
|
export const cwd = () => {
|
|
231
|
+
const {
|
|
232
|
+
process
|
|
233
|
+
} = globalThis;
|
|
234
|
+
|
|
232
235
|
// @ts-ignore
|
|
233
|
-
if (process.browser) {
|
|
236
|
+
if (typeof process?.cwd !== 'function' || process.browser) {
|
|
234
237
|
return stripHash(globalThis.location.href);
|
|
235
238
|
}
|
|
236
239
|
const path = process.cwd();
|
|
@@ -248,13 +251,14 @@ export const cwd = () => {
|
|
|
248
251
|
export const resolve = (from, to) => {
|
|
249
252
|
const resolvedUrl = new URL(to, new URL(from, 'resolve://'));
|
|
250
253
|
if (resolvedUrl.protocol === 'resolve:') {
|
|
251
|
-
// `from` is a relative URL
|
|
254
|
+
// `from` is a relative URL; a network-path reference (`//host/path`) keeps its authority
|
|
252
255
|
const {
|
|
256
|
+
host,
|
|
253
257
|
pathname,
|
|
254
258
|
search,
|
|
255
259
|
hash
|
|
256
260
|
} = resolvedUrl;
|
|
257
|
-
return pathname + search + hash;
|
|
261
|
+
return (host ? `//${host}` : '') + pathname + search + hash;
|
|
258
262
|
}
|
|
259
263
|
return resolvedUrl.toString();
|
|
260
264
|
};
|
|
@@ -2,6 +2,7 @@ import { Element } from '@speclynx/apidom-datamodel';
|
|
|
2
2
|
import DereferenceStrategy, { DereferenceStrategyOptions } from '../DereferenceStrategy.ts';
|
|
3
3
|
import File from '../../../File.ts';
|
|
4
4
|
import type { ReferenceOptions } from '../../../options/index.ts';
|
|
5
|
+
import Overlay1DereferenceVisitor from './visitor.ts';
|
|
5
6
|
export type { default as DereferenceStrategy, DereferenceStrategyOptions, } from '../DereferenceStrategy.ts';
|
|
6
7
|
export type { default as File, FileOptions } from '../../../File.ts';
|
|
7
8
|
export type { default as Reference, ReferenceOptions } from '../../../Reference.ts';
|
|
@@ -25,4 +26,6 @@ declare class Overlay1DereferenceStrategy extends DereferenceStrategy {
|
|
|
25
26
|
dereference(file: File, options: ReferenceOptions): Promise<Element>;
|
|
26
27
|
}
|
|
27
28
|
export { dereferenceExtends } from './extends.ts';
|
|
29
|
+
export { Overlay1DereferenceVisitor };
|
|
30
|
+
export type { Overlay1DereferenceVisitorOptions } from './visitor.ts';
|
|
28
31
|
export default Overlay1DereferenceStrategy;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Element } from '@speclynx/apidom-datamodel';
|
|
2
|
+
import type { Path } from '@speclynx/apidom-traverse';
|
|
3
|
+
import Reference from '../../../Reference.ts';
|
|
4
|
+
import type { ReferenceOptions } from '../../../options/index.ts';
|
|
5
|
+
/**
|
|
6
|
+
* @public
|
|
7
|
+
*/
|
|
8
|
+
export interface Overlay1DereferenceVisitorOptions {
|
|
9
|
+
readonly reference: Reference;
|
|
10
|
+
readonly options: ReferenceOptions;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
declare class Overlay1DereferenceVisitor {
|
|
16
|
+
protected readonly reference: Reference;
|
|
17
|
+
protected readonly options: ReferenceOptions;
|
|
18
|
+
constructor({ reference, options }: Overlay1DereferenceVisitorOptions);
|
|
19
|
+
ReusableActionReferenceElement(path: Path<Element>): void;
|
|
20
|
+
}
|
|
21
|
+
export default Overlay1DereferenceVisitor;
|