bpmn-js 18.25.0 → 18.26.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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * bpmn-js - bpmn-viewer v18.25.0
2
+ * bpmn-js - bpmn-viewer v18.26.0
3
3
  *
4
4
  * Copyright (c) 2014-present, camunda Services GmbH
5
5
  *
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * Source Code: https://github.com/bpmn-io/bpmn-js
10
10
  *
11
- * Date: 2026-08-19
11
+ * Date: 2026-08-28
12
12
  */
13
13
  (function (global, factory) {
14
14
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
@@ -8048,14 +8048,7 @@
8048
8048
  return [];
8049
8049
  }
8050
8050
 
8051
- var title = escapeHTML(parent.name || parent.id);
8052
- var link = domify('<li><span class="bjs-crumb"><a title="' + title + '">' + title + '</a></span></li>');
8053
-
8054
- link.addEventListener('click', function() {
8055
- canvas.setRootElement(parentPlane);
8056
- });
8057
-
8058
- return link;
8051
+ return [ { parent: parent, parentPlane: parentPlane } ];
8059
8052
  });
8060
8053
 
8061
8054
  breadcrumbs.innerHTML = '';
@@ -8065,8 +8058,39 @@
8065
8058
 
8066
8059
  containerClasses.toggle(OPEN_CLASS, visible);
8067
8060
 
