@speclynx/apidom-datamodel 1.12.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/LICENSES/AFL-3.0.txt +182 -0
- package/LICENSES/Apache-2.0.txt +202 -0
- package/LICENSES/BSD-3-Clause.txt +26 -0
- package/LICENSES/MIT.txt +9 -0
- package/NOTICE +74 -0
- package/README.md +479 -0
- package/dist/apidom-datamodel.browser.js +2717 -0
- package/dist/apidom-datamodel.browser.min.js +1 -0
- package/package.json +53 -0
- package/src/KeyValuePair.cjs +38 -0
- package/src/KeyValuePair.mjs +34 -0
- package/src/Namespace.cjs +212 -0
- package/src/Namespace.mjs +206 -0
- package/src/ObjectSlice.cjs +206 -0
- package/src/ObjectSlice.mjs +202 -0
- package/src/elements/LinkElement.cjs +44 -0
- package/src/elements/LinkElement.mjs +39 -0
- package/src/elements/RefElement.cjs +31 -0
- package/src/elements/RefElement.mjs +26 -0
- package/src/index.cjs +25 -0
- package/src/index.mjs +6 -0
- package/src/primitives/ArrayElement.cjs +176 -0
- package/src/primitives/ArrayElement.mjs +169 -0
- package/src/primitives/BooleanElement.cjs +20 -0
- package/src/primitives/BooleanElement.mjs +15 -0
- package/src/primitives/CollectionElement.cjs +194 -0
- package/src/primitives/CollectionElement.mjs +187 -0
- package/src/primitives/Element.cjs +438 -0
- package/src/primitives/Element.mjs +433 -0
- package/src/primitives/MemberElement.cjs +54 -0
- package/src/primitives/MemberElement.mjs +49 -0
- package/src/primitives/NullElement.cjs +28 -0
- package/src/primitives/NullElement.mjs +23 -0
- package/src/primitives/NumberElement.cjs +20 -0
- package/src/primitives/NumberElement.mjs +15 -0
- package/src/primitives/ObjectElement.cjs +222 -0
- package/src/primitives/ObjectElement.mjs +216 -0
- package/src/primitives/StringElement.cjs +27 -0
- package/src/primitives/StringElement.mjs +22 -0
- package/src/registration.cjs +87 -0
- package/src/registration.mjs +70 -0
- package/src/serialisers/JSONSerialiser.cjs +144 -0
- package/src/serialisers/JSONSerialiser.mjs +140 -0
- package/src/types.cjs +3 -0
- package/src/types.mjs +1 -0
- package/types/apidom-datamodel.d.ts +887 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import Element from "./Element.mjs";
|
|
2
|
+
/**
|
|
3
|
+
* Condition function for finding elements.
|
|
4
|
+
* @public
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Options for finding elements.
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* CollectionElement is an abstract base class for collection-like elements.
|
|
12
|
+
* Both ArrayElement and ObjectElement extend this class.
|
|
13
|
+
*
|
|
14
|
+
* This class contains the shared functionality between arrays and objects,
|
|
15
|
+
* while keeping the conflicting methods (get, set, remove, map, filter, etc.)
|
|
16
|
+
* in the respective subclasses.
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* This is primarily an implementation detail. Use ArrayElement or ObjectElement directly.
|
|
20
|
+
*
|
|
21
|
+
* @typeParam T - The element type contained in the collection, defaults to Element
|
|
22
|
+
* @public
|
|
23
|
+
*/
|
|
24
|
+
class CollectionElement extends Element {
|
|
25
|
+
constructor(content, meta, attributes) {
|
|
26
|
+
super(content || [], meta, attributes);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Returns the length of the collection.
|
|
31
|
+
*/
|
|
32
|
+
get length() {
|
|
33
|
+
return this._content.length;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Returns whether the collection is empty.
|
|
38
|
+
*/
|
|
39
|
+
get isEmpty() {
|
|
40
|
+
return this.length === 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Return the first item in the collection.
|
|
45
|
+
*/
|
|
46
|
+
get first() {
|
|
47
|
+
return this._content[0];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Return the second item in the collection.
|
|
52
|
+
*/
|
|
53
|
+
get second() {
|
|
54
|
+
return this._content[1];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Return the last item in the collection.
|
|
59
|
+
*/
|
|
60
|
+
get last() {
|
|
61
|
+
return this._content.at(-1);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Adds the given element to the end of the collection.
|
|
66
|
+
*/
|
|
67
|
+
push(value) {
|
|
68
|
+
this._content.push(this.refract(value));
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Alias for push.
|
|
74
|
+
*/
|
|
75
|
+
add(value) {
|
|
76
|
+
this.push(value);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Removes the first element from the collection.
|
|
81
|
+
*/
|
|
82
|
+
shift() {
|
|
83
|
+
return this._content.shift();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Adds the given element to the beginning of the collection.
|
|
88
|
+
*/
|
|
89
|
+
unshift(value) {
|
|
90
|
+
this._content.unshift(this.refract(value));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Looks for matching children using deep equality.
|
|
95
|
+
*/
|
|
96
|
+
includes(value) {
|
|
97
|
+
return this._content.some(element => element.equals(value));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Recursively search all descendants using a condition function.
|
|
102
|
+
*/
|
|
103
|
+
findElements(condition, givenOptions) {
|
|
104
|
+
const options = givenOptions || {};
|
|
105
|
+
const recursive = !!options.recursive;
|
|
106
|
+
const results = options.results === undefined ? [] : options.results;
|
|
107
|
+
for (let i = 0; i < this._content.length; i += 1) {
|
|
108
|
+
const item = this._content[i];
|
|
109
|
+
|
|
110
|
+
// We use duck-typing here to support any registered class that
|
|
111
|
+
// may contain other elements.
|
|
112
|
+
|
|
113
|
+
const itemWithFindElements = item;
|
|
114
|
+
if (recursive && typeof itemWithFindElements.findElements === 'function') {
|
|
115
|
+
itemWithFindElements.findElements(condition, {
|
|
116
|
+
results,
|
|
117
|
+
recursive
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
if (condition(item, i, undefined)) {
|
|
121
|
+
results.push(item);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return results;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Recursively search all descendants using a condition function.
|
|
129
|
+
*/
|
|
130
|
+
find(condition) {
|
|
131
|
+
const results = this.findElements(condition, {
|
|
132
|
+
recursive: true
|
|
133
|
+
});
|
|
134
|
+
return new this.ArrayElement(results);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Find elements by their element type name.
|
|
139
|
+
*/
|
|
140
|
+
findByElement(element) {
|
|
141
|
+
return this.find(item => item.element === element);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Find elements by class name.
|
|
146
|
+
*/
|
|
147
|
+
findByClass(className) {
|
|
148
|
+
return this.find(item => {
|
|
149
|
+
const classes = item.classes;
|
|
150
|
+
return typeof classes.includes === 'function' && classes.includes(className);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Search the tree recursively and find the element with the matching ID.
|
|
156
|
+
*/
|
|
157
|
+
getById(id) {
|
|
158
|
+
return this.find(item => item.id.toValue() === id).first;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Fantasy Land - Monoid
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Returns an empty collection element.
|
|
165
|
+
*/
|
|
166
|
+
|
|
167
|
+
'fantasy-land/empty'() {
|
|
168
|
+
return this.empty();
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Concatenates two collection elements.
|
|
173
|
+
*/
|
|
174
|
+
concat(other) {
|
|
175
|
+
const Ctor = this.constructor;
|
|
176
|
+
return new Ctor(this._content.concat(other._content));
|
|
177
|
+
}
|
|
178
|
+
'fantasy-land/concat'(other) {
|
|
179
|
+
return this.concat(other);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Iterator support
|
|
183
|
+
[Symbol.iterator]() {
|
|
184
|
+
return this._content[Symbol.iterator]();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
export default CollectionElement;
|
|
@@ -0,0 +1,438 @@
|
|
|
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 _ramda = require("ramda");
|
|
7
|
+
var _KeyValuePair = _interopRequireDefault(require("../KeyValuePair.cjs"));
|
|
8
|
+
var _ObjectSlice = _interopRequireDefault(require("../ObjectSlice.cjs"));
|
|
9
|
+
/**
|
|
10
|
+
* Valid content types for an Element.
|
|
11
|
+
* @public
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Base Element class that all ApiDOM elements extend.
|
|
16
|
+
*
|
|
17
|
+
* Elements are the core building blocks of ApiDOM. Each element has:
|
|
18
|
+
* - An `element` property identifying its type
|
|
19
|
+
* - Optional `content` holding the element's value
|
|
20
|
+
* - Optional `meta` for metadata (id, classes, title, description, links)
|
|
21
|
+
* - Optional `attributes` for element-specific properties
|
|
22
|
+
*
|
|
23
|
+
* @public
|
|
24
|
+
*/
|
|
25
|
+
class Element {
|
|
26
|
+
/**
|
|
27
|
+
* The element type identifier.
|
|
28
|
+
* @internal
|
|
29
|
+
*/
|
|
30
|
+
_storedElement = 'element';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The element's content/value.
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
_content;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Metadata about this element.
|
|
40
|
+
* @internal
|
|
41
|
+
*/
|
|
42
|
+
_meta;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Element-specific attributes.
|
|
46
|
+
* @internal
|
|
47
|
+
*/
|
|
48
|
+
_attributes;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Parent element reference (set when tree is frozen).
|
|
52
|
+
*/
|
|
53
|
+
parent;
|
|
54
|
+
|
|
55
|
+
// ============================================================
|
|
56
|
+
// Prototype-assigned properties (set in elements.ts)
|
|
57
|
+
// Using 'declare' allows TypeScript to know about these
|
|
58
|
+
// without generating runtime code.
|
|
59
|
+
// ============================================================
|
|
60
|
+
|
|
61
|
+
/** @internal ObjectElement constructor for creating meta/attributes */
|
|
62
|
+
|
|
63
|
+
/** @internal ArrayElement constructor for creating arrays */
|
|
64
|
+
|
|
65
|
+
/** @internal MemberElement constructor for creating object members */
|
|
66
|
+
|
|
67
|
+
/** @internal RefElement constructor for creating references */
|
|
68
|
+
|
|
69
|
+
/** @internal Function to convert values to elements */
|
|
70
|
+
|
|
71
|
+
constructor(content, meta, attributes) {
|
|
72
|
+
if (meta !== undefined) {
|
|
73
|
+
this.meta = meta;
|
|
74
|
+
}
|
|
75
|
+
if (attributes !== undefined) {
|
|
76
|
+
this.attributes = attributes;
|
|
77
|
+
}
|
|
78
|
+
if (content !== undefined) {
|
|
79
|
+
this.content = content;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// ============================================================
|
|
84
|
+
// Core Properties
|
|
85
|
+
// ============================================================
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The element type identifier (e.g., 'string', 'object', 'array').
|
|
89
|
+
*/
|
|
90
|
+
get element() {
|
|
91
|
+
return this._storedElement;
|
|
92
|
+
}
|
|
93
|
+
set element(value) {
|
|
94
|
+
this._storedElement = value;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The element's content/value.
|
|
99
|
+
*/
|
|
100
|
+
get content() {
|
|
101
|
+
return this._content;
|
|
102
|
+
}
|
|
103
|
+
set content(value) {
|
|
104
|
+
// Already an element
|
|
105
|
+
if (value instanceof Element) {
|
|
106
|
+
this._content = value;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Primitives (inlined for performance - avoids 8 function calls)
|
|
111
|
+
if (value === null || value === undefined || typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint' || typeof value === 'symbol') {
|
|
112
|
+
this._content = value;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// KeyValuePair
|
|
117
|
+
if (value instanceof _KeyValuePair.default) {
|
|
118
|
+
this._content = value;
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// ObjectSlice - extract elements array
|
|
123
|
+
if (value instanceof _ObjectSlice.default) {
|
|
124
|
+
this._content = value.elements;
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Array - refract each item
|
|
129
|
+
if (Array.isArray(value)) {
|
|
130
|
+
this._content = value.map(item => this.refract(item));
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Plain object - convert to MemberElements
|
|
135
|
+
if (typeof value === 'object') {
|
|
136
|
+
this._content = Object.entries(value).map(([key, val]) => new this.MemberElement(key, val));
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`Cannot set content to value of type ${typeof value}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Metadata about this element (id, classes, title, description, links).
|
|
144
|
+
* Lazily creates an ObjectElement if not set.
|
|
145
|
+
*/
|
|
146
|
+
get meta() {
|
|
147
|
+
if (!this._meta) {
|
|
148
|
+
if (this.isFrozen) {
|
|
149
|
+
const meta = new this.ObjectElement();
|
|
150
|
+
meta.freeze();
|
|
151
|
+
return meta;
|
|
152
|
+
}
|
|
153
|
+
this._meta = new this.ObjectElement();
|
|
154
|
+
}
|
|
155
|
+
return this._meta;
|
|
156
|
+
}
|
|
157
|
+
set meta(value) {
|
|
158
|
+
if (value instanceof Element) {
|
|
159
|
+
this._meta = value;
|
|
160
|
+
} else {
|
|
161
|
+
this.meta.set(value ?? {});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Element-specific attributes.
|
|
167
|
+
* Lazily creates an ObjectElement if not set.
|
|
168
|
+
*/
|
|
169
|
+
get attributes() {
|
|
170
|
+
if (!this._attributes) {
|
|
171
|
+
if (this.isFrozen) {
|
|
172
|
+
const attributes = new this.ObjectElement();
|
|
173
|
+
attributes.freeze();
|
|
174
|
+
return attributes;
|
|
175
|
+
}
|
|
176
|
+
this._attributes = new this.ObjectElement();
|
|
177
|
+
}
|
|
178
|
+
return this._attributes;
|
|
179
|
+
}
|
|
180
|
+
set attributes(value) {
|
|
181
|
+
if (value instanceof Element) {
|
|
182
|
+
this._attributes = value;
|
|
183
|
+
} else {
|
|
184
|
+
this.attributes.set(value ?? {});
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// ============================================================
|
|
189
|
+
// Meta Property Shortcuts
|
|
190
|
+
// ============================================================
|
|
191
|
+
|
|
192
|
+
/** Unique identifier for this element. */
|
|
193
|
+
get id() {
|
|
194
|
+
return this.getMetaProperty('id', '');
|
|
195
|
+
}
|
|
196
|
+
set id(value) {
|
|
197
|
+
this.setMetaProperty('id', value);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** CSS-like class names. */
|
|
201
|
+
get classes() {
|
|
202
|
+
return this.getMetaProperty('classes', []);
|
|
203
|
+
}
|
|
204
|
+
set classes(value) {
|
|
205
|
+
this.setMetaProperty('classes', value);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Human-readable title. */
|
|
209
|
+
get title() {
|
|
210
|
+
return this.getMetaProperty('title', '');
|
|
211
|
+
}
|
|
212
|
+
set title(value) {
|
|
213
|
+
this.setMetaProperty('title', value);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Human-readable description. */
|
|
217
|
+
get description() {
|
|
218
|
+
return this.getMetaProperty('description', '');
|
|
219
|
+
}
|
|
220
|
+
set description(value) {
|
|
221
|
+
this.setMetaProperty('description', value);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Hyperlinks associated with this element. */
|
|
225
|
+
get links() {
|
|
226
|
+
return this.getMetaProperty('links', []);
|
|
227
|
+
}
|
|
228
|
+
set links(value) {
|
|
229
|
+
this.setMetaProperty('links', value);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// ============================================================
|
|
233
|
+
// Tree Navigation
|
|
234
|
+
// ============================================================
|
|
235
|
+
|
|
236
|
+
/** Returns direct children of this element. */
|
|
237
|
+
get children() {
|
|
238
|
+
const {
|
|
239
|
+
_content: content
|
|
240
|
+
} = this;
|
|
241
|
+
if (Array.isArray(content)) {
|
|
242
|
+
return content;
|
|
243
|
+
}
|
|
244
|
+
if (content instanceof _KeyValuePair.default) {
|
|
245
|
+
const children = [];
|
|
246
|
+
if (content.key) children.push(content.key);
|
|
247
|
+
if (content.value) children.push(content.value);
|
|
248
|
+
return children;
|
|
249
|
+
}
|
|
250
|
+
if (content instanceof Element) {
|
|
251
|
+
return [content];
|
|
252
|
+
}
|
|
253
|
+
return [];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// ============================================================
|
|
257
|
+
// Freezable Implementation
|
|
258
|
+
// ============================================================
|
|
259
|
+
|
|
260
|
+
/** Whether this element is frozen (immutable). */
|
|
261
|
+
get isFrozen() {
|
|
262
|
+
return Object.isFrozen(this);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Freezes the element tree, making it immutable.
|
|
267
|
+
* Sets up parent references for tree traversal.
|
|
268
|
+
*/
|
|
269
|
+
freeze() {
|
|
270
|
+
if (this.isFrozen) return;
|
|
271
|
+
|
|
272
|
+
// Freeze meta and attributes
|
|
273
|
+
if (this._meta) {
|
|
274
|
+
this._meta.parent = this;
|
|
275
|
+
this._meta.freeze();
|
|
276
|
+
}
|
|
277
|
+
if (this._attributes) {
|
|
278
|
+
this._attributes.parent = this;
|
|
279
|
+
this._attributes.freeze();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Freeze children
|
|
283
|
+
for (const child of this.children) {
|
|
284
|
+
child.parent = this;
|
|
285
|
+
child.freeze();
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// Freeze content array if applicable
|
|
289
|
+
if (Array.isArray(this._content)) {
|
|
290
|
+
Object.freeze(this._content);
|
|
291
|
+
}
|
|
292
|
+
Object.freeze(this);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ============================================================
|
|
296
|
+
// Cloneable Implementation
|
|
297
|
+
// ============================================================
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Creates a deep clone of this element.
|
|
301
|
+
*/
|
|
302
|
+
clone() {
|
|
303
|
+
const Ctor = this.constructor;
|
|
304
|
+
const copy = new Ctor();
|
|
305
|
+
copy.element = this.element;
|
|
306
|
+
if (this._meta) {
|
|
307
|
+
copy._meta = this._meta.clone();
|
|
308
|
+
}
|
|
309
|
+
if (this._attributes) {
|
|
310
|
+
copy._attributes = this._attributes.clone();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Clone content based on its type
|
|
314
|
+
const {
|
|
315
|
+
_content
|
|
316
|
+
} = this;
|
|
317
|
+
if (_content instanceof Element) {
|
|
318
|
+
copy._content = _content.clone();
|
|
319
|
+
} else if (_content instanceof _KeyValuePair.default) {
|
|
320
|
+
copy._content = _content.clone();
|
|
321
|
+
} else if (Array.isArray(_content)) {
|
|
322
|
+
copy._content = _content.map(el => el.clone());
|
|
323
|
+
} else {
|
|
324
|
+
// Primitives are immutable, assign as-is
|
|
325
|
+
copy._content = _content;
|
|
326
|
+
}
|
|
327
|
+
return copy;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// ============================================================
|
|
331
|
+
// ToValue Implementation
|
|
332
|
+
// ============================================================
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Converts the element to its JavaScript value representation.
|
|
336
|
+
*/
|
|
337
|
+
toValue() {
|
|
338
|
+
const {
|
|
339
|
+
_content
|
|
340
|
+
} = this;
|
|
341
|
+
if (_content instanceof Element) {
|
|
342
|
+
return _content.toValue();
|
|
343
|
+
}
|
|
344
|
+
if (_content instanceof _KeyValuePair.default) {
|
|
345
|
+
return _content.toValue();
|
|
346
|
+
}
|
|
347
|
+
if (Array.isArray(_content)) {
|
|
348
|
+
return _content.map(el => el.toValue());
|
|
349
|
+
}
|
|
350
|
+
return _content;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ============================================================
|
|
354
|
+
// Equatable Implementation
|
|
355
|
+
// ============================================================
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Checks deep equality with another value.
|
|
359
|
+
*/
|
|
360
|
+
equals(value) {
|
|
361
|
+
return (0, _ramda.equals)(this.toValue(), value);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// ============================================================
|
|
365
|
+
// Element Type
|
|
366
|
+
// ============================================================
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Returns the primitive type name for this element.
|
|
370
|
+
* Override in subclasses (e.g., 'string', 'number', 'array').
|
|
371
|
+
*/
|
|
372
|
+
primitive() {
|
|
373
|
+
return undefined;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// ============================================================
|
|
377
|
+
// Content Operations
|
|
378
|
+
// ============================================================
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Sets the content of this element.
|
|
382
|
+
* @returns this for chaining
|
|
383
|
+
*/
|
|
384
|
+
set(content) {
|
|
385
|
+
this.content = content;
|
|
386
|
+
return this;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// ============================================================
|
|
390
|
+
// Reference Creation
|
|
391
|
+
// ============================================================
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Creates a RefElement pointing to this element.
|
|
395
|
+
* @param path - Optional path within the referenced element
|
|
396
|
+
* @throws Error if this element has no ID
|
|
397
|
+
*/
|
|
398
|
+
toRef(path) {
|
|
399
|
+
const idValue = this.id.toValue();
|
|
400
|
+
if (idValue === '') {
|
|
401
|
+
throw new Error('Cannot create reference to an element without an ID');
|
|
402
|
+
}
|
|
403
|
+
const ref = new this.RefElement(idValue);
|
|
404
|
+
if (typeof path === 'string') {
|
|
405
|
+
ref.path = this.refract(path);
|
|
406
|
+
}
|
|
407
|
+
return ref;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// ============================================================
|
|
411
|
+
// Protected Helpers
|
|
412
|
+
// ============================================================
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Gets a meta property, creating it with default value if not present.
|
|
416
|
+
*/
|
|
417
|
+
getMetaProperty(name, defaultValue) {
|
|
418
|
+
if (!this.meta.hasKey(name)) {
|
|
419
|
+
if (this.isFrozen) {
|
|
420
|
+
const element = this.refract(defaultValue);
|
|
421
|
+
element.freeze();
|
|
422
|
+
return element;
|
|
423
|
+
}
|
|
424
|
+
this.meta.set(name, defaultValue);
|
|
425
|
+
}
|
|
426
|
+
return this.meta.get(name);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Sets a meta property.
|
|
431
|
+
*/
|
|
432
|
+
setMetaProperty(name, value) {
|
|
433
|
+
this.meta.set(name, value);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// Re-export types for convenience
|
|
438
|
+
var _default = exports.default = Element;
|