mapshaper 0.6.68 → 0.6.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/mapshaper.js CHANGED
@@ -6661,11 +6661,16 @@
6661
6661
  nn = arcData.nn,
6662
6662
  xx = arcData.xx,
6663
6663
  yy = arcData.yy,
6664
- nodeData;
6664
+ nodeData,
6665
+ globalFilter;
6665
6666
 
6666
6667
  // Accessor function for arcs
6667
6668
  Object.defineProperty(this, 'arcs', {value: arcs});
6668
6669
 
6670
+ this.setArcFilter = function(f) {
6671
+ globalFilter = f;
6672
+ };
6673
+
6669
6674
  this.toArray = function() {
6670
6675
  var chains = getNodeChains(),
6671
6676
  flags = new Uint8Array(chains.length),
@@ -6744,15 +6749,19 @@
6744
6749
  // Returned ids lead into the node (as opposed to outwards from it)
6745
6750
  // An optional filter function receives the directed id (positive or negative)
6746
6751
  // of each connected arc and excludes arcs for which the filter returns false.
6747
- // The filter is also applied to the initial arc; if false, no arcs are returned.
6752
+ // // removed: The filter is also applied to the initial arc; if false, no arcs are returned.
6748
6753
  //
6749
- this.getConnectedArcs = function(arcId, filter) {
6754
+ this.getConnectedArcs = function(arcId, localFilter) {
6750
6755
  var ids = [];
6751
- var filtered = !!filter;
6752
6756
  var nextId = nextConnectedArc(arcId);
6753
- if (filtered && !filter(arcId)) ;
6757
+ // kludge: return empty result if arc fails global test
6758
+ // ... applying the local filter causes tests to fail
6759
+ if (globalFilter && !globalFilter(arcId)) {
6760
+ return [];
6761
+ }
6754
6762
  while (nextId != arcId) {
6755
- if (!filtered || filter(nextId)) {
6763
+ // if (!filtered || filter && filter(nextId) ) {
6764
+ if ((!localFilter || localFilter(nextId)) && (!globalFilter || globalFilter(nextId))) {
6756
6765
  ids.push(nextId);
6757
6766
  }
6758
6767
  nextId = nextConnectedArc(nextId);
@@ -7415,6 +7424,8 @@
7415
7424
  return this ? this.unpack(source, options) : Unpackr.prototype.unpack.call(defaultOptions, source, options)
7416
7425
  })
7417
7426
  }
7427
+ if (!source.buffer && source.constructor === ArrayBuffer)
7428
+ source = typeof Buffer !== 'undefined' ? Buffer.from(source) : new Uint8Array(source);
7418
7429
  if (typeof options === 'object') {
7419
7430
  srcEnd = options.end || source.length;
7420
7431
  position$1 = options.start || 0;
@@ -7460,10 +7471,10 @@
7460
7471
  let size = source.length;
7461
7472
  let value = this ? this.unpack(source, size) : defaultUnpackr.unpack(source, size);
7462
7473
  if (forEach) {
7463
- if (forEach(value) === false) return;
7474
+ if (forEach(value, lastPosition, position$1) === false) return;
7464
7475
  while(position$1 < size) {
7465
7476
  lastPosition = position$1;
7466
- if (forEach(checkedRead()) === false) {
7477
+ if (forEach(checkedRead(), lastPosition, position$1) === false) {
7467
7478
  return
7468
7479
  }
7469
7480
  }
@@ -7511,8 +7522,8 @@
7511
7522
  }
7512
7523
  return this.structures = loadedStructures
7513
7524
  }
7514
- decode(source, end) {
7515
- return this.unpack(source, end)
7525
+ decode(source, options) {
7526
+ return this.unpack(source, options)
7516
7527
  }
7517
7528
  }
7518
7529
  function checkedRead(options) {
@@ -7535,6 +7546,10 @@
7535
7546
  position$1 = bundledStrings$1.postBundlePosition;
7536
7547
  bundledStrings$1 = null;
7537
7548
  }
7549
+ if (sequentialMode)
7550
+ // we only need to restore the structures if there was an error, but if we completed a read,
7551
+ // we can clear this out and keep the structures we read
7552
+ currentStructures.restoreStructures = null;
7538
7553
 
7539
7554
  if (position$1 == srcEnd) {
7540
7555
  // finished reading this source, cleanup references
@@ -7548,7 +7563,13 @@
7548
7563
  // over read
7549
7564
  throw new Error('Unexpected end of MessagePack data')
7550
7565
  } else if (!sequentialMode) {
7551
- throw new Error('Data read, but end of buffer not reached ' + JSON.stringify(result).slice(0, 100))
7566
+ let jsonView;
7567
+ try {
7568
+ jsonView = JSON.stringify(result, (_, value) => typeof value === "bigint" ? `${value}n` : value).slice(0, 100);
7569
+ } catch(error) {
7570
+ jsonView = '(JSON view not available ' + error + ')';
7571
+ }
7572
+ throw new Error('Data read, but end of buffer not reached ' + jsonView)
7552
7573
  }
7553
7574
  // else more to read, but we are reading sequentially, so don't clear source yet
7554
7575
  return result
@@ -7704,6 +7725,9 @@
7704
7725
  value += dataView.getUint32(position$1 + 4);
7705
7726
  } else if (currentUnpackr.int64AsType === 'string') {
7706
7727
  value = dataView.getBigUint64(position$1).toString();
7728
+ } else if (currentUnpackr.int64AsType === 'auto') {
7729
+ value = dataView.getBigUint64(position$1);
7730
+ if (value<=BigInt(2)<<BigInt(52)) value=Number(value);
7707
7731
  } else
7708
7732
  value = dataView.getBigUint64(position$1);
7709
7733
  position$1 += 8;
@@ -7726,6 +7750,9 @@
7726
7750
  value += dataView.getUint32(position$1 + 4);
7727
7751
  } else if (currentUnpackr.int64AsType === 'string') {
7728
7752
  value = dataView.getBigInt64(position$1).toString();
7753
+ } else if (currentUnpackr.int64AsType === 'auto') {
7754
+ value = dataView.getBigInt64(position$1);
7755
+ if (value>=BigInt(-2)<<BigInt(52)&&value<=BigInt(2)<<BigInt(52)) value=Number(value);
7729
7756
  } else
7730
7757
  value = dataView.getBigInt64(position$1);
7731
7758
  position$1 += 8;
@@ -8183,7 +8210,7 @@
8183
8210
  return readFixedString(length)
8184
8211
  } else { // not cacheable, go back and do a standard read
8185
8212
  position$1--;
8186
- return read().toString()
8213
+ return asSafeString(read())
8187
8214
  }
8188
8215
  let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position$1) : length > 0 ? src[position$1] : 0)) & 0xfff;
8189
8216
  let entry = keyCache[key];
@@ -8235,16 +8262,25 @@
8235
8262
  return entry.string = readFixedString(length)
8236
8263
  }
8237
8264
 
8265
+ function asSafeString(property) {
8266
+ if (typeof property === 'string') return property;
8267
+ if (typeof property === 'number') return property.toString();
8268
+ throw new Error('Invalid property type for record', typeof property);
8269
+ }
8238
8270
  // the registration of the record definition extension (as "r")
