mapshaper 0.7.4 → 0.7.5

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,108 +1,5 @@
1
1
  (function () {
2
2
 
3
- var utils = /*#__PURE__*/Object.freeze({
4
- __proto__: null,
5
- get addThousandsSep () { return addThousandsSep; },
6
- get addslashes () { return addslashes; },
7
- get arrayToIndex () { return arrayToIndex; },
8
- get clamp () { return clamp; },
9
- get cleanNumericString () { return cleanNumericString; },
10
- get contains () { return contains; },
11
- get copyElements () { return copyElements; },
12
- get countValues () { return countValues; },
13
- get createBuffer () { return createBuffer; },
14
- get default () { return utils; },
15
- get defaults () { return defaults; },
16
- get difference () { return difference; },
17
- get endsWith () { return endsWith; },
18
- get every () { return every; },
19
- get expandoBuffer () { return expandoBuffer; },
20
- get extend () { return extend; },
21
- get extendBuffer () { return extendBuffer; },
22
- get find () { return find; },
23
- get findMedian () { return findMedian; },
24
- get findQuantile () { return findQuantile; },
25
- get findRankByValue () { return findRankByValue; },
26
- get findStringPrefix () { return findStringPrefix; },
27
- get findValueByPct () { return findValueByPct; },
28
- get findValueByRank () { return findValueByRank; },
29
- get forEach () { return forEach; },
30
- get forEachProperty () { return forEachProperty; },
31
- get format () { return format; },
32
- get formatDateISO () { return formatDateISO; },
33
- get formatIntlNumber () { return formatIntlNumber; },
34
- get formatNumber () { return formatNumber; },
35
- get formatNumberForDisplay () { return formatNumberForDisplay; },
36
- get formatVersionedName () { return formatVersionedName; },
37
- get formatter () { return formatter; },
38
- get genericSort () { return genericSort; },
39
- get getArrayBounds () { return getArrayBounds; },
40
- get getGenericComparator () { return getGenericComparator; },
41
- get getKeyComparator () { return getKeyComparator; },
42
- get getSortedIds () { return getSortedIds; },
43
- get getUniqueName () { return getUniqueName; },
44
- get groupBy () { return groupBy; },
45
- get htmlEscape () { return htmlEscape; },
46
- get indexOf () { return indexOf; },
47
- get indexOn () { return indexOn; },
48
- get inherit () { return inherit; },
49
- get initializeArray () { return initializeArray; },
50
- get intersection () { return intersection; },
51
- get isArray () { return isArray; },
52
- get isArrayLike () { return isArrayLike; },
53
- get isBoolean () { return isBoolean; },
54
- get isDate () { return isDate; },
55
- get isEven () { return isEven; },
56
- get isFiniteNumber () { return isFiniteNumber; },
57
- get isFunction () { return isFunction; },
58
- get isInteger () { return isInteger; },
59
- get isNonNegNumber () { return isNonNegNumber; },
60
- get isNumber () { return isNumber; },
61
- get isObject () { return isObject; },
62
- get isOdd () { return isOdd; },
63
- get isPromise () { return isPromise; },
64
- get isString () { return isString; },
65
- get isValidNumber () { return isValidNumber; },
66
- get lpad () { return lpad; },
67
- get ltrim () { return ltrim; },
68
- get mean () { return mean; },
69
- get merge () { return merge; },
70
- get mergeNames () { return mergeNames; },
71
- get numToStr () { return numToStr; },
72
- get parseIntlNumber () { return parseIntlNumber; },
73
- get parseNumber () { return parseNumber; },
74
- get parsePercent () { return parsePercent; },
75
- get parseString () { return parseString; },
76
- get pickOne () { return pickOne; },
77
- get pluck () { return pluck; },
78
- get pluralSuffix () { return pluralSuffix; },
79
- get promisify () { return promisify; },
80
- get quicksort () { return quicksort; },
81
- get quicksortPartition () { return quicksortPartition; },
82
- get range () { return range; },
83
- get reduceAsync () { return reduceAsync; },
84
- get regexEscape () { return regexEscape; },
85
- get reorderArray () { return reorderArray; },
86
- get repeat () { return repeat; },
87
- get repeatString () { return repeatString; },
88
- get replaceArray () { return replaceArray; },
89
- get rpad () { return rpad; },
90
- get rtrim () { return rtrim; },
91
- get shuffle () { return shuffle; },
92
- get some () { return some; },
93
- get sortArrayIndex () { return sortArrayIndex; },
94
- get sortOn () { return sortOn; },
95
- get splitLines () { return splitLines; },
96
- get sum () { return sum; },
97
- get toArray () { return toArray; },
98
- get toBuffer () { return toBuffer; },
99
- get trim () { return trim; },
100
- get trimQuotes () { return trimQuotes; },
101
- get uniq () { return uniq; },
102
- get uniqifyNames () { return uniqifyNames; },
103
- get wildcardToRegExp () { return wildcardToRegExp; }
104
- });
105
-
106
3
  var api = window.mapshaper; // assuming mapshaper is in global scope
107
4
  var mapshaper = api,
108
5
  utils$1 = api.utils,
@@ -113,7 +10,7 @@
113
10
  UserError$1 = internal.UserError,
114
11
  message$1 = internal.message, // stop, error and message are overridden in gui-proxy.js
115
12
  stop$1 = internal.stop,
116
- error$1 = internal.error;
13
+ error$2 = internal.error;
117
14
 
118
15
  api.enableLogging();
119
16
 
@@ -232,7 +129,7 @@
232
129
  evt = new EventData(this.type);
233
130
  evt.target = this.target;
234
131
  } else if (evt.target != this.target || evt.type != this.type) {
235
- error$1("[Handler] event target/type have changed.");
132
+ error$2("[Handler] event target/type have changed.");
236
133
  }
237
134
  this.callback.call(this.listener, evt);
238
135
  };
@@ -481,10 +378,10 @@
481
378
  try {
482
379
  els = root.querySelectorAll(selector);
483
380
  } catch (e) {
484
- error$1("Invalid selector:", selector);
381
+ error$2("Invalid selector:", selector);
485
382
  }
