@speclynx/apidom-core 4.0.3 → 4.0.5
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 +10 -0
- package/dist/apidom-core.browser.js +28 -4
- package/dist/apidom-core.browser.min.js +1 -1
- package/package.json +7 -6
- package/src/fields/fixed-fields.ts +0 -61
- package/src/fields/index.ts +0 -2
- package/src/identity/errors/ElementIdentityError.ts +0 -26
- package/src/identity/index.ts +0 -64
- package/src/index.ts +0 -81
- package/src/media-types.ts +0 -24
- package/src/merge/deepmerge.ts +0 -274
- package/src/merge/merge-left.ts +0 -14
- package/src/merge/merge-right.ts +0 -42
- package/src/namespace.ts +0 -8
- package/src/refractor/plugins/dispatcher/index.ts +0 -102
- package/src/refractor/plugins/element-identity.ts +0 -31
- package/src/refractor/plugins/semantic-element-identity.ts +0 -32
- package/src/refractor/toolbox.ts +0 -88
- package/src/specification.ts +0 -68
- package/src/transcluder/Transcluder.ts +0 -147
- package/src/transcluder/index.ts +0 -15
- package/src/transformers/dehydrate.ts +0 -14
- package/src/transformers/from.ts +0 -34
- package/src/transformers/serializers/json.ts +0 -107
- package/src/transformers/serializers/value.ts +0 -70
- package/src/transformers/serializers/yaml-1-2.ts +0 -205
- package/src/transformers/sexprs.ts +0 -30
- package/src/transformers/to-string.ts +0 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@speclynx/apidom-core",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.5",
|
|
4
4
|
"description": "Tools for manipulating ApiDOM structures.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"apidom",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"license": "Apache-2.0",
|
|
58
58
|
"dependencies": {
|
|
59
59
|
"@babel/runtime-corejs3": "^7.28.4",
|
|
60
|
-
"@speclynx/apidom-datamodel": "4.0.
|
|
61
|
-
"@speclynx/apidom-error": "4.0.
|
|
62
|
-
"@speclynx/apidom-traverse": "4.0.
|
|
60
|
+
"@speclynx/apidom-datamodel": "4.0.5",
|
|
61
|
+
"@speclynx/apidom-error": "4.0.5",
|
|
62
|
+
"@speclynx/apidom-traverse": "4.0.5",
|
|
63
63
|
"ramda": "~0.32.0",
|
|
64
64
|
"ramda-adjunct": "^6.0.0",
|
|
65
65
|
"short-unique-id": "^5.3.2",
|
|
@@ -67,7 +67,8 @@
|
|
|
67
67
|
"yaml": "^2.8.2"
|
|
68
68
|
},
|
|
69
69
|
"files": [
|
|
70
|
-
"src
|
|
70
|
+
"src/**/*.mjs",
|
|
71
|
+
"src/**/*.cjs",
|
|
71
72
|
"dist/",
|
|
72
73
|
"types/apidom-core.d.ts",
|
|
73
74
|
"LICENSES",
|
|
@@ -75,5 +76,5 @@
|
|
|
75
76
|
"README.md",
|
|
76
77
|
"CHANGELOG.md"
|
|
77
78
|
],
|
|
78
|
-
"gitHead": "
|
|
79
|
+
"gitHead": "5a85d2a832eeefb07d03760faa391b457447e966"
|
|
79
80
|
}
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { Element } from '@speclynx/apidom-datamodel';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Represents a fixed field definition.
|
|
5
|
-
* @public
|
|
6
|
-
*/
|
|
7
|
-
export interface FixedField {
|
|
8
|
-
name: string;
|
|
9
|
-
[key: string]: unknown;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @public
|
|
14
|
-
*/
|
|
15
|
-
export type FixedFieldsElementClass = typeof Element & {
|
|
16
|
-
fixedFields?: FixedField[];
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Returns the fixed fields for an Element class or instance.
|
|
21
|
-
*
|
|
22
|
-
* @param elementOrClass - Element instance or class
|
|
23
|
-
* @param options - Options for return format
|
|
24
|
-
* @returns Array of fixed fields, or object indexed by name if options.indexed is true
|
|
25
|
-
*
|
|
26
|
-
* @example
|
|
27
|
-
* ```ts
|
|
28
|
-
* import { fixedFields } from '@speclynx/apidom-core';
|
|
29
|
-
*
|
|
30
|
-
* // Get fixed fields as array
|
|
31
|
-
* const fields = fixedFields(ParameterElement);
|
|
32
|
-
*
|
|
33
|
-
* // Get fixed fields as indexed object for O(1) lookups
|
|
34
|
-
* const fieldsIndex = fixedFields(ParameterElement, { indexed: true });
|
|
35
|
-
* if (Object.hasOwn(fieldsIndex, 'description')) {
|
|
36
|
-
* // field exists
|
|
37
|
-
* }
|
|
38
|
-
* ```
|
|
39
|
-
*
|
|
40
|
-
* @public
|
|
41
|
-
*/
|
|
42
|
-
export function fixedFields<T extends boolean = false>(
|
|
43
|
-
elementOrClass: Element | FixedFieldsElementClass,
|
|
44
|
-
options?: { indexed?: T },
|
|
45
|
-
): T extends true ? Record<string, FixedField> : FixedField[] {
|
|
46
|
-
const constructor = (
|
|
47
|
-
elementOrClass instanceof Element ? elementOrClass.constructor : elementOrClass
|
|
48
|
-
) as FixedFieldsElementClass;
|
|
49
|
-
|
|
50
|
-
const fields = constructor.fixedFields ?? [];
|
|
51
|
-
|
|
52
|
-
if (options?.indexed) {
|
|
53
|
-
return Object.fromEntries(fields.map((f) => [f.name, f])) as T extends true
|
|
54
|
-
? Record<string, FixedField>
|
|
55
|
-
: FixedField[];
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return fields as T extends true ? Record<string, FixedField> : FixedField[];
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export default fixedFields;
|
package/src/fields/index.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { ApiDOMStructuredError } from '@speclynx/apidom-error';
|
|
2
|
-
import type { ApiDOMErrorOptions } from '@speclynx/apidom-error';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @public
|
|
6
|
-
*/
|
|
7
|
-
export interface ElementIdentityErrorOptions extends ApiDOMErrorOptions {
|
|
8
|
-
readonly value: unknown;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @public
|
|
13
|
-
*/
|
|
14
|
-
class ElementIdentityError extends ApiDOMStructuredError {
|
|
15
|
-
public readonly value: unknown;
|
|
16
|
-
|
|
17
|
-
constructor(message?: string, structuredOptions?: ElementIdentityErrorOptions) {
|
|
18
|
-
super(message, structuredOptions);
|
|
19
|
-
|
|
20
|
-
if (typeof structuredOptions !== 'undefined') {
|
|
21
|
-
this.value = structuredOptions.value;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default ElementIdentityError;
|
package/src/identity/index.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { Element, isElement } from '@speclynx/apidom-datamodel';
|
|
2
|
-
import ShortUniqueId from 'short-unique-id';
|
|
3
|
-
|
|
4
|
-
import ElementIdentityError from './errors/ElementIdentityError.ts';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @public
|
|
8
|
-
*/
|
|
9
|
-
export class IdentityManager {
|
|
10
|
-
protected readonly uuid: ShortUniqueId;
|
|
11
|
-
|
|
12
|
-
protected readonly identityMap: WeakMap<Element, string>;
|
|
13
|
-
|
|
14
|
-
constructor({ length = 6 } = {}) {
|
|
15
|
-
this.uuid = new ShortUniqueId({ length });
|
|
16
|
-
this.identityMap = new WeakMap();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
identify<T extends Element>(this: IdentityManager, element: T): string {
|
|
20
|
-
if (!isElement(element)) {
|
|
21
|
-
throw new ElementIdentityError(
|
|
22
|
-
'Cannot not identify the element. `element` is neither structurally compatible nor a subclass of an Element class.',
|
|
23
|
-
{
|
|
24
|
-
value: element,
|
|
25
|
-
},
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// use already assigned identity
|
|
30
|
-
if (element.hasMetaProperty('id')) {
|
|
31
|
-
const existingId = element.id;
|
|
32
|
-
if (typeof existingId === 'string' && existingId !== '') {
|
|
33
|
-
return existingId;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// assign identity in immutable way
|
|
38
|
-
if (this.identityMap.has(element)) {
|
|
39
|
-
return this.identityMap.get(element)!;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// return element identity
|
|
43
|
-
const id = this.generateId();
|
|
44
|
-
this.identityMap.set(element, id);
|
|
45
|
-
return id;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
forget<T extends Element>(element: T): boolean {
|
|
49
|
-
if (this.identityMap.has(element)) {
|
|
50
|
-
this.identityMap.delete(element);
|
|
51
|
-
return true;
|
|
52
|
-
}
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
generateId(): string {
|
|
57
|
-
return this.uuid.randomUUID();
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* @public
|
|
63
|
-
*/
|
|
64
|
-
export const defaultIdentityManager = new IdentityManager();
|
package/src/index.ts
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
export { dispatchPluginsSync as dispatchRefractorPlugins } from './refractor/plugins/dispatcher/index.ts';
|
|
2
|
-
export type {
|
|
3
|
-
DispatchPluginsSync,
|
|
4
|
-
DispatchPluginsAsync,
|
|
5
|
-
DispatchPluginsOptions,
|
|
6
|
-
} from './refractor/plugins/dispatcher/index.ts';
|
|
7
|
-
|
|
8
|
-
export { default as createToolbox } from './refractor/toolbox.ts';
|
|
9
|
-
export type { Toolbox, Predicates } from './refractor/toolbox.ts';
|
|
10
|
-
|
|
11
|
-
export { default as refractorPluginElementIdentity } from './refractor/plugins/element-identity.ts';
|
|
12
|
-
export { default as refractorPluginSemanticElementIdentity } from './refractor/plugins/semantic-element-identity.ts';
|
|
13
|
-
|
|
14
|
-
export { default as MediaTypes } from './media-types.ts';
|
|
15
|
-
|
|
16
|
-
export { transclude, default as Transcluder } from './transcluder/index.ts';
|
|
17
|
-
|
|
18
|
-
export { resolveSpecification, type ResolvedSpecification } from './specification.ts';
|
|
19
|
-
|
|
20
|
-
export { defaultIdentityManager, IdentityManager } from './identity/index.ts';
|
|
21
|
-
export { default as ElementIdentityError } from './identity/errors/ElementIdentityError.ts';
|
|
22
|
-
export type { ElementIdentityErrorOptions } from './identity/errors/ElementIdentityError.ts';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Transforms data to an Element from a particular namespace.
|
|
26
|
-
*/
|
|
27
|
-
export { default as from } from './transformers/from.ts';
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Transforms the ApiDOM into JavaScript POJO.
|
|
31
|
-
* This POJO would be the result of interpreting the ApiDOM
|
|
32
|
-
* into JavaScript structure.
|
|
33
|
-
*/
|
|
34
|
-
export { default as toValue } from './transformers/serializers/value.ts';
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Transforms the ApiDOM into JSON string.
|
|
38
|
-
*/
|
|
39
|
-
export { default as toJSON, type JSONSerializerOptions } from './transformers/serializers/json.ts';
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Transforms the ApiDOM into YAML string.
|
|
43
|
-
*/
|
|
44
|
-
export {
|
|
45
|
-
default as toYAML,
|
|
46
|
-
type YAMLSerializerOptions,
|
|
47
|
-
} from './transformers/serializers/yaml-1-2.ts';
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Creates a refract representation of an Element.
|
|
51
|
-
* https://github.com/refractproject/refract-spec
|
|
52
|
-
*/
|
|
53
|
-
export { default as dehydrate } from './transformers/dehydrate.ts';
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Create a refracted string representation of an Element.
|
|
57
|
-
*/
|
|
58
|
-
export { default as toString } from './transformers/to-string.ts';
|
|
59
|
-
|
|
60
|
-
export { default as sexprs } from './transformers/sexprs.ts';
|
|
61
|
-
|
|
62
|
-
export { default as deepmerge } from './merge/deepmerge.ts';
|
|
63
|
-
export type {
|
|
64
|
-
DeepMergeUserOptions,
|
|
65
|
-
ObjectOrArrayElement,
|
|
66
|
-
AnyElement,
|
|
67
|
-
DeepMerge,
|
|
68
|
-
DeepMergeOptions,
|
|
69
|
-
ArrayElementMerge as DeepMergeArrayElementMerge,
|
|
70
|
-
ObjectElementMerge as DeepMergeObjectElementMerge,
|
|
71
|
-
CustomMerge as DeepMergeCustomMerge,
|
|
72
|
-
CustomMetaMerge as DeepMergeCustomMetaMerge,
|
|
73
|
-
CustomAttributesMerge as DeepMergeCustomAttributesMerge,
|
|
74
|
-
} from './merge/deepmerge.ts';
|
|
75
|
-
export { default as mergeRight } from './merge/merge-right.ts';
|
|
76
|
-
export type { MergeRightOptions } from './merge/merge-right.ts';
|
|
77
|
-
export { default as mergeLeft } from './merge/merge-left.ts';
|
|
78
|
-
export type { MergeRightOptions as MergeLeftOptions } from './merge/merge-right.ts';
|
|
79
|
-
|
|
80
|
-
export { fixedFields } from './fields/index.ts';
|
|
81
|
-
export type { FixedField, FixedFieldsElementClass } from './fields/index.ts';
|
package/src/media-types.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { NotImplementedError } from '@speclynx/apidom-error';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @public
|
|
5
|
-
*/
|
|
6
|
-
class MediaTypes<T> extends Array<T> {
|
|
7
|
-
unknownMediaType = 'application/octet-stream';
|
|
8
|
-
|
|
9
|
-
filterByFormat() {
|
|
10
|
-
throw new NotImplementedError(
|
|
11
|
-
'filterByFormat method in MediaTypes class is not yet implemented.',
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
findBy() {
|
|
16
|
-
throw new NotImplementedError('findBy method in MediaTypes class is not yet implemented.');
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
latest() {
|
|
20
|
-
throw new NotImplementedError('latest method in MediaTypes class is not yet implemented.');
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export default MediaTypes;
|
package/src/merge/deepmerge.ts
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ObjectElement,
|
|
3
|
-
ArrayElement,
|
|
4
|
-
MemberElement,
|
|
5
|
-
Element,
|
|
6
|
-
Metadata,
|
|
7
|
-
isObjectElement,
|
|
8
|
-
isArrayElement,
|
|
9
|
-
cloneDeep,
|
|
10
|
-
cloneShallow,
|
|
11
|
-
} from '@speclynx/apidom-datamodel';
|
|
12
|
-
|
|
13
|
-
import toValue from '../transformers/serializers/value.ts';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* @public
|
|
17
|
-
*/
|
|
18
|
-
export type ObjectOrArrayElement = ObjectElement | ArrayElement;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* @public
|
|
22
|
-
*/
|
|
23
|
-
export type AnyElement = ObjectElement | ArrayElement | Element;
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @public
|
|
27
|
-
*/
|
|
28
|
-
export type DeepMerge = (
|
|
29
|
-
targetElement: ObjectOrArrayElement,
|
|
30
|
-
sourceElement: ObjectOrArrayElement,
|
|
31
|
-
options?: DeepMergeOptions,
|
|
32
|
-
) => AnyElement;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* @public
|
|
36
|
-
*/
|
|
37
|
-
export type CustomMerge = (keyElement: Element, options: DeepMergeOptions) => DeepMerge;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* @public
|
|
41
|
-
*/
|
|
42
|
-
export type CustomMetaMerge = (
|
|
43
|
-
targetElementMeta: Metadata,
|
|
44
|
-
sourceElementMeta: Metadata,
|
|
45
|
-
) => Metadata;
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* @public
|
|
49
|
-
*/
|
|
50
|
-
export type CustomAttributesMerge = (
|
|
51
|
-
targetElementAttributes: ObjectElement,
|
|
52
|
-
sourceElementAttributes: ObjectElement,
|
|
53
|
-
) => ObjectElement;
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* @public
|
|
57
|
-
*/
|
|
58
|
-
export type ArrayElementMerge = (
|
|
59
|
-
targetElement: ArrayElement,
|
|
60
|
-
sourceElement: ArrayElement,
|
|
61
|
-
options: DeepMergeOptions,
|
|
62
|
-
) => ArrayElement;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* @public
|
|
66
|
-
*/
|
|
67
|
-
export type ObjectElementMerge = (
|
|
68
|
-
targetElement: ObjectElement,
|
|
69
|
-
source: ObjectElement,
|
|
70
|
-
options: DeepMergeOptions,
|
|
71
|
-
) => ObjectElement;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* @public
|
|
75
|
-
*/
|
|
76
|
-
export type DeepMergeUserOptions = {
|
|
77
|
-
clone?: boolean;
|
|
78
|
-
isMergeableElement?: (element: Element) => boolean;
|
|
79
|
-
arrayElementMerge?: ArrayElementMerge;
|
|
80
|
-
objectElementMerge?: ObjectElementMerge;
|
|
81
|
-
customMerge?: CustomMerge;
|
|
82
|
-
customMetaMerge?: CustomMetaMerge;
|
|
83
|
-
customAttributesMerge?: CustomAttributesMerge;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* @public
|
|
88
|
-
*/
|
|
89
|
-
export type DeepMergeOptions = DeepMergeUserOptions & {
|
|
90
|
-
clone: boolean;
|
|
91
|
-
isMergeableElement: (element: Element) => boolean;
|
|
92
|
-
arrayElementMerge: ArrayElementMerge;
|
|
93
|
-
objectElementMerge: ObjectElementMerge;
|
|
94
|
-
customMerge: CustomMerge | undefined;
|
|
95
|
-
customMetaMerge: CustomMetaMerge | undefined;
|
|
96
|
-
customAttributesMerge: CustomAttributesMerge | undefined;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
export const emptyElement = (element: ObjectElement | ArrayElement) => {
|
|
100
|
-
const meta = !element.isMetaEmpty ? element.meta.cloneDeep() : undefined;
|
|
101
|
-
const attributes = !element.isAttributesEmpty ? cloneDeep(element.attributes) : undefined;
|
|
102
|
-
|
|
103
|
-
// @ts-ignore
|
|
104
|
-
return new element.constructor(undefined, meta, attributes);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
const cloneUnlessOtherwiseSpecified = (
|
|
108
|
-
element: AnyElement,
|
|
109
|
-
options: DeepMergeOptions,
|
|
110
|
-
): AnyElement =>
|
|
111
|
-
options.clone && options.isMergeableElement(element)
|
|
112
|
-
? deepmerge(
|
|
113
|
-
emptyElement(element as ObjectOrArrayElement),
|
|
114
|
-
element as ObjectOrArrayElement,
|
|
115
|
-
options,
|
|
116
|
-
)
|
|
117
|
-
: element;
|
|
118
|
-
|
|
119
|
-
const getMergeFunction = (keyElement: Element, options: DeepMergeOptions): DeepMerge => {
|
|
120
|
-
if (typeof options.customMerge !== 'function') {
|
|
121
|
-
return deepmerge;
|
|
122
|
-
}
|
|
123
|
-
const customMerge = options.customMerge(keyElement, options);
|
|
124
|
-
return typeof customMerge === 'function' ? customMerge : deepmerge;
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const getMetaMergeFunction = (options: DeepMergeOptions): CustomMetaMerge => {
|
|
128
|
-
if (typeof options.customMetaMerge !== 'function') {
|
|
129
|
-
return (targetMeta) => targetMeta.cloneDeep();
|
|
130
|
-
}
|
|
131
|
-
return options.customMetaMerge;
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const getAttributesMergeFunction = (options: DeepMergeOptions): CustomAttributesMerge => {
|
|
135
|
-
if (typeof options.customAttributesMerge !== 'function') {
|
|
136
|
-
return (targetAttributes) => cloneDeep(targetAttributes);
|
|
137
|
-
}
|
|
138
|
-
return options.customAttributesMerge;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const mergeArrayElement: ArrayElementMerge = (targetElement, sourceElement, options) => {
|
|
142
|
-
const Ctor = targetElement.constructor as new (content: Element[]) => ArrayElement;
|
|
143
|
-
const merged = targetElement.concat(sourceElement) as ArrayElement;
|
|
144
|
-
return new Ctor(merged.map((item: Element) => cloneUnlessOtherwiseSpecified(item, options)));
|
|
145
|
-
};
|
|
146
|
-
|
|
147
|
-
const mergeObjectElement: ObjectElementMerge = (targetElement, sourceElement, options) => {
|
|
148
|
-
const destination = isObjectElement(targetElement)
|
|
149
|
-
? emptyElement(targetElement)
|
|
150
|
-
: emptyElement(sourceElement);
|
|
151
|
-
|
|
152
|
-
if (isObjectElement(targetElement)) {
|
|
153
|
-
targetElement.forEach((value, key, member) => {
|
|
154
|
-
const clonedMember = cloneShallow(member as MemberElement);
|
|
155
|
-
clonedMember.value = cloneUnlessOtherwiseSpecified(value, options);
|
|
156
|
-
destination.content.push(clonedMember);
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
sourceElement.forEach((value, key, member) => {
|
|
161
|
-
const keyValue = toValue(key) as string;
|
|
162
|
-
let clonedMember;
|
|
163
|
-
|
|
164
|
-
if (
|
|
165
|
-
isObjectElement(targetElement) &&
|
|
166
|
-
targetElement.hasKey(keyValue) &&
|
|
167
|
-
options.isMergeableElement(value)
|
|
168
|
-
) {
|
|
169
|
-
const targetValue = targetElement.get(keyValue)!;
|
|
170
|
-
clonedMember = cloneShallow(member as MemberElement);
|
|
171
|
-
clonedMember.value = getMergeFunction(key, options)(
|
|
172
|
-
targetValue as ObjectOrArrayElement,
|
|
173
|
-
value as ObjectOrArrayElement,
|
|
174
|
-
options,
|
|
175
|
-
);
|
|
176
|
-
} else {
|
|
177
|
-
clonedMember = cloneShallow(member as MemberElement);
|
|
178
|
-
clonedMember.value = cloneUnlessOtherwiseSpecified(value as AnyElement, options);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
destination.remove(keyValue);
|
|
182
|
-
destination.content.push(clonedMember);
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
return destination;
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
export const defaultOptions: DeepMergeOptions = {
|
|
189
|
-
clone: true,
|
|
190
|
-
isMergeableElement: (element) => isObjectElement(element) || isArrayElement(element),
|
|
191
|
-
arrayElementMerge: mergeArrayElement,
|
|
192
|
-
objectElementMerge: mergeObjectElement,
|
|
193
|
-
customMerge: undefined,
|
|
194
|
-
customMetaMerge: undefined,
|
|
195
|
-
customAttributesMerge: undefined,
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* @public
|
|
200
|
-
*/
|
|
201
|
-
const deepmerge = (
|
|
202
|
-
targetElement: ObjectOrArrayElement,
|
|
203
|
-
sourceElement: ObjectOrArrayElement,
|
|
204
|
-
options?: DeepMergeUserOptions,
|
|
205
|
-
): AnyElement => {
|
|
206
|
-
const mergedOptions: DeepMergeOptions = { ...defaultOptions, ...options };
|
|
207
|
-
mergedOptions.isMergeableElement =
|
|
208
|
-
mergedOptions.isMergeableElement ?? defaultOptions.isMergeableElement;
|
|
209
|
-
mergedOptions.arrayElementMerge =
|
|
210
|
-
mergedOptions.arrayElementMerge ?? defaultOptions.arrayElementMerge;
|
|
211
|
-
mergedOptions.objectElementMerge =
|
|
212
|
-
mergedOptions.objectElementMerge ?? defaultOptions.objectElementMerge;
|
|
213
|
-
|
|
214
|
-
const sourceIsArrayElement = isArrayElement(sourceElement);
|
|
215
|
-
const targetIsArrayElement = isArrayElement(targetElement);
|
|
216
|
-
const sourceAndTargetTypesMatch = sourceIsArrayElement === targetIsArrayElement;
|
|
217
|
-
|
|
218
|
-
if (!sourceAndTargetTypesMatch) {
|
|
219
|
-
return cloneUnlessOtherwiseSpecified(sourceElement, mergedOptions);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// merging two elements
|
|
223
|
-
const mergedElement =
|
|
224
|
-
sourceIsArrayElement && typeof mergedOptions.arrayElementMerge === 'function'
|
|
225
|
-
? mergedOptions.arrayElementMerge(
|
|
226
|
-
targetElement as ArrayElement,
|
|
227
|
-
sourceElement as ArrayElement,
|
|
228
|
-
mergedOptions,
|
|
229
|
-
)
|
|
230
|
-
: mergedOptions.objectElementMerge(
|
|
231
|
-
targetElement as ObjectElement,
|
|
232
|
-
sourceElement as ObjectElement,
|
|
233
|
-
mergedOptions,
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
// merging meta & attributes
|
|
237
|
-
if (!targetElement.isMetaEmpty && !sourceElement.isMetaEmpty) {
|
|
238
|
-
mergedElement.meta = getMetaMergeFunction(mergedOptions)(
|
|
239
|
-
targetElement.meta,
|
|
240
|
-
sourceElement.meta,
|
|
241
|
-
);
|
|
242
|
-
} else if (!targetElement.isMetaEmpty) {
|
|
243
|
-
mergedElement.meta = targetElement.meta.cloneDeep();
|
|
244
|
-
} else if (!sourceElement.isMetaEmpty) {
|
|
245
|
-
mergedElement.meta = sourceElement.meta.cloneDeep();
|
|
246
|
-
}
|
|
247
|
-
if (!targetElement.isAttributesEmpty && !sourceElement.isAttributesEmpty) {
|
|
248
|
-
mergedElement.attributes = getAttributesMergeFunction(mergedOptions)(
|
|
249
|
-
targetElement.attributes,
|
|
250
|
-
sourceElement.attributes,
|
|
251
|
-
);
|
|
252
|
-
} else if (!targetElement.isAttributesEmpty) {
|
|
253
|
-
mergedElement.attributes = cloneDeep(targetElement.attributes);
|
|
254
|
-
} else if (!sourceElement.isAttributesEmpty) {
|
|
255
|
-
mergedElement.attributes = cloneDeep(sourceElement.attributes);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
return mergedElement;
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
deepmerge.all = (list: ObjectOrArrayElement[], options?: DeepMergeUserOptions) => {
|
|
262
|
-
if (!Array.isArray(list)) {
|
|
263
|
-
throw new TypeError('First argument of deepmerge should be an array.');
|
|
264
|
-
}
|
|
265
|
-
if (list.length === 0) {
|
|
266
|
-
return new ObjectElement();
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return list.reduce((target, source) => {
|
|
270
|
-
return deepmerge(target, source, options);
|
|
271
|
-
}, emptyElement(list[0]));
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
export default deepmerge;
|
package/src/merge/merge-left.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import mergeRight from './merge-right.ts';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @public
|
|
5
|
-
*/
|
|
6
|
-
const mergeLeft: typeof mergeRight = (...[sourceElement, targetElement, options]) => {
|
|
7
|
-
return mergeRight(targetElement, sourceElement, options);
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
mergeLeft.all = ((...[list, options]) => {
|
|
11
|
-
return mergeRight.all([...list].reverse(), options);
|
|
12
|
-
}) as typeof mergeRight.all;
|
|
13
|
-
|
|
14
|
-
export default mergeLeft;
|
package/src/merge/merge-right.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { ObjectElement } from '@speclynx/apidom-datamodel';
|
|
2
|
-
|
|
3
|
-
import deepmerge, { defaultOptions as defaultDeepmergeOptions, emptyElement } from './deepmerge.ts';
|
|
4
|
-
import type { ObjectOrArrayElement, DeepMergeUserOptions, AnyElement } from './deepmerge.ts';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @public
|
|
8
|
-
*/
|
|
9
|
-
export type MergeRightOptions = Omit<DeepMergeUserOptions, 'customMerge' | 'clone'>;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @public
|
|
13
|
-
*/
|
|
14
|
-
const mergeRight = (
|
|
15
|
-
targetElement: ObjectOrArrayElement,
|
|
16
|
-
sourceElement: ObjectOrArrayElement,
|
|
17
|
-
options?: MergeRightOptions,
|
|
18
|
-
): AnyElement => {
|
|
19
|
-
const mergedOptions = {
|
|
20
|
-
...defaultDeepmergeOptions,
|
|
21
|
-
...options,
|
|
22
|
-
customMerge: () => (target: ObjectOrArrayElement, source: ObjectOrArrayElement) => source,
|
|
23
|
-
clone: false,
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
return deepmerge(targetElement, sourceElement, mergedOptions);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
mergeRight.all = (list: ObjectOrArrayElement[], options?: MergeRightOptions) => {
|
|
30
|
-
if (!Array.isArray(list)) {
|
|
31
|
-
throw new TypeError('First argument of mergeRight should be an array.');
|
|
32
|
-
}
|
|
33
|
-
if (list.length === 0) {
|
|
34
|
-
return new ObjectElement();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return list.reduce((target, source) => {
|
|
38
|
-
return mergeRight(target, source, options);
|
|
39
|
-
}, emptyElement(list[0]));
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export default mergeRight;
|