@speclynx/apidom-core 2.13.0 → 3.0.0

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 CHANGED
@@ -3,6 +3,20 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [3.0.0](https://github.com/speclynx/apidom/compare/v2.13.1...v3.0.0) (2026-03-05)
7
+
8
+ ### Features
9
+
10
+ - introduce new memory efficient meta data management ([#129](https://github.com/speclynx/apidom/issues/129)) ([82ae0d7](https://github.com/speclynx/apidom/commit/82ae0d7cc2e9ee7037c3d9681817add2ca18dc92))
11
+
12
+ ### BREAKING CHANGES
13
+
14
+ - meta data use to be elements before, now they are simple primitives
15
+
16
+ ## [2.13.1](https://github.com/speclynx/apidom/compare/v2.13.0...v2.13.1) (2026-02-28)
17
+
18
+ **Note:** Version bump only for package @speclynx/apidom-core
19
+
6
20
  # [2.13.0](https://github.com/speclynx/apidom/compare/v2.12.4...v2.13.0) (2026-02-28)
7
21
 
8
22
  **Note:** Version bump only for package @speclynx/apidom-core
package/README.md CHANGED
@@ -377,16 +377,20 @@ The `customMetaMerge` function will be passed target and source metadata. If not
377
377
  the default behavior is to deep copy metadata from target to new merged element.
378
378
 
379
379
  ```js
380
- import { ObjectElement } from '@speclynx/apidom-datamodel';
380
+ import { ObjectElement, Metadata } from '@speclynx/apidom-datamodel';
381
381
  import { deepmerge } from '@speclynx/apidom-core';
382
382
 
383
383
  const alex = new ObjectElement({ name: { first: 'Alex' } }, { metaKey: true });
384
384
  const tony = new ObjectElement({ name: { first: 'Tony' } }, { metaKey: false });
385
385
 
386
- const customMetaMerge = (targetMeta, sourceMeta) => deepmerge(targetMeta, sourceMeta);
386
+ const customMetaMerge = (targetMeta, sourceMeta) => {
387
+ const merged = new Metadata();
388
+ Object.assign(merged, targetMeta, sourceMeta);
389
+ return merged;
390
+ };
387
391
 
388
392
  const output = deepmerge(alex, tony, { customMetaMerge });
389
- // output.meta.get('metaKey') // => BooleanElement(false)
393
+ // output.meta.get('metaKey') // => false
390
394
  ```
391
395
 
392
396
  #### customAttributesMerge
@@ -106,10 +106,9 @@ __webpack_require__.r(__webpack_exports__);
106
106
  /* harmony export */ defaultIdentityManager: () => (/* binding */ defaultIdentityManager)
107
107
  /* harmony export */ });
108
108
  /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5162);
109
- /* harmony import */ var _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(8121);
110
- /* harmony import */ var short_unique_id__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4279);
111
- /* harmony import */ var short_unique_id__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(short_unique_id__WEBPACK_IMPORTED_MODULE_2__);
112
- /* harmony import */ var _errors_ElementIdentityError_ts__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(421);
109
+ /* harmony import */ var short_unique_id__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4279);
110
+ /* harmony import */ var short_unique_id__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(short_unique_id__WEBPACK_IMPORTED_MODULE_1__);
111
+ /* harmony import */ var _errors_ElementIdentityError_ts__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(421);
113
112
 
114
113
 
115
114
 