486
383
  } else {
487
- error$1("This browser doesn't support CSS query selectors");
384
+ error$2("This browser doesn't support CSS query selectors");
488
385
  }
489
386
  return utils$1.toArray(els);
490
387
  };
@@ -522,7 +419,7 @@
522
419
  };
523
420
 
524
421
  function El(ref) {
525
- if (!ref) error$1("Element() needs a reference");
422
+ if (!ref) error$2("Element() needs a reference");
526
423
  if (ref instanceof El) {
527
424
  return ref;
528
425
  }
@@ -543,7 +440,7 @@
543
440
  } else if (ref.tagName) {
544
441
  node = ref;
545
442
  }
546
- if (!node) error$1("Unmatched element selector:", ref);
443
+ if (!node) error$2("Unmatched element selector:", ref);
547
444
  this.el = node;
548
445
  }
549
446
 
@@ -1087,7 +984,7 @@
1087
984
  }
1088
985
  var val = utils$1.clamp(arg, _min, _max);
1089
986
  if (!_validator(val)) {
1090
- error$1("ClickText#value() invalid value:", arg);
987
+ error$2("ClickText#value() invalid value:", arg);
1091
988
  } else {
1092
989
  _value = val;
1093
990
  }
@@ -4033,7 +3930,7 @@
4033
3930
  slider.on('change', function(e) {
4034
3931
  var pct = fromSliderPct(e.pct);
4035
3932
  text.value(pct);
4036
- pct = utils$1.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
3933
+ pct = internal.parsePercent(text.text()); // use rounded value (for consistency w/ cli)
4037
3934
  onChange(pct);
4038
3935
  });
