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-modeler v18.25.0
2
+ * bpmn-js - bpmn-modeler 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() :
@@ -8669,14 +8669,109 @@
8669
8669
  */
8670
8670
  function Base() { }
8671
8671
 
8672
+ /**
8673
+ * @template { keyof this } K
8674
+ *
8675
+ * Get property value (typed)
8676
+ *
8677
+ * @overload
8678
+ *
8679
+ * @param {K} name
8680
+ *
8681
+ * @return { this[K] }
8682
+ */
8683
+ /**
8684
+ * @template T
8685
+ *
8686
+ * Get property value
8687
+ *
8688
+ * @overload
8689
+ *
8690
+ * @param {string} name
8691
+ *
8692
+ * @return {T}
8693
+ */
8694
+ /**
8695
+ * Get property value
8696
+ *
8697
+ * @overload
8698
+ *
8699
+ * @param {string} name
8700
+ *
8701
+ * @return {unknown}
8702
+ */
8672
8703
  Base.prototype.get = function(name) {
8673
8704
  return this.$model.properties.get(this, name);
8674
8705
  };
8675
8706
 
8707
+ /**
8708
+ * @template { keyof this } K
8709
+ * @template { this[K] } V
8710
+ *
8711
+ * Set property value
8712
+ *
8713
+ * @overload
8714
+ *
8715
+ * @param {K} name
8716
+ * @param {V} value
8717
+ */
8718
+ /**
8719
+ * @template { string } S
8720
+ *
8721
+ * Set property value
8722
+ *
8723
+ * @overload
8724
+ *
8725
+ * @param { S extends keyof this ? never : S } name
8726
+ * @param { any } value
8727
+ */
8676
8728
  Base.prototype.set = function(name, value) {
8677
8729
  this.$model.properties.set(this, name, value);
8678
8730
  };
8679
8731
 
8732
+ /**
8733
+ * @typedef {import('./ns.js').Namespace} Namespace
8734
+ * @typedef {import('./moddle.js').default} Moddle
8735
+ * @typedef {import('./properties.js').default} Properties
8736
+ * @typedef {import('./registry.js').EffectiveDescriptor} EffectiveDescriptor
8737
+ * @typedef {import('./base.js').default} BaseElement
8738
+ * @typedef {import('./descriptor-builder.js').AnyTypeDescriptor} AnyTypeDescriptor
8739
+ */
8740
+
8741
+ /**
8742
+ * @template [T=Record<string,any>]
8743
+ * @typedef {{
8744
+ * new(attrs?: Partial<T>): ModdleElement<T>;
8745
+ * prototype: ModdleElement<T>;
8746
+ * readonly $model: Moddle;
8747
+ * readonly $descriptor: EffectiveDescriptor;
8748
+ * }} ModdleElementType
8749
+ */
8750
+
8751
+ /**
8752
+ * @template [T=Record<string,any>]
8753
+ * @typedef {BaseElement & T & {
8754
+ * readonly $model: Moddle;
8755
+ * readonly $descriptor: EffectiveDescriptor;
8756
+ * readonly $type: Namespace['name'];
8757
+ * readonly $attrs: Record<string, any>;
8758
+ * $parent?: ModdleElement | AnyModdleElement;
8759
+ * hasType: Moddle['hasType'];
8760
+ * $instanceOf: Moddle['hasType'];
8761
+ * }} ModdleElement
8762
+ */
8763
+
8764
+ /**
8765
+ * @template [T=Record<string,any>]
8766
+ * @typedef {BaseElement & T & {
8767
+ * $type: string;
8768
+ * $instanceOf: (type: string) => boolean;
8769
+ * $parent?: ModdleElement | AnyModdleElement;
8770
+ * readonly $model: Moddle;
8771
+ * readonly $descriptor: AnyTypeDescriptor;
8772
+ * }} AnyModdleElement
8773
+ */
8774
+
8680
8775
  /**
8681
8776
  * A model element factory.
8682
8777
  *
@@ -8684,11 +8779,23 @@
8684
8779
  * @param {Properties} properties
8685
8780
  */
8686
8781
  function Factory(model, properties) {
8782
+
8783
+ /**
8784
+ * @private
8785
+ */
8687
8786
  this.model = model;
8787
+
8788
+ /**
8789
+ * @private
8790
+ */
8688
8791
  this.properties = properties;
8689
8792
  }
8690
8793
 