8239
8271
  const recordDefinition = (id, highByte) => {
8240
- let structure = read().map(property => property.toString()); // ensure that all keys are strings and that the array is mutable
8272
+ let structure = read().map(asSafeString); // ensure that all keys are strings and
8273
+ // that the array is mutable
8241
8274
  let firstByte = id;
8242
8275
  if (highByte !== undefined) {
8243
8276
  id = id < 32 ? -((highByte << 5) + id) : ((highByte << 5) + id);
8244
8277
  structure.highByte = highByte;
8245
8278
  }
8246
8279
  let existingStructure = currentStructures[id];
8247
- if (existingStructure && existingStructure.isShared) {
8280
+ // If it is a shared structure, we need to restore any changes after reading.
8281
+ // Also in sequential mode, we may get incomplete reads and thus errors, and we need to restore
8282
+ // to the state prior to an incomplete read in order to properly resume.
8283
+ if (existingStructure && (existingStructure.isShared || sequentialMode)) {
8248
8284
  (currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure;
8249
8285
  }
8250
8286
  currentStructures[id] = structure;
@@ -8254,13 +8290,26 @@
8254
8290
  currentExtensions[0] = () => {}; // notepack defines extension 0 to mean undefined, so use that as the default here
8255
8291
  currentExtensions[0].noBuffer = true;
8256
8292
 
8293
+ currentExtensions[0x42] = (data) => {
8294
+ // decode bigint
8295
+ let length = data.length;
8296
+ let value = BigInt(data[0] & 0x80 ? data[0] - 0x100 : data[0]);
8297
+ for (let i = 1; i < length; i++) {
8298
+ value <<= 8n;
8299
+ value += BigInt(data[i]);
8300
+ }
8301
+ return value;
8302
+ };
8303
+
8304
+ let errors = { Error, TypeError, ReferenceError };
8257
8305
  currentExtensions[0x65] = () => {
8258
8306
  let data = read();
8259
- return (globalThis[data[0]] || Error)(data[1])
8307
+ return (errors[data[0]] || Error)(data[1])
8260
8308
  };
8261
8309
 
8262
8310
  currentExtensions[0x69] = (data) => {
8263
8311
  // id extension (for structured clones)
8312
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
8264
8313
  let id = dataView.getUint32(position$1 - 4);
8265
8314
  if (!referenceMap)
8266
8315
  referenceMap = new Map();
@@ -8284,6 +8333,7 @@
8284
8333
 
8285
8334
  currentExtensions[0x70] = (data) => {
8286
8335
  // pointer extension (for structured clones)
8336
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
8287
8337
  let id = dataView.getUint32(position$1 - 4);
8288
8338
  let refEntry = referenceMap.get(id);
8289
8339
  refEntry.used = true;
@@ -8294,13 +8344,14 @@
8294
8344
 
8295
8345
  const typedArrays = ['Int8','Uint8','Uint8Clamped','Int16','Uint16','Int32','Uint32','Float32','Float64','BigInt64','BigUint64'].map(type => type + 'Array');
8296
8346
 
8347
+ let glbl = typeof globalThis === 'object' ? globalThis : window;
8297
8348
  currentExtensions[0x74] = (data) => {
8298
8349
  let typeCode = data[0];
8299
8350
  let typedArrayName = typedArrays[typeCode];
8300
8351
  if (!typedArrayName)
8301
8352
  throw new Error('Could not find typed array for code ' + typeCode)
8302
8353
  // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
8303
- return new globalThis[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
8354
+ return new glbl[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
8304
8355
  };
8305
8356
  currentExtensions[0x78] = () => {
8306
8357
  let data = read();
@@ -8465,6 +8516,7 @@
8465
8516
  } else
8466
8517
  position = (position + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
8467
8518
  start = position;
8519
+ if (encodeOptions & RESERVE_START_SPACE) position += (encodeOptions & 0xff);
8468
8520
  referenceMap = packr.structuredClone ? new Map() : null;
8469
8521
  if (packr.bundleStrings && typeof value !== 'string') {
8470
8522
  bundledStrings = [];
@@ -8506,8 +8558,9 @@
8506
8558
  }
8507
8559
  if (hasSharedUpdate)
8508
8560
  hasSharedUpdate = false;
8561
+ let encodingError;
8509
8562
  try {
8510
- if (packr.randomAccessStructure && value.constructor && value.constructor === Object)
8563
+ if (packr.randomAccessStructure && value && value.constructor && value.constructor === Object)
8511
8564
  writeStruct(value);
8512
8565
  else
8513
8566
  pack(value);
@@ -8556,42 +8609,51 @@
8556
8609
  return target
8557
8610
  }
8558
8611
  return target.subarray(start, position) // position can change if we call pack again in saveStructures, so we get the buffer now
8612
+ } catch(error) {
8613
+ encodingError = error;
8614
+ throw error;
8559
8615
  } finally {
8560
8616
  if (structures) {
8561
- if (serializationsSinceTransitionRebuild < 10)
8562
- serializationsSinceTransitionRebuild++;
8563
- let sharedLength = structures.sharedLength || 0;
8564
- if (structures.length > sharedLength)
8565
- structures.length = sharedLength;
8566
- if (transitionsCount > 10000) {
8567
- // force a rebuild occasionally after a lot of transitions so it can get cleaned up
8568
- structures.transitions = null;
8569
- serializationsSinceTransitionRebuild = 0;
8570
- transitionsCount = 0;
8571
- if (recordIdsToRemove.length > 0)
8572
- recordIdsToRemove = [];
8573
- } else if (recordIdsToRemove.length > 0 && !isSequential) {
8574
- for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
8575
- recordIdsToRemove[i][RECORD_SYMBOL] = 0;
8576
- }
8577
- recordIdsToRemove = [];
8578
- }
8617
+ resetStructures();
8579
8618
  if (hasSharedUpdate && packr.saveStructures) {
8619
+ let sharedLength = structures.sharedLength || 0;
8580
8620
  // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
8581
8621
  let returnBuffer = target.subarray(start, position);
8582
8622
  let newSharedData = prepareStructures(structures, packr);
8583
- if (packr.saveStructures(newSharedData, newSharedData.isCompatible) === false) {
8584
- // get updated structures and try again if the update failed
8585
- return packr.pack(value)
8623
+ if (!encodingError) { // TODO: If there is an encoding error, should make the structures as uninitialized so they get rebuilt next time
8624
+ if (packr.saveStructures(newSharedData, newSharedData.isCompatible) === false) {
8625
+ // get updated structures and try again if the update failed
8626
+ return packr.pack(value, encodeOptions)
8627
+ }
8628
+ packr.lastNamedStructuresLength = sharedLength;
8629
+ return returnBuffer
8586
8630
  }
8587
- packr.lastNamedStructuresLength = sharedLength;
8588
- return returnBuffer
8589
8631
  }
8590
8632
  }
8591
8633
  if (encodeOptions & RESET_BUFFER_MODE)
8592
8634
  position = start;
8593
8635
  }
8594
8636
  };
8637
+ const resetStructures = () => {
8638
+ if (serializationsSinceTransitionRebuild < 10)
8639
+ serializationsSinceTransitionRebuild++;
8640
+ let sharedLength = structures.sharedLength || 0;
8641
+ if (structures.length > sharedLength && !isSequential)
8642
+ structures.length = sharedLength;
8643
+ if (transitionsCount > 10000) {
8644
+ // force a rebuild occasionally after a lot of transitions so it can get cleaned up
8645
+ structures.transitions = null;
8646
+ serializationsSinceTransitionRebuild = 0;
8647
+ transitionsCount = 0;
8648
+ if (recordIdsToRemove.length > 0)
8649
+ recordIdsToRemove = [];
8650
+ } else if (recordIdsToRemove.length > 0 && !isSequential) {
8651
+ for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
8652
+ recordIdsToRemove[i][RECORD_SYMBOL] = 0;
8653
+ }
8654
+ recordIdsToRemove = [];
8655
+ }
8656
+ };
8595
8657
  const packArray = (value) => {
8596
8658
  var length = value.length;
8597
8659
  if (length < 0x10) {
@@ -8769,7 +8831,7 @@
8769
8831
  targetView.setFloat64(position, value);
8770
8832
  position += 8;
8771
8833
  }
8772
- } else if (type === 'object') {
8834
+ } else if (type === 'object' || type === 'function') {
8773
8835
  if (!value)
8774
8836
  target[position++] = 0xc0;
8775
8837
  else {
@@ -8794,21 +8856,24 @@
8794
8856
  } else if (constructor === Array) {
8795
8857
  packArray(value);
8796
8858
  } else if (constructor === Map) {
8797
- length = value.size;
8798
- if (length < 0x10) {
8799
- target[position++] = 0x80 | length;
8800
- } else if (length < 0x10000) {
8801
- target[position++] = 0xde;
8802
- target[position++] = length >> 8;
8803
- target[position++] = length & 0xff;
8804
- } else {
8805
- target[position++] = 0xdf;
8806
- targetView.setUint32(position, length);
8807
- position += 4;
8808
- }
8809
- for (let [ key, entryValue ] of value) {
8810
- pack(key);
8811
- pack(entryValue);
8859
+ if (this.mapAsEmptyObject) target[position++] = 0x80;
8860
+ else {
8861
+ length = value.size;
8862
+ if (length < 0x10) {
8863
+ target[position++] = 0x80 | length;
8864
+ } else if (length < 0x10000) {
8865
+ target[position++] = 0xde;
8866
+ target[position++] = length >> 8;
8867
+ target[position++] = length & 0xff;
8868
+ } else {
8869
+ target[position++] = 0xdf;
8870
+ targetView.setUint32(position, length);
8871
+ position += 4;
8872
+ }
8873
+ for (let [key, entryValue] of value) {
8874
+ pack(key);
8875
+ pack(entryValue);
8876
+ }
8812
8877
  }
8813
8878
  } else {
8814
8879
  for (let i = 0, l = extensions.length; i < l; i++) {
@@ -8871,6 +8936,18 @@
8871
8936
  if (Array.isArray(value)) {
8872
8937
  packArray(value);
8873
8938
  } else {
8939
+ // use this as an alternate mechanism for expressing how to serialize
8940
+ if (value.toJSON) {
8941
+ const json = value.toJSON();
8942
+ // if for some reason value.toJSON returns itself it'll loop forever
8943
+ if (json !== value)
8944
+ return pack(json)
8945
+ }
8946
+
8947
+ // if there is a writeFunction, use it, otherwise just encode as undefined
8948
+ if (type === 'function')
8949
+ return pack(this.writeFunction && this.writeFunction(value));
8950
+
8874
8951
  // no extension found, write as object
8875
8952
  writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
8876
8953
  }
@@ -8892,8 +8969,26 @@
8892
8969
  if (this.largeBigIntToFloat) {
8893
8970
  target[position++] = 0xcb;
8894
8971
  targetView.setFloat64(position, Number(value));
8972
+ } else if (this.useBigIntExtension && value < 2n**(1023n) && value > -(2n**(1023n))) {
8973
+ target[position++] = 0xc7;
8974
+ position++;
8975
+ target[position++] = 0x42; // "B" for BigInt
8976
+ let bytes = [];
8977
+ let alignedSign;
8978
+ do {
8979
+ let byte = value & 0xffn;
8980
+ alignedSign = (byte & 0x80n) === (value < 0n ? 0x80n : 0n);
8981
+ bytes.push(byte);
8982
+ value >>= 8n;
8983
+ } while (!((value === 0n || value === -1n) && alignedSign));
8984
+ target[position-2] = bytes.length;
8985
+ for (let i = bytes.length; i > 0;) {
8986
+ target[position++] = Number(bytes[--i]);
8987
+ }
8988
+ return
8895
8989
  } else {
8896
- throw new RangeError(value + ' was too large to fit in MessagePack 64-bit integer format, set largeBigIntToFloat to convert to float-64')
8990
+ throw new RangeError(value + ' was too large to fit in MessagePack 64-bit integer format, use' +
8991
+ ' useBigIntExtension or set largeBigIntToFloat to convert to float-64')
8897
8992
  }
8898
8993
  }
8899
8994
  position += 8;
@@ -8905,14 +9000,12 @@
8905
9000
  target[position++] = 0;
8906
9001
  target[position++] = 0;
8907
9002
  }
8908
- } else if (type === 'function') {
8909
- pack(this.writeFunction && this.writeFunction()); // if there is a writeFunction, use it, otherwise just encode as undefined
8910
9003
  } else {
8911
9004
  throw new Error('Unknown type: ' + type)
8912
9005
  }
8913
9006
  };
8914
9007
 
8915
- const writeObject = this.useRecords === false ? this.variableMapSize ? (object) => {
9008
+ const writePlainObject = (this.variableMapSize || this.coercibleKeyAsNumber) ? (object) => {
8916
9009
  // this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
8917
9010
  let keys = Object.keys(object);
8918
9011
  let length = keys.length;
@@ -8928,9 +9021,19 @@
8928
9021
  position += 4;
8929
9022
  }
8930
9023
  let key;
8931
- for (let i = 0; i < length; i++) {
8932
- pack(key = keys[i]);
8933
- pack(object[key]);
9024
+ if (this.coercibleKeyAsNumber) {
9025
+ for (let i = 0; i < length; i++) {
9026
+ key = keys[i];
9027
+ let num = Number(key);
9028
+ pack(isNaN(num) ? key : num);
9029
+ pack(object[key]);
9030
+ }
9031
+
9032
+ } else {
9033
+ for (let i = 0; i < length; i++) {
9034
+ pack(key = keys[i]);
9035
+ pack(object[key]);
9036
+ }
8934
9037
  }
8935
9038
  } :
8936
9039
  (object, safePrototype) => {
@@ -8947,7 +9050,9 @@
8947
9050
  }
8948
9051
  target[objectOffset++ + start] = size >> 8;
8949
9052
  target[objectOffset + start] = size & 0xff;
8950
- } :
9053
+ };
9054
+
9055
+ const writeRecord = this.useRecords === false ? writePlainObject :
8951
9056
  (options.progressiveRecords && !useTwoByteRecords) ? // this is about 2% faster for highly stable structures, since it only requires one for-in loop (but much more expensive when new structure needs to be written)
8952
9057
  (object, safePrototype) => {
8953
9058
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
@@ -9016,9 +9121,18 @@
9016
9121
  }
9017
9122
  // now write the values
9018
9123
  for (let key in object)
9019
- if (safePrototype || object.hasOwnProperty(key))
9124
+ if (safePrototype || object.hasOwnProperty(key)) {
9020
9125
  pack(object[key]);
9126
+ }
9021
9127
  };
9128
+
9129
+ // craete reference to useRecords if useRecords is a function
9130
+ const checkUseRecords = typeof this.useRecords == 'function' && this.useRecords;
9131
+
9132
+ const writeObject = checkUseRecords ? (object, safePrototype) => {
9133
+ checkUseRecords(object) ? writeRecord(object,safePrototype) : writePlainObject(object,safePrototype);
9134
+ } : writeRecord;
9135
+
9022
9136
  const makeRoom = (end) => {
9023
9137
  let newSize;
9024
9138
  if (end > 0x1000000) {
@@ -9122,12 +9236,13 @@
9122
9236
  }
9123
9237
  };
9124
9238
  const writeStruct = (object, safePrototype) => {
9125
- let newPosition = writeStructSlots(object, target, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
9239
+ let newPosition = writeStructSlots(object, target, start, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
9126
9240
  if (notifySharedUpdate)
9127
9241
  return hasSharedUpdate = true;
9128
9242
  position = newPosition;
9129
9243
  let startTarget = target;
9130
9244
  pack(value);
9245
+ resetStructures();
9131
9246
  if (startTarget !== target) {
9132
9247
  return { position, targetView, target }; // indicate the buffer was re-allocated
9133
9248
  }
@@ -9191,6 +9306,10 @@
9191
9306
  }
9192
9307
  }, {
9193
9308
  pack(set, allocateForWrite, pack) {
9309
+ if (this.setAsEmptyObject) {
9310
+ allocateForWrite(0);
9311
+ return pack({})
9312
+ }
9194
9313
  let array = Array.from(set);
9195
9314
  let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0);
9196
9315
  if (this.moreTypes) {
@@ -9371,6 +9490,7 @@
9371
9490
  defaultPackr.pack;
9372
9491
  const REUSE_BUFFER_MODE = 512;
9373
9492
  const RESET_BUFFER_MODE = 1024;
9493
+ const RESERVE_START_SPACE = 2048;
9374
9494
 
9375
9495
  // DEFLATE is a complex format; to read this code, you should probably check the RFC first:
9376
9496
  // https://tools.ietf.org/html/rfc1951
@@ -41204,6 +41324,8 @@ ${svg}
41204
41324
  }
41205
41325
  requirePolygonLayer(lyr);
41206
41326
  var nodes = addIntersectionCuts(dataset, opts);
41327
+ // ignore arcs that don't belong to this layer
41328
+ nodes.setArcFilter(getArcPresenceTest(lyr.shapes, nodes.arcs));
41207
41329
  var mosaicIndex = new MosaicIndex(lyr, nodes, {flat: false});
41208
41330
  var mosaicShapes = mosaicIndex.mosaic;
41209
41331
  var records2;
@@ -42314,6 +42436,8 @@ ${svg}
42314
42436
 
42315
42437
  function createPolygonLayer(lyr, dataset, opts) {
42316
42438
  var nodes = closeUndershoots(lyr, dataset, opts);
42439
+ // ignore arcs that don't belong to this layer
42440
+ nodes.setArcFilter(getArcPresenceTest(lyr.shapes, nodes.arcs));
42317
42441
  var data = buildPolygonMosaic(nodes);
42318
42442
  return {
42319
42443
  geometry_type: 'polygon',
@@ -45304,7 +45428,7 @@ ${svg}
45304
45428
  });
45305
45429
  }
45306
45430
 
45307
- var version = "0.6.68";
45431
+ var version = "0.6.70";
45308
45432
 
45309
45433
  // Parse command line args into commands and run them
45310
45434
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.6.68",
3
+ "version": "0.6.70",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -57,7 +57,7 @@
57
57
  "idb-keyval": "^6.2.0",
58
58
  "kdbush": "^3.0.0",
59
59
  "mproj": "0.0.37",
60
- "msgpackr": "^1.8.5",
60
+ "msgpackr": "^1.10.1",
61
61
  "opn": "^5.3.0",
62
62
  "rw": "~1.3.3",
63
63
  "sync-request": "5.0.0",
@@ -2417,7 +2417,7 @@
2417
2417
  // Show a popup error message, then throw an error
2418
2418
  var msg = GUI.formatMessageArgs(arguments);
2419
2419
  gui.alert(msg);
2420
- throw new Error(msg);
2420
+ throw new internal.UserError(msg);
2421
2421
  }
2422
2422
 
2423
2423
  function error() {
@@ -3882,7 +3882,11 @@
3882
3882
  } else {
3883
3883
  // stack seems to change if Error is logged directly
3884
3884
  console.error(err.stack);
3885
- gui.alert('Export failed for an unknown reason');
3885
+ var msg = 'Export failed for an unknown reason';
3886
+ if (err.name == 'UserError') {
3887
+ msg = err.message;
3888
+ }
3889
+ gui.alert(msg, 'Export failed');
3886
3890
  }
3887
3891
  }).finally(function() {
3888
3892
  gui.clearProgressMessage();
@@ -8827,11 +8831,11 @@
8827
8831
  return textNode.childNodes.length > 1;
8828
8832
  }
8829
8833
 
8830
- function toggleTextAlign(textNode, rec) {
8831
- var curr = rec['text-anchor'] || 'middle';
8832
- var value = curr == 'middle' && 'start' || curr == 'start' && 'end' || 'middle';
8833
- updateTextAnchor(value, textNode, rec);
8834
- }
8834
+ // export function toggleTextAlign(textNode, rec) {
8835
+ // var curr = rec['text-anchor'] || 'middle';
8836
+ // var value = curr == 'middle' && 'start' || curr == 'start' && 'end' || 'middle';
8837
+ // updateTextAnchor(value, textNode, rec);
8838
+ // }
8835
8839
 
8836
8840
  // Set an attribute on a <text> node and any child <tspan> elements
8837
8841
  // (mapshaper's svg labels require tspans to have the same x and dx values
@@ -8863,6 +8867,7 @@
8863
8867
  var rect = textNode.getBoundingClientRect();
8864
8868
  var labelCenterX = rect.left - svg.getBoundingClientRect().left + rect.width / 2;
8865
8869
  var xpct = (labelCenterX - p[0]) / rect.width; // offset of label center from anchor center
8870
+
8866
8871
  var value = xpct < -0.25 && 'end' || xpct > 0.25 && 'start' || 'middle';
8867
8872
  updateTextAnchor(value, textNode, rec);
8868
8873
  }
@@ -8874,7 +8879,6 @@
8874
8879
  var curr = rec['text-anchor'] || 'middle';
8875
8880
  var xshift = 0;
8876
8881
 
8877
- // console.log("anchor() curr:", curr, "xpct:", xpct, "left:", rect.left, "anchorX:", anchorX, "targ:", targ, "dx:", xshift)
8878
8882
  if (curr == 'middle' && value == 'end' || curr == 'start' && value == 'middle') {
8879
8883
  xshift = width / 2;
8880
8884
  } else if (curr == 'middle' && value == 'start' || curr == 'end' && value == 'middle') {
@@ -8886,16 +8890,29 @@
8886
8890
  }
8887
8891
  if (xshift) {
8888
8892
  rec['text-anchor'] = value;
8889
- applyDelta(rec, 'dx', Math.round(xshift));
8893
+ applyDelta(rec, 'dx', xshift / getScaleAttribute(textNode));
8890
8894
  }
8891
8895
  }