4039
3936
  slider.on('start', function(e) {
@@ -4280,11 +4177,16 @@
4280
4177
  if (!_isOpen) {
4281
4178
  btn.addClass('active');
4282
4179
  _isOpen = true;
4283
- // use console for messages while open
4180
+ // Route logging output to the in-app console while it's open, so a
4181
+ // user typing CLI commands here sees the results inline -- the same
4182
+ // way a CLI user sees output in their terminal. warn() goes to a
4183
+ // distinct consoleWarn() rather than to the Messages inbox: warnings
4184
+ // emitted by command pipelines should land where the user typed,
4185
+ // not in a separate UI surface they might not notice.
4284
4186
  // TODO: find a solution for logging problem when switching between multiple
4285
4187
  // gui instances with the console open. E.g. console could close
4286
4188
  // when an instance loses focus.
4287
- internal.setLoggingFunctions(consoleMessage, consoleError, consoleStop);
4189
+ internal.setLoggingFunctions(consoleMessage, consoleError, consoleStop, consoleWarn);
4288
4190
  gui.container.addClass('console-open');
4289
4191
  el.show();
4290
4192
  gui.dispatchEvent('resize');
@@ -4682,6 +4584,15 @@
4682
4584
  toLog(msg, 'console-error');
4683
4585
  }
4684
4586
 
4587
+ // Routed from internal.warn() while the console is open. Distinct from
4588
+ // consoleWarning() (which is used for hard-stop errors) so the styling
4589
+ // can differ -- warnings shouldn't read as red "something went wrong",
4590
+ // they're just heads-ups about how the input was interpreted.
4591
+ function consoleWarn() {
4592
+ var msg = GUI.formatMessageArgs(arguments);
4593
+ toLog(msg, 'console-warn');
4594
+ }
4595
+
4685
4596
  function consoleMessage() {
4686
4597
  var msg = GUI.formatMessageArgs(arguments);
4687
4598
  if (internal.loggingEnabled()) {
@@ -4932,7 +4843,7 @@
4932
4843
  });
4933
4844
 
4934
4845
  internal.writeFiles = function() {
4935
- error$1(unsupportedMsg);
4846
+ error$2(unsupportedMsg);
4936
4847
  };
4937
4848
  return;
4938
4849
  }
@@ -7047,436 +6958,168 @@
7047
6958
  // Fall back to browserify's Buffer polyfill
7048
6959
  var B = typeof Buffer != 'undefined' ? Buffer : require$1('buffer').Buffer;
7049
6960
 
7050
- // This module provides a way for multiple jobs to run together asynchronously
7051
- // while keeping job-level context variables (like "defs") separate.
7052
-
7053
- var stash = {};
7054
-
7055
- function stashVar(key, val) {
7056
- if (key in stash) {
7057
- error('Tried to replace a stashed variable:', key);
7058
- }
7059
- stash[key] = val;
6961
+ // We do NOT import from mapshaper-logging here to avoid a circular dependency
6962
+ function error$1() {
6963
+ throw new Error(Array.prototype.slice.call(arguments).join(' '));
7060
6964
  }
7061
6965
 
7062
- function getStashedVar(key) {
7063
- if (key in stash === false) {
7064
- return undefined; // to support running commands in tests
7065
- // error('Tried to read a nonexistent variable from the stash:', key);
7066
- }
7067
- return stash[key];
6966
+ var uniqCount = 0;
6967
+ function getUniqueName(prefix) {
6968
+ return (prefix || "__id_") + (++uniqCount);
7068
6969
  }
7069
6970
 
7070
- function clearStash() {
7071
- stash = {};
6971
+ function isFunction(obj) {
6972
+ return typeof obj == 'function';
7072
6973
  }
7073
6974
 
7074
- var LOGGING = false;
7075
- var STDOUT = false; // use stdout for status messages
7076
- var _error, _stop, _message, _warn;
7077
-
7078
- var _interrupt = function() {
7079
- throw new NonFatalError(formatLogArgs(arguments));
7080
- };
7081
-
7082
- var onceMessages = [];
7083
-
7084
- setLoggingForCLI();
7085
-
7086
- function getLoggingSetter() {
7087
- var e = _error, s = _stop, m = _message, w = _warn;
7088
- return function() {
7089
- setLoggingFunctions(m, e, s, w);
7090
- };
6975
+ function isPromise(arg) {
6976
+ return arg ? isFunction(arg.then) : false;
7091
6977
  }
7092
6978
 
7093
- function setLoggingForCLI() {
7094
- function stop() {
7095
- throw new UserError(formatLogArgs(arguments));
7096
- }
7097
-
7098
- function error() {
7099
- var msg = utils.toArray(arguments).join(' ');
7100
- throw new Error(msg);
7101
- }
7102
-
7103
- function message() {
7104
- logArgs(arguments);
7105
- }
7106
-
7107
- // CLI warning is just a message (GUI behaves differently)
7108
- var warn = message;
7109
-
7110
- setLoggingFunctions(message, error, stop, warn);
6979
+ function isObject(obj) {
6980
+ return obj === Object(obj); // via underscore
7111
6981
  }
7112
6982
 
7113
- function enableLogging() {
7114
- LOGGING = true;
6983
+ function clamp(val, min, max) {
6984
+ return val < min ? min : (val > max ? max : val);
7115
6985
  }
7116
6986
 
7117
- function disableLogging() {
7118
- LOGGING = false;
6987
+ function isArray(obj) {
6988
+ return Array.isArray(obj);
7119
6989
  }
7120
6990
 
7121
- function loggingEnabled() {
7122
- return !!LOGGING;
6991
+ // Is obj a valid number or NaN? (test if obj is type number)
6992
+ function isNumber(obj) {
6993
+ return obj != null && obj.constructor == Number;
7123
6994
  }
7124
6995
 
7125
- // Handle an unexpected condition (internal error)
7126
- function error() {
7127
- _error.apply(null, utils.toArray(arguments));
6996
+ function isValidNumber(val) {
6997
+ return isNumber(val) && !isNaN(val);
7128
6998
  }
7129
6999
 
7130
- // Handle an error caused by invalid input or misuse of API
7131
- function stop() {
7132
- // _stop.apply(null, utils.toArray(arguments));
7133
- _stop.apply(null, messageArgs(arguments));
7000
+ // Similar to isFinite() but does not coerce strings or other types
7001
+ function isFiniteNumber(val) {
7002
+ return isValidNumber(val) && val !== Infinity && val !== -Infinity;
7134
7003
  }
7135
7004
 
7136
- function interrupt() {
7137
- _interrupt.apply(null, utils.toArray(arguments));
7005
+ // This uses type conversion
7006
+ // export function isFiniteNumber(val) {
7007
+ // return val > -Infinity && val < Infinity;
7008
+ // }
7009
+
7010
+ function isNonNegNumber(val) {
7011
+ return isNumber(val) && val >= 0;
7138
7012
  }
7139
7013
 
7140
- // Print a status message
7141
- function message() {
7142
- _message.apply(null, messageArgs(arguments));
7014
+ function isInteger(obj) {
7015
+ return isNumber(obj) && ((obj | 0) === obj);
7143
7016
  }
7144
7017
 
7145
- function warn() {
7146
- _warn.apply(null, messageArgs(arguments));
7018
+ function isEven(obj) {
7019
+ return (obj % 2) === 0;
7147
7020
  }
7148
7021
 
7149
- function warnOnce() {
7150
- var str = formatLogArgs(arguments);
7151
- if (onceMessages.includes(str)) return;
7152
- onceMessages.push(str);
7153
- _warn.apply(null, messageArgs(arguments));
7022
+ function isOdd(obj) {
7023
+ return (obj % 2) === 1;
7154
7024
  }
7155
7025
 
7156
- // A way for the GUI to replace the CLI logging functions
7157
- function setLoggingFunctions(message, error, stop, warn) {
7158
- _message = message;
7159
- _error = error;
7160
- _stop = stop;
7161
- _warn = warn;
7026
+ function isString(obj) {
7027
+ return obj != null && obj.toString === String.prototype.toString;
7028
+ // TODO: replace w/ something better.
7162
7029
  }
7163
7030
 
7164
- // get detailed error information from error stack (if available)
7165
- // Example stack string (Node.js):
7166
- /*
7167
- /Users/someuser/somescript.js:226
7168
- opacity: Math.round(weight * 5 / 5 // 0.2 0.4 0.6 etc
7169
- ^
7031
+ function isDate(obj) {
7032
+ return !!obj && obj.getTime === Date.prototype.getTime;
7033
+ }
7170
7034
 
7171
- SyntaxError: missing ) after argument list
7172
- at internalCompileFunction (node:internal/vm:73:18)
7173
- at wrapSafe (node:internal/modules/cjs/loader:1149:20)
7174
- at Module._compile (node:internal/modules/cjs/loader:1190:27)
7175
- ...
7176
- */
7177
- function getErrorDetail(e) {
7178
- var parts = (typeof e.stack == 'string') ? e.stack.split(/\n\s*\n/) : [];
7179
- if (parts.length > 1 || true) {
7180
- return '\nError details:\n' + parts[0];
7181
- }
7182
- return '';
7035
+ function isBoolean(obj) {
7036
+ return obj === true || obj === false;
7183
7037
  }
7184
7038
 
7185
- // print a message to stdout
7186
- function print() {
7187
- STDOUT = true; // tell logArgs() to print to stdout, not stderr
7188
- // calling message() adds the "[command name]" prefix
7189
- _message(utils.toArray(arguments));
7190
- STDOUT = false;
7039
+ function formatDateISO(d) {
7040
+ if (!isDate(d)) return '';
7041
+ return d.toISOString().replace(':00.000Z', 'Z');
7191
7042
  }
7192
7043
 
7193
- function verbose() {
7194
- // verbose can be set globally with the -verbose command or separately for each command
7195
- if (useVerbose()) {
7196
- message.apply(null, arguments);
7044
+ // Convert an array-like object to an Array, or make a copy if @obj is an Array
7045
+ function toArray(obj) {
7046
+ var arr;
7047
+ if (!isArrayLike(obj)) error$1("toArray() requires an array-like object");
7048
+ try {
7049
+ arr = Array.prototype.slice.call(obj, 0); // breaks in ie8
7050
+ } catch(e) {
7051
+ // support ie8
7052
+ arr = [];
7053
+ for (var i=0, n=obj.length; i<n; i++) {
7054
+ arr[i] = obj[i];
7055
+ }
7197
7056
  }
7057
+ return arr;
7198
7058
  }
7199
7059
 
7200
- function useVerbose() {
7201
- return getStashedVar('VERBOSE');
7060
+ // Array like: has length property, is numerically indexed and mutable.
7061
+ // TODO: try to detect objects with length property but no indexed data elements
7062
+ function isArrayLike(obj) {
7063
+ if (!obj) return false;
7064
+ if (isArray(obj)) return true;
7065
+ if (isString(obj)) return false;
7066
+ if (obj.length === 0 || obj.length > 0) return true;
7067
+ return false;
7202
7068
  }
7203
7069
 
7204
- function useDebug() {
7205
- return getStashedVar('DEBUG');
7070
+ // See https://raw.github.com/kvz/phpjs/master/functions/strings/addslashes.js
7071
+ function addslashes(str) {
7072
+ return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
7206
7073
  }
7207
7074
 
7208
- function debug() {
7209
- if (useDebug()) {
7210
- logArgs(arguments);
7211
- }
7075
+ // Escape a literal string to use in a regexp.
7076
+ // Ref.: http://simonwillison.net/2006/Jan/20/escape/
7077
+ function regexEscape(str) {
7078
+ return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
7212
7079
  }
7213
7080
 
7214
- function time(slug) {
7215
- if (useDebug()) {
7216
- console.time(slug);
7217
- }
7081
+
7082
+ // See https://github.com/janl/mustache.js/blob/master/mustache.js
7083
+ var entityMap = {
7084
+ '&': '&amp;',
7085
+ '<': '&lt;',
7086
+ '>': '&gt;',
7087
+ '"': '&quot;',
7088
+ "'": '&#39;',
7089
+ '/': '&#x2F;'
7090
+ };
7091
+ function htmlEscape(s) {
7092
+ return String(s).replace(/[&<>"'/]/g, function(s) {
7093
+ return entityMap[s];
7094
+ });
7218
7095
  }
7219
7096
 
7220
- function timeEnd(slug) {
7221
- if (useDebug()) {
7222
- console.timeEnd(slug);
7097
+
7098
+ function defaults(dest) {
7099
+ for (var i=1, n=arguments.length; i<n; i++) {
7100
+ var src = arguments[i] || {};
7101
+ for (var key in src) {
7102
+ if (key in dest === false && src.hasOwnProperty(key)) {
7103
+ dest[key] = src[key];
7104
+ }
7105
+ }
7223
7106
  }
7107
+ return dest;
7224
7108
  }
7225
7109
 
7226
- function printError(err) {
7227
- var msg;
7228
- if (!LOGGING) return;
7229
- if (utils.isString(err)) {
7230
- err = new UserError(err);
7231
- }
7232
- if (err.name == 'NonFatalError') {
7233
- console.error(messageArgs([err.message]).join(' '));
7234
- } else if (err.name == 'UserError') {
7235
- msg = err.message;
7236
- if (!/Error/.test(msg)) {
7237
- msg = "Error: " + msg;
7110
+ function extend(o) {
7111
+ var dest = o || {},
7112
+ n = arguments.length,
7113
+ key, i, src;
7114
+ for (i=1; i<n; i++) {
7115
+ src = arguments[i] || {};
7116
+ for (key in src) {
7117
+ if (src.hasOwnProperty(key)) {
7118
+ dest[key] = src[key];
7119
+ }
7238
7120
  }
7239
- console.error(messageArgs([msg]).join(' '));
7240
- console.error("Run mapshaper -h to view help");
7241
- } else {
7242
- // not a user error (i.e. a bug in mapshaper)
7243
- console.error(err);
7244
- // throw err;
7245
7121
  }
7246
- }
7247
-
7248
- function UserError(msg) {
7249
- var err = new Error(msg);
7250
- err.name = 'UserError';
7251
- return err;
7252
- }
7253
-
7254
- function NonFatalError(msg) {
7255
- var err = new Error(msg);
7256
- err.name = 'NonFatalError';
7257
- return err;
7258
- }
7259
-
7260
- function formatColumns(arr, alignments) {
7261
- var widths = arr.reduce(function(memo, line) {
7262
- return line.map(function(str, i) {
7263
- return memo ? Math.max(memo[i], str.length) : str.length;
7264
- });
7265
- }, null);
7266
- return arr.map(function(line) {
7267
- line = line.map(function(str, i) {
7268
- var rt = alignments && alignments[i] == 'right';
7269
- var pad = (rt ? str.padStart : str.padEnd).bind(str);
7270
- return pad(widths[i], ' ');
7271
- });
7272
- return ' ' + line.join(' ');
7273
- }).join('\n');
7274
- }
7275
-
7276
- // Format an array of (preferably short) strings in columns for console logging.
7277
- function formatStringsAsGrid(arr, width) {
7278
- // TODO: variable column width
7279
- var longest = arr.reduce(function(len, str) {
7280
- return Math.max(len, str.length);
7281
- }, 0),
7282
- colWidth = longest + 2,
7283
- perLine = Math.floor((width || 80) / colWidth) || 1;
7284
- return arr.reduce(function(memo, name, i) {
7285
- var col = i % perLine;
7286
- if (i > 0 && col === 0) memo += '\n';
7287
- if (col < perLine - 1) { // right-pad all but rightmost column
7288
- name = utils.rpad(name, colWidth - 2, ' ');
7289
- }
7290
- return memo + ' ' + name;
7291
- }, '');
7292
- }
7293
-
7294
- // expose so GUI can use it
7295
- function formatLogArgs(args) {
7296
- return utils.toArray(args).join(' ');
7297
- }
7298
-
7299
- function messageArgs(args) {
7300
- var arr = utils.toArray(args);
7301
- var cmd = getStashedVar('current_command');
7302
- if (cmd && cmd != 'help') {
7303
- arr.unshift('[' + cmd + ']');
7304
- }
7305
- return arr;
7306
- }
7307
-
7308
- function logArgs(args) {
7309
- if (!LOGGING || getStashedVar('QUIET') || !utils.isArrayLike(args)) return;
7310
- var msg = formatLogArgs(args);
7311
- if (STDOUT) console.log(msg);
7312
- else console.error(msg);
7313
- }
7314
-
7315
- function truncateString(str, maxLen) {
7316
- maxLen = maxLen || 80;
7317
- if (str.length > maxLen) {
7318
- str = str.substring(0, maxLen - 3).trimEnd() + '...';
7319
- }
7320
- return str;
7321
- }
7322
-
7323
- var uniqCount = 0;
7324
- function getUniqueName(prefix) {
7325
- return (prefix || "__id_") + (++uniqCount);
7326
- }
7327
-
7328
- function isFunction(obj) {
7329
- return typeof obj == 'function';
7330
- }
7331
-
7332
- function isPromise(arg) {
7333
- return arg ? isFunction(arg.then) : false;
7334
- }
7335
-
7336
- function isObject(obj) {
7337
- return obj === Object(obj); // via underscore
7338
- }
7339
-
7340
- function clamp(val, min, max) {
7341
- return val < min ? min : (val > max ? max : val);
7342
- }
7343
-
7344
- function isArray(obj) {
7345
- return Array.isArray(obj);
7346
- }
7347
-
7348
- // Is obj a valid number or NaN? (test if obj is type number)
7349
- function isNumber(obj) {
7350
- return obj != null && obj.constructor == Number;
7351
- }
7352
-
7353
- function isValidNumber(val) {
7354
- return isNumber(val) && !isNaN(val);
7355
- }
7356
-
7357
- // Similar to isFinite() but does not coerce strings or other types
7358
- function isFiniteNumber(val) {
7359
- return isValidNumber(val) && val !== Infinity && val !== -Infinity;
7360
- }
7361
-
7362
- // This uses type conversion
7363
- // export function isFiniteNumber(val) {
7364
- // return val > -Infinity && val < Infinity;
7365
- // }
7366
-
7367
- function isNonNegNumber(val) {
7368
- return isNumber(val) && val >= 0;
7369
- }
7370
-
7371
- function isInteger(obj) {
7372
- return isNumber(obj) && ((obj | 0) === obj);
7373
- }
7374
-
7375
- function isEven(obj) {
7376
- return (obj % 2) === 0;
7377
- }
7378
-
7379
- function isOdd(obj) {
7380
- return (obj % 2) === 1;
7381
- }
7382
-
7383
- function isString(obj) {
7384
- return obj != null && obj.toString === String.prototype.toString;
7385
- // TODO: replace w/ something better.
7386
- }
7387
-
7388
- function isDate(obj) {
7389
- return !!obj && obj.getTime === Date.prototype.getTime;
7390
- }
7391
-
7392
- function isBoolean(obj) {
7393
- return obj === true || obj === false;
7394
- }
7395
-
7396
- function formatDateISO(d) {
7397
- if (!isDate(d)) return '';
7398
- return d.toISOString().replace(':00.000Z', 'Z');
7399
- }
7400
-
7401
- // Convert an array-like object to an Array, or make a copy if @obj is an Array
7402
- function toArray(obj) {
7403
- var arr;
7404
- if (!isArrayLike(obj)) error("toArray() requires an array-like object");
7405
- try {
7406
- arr = Array.prototype.slice.call(obj, 0); // breaks in ie8
7407
- } catch(e) {
7408
- // support ie8
7409
- arr = [];
7410
- for (var i=0, n=obj.length; i<n; i++) {
7411
- arr[i] = obj[i];
7412
- }
7413
- }
7414
- return arr;
7415
- }
7416
-
7417
- // Array like: has length property, is numerically indexed and mutable.
7418
- // TODO: try to detect objects with length property but no indexed data elements
7419
- function isArrayLike(obj) {
7420
- if (!obj) return false;
7421
- if (isArray(obj)) return true;
7422
- if (isString(obj)) return false;
7423
- if (obj.length === 0 || obj.length > 0) return true;
7424
- return false;
7425
- }
7426
-
7427
- // See https://raw.github.com/kvz/phpjs/master/functions/strings/addslashes.js
7428
- function addslashes(str) {
7429
- return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0');
7430
- }
7431
-
7432
- // Escape a literal string to use in a regexp.
7433
- // Ref.: http://simonwillison.net/2006/Jan/20/escape/
7434
- function regexEscape(str) {
7435
- return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
7436
- }
7437
-
7438
-
7439
- // See https://github.com/janl/mustache.js/blob/master/mustache.js
7440
- var entityMap = {
7441
- '&': '&amp;',
7442
- '<': '&lt;',
7443
- '>': '&gt;',
7444
- '"': '&quot;',
7445
- "'": '&#39;',
7446
- '/': '&#x2F;'
7447
- };
7448
- function htmlEscape(s) {
7449
- return String(s).replace(/[&<>"'/]/g, function(s) {
7450
- return entityMap[s];
7451
- });
7452
- }
7453
-
7454
-
7455
- function defaults(dest) {
7456
- for (var i=1, n=arguments.length; i<n; i++) {
7457
- var src = arguments[i] || {};
7458
- for (var key in src) {
7459
- if (key in dest === false && src.hasOwnProperty(key)) {
7460
- dest[key] = src[key];
7461
- }
7462
- }
7463
- }
7464
- return dest;
7465
- }
7466
-
7467
- function extend(o) {
7468
- var dest = o || {},
7469
- n = arguments.length,
7470
- key, i, src;
7471
- for (i=1; i<n; i++) {
7472
- src = arguments[i] || {};
7473
- for (key in src) {
7474
- if (src.hasOwnProperty(key)) {
7475
- dest[key] = src[key];
7476
- }
7477
- }
7478
- }
7479
- return dest;
7122
+ return dest;
7480
7123
  }
7481
7124
 
7482
7125
  // Pseudoclassical inheritance
@@ -7561,7 +7204,7 @@
7561
7204
  // Append elements of @src array to @dest array
7562
7205
  function merge(dest, src) {
7563
7206
  if (!isArray(dest) || !isArray(src)) {
7564
- error("Usage: merge(destArray, srcArray);");
7207
+ error$1("Usage: merge(destArray, srcArray);");
7565
7208
  }
7566
7209
  for (var i=0, n=src.length; i<n; i++) {
7567
7210
  dest.push(src[i]);
@@ -7602,7 +7245,7 @@
7602
7245
  else if (isArrayLike(container)) {
7603
7246
  return indexOf(container, item) != -1;
7604
7247
  }
7605
- error("Expected Array or String argument");
7248
+ error$1("Expected Array or String argument");
7606
7249
  }
7607
7250
 
7608
7251
  function some(arr, test) {
@@ -7649,7 +7292,7 @@
7649
7292
  // Assumes: no other non-numeric objects in array
7650
7293
  //
7651
7294
  function sum(arr, info) {
7652
- if (!isArrayLike(arr)) error ("sum() expects an array, received:", arr);
7295
+ if (!isArrayLike(arr)) error$1 ("sum() expects an array, received:", arr);
7653
7296
  var tot = 0,
7654
7297
  nan = 0,
7655
7298
  val;
@@ -7931,7 +7574,7 @@
7931
7574
  var arr2 = [];
7932
7575
  for (var i=0; i<len; i++) {
7933
7576
  var idx = idxs[i];
7934
- if (idx < 0 || idx >= len) error("Out-of-bounds array idx");
7577
+ if (idx < 0 || idx >= len) error$1("Out-of-bounds array idx");
7935
7578
  arr2[i] = arr[idx];
7936
7579
  }
7937
7580
  replaceArray(arr, arr2);
@@ -8016,7 +7659,7 @@
8016
7659
  // Elements of @arr are reordered
8017
7660
  //
8018
7661
  function findValueByRank(arr, rank) {
8019
- if (!arr.length || rank < 1 || rank > arr.length) error("[findValueByRank()] invalid input");
7662
+ if (!arr.length || rank < 1 || rank > arr.length) error$1("[findValueByRank()] invalid input");
8020
7663
 
8021
7664
  rank = clamp(rank | 0, 1, arr.length);
8022
7665
  var k = rank - 1, // conv. rank to array index
@@ -8207,7 +7850,7 @@
8207
7850
  var str = literals[0],
8208
7851
  n = arguments.length;
8209
7852
  if (n != formatCodes.length) {
8210
- error("[format()] Data does not match format string; format:", fmt, "data:", arguments);
7853
+ error$1("[format()] Data does not match format string; format:", fmt, "data:", arguments);
8211
7854
  }
8212
7855
  for (var i=0; i<n; i++) {
8213
7856
  str += formatValue(arguments[i], formatCodes[i]) + literals[i+1];
@@ -8238,7 +7881,7 @@
8238
7881
  if (src instanceof Uint8Array) {
8239
7882
  return B.from(src.buffer, src.byteOffset, src.byteLength);
8240
7883
  }
8241
- error('Unexpected argument type');
7884
+ error$1('Unexpected argument type');
8242
7885
  }
8243
7886
 
8244
7887
  function expandoBuffer(constructor, rate) {
@@ -8260,7 +7903,7 @@
8260
7903
  offs = 0,
8261
7904
  k;
8262
7905
  if (rev) {
8263
- if (same) error('copy error');
7906
+ if (same) error$1('copy error');
8264
7907
  inc = -1;
8265
7908
  offs = n - 1;
8266
7909
  }
@@ -8299,21 +7942,6 @@
8299
7942
  return a.substr(0, i);
8300
7943
  }
8301
7944
 
8302
- function parsePercent(o) {
8303
- var str = String(o);
8304
- var isPct = str.indexOf('%') > 0;
8305
- var pct;
8306
- if (isPct) {
8307
- pct = Number(str.replace('%', '')) / 100;
8308
- } else {
8309
- pct = Number(str);
8310
- }
8311
- if (!(pct >= 0 && pct <= 1)) {
8312
- stop(format("Invalid percentage: %s", str));
8313
- }
8314
- return pct;
8315
- }
8316
-
8317
7945
  function formatVersionedName(name, i) {
8318
7946
  var suffix = String(i);
8319
7947
  if (/[0-9]$/.test(name)) {
@@ -8401,6 +8029,319 @@
8401
8029
  return str;
8402
8030
  }
8403
8031
 
8032
+ // Default export so consumers can do `import utils from './mapshaper-utils'`
8033
+ // and call `utils.isObject(x)` etc. Listing the names explicitly (instead
8034
+ // of using `import * as utils from './mapshaper-utils'`) avoids a
8035
+ // self-import and the resulting Rollup circular-dependency warning.
8036
+ var utils = {
8037
+ addThousandsSep, addslashes, arrayToIndex,
8038
+ clamp, cleanNumericString, contains, copyElements, countValues, createBuffer,
8039
+ defaults, difference,
8040
+ endsWith, every, expandoBuffer, extend, extendBuffer,
8041
+ find, findMedian, findQuantile, findRankByValue, findStringPrefix,
8042
+ findValueByPct, findValueByRank, forEach, forEachProperty, format,
8043
+ formatDateISO, formatIntlNumber, formatNumber, formatNumberForDisplay,
8044
+ formatVersionedName, formatter,
8045
+ genericSort, getArrayBounds, getGenericComparator, getKeyComparator,
8046
+ getSortedIds, getUniqueName, groupBy,
8047
+ htmlEscape,
8048
+ indexOf, indexOn, inherit, initializeArray, intersection,
8049
+ isArray, isArrayLike, isBoolean, isDate, isEven, isFiniteNumber, isFunction,
8050
+ isInteger, isNonNegNumber, isNumber, isObject, isOdd, isPromise, isString,
8051
+ isValidNumber,
8052
+ lpad, ltrim,
8053
+ mean, merge, mergeNames,
8054
+ numToStr,
8055
+ parseIntlNumber, parseNumber, parseString, pickOne, pluck,
8056
+ pluralSuffix, promisify,
8057
+ quicksort, quicksortPartition,
8058
+ range, reduceAsync, regexEscape, reorderArray, repeat, repeatString,
8059
+ replaceArray, rpad, rtrim,
8060
+ shuffle, some, sortArrayIndex, sortOn, splitLines, sum,
8061
+ toArray, toBuffer, trim, trimQuotes,
8062
+ uniq, uniqifyNames,
8063
+ wildcardToRegExp
8064
+ };
8065
+
8066
+ // This module provides a way for multiple jobs to run together asynchronously
8067
+ // while keeping job-level context variables (like "defs") separate.
8068
+ //
8069
+ // We deliberately do NOT import from mapshaper-logging here -- the logging
8070
+ // module imports from this one, and avoiding the back-edge keeps the
8071
+ // foundational dependency graph acyclic. (The single error path below is
8072
+ // an internal-bug guard, not a user-facing message, so a plain Error is
8073
+ // adequate.)
8074
+
8075
+ var stash = {};
8076
+
8077
+ function stashVar(key, val) {
8078
+ if (key in stash) {
8079
+ throw new Error('Tried to replace a stashed variable: ' + key);
8080
+ }
8081
+ stash[key] = val;
8082
+ }
8083
+
8084
+ function getStashedVar(key) {
8085
+ if (key in stash === false) {
8086
+ return undefined; // to support running commands in tests
8087
+ // error('Tried to read a nonexistent variable from the stash:', key);
8088
+ }
8089
+ return stash[key];
8090
+ }
8091
+
8092
+ function clearStash() {
8093
+ stash = {};
8094
+ }
8095
+
8096
+ var LOGGING = false;
8097
+ var STDOUT = false; // use stdout for status messages
8098
+ var _error, _stop, _message, _warn;
8099
+
8100
+ var _interrupt = function() {
8101
+ throw new NonFatalError(formatLogArgs(arguments));
8102
+ };
8103
+
8104
+ var onceMessages = [];
8105
+
8106
+ setLoggingForCLI();
8107
+
8108
+ function getLoggingSetter() {
8109
+ var e = _error, s = _stop, m = _message, w = _warn;
8110
+ return function() {
8111
+ setLoggingFunctions(m, e, s, w);
8112
+ };
8113
+ }
8114
+
8115
+ function setLoggingForCLI() {
8116
+ function stop() {
8117
+ throw new UserError(formatLogArgs(arguments));
8118
+ }
8119
+
8120
+ function error() {
8121
+ var msg = utils.toArray(arguments).join(' ');
8122
+ throw new Error(msg);
8123
+ }
8124
+
8125
+ function message() {
8126
+ logArgs(arguments);
8127
+ }
8128
+
8129
+ // CLI warning is just a message (GUI behaves differently)
8130
+ var warn = message;
8131
+
8132
+ setLoggingFunctions(message, error, stop, warn);
8133
+ }
8134
+
8135
+ function enableLogging() {
8136
+ LOGGING = true;
8137
+ }
8138
+
8139
+ function disableLogging() {
8140
+ LOGGING = false;
8141
+ }
8142
+
8143
+ function loggingEnabled() {
8144
+ return !!LOGGING;
8145
+ }
8146
+
8147
+ // Handle an unexpected condition (internal error)
8148
+ function error() {
8149
+ _error.apply(null, utils.toArray(arguments));
8150
+ }
8151
+
8152
+ // Handle an error caused by invalid input or misuse of API
8153
+ function stop() {
8154
+ // _stop.apply(null, utils.toArray(arguments));
8155
+ _stop.apply(null, messageArgs(arguments));
8156
+ }
8157
+
8158
+ function interrupt() {
8159
+ _interrupt.apply(null, utils.toArray(arguments));
8160
+ }
8161
+
8162
+ // Print a status message
8163
+ function message() {
8164
+ _message.apply(null, messageArgs(arguments));
8165
+ }
8166
+
8167
+ function warn() {
8168
+ _warn.apply(null, messageArgs(arguments));
8169
+ }
8170
+
8171
+ function warnOnce() {
8172
+ var str = formatLogArgs(arguments);
8173
+ if (onceMessages.includes(str)) return;
8174
+ onceMessages.push(str);
8175
+ _warn.apply(null, messageArgs(arguments));
8176
+ }
8177
+
8178
+ // A way for the GUI to replace the CLI logging functions
8179
+ function setLoggingFunctions(message, error, stop, warn) {
8180
+ _message = message;
8181
+ _error = error;
8182
+ _stop = stop;
8183
+ _warn = warn;
8184
+ }
8185
+
8186
+ // get detailed error information from error stack (if available)
8187
+ // Example stack string (Node.js):
8188
+ /*
8189
+ /Users/someuser/somescript.js:226
8190
+ opacity: Math.round(weight * 5 / 5 // 0.2 0.4 0.6 etc
8191
+ ^
8192
+
8193
+ SyntaxError: missing ) after argument list
8194
+ at internalCompileFunction (node:internal/vm:73:18)
8195
+ at wrapSafe (node:internal/modules/cjs/loader:1149:20)
8196
+ at Module._compile (node:internal/modules/cjs/loader:1190:27)
8197
+ ...
8198
+ */
8199
+ function getErrorDetail(e) {
8200
+ var parts = (typeof e.stack == 'string') ? e.stack.split(/\n\s*\n/) : [];
8201
+ if (parts.length > 1 || true) {
8202
+ return '\nError details:\n' + parts[0];
8203
+ }
8204
+ return '';
8205
+ }
8206
+
8207
+ // print a message to stdout
8208
+ function print() {
8209
+ STDOUT = true; // tell logArgs() to print to stdout, not stderr
8210
+ // calling message() adds the "[command name]" prefix
8211
+ _message(utils.toArray(arguments));
8212
+ STDOUT = false;
8213
+ }
8214
+
8215
+ function verbose() {
8216
+ // verbose can be set globally with the -verbose command or separately for each command
8217
+ if (useVerbose()) {
8218
+ message.apply(null, arguments);
8219
+ }
8220
+ }
8221
+
8222
+ function useVerbose() {
8223
+ return getStashedVar('VERBOSE');
8224
+ }
8225
+
8226
+ function useDebug() {
8227
+ return getStashedVar('DEBUG');
8228
+ }
8229
+
8230
+ function debug() {
8231
+ if (useDebug()) {
8232
+ logArgs(arguments);
8233
+ }
8234
+ }
8235
+
8236
+ function time(slug) {
8237
+ if (useDebug()) {
8238
+ console.time(slug);
8239
+ }
8240
+ }
8241
+
8242
+ function timeEnd(slug) {
8243
+ if (useDebug()) {
8244
+ console.timeEnd(slug);
8245
+ }
8246
+ }
8247
+
8248
+ function printError(err) {
8249
+ var msg;
8250
+ if (!LOGGING) return;
8251
+ if (utils.isString(err)) {
8252
+ err = new UserError(err);
8253
+ }
8254
+ if (err.name == 'NonFatalError') {
8255
+ console.error(messageArgs([err.message]).join(' '));
8256
+ } else if (err.name == 'UserError') {
8257
+ msg = err.message;
8258
+ if (!/Error/.test(msg)) {
8259
+ msg = "Error: " + msg;
8260
+ }
8261
+ console.error(messageArgs([msg]).join(' '));
8262
+ console.error("Run mapshaper -h to view help");
8263
+ } else {
8264
+ // not a user error (i.e. a bug in mapshaper)
8265
+ console.error(err);
8266
+ // throw err;
8267
+ }
8268
+ }
8269
+
8270
+ function UserError(msg) {
8271
+ var err = new Error(msg);
8272
+ err.name = 'UserError';
8273
+ return err;
8274
+ }
8275
+
8276
+ function NonFatalError(msg) {
8277
+ var err = new Error(msg);
8278
+ err.name = 'NonFatalError';
8279
+ return err;
8280
+ }
8281
+
8282
+ function formatColumns(arr, alignments) {
8283
+ var widths = arr.reduce(function(memo, line) {
8284
+ return line.map(function(str, i) {
8285
+ return memo ? Math.max(memo[i], str.length) : str.length;
8286
+ });
8287
+ }, null);
8288
+ return arr.map(function(line) {
8289
+ line = line.map(function(str, i) {
8290
+ var rt = alignments && alignments[i] == 'right';
8291
+ var pad = (rt ? str.padStart : str.padEnd).bind(str);
8292
+ return pad(widths[i], ' ');
8293
+ });
8294
+ return ' ' + line.join(' ');
8295
+ }).join('\n');
8296
+ }
8297
+
8298
+ // Format an array of (preferably short) strings in columns for console logging.
8299
+ function formatStringsAsGrid(arr, width) {
8300
+ // TODO: variable column width
8301
+ var longest = arr.reduce(function(len, str) {
8302
+ return Math.max(len, str.length);
8303
+ }, 0),
8304
+ colWidth = longest + 2,
8305
+ perLine = Math.floor((width || 80) / colWidth) || 1;
8306
+ return arr.reduce(function(memo, name, i) {
8307
+ var col = i % perLine;
8308
+ if (i > 0 && col === 0) memo += '\n';
8309
+ if (col < perLine - 1) { // right-pad all but rightmost column
8310
+ name = utils.rpad(name, colWidth - 2, ' ');
8311
+ }
8312
+ return memo + ' ' + name;
8313
+ }, '');
8314
+ }
8315
+
8316
+ // expose so GUI can use it
8317
+ function formatLogArgs(args) {
8318
+ return utils.toArray(args).join(' ');
8319
+ }
8320
+
8321
+ function messageArgs(args) {
8322
+ var arr = utils.toArray(args);
8323
+ var cmd = getStashedVar('current_command');
8324
+ if (cmd && cmd != 'help') {
8325
+ arr.unshift('[' + cmd + ']');
8326
+ }
8327
+ return arr;
8328
+ }
8329
+
8330
+ function logArgs(args) {
8331
+ if (!LOGGING || getStashedVar('QUIET') || !utils.isArrayLike(args)) return;
8332
+ var msg = formatLogArgs(args);
8333
+ if (STDOUT) console.log(msg);
8334
+ else console.error(msg);
8335
+ }
8336
+
8337
+ function truncateString(str, maxLen) {
8338
+ maxLen = maxLen || 80;
8339
+ if (str.length > maxLen) {
8340
+ str = str.substring(0, maxLen - 3).trimEnd() + '...';
8341
+ }
8342
+ return str;
8343
+ }
8344
+
8404
8345
  function absArcId(arcId) {
8405
8346
  return arcId >= 0 ? arcId : ~arcId;
8406
8347
  }
@@ -8637,7 +8578,7 @@
8637
8578
  } else if (geoType == 'polygon') {
8638
8579
  test = polygonTest;
8639
8580
  } else {
8640
- error$1("Unexpected geometry type:", geoType);
8581
+ error$2("Unexpected geometry type:", geoType);
8641
8582
  }
8642
8583
  return test;
8643
8584
 
@@ -11313,7 +11254,7 @@
11313
11254
  hit.on('drag', function(e) {
11314
11255
  if (!labelSelected(e) || activeId == -1) return;
11315
11256
  if (e.id != activeId) {
11316
- error$1("Mismatched hit ids:", e.id, activeId);
11257
+ error$2("Mismatched hit ids:", e.id, activeId);
11317
11258
  }
11318
11259
  var scale = ext.getSymbolScale() || 1;
11319
11260
  var symNode, textNode;
@@ -13689,9 +13630,12 @@
13689
13630
  // is noticeably slower during animations with multiple canvases.
13690
13631
  // Highlights are drawn on a separate canvas while hovering, because this
13691
13632
  // is generally faster than redrawing all of the shapes.
13633
+ // Fast-nav forces the same path: _mainCanv has a CSS transform but stale
13634
+ // pixels, so painting on it would visually go through that transform a
13635
+ // second time and detach the highlight from its feature.
13692
13636
  this.drawOverlayLayers = function(layers, action) {
13693
13637
  var canv;
13694
- if (action == 'hover') {
13638
+ if (action == 'hover' || _fastActive) {
13695
13639
  canv = _overlayCanv;
13696
13640
  _overlayCanv.prep(_ext);
13697
13641
  } else {
@@ -14871,7 +14815,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
14871
14815
  ]
14872
14816
  });
14873
14817
  } else {
14874
- error$1('unsupported map style:', style);
14818
+ error$2('unsupported map style:', style);
14875
14819
  }
14876
14820
  }
14877
14821