8691
-
8794
+ /**
8795
+ * @template [T=Record<string,any>]
8796
+ * @param {EffectiveDescriptor} descriptor
8797
+ * @return {ModdleElementType<T>}
8798
+ */
8692
8799
  Factory.prototype.createType = function(descriptor) {
8693
8800
 
8694
8801
  var model = this.model;
@@ -8710,6 +8817,8 @@
8710
8817
 
8711
8818
  /**
8712
8819
  * The new type constructor
8820
+ *
8821
+ * @type { ModdleElementType }
8713
8822
  */
8714
8823
  function ModdleElement(attrs) {
8715
8824
  props.define(this, '$type', { value: name, enumerable: true });
@@ -8735,26 +8844,62 @@
8735
8844
  /**
8736
8845
  * Built-in moddle types
8737
8846
  */
8738
- var BUILTINS = {
8847
+ var BUILTINS = assign$1(Object.create(null), {
8739
8848
  String: true,
8740
8849
  Boolean: true,
8741
8850
  Integer: true,
8742
8851
  Real: true,
8743
8852
  Element: true
8744
- };
8853
+ });
8745
8854
 
8746
8855
  /**
8747
- * Converters for built in types from string representations
8856
+ * Converters for built-in types from string representations
8748
8857
  */
8749
- var TYPE_CONVERTERS = {
8858
+ var TYPE_CONVERTERS = assign$1(Object.create(null), {
8750
8859
  String: function(s) { return s; },
8751
8860
  Boolean: function(s) { return s === 'true'; },
8752
8861
  Integer: function(s) { return parseInt(s, 10); },
8753
8862
  Real: function(s) { return parseFloat(s); }
8754
- };
8863
+ });
8864
+
8865
+ /**
8866
+ * @typedef {'String'} StringType
8867
+ * @typedef {'Boolean'} BooleanType
8868
+ * @typedef {'Integer'} IntegerType
8869
+ * @typedef {'Real'} RealType
8870
+ * @typedef {'Element'} ElementType
8871
+ * @typedef {StringType | BooleanType | IntegerType | RealType} BuiltInSimpleType
8872
+ * @typedef {BuiltInSimpleType | ElementType} BuiltInType
8873
+ */
8755
8874
 
8875
+ /**
8876
+ * Convert given value to string
8877
+ * @overlord
8878
+ * @param {StringType} type
8879
+ * @param {any} value
8880
+ * @return {string}
8881
+ */
8882
+ /**
8883
+ * Convert given value to boolean
8884
+ * @overlord
8885
+ * @param {BooleanType} type
8886
+ * @param {any} value
8887
+ * @return {boolean}
8888
+ */
8889
+ /**
8890
+ * Convert given value to number
8891
+ * @overlord
8892
+ * @param {IntegerType | RealType} type
8893
+ * @param {any} value
8894
+ * @return {number}
8895
+ */
8756
8896
  /**
8757
8897
  * Convert a type to its real representation
8898
+ * @template T
8899
+ * @overlord
8900
+ * @param {Exclude<string,BuiltInSimpleType>} type
8901
+ * @param {T} value
8902
+ * @return {T}
8758
8903
  */
8759
8904
  function coerceType(type, value) {
8760
8905
 
@@ -8769,18 +8914,44 @@
8769
8914
 
8770
8915
  /**
8771
8916
  * Return whether the given type is built-in
8917
+ * @overload
8918
+ * @param {BuiltInType} type
8919
+ * @return {true}
8920
+ */
8921
+ /**
8922
+ * Return whether the given type is built-in
8923
+ * @overload
8924
+ * @param {Exclude<string,BuiltInType>} type
8925
+ * @return {false}
8772
8926
  */
8773
8927
  function isBuiltIn(type) {
8774
8928
  return !!BUILTINS[type];
8775
8929
  }
8776
8930
 
8777
8931
  /**
8778
- * Return whether the given type is simple
8932
+ * Return true if the given type is simple
8933
+ * @overload
8934
+ * @param {BuiltInSimpleType} type
8935
+ * @return {true}
8936
+ */
8937
+ /**
8938
+ * Return false the given type is not simple
8939
+ * @overload
8940
+ * @param {Exclude<string,BuiltInSimpleType>} type
8941
+ * @return {false}
8779
8942
  */
8780
8943
  function isSimple(type) {
8781
8944
  return !!TYPE_CONVERTERS[type];
8782
8945
  }
8783
8946
 
8947
+ /**
8948
+ * @typedef {{
8949
+ * name: string;
8950
+ * prefix: string;
8951
+ * localName: string;
8952
+ * }} Namespace
8953
+ */
8954
+
8784
8955
  /**
8785
8956
  * Parses a namespaced attribute name of the form (ns:)localName to an object,
8786
8957
  * given a default prefix to assume in case no explicit namespace is given.
@@ -8788,7 +8959,7 @@
8788
8959
  * @param {String} name
8789
8960
  * @param {String} [defaultPrefix] the default prefix to take, if none is present.
8790
8961
  *
8791
- * @return {Object} the parsed name
8962
+ * @return {Namespace} the parsed name
8792
8963
  */
8793
8964
  function parseName(name, defaultPrefix) {
8794
8965
  var parts = name.split(/:/),
@@ -8819,19 +8990,98 @@
8819
8990
  };
8820
8991
  }
8821
8992
 
8993
+ /**
8994
+ * @typedef {import('./ns.js').Namespace} Namespace
8995
+ * @typedef {import('./registry.js').RegisteredPackage} RegisteredPackage
8996
+ * @typedef {import('./registry.js').RegisteredTypeDef} RegisteredTypeDef
8997
+ * @typedef {import('./registry.js').RegisteredPropertyDef} RegisteredPropertyDef
8998
+ */
8999
+
9000
+ /**
9001
+ * Effective element descriptor
9002
+ * aka element type descriptor
9003
+ * aka element descriptor
9004
+ * @typedef {{
9005
+ * readonly ns: Namespace;
9006
+ * readonly name: Namespace['name'];
9007
+ * readonly allTypes: Array<RegisteredTypeDef>;
9008
+ * readonly allTypesByName: Record<string, RegisteredTypeDef>;
9009
+ * readonly properties: Array<PropertyDescriptor>;
9010
+ * readonly propertiesByName: Record<string, PropertyDescriptor>;
9011
+ * readonly bodyProperty?: PropertyDescriptor;
9012
+ * readonly idProperty?: PropertyDescriptor;
9013
+ * readonly $pkg?: RegisteredPackage;
9014
+ * }} EffectiveDescriptor
9015
+ */
9016
+
9017
+ /**
9018
+ * Property descriptor
9019
+ * @typedef {RegisteredPropertyDef & {
9020
+ * localName: Namespace['localName'];
9021
+ * inherited?: boolean;
9022
+ * definedBy?: RegisteredTypeDef;
9023
+ * }} PropertyDescriptor
9024
+ */
9025
+
9026
+ /**
9027
+ * @typedef {{
9028
+ * name: string;
9029
+ * isGeneric: true;
9030
+ * ns: {
9031
+ * prefix: string;
9032
+ * localName: string;
9033
+ * uri: string;
9034
+ * };
9035
+ * }} AnyTypeDescriptor
9036
+ */
9037
+
8822
9038
  /**
8823
9039
  * A utility to build element descriptors.
9040
+ * @class DescriptorBuilder
9041
+ * @param {Namespace} nameNs
8824
9042
  */
8825
9043
  function DescriptorBuilder(nameNs) {
9044
+
9045
+ /**
9046
+ * @private
9047
+ * @type {Namespace}
9048
+ */
8826
9049
  this.ns = nameNs;
9050
+
9051
+ /**
9052
+ * @private
9053
+ * @type {Namespace['name']}
9054
+ */
8827
9055
  this.name = nameNs.name;
9056
+
9057
+ /**
9058
+ * @private
9059
+ * @type {Array<RegisteredTypeDef>}
9060
+ */
8828
9061
  this.allTypes = [];
8829
- this.allTypesByName = {};
9062
+
9063
+ /**
9064
+ * @private
9065
+ * @type {Record<string, RegisteredTypeDef>}
9066
+ */
9067
+ this.allTypesByName = Object.create(null);
9068
+
9069
+ /**
9070
+ * @private
9071
+ * @type {Array<PropertyDescriptor>}
9072
+ */
8830
9073
  this.properties = [];
8831
- this.propertiesByName = {};
8832
- }
8833
9074
 
9075
+ /**
9076
+ * @private
9077
+ * @type {Record<string, PropertyDescriptor>}
9078
+ */
9079
+ this.propertiesByName = Object.create(null);
9080
+ }
8834
9081
 
9082
+ /**
9083
+ * @return {EffectiveDescriptor}
9084
+ */
8835
9085
  DescriptorBuilder.prototype.build = function() {
8836
9086
  return pick(this, [
8837
9087
  'ns',
@@ -8848,7 +9098,7 @@
8848
9098
  /**
8849
9099
  * Add property at given index.
8850
9100
  *
8851
- * @param {Object} p
9101
+ * @param {PropertyDescriptor} p
8852
9102
  * @param {Number} [idx]
8853
9103
  * @param {Boolean} [validate=true]
8854
9104
  */
@@ -8870,7 +9120,11 @@
8870
9120
  }
8871
9121
  };
8872
9122
 
8873
-
9123
+ /**
9124
+ * @param {PropertyDescriptor} oldProperty
9125
+ * @param {PropertyDescriptor} newProperty
9126
+ * @param {string} replace
9127
+ */
8874
9128
  DescriptorBuilder.prototype.replaceProperty = function(oldProperty, newProperty, replace) {
8875
9129
  var oldNameNs = oldProperty.ns;
8876
9130
 
@@ -8920,7 +9174,11 @@
8920
9174
  propertiesByName[oldNameNs.name] = propertiesByName[oldNameNs.localName] = newProperty;
8921
9175
  };
8922
9176
 
8923
-
9177
+ /**
9178
+ * @param {PropertyDescriptor} p
9179
+ * @param {string} targetPropertyName
9180
+ * @param {string} replace
9181
+ */
8924
9182
  DescriptorBuilder.prototype.redefineProperty = function(p, targetPropertyName, replace) {
8925
9183
 
8926
9184
  var nsPrefix = p.ns.prefix;
@@ -8939,6 +9197,10 @@
8939
9197
  delete p.redefines;
8940
9198
  };
8941
9199
 
9200
+ /**
9201
+ * @param {PropertyDescriptor} p
9202
+ * @param {boolean} validate
9203
+ */
8942
9204
  DescriptorBuilder.prototype.addNamedProperty = function(p, validate) {
8943
9205
  var ns = p.ns,
8944
9206
  propsByName = this.propertiesByName;
@@ -8951,6 +9213,9 @@
8951
9213
  propsByName[ns.name] = propsByName[ns.localName] = p;
8952
9214
  };
8953
9215
 
9216
+ /**
9217
+ * @param {RegisteredPropertyDef} p
9218
+ */
8954
9219
  DescriptorBuilder.prototype.removeNamedProperty = function(p) {
8955
9220
  var ns = p.ns,
8956
9221
  propsByName = this.propertiesByName;
@@ -8959,6 +9224,10 @@
8959
9224
  delete propsByName[ns.localName];
8960
9225
  };
8961
9226
 
9227
+ /**
9228
+ * @param {PropertyDescriptor} p
9229
+ * @param {boolean} [validate]
9230
+ */
8962
9231
  DescriptorBuilder.prototype.setBodyProperty = function(p, validate) {
8963
9232
 
8964
9233
  if (validate && this.bodyProperty) {
@@ -8970,6 +9239,10 @@
8970
9239
  this.bodyProperty = p;
8971
9240
  };
8972
9241
 
9242
+ /**
9243
+ * @param {PropertyDescriptor} p
9244
+ * @param {boolean} [validate]
9245
+ */
8973
9246
  DescriptorBuilder.prototype.setIdProperty = function(p, validate) {
8974
9247
 
8975
9248
  if (validate && this.idProperty) {
@@ -8981,6 +9254,9 @@
8981
9254
  this.idProperty = p;
8982
9255
  };
8983
9256
 
9257
+ /**
9258
+ * @param {RegisteredTypeDef} typeDescriptor
9259
+ */
8984
9260
  DescriptorBuilder.prototype.assertNotTrait = function(typeDescriptor) {
8985
9261
 
8986
9262
  const _extends = typeDescriptor.extends || [];
@@ -8992,6 +9268,9 @@
8992
9268
  }
8993
9269
  };
8994
9270
 
9271
+ /**
9272
+ * @param {PropertyDescriptor} p
9273
+ */
8995
9274
  DescriptorBuilder.prototype.assertNotDefined = function(p, name) {
8996
9275
  var propertyName = p.name,
8997
9276
  definedProperty = this.propertiesByName[propertyName];
@@ -9004,10 +9283,18 @@
9004
9283
  }
9005
9284
  };
9006
9285
 
9286
+ /**
9287
+ * @param {string} name
9288
+ * @return {PropertyDescriptor}
9289
+ */
9007
9290
  DescriptorBuilder.prototype.hasProperty = function(name) {
9008
9291
  return this.propertiesByName[name];
9009
9292
  };
9010
9293
 
9294
+ /**
9295
+ * @param {RegisteredTypeDef} t
9296
+ * @param {boolean} inherited
9297
+ */
9011
9298
  DescriptorBuilder.prototype.addTrait = function(t, inherited) {
9012
9299
 
9013
9300
  if (inherited) {
@@ -9056,33 +9343,94 @@
9056
9343
  typesByName[typeName] = t;
9057
9344
  };
9058
9345
 
9346
+ /**
9347
+ * @typedef {import('./ns.js').Namespace} Namespace
9348
+ * @typedef {import('./moddle.js').PackageDefinition} PackageDefinition
9349
+ * @typedef {import('./moddle.js').TypeDefinition} TypeDefinition
9350
+ * @typedef {import('./moddle.js').PropertyDefinition} PropertyDefinition
9351
+ * @typedef {import('./properties.js').default} Properties
9352
+ * @typedef {import('./descriptor-builder.js').EffectiveDescriptor} EffectiveDescriptor
9353
+ */
9354
+
9355
+ /**
9356
+ * Registered package definition
9357
+ * @typedef {Omit<PackageDefinition, 'types'> & {
9358
+ * types?: Array<RegisteredTypeDef>;
9359
+ * }} RegisteredPackage
9360
+ */
9361
+
9362
+ /**
9363
+ * Registered type definition
9364
+ * @typedef {Omit<TypeDefinition, 'properties'> & {
9365
+ * properties?: Array<RegisteredPropertyDef>;
9366
+ * propertiesByName?: Record<string, RegisteredPropertyDef>;
9367
+ * superClass?: Array<string>;
9368
+ * extends?: Array<string>;
9369
+ * meta?: Record<string, *>;
9370
+ * traits?: Array<string>;
9371
+ * ns?: Namespace;
9372
+ * readonly $pkg?: RegisteredPackage;
9373
+ * }} RegisteredTypeDef
9374
+ */
9375
+
9376
+ /**
9377
+ * Registered property definition
9378
+ * @typedef {PropertyDefinition & { ns: Namespace }} RegisteredPropertyDef
9379
+ */
9380
+
9059
9381
  /**
9060
9382
  * A registry of Moddle packages.
9061
9383
  *
9062
- * @param {Array<Package>} packages
9384
+ * @param {Array<PackageDefinition> | Record<string,PackageDefinition>} packages
9063
9385
  * @param {Properties} properties
9064
9386
  */
9065
9387
  function Registry(packages, properties) {
9066
- this.packageMap = {};
9067
- this.typeMap = {};
9068
9388
 
9389
+ /**
9390
+ * @private
9391
+ * @type {Record<string, RegisteredPackage>} registered packages map
9392
+ */
9393
+ this.packageMap = Object.create(null);
9394
+
9395
+ /**
9396
+ * @type {Record<string,RegisteredTypeDef>}
9397
+ */
9398
+ this.typeMap = Object.create(null);
9399
+
9400
+ /**
9401
+ * @private
9402
+ * @type {Array<RegisteredPackage>} all registered packages
9403
+ */
9069
9404
  this.packages = [];
9070
9405
 
9406
+ /**
9407
+ * @private
9408
+ * @type {Properties}
9409
+ */
9071
9410
  this.properties = properties;
9072
9411
 
9073
9412
  forEach(packages, bind$1(this.registerPackage, this));
9074
9413
  }
9075
9414
 
9076
-
9415
+ /**
9416
+ * @param {string} uriOrPrefix uri or prefix of package
9417
+ * @return {RegisteredPackage} registered package
9418
+ */
9077
9419
  Registry.prototype.getPackage = function(uriOrPrefix) {
9078
9420
  return this.packageMap[uriOrPrefix];
9079
9421
  };
9080
9422
 
9423
+ /**
9424
+ * @return {Array<RegisteredPackage>} all registered packages
9425
+ */
9081
9426
  Registry.prototype.getPackages = function() {
9082
9427
  return this.packages;
9083
9428
  };
9084
9429
 
9085
-
9430
+ /**
9431
+ * @private
9432
+ * @param {PackageDefinition} pkg registering package
9433
+ */
9086
9434
  Registry.prototype.registerPackage = function(pkg) {
9087
9435
 
9088
9436
  // copy package
@@ -9102,22 +9450,23 @@
9102
9450
  this.packages.push(pkg);
9103
9451
  };
9104
9452
 
9105
-
9106
9453
  /**
9454
+ * @private
9107
9455
  * Register a type from a specific package with us
9456
+ * @param {TypeDefinition} type
9457
+ * @param {RegisteredPackage} pkg
9108
9458
  */
9109
9459
  Registry.prototype.registerType = function(type, pkg) {
9110
-
9111
9460
  type = assign$1({}, type, {
9112
9461
  superClass: (type.superClass || []).slice(),
9113
9462
  extends: (type.extends || []).slice(),
9114
9463
  properties: (type.properties || []).slice(),
9115
- meta: assign$1((type.meta || {}))
9464
+ meta: assign$1({}, type.meta || {})
9116
9465
  });
9117
9466
 
9118
9467
  var ns = parseName(type.name, pkg.prefix),
9119
9468
  name = ns.name,
9120
- propertiesByName = {};
9469
+ /** @type {Record<string, RegisteredPropertyDef>} */ propertiesByName = Object.create(null);
9121
9470
 
9122
9471
  // parse properties
9123
9472
  forEach(type.properties, bind$1(function(p) {
@@ -9162,18 +9511,24 @@
9162
9511
  this.typeMap[name] = type;
9163
9512
  };
9164
9513
 
9514
+ /**
9515
+ * @callback IteratorFn
9516
+ * @param {RegisteredTypeDef} type
9517
+ * @param {boolean} inherited
9518
+ */
9165
9519
 
9166
9520
  /**
9167
9521
  * Traverse the type hierarchy from bottom to top,
9168
9522
  * calling iterator with (type, inherited) for all elements in
9169
9523
  * the inheritance chain.
9170
- *
9171
- * @param {Object} nsName
9172
- * @param {Function} iterator
9524
+ * @private
9525
+ * @param {Namespace} nsName
9526
+ * @param {IteratorFn} iterator
9173
9527
  * @param {Boolean} [trait=false]
9174
9528
  */
9175
9529
  Registry.prototype.mapTypes = function(nsName, iterator, trait) {
9176
9530
 
9531
+ /** @type {RegisteredTypeDef} */
9177
9532
  var type = isBuiltIn(nsName.name) ? { name: nsName.name } : this.typeMap[nsName.name];
9178
9533
 
9179
9534
  var self = this;
@@ -9219,13 +9574,10 @@
9219
9574
  forEach(type.traits, traverseTrait);
9220
9575
  };
9221
9576
 
9222
-
9223
9577
  /**
9224
9578
  * Returns the effective descriptor for a type.
9225
- *
9226
- * @param {String} type the namespaced name (ns:localName) of the type
9227
- *
9228
- * @return {Descriptor} the resulting effective descriptor
9579
+ * @param {Namespace['name']} name the namespaced name (ns:localName) of the type
9580
+ * @return {EffectiveDescriptor} the resulting effective descriptor
9229
9581
  */
9230
9582
  Registry.prototype.getEffectiveDescriptor = function(name) {
9231
9583
 
@@ -9245,15 +9597,23 @@
9245
9597
  return descriptor;
9246
9598
  };
9247
9599
 
9248
-
9600
+ /**
9601
+ * @private
9602
+ * @param {RegisteredTypeDef | EffectiveDescriptor} target
9603
+ * @param {RegisteredPackage} pkg
9604
+ */
9249
9605
  Registry.prototype.definePackage = function(target, pkg) {
9250
9606
  this.properties.define(target, '$pkg', { value: pkg });
9251
9607
  };
9252
9608
 
9253
-
9254
-
9255
9609
  // helpers ////////////////////////////
9256
9610
 
9611
+ /**
9612
+ * Checking already defined packages
9613
+ * @param {Record<string, RegisteredPackage>} packageMap
9614
+ * @param {PackageDefinition} pkg
9615
+ * @param {'prefix' | 'uri'} identifierKey
9616
+ */
9257
9617
  function ensureAvailable(packageMap, pkg, identifierKey) {
9258
9618
 
9259
9619
  var value = pkg[identifierKey];
@@ -9263,21 +9623,30 @@
9263
9623
  }
9264
9624
  }
9265
9625
 
9626
+ /**
9627
+ * @typedef {import('./moddle.js').default} Moddle
9628
+ * @typedef {import('./descriptor-builder.js').PropertyDescriptor} PropertyDesc
9629
+ * @typedef {import('./registry.js').EffectiveDescriptor} EffectiveDescriptor
9630
+ * @typedef {import('./factory.js').ModdleElement} ModdleElement
9631
+ * @typedef {import('./descriptor-builder.js').AnyTypeDescriptor} AnyTypeDescriptor
9632
+ */
9633
+
9266
9634
  /**
9267
9635
  * A utility that gets and sets properties of model elements.
9268
9636
  *
9269
- * @param {Model} model
9637
+ * @param {Moddle} model
9270
9638
  */
9271
9639
  function Properties(model) {
9640
+
9641
+ /** @type {Moddle} */
9272
9642
  this.model = model;
9273
9643
  }
9274
9644
 
9275
-
9276
9645
  /**
9277
9646
  * Sets a named property on the target element.
9278
9647
  * If the value is undefined, the property gets deleted.
9279
9648
  *
9280
- * @param {Object} target
9649
+ * @param {ModdleElement} target
9281
9650
  * @param {String} name
9282
9651
  * @param {Object} value
9283
9652
  */
@@ -9319,7 +9688,7 @@
9319
9688
  /**
9320
9689
  * Returns the named property of the given element
9321
9690
  *
9322
- * @param {Object} target
9691
+ * @param {ModdleElement} target
9323
9692
  * @param {String} name
9324
9693
  *
9325
9694
  * @return {Object}
@@ -9342,13 +9711,12 @@
9342
9711
  return target[propertyName];
9343
9712
  };
9344
9713
 
9345
-
9346
9714
  /**
9347
9715
  * Define a property on the target element
9348
- *
9349
- * @param {Object} target
9716
+ * @template [T=any]
9717
+ * @param {NonNullable<T>} target
9350
9718
  * @param {String} name
9351
- * @param {Object} options
9719
+ * @param {PropertyDescriptor} options
9352
9720
  */
9353
9721
  Properties.prototype.define = function(target, name, options) {
9354
9722
 
@@ -9368,9 +9736,11 @@
9368
9736
  Object.defineProperty(target, name, options);
9369
9737
  };
9370
9738
 
9371
-
9372
9739
  /**
9373
9740
  * Define the descriptor for an element
9741
+ * @template [T=any]
9742
+ * @param {NonNullable<T>} target
9743
+ * @param {EffectiveDescriptor | AnyTypeDescriptor} descriptor
9374
9744
  */
9375
9745
  Properties.prototype.defineDescriptor = function(target, descriptor) {
9376
9746
  this.define(target, '$descriptor', { value: descriptor });
@@ -9378,6 +9748,9 @@
9378
9748
 
9379
9749
  /**
9380
9750
  * Define the model for an element
9751
+ * @template [T=any]
9752
+ * @param {NonNullable<T>} target
9753
+ * @param {Moddle} model
9381
9754
  */
9382
9755
  Properties.prototype.defineModel = function(target, model) {
9383
9756
  this.define(target, '$model', { value: model });
@@ -9386,10 +9759,10 @@
9386
9759
  /**
9387
9760
  * Return property with the given name on the element.
9388
9761
  *
9389
- * @param {any} target
9762
+ * @param {ModdleElement} target
9390
9763
  * @param {string} name
9391
9764
  *
9392
- * @return {object | null} property
9765
+ * @return {PropertyDesc | null} property
9393
9766
  */
9394
9767
  Properties.prototype.getProperty = function(target, name) {
9395
9768
 
@@ -9438,6 +9811,83 @@
9438
9811
  return name.replace(/^:/, '');
9439
9812
  }
9440
9813
 
9814
+ /**
9815
+ * @typedef {import('./registry.js').RegisteredTypeDef} RegisteredTypeDef
9816
+ * @typedef {import('./registry.js').RegisteredPackage} RegisteredPackage
9817
+ * @typedef {import('./base.js').default} BaseElement
9818
+ * @typedef {import('./descriptor-builder.js').EffectiveDescriptor} EffectiveDescriptor
9819
+ * @typedef {import('./descriptor-builder.js').AnyTypeDescriptor} AnyTypeDescriptor
9820
+ * @typedef {import('./descriptor-builder.js').PropertyDescriptor} PropertyDescriptor
9821
+ */
9822
+
9823
+ /**
9824
+ * @template [T=Record<string,any>]
9825
+ * @typedef {import('./factory.js').ModdleElement<T>} ModdleElement
9826
+ * @typedef {import('./factory.js').ModdleElementType<T>} ModdleElementType
9827
+ * @typedef {import('./factory.js').AnyModdleElement<T>} AnyModdleElement
9828
+ */
9829
+
9830
+ /**
9831
+ * Package definition
9832
+ * @typedef {{
9833
+ * $schema?: string;
9834
+ * name: string;
9835
+ * prefix: string;
9836
+ * types?: Array<TypeDefinition>;
9837
+ * [key: string]: any;
9838
+ * } & PackageDefinitionXmlExtension} PackageDefinition
9839
+ */
9840
+
9841
+ /**
9842
+ * Set of extended parameters for package definition used in moddle-xml.
9843
+ * @typedef {{
9844
+ * uri?: string;
9845
+ * xml?: {
9846
+ * tagAlias?: 'lowerCase';
9847
+ * typePrefix?: string;
9848
+ * };
9849
+ * }} PackageDefinitionXmlExtension
9850
+ */
9851
+
9852
+ /**
9853
+ * Type definition in declaration in package
9854
+ * @typedef {{
9855
+ * name: string;
9856
+ * isAbstract?: boolean;
9857
+ * properties?: Array<PropertyDefinition>;
9858
+ * superClass?: Array<string>;
9859
+ * extends?: Array<string>;
9860
+ * meta?: Record<string, *>;
9861
+ * [key: string]: any;
9862
+ * }} TypeDefinition
9863
+ */
9864
+
9865
+ /**
9866
+ * Set of extended parameters for property definition used in moddle-xml.
9867
+ * @typedef {{
9868
+ * isBody?: boolean;
9869
+ * isAttr?: boolean;
9870
+ * xml?: {
9871
+ * serialize?: string;
9872
+ * };
9873
+ * }} PropertyDefinitionXmlExtension
9874
+ */
9875
+
9876
+ /**
9877
+ * Property definition of type definition
9878
+ * @typedef {{
9879
+ * name: string;
9880
+ * type: 'String' | 'Boolean' | 'Integer' | 'Real' | string;
9881
+ * default?: string | boolean | number;
9882
+ * isMany?: boolean;
9883
+ * isReference?: boolean;
9884
+ * isId?: boolean;
9885
+ * redefines?: string;
9886
+ * replaces?: string;
9887
+ * [key: string]: any;
9888
+ * } & PropertyDefinitionXmlExtension} PropertyDefinition
9889
+ */
9890
+
9441
9891
  // Moddle implementation /////////////////////////////////////////////////
9442
9892
 
9443
9893
  /**
@@ -9447,7 +9897,7 @@
9447
9897
  *
9448
9898
  * @example
9449
9899
  *
9450
- * var Moddle = require('moddle');
9900
+ * import Moddle from 'moddle';
9451
9901
  *
9452
9902
  * var pkg = {
9453
9903
  * name: 'mypackage',
@@ -9459,23 +9909,31 @@
9459
9909
  *
9460
9910
  * var moddle = new Moddle([pkg]);
9461
9911
  *
9462
- * @param {Array<Package>} packages the packages to contain
9463
- *
9464
- * @param { { strict?: boolean } } [config] moddle configuration
9912
+ * @param {Array<PackageDefinition> | Record<string,PackageDefinition>} packages the packages to contain
9913
+ * @param {{ strict?: boolean }} [config={}] moddle configuration
9465
9914
  */
9466
9915
  function Moddle(packages, config = {}) {
9467
9916
 
9917
+ /** @type Readonly<Properties> */
9468
9918
  this.properties = new Properties(this);
9469
9919
 
9920
+ /** @type Readonly<Factory> */
9470
9921
  this.factory = new Factory(this, this.properties);
9922
+
9923
+ /** @type Readonly<Registry> */
9471
9924
  this.registry = new Registry(packages, this.properties);
9472
9925
 
9473
- this.typeCache = {};
9926
+ /**
9927
+ * @type {Record<string,ModdleElementType>}
9928
+ */
9929
+ this.typeCache = Object.create(null);
9474
9930
 
9931
+ /**
9932
+ * @type {Readonly<{readonly strict?: boolean}>}
9933
+ */
9475
9934
  this.config = config;
9476
9935
  }
9477
9936
 
9478
-
9479
9937
  /**
9480
9938
  * Create an instance of the specified type.
9481
9939
  *
@@ -9486,9 +9944,10 @@
9486
9944
  * var foo = moddle.create('my:Foo');
9487
9945
  * var bar = moddle.create('my:Bar', { id: 'BAR_1' });
9488
9946
  *
9489
- * @param {String|Object} descriptor the type descriptor or name know to the model
9490
- * @param {Object} attrs a number of attributes to initialize the model instance with
9491
- * @return {Object} model instance
9947
+ * @template [T=Record<string,any>]
9948
+ * @param {String|EffectiveDescriptor} descriptor the type descriptor or name know to the model
9949
+ * @param {Partial<T>} [attrs] a number of attributes to initialize the model instance with
9950
+ * @return {ModdleElement<T>} model instance
9492
9951
  */
9493
9952
  Moddle.prototype.create = function(descriptor, attrs) {
9494
9953
  var Type = this.getType(descriptor);
@@ -9500,7 +9959,6 @@
9500
9959
  return new Type(attrs);
9501
9960
  };
9502
9961
 
9503
-
9504
9962
  /**
9505
9963
  * Returns the type representing a given descriptor
9506
9964
  *
@@ -9511,8 +9969,9 @@
9511
9969
  * var Foo = moddle.getType('my:Foo');
9512
9970
  * var foo = new Foo({ 'id' : 'FOO_1' });
9513
9971
  *
9514
- * @param {String|Object} descriptor the type descriptor or name know to the model
9515
- * @return {Object} the type representing the descriptor
9972
+ * @template [T=Record<string,any>]
9973
+ * @param {String|EffectiveDescriptor} descriptor the type descriptor or name know to the model
9974
+ * @return {ModdleElementType<T>} the type representing the descriptor
9516
9975
  */
9517
9976
  Moddle.prototype.getType = function(descriptor) {
9518
9977
 
@@ -9530,7 +9989,6 @@
9530
9989
  return type;
9531
9990
  };
9532
9991
 
9533
-
9534
9992
  /**
9535
9993
  * Creates an any-element type to be used within model instances.
9536
9994
  *
@@ -9552,16 +10010,17 @@
9552
10010
  *
9553
10011
  * // go ahead and serialize the stuff
9554
10012
  *
9555
- *
10013
+ * @template [T=Record<string, any>]
9556
10014
  * @param {String} name the name of the element
9557
10015
  * @param {String} nsUri the namespace uri of the element
9558
- * @param {Object} [properties] a map of properties to initialize the instance with
9559
- * @return {Object} the any type instance
10016
+ * @param {T} [properties] a map of properties to initialize the instance with
10017
+ * @return {AnyModdleElement<T>} the any type instance
9560
10018
  */
9561
10019
  Moddle.prototype.createAny = function(name, nsUri, properties) {
9562
10020
 
9563
10021
  var nameNs = parseName(name);
9564
10022
 
10023
+ /** @type AnyModdleElement */
9565
10024
  var element = {
9566
10025
  $type: name,
9567
10026
  $instanceOf: function(type) {
@@ -9575,6 +10034,7 @@
9575
10034
  }
9576
10035
  };
9577
10036
 
10037
+ /** @type AnyTypeDescriptor */
9578
10038
  var descriptor = {
9579
10039
  name: name,
9580
10040
  isGeneric: true,
@@ -9605,8 +10065,8 @@
9605
10065
 
9606
10066
  /**
9607
10067
  * Returns a registered package by uri or prefix
9608
- *
9609
- * @return {Object} the package
10068
+ * @param {string} uriOrPrefix
10069
+ * @return {RegisteredPackage} the package
9610
10070
  */
9611
10071
  Moddle.prototype.getPackage = function(uriOrPrefix) {
9612
10072
  return this.registry.getPackage(uriOrPrefix);
@@ -9615,7 +10075,7 @@
9615
10075
  /**
9616
10076
  * Returns a snapshot of all known packages
9617
10077
  *
9618
- * @return {Object} the package
10078
+ * @return {Readonly<Array<RegisteredPackage>>} the package
9619
10079
  */
9620
10080
  Moddle.prototype.getPackages = function() {
9621
10081
  return this.registry.getPackages();
@@ -9623,16 +10083,25 @@
9623
10083
 
9624
10084
  /**
9625
10085
  * Returns the descriptor for an element
10086
+ * @param {ModdleElement | ModdleElementType} element
10087
+ * @return {EffectiveDescriptor}
9626
10088
  */
9627
10089
  Moddle.prototype.getElementDescriptor = function(element) {
9628
10090
  return element.$descriptor;
9629
10091
  };
9630
10092
 
9631
10093
  /**
10094
+ * @overload
9632
10095
  * Returns true if the given descriptor or instance
9633
10096
  * represents the given type.
9634
- *
9635
- * May be applied to this, if element is omitted.
10097
+ * @param {ModdleElement | ModdleElementType} element
10098
+ * @param {string} type
10099
+ * @return {boolean}
10100
+ */
10101
+ /**
10102
+ * @overload
10103
+ * @param {string} type
10104
+ * @return {boolean}
9636
10105
  */
9637
10106
  Moddle.prototype.hasType = function(element, type) {
9638
10107
  if (type === undefined) {
@@ -9647,13 +10116,18 @@
9647
10116
 
9648
10117
  /**
9649
10118
  * Returns the descriptor of an elements named property
10119
+ * @param {ModdleElement | ModdleElementType} element
10120
+ * @param {string} property
10121
+ * @return {PropertyDescriptor}
9650
10122
  */
9651
10123
  Moddle.prototype.getPropertyDescriptor = function(element, property) {
9652
10124
  return this.getElementDescriptor(element).propertiesByName[property];
9653
10125
  };
9654
10126
 
9655
10127
  /**
9656
- * Returns a mapped type's descriptor
10128
+ * Return registered type definition
10129
+ * @param {string} type
10130
+ * @return {RegisteredTypeDef}
9657
10131
  */
9658
10132
  Moddle.prototype.getTypeDescriptor = function(type) {
9659
10133
  return this.registry.typeMap[type];
@@ -9737,19 +10211,24 @@
9737
10211
  }
9738
10212
 
9739
10213
  function cloneNsMatrix(nsMatrix) {
9740
- var clone = {}, key;
10214
+ var clone = Object.create(null), key;
9741
10215
  for (key in nsMatrix) {
9742
10216
  clone[key] = nsMatrix[key];
9743
10217
  }
9744
10218
  return clone;
9745
10219
  }
9746
10220
 
10221
+ // per-matrix element name cache; stored under a symbol so it is
10222
+ // invisible to the `for (key in nsMatrix)` clone above and gets
10223
+ // collected together with the matrix it belongs to
10224
+ var NAME_CACHE = Symbol('nameCache');
10225
+
9747
10226
  function uriPrefix(prefix) {
9748
10227
  return prefix + '$uri';
9749
10228
  }
9750
10229
 
9751
10230
  function buildNsMatrix(nsUriToPrefix) {
9752
- var nsMatrix = {},
10231
+ var nsMatrix = Object.create(null),
9753
10232
  uri,
9754
10233
  prefix;
9755
10234
 
@@ -9797,6 +10276,33 @@
9797
10276
 
9798
10277
  var getContext = noopGetContext;
9799
10278
 
10279
+ /**
10280
+ * Are we currently consuming a chunked stream of XML,
10281
+ * i.e. is a `write` call in progress that may be followed
10282
+ * by more chunks?
10283
+ *
10284
+ * @type {boolean}
10285
+ */
10286
+ var streaming = false;
10287
+
10288
+ /**
10289
+ * Did we already encounter the root tag?
10290
+ *
10291
+ * Persisted across `write` calls so we can detect a missing
10292
+ * start tag once the stream ends.
10293
+ *
10294
+ * @type {boolean}
10295
+ */
10296
+ var rootTagFound = false;
10297
+
10298
+ /**
10299
+ * Not yet parsed remainder of the previously written chunk,
10300
+ * i.e. an incomplete token that awaits more input.
10301
+ *
10302
+ * @type {string}
10303
+ */
10304
+ var leftoverXml = '';
10305
+
9800
10306
  /**
9801
10307
  * Do we need to parse the current elements attributes for namespaces?
9802
10308
  *
@@ -9825,6 +10331,13 @@
9825
10331
  */
9826
10332
  var parseStop = false;
9827
10333
 
10334
+ /**
10335
+ * Namespace + node state shared across (streamed) parse runs.
10336
+ */
10337
+ var nsMatrixStack,
10338
+ nsMatrix,
10339
+ nodeStack;
10340
+
9828
10341
  /**
9829
10342
  * A map of { uri: prefix } used by the parser.
9830
10343
  *
@@ -9923,7 +10436,7 @@
9923
10436
  throw error$2('required args <nsMap={}>');
9924
10437
  }
9925
10438
 
9926
- var _nsUriToPrefix = {}, k;
10439
+ var _nsUriToPrefix = Object.create(null), k;
9927
10440
 
9928
10441
  for (k in nsMap) {
9929
10442
  _nsUriToPrefix[k] = nsMap[k];
@@ -9936,7 +10449,22 @@
9936
10449
  };
9937
10450
 
9938
10451
  /**
9939
- * Parse xml string.
10452
+ * Reset the parser state before a (streamed) parse run.
10453
+ */
10454
+ function resetState() {
10455
+ nsMatrixStack = isNamespace ? [] : null;
10456
+ nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null;
10457
+ nodeStack = [];
10458
+
10459
+ getContext = noopGetContext;
10460
+ parseStop = false;
10461
+ returnError = null;
10462
+ rootTagFound = false;
10463
+ leftoverXml = '';
10464
+ }
10465
+
10466
+ /**
10467
+ * Parse a complete xml string.
9940
10468
  *
9941
10469
  * @param {string} xml
9942
10470
  *
@@ -9947,7 +10475,11 @@
9947
10475
  throw error$2('required args <xml=string>');
9948
10476
  }
9949
10477
 
9950
- returnError = null;
10478
+ if (streaming) {
10479
+ throw error$2('parse during stream; call end() first');
10480
+ }
10481
+
10482
+ resetState();
9951
10483
 
9952
10484
  parse(xml);
9953
10485
 
@@ -9957,6 +10489,60 @@
9957
10489
  return returnError;
9958
10490
  };
9959
10491
 
10492
+ /**
10493
+ * Write the next chunk of a streamed xml string.
10494
+ *
10495
+ * Parse events are emitted for all complete tokens; an
10496
+ * incomplete trailing token is buffered until the next
10497
+ * `write` or, ultimately, reported as an error on `end`.
10498
+ *
10499
+ * @param {string} xml
10500
+ *
10501
+ * @return {Parser} self
10502
+ */
10503
+ this['write'] = function(xml) {
10504
+ if (typeof xml !== 'string') {
10505
+ throw error$2('required args <xml=string>');
10506
+ }
10507
+
10508
+ if (!streaming) {
10509
+ resetState();
10510
+ streaming = true;
10511
+ }
10512
+
10513
+ if (!returnError) {
10514
+ leftoverXml = parse(leftoverXml + xml, true) || '';
10515
+ }
10516
+
10517
+ return this;
10518
+ };
10519
+
10520
+ /**
10521
+ * Finish parsing a streamed xml string, i.e. signal that
10522
+ * no more chunks will be written.
10523
+ *
10524
+ * @return {Error} returnError, if not thrown
10525
+ */
10526
+ this['end'] = function() {
10527
+ if (!streaming) {
10528
+ resetState();
10529
+ }
10530
+
10531
+ // flush the buffered remainder, now treating an incomplete
10532
+ // trailing token as a hard error
10533
+ streaming = false;
10534
+
10535
+ if (!returnError) {
10536
+ parse(leftoverXml);
10537
+ }
10538
+
10539
+ leftoverXml = '';
10540
+ getContext = noopGetContext;
10541
+ parseStop = false;
10542
+
10543
+ return returnError;
10544
+ };
10545
+
9960
10546
  /**
9961
10547
  * Stop parsing.
9962
10548
  */
@@ -9967,13 +10553,26 @@
9967
10553
  /**
9968
10554
  * Parse string, invoking configured listeners on element.
9969
10555
  *
9970
- * @param {string} xml
10556
+ * Namespace and node stack state is shared across (streamed)
10557
+ * invocations via the enclosing parser scope.
10558
+ *
10559
+ * Internal note: while `streaming`, an incomplete trailing token
10560
+ * is not treated as an error but returned so `write` can buffer it
10561
+ * and prepend it to the next chunk. This buffered remainder is an
10562
+ * implementation detail of the streaming buffer, not a public API;
10563
+ * outside of that case the return value is `undefined`.
10564
+ *
10565
+ * @param {string} xml
10566
+ * @param {boolean} streaming
10567
+ *
10568
+ * @return {string|undefined} buffered remainder, streaming internal use only
9971
10569
  */
9972
- function parse(xml) {
9973
- var nsMatrixStack = isNamespace ? [] : null,
9974
- nsMatrix = isNamespace ? buildNsMatrix(nsUriToPrefix) : null,
9975
- _nsMatrix,
9976
- nodeStack = [],
10570
+ function parse(xml, streaming = false) {
10571
+
10572
+ var elNameCache = null,
10573
+ elNameCacheMatrix = null;
10574
+
10575
+ var _nsMatrix,
9977
10576
  anonymousNsCount = 0,
9978
10577
  tagStart = false,
9979
10578
  tagEnd = false,
@@ -9990,6 +10589,36 @@
9990
10589
  cachedAttrs // false = parsed with errors, null = needs parsing
9991
10590
  ;
9992
10591
 
10592
+ /**
10593
+ * Normalize a namespaced attribute name against the current
10594
+ * namespace matrix.
10595
+ *
10596
+ * @param {string} name
10597
+ * @param {string|boolean} defaultAlias
10598
+ *
10599
+ * @return {string|null} normalized name, or `null` when the prefix
10600
+ * has no namespace (a warning is emitted)
10601
+ */
10602
+ function normalizeAttrName(name, defaultAlias) {
10603
+ var w = name.indexOf(':');
10604
+
10605
+ if (w === -1) {
10606
+ return name;
10607
+ }
10608
+
10609
+ // normalize ns attribute name
10610
+ var nsName = nsMatrix[name.substring(0, w)];
10611
+
10612
+ if (!nsName) {
10613
+ handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
10614
+ return null;
10615
+ }
10616
+
10617
+ return defaultAlias === nsName
10618
+ ? name.substr(w + 1)
10619
+ : nsName + name.substr(w);
10620
+ }
10621
+
9993
10622
  /**
9994
10623
  * Parse attributes on demand and returns the parsed attributes.
9995
10624
  *
@@ -10005,7 +10634,6 @@
10005
10634
 
10006
10635
  var nsUri,
10007
10636
  nsUriPrefix,
10008
- nsName,
10009
10637
  defaultAlias = isNamespace && nsMatrix['xmlns'],
10010
10638
  attrList = isNamespace && maybeNS ? [] : null,
10011
10639
  i = attrsStart,
@@ -10017,7 +10645,7 @@
10017
10645
  alias,
10018
10646
  name,
10019
10647
  attrs = {},
10020
- seenAttrs = {},
10648
+ seenAttrs = new Set(),
10021
10649
  skipAttr,
10022
10650
  w,
10023
10651
  j;
@@ -10157,12 +10785,12 @@
10157
10785
  }
10158
10786
 
10159
10787
  // check attribute re-declaration
10160
- if (name in seenAttrs) {
10788
+ if (seenAttrs.has(name)) {
10161
10789
  handleWarning('attribute <' + name + '> already defined');
10162
10790
  continue;
10163
10791
  }
10164
10792
 
10165
- seenAttrs[name] = true;
10793
+ seenAttrs.add(name);
10166
10794
 
10167
10795
  if (!isNamespace) {
10168
10796
  attrs[name] = value;
@@ -10234,24 +10862,12 @@
10234
10862
 
10235
10863
  // handle attributes on element without
10236
10864
  // namespace declarations
10237
- w = name.indexOf(':');
10238
- if (w === -1) {
10239
- attrs[name] = value;
10240
- continue;
10241
- }
10865
+ name = normalizeAttrName(name, defaultAlias);
10242
10866
 
10243
- // normalize ns attribute name
10244
- if (!(nsName = nsMatrix[name.substring(0, w)])) {
10245
- handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
10867
+ if (name === null) {
10246
10868
  continue;
10247
10869
  }
10248
10870
 
10249
- name = defaultAlias === nsName
10250
- ? name.substr(w + 1)
10251
- : nsName + name.substr(w);
10252
-
10253
- // end: normalize ns attribute name
10254
-
10255
10871
  attrs[name] = value;
10256
10872
  }
10257
10873
 
@@ -10262,24 +10878,11 @@
10262
10878
  // normalize captured attributes
10263
10879
  for (i = 0, l = attrList.length; i < l; i++) {
10264
10880
 
10265
- name = attrList[i++];
10881
+ name = normalizeAttrName(attrList[i++], defaultAlias);
10266
10882
  value = attrList[i];
10267
10883
 
10268
- w = name.indexOf(':');
10269
-
10270
- if (w !== -1) {
10271
-
10272
- // normalize ns attribute name
10273
- if (!(nsName = nsMatrix[name.substring(0, w)])) {
10274
- handleWarning(missingNamespaceForPrefix(name.substring(0, w)));
10275
- continue;
10276
- }
10277
-
10278
- name = defaultAlias === nsName
10279
- ? name.substr(w + 1)
10280
- : nsName + name.substr(w);
10281
-
10282
- // end: normalize ns attribute name
10884
+ if (name === null) {
10885
+ continue;
10283
10886
  }
10284
10887
 
10285
10888
  attrs[name] = value;
@@ -10379,13 +10982,19 @@
10379
10982
  i = xml.indexOf('<', j);
10380
10983
  }
10381
10984
 
10382
- // parse end
10985
+ // no (more) tags found
10383
10986
  if (i === -1) {
10987
+
10988
+ // buffer the remainder for the next chunk
10989
+ if (streaming) {
10990
+ return xml.substring(j);
10991
+ }
10992
+
10384
10993
  if (nodeStack.length) {
10385
10994
  return handleError('unexpected end of file');
10386
10995
  }
10387
10996
 
10388
- if (j === 0) {
10997
+ if (!rootTagFound) {
10389
10998
  return handleError('missing start tag');
10390
10999
  }
10391
11000
 
@@ -10398,6 +11007,11 @@
10398
11007
  return;
10399
11008
  }
10400
11009
 
11010
+ // remember that we saw the root tag
11011
+ if (!rootTagFound) {
11012
+ rootTagFound = true;
11013
+ }
11014
+
10401
11015
  // parse text
10402
11016
  if (j !== i) {
10403
11017
 
@@ -10430,6 +11044,9 @@
10430
11044
  if (q === 91 && xml.substr(i + 3, 6) === 'CDATA[') { // 91 == "["
10431
11045
  j = xml.indexOf(']]>', i);
10432
11046
  if (j === -1) {
11047
+ if (streaming) {
11048
+ return xml.substring(i);
11049
+ }
10433
11050
  return handleError('unclosed cdata');
10434
11051
  }
10435
11052
 
@@ -10448,6 +11065,9 @@
10448
11065
  if (q === 45 && xml.charCodeAt(i + 3) === 45) { // 45 == "-"
10449
11066
  j = xml.indexOf('-->', i);
10450
11067
  if (j === -1) {
11068
+ if (streaming) {
11069
+ return xml.substring(i);
11070
+ }
10451
11071
  return handleError('unclosed comment');
10452
11072
  }
10453
11073
 
@@ -10468,6 +11088,9 @@
10468
11088
  if (w === 63) { // "?"
10469
11089
  j = xml.indexOf('?>', i);
10470
11090
  if (j === -1) {
11091
+ if (streaming) {
11092
+ return xml.substring(i);
11093
+ }
10471
11094
  return handleError('unclosed question');
10472
11095
  }
10473
11096
 
@@ -10488,6 +11111,9 @@
10488
11111
  for (x = i + 1; ; x++) {
10489
11112
  v = xml.charCodeAt(x);
10490
11113
  if (isNaN(v)) {
11114
+ if (streaming) {
11115
+ return xml.substring(i);
11116
+ }
10491
11117
  j = -1;
10492
11118
  return handleError('unclosed tag');
10493
11119
  }
@@ -10627,30 +11253,49 @@
10627
11253
 
10628
11254
  _elementName = elementName;
10629
11255
 
10630
- w = elementName.indexOf(':');
10631
- if (w !== -1) {
10632
- xmlns = nsMatrix[elementName.substring(0, w)];
10633
-
10634
- // prefix given; namespace must exist
10635
- if (!xmlns) {
10636
- return handleError('missing namespace on <' + _elementName + '>');
11256
+ // memoize normalized names per namespace matrix; tag names
11257
+ // typically repeat heavily and the matrix rarely changes.
11258
+ if (elNameCacheMatrix !== nsMatrix) {
11259
+ elNameCache = nsMatrix[NAME_CACHE];
11260
+ if (elNameCache === undefined) {
11261
+ elNameCache = nsMatrix[NAME_CACHE] = Object.create(null);
10637
11262
  }
11263
+ elNameCacheMatrix = nsMatrix;
11264
+ }
10638
11265
 
10639
- elementName = elementName.substr(w + 1);
11266
+ var _cachedName = elNameCache[elementName];
11267
+
11268
+ if (_cachedName !== undefined) {
11269
+ elementName = _cachedName;
10640
11270
  } else {
10641
- xmlns = nsMatrix['xmlns'];
10642
-
10643
- // if no default namespace is defined,
10644
- // we'll import the element as anonymous.
10645
- //
10646
- // it is up to users to correct that to the document defined
10647
- // targetNamespace, or whatever their undersanding of the
10648
- // XML spec mandates.
10649
- }
10650
11271
 
10651
- // adjust namespace prefixs as configured
10652
- if (xmlns) {
10653
- elementName = xmlns + ':' + elementName;
11272
+ w = elementName.indexOf(':');
11273
+ if (w !== -1) {
11274
+ xmlns = nsMatrix[elementName.substring(0, w)];
11275
+
11276
+ // prefix given; namespace must exist
11277
+ if (!xmlns) {
11278
+ return handleError('missing namespace on <' + _elementName + '>');
11279
+ }
11280
+
11281
+ elementName = elementName.substr(w + 1);
11282
+ } else {
11283
+ xmlns = nsMatrix['xmlns'];
11284
+
11285
+ // if no default namespace is defined,
11286
+ // we'll import the element as anonymous.
11287
+ //
11288
+ // it is up to users to correct that to the document defined
11289
+ // targetNamespace, or whatever their undersanding of the
11290
+ // XML spec mandates.
11291
+ }
11292
+
11293
+ // adjust namespace prefixs as configured
11294
+ if (xmlns) {
11295
+ elementName = xmlns + ':' + elementName;
11296
+ }
11297
+
11298
+ elNameCache[_elementName] = elementName;
10654
11299
  }
10655
11300
 
10656
11301
  }
@@ -11674,10 +12319,48 @@
11674
12319
  return this.defaultPrefixMap[prefix];
11675
12320
  };
11676
12321
 
12322
+ /**
12323
+ * Return the first truthy `fn(scope)` walking this scope and its ancestors.
12324
+ *
12325
+ * @param {(scope: Namespaces) => any} fn
12326
+ *
12327
+ * @return {any}
12328
+ */
12329
+ Namespaces.prototype.resolve = function(fn) {
12330
+
12331
+ var scope = this;
12332
+
12333
+ while (scope) {
12334
+ var resolved = fn(scope);
12335
+
12336
+ if (resolved) {
12337
+ return resolved;
12338
+ }
12339
+
12340
+ scope = scope.parent;
12341
+ }
12342
+ };
12343
+
12344
+ /**
12345
+ * Call `fn(scope)` for this scope and each of its ancestors.
12346
+ *
12347
+ * @param {(scope: Namespaces) => void} fn
12348
+ */
12349
+ Namespaces.prototype.eachScope = function(fn) {
12350
+
12351
+ var scope = this;
12352
+
12353
+ while (scope) {
12354
+ fn(scope);
12355
+
12356
+ scope = scope.parent;
12357
+ }
12358
+ };
12359
+
11677
12360
  Namespaces.prototype.byUri = function(uri) {
11678
- return this.uriMap[uri] || (
11679
- this.parent && this.parent.byUri(uri)
11680
- );
12361
+ return this.resolve(function(scope) {
12362
+ return scope.uriMap[uri];
12363
+ });
11681
12364
  };
11682
12365
 
11683
12366
  Namespaces.prototype.add = function(ns, isWellknown) {
@@ -11694,9 +12377,11 @@
11694
12377
  };
11695
12378
 
11696
12379
  Namespaces.prototype.uriByPrefix = function(prefix) {
11697
- return this.prefixMap[prefix || 'xmlns'] || (
11698
- this.parent && this.parent.uriByPrefix(prefix)
11699
- );
12380
+ var key = prefix || 'xmlns';
12381
+
12382
+ return this.resolve(function(scope) {
12383
+ return scope.prefixMap[key];
12384
+ });
11700
12385
  };
11701
12386
 
11702
12387
  Namespaces.prototype.mapPrefix = function(prefix, uri) {
@@ -11712,12 +12397,9 @@
11712
12397
  var uri = ns.uri;
11713
12398
  var nsKey = this.getNSKey(ns);
11714
12399
 
11715
- this.used[nsKey] = this.byUri(uri);
11716
-
11717
- // Inform parent recursively about the usage of this NS
11718
- if (this.parent) {
11719
- this.parent.logUsed(ns);
11720
- }
12400
+ this.eachScope(function(scope) {
12401
+ scope.used[nsKey] = scope.byUri(uri);
12402
+ });
11721
12403
  };
11722
12404
 
11723
12405
  Namespaces.prototype.getUsed = function(ns) {
@@ -11934,20 +12616,32 @@
11934
12616
  }
11935
12617
 
11936
12618
  ElementSerializer.prototype.build = function(element) {
12619
+ buildTree(this, element);
12620
+
12621
+ return this;
12622
+ };
12623
+
12624
+ /**
12625
+ * Enter the element during the build walk: register its namespaces, tag
12626
+ * name and attributes, then return the deferred, ordered work to build its
12627
+ * child nodes (empty when it has none).
12628
+ *
12629
+ * @param {Object} element
12630
+ *
12631
+ * @return {Array<Object>} ordered, deferred work items to build the children
12632
+ */
12633
+ ElementSerializer.prototype.enter = function(element) {
11937
12634
  this.element = element;
11938
12635
 
11939
12636
  var elementDescriptor = element.$descriptor,
11940
12637
  propertyDescriptor = this.propertyDescriptor;
11941
12638
 
11942
- var otherAttrs,
11943
- properties;
11944
-
11945
12639
  var isGeneric = elementDescriptor.isGeneric;
11946
12640
 
11947
12641
  if (isGeneric) {
11948
- otherAttrs = this.parseGenericNsAttributes(element);
12642
+ this.otherAttrs = this.parseGenericNsAttributes(element);
11949
12643
  } else {
11950
- otherAttrs = this.parseNsAttributes(element);
12644
+ this.otherAttrs = this.parseNsAttributes(element);
11951
12645
  }
11952
12646
 
11953
12647
  if (propertyDescriptor) {
@@ -11956,21 +12650,26 @@
11956
12650
  this.ns = this.nsTagName(elementDescriptor);
11957
12651
  }
11958
12652
 
11959
- // compute tag name
11960
12653
  this.tagName = this.addTagName(this.ns);
11961
12654
 
11962
12655
  if (isGeneric) {
11963
- this.parseGenericContainments(element);
11964
- } else {
11965
- properties = getSerializableProperties(element);
11966
-
11967
- this.parseAttributes(filterAttributes(properties));
11968
- this.parseContainments(filterContained(properties));
12656
+ return this.collectGenericContainments(element);
11969
12657
  }
11970
12658
 
11971
- this.parseGenericAttributes(element, otherAttrs);
12659
+ var properties = getSerializableProperties(element);
11972
12660
 
11973
- return this;
12661
+ this.parseAttributes(filterAttributes(properties));
12662
+
12663
+ return this.collectContainments(filterContained(properties));
12664
+ };
12665
+
12666
+ /**
12667
+ * Exit the element during the build walk: register its generic attributes,
12668
+ * which must happen after the children so namespace usage is logged in
12669
+ * document order.
12670
+ */
12671
+ ElementSerializer.prototype.exit = function() {
12672
+ this.parseGenericAttributes(this.element, this.otherAttrs);
11974
12673
  };
11975
12674
 
11976
12675
  ElementSerializer.prototype.nsTagName = function(descriptor) {
@@ -12033,20 +12732,34 @@
12033
12732
  );
12034
12733
  };
12035
12734
 
12036
- ElementSerializer.prototype.parseGenericContainments = function(element) {
12037
- var body = element.$body;
12735
+ ElementSerializer.prototype.collectGenericContainments = function(element) {
12736
+ var self = this,
12737
+ children = [];
12738
+
12739
+ var bodyText = element.$body;
12038
12740
 
12039
- if (body) {
12040
- this.body.push(new BodySerializer().build({ type: 'String' }, body));
12741
+ if (bodyText) {
12742
+ children.push({
12743
+ create: function() {
12744
+ return new BodySerializer().build({ type: 'String' }, bodyText);
12745
+ }
12746
+ });
12041
12747
  }
12042
12748
 
12043
- var children = element.$children;
12749
+ var genericChildren = element.$children;
12044
12750
 
12045
- if (children) {
12046
- forEach(children, child => {
12047
- this.body.push(new ElementSerializer(this).build(child));
12751
+ if (genericChildren) {
12752
+ forEach(genericChildren, function(child) {
12753
+ children.push({
12754
+ create: function() {
12755
+ return new ElementSerializer(self);
12756
+ },
12757
+ element: child
12758
+ });
12048
12759
  });
12049
12760
  }
12761
+
12762
+ return children;
12050
12763
  };
12051
12764
 
12052
12765
  ElementSerializer.prototype.parseNsAttribute = function(element, name, value) {
@@ -12125,7 +12838,6 @@
12125
12838
  self.addAttribute(self.nsAttributeName(attr.name), attr.value);
12126
12839
  } catch (e) {
12127
12840
 
12128
- // eslint-disable-next-line no-undef
12129
12841
  typeof console !== 'undefined' && console.warn(
12130
12842
  `missing namespace information for <${
12131
12843
  attr.name
@@ -12135,11 +12847,11 @@
12135
12847
  });
12136
12848
  };
12137
12849
 
12138
- ElementSerializer.prototype.parseContainments = function(properties) {
12850
+ ElementSerializer.prototype.collectContainments = function(properties) {
12139
12851
 
12140
12852
  var self = this,
12141
- body = this.body,
12142
- element = this.element;
12853
+ element = this.element,
12854
+ children = [];
12143
12855
 
12144
12856
  forEach(properties, function(p) {
12145
12857
  var value = element.get(p.name),
@@ -12151,14 +12863,26 @@
12151
12863
  }
12152
12864
 
12153
12865
  if (p.isBody) {
12154
- body.push(new BodySerializer().build(p, value[0]));
12866
+ children.push({
12867
+ create: function() {
12868
+ return new BodySerializer().build(p, value[0]);
12869
+ }
12870
+ });
12155
12871
  } else if (isSimple(p.type)) {
12156
12872
  forEach(value, function(v) {
12157
- body.push(new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v));
12873
+ children.push({
12874
+ create: function() {
12875
+ return new ValueSerializer(self.addTagName(self.nsPropertyTagName(p))).build(p, v);
12876
+ }
12877
+ });
12158
12878
  });
12159
12879
  } else if (isReference) {
12160
12880
  forEach(value, function(v) {
12161
- body.push(new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v));
12881
+ children.push({
12882
+ create: function() {
12883
+ return new ReferenceSerializer(self.addTagName(self.nsPropertyTagName(p))).build(v);
12884
+ }
12885
+ });
12162
12886
  });
12163
12887
  } else {
12164
12888
 
@@ -12167,32 +12891,33 @@
12167
12891
  var serialization = getSerialization(p);
12168
12892
 
12169
12893
  forEach(value, function(v) {
12170
- var serializer;
12894
+ children.push({
12895
+ create: function() {
12896
+ if (serialization) {
12897
+ if (serialization === SERIALIZE_PROPERTY) {
12898
+ return new ElementSerializer(self, p);
12899
+ }
12171
12900
 
12172
- if (serialization) {
12173
- if (serialization === SERIALIZE_PROPERTY) {
12174
- serializer = new ElementSerializer(self, p);
12175
- } else {
12176
- serializer = new TypeSerializer(self, p, serialization);
12177
- }
12178
- } else {
12179
- serializer = new ElementSerializer(self);
12180
- }
12901
+ return new TypeSerializer(self, p, serialization);
12902
+ }
12181
12903
 
12182
- body.push(serializer.build(v));
12904
+ return new ElementSerializer(self);
12905
+ },
12906
+ element: v
12907
+ });
12183
12908
  });
12184
12909
  }
12185
12910
  });
12911
+
12912
+ return children;
12186
12913
  };
12187
12914
 
12188
12915
  ElementSerializer.prototype.getNamespaces = function(local) {
12189
12916
 
12190
- var namespaces = this.namespaces,
12191
- parent = this.parent,
12192
- parentNamespaces;
12917
+ var namespaces = this.namespaces;
12193
12918
 
12194
12919
  if (!namespaces) {
12195
- parentNamespaces = parent && parent.getNamespaces();
12920
+ var parentNamespaces = this.getParentNamespaces();
12196
12921
 
12197
12922
  if (local || !parentNamespaces) {
12198
12923
  this.namespaces = namespaces = new Namespaces(parentNamespaces);
@@ -12204,6 +12929,38 @@
12204
12929
  return namespaces;
12205
12930
  };
12206
12931
 
12932
+ /**
12933
+ * Resolve, and memoize, the namespaces scope owned by the closest
12934
+ * ancestor serializer.
12935
+ *
12936
+ * @return {Namespaces|null}
12937
+ */
12938
+ ElementSerializer.prototype.getParentNamespaces = function() {
12939
+
12940
+ if (this.parentNamespaces !== undefined) {
12941
+ return this.parentNamespaces;
12942
+ }
12943
+
12944
+ var scope = null,
12945
+ ancestor = this.parent;
12946
+
12947
+ while (ancestor) {
12948
+ if (ancestor.namespaces) {
12949
+ scope = ancestor.namespaces;
12950
+ break;
12951
+ }
12952
+
12953
+ if (ancestor.parentNamespaces !== undefined) {
12954
+ scope = ancestor.parentNamespaces;
12955
+ break;
12956
+ }
12957
+
12958
+ ancestor = ancestor.parent;
12959
+ }
12960
+
12961
+ return (this.parentNamespaces = scope);
12962
+ };
12963
+
12207
12964
  ElementSerializer.prototype.logNamespace = function(ns, wellknown, local) {
12208
12965
  var namespaces = this.getNamespaces(local);
12209
12966
 
@@ -12352,40 +13109,77 @@
12352
13109
  };
12353
13110
 
12354
13111
  ElementSerializer.prototype.serializeTo = function(writer) {
12355
- var firstBody = this.body[0],
12356
- indent = firstBody && firstBody.constructor !== BodySerializer;
13112
+ serializeTree(this, writer);
13113
+ };
12357
13114
 
12358
- writer
12359
- .appendIndent()
12360
- .append('<' + this.tagName);
13115
+ /**
13116
+ * Serialize the serializer tree rooted at the given element serializer to
13117
+ * the writer, using an explicit stack to stay flat for nested documents.
13118
+ *
13119
+ * @param {ElementSerializer} root
13120
+ * @param {Object} writer
13121
+ */
13122
+ function serializeTree(root, writer) {
12361
13123
 
12362
- this.serializeAttributes(writer);
13124
+ var stack = [ { serializer: root, index: 0, opened: false, indent: false } ];
12363
13125
 
12364
- writer.append(firstBody ? '>' : ' />');
13126
+ while (stack.length) {
13127
+ var frame = stack[stack.length - 1],
13128
+ serializer = frame.serializer;
12365
13129
 
12366
- if (firstBody) {
13130
+ if (!frame.opened) {
13131
+ var firstBody = serializer.body[0];
13132
+
13133
+ frame.indent = firstBody && firstBody.constructor !== BodySerializer;
12367
13134
 
12368
- if (indent) {
12369
13135
  writer
12370
- .appendNewLine()
12371
- .indent();
13136
+ .appendIndent()
13137
+ .append('<' + serializer.tagName);
13138
+
13139
+ serializer.serializeAttributes(writer);
13140
+
13141
+ writer.append(firstBody ? '>' : ' />');
13142
+
13143
+ frame.opened = true;
13144
+
13145
+ if (!firstBody) {
13146
+ writer.appendNewLine();
13147
+ stack.pop();
13148
+ continue;
13149
+ }
13150
+
13151
+ if (frame.indent) {
13152
+ writer
13153
+ .appendNewLine()
13154
+ .indent();
13155
+ }
12372
13156
  }
12373
13157
 
12374
- forEach(this.body, function(b) {
12375
- b.serializeTo(writer);
12376
- });
13158
+ if (frame.index < serializer.body.length) {
13159
+ var child = serializer.body[frame.index++];
13160
+
13161
+ if (child instanceof ElementSerializer) {
13162
+ stack.push({ serializer: child, index: 0, opened: false, indent: false });
13163
+ } else {
13164
+ child.serializeTo(writer);
13165
+ }
13166
+
13167
+ continue;
13168
+ }
12377
13169
 
12378
- if (indent) {
13170
+ if (frame.indent) {
12379
13171
  writer
12380
13172
  .unindent()
12381
13173
  .appendIndent();
12382
13174
  }
12383
13175
 
12384
- writer.append('</' + this.tagName + '>');
12385
- }
13176
+ writer
13177
+ .append('</' + serializer.tagName + '>')
13178
+ .appendNewLine();
12386
13179
 
12387
- writer.appendNewLine();
12388
- };
13180
+ stack.pop();
13181
+ }
13182
+ }
12389
13183
 
12390
13184
  /**
12391
13185
  * A serializer for types that handles serialization of data types
@@ -12517,6 +13311,51 @@
12517
13311
 
12518
13312
  // helpers ///////////
12519
13313
 
13314
+ /**
13315
+ * Build the serializer tree for the given root element, iterating an
13316
+ * explicit stack rather than recursing so deeply nested documents stay
13317
+ * flat.
13318
+ *
13319
+ * Elements are visited pre-order so namespaces register in document order:
13320
+ * `enter` opens an element and returns its children, `exit` runs once its
13321
+ * subtree is built.
13322
+ *
13323
+ * @param {ElementSerializer} rootSerializer
13324
+ * @param {Object} rootElement
13325
+ */
13326
+ function buildTree(rootSerializer, rootElement) {
13327
+
13328
+ var stack = [ {
13329
+ serializer: rootSerializer,
13330
+ children: rootSerializer.enter(rootElement),
13331
+ index: 0
13332
+ } ];
13333
+
13334
+ while (stack.length) {
13335
+ var frame = stack[stack.length - 1];
13336
+
13337
+ if (frame.index >= frame.children.length) {
13338
+ frame.serializer.exit();
13339
+ stack.pop();
13340
+ continue;
13341
+ }
13342
+
13343
+ var child = frame.children[frame.index++];
13344
+
13345
+ var childSerializer = child.create();
13346
+
13347
+ frame.serializer.body.push(childSerializer);
13348
+
13349
+ if (child.element) {
13350
+ stack.push({
13351
+ serializer: childSerializer,
13352
+ children: childSerializer.enter(child.element),
13353
+ index: 0
13354
+ });
13355
+ }
13356
+ }
13357
+ }
13358
+
12520
13359
  /**
12521
13360
  * @param {Moddle} model
12522
13361
  *
@@ -23831,14 +24670,7 @@
23831
24670
  return [];
23832
24671
  }
23833
24672
 
23834
- var title = escapeHTML(parent.name || parent.id);
23835
- var link = domify('<li><span class="bjs-crumb"><a title="' + title + '">' + title + '</a></span></li>');
23836
-
23837
- link.addEventListener('click', function() {
23838
- canvas.setRootElement(parentPlane);
23839
- });
23840
-
23841
- return link;
24673
+ return [ { parent: parent, parentPlane: parentPlane } ];
23842
24674
  });
23843
24675
 
23844
24676
  breadcrumbs.innerHTML = '';
@@ -23848,8 +24680,39 @@
23848
24680
 
23849
24681
  containerClasses.toggle(OPEN_CLASS, visible);
23850
24682
 
23851
- path.forEach(function(element) {
23852
- breadcrumbs.appendChild(element);
24683
+ path.forEach(function(entry, index) {
24684
+ var parent = entry.parent,
24685
+ parentPlane = entry.parentPlane,
24686
+ title = escapeHTML(parent.name || parent.id);
24687
+
24688
+ // the last crumb represents the current plane; render it as
24689
+ // plain, non-interactive text
24690
+ var isCurrent = index === path.length - 1;
24691
+
24692
+ var crumb;
24693
+
24694
+ if (isCurrent) {
24695
+ crumb = domify(
24696
+ '<li><span class="bjs-crumb" title="' + title + '">' + title + '</span></li>'
24697
+ );
24698
+ } else {
24699
+
24700
+ // render navigable crumbs as local links so they are focusable
24701
+ // and keyboard-operable
24702
+ var href = '#' + escapeHTML(parent.id);
24703
+
24704
+ crumb = domify(
24705
+ '<li><a class="bjs-crumb" href="' + href + '" title="' + title + '">' + title + '</a></li>'
24706
+ );
24707
+
24708
+ crumb.addEventListener('click', function(event) {
24709
+ event.preventDefault();
24710
+
24711
+ canvas.setRootElement(parentPlane);
24712
+ });
24713
+ }
24714
+
24715
+ breadcrumbs.appendChild(crumb);
23853
24716
  });
23854
24717
  }
23855
24718
 
@@ -32930,6 +33793,7 @@
32930
33793
  attr(visual, {
32931
33794
  x: -width / 2,
32932
33795
  y: -height / 2,
33796
+ rx: 3,
32933
33797
  width: width,
32934
33798
  height: height
32935
33799
  });
@@ -62735,6 +63599,7 @@
62735
63599
  attr(visual, {
62736
63600
  x: -HANDLE_SIZE / 2 + offset.x,
62737
63601
  y: -HANDLE_SIZE / 2 + offset.y,
63602
+ rx: 2,
62738
63603
  width: HANDLE_SIZE,
62739
63604
  height: HANDLE_SIZE
62740
63605
  });