@speclynx/apidom-overlay 6.1.0 → 6.1.2
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 +13 -0
- package/README.md +1 -1
- package/dist/apidom-overlay.browser.js +471 -338
- package/dist/apidom-overlay.browser.min.js +1 -1
- package/package.json +9 -9
- package/src/diff/realms/apidom.cjs +28 -7
- package/src/diff/realms/apidom.mjs +27 -7
- package/src/diff/realms/uri.cjs +2 -0
- package/src/diff/realms/uri.mjs +3 -1
- package/types/apidom-overlay.d.ts +5 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@speclynx/apidom-overlay",
|
|
3
|
-
"version": "6.1.
|
|
3
|
+
"version": "6.1.2",
|
|
4
4
|
"description": "Apply Overlay 1.x.y documents to API definitions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"apidom",
|
|
@@ -53,13 +53,13 @@
|
|
|
53
53
|
"author": "Vladimir Gorej",
|
|
54
54
|
"license": "Apache-2.0",
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@babel/runtime-corejs3": "^8.0.
|
|
57
|
-
"@speclynx/apidom-core": "6.1.
|
|
58
|
-
"@speclynx/apidom-datamodel": "6.1.
|
|
59
|
-
"@speclynx/apidom-error": "6.1.
|
|
60
|
-
"@speclynx/apidom-json-path": "6.1.
|
|
61
|
-
"@speclynx/apidom-ns-overlay-1": "6.1.
|
|
62
|
-
"@speclynx/apidom-reference": "6.1.
|
|
56
|
+
"@babel/runtime-corejs3": "^8.0.8",
|
|
57
|
+
"@speclynx/apidom-core": "6.1.2",
|
|
58
|
+
"@speclynx/apidom-datamodel": "6.1.2",
|
|
59
|
+
"@speclynx/apidom-error": "6.1.2",
|
|
60
|
+
"@speclynx/apidom-json-path": "6.1.2",
|
|
61
|
+
"@speclynx/apidom-ns-overlay-1": "6.1.2",
|
|
62
|
+
"@speclynx/apidom-reference": "6.1.2",
|
|
63
63
|
"ramda": "~0.32.0",
|
|
64
64
|
"type-fest": "^5.10.0"
|
|
65
65
|
},
|
|
@@ -73,5 +73,5 @@
|
|
|
73
73
|
"README.md",
|
|
74
74
|
"CHANGELOG.md"
|
|
75
75
|
],
|
|
76
|
-
"gitHead": "
|
|
76
|
+
"gitHead": "e3ba735e1c56369bb263dd8246c711d405ed9606"
|
|
77
77
|
}
|
|
@@ -4,7 +4,7 @@ var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequ
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.diff = void 0;
|
|
7
|
+
exports.diff = exports.assertSupportedOverlayVersion = void 0;
|
|
8
8
|
var _ramda = require("ramda");
|
|
9
9
|
var _apidomDatamodel = require("@speclynx/apidom-datamodel");
|
|
10
10
|
var _apidomCore = require("@speclynx/apidom-core");
|
|
@@ -22,6 +22,21 @@ const defaultDiffOptions = {
|
|
|
22
22
|
version: '0.0.0'
|
|
23
23
|
}
|
|
24
24
|
};
|
|
25
|
+
|
|
26
|
+
// generated actions update primitive values and concatenate arrays, which Overlay 1.0.0 doesn't allow
|
|
27
|
+
const supportedOverlayVersions = _apidomNsOverlay.mediaTypes.filterByFormat('generic').map(mediaType => mediaType.split('version=')[1]).filter(version => version !== '1.0.0');
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Throws {@link OverlayError} when the overlay version option is unsupported.
|
|
31
|
+
* Shared with the URI realm, which checks it before parsing any document.
|
|
32
|
+
*/
|
|
33
|
+
const assertSupportedOverlayVersion = overlay => {
|
|
34
|
+
const overlayVersion = overlay ?? defaultDiffOptions.overlay;
|
|
35
|
+
if (!supportedOverlayVersions.includes(overlayVersion)) {
|
|
36
|
+
throw new _OverlayError.default(`Unsupported overlay version "${overlayVersion}": diff supports ${supportedOverlayVersions.join(', ')}`);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
exports.assertSupportedOverlayVersion = assertSupportedOverlayVersion;
|
|
25
40
|
const createUpdateAction = (segments, value) => {
|
|
26
41
|
const action = new _apidomNsOverlay.ActionElement();
|
|
27
42
|
action.target = new _apidomDatamodel.StringElement(_apidomJsonPath.NormalizedPath.from(segments));
|
|
@@ -41,14 +56,19 @@ const createRemoveAction = segments => {
|
|
|
41
56
|
return action;
|
|
42
57
|
};
|
|
43
58
|
|
|
44
|
-
// elements are compared by their
|
|
45
|
-
// empty string; Element#equals compares the elements' own values, where both are an empty string
|
|
59
|
+
// elements are compared by their values, read with the core toValue
|
|
46
60
|
const isEqual = (left, right) => (0, _ramda.equals)((0, _apidomCore.toValue)(left), (0, _apidomCore.toValue)(right));
|
|
61
|
+
|
|
62
|
+
// a null (as an empty YAML node is) filled in with a scalar, or a scalar emptied to a null, is
|
|
63
|
+
// updated in place like a value, keeping its position; any other change of type is structural
|
|
64
|
+
const isStructuralChange = (left, right) => {
|
|
65
|
+
const kinds = [left.primitive(), right.primitive()];
|
|
66
|
+
const isCollection = kinds.some(kind => kind === 'object' || kind === 'array');
|
|
67
|
+
return kinds[0] !== kinds[1] && (isCollection || !kinds.includes('null'));
|
|
68
|
+
};
|
|
47
69
|
const diffElements = (left, right, segments, actions) => {
|
|
48
70
|
if (isEqual(left, right)) return;
|
|
49
|
-
|
|
50
|
-
const rightKind = right.primitive();
|
|
51
|
-
if (leftKind !== rightKind) {
|
|
71
|
+
if (isStructuralChange(left, right)) {
|
|
52
72
|
if (segments.length === 0) {
|
|
53
73
|
throw new _OverlayError.default('Cannot diff documents with incompatible root types');
|
|
54
74
|
}
|
|
@@ -111,7 +131,7 @@ const diffArrays = (left, right, segments, actions) => {
|
|
|
111
131
|
const leftItem = left.get(i);
|
|
112
132
|
const rightItem = right.get(i);
|
|
113
133
|
if (isEqual(leftItem, rightItem)) continue;
|
|
114
|
-
if (leftItem
|
|
134
|
+
if (isStructuralChange(leftItem, rightItem)) {
|
|
115
135
|
// structural type change at index i — reconstruct tail:
|
|
116
136
|
// remove from end down to i (reverse order preserves index stability),
|
|
117
137
|
// then batch-append right[i..] as a single ArrayElement (Overlay concat semantics)
|
|
@@ -166,6 +186,7 @@ const diff = (leftElement, rightElement, options = {}) => {
|
|
|
166
186
|
const infoTitle = options.info?.title ?? defaultDiffOptions.info.title;
|
|
167
187
|
const infoVersion = options.info?.version ?? defaultDiffOptions.info.version;
|
|
168
188
|
const infoDescription = options.info?.description;
|
|
189
|
+
assertSupportedOverlayVersion(overlayVersion);
|
|
169
190
|
const actions = [];
|
|
170
191
|
diffElements(leftElement, rightElement, [], actions);
|
|
171
192
|
if (actions.length === 0 && options.onEmptyDiff === 'throw') {
|
|
@@ -2,7 +2,7 @@ import { equals } from 'ramda';
|
|
|
2
2
|
import { ObjectElement, ArrayElement, StringElement, BooleanElement, isObjectElement, isArrayElement, cloneDeep } from '@speclynx/apidom-datamodel';
|
|
3
3
|
import { toValue } from '@speclynx/apidom-core';
|
|
4
4
|
import { NormalizedPath } from '@speclynx/apidom-json-path';
|
|
5
|
-
import { ActionElement, Overlay1Element, InfoElement, OverlayElement, ActionsElement } from '@speclynx/apidom-ns-overlay-1';
|
|
5
|
+
import { ActionElement, Overlay1Element, InfoElement, OverlayElement, ActionsElement, mediaTypes } from '@speclynx/apidom-ns-overlay-1';
|
|
6
6
|
import OverlayError from "../../errors/OverlayError.mjs";
|
|
7
7
|
/**
|
|
8
8
|
* @public
|
|
@@ -14,6 +14,20 @@ const defaultDiffOptions = {
|
|
|
14
14
|
version: '0.0.0'
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
|
+
|
|
18
|
+
// generated actions update primitive values and concatenate arrays, which Overlay 1.0.0 doesn't allow
|
|
19
|
+
const supportedOverlayVersions = mediaTypes.filterByFormat('generic').map(mediaType => mediaType.split('version=')[1]).filter(version => version !== '1.0.0');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Throws {@link OverlayError} when the overlay version option is unsupported.
|
|
23
|
+
* Shared with the URI realm, which checks it before parsing any document.
|
|
24
|
+
*/
|
|
25
|
+
export const assertSupportedOverlayVersion = overlay => {
|
|
26
|
+
const overlayVersion = overlay ?? defaultDiffOptions.overlay;
|
|
27
|
+
if (!supportedOverlayVersions.includes(overlayVersion)) {
|
|
28
|
+
throw new OverlayError(`Unsupported overlay version "${overlayVersion}": diff supports ${supportedOverlayVersions.join(', ')}`);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
17
31
|
const createUpdateAction = (segments, value) => {
|
|
18
32
|
const action = new ActionElement();
|
|
19
33
|
action.target = new StringElement(NormalizedPath.from(segments));
|
|
@@ -33,14 +47,19 @@ const createRemoveAction = segments => {
|
|
|
33
47
|
return action;
|
|
34
48
|
};
|
|
35
49
|
|
|
36
|
-
// elements are compared by their
|
|
37
|
-
// empty string; Element#equals compares the elements' own values, where both are an empty string
|
|
50
|
+
// elements are compared by their values, read with the core toValue
|
|
38
51
|
const isEqual = (left, right) => equals(toValue(left), toValue(right));
|
|
52
|
+
|
|
53
|
+
// a null (as an empty YAML node is) filled in with a scalar, or a scalar emptied to a null, is
|
|
54
|
+
// updated in place like a value, keeping its position; any other change of type is structural
|
|
55
|
+
const isStructuralChange = (left, right) => {
|
|
56
|
+
const kinds = [left.primitive(), right.primitive()];
|
|
57
|
+
const isCollection = kinds.some(kind => kind === 'object' || kind === 'array');
|
|
58
|
+
return kinds[0] !== kinds[1] && (isCollection || !kinds.includes('null'));
|
|
59
|
+
};
|
|
39
60
|
const diffElements = (left, right, segments, actions) => {
|
|
40
61
|
if (isEqual(left, right)) return;
|
|
41
|
-
|
|
42
|
-
const rightKind = right.primitive();
|
|
43
|
-
if (leftKind !== rightKind) {
|
|
62
|
+
if (isStructuralChange(left, right)) {
|
|
44
63
|
if (segments.length === 0) {
|
|
45
64
|
throw new OverlayError('Cannot diff documents with incompatible root types');
|
|
46
65
|
}
|
|
@@ -103,7 +122,7 @@ const diffArrays = (left, right, segments, actions) => {
|
|
|
103
122
|
const leftItem = left.get(i);
|
|
104
123
|
const rightItem = right.get(i);
|
|
105
124
|
if (isEqual(leftItem, rightItem)) continue;
|
|
106
|
-
if (leftItem
|
|
125
|
+
if (isStructuralChange(leftItem, rightItem)) {
|
|
107
126
|
// structural type change at index i — reconstruct tail:
|
|
108
127
|
// remove from end down to i (reverse order preserves index stability),
|
|
109
128
|
// then batch-append right[i..] as a single ArrayElement (Overlay concat semantics)
|
|
@@ -158,6 +177,7 @@ export const diff = (leftElement, rightElement, options = {}) => {
|
|
|
158
177
|
const infoTitle = options.info?.title ?? defaultDiffOptions.info.title;
|
|
159
178
|
const infoVersion = options.info?.version ?? defaultDiffOptions.info.version;
|
|
160
179
|
const infoDescription = options.info?.description;
|
|
180
|
+
assertSupportedOverlayVersion(overlayVersion);
|
|
161
181
|
const actions = [];
|
|
162
182
|
diffElements(leftElement, rightElement, [], actions);
|
|
163
183
|
if (actions.length === 0 && options.onEmptyDiff === 'throw') {
|
package/src/diff/realms/uri.cjs
CHANGED
|
@@ -49,6 +49,8 @@ const defaultOptions = exports.defaultOptions = {
|
|
|
49
49
|
* @public
|
|
50
50
|
*/
|
|
51
51
|
const diff = async (leftURI, rightURI, options = defaultOptions) => {
|
|
52
|
+
// fail on an unsupported version before fetching and parsing the documents
|
|
53
|
+
(0, _apidom.assertSupportedOverlayVersion)(options.overlay);
|
|
52
54
|
const mergedRefOptions = (0, _apidomReference.mergeOptions)(defaultReferenceOptions, options.reference ?? {});
|
|
53
55
|
const [leftParseResult, rightParseResult] = await Promise.all([(0, _apidomReference.parse)(leftURI, mergedRefOptions), (0, _apidomReference.parse)(rightURI, mergedRefOptions)]);
|
|
54
56
|
const leftElement = leftParseResult.api;
|
package/src/diff/realms/uri.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { parse, mergeOptions } from '@speclynx/apidom-reference';
|
|
2
|
-
import { diff as diffApiDOM } from "./apidom.mjs";
|
|
2
|
+
import { diff as diffApiDOM, assertSupportedOverlayVersion } from "./apidom.mjs";
|
|
3
3
|
import OverlayError from "../../errors/OverlayError.mjs";
|
|
4
4
|
/**
|
|
5
5
|
* @public
|
|
@@ -41,6 +41,8 @@ export const defaultOptions = {
|
|
|
41
41
|
* @public
|
|
42
42
|
*/
|
|
43
43
|
const diff = async (leftURI, rightURI, options = defaultOptions) => {
|
|
44
|
+
// fail on an unsupported version before fetching and parsing the documents
|
|
45
|
+
assertSupportedOverlayVersion(options.overlay);
|
|
44
46
|
const mergedRefOptions = mergeOptions(defaultReferenceOptions, options.reference ?? {});
|
|
45
47
|
const [leftParseResult, rightParseResult] = await Promise.all([parse(leftURI, mergedRefOptions), parse(rightURI, mergedRefOptions)]);
|
|
46
48
|
const leftElement = leftParseResult.api;
|
|
@@ -155,6 +155,11 @@ export declare const diffApiDOM: (leftElement: Element_2, rightElement: Element_
|
|
|
155
155
|
* @public
|
|
156
156
|
*/
|
|
157
157
|
export declare interface DiffOptions {
|
|
158
|
+
/**
|
|
159
|
+
* Version written to the `overlay` field (default `'1.2.0'`). Must be `1.1.0` or later,
|
|
160
|
+
* otherwise {@link OverlayError} is thrown: generated actions update primitive values and
|
|
161
|
+
* concatenate arrays, which Overlay 1.0.0 doesn't allow.
|
|
162
|
+
*/
|
|
158
163
|
readonly overlay?: string;
|
|
159
164
|
readonly info?: {
|
|
160
165
|
title?: string;
|