@speclynx/apidom-datamodel 4.0.2 → 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 +6 -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,556 @@
|
|
|
1
|
+
import { equals } from 'ramda';
|
|
2
|
+
|
|
3
|
+
import type { Meta, Attributes, ToValue, Equatable, Freezable } from '../types.ts';
|
|
4
|
+
import Metadata from '../Metadata.ts';
|
|
5
|
+
import type ObjectElement from './ObjectElement.ts';
|
|
6
|
+
import type ArrayElement from './ArrayElement.ts';
|
|
7
|
+
import KeyValuePair from '../KeyValuePair.ts';
|
|
8
|
+
import ObjectSlice from '../ObjectSlice.ts';
|
|
9
|
+
|
|
10
|
+
// shared singleton for frozen elements with no meta — avoids allocation on every access
|
|
11
|
+
const FROZEN_EMPTY_METADATA = Object.freeze(new Metadata());
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Valid content types for an Element.
|
|
15
|
+
* @public
|
|
16
|
+
*/
|
|
17
|
+
export type ElementContent =
|
|
18
|
+
| Element
|
|
19
|
+
| Element[]
|
|
20
|
+
| KeyValuePair
|
|
21
|
+
| string
|
|
22
|
+
| number
|
|
23
|
+
| bigint
|
|
24
|
+
| symbol
|
|
25
|
+
| boolean
|
|
26
|
+
| null
|
|
27
|
+
| undefined;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Base Element class that all ApiDOM elements extend.
|
|
31
|
+
*
|
|
32
|
+
* Elements are the core building blocks of ApiDOM. Each element has:
|
|
33
|
+
* - An `element` property identifying its type
|
|
34
|
+
* - Optional `content` holding the element's value
|
|
35
|
+
* - Optional `meta` for metadata (id, classes, title, description, links)
|
|
36
|
+
* - Optional `attributes` for element-specific properties
|
|
37
|
+
*
|
|
38
|
+
* @public
|
|
39
|
+
*/
|
|
40
|
+
class Element implements ToValue, Equatable, Freezable {
|
|
41
|
+
// ============================================================
|
|
42
|
+
// Public Properties
|
|
43
|
+
// ============================================================
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Parent element reference (set when tree is frozen).
|
|
47
|
+
*/
|
|
48
|
+
public parent?: Element;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Format-specific style information for round-trip preservation.
|
|
52
|
+
* Each format owns its own namespace (e.g., `yaml`, `json`).
|
|
53
|
+
*/
|
|
54
|
+
public style?: Record<string, unknown>;
|
|
55
|
+
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// Source Position (LSP-compatible, TextDocument-compatible, UTF-16 code units)
|
|
58
|
+
// web-tree-sitter automatically provides position data in UTF-16 code units.
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Starting line number (0-based).
|
|
63
|
+
* Compatible with LSP Position.line.
|
|
64
|
+
*/
|
|
65
|
+
public startLine?: number;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Starting character offset within the line (0-based, UTF-16 code units).
|
|
69
|
+
* Compatible with LSP Position.character.
|
|
70
|
+
*/
|
|
71
|
+
public startCharacter?: number;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Starting offset from beginning of document (UTF-16 code units).
|
|
75
|
+
* Can be used directly as JavaScript string index.
|
|
76
|
+
*/
|
|
77
|
+
public startOffset?: number;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Ending line number (0-based).
|
|
81
|
+
* Compatible with LSP Position.line.
|
|
82
|
+
*/
|
|
83
|
+
public endLine?: number;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Ending character offset within the line (0-based, UTF-16 code units).
|
|
87
|
+
* Compatible with LSP Position.character.
|
|
88
|
+
*/
|
|
89
|
+
public endCharacter?: number;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Ending offset from beginning of document (UTF-16 code units).
|
|
93
|
+
* Can be used directly as JavaScript string index.
|
|
94
|
+
*/
|
|
95
|
+
public endOffset?: number;
|
|
96
|
+
|
|
97
|
+
// ============================================================
|
|
98
|
+
// Protected Properties
|
|
99
|
+
// ============================================================
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The element type identifier.
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
protected _storedElement: string = 'element';
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The element's content/value.
|
|
109
|
+
* @internal
|
|
110
|
+
*/
|
|
111
|
+
protected _content?: ElementContent;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Metadata about this element.
|
|
115
|
+
* @internal
|
|
116
|
+
*/
|
|
117
|
+
protected _meta?: Metadata;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Element-specific attributes.
|
|
121
|
+
* @internal
|
|
122
|
+
*/
|
|
123
|
+
protected _attributes?: Element;
|
|
124
|
+
|
|
125
|
+
// ============================================================
|
|
126
|
+
// Prototype-assigned properties (set in registration.ts)
|
|
127
|
+
// Using 'declare' allows TypeScript to know about these
|
|
128
|
+
// without generating runtime code.
|
|
129
|
+
// ============================================================
|
|
130
|
+
|
|
131
|
+
/** @internal ObjectElement constructor for creating meta/attributes */
|
|
132
|
+
declare ObjectElement: new (content?: Record<string, unknown>) => ObjectElement;
|
|
133
|
+
|
|
134
|
+
/** @internal ArrayElement constructor for creating arrays */
|
|
135
|
+
declare ArrayElement: new (content?: Element[]) => ArrayElement;
|
|
136
|
+
|
|
137
|
+
/** @internal MemberElement constructor for creating object members */
|
|
138
|
+
declare MemberElement: new (key?: unknown, value?: unknown) => Element;
|
|
139
|
+
|
|
140
|
+
/** @internal RefElement constructor for creating references */
|
|
141
|
+
declare RefElement: new (content?: unknown) => Element & { path?: Element };
|
|
142
|
+
|
|
143
|
+
/** @internal Function to convert values to elements */
|
|
144
|
+
declare refract: (value: unknown) => Element;
|
|
145
|
+
|
|
146
|
+
constructor(content?: unknown, meta?: Meta, attributes?: Attributes) {
|
|
147
|
+
if (meta !== undefined) {
|
|
148
|
+
this.meta = meta;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (attributes !== undefined) {
|
|
152
|
+
this.attributes = attributes;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (content !== undefined) {
|
|
156
|
+
this.content = content;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// ============================================================
|
|
161
|
+
// Core Properties
|
|
162
|
+
// ============================================================
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* The element type identifier (e.g., 'string', 'object', 'array').
|
|
166
|
+
*/
|
|
167
|
+
get element(): string {
|
|
168
|
+
return this._storedElement;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
set element(value: string) {
|
|
172
|
+
this._storedElement = value;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* The element's content/value.
|
|
177
|
+
*/
|
|
178
|
+
get content(): ElementContent {
|
|
179
|
+
return this._content;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
set content(value: unknown) {
|
|
183
|
+
// Already an element
|
|
184
|
+
if (value instanceof Element) {
|
|
185
|
+
this._content = value;
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Primitives (inlined for performance - avoids 8 function calls)
|
|
190
|
+
if (
|
|
191
|
+
value === null ||
|
|
192
|
+
value === undefined ||
|
|
193
|
+
typeof value === 'string' ||
|
|
194
|
+
typeof value === 'number' ||
|
|
195
|
+
typeof value === 'boolean' ||
|
|
196
|
+
typeof value === 'bigint' ||
|
|
197
|
+
typeof value === 'symbol'
|
|
198
|
+
) {
|
|
199
|
+
this._content = value;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// KeyValuePair
|
|
204
|
+
if (value instanceof KeyValuePair) {
|
|
205
|
+
this._content = value;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ObjectSlice - extract elements array
|
|
210
|
+
if (value instanceof ObjectSlice) {
|
|
211
|
+
this._content = value.elements;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Array - refract each item
|
|
216
|
+
if (Array.isArray(value)) {
|
|
217
|
+
this._content = value.map((item) => this.refract(item));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Plain object - convert to MemberElements
|
|
222
|
+
if (typeof value === 'object') {
|
|
223
|
+
this._content = Object.entries(value as Record<string, unknown>).map(
|
|
224
|
+
([key, val]) => new this.MemberElement(key, val),
|
|
225
|
+
);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
throw new Error(`Cannot set content to value of type ${typeof value}`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Metadata about this element (id, classes, title, description, links).
|
|
234
|
+
* Lazily creates a Metadata instance if not set.
|
|
235
|
+
*/
|
|
236
|
+
get meta(): Metadata {
|
|
237
|
+
if (!this._meta) {
|
|
238
|
+
if (this.isFrozen) return FROZEN_EMPTY_METADATA;
|
|
239
|
+
this._meta = new Metadata();
|
|
240
|
+
}
|
|
241
|
+
return this._meta;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
set meta(value: Meta) {
|
|
245
|
+
if (value instanceof Metadata) {
|
|
246
|
+
this._meta = value;
|
|
247
|
+
} else if (value && typeof value === 'object') {
|
|
248
|
+
const meta = new Metadata();
|
|
249
|
+
Object.assign(meta, value);
|
|
250
|
+
this._meta = meta;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Element-specific attributes.
|
|
256
|
+
* Lazily creates an ObjectElement if not set.
|
|
257
|
+
*/
|
|
258
|
+
get attributes(): ObjectElement {
|
|
259
|
+
if (!this._attributes) {
|
|
260
|
+
if (this.isFrozen) {
|
|
261
|
+
const attributes = new this.ObjectElement();
|
|
262
|
+
attributes.freeze();
|
|
263
|
+
return attributes;
|
|
264
|
+
}
|
|
265
|
+
this._attributes = new this.ObjectElement();
|
|
266
|
+
}
|
|
267
|
+
return this._attributes as ObjectElement;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
set attributes(value: Attributes) {
|
|
271
|
+
if (value instanceof Element) {
|
|
272
|
+
this._attributes = value;
|
|
273
|
+
} else {
|
|
274
|
+
this.attributes.set(value ?? {});
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// ============================================================
|
|
279
|
+
// Meta Property Shortcuts
|
|
280
|
+
// ============================================================
|
|
281
|
+
|
|
282
|
+
/** Unique identifier for this element. */
|
|
283
|
+
get id(): string {
|
|
284
|
+
if (!this.hasMetaProperty('id')) {
|
|
285
|
+
if (this.isFrozen) return '';
|
|
286
|
+
this.setMetaProperty('id', '');
|
|
287
|
+
}
|
|
288
|
+
return this.meta.get('id') as string;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
set id(value: string) {
|
|
292
|
+
this.setMetaProperty('id', value);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** CSS-like class names. */
|
|
296
|
+
get classes(): string[] {
|
|
297
|
+
if (!this.hasMetaProperty('classes')) {
|
|
298
|
+
if (this.isFrozen) return [];
|
|
299
|
+
this.setMetaProperty('classes', []);
|
|
300
|
+
}
|
|
301
|
+
return this.meta.get('classes') as string[];
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
set classes(value: string[]) {
|
|
305
|
+
this.setMetaProperty('classes', value);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/** Hyperlinks associated with this element. */
|
|
309
|
+
get links(): ArrayElement {
|
|
310
|
+
if (!this.hasMetaProperty('links')) {
|
|
311
|
+
if (this.isFrozen) {
|
|
312
|
+
const empty = new this.ArrayElement();
|
|
313
|
+
empty.freeze();
|
|
314
|
+
return empty;
|
|
315
|
+
}
|
|
316
|
+
this.setMetaProperty('links', new this.ArrayElement());
|
|
317
|
+
}
|
|
318
|
+
return this.meta.get('links') as ArrayElement;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
set links(value: ArrayElement) {
|
|
322
|
+
this.setMetaProperty('links', value);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ============================================================
|
|
326
|
+
// Tree Navigation
|
|
327
|
+
// ============================================================
|
|
328
|
+
|
|
329
|
+
/** Returns direct children of this element. */
|
|
330
|
+
get children(): Element[] {
|
|
331
|
+
const { _content: content } = this;
|
|
332
|
+
|
|
333
|
+
if (Array.isArray(content)) {
|
|
334
|
+
return content;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (content instanceof KeyValuePair) {
|
|
338
|
+
const children: Element[] = [];
|
|
339
|
+
if (content.key) children.push(content.key as Element);
|
|
340
|
+
if (content.value) children.push(content.value as Element);
|
|
341
|
+
return children;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (content instanceof Element) {
|
|
345
|
+
return [content];
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return [];
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// ============================================================
|
|
352
|
+
// Freezable Implementation
|
|
353
|
+
// ============================================================
|
|
354
|
+
|
|
355
|
+
/** Whether this element is frozen (immutable). */
|
|
356
|
+
get isFrozen(): boolean {
|
|
357
|
+
return Object.isFrozen(this);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Freezes the element tree, making it immutable.
|
|
362
|
+
* Sets up parent references for tree traversal.
|
|
363
|
+
*/
|
|
364
|
+
freeze(): void {
|
|
365
|
+
if (this.isFrozen) return;
|
|
366
|
+
|
|
367
|
+
// Freeze meta and attributes
|
|
368
|
+
if (this._meta) {
|
|
369
|
+
this._meta.freeze();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (this._attributes) {
|
|
373
|
+
this._attributes.parent = this;
|
|
374
|
+
this._attributes.freeze();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Freeze children
|
|
378
|
+
for (const child of this.children) {
|
|
379
|
+
child.parent = this;
|
|
380
|
+
child.freeze();
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Freeze content array if applicable
|
|
384
|
+
if (Array.isArray(this._content)) {
|
|
385
|
+
Object.freeze(this._content);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
Object.freeze(this);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// ============================================================
|
|
392
|
+
// ToValue Implementation
|
|
393
|
+
// ============================================================
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Converts the element to its JavaScript value representation.
|
|
397
|
+
*/
|
|
398
|
+
toValue(): unknown {
|
|
399
|
+
const { _content } = this;
|
|
400
|
+
|
|
401
|
+
if (_content instanceof Element) {
|
|
402
|
+
return _content.toValue();
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (_content instanceof KeyValuePair) {
|
|
406
|
+
return _content.toValue();
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (Array.isArray(_content)) {
|
|
410
|
+
return _content.map((el) => el.toValue());
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
return _content;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// ============================================================
|
|
417
|
+
// Equatable Implementation
|
|
418
|
+
// ============================================================
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Checks deep equality with another value.
|
|
422
|
+
*/
|
|
423
|
+
equals(value: unknown): boolean {
|
|
424
|
+
const compareTo: unknown = value instanceof Element ? value.toValue() : value;
|
|
425
|
+
return equals(this.toValue(), compareTo);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ============================================================
|
|
429
|
+
// Element Type
|
|
430
|
+
// ============================================================
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Returns the primitive type name for this element.
|
|
434
|
+
* Override in subclasses (e.g., 'string', 'number', 'array').
|
|
435
|
+
*/
|
|
436
|
+
primitive(): string | undefined {
|
|
437
|
+
return undefined;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// ============================================================
|
|
441
|
+
// Content Operations
|
|
442
|
+
// ============================================================
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Sets the content of this element.
|
|
446
|
+
* @returns this for chaining
|
|
447
|
+
*/
|
|
448
|
+
set(content: unknown): this {
|
|
449
|
+
this.content = content;
|
|
450
|
+
return this;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// ============================================================
|
|
454
|
+
// Reference Creation
|
|
455
|
+
// ============================================================
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Creates a RefElement pointing to this element.
|
|
459
|
+
* @param path - Optional path within the referenced element
|
|
460
|
+
* @throws Error if this element has no ID
|
|
461
|
+
*/
|
|
462
|
+
toRef(path?: string): Element {
|
|
463
|
+
const idValue = this.id;
|
|
464
|
+
if (idValue === '') {
|
|
465
|
+
throw new Error('Cannot create reference to an element without an ID');
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const ref = new this.RefElement(idValue);
|
|
469
|
+
if (typeof path === 'string') {
|
|
470
|
+
ref.path = this.refract(path);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
return ref;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Gets a meta property value.
|
|
478
|
+
*
|
|
479
|
+
* When the property doesn't exist:
|
|
480
|
+
* - With defaultValue: returns the provided default value
|
|
481
|
+
* - Without defaultValue: returns undefined
|
|
482
|
+
*/
|
|
483
|
+
public getMetaProperty(name: string, defaultValue: unknown): unknown;
|
|
484
|
+
public getMetaProperty(name: string): unknown;
|
|
485
|
+
public getMetaProperty(name: string, defaultValue?: unknown): unknown {
|
|
486
|
+
if (!this.hasMetaProperty(name)) {
|
|
487
|
+
return defaultValue;
|
|
488
|
+
}
|
|
489
|
+
return this.meta.get(name);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* Sets a meta property.
|
|
494
|
+
*/
|
|
495
|
+
public setMetaProperty(name: string, value: unknown): void {
|
|
496
|
+
this.meta.set(name, value);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* Checks whether a meta property exists.
|
|
501
|
+
*/
|
|
502
|
+
public hasMetaProperty(name: string): boolean {
|
|
503
|
+
return this._meta !== undefined && this._meta.hasKey(name);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Checks if meta is empty.
|
|
508
|
+
*/
|
|
509
|
+
get isMetaEmpty(): boolean {
|
|
510
|
+
return this._meta === undefined || this._meta.isEmpty;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Gets an attribute property, creating it with default value if not present.
|
|
515
|
+
*/
|
|
516
|
+
public getAttributesProperty(name: string, defaultValue: unknown): Element {
|
|
517
|
+
if (!this.hasAttributesProperty(name)) {
|
|
518
|
+
if (this.isFrozen) {
|
|
519
|
+
const element = this.refract(defaultValue);
|
|
520
|
+
element.freeze();
|
|
521
|
+
return element;
|
|
522
|
+
}
|
|
523
|
+
this.attributes.set(name, defaultValue);
|
|
524
|
+
}
|
|
525
|
+
return this.attributes.get(name)!;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Sets an attributes property.
|
|
530
|
+
*/
|
|
531
|
+
public setAttributesProperty(name: string, value: unknown): void {
|
|
532
|
+
this.attributes.set(name, value);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Checks whether an attributes property exists.
|
|
537
|
+
*/
|
|
538
|
+
public hasAttributesProperty(name: string): boolean {
|
|
539
|
+
if (!this.isAttributesEmpty) {
|
|
540
|
+
return this.attributes.hasKey(name);
|
|
541
|
+
}
|
|
542
|
+
return false;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Checks if attributes is empty.
|
|
547
|
+
*/
|
|
548
|
+
get isAttributesEmpty(): boolean {
|
|
549
|
+
return this._attributes === undefined || this.attributes.isEmpty;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// Re-export types for convenience
|
|
554
|
+
export type { Meta, Attributes };
|
|
555
|
+
export { Metadata };
|
|
556
|
+
export default Element;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault").default;
|
|
4
|
+
exports.__esModule = true;
|
|
5
|
+
exports.default = void 0;
|
|
6
|
+
var _KeyValuePair = _interopRequireDefault(require("../KeyValuePair.cjs"));
|
|
7
|
+
var _Element = _interopRequireDefault(require("./Element.cjs"));
|
|
8
|
+
/**
|
|
9
|
+
* MemberElement represents a key-value pair member in an ObjectElement.
|
|
10
|
+
*
|
|
11
|
+
* The member's content is always a KeyValuePair containing:
|
|
12
|
+
* - `key`: The key element (typically a StringElement)
|
|
13
|
+
* - `value`: The value element (any Element type)
|
|
14
|
+
*
|
|
15
|
+
* @typeParam K - The key element type, defaults to Element
|
|
16
|
+
* @typeParam V - The value element type, defaults to Element
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
class MemberElement extends _Element.default {
|
|
20
|
+
constructor(key, value, meta, attributes) {
|
|
21
|
+
super(new _KeyValuePair.default(), meta, attributes);
|
|
22
|
+
this.element = 'member';
|
|
23
|
+
if (key !== undefined) {
|
|
24
|
+
this.key = key;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Note: We check arguments.length to distinguish between:
|
|
28
|
+
// - new MemberElement('key') - value not provided, don't set
|
|
29
|
+
// - new MemberElement('key', undefined) - value explicitly undefined, set it
|
|
30
|
+
if (arguments.length >= 2) {
|
|
31
|
+
this.value = value;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
primitive() {
|
|
35
|
+
return 'member';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The key element of this member.
|
|
40
|
+
*/
|
|
41
|
+
get key() {
|
|
42
|
+
return this._content.key;
|
|
43
|
+
}
|
|
44
|
+
set key(value) {
|
|
45
|
+
this._content.key = this.refract(value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The value element of this member.
|
|
50
|
+
*/
|
|
51
|
+
get value() {
|
|
52
|
+
return this._content.value;
|
|
53
|
+
}
|
|
54
|
+
set value(value) {
|
|
55
|
+
this._content.value = value === undefined ? undefined : this.refract(value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
var _default = exports.default = MemberElement;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import KeyValuePair from "../KeyValuePair.mjs";
|
|
2
|
+
import Element from "./Element.mjs";
|
|
3
|
+
/**
|
|
4
|
+
* MemberElement represents a key-value pair member in an ObjectElement.
|
|
5
|
+
*
|
|
6
|
+
* The member's content is always a KeyValuePair containing:
|
|
7
|
+
* - `key`: The key element (typically a StringElement)
|
|
8
|
+
* - `value`: The value element (any Element type)
|
|
9
|
+
*
|
|
10
|
+
* @typeParam K - The key element type, defaults to Element
|
|
11
|
+
* @typeParam V - The value element type, defaults to Element
|
|
12
|
+
* @public
|
|
13
|
+
*/
|
|
14
|
+
class MemberElement extends Element {
|
|
15
|
+
constructor(key, value, meta, attributes) {
|
|
16
|
+
super(new KeyValuePair(), meta, attributes);
|
|
17
|
+
this.element = 'member';
|
|
18
|
+
if (key !== undefined) {
|
|
19
|
+
this.key = key;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Note: We check arguments.length to distinguish between:
|
|
23
|
+
// - new MemberElement('key') - value not provided, don't set
|
|
24
|
+
// - new MemberElement('key', undefined) - value explicitly undefined, set it
|
|
25
|
+
if (arguments.length >= 2) {
|
|
26
|
+
this.value = value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
primitive() {
|
|
30
|
+
return 'member';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The key element of this member.
|
|
35
|
+
*/
|
|
36
|
+
get key() {
|
|
37
|
+
return this._content.key;
|
|
38
|
+
}
|
|
39
|
+
set key(value) {
|
|
40
|
+
this._content.key = this.refract(value);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The value element of this member.
|
|
45
|
+
*/
|
|
46
|
+
get value() {
|
|
47
|
+
return this._content.value;
|
|
48
|
+
}
|
|
49
|
+
set value(value) {
|
|
50
|
+
this._content.value = value === undefined ? undefined : this.refract(value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export default MemberElement;
|