8892
8896
 
8893
- // handle either numeric strings or numbers in fields
8897
+ function getScaleAttribute(node) {
8898
+ // this is fragile, consider passing in the value of <MapExtent>.getSymbolScale()
8899
+ var transform = node.getAttribute('transform') ||
8900
+ node.parentNode.getAttribute('transform'); // compound label puts it here
8901
+ var match = /scale\(([^)]+)\)/.exec(transform || '');
8902
+ return match ? parseFloat(match[1]) : 1;
8903
+ }
8904
+
8905
+ // handle either numeric strings or numbers in record
8894
8906
  function applyDelta(rec, key, delta) {
8895
8907
  var currVal = rec[key];
8896
- var isString = utils$1.isString(currVal);
8897
8908
  var newVal = (+currVal + delta) || 0;
8898
- rec[key] = isString ? String(newVal) : newVal;
8909
+ updateNumber(rec, key, newVal);
8910
+ }
8911
+
8912
+ // handle either numeric strings or numbers in record
8913
+ function updateNumber(rec, key, num) {
8914
+ var isString = utils$1.isString(rec[key]);
8915
+ rec[key] = isString ? String(num) : num;
8899
8916
  }
8900
8917
 
8901
8918
  function initLabelDragging(gui, ext, hit) {
@@ -8909,9 +8926,9 @@
8909
8926
 
8910
8927
  hit.on('dragstart', function(e) {
8911
8928
  if (!active(e)) return;
8912
- var textNode = getTextTarget3(e);
8929
+ var symNode = getSymbolTarget(e);
8913
8930
  var table = hit.getTargetDataTable();
8914
- if (!textNode || !table) {
8931
+ if (!symNode || !table) {
8915
8932
  activeId = -1;
8916
8933
  return false;
8917
8934
  }
@@ -8927,18 +8944,22 @@
8927
8944
  error$1("Mismatched hit ids:", e.id, activeId);
8928
8945
  }
8929
8946
  var scale = ext.getSymbolScale() || 1;
8930
- var textNode;
8947
+ var symNode, textNode;
8931
8948
  applyDelta(activeRecord, 'dx', e.dx / scale);
8932
8949
  applyDelta(activeRecord, 'dy', e.dy / scale);
8933
- textNode = getTextTarget3(e);
8934
- if (!isMultilineLabel(textNode)) {
8935
- // update anchor position of single-line labels based on label position
8936
- // relative to anchor point, for better placement when eventual display font is
8937
- // different from mapshaper's font.
8938
- autoUpdateTextAnchor(textNode, activeRecord, getDisplayCoordsById(activeId, hit.getHitTarget().layer, ext));
8939
- }
8940
- // updateSymbol(targetTextNode, activeRecord);
8941
- updateSymbol2(textNode, activeRecord, activeId);
8950
+ symNode = getSymbolTarget(e);
8951
+ textNode = getTextNode(symNode);
8952
+ // update anchor position of labels based on label position relative
8953
+ // to anchor point, for better placement when eventual display font is
8954
+ // different from mapshaper's font.
8955
+ // if (!isMultilineLabel(textNode)) {
8956
+ autoUpdateTextAnchor(textNode, activeRecord, getDisplayCoordsById(activeId, hit.getHitTarget().layer, ext));
8957
+ // }
8958
+ updateNumber(activeRecord, 'dx', internal.roundToDigits(+activeRecord.dx, 3));
8959
+ updateNumber(activeRecord, 'dy', internal.roundToDigits(+activeRecord.dy, 3));
8960
+ updateTextNode(textNode, activeRecord);
8961
+ // updateSymbolNode(symNode, activeRecord, activeId);
8962
+ gui.dispatchEvent('popup-needs-refresh');
8942
8963
  });
8943
8964
 
8944
8965
  hit.on('dragend', function(e) {
@@ -8962,32 +8983,37 @@
8962
8983
  return coords[0];
8963
8984
  }
8964
8985
 
8965
- function getTextTarget3(e) {
8986
+ function getSymbolTarget(e) {
8966
8987
  if (e.id > -1 === false || !e.container) return null;
8967
8988
  return getSymbolNodeById(e.id, e.container);
8968
8989
  }
8969
8990
 
8991
+ function getTextNode(symNode) {
8992
+ if (symNode.tagName == 'text') return symNode;
8993
+ return symNode.querySelector('text');
8994
+ }
8995
+
8970
8996
  function getSymbolNodeById(id, parent) {
8971
8997
  // TODO: optimize selector
8972
8998
  var sel = '[data-id="' + id + '"]';
8973
8999
  return parent.querySelector(sel);
8974
9000
  }
8975
9001
 
8976
- function getTextTarget2(e) {
8977
- var el = e && e.targetSymbol || null;
8978
- if (el && el.tagName == 'tspan') {
8979
- el = el.parentNode;
8980
- }
8981
- return el && el.tagName == 'text' ? el : null;
8982
- }
9002
+ // function getTextTarget2(e) {
9003
+ // var el = e && e.targetSymbol || null;
9004
+ // if (el && el.tagName == 'tspan') {
9005
+ // el = el.parentNode;
9006
+ // }
9007
+ // return el && el.tagName == 'text' ? el : null;
9008
+ // }
8983
9009
 
8984
- function getTextTarget(e) {
8985
- var el = e.target;
8986
- if (el.tagName == 'tspan') {
8987
- el = el.parentNode;
8988
- }
8989
- return el.tagName == 'text' ? el : null;
8990
- }
9010
+ // function getTextTarget(e) {
9011
+ // var el = e.target;
9012
+ // if (el.tagName == 'tspan') {
9013
+ // el = el.parentNode;
9014
+ // }
9015
+ // return el.tagName == 'text' ? el : null;
9016
+ // }
8991
9017
 
8992
9018
  function getLabelRecordById(id) {
8993
9019
  var table = hit.getTargetDataTable();
@@ -9006,7 +9032,7 @@
9006
9032
  }
9007
9033
 
9008
9034
  // update symbol by setting attributes
9009
- function updateSymbol(node, d) {
9035
+ function updateTextNode(node, d) {
9010
9036
  var a = d['text-anchor'];
9011
9037
  if (a) node.setAttribute('text-anchor', a);
9012
9038
  setMultilineAttribute(node, 'dx', d.dx || 0);
@@ -9014,7 +9040,8 @@
9014
9040
  }
9015
9041
 
9016
9042
  // update symbol by re-rendering it
9017
- function updateSymbol2(node, d, id) {
9043
+ // fails when symbol includes a dot (<g><circle/><text/></g> structure)
9044
+ function updateSymbolNode(node, d, id) {
9018
9045
  var o = internal.svg.renderStyledLabel(d); // TODO: symbol support
9019
9046
  var activeLayer = hit.getHitTarget().layer;
9020
9047
  var xy = activeLayer.shapes[id][0];
@@ -9027,8 +9054,6 @@
9027
9054
  g.innerHTML = internal.svg.stringify(o);
9028
9055
  node2 = g.firstChild;
9029
9056
  node.parentNode.replaceChild(node2, node);
9030
- gui.dispatchEvent('popup-needs-refresh');
9031
- return node2;
9032
9057
  }
9033
9058
  }
9034
9059
 
@@ -9427,15 +9452,16 @@
9427
9452
  var styler = function(style, i) {
9428
9453
  var defaultStyle = i === topIdx ? topStyle : outlineStyle;
9429
9454
  if (baseStyle.styler) {
9430
- Object.assign(style, baseStyle);
9431
- baseStyle.styler(style, i);
9455
+ // TODO: render default stroke widths without scaling
9456
+ // (will need to pass symbol scale to the styler function)
9457
+ style.strokeWidth = defaultStyle.strokeWidth;
9458
+ baseStyle.styler(style, i); // get styled stroke width (if set)
9432
9459
  style.strokeColor = defaultStyle.strokeColor;
9433
9460
  style.fillColor = defaultStyle.fillColor;
9434
9461
  } else {
9435
9462
  Object.assign(style, defaultStyle);
9436
9463
  }
9437
9464
  };
9438
- // var baseStyle = getDefaultStyle(baseLyr, selectionStyles[geomType]);
9439
9465
  var baseStyle = getActiveLayerStyle(baseLyr, opts);
9440
9466
  var outlineStyle = getDefaultStyle(baseLyr, selectionStyles[geomType]);
9441
9467
  var topStyle;
@@ -10308,7 +10334,9 @@
10308
10334
  for (var i=0; i<shapes.length; i++) {
10309
10335
  shp = shapes[i];
10310
10336
  if (!shp || filter && !filter(shp)) continue;
10311
- if (styler) styler(style, i);
10337
+ if (styler) {
10338
+ styler(style, i);
10339
+ }
10312
10340
  if (style.overlay || style.opacity < 1 || style.fillOpacity < 1 || style.strokeOpacity < 1 || style.fillEffect) {
10313
10341
  // don't batch shapes with opacity, in case they overlap
10314
10342
  drawPaths([shp], startPath, draw, style);
@@ -11738,6 +11766,7 @@
11738
11766
  }
11739
11767
 
11740
11768
  _activeLyr = getDisplayLayer(e.layer, e.dataset, getDisplayOptions());
11769
+ _activeLyr.style = getActiveLayerStyle(_activeLyr.layer, getGlobalStyleOptions());
11741
11770
  _activeLyr.active = true;
11742
11771
 
11743
11772
  if (popupCanStayOpen(e.flags)) {
@@ -11841,7 +11870,12 @@
11841
11870
  }
11842
11871
 
11843
11872
  function calcFullBounds() {
11844
- var b = getContentLayerBounds();
11873
+ var b;
11874
+ if (isPreviewView()) {
11875
+ b = new Bounds(getFrameData().bbox);
11876
+ } else {
11877
+ b = getContentLayerBounds();
11878
+ }
11845
11879
 
11846
11880
  // add margin
11847
11881
  // use larger margin for small sizes
@@ -11868,7 +11902,7 @@
11868
11902
  }
11869
11903
 
11870
11904
  function isTableView() {
11871
- return !isPreviewView() && !!_activeLyr.tabular;
11905
+ return !!_activeLyr.tabular;
11872
11906
  }
11873
11907
 
11874
11908
  function findFrameLayer() {
@@ -11879,8 +11913,7 @@
11879
11913
 
11880
11914
  // Preview view: symbols are scaled based on display size of frame layer
11881
11915
  function isPreviewView() {
11882
- var data = getFrameData();
11883
- return !!data;
11916
+ return !isTableView() && !!getFrameData();
11884
11917
  }
11885
11918
 
11886
11919
  function getFrameData() {
@@ -11919,7 +11952,9 @@
11919
11952
 
11920
11953
  function getContentLayers() {
11921
11954
  var layers = getVisibleMapLayers();
11922
- if (isTableView()) return findActiveLayer(layers);
11955
+ if (isTableView()) {
11956
+ return findActiveLayer(layers);
11957
+ }
11923
11958
  return layers.filter(function(o) {
11924
11959
  return !!o.geographic;
11925
11960
  });
package/www/mapshaper.js CHANGED
@@ -6661,11 +6661,16 @@
6661
6661
  nn = arcData.nn,
6662
6662
  xx = arcData.xx,
6663
6663
  yy = arcData.yy,
6664
- nodeData;
6664
+ nodeData,
6665
+ globalFilter;
6665
6666
 
6666
6667
  // Accessor function for arcs
6667
6668
  Object.defineProperty(this, 'arcs', {value: arcs});
6668
6669
 
6670
+ this.setArcFilter = function(f) {
6671
+ globalFilter = f;
6672
+ };
6673
+
6669
6674
  this.toArray = function() {
6670
6675
  var chains = getNodeChains(),
6671
6676
  flags = new Uint8Array(chains.length),
@@ -6744,15 +6749,19 @@
6744
6749
  // Returned ids lead into the node (as opposed to outwards from it)
6745
6750
  // An optional filter function receives the directed id (positive or negative)
6746
6751
  // of each connected arc and excludes arcs for which the filter returns false.
6747
- // The filter is also applied to the initial arc; if false, no arcs are returned.
6752
+ // // removed: The filter is also applied to the initial arc; if false, no arcs are returned.
6748
6753
  //
6749
- this.getConnectedArcs = function(arcId, filter) {
6754
+ this.getConnectedArcs = function(arcId, localFilter) {
6750
6755
  var ids = [];
6751
- var filtered = !!filter;
6752
6756
  var nextId = nextConnectedArc(arcId);
6753
- if (filtered && !filter(arcId)) ;
6757
+ // kludge: return empty result if arc fails global test
6758
+ // ... applying the local filter causes tests to fail
6759
+ if (globalFilter && !globalFilter(arcId)) {
6760
+ return [];
6761
+ }
6754
6762
  while (nextId != arcId) {
6755
- if (!filtered || filter(nextId)) {
6763
+ // if (!filtered || filter && filter(nextId) ) {
6764
+ if ((!localFilter || localFilter(nextId)) && (!globalFilter || globalFilter(nextId))) {
6756
6765
  ids.push(nextId);
6757
6766
  }
6758
6767
  nextId = nextConnectedArc(nextId);
@@ -7415,6 +7424,8 @@
7415
7424
  return this ? this.unpack(source, options) : Unpackr.prototype.unpack.call(defaultOptions, source, options)
7416
7425
  })
7417
7426
  }
7427
+ if (!source.buffer && source.constructor === ArrayBuffer)
7428
+ source = typeof Buffer !== 'undefined' ? Buffer.from(source) : new Uint8Array(source);
7418
7429
  if (typeof options === 'object') {
7419
7430
  srcEnd = options.end || source.length;
7420
7431
  position$1 = options.start || 0;
@@ -7460,10 +7471,10 @@
7460
7471
  let size = source.length;
7461
7472
  let value = this ? this.unpack(source, size) : defaultUnpackr.unpack(source, size);
7462
7473
  if (forEach) {
7463
- if (forEach(value) === false) return;
7474
+ if (forEach(value, lastPosition, position$1) === false) return;
7464
7475
  while(position$1 < size) {
7465
7476
  lastPosition = position$1;
7466
- if (forEach(checkedRead()) === false) {
7477
+ if (forEach(checkedRead(), lastPosition, position$1) === false) {
7467
7478
  return
7468
7479
  }
7469
7480
  }
@@ -7511,8 +7522,8 @@
7511
7522
  }
7512
7523
  return this.structures = loadedStructures
7513
7524
  }
7514
- decode(source, end) {
7515
- return this.unpack(source, end)
7525
+ decode(source, options) {
7526
+ return this.unpack(source, options)
7516
7527
  }
7517
7528
  }
7518
7529
  function checkedRead(options) {
@@ -7535,6 +7546,10 @@
7535
7546
  position$1 = bundledStrings$1.postBundlePosition;
7536
7547
  bundledStrings$1 = null;
7537
7548
  }
7549
+ if (sequentialMode)
7550
+ // we only need to restore the structures if there was an error, but if we completed a read,
7551
+ // we can clear this out and keep the structures we read
7552
+ currentStructures.restoreStructures = null;
7538
7553
 
7539
7554
  if (position$1 == srcEnd) {
7540
7555
  // finished reading this source, cleanup references
@@ -7548,7 +7563,13 @@
7548
7563
  // over read
7549
7564
  throw new Error('Unexpected end of MessagePack data')
7550
7565
  } else if (!sequentialMode) {
7551
- throw new Error('Data read, but end of buffer not reached ' + JSON.stringify(result).slice(0, 100))
7566
+ let jsonView;
7567
+ try {
7568
+ jsonView = JSON.stringify(result, (_, value) => typeof value === "bigint" ? `${value}n` : value).slice(0, 100);
7569
+ } catch(error) {
7570
+ jsonView = '(JSON view not available ' + error + ')';
7571
+ }
7572
+ throw new Error('Data read, but end of buffer not reached ' + jsonView)
7552
7573
  }
7553
7574
  // else more to read, but we are reading sequentially, so don't clear source yet
7554
7575
  return result
@@ -7704,6 +7725,9 @@
7704
7725
  value += dataView.getUint32(position$1 + 4);
7705
7726
  } else if (currentUnpackr.int64AsType === 'string') {
7706
7727
  value = dataView.getBigUint64(position$1).toString();
7728
+ } else if (currentUnpackr.int64AsType === 'auto') {
7729
+ value = dataView.getBigUint64(position$1);
7730
+ if (value<=BigInt(2)<<BigInt(52)) value=Number(value);
7707
7731
  } else
7708
7732
  value = dataView.getBigUint64(position$1);
7709
7733
  position$1 += 8;
@@ -7726,6 +7750,9 @@
7726
7750
  value += dataView.getUint32(position$1 + 4);
7727
7751
  } else if (currentUnpackr.int64AsType === 'string') {
7728
7752
  value = dataView.getBigInt64(position$1).toString();
7753
+ } else if (currentUnpackr.int64AsType === 'auto') {
7754
+ value = dataView.getBigInt64(position$1);
7755
+ if (value>=BigInt(-2)<<BigInt(52)&&value<=BigInt(2)<<BigInt(52)) value=Number(value);
7729
7756
  } else
7730
7757
  value = dataView.getBigInt64(position$1);
7731
7758
  position$1 += 8;
@@ -8183,7 +8210,7 @@
8183
8210
  return readFixedString(length)
8184
8211
  } else { // not cacheable, go back and do a standard read
8185
8212
  position$1--;
8186
- return read().toString()
8213
+ return asSafeString(read())
8187
8214
  }
8188
8215
  let key = ((length << 5) ^ (length > 1 ? dataView.getUint16(position$1) : length > 0 ? src[position$1] : 0)) & 0xfff;
8189
8216
  let entry = keyCache[key];
@@ -8235,16 +8262,25 @@
8235
8262
  return entry.string = readFixedString(length)
8236
8263
  }
8237
8264
 
8265
+ function asSafeString(property) {
8266
+ if (typeof property === 'string') return property;
8267
+ if (typeof property === 'number') return property.toString();
8268
+ throw new Error('Invalid property type for record', typeof property);
8269
+ }
8238
8270
  // the registration of the record definition extension (as "r")
8239
8271
  const recordDefinition = (id, highByte) => {
8240
- let structure = read().map(property => property.toString()); // ensure that all keys are strings and that the array is mutable
8272
+ let structure = read().map(asSafeString); // ensure that all keys are strings and
8273
+ // that the array is mutable
8241
8274
  let firstByte = id;
8242
8275
  if (highByte !== undefined) {
8243
8276
  id = id < 32 ? -((highByte << 5) + id) : ((highByte << 5) + id);
8244
8277
  structure.highByte = highByte;
8245
8278
  }
8246
8279
  let existingStructure = currentStructures[id];
8247
- if (existingStructure && existingStructure.isShared) {
8280
+ // If it is a shared structure, we need to restore any changes after reading.
8281
+ // Also in sequential mode, we may get incomplete reads and thus errors, and we need to restore
8282
+ // to the state prior to an incomplete read in order to properly resume.
8283
+ if (existingStructure && (existingStructure.isShared || sequentialMode)) {
8248
8284
  (currentStructures.restoreStructures || (currentStructures.restoreStructures = []))[id] = existingStructure;
8249
8285
  }
8250
8286
  currentStructures[id] = structure;
@@ -8254,13 +8290,26 @@
8254
8290
  currentExtensions[0] = () => {}; // notepack defines extension 0 to mean undefined, so use that as the default here
8255
8291
  currentExtensions[0].noBuffer = true;
8256
8292
 
8293
+ currentExtensions[0x42] = (data) => {
8294
+ // decode bigint
8295
+ let length = data.length;
8296
+ let value = BigInt(data[0] & 0x80 ? data[0] - 0x100 : data[0]);
8297
+ for (let i = 1; i < length; i++) {
8298
+ value <<= 8n;
8299
+ value += BigInt(data[i]);
8300
+ }
8301
+ return value;
8302
+ };
8303
+
8304
+ let errors = { Error, TypeError, ReferenceError };
8257
8305
  currentExtensions[0x65] = () => {
8258
8306
  let data = read();
8259
- return (globalThis[data[0]] || Error)(data[1])
8307
+ return (errors[data[0]] || Error)(data[1])
8260
8308
  };
8261
8309
 
8262
8310
  currentExtensions[0x69] = (data) => {
8263
8311
  // id extension (for structured clones)
8312
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
8264
8313
  let id = dataView.getUint32(position$1 - 4);
8265
8314
  if (!referenceMap)
8266
8315
  referenceMap = new Map();
@@ -8284,6 +8333,7 @@
8284
8333
 
8285
8334
  currentExtensions[0x70] = (data) => {
8286
8335
  // pointer extension (for structured clones)
8336
+ if (currentUnpackr.structuredClone === false) throw new Error('Structured clone extension is disabled')
8287
8337
  let id = dataView.getUint32(position$1 - 4);
8288
8338
  let refEntry = referenceMap.get(id);
8289
8339
  refEntry.used = true;
@@ -8294,13 +8344,14 @@
8294
8344
 
8295
8345
  const typedArrays = ['Int8','Uint8','Uint8Clamped','Int16','Uint16','Int32','Uint32','Float32','Float64','BigInt64','BigUint64'].map(type => type + 'Array');
8296
8346
 
8347
+ let glbl = typeof globalThis === 'object' ? globalThis : window;
8297
8348
  currentExtensions[0x74] = (data) => {
8298
8349
  let typeCode = data[0];
8299
8350
  let typedArrayName = typedArrays[typeCode];
8300
8351
  if (!typedArrayName)
8301
8352
  throw new Error('Could not find typed array for code ' + typeCode)
8302
8353
  // we have to always slice/copy here to get a new ArrayBuffer that is word/byte aligned
8303
- return new globalThis[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
8354
+ return new glbl[typedArrayName](Uint8Array.prototype.slice.call(data, 1).buffer)
8304
8355
  };
8305
8356
  currentExtensions[0x78] = () => {
8306
8357
  let data = read();
@@ -8465,6 +8516,7 @@
8465
8516
  } else
8466
8517
  position = (position + 7) & 0x7ffffff8; // Word align to make any future copying of this buffer faster
8467
8518
  start = position;
8519
+ if (encodeOptions & RESERVE_START_SPACE) position += (encodeOptions & 0xff);
8468
8520
  referenceMap = packr.structuredClone ? new Map() : null;
8469
8521
  if (packr.bundleStrings && typeof value !== 'string') {
8470
8522
  bundledStrings = [];
@@ -8506,8 +8558,9 @@
8506
8558
  }
8507
8559
  if (hasSharedUpdate)
8508
8560
  hasSharedUpdate = false;
8561
+ let encodingError;
8509
8562
  try {
8510
- if (packr.randomAccessStructure && value.constructor && value.constructor === Object)
8563
+ if (packr.randomAccessStructure && value && value.constructor && value.constructor === Object)
8511
8564
  writeStruct(value);
8512
8565
  else
8513
8566
  pack(value);
@@ -8556,42 +8609,51 @@
8556
8609
  return target
8557
8610
  }
8558
8611
  return target.subarray(start, position) // position can change if we call pack again in saveStructures, so we get the buffer now
8612
+ } catch(error) {
8613
+ encodingError = error;
8614
+ throw error;
8559
8615
  } finally {
8560
8616
  if (structures) {
8561
- if (serializationsSinceTransitionRebuild < 10)
8562
- serializationsSinceTransitionRebuild++;
8563
- let sharedLength = structures.sharedLength || 0;
8564
- if (structures.length > sharedLength)
8565
- structures.length = sharedLength;
8566
- if (transitionsCount > 10000) {
8567
- // force a rebuild occasionally after a lot of transitions so it can get cleaned up
8568
- structures.transitions = null;
8569
- serializationsSinceTransitionRebuild = 0;
8570
- transitionsCount = 0;
8571
- if (recordIdsToRemove.length > 0)
8572
- recordIdsToRemove = [];
8573
- } else if (recordIdsToRemove.length > 0 && !isSequential) {
8574
- for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
8575
- recordIdsToRemove[i][RECORD_SYMBOL] = 0;
8576
- }
8577
- recordIdsToRemove = [];
8578
- }
8617
+ resetStructures();
8579
8618
  if (hasSharedUpdate && packr.saveStructures) {
8619
+ let sharedLength = structures.sharedLength || 0;
8580
8620
  // we can't rely on start/end with REUSE_BUFFER_MODE since they will (probably) change when we save
8581
8621
  let returnBuffer = target.subarray(start, position);
8582
8622
  let newSharedData = prepareStructures(structures, packr);
8583
- if (packr.saveStructures(newSharedData, newSharedData.isCompatible) === false) {
8584
- // get updated structures and try again if the update failed
8585
- return packr.pack(value)
8623
+ if (!encodingError) { // TODO: If there is an encoding error, should make the structures as uninitialized so they get rebuilt next time
8624
+ if (packr.saveStructures(newSharedData, newSharedData.isCompatible) === false) {
8625
+ // get updated structures and try again if the update failed
8626
+ return packr.pack(value, encodeOptions)
8627
+ }
8628
+ packr.lastNamedStructuresLength = sharedLength;
8629
+ return returnBuffer
8586
8630
  }
8587
- packr.lastNamedStructuresLength = sharedLength;
8588
- return returnBuffer
8589
8631
  }
8590
8632
  }
8591
8633
  if (encodeOptions & RESET_BUFFER_MODE)
8592
8634
  position = start;
8593
8635
  }
8594
8636
  };
8637
+ const resetStructures = () => {
8638
+ if (serializationsSinceTransitionRebuild < 10)
8639
+ serializationsSinceTransitionRebuild++;
8640
+ let sharedLength = structures.sharedLength || 0;
8641
+ if (structures.length > sharedLength && !isSequential)
8642
+ structures.length = sharedLength;
8643
+ if (transitionsCount > 10000) {
8644
+ // force a rebuild occasionally after a lot of transitions so it can get cleaned up
8645
+ structures.transitions = null;
8646
+ serializationsSinceTransitionRebuild = 0;
8647
+ transitionsCount = 0;
8648
+ if (recordIdsToRemove.length > 0)
8649
+ recordIdsToRemove = [];
8650
+ } else if (recordIdsToRemove.length > 0 && !isSequential) {
8651
+ for (let i = 0, l = recordIdsToRemove.length; i < l; i++) {
8652
+ recordIdsToRemove[i][RECORD_SYMBOL] = 0;
8653
+ }
8654
+ recordIdsToRemove = [];
8655
+ }
8656
+ };
8595
8657
  const packArray = (value) => {
8596
8658
  var length = value.length;
8597
8659
  if (length < 0x10) {
@@ -8769,7 +8831,7 @@
8769
8831
  targetView.setFloat64(position, value);
8770
8832
  position += 8;
8771
8833
  }
8772
- } else if (type === 'object') {
8834
+ } else if (type === 'object' || type === 'function') {
8773
8835
  if (!value)
8774
8836
  target[position++] = 0xc0;
8775
8837
  else {
@@ -8794,21 +8856,24 @@
8794
8856
  } else if (constructor === Array) {
8795
8857
  packArray(value);
8796
8858
  } else if (constructor === Map) {
8797
- length = value.size;
8798
- if (length < 0x10) {
8799
- target[position++] = 0x80 | length;
8800
- } else if (length < 0x10000) {
8801
- target[position++] = 0xde;
8802
- target[position++] = length >> 8;
8803
- target[position++] = length & 0xff;
8804
- } else {
8805
- target[position++] = 0xdf;
8806
- targetView.setUint32(position, length);
8807
- position += 4;
8808
- }
8809
- for (let [ key, entryValue ] of value) {
8810
- pack(key);
8811
- pack(entryValue);
8859
+ if (this.mapAsEmptyObject) target[position++] = 0x80;
8860
+ else {
8861
+ length = value.size;
8862
+ if (length < 0x10) {
8863
+ target[position++] = 0x80 | length;
8864
+ } else if (length < 0x10000) {
8865
+ target[position++] = 0xde;
8866
+ target[position++] = length >> 8;
8867
+ target[position++] = length & 0xff;
8868
+ } else {
8869
+ target[position++] = 0xdf;
8870
+ targetView.setUint32(position, length);
8871
+ position += 4;
8872
+ }
8873
+ for (let [key, entryValue] of value) {
8874
+ pack(key);
8875
+ pack(entryValue);
8876
+ }
8812
8877
  }
8813
8878
  } else {
8814
8879
  for (let i = 0, l = extensions.length; i < l; i++) {
@@ -8871,6 +8936,18 @@
8871
8936
  if (Array.isArray(value)) {
8872
8937
  packArray(value);
8873
8938
  } else {
8939
+ // use this as an alternate mechanism for expressing how to serialize
8940
+ if (value.toJSON) {
8941
+ const json = value.toJSON();
8942
+ // if for some reason value.toJSON returns itself it'll loop forever
8943
+ if (json !== value)
8944
+ return pack(json)
8945
+ }
8946
+
8947
+ // if there is a writeFunction, use it, otherwise just encode as undefined
8948
+ if (type === 'function')
8949
+ return pack(this.writeFunction && this.writeFunction(value));
8950
+
8874
8951
  // no extension found, write as object
8875
8952
  writeObject(value, !value.hasOwnProperty); // if it doesn't have hasOwnProperty, don't do hasOwnProperty checks
8876
8953
  }
@@ -8892,8 +8969,26 @@
8892
8969
  if (this.largeBigIntToFloat) {
8893
8970
  target[position++] = 0xcb;
8894
8971
  targetView.setFloat64(position, Number(value));
8972
+ } else if (this.useBigIntExtension && value < 2n**(1023n) && value > -(2n**(1023n))) {
8973
+ target[position++] = 0xc7;
8974
+ position++;
8975
+ target[position++] = 0x42; // "B" for BigInt
8976
+ let bytes = [];
8977
+ let alignedSign;
8978
+ do {
8979
+ let byte = value & 0xffn;
8980
+ alignedSign = (byte & 0x80n) === (value < 0n ? 0x80n : 0n);
8981
+ bytes.push(byte);
8982
+ value >>= 8n;
8983
+ } while (!((value === 0n || value === -1n) && alignedSign));
8984
+ target[position-2] = bytes.length;
8985
+ for (let i = bytes.length; i > 0;) {
8986
+ target[position++] = Number(bytes[--i]);
8987
+ }
8988
+ return
8895
8989
  } else {
8896
- throw new RangeError(value + ' was too large to fit in MessagePack 64-bit integer format, set largeBigIntToFloat to convert to float-64')
8990
+ throw new RangeError(value + ' was too large to fit in MessagePack 64-bit integer format, use' +
8991
+ ' useBigIntExtension or set largeBigIntToFloat to convert to float-64')
8897
8992
  }
8898
8993
  }
8899
8994
  position += 8;
@@ -8905,14 +9000,12 @@
8905
9000
  target[position++] = 0;
8906
9001
  target[position++] = 0;
8907
9002
  }
8908
- } else if (type === 'function') {
8909
- pack(this.writeFunction && this.writeFunction()); // if there is a writeFunction, use it, otherwise just encode as undefined
8910
9003
  } else {
8911
9004
  throw new Error('Unknown type: ' + type)
8912
9005
  }
8913
9006
  };
8914
9007
 
8915
- const writeObject = this.useRecords === false ? this.variableMapSize ? (object) => {
9008
+ const writePlainObject = (this.variableMapSize || this.coercibleKeyAsNumber) ? (object) => {
8916
9009
  // this method is slightly slower, but generates "preferred serialization" (optimally small for smaller objects)
8917
9010
  let keys = Object.keys(object);
8918
9011
  let length = keys.length;
@@ -8928,9 +9021,19 @@
8928
9021
  position += 4;
8929
9022
  }
8930
9023
  let key;
8931
- for (let i = 0; i < length; i++) {
8932
- pack(key = keys[i]);
8933
- pack(object[key]);
9024
+ if (this.coercibleKeyAsNumber) {
9025
+ for (let i = 0; i < length; i++) {
9026
+ key = keys[i];
9027
+ let num = Number(key);
9028
+ pack(isNaN(num) ? key : num);
9029
+ pack(object[key]);
9030
+ }
9031
+
9032
+ } else {
9033
+ for (let i = 0; i < length; i++) {
9034
+ pack(key = keys[i]);
9035
+ pack(object[key]);
9036
+ }
8934
9037
  }
8935
9038
  } :
8936
9039
  (object, safePrototype) => {
@@ -8947,7 +9050,9 @@
8947
9050
  }
8948
9051
  target[objectOffset++ + start] = size >> 8;
8949
9052
  target[objectOffset + start] = size & 0xff;
8950
- } :
9053
+ };
9054
+
9055
+ const writeRecord = this.useRecords === false ? writePlainObject :
8951
9056
  (options.progressiveRecords && !useTwoByteRecords) ? // this is about 2% faster for highly stable structures, since it only requires one for-in loop (but much more expensive when new structure needs to be written)
8952
9057
  (object, safePrototype) => {
8953
9058
  let nextTransition, transition = structures.transitions || (structures.transitions = Object.create(null));
@@ -9016,9 +9121,18 @@
9016
9121
  }
9017
9122
  // now write the values
9018
9123
  for (let key in object)
9019
- if (safePrototype || object.hasOwnProperty(key))
9124
+ if (safePrototype || object.hasOwnProperty(key)) {
9020
9125
  pack(object[key]);
9126
+ }
9021
9127
  };
9128
+
9129
+ // craete reference to useRecords if useRecords is a function
9130
+ const checkUseRecords = typeof this.useRecords == 'function' && this.useRecords;
9131
+
9132
+ const writeObject = checkUseRecords ? (object, safePrototype) => {
9133
+ checkUseRecords(object) ? writeRecord(object,safePrototype) : writePlainObject(object,safePrototype);
9134
+ } : writeRecord;
9135
+
9022
9136
  const makeRoom = (end) => {
9023
9137
  let newSize;
9024
9138
  if (end > 0x1000000) {
@@ -9122,12 +9236,13 @@
9122
9236
  }
9123
9237
  };
9124
9238
  const writeStruct = (object, safePrototype) => {
9125
- let newPosition = writeStructSlots(object, target, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
9239
+ let newPosition = writeStructSlots(object, target, start, position, structures, makeRoom, (value, newPosition, notifySharedUpdate) => {
9126
9240
  if (notifySharedUpdate)
9127
9241
  return hasSharedUpdate = true;
9128
9242
  position = newPosition;
9129
9243
  let startTarget = target;
9130
9244
  pack(value);
9245
+ resetStructures();
9131
9246
  if (startTarget !== target) {
9132
9247
  return { position, targetView, target }; // indicate the buffer was re-allocated
9133
9248
  }
@@ -9191,6 +9306,10 @@
9191
9306
  }
9192
9307
  }, {
9193
9308
  pack(set, allocateForWrite, pack) {
9309
+ if (this.setAsEmptyObject) {
9310
+ allocateForWrite(0);
9311
+ return pack({})
9312
+ }
9194
9313
  let array = Array.from(set);
9195
9314
  let { target, position} = allocateForWrite(this.moreTypes ? 3 : 0);
9196
9315
  if (this.moreTypes) {
@@ -9371,6 +9490,7 @@
9371
9490
  defaultPackr.pack;
9372
9491
  const REUSE_BUFFER_MODE = 512;
9373
9492
  const RESET_BUFFER_MODE = 1024;
9493
+ const RESERVE_START_SPACE = 2048;
9374
9494
 
9375
9495
  // DEFLATE is a complex format; to read this code, you should probably check the RFC first:
9376
9496
  // https://tools.ietf.org/html/rfc1951
@@ -41204,6 +41324,8 @@ ${svg}
41204
41324
  }
41205
41325
  requirePolygonLayer(lyr);
41206
41326
  var nodes = addIntersectionCuts(dataset, opts);
41327
+ // ignore arcs that don't belong to this layer
41328
+ nodes.setArcFilter(getArcPresenceTest(lyr.shapes, nodes.arcs));
41207
41329
  var mosaicIndex = new MosaicIndex(lyr, nodes, {flat: false});
41208
41330
  var mosaicShapes = mosaicIndex.mosaic;
41209
41331
  var records2;
@@ -42314,6 +42436,8 @@ ${svg}
42314
42436
 
42315
42437
  function createPolygonLayer(lyr, dataset, opts) {
42316
42438
  var nodes = closeUndershoots(lyr, dataset, opts);
42439
+ // ignore arcs that don't belong to this layer
42440
+ nodes.setArcFilter(getArcPresenceTest(lyr.shapes, nodes.arcs));
42317
42441
  var data = buildPolygonMosaic(nodes);
42318
42442
  return {
42319
42443
  geometry_type: 'polygon',
@@ -45304,7 +45428,7 @@ ${svg}
45304
45428
  });
45305
45429
  }
45306
45430
 
45307
- var version = "0.6.68";
45431
+ var version = "0.6.70";
45308
45432
 
45309
45433
  // Parse command line args into commands and run them
45310
45434
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.