8068
- path.forEach(function(element) {
8069
- breadcrumbs.appendChild(element);
8061
+ path.forEach(function(entry, index) {
8062
+ var parent = entry.parent,
8063
+ parentPlane = entry.parentPlane,
8064
+ title = escapeHTML(parent.name || parent.id);
8065
+
8066
+ // the last crumb represents the current plane; render it as
8067
+ // plain, non-interactive text
8068
+ var isCurrent = index === path.length - 1;
8069
+
8070
+ var crumb;
8071
+
8072
+ if (isCurrent) {
8073
+ crumb = domify(
8074
+ '<li><span class="bjs-crumb" title="' + title + '">' + title + '</span></li>'
8075
+ );
8076
+ } else {
8077
+
8078
+ // render navigable crumbs as local links so they are focusable
8079
+ // and keyboard-operable
8080
+ var href = '#' + escapeHTML(parent.id);
8081
+
8082
+ crumb = domify(
8083
+ '<li><a class="bjs-crumb" href="' + href + '" title="' + title + '">' + title + '</a></li>'
8084
+ );
8085
+
8086
+ crumb.addEventListener('click', function(event) {
8087
+ event.preventDefault();
8088
+
8089
+ canvas.setRootElement(parentPlane);
8090
+ });
8091
+ }
8092
+
8093
+ breadcrumbs.appendChild(crumb);
8070
8094
  });
8071
8095
  }
8072
8096
 
@@ -14120,14 +14144,109 @@
14120
14144
  */
14121
14145
  function Base() { }
14122
14146
 
14147
+ /**
14148
+ * @template { keyof this } K
14149
+ *
14150
+ * Get property value (typed)
14151
+ *
14152
+ * @overload
14153
+ *
14154
+ * @param {K} name
14155
+ *
14156
+ * @return { this[K] }
14157
+ */
14158
+ /**
14159
+ * @template T
14160
+ *
14161
+ * Get property value
14162
+ *
14163
+ * @overload
14164
+ *
14165
+ * @param {string} name
14166
+ *
14167
+ * @return {T}
14168
+ */
14169
+ /**
14170
+ * Get property value
14171
+ *
14172
+ * @overload
14173
+ *
14174
+ * @param {string} name
14175
+ *
14176
+ * @return {unknown}
14177
+ */
14123
14178
  Base.prototype.get = function(name) {
14124
14179
  return this.$model.properties.get(this, name);
14125
14180
  };
14126
14181
 
14182
+ /**
14183
+ * @template { keyof this } K
14184
+ * @template { this[K] } V
14185
+ *
14186
+ * Set property value
14187
+ *
14188
+ * @overload
14189
+ *
14190
+ * @param {K} name
14191
+ * @param {V} value
14192
+ */
14193
+ /**
14194
+ * @template { string } S
14195
+ *
14196
+ * Set property value
14197
+ *
14198
+ * @overload
14199
+ *
14200
+ * @param { S extends keyof this ? never : S } name
14201
+ * @param { any } value
14202
+ */
14127
14203
  Base.prototype.set = function(name, value) {
14128
14204
  this.$model.properties.set(this, name, value);
14129
14205
  };
14130
14206
 
14207
+ /**
14208
+ * @typedef {import('./ns.js').Namespace} Namespace
14209
+ * @typedef {import('./moddle.js').default} Moddle
14210
+ * @typedef {import('./properties.js').default} Properties
14211
+ * @typedef {import('./registry.js').EffectiveDescriptor} EffectiveDescriptor
14212
+ * @typedef {import('./base.js').default} BaseElement
14213
+ * @typedef {import('./descriptor-builder.js').AnyTypeDescriptor} AnyTypeDescriptor
14214
+ */
14215
+
14216
+ /**
14217
+ * @template [T=Record<string,any>]
14218
+ * @typedef {{
14219
+ * new(attrs?: Partial<T>): ModdleElement<T>;
14220
+ * prototype: ModdleElement<T>;
14221
+ * readonly $model: Moddle;
14222
+ * readonly $descriptor: EffectiveDescriptor;
14223
+ * }} ModdleElementType
14224
+ */
14225
+
14226
+ /**
14227
+ * @template [T=Record<string,any>]
14228
+ * @typedef {BaseElement & T & {
14229
+ * readonly $model: Moddle;
14230
+ * readonly $descriptor: EffectiveDescriptor;
14231
+ * readonly $type: Namespace['name'];
14232
+ * readonly $attrs: Record<string, any>;
14233
+ * $parent?: ModdleElement | AnyModdleElement;
14234
+ * hasType: Moddle['hasType'];
14235
+ * $instanceOf: Moddle['hasType'];
14236
+ * }} ModdleElement
14237
+ */
14238
+
14239
+ /**
14240
+ * @template [T=Record<string,any>]
14241
+ * @typedef {BaseElement & T & {
14242
+ * $type: string;
14243
+ * $instanceOf: (type: string) => boolean;
14244
+ * $parent?: ModdleElement | AnyModdleElement;
14245
+ * readonly $model: Moddle;
14246
+ * readonly $descriptor: AnyTypeDescriptor;
14247
+ * }} AnyModdleElement
14248
+ */
14249
+
14131
14250
  /**
14132
14251
  * A model element factory.
14133
14252
  *
@@ -14135,11 +14254,23 @@
14135
14254
  * @param {Properties} properties
14136
14255
  */
14137
14256
  function Factory(model, properties) {
14257
+
14258
+ /**
14259
+ * @private
14260
+ */
14138
14261
  this.model = model;
14262
+
14263
+ /**
14264
+ * @private
14265
+ */
14139
14266
  this.properties = properties;
14140
14267
  }
14141
14268
 
14142
-
14269
+ /**
14270
+ * @template [T=Record<string,any>]
14271
+ * @param {EffectiveDescriptor} descriptor
14272
+ * @return {ModdleElementType<T>}
14273
+ */
14143
14274
  Factory.prototype.createType = function(descriptor) {
14144
14275
 
14145
14276
  var model = this.model;
@@ -14161,6 +14292,8 @@
14161
14292
 
14162
14293
  /**
14163
14294
  * The new type constructor
14295
+ *
14296
+ * @type { ModdleElementType }
14164
14297
  */
14165
14298
  function ModdleElement(attrs) {
14166
14299
  props.define(this, '$type', { value: name, enumerable: true });
@@ -14186,26 +14319,62 @@
14186
14319
  /**
14187
14320
  * Built-in moddle types
14188
14321
  */
14189
- var BUILTINS = {
14322
+ var BUILTINS = assign$1(Object.create(null), {
14190
14323
  String: true,
14191
14324
  Boolean: true,
14192
14325
  Integer: true,
14193
14326
  Real: true,
14194
14327
  Element: true
14195
- };
14328
+ });
14196
14329
 
14197
14330
  /**
14198
- * Converters for built in types from string representations
14331
+ * Converters for built-in types from string representations
14199
14332
  */
14200
- var TYPE_CONVERTERS = {
14333
+ var TYPE_CONVERTERS = assign$1(Object.create(null), {
14201
14334
  String: function(s) { return s; },
14202
14335
  Boolean: function(s) { return s === 'true'; },
14203
14336
  Integer: function(s) { return parseInt(s, 10); },
14204
14337
  Real: function(s) { return parseFloat(s); }
14205
- };
14338
+ });
14339
+
14340
+ /**
14341
+ * @typedef {'String'} StringType
14342
+ * @typedef {'Boolean'} BooleanType
14343
+ * @typedef {'Integer'} IntegerType
14344
+ * @typedef {'Real'} RealType
14345
+ * @typedef {'Element'} ElementType
14346
+ * @typedef {StringType | BooleanType | IntegerType | RealType} BuiltInSimpleType
14347
+ * @typedef {BuiltInSimpleType | ElementType} BuiltInType
14348
+ */
14206
14349
 
14350
+ /**
14351
+ * Convert given value to string
14352
+ * @overlord
14353
+ * @param {StringType} type
14354
+ * @param {any} value
14355
+ * @return {string}
14356
+ */
14357
+ /**
14358
+ * Convert given value to boolean
14359
+ * @overlord
14360
+ * @param {BooleanType} type
14361
+ * @param {any} value
14362
+ * @return {boolean}
14363
+ */
14364
+ /**
14365
+ * Convert given value to number
14366
+ * @overlord
14367
+ * @param {IntegerType | RealType} type
14368
+ * @param {any} value
14369
+ * @return {number}
14370
+ */
14207
14371
  /**
14208
14372
  * Convert a type to its real representation
14373
+ * @template T
14374
+ * @overlord
14375
+ * @param {Exclude<string,BuiltInSimpleType>} type
14376
+ * @param {T} value
14377
+ * @return {T}
14209
14378
  */
14210
14379
  function coerceType(type, value) {
14211
14380
 
@@ -14220,18 +14389,44 @@
14220
14389
 
14221
14390
  /**
14222
14391
  * Return whether the given type is built-in
14392
+ * @overload
14393
+ * @param {BuiltInType} type
14394
+ * @return {true}
14395
+ */
14396
+ /**
14397
+ * Return whether the given type is built-in
14398
+ * @overload
14399
+ * @param {Exclude<string,BuiltInType>} type
14400
+ * @return {false}
14223
14401
  */
14224
14402
  function isBuiltIn(type) {
14225
14403
  return !!BUILTINS[type];
14226
14404
  }
14227
14405
 
14228
14406
  /**
14229
- * Return whether the given type is simple
14407
+ * Return true if the given type is simple
14408
+ * @overload
14409
+ * @param {BuiltInSimpleType} type
14410
+ * @return {true}
14411
+ */
14412
+ /**
14413
+ * Return false the given type is not simple
14414
+ * @overload
14415
+ * @param {Exclude<string,BuiltInSimpleType>} type
14416
+ * @return {false}
14230
14417
  */
14231
14418
  function isSimple(type) {
14232
14419
  return !!TYPE_CONVERTERS[type];
14233
14420
  }
14234
14421
 
14422
+ /**
14423
+ * @typedef {{
14424
+ * name: string;
14425
+ * prefix: string;
14426
+ * localName: string;
14427
+ * }} Namespace
14428
+ */
14429
+
14235
14430
  /**
14236
14431
  * Parses a namespaced attribute name of the form (ns:)localName to an object,
14237
14432
  * given a default prefix to assume in case no explicit namespace is given.
@@ -14239,7 +14434,7 @@
14239
14434
  * @param {String} name
14240
14435
  * @param {String} [defaultPrefix] the default prefix to take, if none is present.
14241
14436
  *
14242
- * @return {Object} the parsed name
14437
+ * @return {Namespace} the parsed name
14243
14438
  */
14244
14439
  function parseName(name, defaultPrefix) {
14245
14440
  var parts = name.split(/:/),
@@ -14270,19 +14465,98 @@
14270
14465
  };
14271
14466
  }
14272
14467
 
14468
+ /**
14469
+ * @typedef {import('./ns.js').Namespace} Namespace
14470
+ * @typedef {import('./registry.js').RegisteredPackage} RegisteredPackage
14471
+ * @typedef {import('./registry.js').RegisteredTypeDef} RegisteredTypeDef
14472
+ * @typedef {import('./registry.js').RegisteredPropertyDef} RegisteredPropertyDef
14473
+ */
14474
+
14475
+ /**
14476
+ * Effective element descriptor
14477
+ * aka element type descriptor
14478
+ * aka element descriptor
14479
+ * @typedef {{
14480
+ * readonly ns: Namespace;
14481
+ * readonly name: Namespace['name'];
14482
+ * readonly allTypes: Array<RegisteredTypeDef>;
14483
+ * readonly allTypesByName: Record<string, RegisteredTypeDef>;
14484
+ * readonly properties: Array<PropertyDescriptor>;
14485
+ * readonly propertiesByName: Record<string, PropertyDescriptor>;
14486
+ * readonly bodyProperty?: PropertyDescriptor;
14487
+ * readonly idProperty?: PropertyDescriptor;
14488
+ * readonly $pkg?: RegisteredPackage;
14489
+ * }} EffectiveDescriptor
14490
+ */
14491
+
14492
+ /**
14493
+ * Property descriptor
14494
+ * @typedef {RegisteredPropertyDef & {
14495
+ * localName: Namespace['localName'];
14496
+ * inherited?: boolean;
14497
+ * definedBy?: RegisteredTypeDef;
14498
+ * }} PropertyDescriptor
14499
+ */
14500
+
14501
+ /**
14502
+ * @typedef {{
14503
+ * name: string;
14504
+ * isGeneric: true;
14505
+ * ns: {
14506
+ * prefix: string;
14507
+ * localName: string;
14508
+ * uri: string;
14509
+ * };
14510
+ * }} AnyTypeDescriptor
14511
+ */
14512
+
14273
14513
  /**
14274
14514
  * A utility to build element descriptors.
14515
+ * @class DescriptorBuilder
14516
+ * @param {Namespace} nameNs
14275
14517
  */
14276
14518
  function DescriptorBuilder(nameNs) {
14519
+
14520
+ /**
14521
+ * @private
14522
+ * @type {Namespace}
14523
+ */
14277
14524
  this.ns = nameNs;
14525
+
14526
+ /**
14527
+ * @private
14528
+ * @type {Namespace['name']}
14529
+ */
14278
14530
  this.name = nameNs.name;
14531
+
14532
+ /**
14533
+ * @private
14534
+ * @type {Array<RegisteredTypeDef>}
14535
+ */
14279
14536
  this.allTypes = [];
14280
- this.allTypesByName = {};
14537
+
14538
+ /**
14539
+ * @private
14540
+ * @type {Record<string, RegisteredTypeDef>}
14541
+ */
14542
+ this.allTypesByName = Object.create(null);
14543
+
14544
+ /**
14545
+ * @private
14546
+ * @type {Array<PropertyDescriptor>}
14547
+ */
14281
14548
  this.properties = [];
14282
- this.propertiesByName = {};
14283
- }
14284
14549
 
14550
+ /**
14551
+ * @private
14552
+ * @type {Record<string, PropertyDescriptor>}
14553
+ */
14554
+ this.propertiesByName = Object.create(null);
14555
+ }
14285
14556
 
14557
+ /**
14558
+ * @return {EffectiveDescriptor}
14559
+ */
14286
14560
  DescriptorBuilder.prototype.build = function() {
14287
14561
  return pick(this, [
14288
14562
  'ns',
@@ -14299,7 +14573,7 @@
14299
14573
  /**
14300
14574
  * Add property at given index.
14301
14575
  *
14302
- * @param {Object} p
14576
+ * @param {PropertyDescriptor} p
14303
14577
  * @param {Number} [idx]
14304
14578
  * @param {Boolean} [validate=true]
14305
14579
  */
@@ -14321,7 +14595,11 @@
14321
14595
  }
14322
14596
  };
14323
14597
 
14324
-
14598
+ /**
14599
+ * @param {PropertyDescriptor} oldProperty
14600
+ * @param {PropertyDescriptor} newProperty
14601
+ * @param {string} replace
14602
+ */
14325
14603
  DescriptorBuilder.prototype.replaceProperty = function(oldProperty, newProperty, replace) {
14326
14604
  var oldNameNs = oldProperty.ns;
14327
14605
 
@@ -14371,7 +14649,11 @@
14371
14649
  propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty;
14372
14650
  };
14373
14651
 
14374
-
14652
+ /**
14653
+ * @param {PropertyDescriptor} p
14654
+ * @param {string} targetPropertyName
14655
+ * @param {string} replace
14656
+ */
14375
14657
  DescriptorBuilder.prototype.redefineProperty = function(p, targetPropertyName, replace) {
14376
14658
 
14377
14659
  var nsPrefix = p.ns.prefix;
@@ -14390,6 +14672,10 @@
14390
14672
  delete p.redefines;
14391
14673
  };
14392
14674
 
14675
+ /**
14676
+ * @param {PropertyDescriptor} p
14677
+ * @param {boolean} validate
14678
+ */
14393
14679
  DescriptorBuilder.prototype.addNamedProperty = function(p, validate) {
14394
14680
  var ns = p.ns,
14395
14681
  propsByName = this.propertiesByName;
@@ -14402,6 +14688,9 @@
14402
14688
  propsByName[ns.name] = propsByName[ns.localName] = p;
14403
14689
  };
14404
14690
 
14691
+ /**
14692
+ * @param {RegisteredPropertyDef} p
14693
+ */
14405
14694
  DescriptorBuilder.prototype.removeNamedProperty = function(p) {
14406
14695
  var ns = p.ns,
14407
14696
  propsByName = this.propertiesByName;
@@ -14410,6 +14699,10 @@
14410
14699
  delete propsByName[ns.localName];
14411
14700
  };
14412
14701
 
14702
+ /**
14703
+ * @param {PropertyDescriptor} p
14704
+ * @param {boolean} [validate]
14705
+ */
14413
14706
  DescriptorBuilder.prototype.setBodyProperty = function(p, validate) {
14414
14707
 
14415
14708
  if (validate && this.bodyProperty) {
@@ -14421,6 +14714,10 @@
14421
14714
  this.bodyProperty = p;
14422
14715
  };
14423
14716
 
14717
+ /**
14718
+ * @param {PropertyDescriptor} p
14719
+ * @param {boolean} [validate]
14720
+ */
14424
14721
  DescriptorBuilder.prototype.setIdProperty = function(p, validate) {
14425
14722
 
14426
14723
  if (validate && this.idProperty) {
@@ -14432,6 +14729,9 @@
14432
14729
  this.idProperty = p;
14433
14730
  };
14434
14731
 
14732
+ /**
14733
+ * @param {RegisteredTypeDef} typeDescriptor
14734
+ */
14435
14735
  DescriptorBuilder.prototype.assertNotTrait = function(typeDescriptor) {
14436
14736
 
14437
14737
  const _extends = typeDescriptor.extends || [];
@@ -14443,6 +14743,9 @@
14443
14743
  }
14444
14744
  };
14445
14745
 
14746
+ /**
14747
+ * @param {PropertyDescriptor} p
14748
+ */
14446
14749
  DescriptorBuilder.prototype.assertNotDefined = function(p, name) {
14447
14750
  var propertyName = p.name,
14448
14751
  definedProperty = this.propertiesByName[propertyName];
@@ -14455,10 +14758,18 @@
14455
14758
  }
14456
14759
  };
14457
14760
 
14761
+ /**
14762
+ * @param {string} name
14763
+ * @return {PropertyDescriptor}
14764
+ */
14458
14765
  DescriptorBuilder.prototype.hasProperty = function(name) {
14459
14766
  return this.propertiesByName[name];
14460
14767
  };
14461
14768
 
14769
+ /**
14770
+ * @param {RegisteredTypeDef} t
14771
+ * @param {boolean} inherited
14772
+ */
14462
14773
  DescriptorBuilder.prototype.addTrait = function(t, inherited) {
14463
14774
 
14464
14775
  if (inherited) {
@@ -14507,33 +14818,94 @@
14507
14818
  typesByName[typeName] = t;
14508
14819
  };
14509
14820
 
14821
+ /**
14822
+ * @typedef {import('./ns.js').Namespace} Namespace
14823
+ * @typedef {import('./moddle.js').PackageDefinition} PackageDefinition
14824
+ * @typedef {import('./moddle.js').TypeDefinition} TypeDefinition
14825
+ * @typedef {import('./moddle.js').PropertyDefinition} PropertyDefinition
14826
+ * @typedef {import('./properties.js').default} Properties
14827
+ * @typedef {import('./descriptor-builder.js').EffectiveDescriptor} EffectiveDescriptor
14828
+ */
14829
+
14830
+ /**
14831
+ * Registered package definition
14832
+ * @typedef {Omit<PackageDefinition, 'types'> & {
14833
+ * types?: Array<RegisteredTypeDef>;
14834
+ * }} RegisteredPackage
14835
+ */
14836
+
14837
+ /**
14838
+ * Registered type definition
14839
+ * @typedef {Omit<TypeDefinition, 'properties'> & {
14840
+ * properties?: Array<RegisteredPropertyDef>;
14841
+ * propertiesByName?: Record<string, RegisteredPropertyDef>;
14842
+ * superClass?: Array<string>;
14843
+ * extends?: Array<string>;
14844
+ * meta?: Record<string, *>;
14845
+ * traits?: Array<string>;
14846
+ * ns?: Namespace;
14847
+ * readonly $pkg?: RegisteredPackage;
14848
+ * }} RegisteredTypeDef
14849
+ */
14850
+
14851
+ /**
14852
+ * Registered property definition
14853
+ * @typedef {PropertyDefinition & { ns: Namespace }} RegisteredPropertyDef
14854
+ */
14855
+
14510
14856
  /**
14511
14857
  * A registry of Moddle packages.
14512
14858
  *
14513
- * @param {Array<Package>} packages
14859
+ * @param {Array<PackageDefinition> | Record<string,PackageDefinition>} packages
14514
14860
  * @param {Properties} properties
14515
14861
  */
14516
14862
  function Registry(packages, properties) {
14517
- this.packageMap = {};
14518
- this.typeMap = {};
14519
14863
 
14864
+ /**
14865
+ * @private
14866
+ * @type {Record<string, RegisteredPackage>} registered packages map
14867
+ */
14868
+ this.packageMap = Object.create(null);
14869
+
14870
+ /**
14871
+ * @type {Record<string,RegisteredTypeDef>}
14872
+ */
14873
+ this.typeMap = Object.create(null);
14874
+
14875
+ /**
14876
+ * @private
14877
+ * @type {Array<RegisteredPackage>} all registered packages
14878
+ */
14520
14879
  this.packages = [];
14521
14880
 
14881
+ /**
14882
+ * @private
14883
+ * @type {Properties}
14884
+ */
14522
14885
  this.properties = properties;
14523
14886
 
14524
14887
  forEach(packages, bind$1(this.registerPackage, this));
14525
14888
  }
14526
14889
 
14527
-
14890
+ /**
14891
+ * @param {string} uriOrPrefix uri or prefix of package
14892
+ * @return {RegisteredPackage} registered package
14893
+ */
14528
14894
  Registry.prototype.getPackage = function(uriOrPrefix) {
14529
14895
  return this.packageMap[uriOrPrefix];
14530
14896
  };
14531
14897
 
14898
+ /**
14899
+ * @return {Array<RegisteredPackage>} all registered packages
14900
+ */
14532
14901
  Registry.prototype.getPackages = function() {
14533
14902
  return this.packages;
14534
14903
  };
14535
14904
 
14536
-
14905
+ /**
14906
+ * @private
14907
+ * @param {PackageDefinition} pkg registering package
14908
+ */
14537
14909
  Registry.prototype.registerPackage = function(pkg) {
14538
14910
 
14539
14911
  // copy package
@@ -14553,22 +14925,23 @@
14553
14925
  this.packages.push(pkg);
14554
14926
  };
14555
14927
 
14556
-
14557
14928
  /**
14929
+ * @private
14558
14930
  * Register a type from a specific package with us
14931
+ * @param {TypeDefinition} type
14932
+ * @param {RegisteredPackage} pkg
14559
14933
  */
14560
14934
  Registry.prototype.registerType = function(type, pkg) {
14561
-
14562
14935
  type = assign$1({}, type, {
14563
14936
  superClass: (type.superClass || []).slice(),
14564
14937
  extends: (type.extends || []).slice(),
14565
14938
  properties: (type.properties || []).slice(),
14566
- meta: assign$1((type.meta || {}))
14939
+ meta: assign$1({}, type.meta || {})
14567
14940
  });
14568
14941
 
14569
14942
  var ns = parseName(type.name, pkg.prefix),
14570
14943
  name = ns.name,
14571
- propertiesByName = {};
14944
+ /** @type {Record<string, RegisteredPropertyDef>} */ propertiesByName = Object.create(null);
14572
14945
 
14573
14946
  // parse properties
14574
14947
  forEach(type.properties, bind$1(function(p) {
@@ -14613,18 +14986,24 @@
14613
14986
  this.typeMap[name] = type;
14614
14987
  };
14615
14988
 
14989
+ /**
14990
+ * @callback IteratorFn
14991
+ * @param {RegisteredTypeDef} type
14992
+ * @param {boolean} inherited
14993
+ */
14616
14994
 
14617
14995
  /**
14618
14996
  * Traverse the type hierarchy from bottom to top,
14619
14997
  * calling iterator with (type, inherited) for all elements in
14620
14998
  * the inheritance chain.
14621
- *
14622
- * @param {Object} nsName
14623
- * @param {Function} iterator
14999
+ * @private
15000
+ * @param {Namespace} nsName
15001
+ * @param {IteratorFn} iterator
14624
15002
  * @param {Boolean} [trait=false]
14625
15003
  */
14626
15004
  Registry.prototype.mapTypes = function(nsName, iterator, trait) {
14627
15005
 
15006
+ /** @type {RegisteredTypeDef} */
14628
15007
  var type = isBuiltIn(nsName.name) ? { name: nsName.name } : this.typeMap[nsName.name];
14629
15008
 
14630
15009
  var self = this;
@@ -14670,13 +15049,10 @@
14670
15049
  forEach(type.traits, traverseTrait);
14671
15050
  };
14672
15051
 
14673
-
14674
15052
  /**
14675
15053
  * Returns the effective descriptor for a type.
14676
- *
14677
- * @param {String} type the namespaced name (ns:localName) of the type
14678
- *
14679
- * @return {Descriptor} the resulting effective descriptor
15054
+ * @param {Namespace['name']} name the namespaced name (ns:localName) of the type
15055
+ * @return {EffectiveDescriptor} the resulting effective descriptor
14680
15056
  */
14681
15057
  Registry.prototype.getEffectiveDescriptor = function(name) {
14682
15058
 
@@ -14696,15 +15072,23 @@
14696
15072
  return descriptor;
14697
15073
  };
14698
15074
 
14699
-
15075
+ /**
15076
+ * @private
15077
+ * @param {RegisteredTypeDef | EffectiveDescriptor} target
15078
+ * @param {RegisteredPackage} pkg
15079
+ */
14700
15080
  Registry.prototype.definePackage = function(target, pkg) {
14701
15081
  this.properties.define(target, '$pkg', { value: pkg });
14702
15082
  };
14703
15083
 
14704
-
14705
-
14706
15084
  // helpers ////////////////////////////
14707
15085
 
15086
+ /**
15087
+ * Checking already defined packages
15088
+ * @param {Record<string, RegisteredPackage>} packageMap
15089
+ * @param {PackageDefinition} pkg
15090
+ * @param {'prefix' | 'uri'} identifierKey
15091
+ */
14708
15092
  function ensureAvailable(packageMap, pkg, identifierKey) {
14709
15093
 
14710
15094
  var value = pkg[identifierKey];
@@ -14714,21 +15098,30 @@
14714
15098
  }
14715
15099
  }
14716
15100
 
15101
+ /**
15102
+ * @typedef {import('./moddle.js').default} Moddle
15103
+ * @typedef {import('./descriptor-builder.js').PropertyDescriptor} PropertyDesc
15104
+ * @typedef {import('./registry.js').EffectiveDescriptor} EffectiveDescriptor
15105
+ * @typedef {import('./factory.js').ModdleElement} ModdleElement
15106
+ * @typedef {import('./descriptor-builder.js').AnyTypeDescriptor} AnyTypeDescriptor
15107
+ */
15108
+
14717
15109
  /**
14718
15110
  * A utility that gets and sets properties of model elements.
14719
15111
  *
14720
- * @param {Model} model
15112
+ * @param {Moddle} model
14721
15113
  */
14722
15114
  function Properties(model) {
15115
+
15116
+ /** @type {Moddle} */
14723
15117
  this.model = model;
14724
15118
  }
14725
15119
 
14726
-
14727
15120
  /**
14728
15121
  * Sets a named property on the target element.
14729
15122
  * If the value is undefined, the property gets deleted.
14730
15123
  *
14731
- * @param {Object} target
15124
+ * @param {ModdleElement} target
14732
15125
  * @param {String} name
14733
15126
  * @param {Object} value
14734
15127
  */
@@ -14770,7 +15163,7 @@
14770
15163
  /**
14771
15164
  * Returns the named property of the given element
14772
15165
  *
14773
- * @param {Object} target
15166
+ * @param {ModdleElement} target
14774
15167
  * @param {String} name
14775
15168
  *
14776
15169
  * @return {Object}
@@ -14793,13 +15186,12 @@
14793
15186
  return target[propertyName];
14794
15187
  };
14795
15188
 
14796
-
14797
15189
  /**
14798
15190
  * Define a property on the target element
14799
- *
14800
- * @param {Object} target
15191
+ * @template [T=any]
15192
+ * @param {NonNullable<T>} target
14801
15193
  * @param {String} name
14802
- * @param {Object} options
15194
+ * @param {PropertyDescriptor} options
14803
15195
  */
14804
15196
  Properties.prototype.define = function(target, name, options) {
14805
15197
 
@@ -14819,9 +15211,11 @@
14819
15211
  Object.defineProperty(target, name, options);
14820
15212
  };
14821
15213
 
14822
-
14823
15214
  /**
14824
15215
  * Define the descriptor for an element
15216
+ * @template [T=any]
15217
+ * @param {NonNullable<T>} target
15218
+ * @param {EffectiveDescriptor | AnyTypeDescriptor} descriptor
14825
15219
  */
14826
15220
  Properties.prototype.defineDescriptor = function(target, descriptor) {
14827
15221
  this.define(target, '$descriptor', { value: descriptor });
@@ -14829,6 +15223,9 @@
14829
15223
 
14830
15224
  /**
14831
15225
  * Define the model for an element
15226
+ * @template [T=any]
15227
+ * @param {NonNullable<T>} target
15228
+ * @param {Moddle} model
14832
15229
  */
14833
15230
  Properties.prototype.defineModel = function(target, model) {
14834
15231
  this.define(target, '$model', { value: model });
@@ -14837,10 +15234,10 @@
14837
15234
  /**
14838
15235
  * Return property with the given name on the element.
14839
15236
  *
14840
- * @param {any} target
15237
+ * @param {ModdleElement} target
14841
15238
  * @param {string} name
14842
15239
  *
14843
- * @return {object | null} property
15240
+ * @return {PropertyDesc | null} property
14844
15241
  */
14845
15242
  Properties.prototype.getProperty = function(target, name) {
14846
15243
 
@@ -14889,6 +15286,83 @@
14889
15286
  return name.replace(/^:/, '');
14890
15287
  }
14891
15288
 
15289
+ /**
15290
+ * @typedef {import('./registry.js').RegisteredTypeDef} RegisteredTypeDef
15291
+ * @typedef {import('./registry.js').RegisteredPackage} RegisteredPackage
15292
+ * @typedef {import('./base.js').default} BaseElement
15293
+ * @typedef {import('./descriptor-builder.js').EffectiveDescriptor} EffectiveDescriptor
15294
+ * @typedef {import('./descriptor-builder.js').AnyTypeDescriptor} AnyTypeDescriptor
15295
+ * @typedef {import('./descriptor-builder.js').PropertyDescriptor} PropertyDescriptor
15296
+ */
15297
+
15298
+ /**
15299
+ * @template [T=Record<string,any>]
15300
+ * @typedef {import('./factory.js').ModdleElement<T>} ModdleElement
15301
+ * @typedef {import('./factory.js').ModdleElementType<T>} ModdleElementType
15302
+ * @typedef {import('./factory.js').AnyModdleElement<T>} AnyModdleElement
15303
+ */
15304
+
15305
+ /**
15306
+ * Package definition
15307
+ * @typedef {{
15308
+ * $schema?: string;
15309
+ * name: string;
15310
+ * prefix: string;
15311
+ * types?: Array<TypeDefinition>;
15312
+ * [key: string]: any;
15313
+ * } & PackageDefinitionXmlExtension} PackageDefinition
15314
+ */
15315
+
15316
+ /**
15317
+ * Set of extended parameters for package definition used in moddle-xml.
15318
+ * @typedef {{
15319
+ * uri?: string;
15320
+ * xml?: {
15321
+ * tagAlias?: 'lowerCase';
15322
+ * typePrefix?: string;
15323
+ * };
15324
+ * }} PackageDefinitionXmlExtension
15325
+ */
15326
+
15327
+ /**
15328
+ * Type definition in declaration in package
15329
+ * @typedef {{
15330
+ * name: string;
15331
+ * isAbstract?: boolean;
15332
+ * properties?: Array<PropertyDefinition>;
15333
+ * superClass?: Array<string>;
15334
+ * extends?: Array<string>;
15335
+ * meta?: Record<string, *>;
15336
+ * [key: string]: any;
15337
+ * }} TypeDefinition
15338
+ */
15339
+
15340
+ /**
15341
+ * Set of extended parameters for property definition used in moddle-xml.
15342
+ * @typedef {{
15343
+ * isBody?: boolean;
15344
+ * isAttr?: boolean;
15345
+ * xml?: {
15346
+ * serialize?: string;
15347
+ * };
15348
+ * }} PropertyDefinitionXmlExtension
15349
+ */
15350
+
15351
+ /**
15352
+ * Property definition of type definition
15353
+ * @typedef {{
15354
+ * name: string;
15355
+ * type: 'String' | 'Boolean' | 'Integer' | 'Real' | string;
15356
+ * default?: string | boolean | number;
15357
+ * isMany?: boolean;
15358
+ * isReference?: boolean;
15359
+ * isId?: boolean;
15360
+ * redefines?: string;
15361
+ * replaces?: string;
15362
+ * [key: string]: any;
15363
+ * } & PropertyDefinitionXmlExtension} PropertyDefinition
15364
+ */
15365
+
14892
15366
  // Moddle implementation /////////////////////////////////////////////////
14893
15367
 
14894
15368
  /**
@@ -14898,7 +15372,7 @@
14898
15372
  *
14899
15373
  * @example
14900
15374
  *
14901
- * var Moddle = require('moddle');
15375
+ * import Moddle from 'moddle';
14902
15376
  *
14903
15377
  * var pkg = {
14904
15378
  * name: 'mypackage',
@@ -14910,23 +15384,31 @@
14910
15384
  *
14911
15385
  * var moddle = new Moddle([pkg]);
14912
15386
  *
14913
- * @param {Array<Package>} packages the packages to contain
14914
- *
14915
- * @param { { strict?: boolean } } [config] moddle configuration
15387
+ * @param {Array<PackageDefinition> | Record<string,PackageDefinition>} packages the packages to contain
15388
+ * @param {{ strict?: boolean }} [config={}] moddle configuration
14916
15389
  */
14917
15390
  function Moddle(packages, config = {}) {
14918
15391
 
15392
+ /** @type Readonly<Properties> */
14919
15393
  this.properties = new Properties(this);
14920
15394
 
15395
+ /** @type Readonly<Factory> */
14921
15396
  this.factory = new Factory(this, this.properties);
14922
- this.registry = new Registry(packages, this.properties);
14923
15397
 
14924
- this.typeCache = {};
15398
+ /** @type Readonly<Registry> */
15399
+ this.registry = new Registry(packages, this.properties);
14925
15400
 
15401
+ /**
15402
+ * @type {Record<string,ModdleElementType>}
15403
+ */
15404
+ this.typeCache = Object.create(null);
15405
+
15406
+ /**
15407
+ * @type {Readonly<{readonly strict?: boolean}>}
15408
+ */
14926
15409
  this.config = config;
14927
15410
  }
14928
15411
 
14929
-
14930
15412
  /**
14931
15413
  * Create an instance of the specified type.
14932
15414
  *
@@ -14937,9 +15419,10 @@
14937
15419
  * var foo = moddle.create('my:Foo');
14938
15420
  * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
14939
15421
  *
14940
- * @param {String|Object} descriptor the type descriptor or name know to the model
14941
- * @param {Object} attrs a number of attributes to initialize the model instance with
14942
- * @return {Object} model instance
15422
+ * @template [T=Record<string,any>]
15423
+ * @param {String|EffectiveDescriptor} descriptor the type descriptor or name know to the model
15424
+ * @param {Partial<T>} [attrs] a number of attributes to initialize the model instance with
15425
+ * @return {ModdleElement<T>} model instance
14943
15426
  */
14944
15427
  Moddle.prototype.create = function(descriptor, attrs) {
14945
15428
  var Type = this.getType(descriptor);
@@ -14951,7 +15434,6 @@
14951
15434
  return new Type(attrs);
14952
15435
  };
14953
15436
 
14954
-
14955
15437
  /**
14956
15438
  * Returns the type representing a given descriptor
14957
15439
  *
@@ -14962,8 +15444,9 @@
14962
15444
  * var Foo = moddle.getType('my:Foo');
14963
15445
  * var foo = new Foo({ 'id' : 'FOO_1' });
14964
15446
  *
14965
- * @param {String|Object} descriptor the type descriptor or name know to the model
14966
- * @return {Object} the type representing the descriptor
15447
+ * @template [T=Record<string,any>]
15448
+ * @param {String|EffectiveDescriptor} descriptor the type descriptor or name know to the model
15449
+ * @return {ModdleElementType<T>} the type representing the descriptor
14967
15450
  */
14968
15451
  Moddle.prototype.getType = function(descriptor) {
14969
15452
 
@@ -14981,7 +15464,6 @@
14981
15464
  return type;
14982
15465
  };
14983
15466
 
14984
-
14985
15467
  /**
14986
15468
  * Creates an any-element type to be used within model instances.
14987
15469
  *
@@ -15003,16 +15485,17 @@
15003
15485
  *
15004
15486
  * // go ahead and serialize the stuff
15005
15487
  *
15006
- *
15488
+ * @template [T=Record<string, any>]
15007
15489
  * @param {String} name the name of the element
15008
15490
  * @param {String} nsUri the namespace uri of the element
15009
- * @param {Object} [properties] a map of properties to initialize the instance with
15010
- * @return {Object} the any type instance
15491
+ * @param {T} [properties] a map of properties to initialize the instance with
15492
+ * @return {AnyModdleElement<T>} the any type instance
15011
15493
  */
15012
15494
  Moddle.prototype.createAny = function(name, nsUri, properties) {
15013
15495
 
15014
15496
  var nameNs = parseName(name);
15015
15497
 
15498
+ /** @type AnyModdleElement */
15016
15499
  var element = {
15017
15500
  $type: name,
15018
15501
  $instanceOf: function(type) {
@@ -15026,6 +15509,7 @@
15026
15509
  }
15027
15510
  };
15028
15511
 
15512
+ /** @type AnyTypeDescriptor */
15029
15513
  var descriptor = {
15030
15514
  name: name,
15031
15515
  isGeneric: true,
@@ -15056,8 +15540,8 @@
15056
15540
 
15057
15541
  /**
15058
15542
  * Returns a registered package by uri or prefix
15059
- *
15060
- * @return {Object} the package
15543
+ * @param {string} uriOrPrefix
15544
+ * @return {RegisteredPackage} the package
15061
15545
  */
15062
15546
  Moddle.prototype.getPackage = function(uriOrPrefix) {
15063
15547
  return this.registry.getPackage(uriOrPrefix);
@@ -15066,7 +15550,7 @@
15066
15550
  /**
15067
15551
  * Returns a snapshot of all known packages
15068
15552
  *
15069
- * @return {Object} the package
15553
+ * @return {Readonly<Array<RegisteredPackage>>} the package
15070
15554
  */
15071
15555
  Moddle.prototype.getPackages = function() {
15072
15556
  return this.registry.getPackages();
@@ -15074,16 +15558,25 @@
15074
15558
 
15075
15559
  /**
15076
15560
  * Returns the descriptor for an element
15561
+ * @param {ModdleElement | ModdleElementType} element
15562
+ * @return {EffectiveDescriptor}
15077
15563
  */
15078
15564
  Moddle.prototype.getElementDescriptor = function(element) {
15079
15565
  return element.$descriptor;
15080
15566
  };
15081
15567
 
15082
15568
  /**
15569
+ * @overload
15083
15570
  * Returns true if the given descriptor or instance
15084
15571
  * represents the given type.
15085
- *
15086
- * May be applied to this, if element is omitted.
15572
+ * @param {ModdleElement | ModdleElementType} element
15573
+ * @param {string} type
15574
+ * @return {boolean}
15575
+ */
15576
+ /**
15577
+ * @overload
15578
+ * @param {string} type
15579
+ * @return {boolean}
15087
15580
  */
15088
15581
  Moddle.prototype.hasType = function(element, type) {
15089
15582
  if (type === undefined) {
@@ -15098,13 +15591,18 @@
15098
15591
 
15099
15592
  /**
15100
15593
  * Returns the descriptor of an elements named property
15594
+ * @param {ModdleElement | ModdleElementType} element
15595
+ * @param {string} property
15596
+ * @return {PropertyDescriptor}
15101
15597
  */
15102
15598
  Moddle.prototype.getPropertyDescriptor = function(element, property) {
15103
15599
  return this.getElementDescriptor(element).propertiesByName[property];
15104
15600
  };
15105
15601
 
15106
15602
  /**
15107
- * Returns a mapped type's descriptor
15603
+ * Return registered type definition
15604
+ * @param {string} type
15605
+ * @return {RegisteredTypeDef}
15108
15606
  */
15109
15607
  Moddle.prototype.getTypeDescriptor = function(type) {
15110
15608
  return this.registry.typeMap[type];
@@ -15188,19 +15686,24 @@
15188
15686
  }
15189
15687
 
15190
15688
  function cloneNsMatrix(nsMatrix) {
15191
- var clone = {}, key;
15689
+ var clone = Object.create(null), key;
15192
15690
  for (key in nsMatrix) {
15193
15691
  clone[key] = nsMatrix[key];
15194
15692
  }
15195
15693
  return clone;
15196
15694
  }
15197
15695
 
15696
+ // per-matrix element name cache; stored under a symbol so it is
15697
+ // invisible to the `for (key in nsMatrix)` clone above and gets
15698
+ // collected together with the matrix it belongs to
15699
+ var NAME_CACHE = Symbol('nameCache');
15700
+
15198
15701
  function uriPrefix(prefix) {
15199
15702
  return prefix + '$uri';
15200
15703
  }
15201
15704
 
15202
15705
  function buildNsMatrix(nsUriToPrefix) {
15203
- var nsMatrix = {},
15706
+ var nsMatrix = Object.create(null),
15204
15707
  uri,
15205
15708
  prefix;
15206
15709
 
@@ -15248,6 +15751,33 @@
15248
15751
 
15249
15752
  var getContext = noopGetContext;
15250
15753
 
15754
+ /**
15755
+ * Are we currently consuming a chunked stream of XML,
15756
+ * i.e. is a `write` call in progress that may be followed
15757
+ * by more chunks?
15758
+ *
15759
+ * @type {boolean}
15760
+ */
15761
+ var streaming = false;
15762
+
15763
+ /**
15764
+ * Did we already encounter the root tag?
15765
+ *
15766
+ * Persisted across `write` calls so we can detect a missing
15767
+ * start tag once the stream ends.
15768
+ *
15769
+ * @type {boolean}
15770
+ */
15771
+ var rootTagFound = false;
15772
+
15773
+ /**
15774
+ * Not yet parsed remainder of the previously written chunk,
15775
+ * i.e. an incomplete token that awaits more input.
15776
+ *
15777
+ * @type {string}
15778
+ */
15779
+ var leftoverXml = '';
15780
+
15251
15781
  /**
15252
15782
  * Do we need to parse the current elements attributes for namespaces?
15253
15783
  *
@@ -15276,6 +15806,13 @@
15276
15806
  */
15277
15807
  var parseStop = false;
15278
15808
 
15809
+ /**
15810
+ * Namespace + node state shared across (streamed) parse runs.
15811
+ */
15812
+ var nsMatrixStack,
15813
+ nsMatrix,
15814
+ nodeStack;
15815
+
15279
15816
  /**
15280
15817
  * A map of { uri: prefix } used by the parser.
15281
15818
  *
@@ -15374,7 +15911,7 @@
15374
15911
  throw error$1('required args <nsMap={}>');
15375
15912
  }
15376
15913
 
15377
- var _nsUriToPrefix = {}, k;
15914
+ var _nsUriToPrefix = Object.create(null), k;
15378
15915
 
15379
15916
  for (k in nsMap) {
15380
15917
  _nsUriToPrefix[k] = nsMap[k];
@@ -15387,7 +15924,22 @@
15387
15924
  };
15388
15925
 
15389
15926
  /**
15390
- * Parse xml string.
15927
+ * Reset the parser state before a (streamed) parse run.
15928
+ */
15929
+ function resetState() {
15930
+ nsMatrixStack = isNamespace ? [] : null;
15931
+ nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null;
15932
+ nodeStack = [];
15933
+
15934
+ getContext = noopGetContext;
15935
+ parseStop = false;
15936
+ returnError = null;
15937
+ rootTagFound = false;
15938
+ leftoverXml = '';
15939
+ }
15940
+
15941
+ /**
15942
+ * Parse a complete xml string.
15391
15943
  *
15392
15944
  * @param {string} xml
15393
15945
  *
@@ -15398,7 +15950,11 @@
15398
15950
  throw error$1('required args <xml=string>');
15399
15951
  }
15400
15952
 
15401
- returnError = null;
15953
+ if (streaming) {
15954
+ throw error$1('parse during stream; call end() first');
15955
+ }
15956
+
15957
+ resetState();
15402
15958
 
15403
15959
  parse(xml);
15404
15960
 
@@ -15408,6 +15964,60 @@
15408
15964
  return returnError;
15409
15965
  };
15410
15966
 
15967
+ /**
15968
+ * Write the next chunk of a streamed xml string.
15969
+ *
15970
+ * Parse events are emitted for all complete tokens; an
15971
+ * incomplete trailing token is buffered until the next
15972
+ * `write` or, ultimately, reported as an error on `end`.
15973
+ *
15974
+ * @param {string} xml
15975
+ *
15976
+ * @return {Parser} self
15977
+ */
15978
+ this['write'] = function(xml) {
15979
+ if (typeof xml !== 'string') {
15980
+ throw error$1('required args <xml=string>');
15981
+ }
15982
+
15983
+ if (!streaming) {
15984
+ resetState();
15985
+ streaming = true;
15986
+ }
15987
+
15988
+ if (!returnError) {
15989
+ leftoverXml = parse(leftoverXml + xml, true) || '';
15990
+ }
15991
+
15992
+ return this;
15993
+ };
15994
+
15995
+ /**
15996
+ * Finish parsing a streamed xml string, i.e. signal that
15997
+ * no more chunks will be written.
15998
+ *
15999
+ * @return {Error} returnError, if not thrown
16000
+ */
16001
+ this['end'] = function() {
16002
+ if (!streaming) {
16003
+ resetState();
16004
+ }
16005
+
16006
+ // flush the buffered remainder, now treating an incomplete
16007
+ // trailing token as a hard error
16008
+ streaming = false;
16009
+
16010
+ if (!returnError) {
16011
+ parse(leftoverXml);
16012
+ }
16013
+
16014
+ leftoverXml = '';
16015
+ getContext = noopGetContext;
16016
+ parseStop = false;
16017
+
16018
+ return returnError;
16019
+ };
16020
+
15411
16021
  /**
15412
16022
  * Stop parsing.
15413
16023
  */
@@ -15418,13 +16028,26 @@
15418
16028
  /**
15419
16029
  * Parse string, invoking configured listeners on element.
15420
16030
  *
15421
- * @param {string} xml
16031
+ * Namespace and node stack state is shared across (streamed)
16032
+ * invocations via the enclosing parser scope.
16033
+ *
16034
+ * Internal note: while `streaming`, an incomplete trailing token
16035
+ * is not treated as an error but returned so `write` can buffer it
16036
+ * and prepend it to the next chunk. This buffered remainder is an
16037
+ * implementation detail of the streaming buffer, not a public API;
16038
+ * outside of that case the return value is `undefined`.
16039
+ *
16040
+ * @param {string} xml
16041
+ * @param {boolean} streaming
16042
+ *
16043
+ * @return {string|undefined} buffered remainder, streaming internal use only
15422
16044
  */
15423
- function parse(xml) {
15424
- var nsMatrixStack = isNamespace ? [] : null,
15425
- nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null,
15426
- _nsMatrix,
15427
- nodeStack = [],
16045
+ function parse(xml, streaming = false) {
16046
+
16047
+ var elNameCache = null,
16048
+ elNameCacheMatrix = null;
16049
+
16050
+ var _nsMatrix,
15428
16051
  anonymousNsCount = 0,
15429
16052
  tagStart = false,
15430
16053
  tagEnd = false,
@@ -15441,6 +16064,36 @@
15441
16064
  cachedAttrs // false = parsed with errors, null = needs parsing
15442
16065
  ;
15443
16066
 
16067
+ /**
16068
+ * Normalize a namespaced attribute name against the current
16069
+ * namespace matrix.
16070
+ *
16071
+ * @param {string} name
16072
+ * @param {string|boolean} defaultAlias
16073
+ *
16074
+ * @return {string|null} normalized name, or `null` when the prefix
16075
+ * has no namespace (a warning is emitted)
16076
+ */
16077
+ function normalizeAttrName(name, defaultAlias) {
16078
+ var w = name.indexOf(':');
16079
+
16080
+ if (w === -1) {
16081
+ return name;
16082
+ }
16083
+
16084
+ // normalize ns attribute name
16085
+ var nsName = nsMatrix[name.substring(0, w)];
16086
+
16087
+ if (!nsName) {
16088
+ handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
16089
+ return null;
16090
+ }
16091
+
16092
+ return defaultAlias === nsName
16093
+ ? name.substr(w + 1)
16094
+ : nsName + name.substr(w);
16095
+ }
16096
+
15444
16097
  /**
15445
16098
  * Parse attributes on demand and returns the parsed attributes.
15446
16099
  *
@@ -15456,7 +16109,6 @@
15456
16109
 
15457
16110
  var nsUri,
15458
16111
  nsUriPrefix,
15459
- nsName,
15460
16112
  defaultAlias = isNamespace && nsMatrix['xmlns'],
15461
16113
  attrList = isNamespace && maybeNS ? [] : null,
15462
16114
  i = attrsStart,
@@ -15468,7 +16120,7 @@
15468
16120
  alias,
15469
16121
  name,
15470
16122
  attrs = {},
15471
- seenAttrs = {},
16123
+ seenAttrs = new Set(),
15472
16124
  skipAttr,
15473
16125
  w,
15474
16126
  j;
@@ -15608,12 +16260,12 @@
15608
16260
  }
15609
16261
 
15610
16262
  // check attribute re-declaration
15611
- if (name in seenAttrs) {
16263
+ if (seenAttrs.has(name)) {
15612
16264
  handleWarning('attribute <' + name + '> already defined');
15613
16265
  continue;
15614
16266
  }
15615
16267
 
15616
- seenAttrs[name] = true;
16268
+ seenAttrs.add(name);
15617
16269
 
15618
16270
  if (!isNamespace) {
15619
16271
  attrs[name] = value;
@@ -15685,24 +16337,12 @@
15685
16337
 
15686
16338
  // handle attributes on element without
15687
16339
  // namespace declarations
15688
- w = name.indexOf(':');
15689
- if (w === -1) {
15690
- attrs[name] = value;
15691
- continue;
15692
- }
16340
+ name = normalizeAttrName(name, defaultAlias);
15693
16341
 
15694
- // normalize ns attribute name
15695
- if (!(nsName = nsMatrix[name.substring(0, w)])) {
15696
- handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
16342
+ if (name === null) {
15697
16343
  continue;
15698
16344
  }
15699
16345
 
15700
- name = defaultAlias === nsName
15701
- ? name.substr(w + 1)
15702
- : nsName + name.substr(w);
15703
-
15704
- // end: normalize ns attribute name
15705
-
15706
16346
  attrs[name] = value;
15707
16347
  }
15708
16348
 
@@ -15713,24 +16353,11 @@
15713
16353
  // normalize captured attributes
15714
16354
  for (i = 0, l = attrList.length; i < l; i++) {
15715
16355
 
15716
- name = attrList[i++];
16356
+ name = normalizeAttrName(attrList[i++], defaultAlias);
15717
16357
  value = attrList[i];
15718
16358
 
15719
- w = name.indexOf(':');
15720
-
15721
- if (w !== -1) {
15722
-
15723
- // normalize ns attribute name
15724
- if (!(nsName = nsMatrix[name.substring(0, w)])) {
15725
- handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
15726
- continue;
15727
- }
15728
-
15729
- name = defaultAlias === nsName
15730
- ? name.substr(w + 1)
15731
- : nsName + name.substr(w);
15732
-
15733
- // end: normalize ns attribute name
16359
+ if (name === null) {
16360
+ continue;
15734
16361
  }
15735
16362
 
15736
16363
  attrs[name] = value;
@@ -15830,13 +16457,19 @@
15830
16457
  i = xml.indexOf('<', j);
15831
16458
  }
15832
16459
 
15833
- // parse end
16460
+ // no (more) tags found
15834
16461
  if (i === -1) {
16462
+
16463
+ // buffer the remainder for the next chunk
16464
+ if (streaming) {
16465
+ return xml.substring(j);
16466
+ }
16467
+
15835
16468
  if (nodeStack.length) {
15836
16469
  return handleError('unexpected end of file');
15837
16470
  }
15838
16471
 
15839
- if (j === 0) {
16472
+ if (!rootTagFound) {
15840
16473
  return handleError('missing start tag');
15841
16474
  }
15842
16475
 
@@ -15849,6 +16482,11 @@
15849
16482
  return;
15850
16483
  }
15851
16484
 
16485
+ // remember that we saw the root tag
16486
+ if (!rootTagFound) {
16487
+ rootTagFound = true;
16488
+ }
16489
+
15852
16490
  // parse text
15853
16491
  if (j !== i) {
15854
16492
 
@@ -15881,6 +16519,9 @@
15881
16519
  if (q === 91 && xml.substr(i + 3, 6) === 'CDATA[') { // 91 == "["
15882
16520
  j = xml.indexOf(']]>', i);
15883
16521
  if (j === -1) {
16522
+ if (streaming) {
16523
+ return xml.substring(i);
16524
+ }
15884
16525
  return handleError('unclosed cdata');
15885
16526
  }
15886
16527
 
@@ -15899,6 +16540,9 @@
15899
16540
  if (q === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-"
15900
16541
  j = xml.indexOf('-->', i);
15901
16542
  if (j === -1) {
16543
+ if (streaming) {
16544
+ return xml.substring(i);
16545
+ }
15902
16546
  return handleError('unclosed comment');
15903
16547
  }
15904
16548
 
@@ -15919,6 +16563,9 @@
15919
16563
  if (w === 63) { // "?"
15920
16564
  j = xml.indexOf('?>', i);
15921
16565
  if (j === -1) {
16566
+ if (streaming) {
16567
+ return xml.substring(i);
16568
+ }
15922
16569
  return handleError('unclosed question');
15923
16570
  }
15924
16571
 
@@ -15939,6 +16586,9 @@
15939
16586
  for (x = i + 1; ; x++) {
15940
16587
  v = xml.charCodeAt(x);
15941
16588
  if (isNaN(v)) {
16589
+ if (streaming) {
16590
+ return xml.substring(i);
16591
+ }
15942
16592
  j = -1;
15943
16593
  return handleError('unclosed tag');
15944
16594
  }
@@ -16078,30 +16728,49 @@
16078
16728
 
16079
16729
  _elementName = elementName;
16080
16730
 
16081
- w = elementName.indexOf(':');
16082
- if (w !== -1) {
16083
- xmlns = nsMatrix[elementName.substring(0, w)];
16084
-
16085
- // prefix given; namespace must exist
16086
- if (!xmlns) {
16087
- return handleError('missing namespace on <' + _elementName + '>');
16731
+ // memoize normalized names per namespace matrix; tag names
16732
+ // typically repeat heavily and the matrix rarely changes.
16733
+ if (elNameCacheMatrix !== nsMatrix) {
16734
+ elNameCache = nsMatrix[NAME_CACHE];
16735
+ if (elNameCache === undefined) {
16736
+ elNameCache = nsMatrix[NAME_CACHE] = Object.create(null);
16088
16737
  }
16738
+ elNameCacheMatrix = nsMatrix;
16739
+ }
16740
+
16741
+ var _cachedName = elNameCache[elementName];
16089
16742
 
16090
- elementName = elementName.substr(w + 1);
16743
+ if (_cachedName !== undefined) {
16744
+ elementName = _cachedName;
16091
16745
  } else {
16092
- xmlns = nsMatrix['xmlns'];
16093
-
16094
- // if no default namespace is defined,
16095
- // we'll import the element as anonymous.
16096
- //
16097
- // it is up to users to correct that to the document defined
16098
- // targetNamespace, or whatever their undersanding of the
16099
- // XML spec mandates.
16100
- }
16101
16746
 
16102
- // adjust namespace prefixs as configured
16103
- if (xmlns) {
16104
- elementName = xmlns + ':' + elementName;
16747
+ w = elementName.indexOf(':');
16748
+ if (w !== -1) {
16749
+ xmlns = nsMatrix[elementName.substring(0, w)];
16750
+
16751
+ // prefix given; namespace must exist
16752
+ if (!xmlns) {
16753
+ return handleError('missing namespace on <' + _elementName + '>');
16754
+ }
16755
+
16756
+ elementName = elementName.substr(w + 1);
16757
+ } else {
16758
+ xmlns = nsMatrix['xmlns'];
16759
+
16760
+ // if no default namespace is defined,
16761
+ // we'll import the element as anonymous.
16762
+ //
16763
+ // it is up to users to correct that to the document defined
16764
+ // targetNamespace, or whatever their undersanding of the
16765
+ // XML spec mandates.
16766
+ }
16767
+
16768
+ // adjust namespace prefixs as configured
16769
+ if (xmlns) {
16770
+ elementName = xmlns + ':' + elementName;
16771
+ }
16772
+
16773
+ elNameCache[_elementName] = elementName;
16105
16774
  }
16106
16775
 
16107
16776
  }
@@ -17125,10 +17794,48 @@
17125
17794
  return this.defaultPrefixMap[prefix];
17126
17795
  };
17127
17796
 
17797
+ /**
17798
+ * Return the first truthy `fn(scope)` walking this scope and its ancestors.
17799
+ *
17800
+ * @param {(scope: Namespaces) => any} fn
17801
+ *
17802
+ * @return {any}
17803
+ */
17804
+ Namespaces.prototype.resolve = function(fn) {
17805
+
17806
+ var scope = this;
17807
+
17808
+ while (scope) {
17809
+ var resolved = fn(scope);
17810
+
17811
+ if (resolved) {
17812
+ return resolved;
17813
+ }
17814
+
17815
+ scope = scope.parent;
17816
+ }
17817
+ };
17818
+
17819
+ /**
17820
+ * Call `fn(scope)` for this scope and each of its ancestors.
17821
+ *
17822
+ * @param {(scope: Namespaces) => void} fn
17823
+ */
17824
+ Namespaces.prototype.eachScope = function(fn) {
17825
+
17826
+ var scope = this;
17827
+
17828
+ while (scope) {
17829
+ fn(scope);
17830
+
17831
+ scope = scope.parent;
17832
+ }
17833
+ };
17834
+
17128
17835
  Namespaces.prototype.byUri = function(uri) {
17129
- return this.uriMap[uri] || (
17130
- this.parent && this.parent.byUri(uri)
17131
- );
17836
+ return this.resolve(function(scope) {
17837
+ return scope.uriMap[uri];
17838
+ });
17132
17839
  };
17133
17840
 
17134
17841
  Namespaces.prototype.add = function(ns, isWellknown) {
@@ -17145,9 +17852,11 @@
17145
17852
  };
17146
17853
 
17147
17854
  Namespaces.prototype.uriByPrefix = function(prefix) {
17148
- return this.prefixMap[prefix || 'xmlns'] || (
17149
- this.parent && this.parent.uriByPrefix(prefix)
17150
- );
17855
+ var key = prefix || 'xmlns';
17856
+
17857
+ return this.resolve(function(scope) {
17858
+ return scope.prefixMap[key];
17859
+ });
17151
17860
  };
17152
17861
 
17153
17862
  Namespaces.prototype.mapPrefix = function(prefix, uri) {
@@ -17163,12 +17872,9 @@
17163
17872
  var uri = ns.uri;
17164
17873
  var nsKey = this.getNSKey(ns);
17165
17874
 
17166
- this.used[nsKey] = this.byUri(uri);
17167
-
17168
- // Inform parent recursively about the usage of this NS
17169
- if (this.parent) {
17170
- this.parent.logUsed(ns);
17171
- }
17875
+ this.eachScope(function(scope) {
17876
+ scope.used[nsKey] = scope.byUri(uri);
17877
+ });
17172
17878
  };
17173
17879
 
17174
17880
  Namespaces.prototype.getUsed = function(ns) {
@@ -17385,20 +18091,32 @@
17385
18091
  }
17386
18092
 
17387
18093
  ElementSerializer.prototype.build = function(element) {
18094
+ buildTree(this, element);
18095
+
18096
+ return this;
18097
+ };
18098
+
18099
+ /**
18100
+ * Enter the element during the build walk: register its namespaces, tag
18101
+ * name and attributes, then return the deferred, ordered work to build its
18102
+ * child nodes (empty when it has none).
18103
+ *
18104
+ * @param {Object} element
18105
+ *
18106
+ * @return {Array<Object>} ordered, deferred work items to build the children
18107
+ */
18108
+ ElementSerializer.prototype.enter = function(element) {
17388
18109
  this.element = element;
17389
18110
 
17390
18111
  var elementDescriptor = element.$descriptor,
17391
18112
  propertyDescriptor = this.propertyDescriptor;
17392
18113
 
17393
- var otherAttrs,
17394
- properties;
17395
-
17396
18114
  var isGeneric = elementDescriptor.isGeneric;
17397
18115
 
17398
18116
  if (isGeneric) {
17399
- otherAttrs = this.parseGenericNsAttributes(element);
18117
+ this.otherAttrs = this.parseGenericNsAttributes(element);
17400
18118
  } else {
17401
- otherAttrs = this.parseNsAttributes(element);
18119
+ this.otherAttrs = this.parseNsAttributes(element);
17402
18120
  }
17403
18121
 
17404
18122
  if (propertyDescriptor) {
@@ -17407,21 +18125,26 @@
17407
18125
  this.ns = this.nsTagName(elementDescriptor);
17408
18126
  }
17409
18127
 
17410
- // compute tag name
17411
18128
  this.tagName = this.addTagName(this.ns);
17412
18129
 
17413
18130
  if (isGeneric) {
17414
- this.parseGenericContainments(element);
17415
- } else {
17416
- properties = getSerializableProperties(element);
17417
-
17418
- this.parseAttributes(filterAttributes(properties));
17419
- this.parseContainments(filterContained(properties));
18131
+ return this.collectGenericContainments(element);
17420
18132
  }
17421
18133
 
17422
- this.parseGenericAttributes(element, otherAttrs);
18134
+ var properties = getSerializableProperties(element);
17423
18135
 
17424
- return this;
18136
+ this.parseAttributes(filterAttributes(properties));
18137
+
18138
+ return this.collectContainments(filterContained(properties));
18139
+ };
18140
+
18141
+ /**
18142
+ * Exit the element during the build walk: register its generic attributes,
18143
+ * which must happen after the children so namespace usage is logged in
18144
+ * document order.
18145
+ */
18146
+ ElementSerializer.prototype.exit = function() {
18147
+ this.parseGenericAttributes(this.element, this.otherAttrs);
17425
18148
  };
17426
18149
 
17427
18150
  ElementSerializer.prototype.nsTagName = function(descriptor) {
@@ -17484,20 +18207,34 @@
17484
18207
  );
17485
18208
  };
17486
18209
 
17487
- ElementSerializer.prototype.parseGenericContainments = function(element) {
17488
- var body = element.$body;
18210
+ ElementSerializer.prototype.collectGenericContainments = function(element) {
18211
+ var self = this,
18212
+ children = [];
18213
+
18214
+ var bodyText = element.$body;
17489
18215
 
17490
- if (body) {
17491
- this.body.push(new BodySerializer().build({ type: 'String' }, body));
18216
+ if (bodyText) {
18217
+ children.push({
18218
+ create: function() {
18219
+ return new BodySerializer().build({ type: 'String' }, bodyText);
18220
+ }
18221
+ });
17492
18222
  }
17493
18223
 
17494
- var children = element.$children;
18224
+ var genericChildren = element.$children;
17495
18225
 
17496
- if (children) {
17497
- forEach(children, child => {
17498
- this.body.push(new ElementSerializer(this).build(child));
18226
+ if (genericChildren) {
18227
+ forEach(genericChildren, function(child) {
18228
+ children.push({
18229
+ create: function() {
18230
+ return new ElementSerializer(self);
18231
+ },
18232
+ element: child
18233
+ });
17499
18234
  });
17500
18235
  }
18236
+
18237
+ return children;
17501
18238
  };
17502
18239
 
17503
18240
  ElementSerializer.prototype.parseNsAttribute = function(element, name, value) {
@@ -17576,7 +18313,6 @@
17576
18313
  self.addAttribute(self.nsAttributeName(attr.name), attr.value);
17577
18314
  } catch (e) {
17578
18315
 
17579
- // eslint-disable-next-line no-undef
17580
18316
  typeof console !== 'undefined' && console.warn(
17581
18317
  `missing namespace information for <${
17582
18318
  attr.name
@@ -17586,11 +18322,11 @@
17586
18322
  });
17587
18323
  };
17588
18324
 
17589
- ElementSerializer.prototype.parseContainments = function(properties) {
18325
+ ElementSerializer.prototype.collectContainments = function(properties) {
17590
18326
 
17591
18327
  var self = this,
17592
- body = this.body,
17593
- element = this.element;
18328
+ element = this.element,
18329
+ children = [];
17594
18330
 
17595
18331
  forEach(properties, function(p) {
17596
18332
  var value = element.get(p.name),
@@ -17602,14 +18338,26 @@
17602
18338
  }
17603
18339
 
17604
18340
  if (p.isBody) {
17605
- body.push(new BodySerializer().build(p, value[0]));
18341
+ children.push({
18342
+ create: function() {
18343
+ return new BodySerializer().build(p, value[0]);
18344
+ }
18345
+ });
17606
18346
  } else if (isSimple(p.type)) {
17607
18347
  forEach(value, function(v) {
17608
- body.push(new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v));
18348
+ children.push({
18349
+ create: function() {
18350
+ return new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v);
18351
+ }
18352
+ });
17609
18353
  });
17610
18354
  } else if (isReference) {
17611
18355
  forEach(value, function(v) {
17612
- body.push(new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v));
18356
+ children.push({
18357
+ create: function() {
18358
+ return new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v);
18359
+ }
18360
+ });
17613
18361
  });
17614
18362
  } else {
17615
18363
 
@@ -17618,32 +18366,33 @@
17618
18366
  var serialization = getSerialization(p);
17619
18367
 
17620
18368
  forEach(value, function(v) {
17621
- var serializer;
18369
+ children.push({
18370
+ create: function() {
18371
+ if (serialization) {
18372
+ if (serialization === SERIALIZE_PROPERTY) {
18373
+ return new ElementSerializer(self, p);
18374
+ }
17622
18375
 
17623
- if (serialization) {
17624
- if (serialization === SERIALIZE_PROPERTY) {
17625
- serializer = new ElementSerializer(self, p);
17626
- } else {
17627
- serializer = new TypeSerializer(self, p, serialization);
17628
- }
17629
- } else {
17630
- serializer = new ElementSerializer(self);
17631
- }
18376
+ return new TypeSerializer(self, p, serialization);
18377
+ }
17632
18378
 
17633
- body.push(serializer.build(v));
18379
+ return new ElementSerializer(self);
18380
+ },
18381
+ element: v
18382
+ });
17634
18383
  });
17635
18384
  }
17636
18385
  });
18386
+
18387
+ return children;
17637
18388
  };
17638
18389
 
17639
18390
  ElementSerializer.prototype.getNamespaces = function(local) {
17640
18391
 
17641
- var namespaces = this.namespaces,
17642
- parent = this.parent,
17643
- parentNamespaces;
18392
+ var namespaces = this.namespaces;
17644
18393
 
17645
18394
  if (!namespaces) {
17646
- parentNamespaces = parent && parent.getNamespaces();
18395
+ var parentNamespaces = this.getParentNamespaces();
17647
18396
 
17648
18397
  if (local || !parentNamespaces) {
17649
18398
  this.namespaces = namespaces = new Namespaces(parentNamespaces);
@@ -17655,6 +18404,38 @@
17655
18404
  return namespaces;
17656
18405
  };
17657
18406
 
18407
+ /**
18408
+ * Resolve, and memoize, the namespaces scope owned by the closest
18409
+ * ancestor serializer.
18410
+ *
18411
+ * @return {Namespaces|null}
18412
+ */
18413
+ ElementSerializer.prototype.getParentNamespaces = function() {
18414
+
18415
+ if (this.parentNamespaces !== undefined) {
18416
+ return this.parentNamespaces;
18417
+ }
18418
+
18419
+ var scope = null,
18420
+ ancestor = this.parent;
18421
+
18422
+ while (ancestor) {
18423
+ if (ancestor.namespaces) {
18424
+ scope = ancestor.namespaces;
18425
+ break;
18426
+ }
18427
+
18428
+ if (ancestor.parentNamespaces !== undefined) {
18429
+ scope = ancestor.parentNamespaces;
18430
+ break;
18431
+ }
18432
+
18433
+ ancestor = ancestor.parent;
18434
+ }
18435
+
18436
+ return (this.parentNamespaces = scope);
18437
+ };
18438
+
17658
18439
  ElementSerializer.prototype.logNamespace = function(ns, wellknown, local) {
17659
18440
  var namespaces = this.getNamespaces(local);
17660
18441
 
@@ -17803,40 +18584,77 @@
17803
18584
  };
17804
18585
 
17805
18586
  ElementSerializer.prototype.serializeTo = function(writer) {
17806
- var firstBody = this.body[0],
17807
- indent = firstBody && firstBody.constructor !== BodySerializer;
18587
+ serializeTree(this, writer);
18588
+ };
17808
18589
 
17809
- writer
17810
- .appendIndent()
17811
- .append('<' + this.tagName);
18590
+ /**
18591
+ * Serialize the serializer tree rooted at the given element serializer to
18592
+ * the writer, using an explicit stack to stay flat for nested documents.
18593
+ *
18594
+ * @param {ElementSerializer} root
18595
+ * @param {Object} writer
18596
+ */
18597
+ function serializeTree(root, writer) {
17812
18598
 
17813
- this.serializeAttributes(writer);
18599
+ var stack = [ { serializer: root, index: 0, opened: false, indent: false } ];
17814
18600
 
17815
- writer.append(firstBody ? '>' : ' />');
18601
+ while (stack.length) {
18602
+ var frame = stack[stack.length - 1],
18603
+ serializer = frame.serializer;
17816
18604
 
17817
- if (firstBody) {
18605
+ if (!frame.opened) {
18606
+ var firstBody = serializer.body[0];
18607
+
18608
+ frame.indent = firstBody && firstBody.constructor !== BodySerializer;
17818
18609
 
17819
- if (indent) {
17820
18610
  writer
17821
- .appendNewLine()
17822
- .indent();
18611
+ .appendIndent()
18612
+ .append('<' + serializer.tagName);
18613
+
18614
+ serializer.serializeAttributes(writer);
18615
+
18616
+ writer.append(firstBody ? '>' : ' />');
18617
+
18618
+ frame.opened = true;
18619
+
18620
+ if (!firstBody) {
18621
+ writer.appendNewLine();
18622
+ stack.pop();
18623
+ continue;
18624
+ }
18625
+
18626
+ if (frame.indent) {
18627
+ writer
18628
+ .appendNewLine()
18629
+ .indent();
18630
+ }
17823
18631
  }
17824
18632
 
17825
- forEach(this.body, function(b) {
17826
- b.serializeTo(writer);
17827
- });
18633
+ if (frame.index < serializer.body.length) {
18634
+ var child = serializer.body[frame.index++];
17828
18635
 
17829
- if (indent) {
18636
+ if (child instanceof ElementSerializer) {
18637
+ stack.push({ serializer: child, index: 0, opened: false, indent: false });
18638
+ } else {
18639
+ child.serializeTo(writer);
18640
+ }
18641
+
18642
+ continue;
18643
+ }
18644
+
18645
+ if (frame.indent) {
17830
18646
  writer
17831
18647
  .unindent()
17832
18648
  .appendIndent();
17833
18649
  }
17834
18650
 
17835
- writer.append('</' + this.tagName + '>');
17836
- }
18651
+ writer
18652
+ .append('</' + serializer.tagName + '>')
18653
+ .appendNewLine();
17837
18654
 
17838
- writer.appendNewLine();
17839
- };
18655
+ stack.pop();
18656
+ }
18657
+ }
17840
18658
 
17841
18659
  /**
17842
18660
  * A serializer for types that handles serialization of data types
@@ -17968,6 +18786,51 @@
17968
18786
 
17969
18787
  // helpers ///////////
17970
18788
 
18789
+ /**
18790
+ * Build the serializer tree for the given root element, iterating an
18791
+ * explicit stack rather than recursing so deeply nested documents stay
18792
+ * flat.
18793
+ *
18794
+ * Elements are visited pre-order so namespaces register in document order:
18795
+ * `enter` opens an element and returns its children, `exit` runs once its
18796
+ * subtree is built.
18797
+ *
18798
+ * @param {ElementSerializer} rootSerializer
18799
+ * @param {Object} rootElement
18800
+ */
18801
+ function buildTree(rootSerializer, rootElement) {
18802
+
18803
+ var stack = [ {
18804
+ serializer: rootSerializer,
18805
+ children: rootSerializer.enter(rootElement),
18806
+ index: 0
18807
+ } ];
18808
+
18809
+ while (stack.length) {
18810
+ var frame = stack[stack.length - 1];
18811
+
18812
+ if (frame.index >= frame.children.length) {
18813
+ frame.serializer.exit();
18814
+ stack.pop();
18815
+ continue;
18816
+ }
18817
+
18818
+ var child = frame.children[frame.index++];
18819
+
18820
+ var childSerializer = child.create();
18821
+
18822
+ frame.serializer.body.push(childSerializer);
18823
+
18824
+ if (child.element) {
18825
+ stack.push({
18826
+ serializer: childSerializer,
18827
+ children: childSerializer.enter(child.element),
18828
+ index: 0
18829
+ });
18830
+ }
18831
+ }
18832
+ }
18833
+
17971
18834
  /**
17972
18835
  * @param {Moddle} model
17973
18836
  *