@speclynx/apidom-reference 5.2.7 → 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 +16 -0
- package/README.md +23 -1
- package/dist/apidom-reference.browser.js +860 -31
- package/dist/apidom-reference.browser.min.js +1 -1
- package/package.json +28 -28
- 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 +3 -2
- package/src/util/url.mjs +3 -2
- 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,32 +299,32 @@
|
|
|
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",
|
|
@@ -345,5 +345,5 @@
|
|
|
345
345
|
"README.md",
|
|
346
346
|
"CHANGELOG.md"
|
|
347
347
|
],
|
|
348
|
-
"gitHead": "
|
|
348
|
+
"gitHead": "d2ea4f01cac54a0d5e1030386e3b0b60664c9619"
|
|
349
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
|
@@ -266,13 +266,14 @@ exports.cwd = cwd;
|
|
|
266
266
|
const resolve = (from, to) => {
|
|
267
267
|
const resolvedUrl = new URL(to, new URL(from, 'resolve://'));
|
|
268
268
|
if (resolvedUrl.protocol === 'resolve:') {
|
|
269
|
-
// `from` is a relative URL
|
|
269
|
+
// `from` is a relative URL; a network-path reference (`//host/path`) keeps its authority
|
|
270
270
|
const {
|
|
271
|
+
host,
|
|
271
272
|
pathname,
|
|
272
273
|
search,
|
|
273
274
|
hash
|
|
274
275
|
} = resolvedUrl;
|
|
275
|
-
return pathname + search + hash;
|
|
276
|
+
return (host ? `//${host}` : '') + pathname + search + hash;
|
|
276
277
|
}
|
|
277
278
|
return resolvedUrl.toString();
|
|
278
279
|
};
|
package/src/util/url.mjs
CHANGED
|
@@ -251,13 +251,14 @@ export const cwd = () => {
|
|
|
251
251
|
export const resolve = (from, to) => {
|
|
252
252
|
const resolvedUrl = new URL(to, new URL(from, 'resolve://'));
|
|
253
253
|
if (resolvedUrl.protocol === 'resolve:') {
|
|
254
|
-
// `from` is a relative URL
|
|
254
|
+
// `from` is a relative URL; a network-path reference (`//host/path`) keeps its authority
|
|
255
255
|
const {
|
|
256
|
+
host,
|
|
256
257
|
pathname,
|
|
257
258
|
search,
|
|
258
259
|
hash
|
|
259
260
|
} = resolvedUrl;
|
|
260
|
-
return pathname + search + hash;
|
|
261
|
+
return (host ? `//${host}` : '') + pathname + search + hash;
|
|
261
262
|
}
|
|
262
263
|
return resolvedUrl.toString();
|
|
263
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;
|