@speclynx/apidom-datamodel 4.0.1 → 4.0.3
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/package.json +4 -5
- package/src/KeyValuePair.cjs +31 -0
- package/src/KeyValuePair.mjs +27 -0
- package/src/KeyValuePair.ts +31 -0
- package/src/Metadata.cjs +91 -0
- package/src/Metadata.mjs +87 -0
- package/src/Metadata.ts +100 -0
- package/src/Namespace.cjs +212 -0
- package/src/Namespace.mjs +206 -0
- package/src/Namespace.ts +260 -0
- package/src/ObjectSlice.cjs +199 -0
- package/src/ObjectSlice.mjs +195 -0
- package/src/ObjectSlice.ts +228 -0
- package/src/clone/errors/CloneError.cjs +22 -0
- package/src/clone/errors/CloneError.mjs +19 -0
- package/src/clone/errors/CloneError.ts +26 -0
- package/src/clone/errors/DeepCloneError.cjs +11 -0
- package/src/clone/errors/DeepCloneError.mjs +6 -0
- package/src/clone/errors/DeepCloneError.ts +8 -0
- package/src/clone/errors/ShallowCloneError.cjs +11 -0
- package/src/clone/errors/ShallowCloneError.mjs +6 -0
- package/src/clone/errors/ShallowCloneError.ts +8 -0
- package/src/clone/index.cjs +188 -0
- package/src/clone/index.mjs +178 -0
- package/src/clone/index.ts +195 -0
- package/src/elements/Annotation.cjs +35 -0
- package/src/elements/Annotation.mjs +30 -0
- package/src/elements/Annotation.ts +35 -0
- package/src/elements/Comment.cjs +18 -0
- package/src/elements/Comment.mjs +13 -0
- package/src/elements/Comment.ts +16 -0
- package/src/elements/LinkElement.cjs +50 -0
- package/src/elements/LinkElement.mjs +45 -0
- package/src/elements/LinkElement.ts +49 -0
- package/src/elements/ParseResult.cjs +91 -0
- package/src/elements/ParseResult.mjs +86 -0
- package/src/elements/ParseResult.ts +94 -0
- package/src/elements/RefElement.cjs +34 -0
- package/src/elements/RefElement.mjs +29 -0
- package/src/elements/RefElement.ts +33 -0
- package/src/elements/SourceMap.cjs +140 -0
- package/src/elements/SourceMap.mjs +134 -0
- package/src/elements/SourceMap.ts +170 -0
- package/src/elements/Style.cjs +54 -0
- package/src/elements/Style.mjs +48 -0
- package/src/elements/Style.ts +56 -0
- package/src/index.cjs +58 -0
- package/src/index.mjs +11 -0
- package/src/index.ts +79 -0
- package/src/predicates/elements.cjs +46 -0
- package/src/predicates/elements.mjs +35 -0
- package/src/predicates/elements.ts +42 -0
- package/src/predicates/index.cjs +77 -0
- package/src/predicates/index.mjs +56 -0
- package/src/predicates/index.ts +89 -0
- package/src/predicates/primitives.cjs +69 -0
- package/src/predicates/primitives.mjs +56 -0
- package/src/predicates/primitives.ts +79 -0
- package/src/primitives/ArrayElement.cjs +155 -0
- package/src/primitives/ArrayElement.mjs +148 -0
- package/src/primitives/ArrayElement.ts +161 -0
- package/src/primitives/BooleanElement.cjs +20 -0
- package/src/primitives/BooleanElement.mjs +15 -0
- package/src/primitives/BooleanElement.ts +18 -0
- package/src/primitives/CollectionElement.cjs +180 -0
- package/src/primitives/CollectionElement.mjs +173 -0
- package/src/primitives/CollectionElement.ts +191 -0
- package/src/primitives/Element.cjs +510 -0
- package/src/primitives/Element.mjs +505 -0
- package/src/primitives/Element.ts +556 -0
- package/src/primitives/MemberElement.cjs +58 -0
- package/src/primitives/MemberElement.mjs +53 -0
- package/src/primitives/MemberElement.ts +61 -0
- package/src/primitives/NullElement.cjs +28 -0
- package/src/primitives/NullElement.mjs +23 -0
- package/src/primitives/NullElement.ts +26 -0
- package/src/primitives/NumberElement.cjs +20 -0
- package/src/primitives/NumberElement.mjs +15 -0
- package/src/primitives/NumberElement.ts +18 -0
- package/src/primitives/ObjectElement.cjs +220 -0
- package/src/primitives/ObjectElement.mjs +214 -0
- package/src/primitives/ObjectElement.ts +263 -0
- package/src/primitives/StringElement.cjs +27 -0
- package/src/primitives/StringElement.mjs +22 -0
- package/src/primitives/StringElement.ts +25 -0
- package/src/registration.cjs +101 -0
- package/src/registration.mjs +79 -0
- package/src/registration.ts +111 -0
- package/src/serialisers/JSONSerialiser.cjs +230 -0
- package/src/serialisers/JSONSerialiser.mjs +221 -0
- package/src/serialisers/JSONSerialiser.ts +295 -0
- package/src/types.cjs +3 -0
- package/src/types.mjs +1 -0
- package/src/types.ts +72 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import type Namespace from '../Namespace.ts';
|
|
2
|
+
import type Element from '../primitives/Element.ts';
|
|
3
|
+
import type KeyValuePair from '../KeyValuePair.ts';
|
|
4
|
+
import type ObjectElement from '../primitives/ObjectElement.ts';
|
|
5
|
+
import SourceMapElement from '../elements/SourceMap.ts';
|
|
6
|
+
import StyleElement from '../elements/Style.ts';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Serialized representation of an Element in JSON Refract format.
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
interface SerializedElement {
|
|
13
|
+
element: string;
|
|
14
|
+
meta?: Record<string, SerializedElement>;
|
|
15
|
+
attributes?: Record<string, SerializedElement>;
|
|
16
|
+
content?: SerializedContent;
|
|
17
|
+
__meta_raw__?: string[];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Serialized representation of a KeyValuePair in JSON Refract format.
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
interface SerializedKeyValuePair {
|
|
25
|
+
key: SerializedElement;
|
|
26
|
+
value?: SerializedElement;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Possible content types in a serialized element.
|
|
31
|
+
* @public
|
|
32
|
+
*/
|
|
33
|
+
type SerializedContent =
|
|
34
|
+
| SerializedElement
|
|
35
|
+
| SerializedElement[]
|
|
36
|
+
| SerializedKeyValuePair
|
|
37
|
+
| string
|
|
38
|
+
| number
|
|
39
|
+
| boolean
|
|
40
|
+
| null
|
|
41
|
+
| undefined;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Input document format for deserialization.
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
interface RefractDocument {
|
|
48
|
+
element: string;
|
|
49
|
+
meta?: Record<string, unknown>;
|
|
50
|
+
attributes?: Record<string, unknown>;
|
|
51
|
+
content?: unknown;
|
|
52
|
+
__meta_raw__?: string[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* JSONSerialiser handles serialization and deserialization of ApiDOM elements
|
|
57
|
+
* to and from JSON Refract format.
|
|
58
|
+
* @public
|
|
59
|
+
*/
|
|
60
|
+
class JSONSerialiser {
|
|
61
|
+
public namespace: Namespace;
|
|
62
|
+
|
|
63
|
+
// This will be set via prototype assignment to avoid circular dependency
|
|
64
|
+
declare Namespace: typeof Namespace;
|
|
65
|
+
|
|
66
|
+
constructor(namespace?: Namespace) {
|
|
67
|
+
this.namespace = namespace || new this.Namespace();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Serializes an Element to JSON Refract format.
|
|
72
|
+
*/
|
|
73
|
+
serialise(element: Element): SerializedElement {
|
|
74
|
+
if (!(element instanceof this.namespace.elements.Element)) {
|
|
75
|
+
throw new TypeError(`Given element \`${element}\` is not an Element instance`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const payload: SerializedElement = {
|
|
79
|
+
element: element.element,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
if (!element.isMetaEmpty) {
|
|
83
|
+
const serialisedMeta = this.serialiseMeta(element);
|
|
84
|
+
if (serialisedMeta) {
|
|
85
|
+
payload.meta = serialisedMeta.meta;
|
|
86
|
+
if (serialisedMeta.rawKeys.length > 0) {
|
|
87
|
+
payload.__meta_raw__ = serialisedMeta.rawKeys;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (!element.isAttributesEmpty) {
|
|
93
|
+
payload.attributes = this.serialiseObject(element.attributes as ObjectElement);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Serialize source position as __mappings__ in meta (skip for SourceMapElement itself)
|
|
97
|
+
if (!(element instanceof SourceMapElement)) {
|
|
98
|
+
const sourceMap = SourceMapElement.from(element);
|
|
99
|
+
if (sourceMap) {
|
|
100
|
+
if (!payload.meta) {
|
|
101
|
+
payload.meta = {};
|
|
102
|
+
}
|
|
103
|
+
payload.meta.__mappings__ = this.serialise(sourceMap);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Serialize style as __styles__ in meta (skip for StyleElement itself)
|
|
108
|
+
if (!(element instanceof StyleElement)) {
|
|
109
|
+
const styleElement = StyleElement.from(element);
|
|
110
|
+
if (styleElement) {
|
|
111
|
+
if (!payload.meta) {
|
|
112
|
+
payload.meta = {};
|
|
113
|
+
}
|
|
114
|
+
payload.meta.__styles__ = this.serialise(styleElement);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const content = this.serialiseContent(element.content);
|
|
119
|
+
|
|
120
|
+
if (content !== undefined) {
|
|
121
|
+
payload.content = content;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return payload;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Deserializes a JSON Refract document to an Element.
|
|
129
|
+
*/
|
|
130
|
+
deserialise(value: RefractDocument): Element {
|
|
131
|
+
if (!value.element) {
|
|
132
|
+
throw new Error('Given value is not an object containing an element name');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const ElementClass = this.namespace.getElementClass(value.element);
|
|
136
|
+
const element = new ElementClass();
|
|
137
|
+
|
|
138
|
+
if (element.element !== value.element) {
|
|
139
|
+
element.element = value.element;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Extract special meta keys without mutating input, filter remaining meta
|
|
143
|
+
let mappingsDoc: RefractDocument | undefined;
|
|
144
|
+
let stylesDoc: RefractDocument | undefined;
|
|
145
|
+
let metaToDeserialize = value.meta;
|
|
146
|
+
|
|
147
|
+
if (value.meta?.__mappings__ || value.meta?.__styles__) {
|
|
148
|
+
const { __mappings__, __styles__, ...rest } = value.meta as Record<string, unknown>;
|
|
149
|
+
mappingsDoc = __mappings__ as RefractDocument | undefined;
|
|
150
|
+
stylesDoc = __styles__ as RefractDocument | undefined;
|
|
151
|
+
metaToDeserialize = Object.keys(rest).length > 0 ? rest : undefined;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// determine which meta keys were raw primitives before serialization
|
|
155
|
+
const rawKeys = value.__meta_raw__ ? new Set(value.__meta_raw__) : undefined;
|
|
156
|
+
|
|
157
|
+
if (metaToDeserialize) {
|
|
158
|
+
for (const [key, doc] of Object.entries(metaToDeserialize)) {
|
|
159
|
+
const deserialized = this.deserialise(doc as RefractDocument);
|
|
160
|
+
// unwrap keys that were raw primitives before serialization
|
|
161
|
+
element.setMetaProperty(key, rawKeys?.has(key) ? deserialized.toValue() : deserialized);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Restore source position from __mappings__
|
|
166
|
+
if (mappingsDoc) {
|
|
167
|
+
const sourceMap = this.deserialise(mappingsDoc) as SourceMapElement;
|
|
168
|
+
sourceMap.applyTo(element);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Restore style from __styles__
|
|
172
|
+
if (stylesDoc) {
|
|
173
|
+
const styleElement = this.deserialise(stylesDoc) as StyleElement;
|
|
174
|
+
styleElement.applyTo(element);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (value.attributes) {
|
|
178
|
+
this.deserialiseObject(
|
|
179
|
+
value.attributes as Record<string, RefractDocument>,
|
|
180
|
+
element.attributes as ObjectElement,
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const content = this.deserialiseContent(value.content);
|
|
185
|
+
if (content !== undefined || element.content === null) {
|
|
186
|
+
element.content = content;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return element;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
protected serialiseContent(content: unknown): SerializedContent {
|
|
193
|
+
if (content instanceof this.namespace.elements.Element) {
|
|
194
|
+
return this.serialise(content as Element);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (content instanceof this.namespace.KeyValuePair) {
|
|
198
|
+
const kvp = content as KeyValuePair;
|
|
199
|
+
const pair: SerializedKeyValuePair = {
|
|
200
|
+
key: this.serialise(kvp.key as Element),
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
if (kvp.value) {
|
|
204
|
+
pair.value = this.serialise(kvp.value as Element);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return pair;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (content && Array.isArray(content)) {
|
|
211
|
+
if (content.length === 0) {
|
|
212
|
+
return undefined;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return content.map((item) => this.serialise(item));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return content as SerializedContent;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
protected deserialiseContent(content: unknown): unknown {
|
|
222
|
+
if (content) {
|
|
223
|
+
if ((content as RefractDocument).element) {
|
|
224
|
+
return this.deserialise(content as RefractDocument);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if ((content as SerializedKeyValuePair).key) {
|
|
228
|
+
const pair = new this.namespace.KeyValuePair(
|
|
229
|
+
this.deserialise((content as SerializedKeyValuePair).key),
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
if ((content as SerializedKeyValuePair).value) {
|
|
233
|
+
pair.value = this.deserialise((content as SerializedKeyValuePair).value!);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return pair;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (Array.isArray(content)) {
|
|
240
|
+
return content.map((item) => this.deserialise(item));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return content;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
protected serialiseMeta(
|
|
248
|
+
element: Element,
|
|
249
|
+
): { meta: Record<string, SerializedElement>; rawKeys: string[] } | undefined {
|
|
250
|
+
const meta: Record<string, SerializedElement> = {};
|
|
251
|
+
const rawKeys: string[] = [];
|
|
252
|
+
let hasEntries = false;
|
|
253
|
+
|
|
254
|
+
for (const [key, value] of Object.entries(element.meta)) {
|
|
255
|
+
if (value instanceof this.namespace.elements.Element) {
|
|
256
|
+
meta[key] = this.serialise(value as Element);
|
|
257
|
+
hasEntries = true;
|
|
258
|
+
} else if (value !== undefined) {
|
|
259
|
+
// refract primitives to maintain JSON Refract spec compatibility
|
|
260
|
+
const refracted = element.refract(value);
|
|
261
|
+
meta[key] = this.serialise(refracted);
|
|
262
|
+
rawKeys.push(key);
|
|
263
|
+
hasEntries = true;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return hasEntries ? { meta, rawKeys } : undefined;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
protected serialiseObject(obj: ObjectElement): Record<string, SerializedElement> | undefined {
|
|
271
|
+
const result: Record<string, SerializedElement> = {};
|
|
272
|
+
|
|
273
|
+
obj.forEach((value: Element, key: Element) => {
|
|
274
|
+
if (value) {
|
|
275
|
+
result[key.toValue() as string] = this.serialise(value);
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
if (Object.keys(result).length === 0) {
|
|
280
|
+
return undefined;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return result;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
protected deserialiseObject(from: Record<string, RefractDocument>, to: ObjectElement): void {
|
|
287
|
+
Object.keys(from).forEach((key) => {
|
|
288
|
+
to.set(key, this.deserialise(from[key]));
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export default JSONSerialiser;
|
|
294
|
+
|
|
295
|
+
export type { SerializedElement, SerializedContent, SerializedKeyValuePair, RefractDocument };
|
package/src/types.cjs
ADDED
package/src/types.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared type definitions for ApiDOM data model.
|
|
3
|
+
* These types are used across multiple modules to ensure consistency.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type ObjectElement from './primitives/ObjectElement.ts';
|
|
7
|
+
import type Metadata from './Metadata.ts';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Metadata input for an element constructor/setter.
|
|
11
|
+
* Can be a Metadata instance or a plain object.
|
|
12
|
+
* Common meta properties include: id, classes, title, description, links.
|
|
13
|
+
* @public
|
|
14
|
+
*/
|
|
15
|
+
export type Meta = Metadata | Record<string, unknown>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Attributes associated with an element.
|
|
19
|
+
* Can be a plain object or an ObjectElement.
|
|
20
|
+
* Attributes are element-specific properties beyond the standard meta.
|
|
21
|
+
* @public
|
|
22
|
+
*/
|
|
23
|
+
export type Attributes = Record<string, unknown> | ObjectElement;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Primitive JavaScript values that can be element content.
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export type PrimitiveValue = string | number | boolean | null | undefined;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Predicate function for filtering/matching elements.
|
|
33
|
+
* @public
|
|
34
|
+
*/
|
|
35
|
+
export type ElementPredicate<T = unknown> = (element: T) => boolean;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Callback for array-style iteration (element, index, array).
|
|
39
|
+
* @public
|
|
40
|
+
*/
|
|
41
|
+
export type ArrayCallback<T, U> = (element: T, index: number, array: T[]) => U;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Callback for object-style iteration (value, key, member).
|
|
45
|
+
* @public
|
|
46
|
+
*/
|
|
47
|
+
export type ObjectCallback<V, K, M, U> = (value: V, key: K, member: M) => U;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Type for objects that can convert to JavaScript values.
|
|
51
|
+
* @public
|
|
52
|
+
*/
|
|
53
|
+
export interface ToValue<T = unknown> {
|
|
54
|
+
toValue(): T;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Type for objects that support deep equality comparison.
|
|
59
|
+
* @public
|
|
60
|
+
*/
|
|
61
|
+
export interface Equatable {
|
|
62
|
+
equals(value: unknown): boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Type for freezable objects (immutable after freeze).
|
|
67
|
+
* @public
|
|
68
|
+
*/
|
|
69
|
+
export interface Freezable {
|
|
70
|
+
freeze(): void;
|
|
71
|
+
readonly isFrozen: boolean;
|
|
72
|
+
}
|