@@ -123,23 +122,23 @@ class IdentityManager {
123
122
  constructor({
124
123
  length = 6
125
124
  } = {}) {
126
- this.uuid = new (short_unique_id__WEBPACK_IMPORTED_MODULE_2___default())({
125
+ this.uuid = new (short_unique_id__WEBPACK_IMPORTED_MODULE_1___default())({
127
126
  length
128
127
  });
129
128
  this.identityMap = new WeakMap();
130
129
  }
131
130
  identify(element) {
132
131
  if (!(0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.isElement)(element)) {
133
- throw new _errors_ElementIdentityError_ts__WEBPACK_IMPORTED_MODULE_3__["default"]('Cannot not identify the element. `element` is neither structurally compatible nor a subclass of an Element class.', {
132
+ throw new _errors_ElementIdentityError_ts__WEBPACK_IMPORTED_MODULE_2__["default"]('Cannot not identify the element. `element` is neither structurally compatible nor a subclass of an Element class.', {
134
133
  value: element
135
134
  });
136
135
  }
137
136
 
138
137
  // use already assigned identity
139
138
  if (element.hasMetaProperty('id')) {
140
- const existingId = element.meta.get('id');
141
- if ((0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_0__.isStringElement)(existingId) && !existingId.equals('')) {
142
- return element.id;
139
+ const existingId = element.id;
140
+ if (typeof existingId === 'string' && existingId !== '') {
141
+ return existingId;
143
142
  }
144
143
  }
145
144
 
@@ -149,7 +148,7 @@ class IdentityManager {
149
148
  }
150
149
 
151
150
  // return element identity
152
- const id = new _speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__["default"](this.generateId());
151
+ const id = this.generateId();
153
152
  this.identityMap.set(element, id);
154
153
  return id;
155
154
  }
@@ -258,7 +257,7 @@ __webpack_require__.r(__webpack_exports__);
258
257
  */
259
258
 
260
259
  const emptyElement = element => {
261
- const meta = !element.isMetaEmpty ? (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__.cloneDeep)(element.meta) : undefined;
260
+ const meta = !element.isMetaEmpty ? element.meta.cloneDeep() : undefined;
262
261
  const attributes = !element.isAttributesEmpty ? (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__.cloneDeep)(element.attributes) : undefined;
263
262
 
264
263
  // @ts-ignore
@@ -274,7 +273,7 @@ const getMergeFunction = (keyElement, options) => {
274
273
  };
275
274
  const getMetaMergeFunction = options => {
276
275
  if (typeof options.customMetaMerge !== 'function') {
277
- return targetMeta => (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__.cloneDeep)(targetMeta);
276
+ return targetMeta => targetMeta.cloneDeep();
278
277
  }
279
278
  return options.customMetaMerge;
280
279
  };
@@ -346,8 +345,20 @@ const deepmerge = (targetElement, sourceElement, options) => {
346
345
  const mergedElement = sourceIsArrayElement && typeof mergedOptions.arrayElementMerge === 'function' ? mergedOptions.arrayElementMerge(targetElement, sourceElement, mergedOptions) : mergedOptions.objectElementMerge(targetElement, sourceElement, mergedOptions);
347
346
 
348
347
  // merging meta & attributes
349
- mergedElement.meta = getMetaMergeFunction(mergedOptions)(targetElement.meta, sourceElement.meta);
350
- mergedElement.attributes = getAttributesMergeFunction(mergedOptions)(targetElement.attributes, sourceElement.attributes);
348
+ if (!targetElement.isMetaEmpty && !sourceElement.isMetaEmpty) {
349
+ mergedElement.meta = getMetaMergeFunction(mergedOptions)(targetElement.meta, sourceElement.meta);
350
+ } else if (!targetElement.isMetaEmpty) {
351
+ mergedElement.meta = targetElement.meta.cloneDeep();
352
+ } else if (!sourceElement.isMetaEmpty) {
353
+ mergedElement.meta = sourceElement.meta.cloneDeep();
354
+ }
355
+ if (!targetElement.isAttributesEmpty && !sourceElement.isAttributesEmpty) {
356
+ mergedElement.attributes = getAttributesMergeFunction(mergedOptions)(targetElement.attributes, sourceElement.attributes);
357
+ } else if (!targetElement.isAttributesEmpty) {
358
+ mergedElement.attributes = (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__.cloneDeep)(targetElement.attributes);
359
+ } else if (!sourceElement.isAttributesEmpty) {
360
+ mergedElement.attributes = (0,_speclynx_apidom_datamodel__WEBPACK_IMPORTED_MODULE_1__.cloneDeep)(sourceElement.attributes);
361
+ }
351
362
  return mergedElement;
352
363
  };
353
364
  deepmerge.all = (list, options) => {
@@ -24783,6 +24794,104 @@ class KeyValuePair {
24783
24794
 
24784
24795
  /***/ },
24785
24796
 
24797
+ /***/ 1844
24798
+ (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
24799
+
24800
+ __webpack_require__.r(__webpack_exports__);
24801
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
24802
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
24803
+ /* harmony export */ });
24804
+ /* harmony import */ var ramda__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(8138);
24805
+
24806
+ /**
24807
+ * Lightweight meta container for Element metadata.
24808
+ *
24809
+ * Data is stored as own properties on the instance; methods live on the prototype.
24810
+ * `Object.keys()`, `Object.entries()`, etc. only see data properties.
24811
+ *
24812
+ * @public
24813
+ */
24814
+ class Metadata {
24815
+ // Set via prototype assignment in registration.ts to avoid circular dependency
24816
+
24817
+ get(name) {
24818
+ return this[name];
24819
+ }
24820
+ set(name, value) {
24821
+ this[name] = value;
24822
+ }
24823
+ hasKey(name) {
24824
+ return Object.hasOwn(this, name);
24825
+ }
24826
+ keys() {
24827
+ return Object.keys(this);
24828
+ }
24829
+ remove(name) {
24830
+ delete this[name];
24831
+ }
24832
+ get isEmpty() {
24833
+ return Object.keys(this).length === 0;
24834
+ }
24835
+ get isFrozen() {
24836
+ return Object.isFrozen(this);
24837
+ }
24838
+ freeze() {
24839
+ for (const value of Object.values(this)) {
24840
+ if (value instanceof this.Element) {
24841
+ value.freeze();
24842
+ } else if (Array.isArray(value) || value !== null && typeof value === 'object') {
24843
+ Object.freeze(value);
24844
+ }
24845
+ }
24846
+ Object.freeze(this);
24847
+ }
24848
+
24849
+ /**
24850
+ * Creates a shallow clone. Same references, new container.
24851
+ */
24852
+ cloneShallow() {
24853
+ const clone = new Metadata();
24854
+ Object.assign(clone, this);
24855
+ return clone;
24856
+ }
24857
+
24858
+ /**
24859
+ * Merges another Metadata into a new instance.
24860
+ * Arrays are concatenated, all other values are overwritten by source.
24861
+ */
24862
+ merge(source) {
24863
+ const result = this.cloneShallow();
24864
+ for (const [key, value] of Object.entries(source)) {
24865
+ const existing = result.get(key);
24866
+ if (Array.isArray(existing) && Array.isArray(value)) {
24867
+ result.set(key, [...existing, ...value]);
24868
+ } else {
24869
+ result.set(key, value);
24870
+ }
24871
+ }
24872
+ return result;
24873
+ }
24874
+
24875
+ /**
24876
+ * Creates a deep clone. Elements are deep cloned,
24877
+ * all other values are deep cloned via ramda clone.
24878
+ */
24879
+ cloneDeep() {
24880
+ const copy = new Metadata();
24881
+ for (const [key, value] of Object.entries(this)) {
24882
+ if (value instanceof this.Element) {
24883
+ copy.set(key, this.cloneDeepElement(value));
24884
+ } else {
24885
+ copy.set(key, (0,ramda__WEBPACK_IMPORTED_MODULE_0__["default"])(value));
24886
+ }
24887
+ }
24888
+ return copy;
24889
+ }
24890
+ }
24891
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Metadata);
24892
+
24893
+ /***/ },
24894
+
24786
24895
  /***/ 5156
24787
24896
  (__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) {
24788
24897
 
@@ -25423,7 +25532,7 @@ const cloneShallowElement = element => {
25423
25532
  const copy = new Ctor();
25424
25533
  copy.element = element.element;
25425
25534
  if (!element.isMetaEmpty) {
25426
- copy.meta = cloneDeep(element.meta);
25535
+ copy.meta = element.meta.cloneDeep();
25427
25536
  }
25428
25537
  if (!element.isAttributesEmpty) {
25429
25538
  copy.attributes = cloneDeep(element.attributes);
@@ -25451,8 +25560,8 @@ const cloneShallowElement = element => {
25451
25560
 
25452
25561
  /**
25453
25562
  * Creates a shallow clone of an ApiDOM Element, KeyValuePair, or ObjectSlice.
25454
- * The element itself is cloned, but content references are shared (except for
25455
- * meta and attributes which are deep cloned to preserve semantic information).
25563
+ * The element itself is cloned, but content references are shared.
25564
+ * Meta and attributes are deep cloned to preserve semantic information.
25456
25565
  * @public
25457
25566
  */
25458
25567
  const cloneShallow = value => {
@@ -26514,7 +26623,7 @@ class CollectionElement extends _Element_mjs__WEBPACK_IMPORTED_MODULE_0__["defau
26514
26623
  * Search the tree recursively and find the element with the matching ID.
26515
26624
  */
26516
26625
  getById(id) {
26517
- return this.find(item => item.id.toValue() === id).first;
26626
+ return this.find(item => item.id === id).first;
26518
26627
  }
26519
26628
 
26520
26629
  /**
@@ -26543,18 +26652,24 @@ class CollectionElement extends _Element_mjs__WEBPACK_IMPORTED_MODULE_0__["defau
26543
26652
 
26544
26653
  __webpack_require__.r(__webpack_exports__);
26545
26654
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
26655
+ /* harmony export */ Metadata: () => (/* reexport safe */ _Metadata_mjs__WEBPACK_IMPORTED_MODULE_1__["default"]),
26546
26656
  /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
26547
26657
  /* harmony export */ });
26548
26658
  /* harmony import */ var ramda__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(3654);
26549
- /* harmony import */ var _KeyValuePair_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6663);
26550
- /* harmony import */ var _ObjectSlice_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8504);
26659
+ /* harmony import */ var _Metadata_mjs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1844);
26660
+ /* harmony import */ var _KeyValuePair_mjs__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6663);
26661
+ /* harmony import */ var _ObjectSlice_mjs__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8504);
26662
+
26551
26663
 
26552
26664
 
26665
+ // shared singleton for frozen elements with no meta — avoids allocation on every access
26666
+ const FROZEN_EMPTY_METADATA = Object.freeze(new _Metadata_mjs__WEBPACK_IMPORTED_MODULE_1__["default"]());
26553
26667
 
26554
26668
  /**
26555
26669
  * Valid content types for an Element.
26556
26670
  * @public
26557
26671
  */
26672
+
26558
26673
  /**
26559
26674
  * Base Element class that all ApiDOM elements extend.
26560
26675
  *
@@ -26652,7 +26767,7 @@ class Element {
26652
26767
  _attributes;
26653
26768
 
26654
26769
  // ============================================================
26655
- // Prototype-assigned properties (set in elements.ts)
26770
+ // Prototype-assigned properties (set in registration.ts)
26656
26771
  // Using 'declare' allows TypeScript to know about these
26657
26772
  // without generating runtime code.
26658
26773
  // ============================================================
@@ -26713,13 +26828,13 @@ class Element {
26713
26828
  }
26714
26829
 
26715
26830
  // KeyValuePair
26716
- if (value instanceof _KeyValuePair_mjs__WEBPACK_IMPORTED_MODULE_1__["default"]) {
26831
+ if (value instanceof _KeyValuePair_mjs__WEBPACK_IMPORTED_MODULE_2__["default"]) {
26717
26832
  this._content = value;
26718
26833
  return;
26719
26834
  }
26720
26835
 
26721
26836
  // ObjectSlice - extract elements array
26722
- if (value instanceof _ObjectSlice_mjs__WEBPACK_IMPORTED_MODULE_2__["default"]) {
26837
+ if (value instanceof _ObjectSlice_mjs__WEBPACK_IMPORTED_MODULE_3__["default"]) {
26723
26838
  this._content = value.elements;
26724
26839
  return;
26725
26840
  }
@@ -26740,24 +26855,22 @@ class Element {
26740
26855
 
26741
26856
  /**
26742
26857
  * Metadata about this element (id, classes, title, description, links).
26743
- * Lazily creates an ObjectElement if not set.
26858
+ * Lazily creates a Metadata instance if not set.
26744
26859
  */
26745
26860
  get meta() {
26746
26861
  if (!this._meta) {
26747
- if (this.isFrozen) {
26748
- const meta = new this.ObjectElement();
26749
- meta.freeze();
26750
- return meta;
26751
- }
26752
- this._meta = new this.ObjectElement();
26862
+ if (this.isFrozen) return FROZEN_EMPTY_METADATA;
26863
+ this._meta = new _Metadata_mjs__WEBPACK_IMPORTED_MODULE_1__["default"]();
26753
26864
  }
26754
26865
  return this._meta;
26755
26866
  }
26756
26867
  set meta(value) {
26757
- if (value instanceof Element) {
26868
+ if (value instanceof _Metadata_mjs__WEBPACK_IMPORTED_MODULE_1__["default"]) {
26758
26869
  this._meta = value;
26759
- } else {
26760
- this.meta.set(value ?? {});
26870
+ } else if (value && typeof value === 'object') {
26871
+ const meta = new _Metadata_mjs__WEBPACK_IMPORTED_MODULE_1__["default"]();
26872
+ Object.assign(meta, value);
26873
+ this._meta = meta;
26761
26874
  }
26762
26875
  }
26763
26876
 
@@ -26790,10 +26903,8 @@ class Element {
26790
26903
 
26791
26904
  /** Unique identifier for this element. */
26792
26905
  get id() {
26793
- if (this.isFrozen) {
26794
- return this.getMetaProperty('id', '');
26795
- }
26796
26906
  if (!this.hasMetaProperty('id')) {
26907
+ if (this.isFrozen) return '';
26797
26908
  this.setMetaProperty('id', '');
26798
26909
  }
26799
26910
  return this.meta.get('id');
@@ -26804,10 +26915,8 @@ class Element {
26804
26915
 
26805
26916
  /** CSS-like class names. */
26806
26917
  get classes() {
26807
- if (this.isFrozen) {
26808
- return this.getMetaProperty('classes', []);
26809
- }
26810
26918
  if (!this.hasMetaProperty('classes')) {
26919
+ if (this.isFrozen) return [];
26811
26920
  this.setMetaProperty('classes', []);
26812
26921
  }
26813
26922
  return this.meta.get('classes');
@@ -26818,11 +26927,13 @@ class Element {
26818
26927
 
26819
26928
  /** Hyperlinks associated with this element. */
26820
26929
  get links() {
26821
- if (this.isFrozen) {
26822
- return this.getMetaProperty('links', []);
26823
- }
26824
26930
  if (!this.hasMetaProperty('links')) {
26825
- this.setMetaProperty('links', []);
26931
+ if (this.isFrozen) {
26932
+ const empty = new this.ArrayElement();
26933
+ empty.freeze();
26934
+ return empty;
26935
+ }
26936
+ this.setMetaProperty('links', new this.ArrayElement());
26826
26937
  }
26827
26938
  return this.meta.get('links');
26828
26939
  }
@@ -26842,7 +26953,7 @@ class Element {
26842
26953
  if (Array.isArray(content)) {
26843
26954
  return content;
26844
26955
  }
26845
- if (content instanceof _KeyValuePair_mjs__WEBPACK_IMPORTED_MODULE_1__["default"]) {
26956
+ if (content instanceof _KeyValuePair_mjs__WEBPACK_IMPORTED_MODULE_2__["default"]) {
26846
26957
  const children = [];
26847
26958
  if (content.key) children.push(content.key);
26848
26959
  if (content.value) children.push(content.value);
@@ -26872,7 +26983,6 @@ class Element {
26872
26983
 
26873
26984
  // Freeze meta and attributes
26874
26985
  if (this._meta) {
26875
- this._meta.parent = this;
26876
26986
  this._meta.freeze();
26877
26987
  }
26878
26988
  if (this._attributes) {
@@ -26907,7 +27017,7 @@ class Element {
26907
27017
  if (_content instanceof Element) {
26908
27018
  return _content.toValue();
26909
27019
  }
26910
- if (_content instanceof _KeyValuePair_mjs__WEBPACK_IMPORTED_MODULE_1__["default"]) {
27020
+ if (_content instanceof _KeyValuePair_mjs__WEBPACK_IMPORTED_MODULE_2__["default"]) {
26911
27021
  return _content.toValue();
26912
27022
  }
26913
27023
  if (Array.isArray(_content)) {
@@ -26963,7 +27073,7 @@ class Element {
26963
27073
  * @throws Error if this element has no ID
26964
27074
  */
26965
27075
  toRef(path) {
26966
- const idValue = this.id.toValue();
27076
+ const idValue = this.id;
26967
27077
  if (idValue === '') {
26968
27078
  throw new Error('Cannot create reference to an element without an ID');
26969
27079
  }
@@ -26975,26 +27085,16 @@ class Element {
26975
27085
  }
26976
27086
 
26977
27087
  /**
26978
- * Gets a meta property.
27088
+ * Gets a meta property value.
26979
27089
  *
26980
27090
  * When the property doesn't exist:
26981
- * - With defaultValue: returns a new refracted element instance (not cached)
27091
+ * - With defaultValue: returns the provided default value
26982
27092
  * - Without defaultValue: returns undefined
26983
- *
26984
- * Note: Each call with a default creates a new instance. Use setMetaProperty
26985
- * first if you need reference equality across multiple accesses.
26986
27093
  */
26987
27094
 
26988
27095
  getMetaProperty(name, defaultValue) {
26989
27096
  if (!this.hasMetaProperty(name)) {
26990
- if (defaultValue === undefined) {
26991
- return undefined;
26992
- }
26993
- const element = this.refract(defaultValue);
26994
- if (element && this.isFrozen) {
26995
- element.freeze();
26996
- }
26997
- return element;
27097
+ return defaultValue;
26998
27098
  }
26999
27099
  return this.meta.get(name);
27000
27100
  }
@@ -27007,20 +27107,17 @@ class Element {
27007
27107
  }
27008
27108
 
27009
27109
  /**
27010
- * Has meta property.
27110
+ * Checks whether a meta property exists.
27011
27111
  */
27012
27112
  hasMetaProperty(name) {
27013
- if (!this.isMetaEmpty) {
27014
- return this.meta.hasKey(name);
27015
- }
27016
- return false;
27113
+ return this._meta !== undefined && this._meta.hasKey(name);
27017
27114
  }
27018
27115
 
27019
27116
  /**
27020
27117
  * Checks if meta is empty.
27021
27118
  */
27022
27119
  get isMetaEmpty() {
27023
- return this._meta === undefined || this.meta.isEmpty;
27120
+ return this._meta === undefined || this._meta.isEmpty;
27024
27121
  }
27025
27122
 
27026
27123
  /**
@@ -27046,7 +27143,7 @@ class Element {
27046
27143
  }
27047
27144
 
27048
27145
  /**
27049
- * Has attributes property.
27146
+ * Checks whether an attributes property exists.
27050
27147
  */
27051
27148
  hasAttributesProperty(name) {
27052
27149
  if (!this.isAttributesEmpty) {
@@ -27065,6 +27162,7 @@ class Element {
27065
27162
 
27066
27163
  // Re-export types for convenience
27067
27164
 
27165
+
27068
27166
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Element);
27069
27167
 
27070
27168
  /***/ },
@@ -27506,7 +27604,13 @@ class JSONSerialiser {
27506
27604
  element: element.element
27507
27605
  };
27508
27606
  if (!element.isMetaEmpty) {
27509
- payload.meta = this.serialiseObject(element.meta);
27607
+ const serialisedMeta = this.serialiseMeta(element);
27608
+ if (serialisedMeta) {
27609
+ payload.meta = serialisedMeta.meta;
27610
+ if (serialisedMeta.rawKeys.length > 0) {
27611
+ payload.__meta_raw__ = serialisedMeta.rawKeys;
27612
+ }
27613
+ }
27510
27614
  }
27511
27615
  if (!element.isAttributesEmpty) {
27512
27616
  payload.attributes = this.serialiseObject(element.attributes);
@@ -27553,7 +27657,7 @@ class JSONSerialiser {
27553
27657
  element.element = value.element;
27554
27658
  }
27555
27659
 
27556
- // Extract __mappings__ and __styles__ without mutating input, filter remaining meta
27660
+ // Extract special meta keys without mutating input, filter remaining meta
27557
27661
  let mappingsDoc;
27558
27662
  let stylesDoc;
27559
27663
  let metaToDeserialize = value.meta;
@@ -27567,8 +27671,15 @@ class JSONSerialiser {
27567
27671
  stylesDoc = __styles__;
27568
27672
  metaToDeserialize = Object.keys(rest).length > 0 ? rest : undefined;
27569
27673
  }
27674
+
27675
+ // determine which meta keys were raw primitives before serialization
27676
+ const rawKeys = value.__meta_raw__ ? new Set(value.__meta_raw__) : undefined;
27570
27677
  if (metaToDeserialize) {
27571
- this.deserialiseObject(metaToDeserialize, element.meta);
27678
+ for (const [key, doc] of Object.entries(metaToDeserialize)) {
27679
+ const deserialized = this.deserialise(doc);
27680
+ // unwrap keys that were raw primitives before serialization
27681
+ element.setMetaProperty(key, rawKeys?.has(key) ? deserialized.toValue() : deserialized);
27682
+ }
27572
27683
  }
27573
27684
 
27574
27685
  // Restore source position from __mappings__
@@ -27631,6 +27742,27 @@ class JSONSerialiser {
27631
27742
  }
27632
27743
  return content;
27633
27744
  }
27745
+ serialiseMeta(element) {
27746
+ const meta = {};
27747
+ const rawKeys = [];
27748
+ let hasEntries = false;
27749
+ for (const [key, value] of Object.entries(element.meta)) {
27750
+ if (value instanceof this.namespace.elements.Element) {
27751
+ meta[key] = this.serialise(value);
27752
+ hasEntries = true;
27753
+ } else if (value !== undefined) {
27754
+ // refract primitives to maintain JSON Refract spec compatibility
27755
+ const refracted = element.refract(value);
27756
+ meta[key] = this.serialise(refracted);
27757
+ rawKeys.push(key);
27758
+ hasEntries = true;
27759
+ }
27760
+ }
27761
+ return hasEntries ? {
27762
+ meta,
27763
+ rawKeys
27764
+ } : undefined;
27765
+ }
27634
27766
  serialiseObject(obj) {
27635
27767
  const result = {};
27636
27768
  obj.forEach((value, key) => {