mapshaper 0.6.13 → 0.6.15

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
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.13";
3
+ var VERSION = "0.6.15";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -5560,7 +5560,9 @@
5560
5560
  len = _nn[absId];
5561
5561
  if (nth < 0) nth = len + nth;
5562
5562
  if (absId != arcId) nth = len - nth - 1;
5563
- if (nth < 0 || nth >= len) error("[ArcCollection] out-of-range vertex id");
5563
+ if (nth < 0 || nth >= len) {
5564
+ error("[ArcCollection] out-of-range vertex id");
5565
+ }
5564
5566
  return _ii[absId] + nth;
5565
5567
  };
5566
5568
 
@@ -7066,15 +7068,6 @@
7066
7068
  transformPoints: transformPoints
7067
7069
  });
7068
7070
 
7069
- function runningInBrowser() {
7070
- return typeof window !== 'undefined' && typeof window.document !== 'undefined';
7071
- }
7072
-
7073
- var Env = /*#__PURE__*/Object.freeze({
7074
- __proto__: null,
7075
- runningInBrowser: runningInBrowser
7076
- });
7077
-
7078
7071
  function getPathSep(path) {
7079
7072
  // TODO: improve
7080
7073
  return path.indexOf('/') == -1 && path.indexOf('\\') != -1 ? '\\' : '/';
@@ -7127,6 +7120,11 @@
7127
7120
  return getPathBase(path) + '.' + ext;
7128
7121
  }
7129
7122
 
7123
+ function toLowerCaseExtension(name) {
7124
+ var ext = getFileExtension(name);
7125
+ return ext ? getPathBase(name) + '.' + ext.toLowerCase() : name;
7126
+ }
7127
+
7130
7128
  function getCommonFileBase(names) {
7131
7129
  return names.reduce(function(memo, name, i) {
7132
7130
  if (i === 0) {
@@ -7150,10 +7148,164 @@
7150
7148
  getFileExtension: getFileExtension,
7151
7149
  getPathBase: getPathBase,
7152
7150
  replaceFileExtension: replaceFileExtension,
7151
+ toLowerCaseExtension: toLowerCaseExtension,
7153
7152
  getCommonFileBase: getCommonFileBase,
7154
7153
  getOutputFileBase: getOutputFileBase
7155
7154
  });
7156
7155
 
7156
+ // Guess the type of a data file from file extension, or return null if not sure
7157
+ function guessInputFileType(file) {
7158
+ var ext = getFileExtension(file || '').toLowerCase(),
7159
+ type = null;
7160
+ if (ext == 'dbf' || ext == 'shp' || ext == 'prj' || ext == 'shx' || ext == 'kml' || ext == 'cpg') {
7161
+ type = ext;
7162
+ } else if (/json$/.test(ext)) {
7163
+ type = 'json';
7164
+ } else if (ext == 'csv' || ext == 'tsv' || ext == 'txt' || ext == 'tab') {
7165
+ type = 'text';
7166
+ }
7167
+ return type;
7168
+ }
7169
+
7170
+ function guessInputContentType(content) {
7171
+ var type = null;
7172
+ if (utils.isString(content)) {
7173
+ type = stringLooksLikeJSON(content) && 'json' ||
7174
+ stringLooksLikeKML(content) && 'kml' || 'text';
7175
+ } else if (utils.isObject(content) && content.type || utils.isArray(content)) {
7176
+ type = 'json';
7177
+ }
7178
+ return type;
7179
+ }
7180
+
7181
+ function guessInputType(file, content) {
7182
+ return guessInputFileType(file) || guessInputContentType(content);
7183
+ }
7184
+
7185
+ function stringLooksLikeJSON(str) {
7186
+ return /^\s*[{[]/.test(String(str));
7187
+ }
7188
+
7189
+ function stringLooksLikeKML(str) {
7190
+ str = String(str);
7191
+ return str.includes('<kml ') && str.includes('xmlns="http://www.opengis.net/kml/');
7192
+ }
7193
+
7194
+ function couldBeDsvFile(name) {
7195
+ var ext = getFileExtension(name).toLowerCase();
7196
+ return /csv|tsv|txt$/.test(ext);
7197
+ }
7198
+
7199
+ function isZipFile(file) {
7200
+ return /\.zip$/i.test(file);
7201
+ }
7202
+
7203
+ function isKmzFile(file) {
7204
+ return /\.kmz$/i.test(file);
7205
+ }
7206
+
7207
+ function isSupportedOutputFormat(fmt) {
7208
+ var types = ['geojson', 'topojson', 'json', 'dsv', 'dbf', 'shapefile', 'svg', 'kml'];
7209
+ return types.indexOf(fmt) > -1;
7210
+ }
7211
+
7212
+ function getFormatName(fmt) {
7213
+ return {
7214
+ geojson: 'GeoJSON',
7215
+ topojson: 'TopoJSON',
7216
+ json: 'JSON records',
7217
+ dsv: 'CSV',
7218
+ dbf: 'DBF',
7219
+ kml: 'KML',
7220
+ kmz: 'KMZ',
7221
+ shapefile: 'Shapefile',
7222
+ svg: 'SVG'
7223
+ }[fmt] || '';
7224
+ }
7225
+
7226
+ // Assumes file at @path is one of Mapshaper's supported file types
7227
+ function isSupportedBinaryInputType(path) {
7228
+ var ext = getFileExtension(path).toLowerCase();
7229
+ return ext == 'shp' || ext == 'shx' || ext == 'dbf'; // GUI also supports zip files
7230
+ }
7231
+
7232
+ // Detect extensions of some unsupported file types, for cmd line validation
7233
+ function filenameIsUnsupportedOutputType(file) {
7234
+ var rxp = /\.(shx|prj|xls|xlsx|gdb|sbn|sbx|xml)$/i;
7235
+ return rxp.test(file);
7236
+ }
7237
+
7238
+ var FileTypes = /*#__PURE__*/Object.freeze({
7239
+ __proto__: null,
7240
+ guessInputFileType: guessInputFileType,
7241
+ guessInputContentType: guessInputContentType,
7242
+ guessInputType: guessInputType,
7243
+ stringLooksLikeJSON: stringLooksLikeJSON,
7244
+ stringLooksLikeKML: stringLooksLikeKML,
7245
+ couldBeDsvFile: couldBeDsvFile,
7246
+ isZipFile: isZipFile,
7247
+ isKmzFile: isKmzFile,
7248
+ isSupportedOutputFormat: isSupportedOutputFormat,
7249
+ getFormatName: getFormatName,
7250
+ isSupportedBinaryInputType: isSupportedBinaryInputType,
7251
+ filenameIsUnsupportedOutputType: filenameIsUnsupportedOutputType
7252
+ });
7253
+
7254
+ // input: input file path or a Buffer containing .zip file bytes
7255
+ // cache: destination for extracted file contents
7256
+ function extractFiles(input, cache) {
7257
+ var zip = new require('adm-zip')(input);
7258
+ var files = zip.getEntries().map(function(entry) {
7259
+ // entry.entryName // path, including filename
7260
+ // entry.name // filename
7261
+ var file = toLowerCaseExtension(entry.name);
7262
+ if (file[0] == '.') return ''; // skip hidden system file
7263
+ var type = guessInputFileType(file);
7264
+ if (!type) return ''; // skip unrecognized extensions
7265
+ cache[file] = entry.getData();
7266
+ return file;
7267
+ });
7268
+ // remove auxiliary files from the import list
7269
+ // (these are files that can't be converted into datasets);
7270
+ return files.filter(function(file) {
7271
+ if (!file) return false;
7272
+ var type = guessInputFileType(file);
7273
+ if (type == 'dbf') {
7274
+ // don't import .dbf separately if .shp is present
7275
+ if (replaceFileExtension(file, 'shp') in cache) return false;
7276
+ }
7277
+ return type == 'text' || type == 'json' || type == 'shp' || type == 'dbf' || type == 'kml';
7278
+ });
7279
+ }
7280
+
7281
+ function convertOutputFiles(files, opts) {
7282
+ var filename = opts.zipfile || 'output.zip';
7283
+ var dirname = parseLocalPath(filename).basename;
7284
+ var zip = new require('adm-zip')();
7285
+ files.forEach(function(o) {
7286
+ var ofile = require('path').join(dirname, o.filename);
7287
+ var buf = Buffer.from(o.content);
7288
+ if (buf instanceof ArrayBuffer) {
7289
+ buf = new Uint8Array(buf);
7290
+ }
7291
+ zip.addFile(ofile, buf);
7292
+ delete o.content; // for gc?
7293
+ });
7294
+ return [{
7295
+ filename: filename,
7296
+ content: zip.toBuffer()
7297
+ }];
7298
+ }
7299
+
7300
+ function runningInBrowser() {
7301
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined';
7302
+ }
7303
+
7304
+ var Env = /*#__PURE__*/Object.freeze({
7305
+ __proto__: null,
7306
+ runningInBrowser: runningInBrowser
7307
+ });
7308
+
7157
7309
  var cli = {};
7158
7310
 
7159
7311
  cli.isFile = function(path, cache) {
@@ -7163,6 +7315,13 @@
7163
7315
  return ss && ss.isFile() || false;
7164
7316
  };
7165
7317
 
7318
+ cli.checkCommandEnv = function(cname) {
7319
+ var blocked = ['i', 'include', 'require', 'external'];
7320
+ if (runningInBrowser() && blocked.includes(cname)) {
7321
+ stop('The -' + cname + ' command cannot be run in the browser');
7322
+ }
7323
+ };
7324
+
7166
7325
  // cli.fileSize = function(path) {
7167
7326
  // var ss = cli.statSync(path);
7168
7327
  // return ss && ss.size || 0;
@@ -7303,6 +7462,9 @@
7303
7462
  // trigger EAGAIN error, e.g. when piped to less)
7304
7463
  return cli.writeFile('/dev/stdout', exports[0].content, cb);
7305
7464
  } else {
7465
+ if (opts.zip) {
7466
+ exports = convertOutputFiles(exports, opts);
7467
+ }
7306
7468
  var paths = getOutputPaths(utils.pluck(exports, 'filename'), opts);
7307
7469
  var inputFiles = getStashedVar('input_files');
7308
7470
  exports.forEach(function(obj, i) {
@@ -7312,7 +7474,7 @@
7312
7474
  obj.content = cli.convertArrayBuffer(obj.content); // convert to Buffer
7313
7475
  }
7314
7476
  if (opts.gzip) {
7315
- path = path + '.gz';
7477
+ path = /gz$/i.test(path) ? path : path + '.gz';
7316
7478
  obj.content = require$1('zlib').gzipSync(obj.content);
7317
7479
  }
7318
7480
  if (opts.output) {
@@ -8080,55 +8242,71 @@
8080
8242
  getFormattedStringify: getFormattedStringify
8081
8243
  });
8082
8244
 
8083
- // Return id of rightmost connected arc in relation to @arcId
8084
- // Return @arcId if no arcs can be found
8085
- function getRightmostArc(arcId, nodes, filter) {
8086
- var ids = nodes.getConnectedArcs(arcId);
8245
+ function isValidArc(arcId, arcs) {
8246
+ // check for arcs with no vertices
8247
+ // TODO: also check for other kinds of degenerate arcs
8248
+ // (e.g. collapsed arcs consisting of identical points)
8249
+ return arcs.getArcLength(arcId) > 1;
8250
+ }
8251
+
8252
+ // Return id of rightmost connected arc in relation to @fromArcId
8253
+ // Return @fromArcId if no arcs can be found
8254
+ function getRightmostArc(fromArcId, nodes, filter) {
8255
+ var arcs = nodes.arcs,
8256
+ coords = arcs.getVertexData(),
8257
+ xx = coords.xx,
8258
+ yy = coords.yy,
8259
+ ids = nodes.getConnectedArcs(fromArcId),
8260
+ toArcId = fromArcId; // initialize to fromArcId -- an error condition
8261
+
8087
8262
  if (filter) {
8088
8263
  ids = ids.filter(filter);
8089
8264
  }
8090
- if (ids.length === 0) {
8091
- return arcId; // error condition, handled by caller
8265
+
8266
+ if (!isValidArc(fromArcId, arcs) || ids.length === 0) {
8267
+ return fromArcId;
8092
8268
  }
8093
- return getRighmostArc2(arcId, ids, nodes.arcs);
8094
- }
8095
8269
 
8096
- function getRighmostArc2 (fromId, ids, arcs) {
8097
- var coords = arcs.getVertexData(),
8098
- xx = coords.xx,
8099
- yy = coords.yy,
8100
- inode = arcs.indexOfVertex(fromId, -1),
8270
+ var inode = arcs.indexOfVertex(fromArcId, -1),
8101
8271
  nodeX = xx[inode],
8102
8272
  nodeY = yy[inode],
8103
- ifrom = arcs.indexOfVertex(fromId, -2),
8273
+ ifrom = arcs.indexOfVertex(fromArcId, -2),
8104
8274
  fromX = xx[ifrom],
8105
8275
  fromY = yy[ifrom],
8106
- toId = fromId, // initialize to from-arc -- an error
8107
8276
  ito, candId, icand, code, j;
8108
8277
 
8109
8278
  /*if (x == ax && y == ay) {
8110
8279
  error("Duplicate point error");
8111
8280
  }*/
8112
- if (ids.length > 0) {
8113
- toId = ids[0];
8114
- ito = arcs.indexOfVertex(toId, -2);
8115
- }
8116
8281
 
8117
- for (j=1; j<ids.length; j++) {
8282
+
8283
+ for (j=0; j<ids.length; j++) {
8118
8284
  candId = ids[j];
8285
+ if (!isValidArc(candId, arcs)) {
8286
+ // skip empty arcs
8287
+ continue;
8288
+ }
8119
8289
  icand = arcs.indexOfVertex(candId, -2);
8290
+
8291
+ if (toArcId == fromArcId) {
8292
+ // first valid candidate
8293
+ ito = icand;
8294
+ toArcId = candId;
8295
+ continue;
8296
+ }
8297
+
8120
8298
  code = chooseRighthandPath(fromX, fromY, nodeX, nodeY, xx[ito], yy[ito], xx[icand], yy[icand]);
8121
- // code = internal.chooseRighthandPath(0, 0, nodeX - fromX, nodeY - fromY, xx[ito] - fromX, yy[ito] - fromY, xx[icand] - fromX, yy[icand] - fromY);
8122
8299
  if (code == 2) {
8123
- toId = candId;
8124
8300
  ito = icand;
8301
+ toArcId = candId;
8125
8302
  }
8126
8303
  }
8127
- if (toId == fromId) {
8304
+
8305
+ if (toArcId == fromArcId) {
8128
8306
  // This shouldn't occur, assuming that other arcs are present
8129
8307
  error("Pathfinder error");
8130
8308
  }
8131
- return toId;
8309
+ return toArcId;
8132
8310
  }
8133
8311
 
8134
8312
  function chooseRighthandPath2(fromX, fromY, nodeX, nodeY, ax, ay, bx, by) {
@@ -8327,11 +8505,19 @@
8327
8505
  return ~getRightmostArc(prevId, nodes, testArc);
8328
8506
  }
8329
8507
 
8508
+ function isEmptyArc(id) {
8509
+ return nodes.arcs.getArcLength(id) > 1 === false;
8510
+ }
8511
+
8330
8512
  return function(startId) {
8331
8513
  var path = [],
8332
8514
  nextId, msg,
8333
8515
  candId = startId;
8334
8516
 
8517
+ if (isEmptyArc(startId)) {
8518
+ return null;
8519
+ }
8520
+
8335
8521
  do {
8336
8522
  if (useRoute(candId)) {
8337
8523
  path.push(candId);
@@ -15620,6 +15806,22 @@ ${svg}
15620
15806
  layerHasLabels: layerHasLabels
15621
15807
  });
15622
15808
 
15809
+ // import { isKmzFile } from '../io/mapshaper-file-types';
15810
+
15811
+ function exportKML(dataset, opts) {
15812
+ var toKML = require("@placemarkio/tokml").toKML;
15813
+ var geojsonOpts = Object.assign({combine_layers: true, geojson_type: 'FeatureCollection'}, opts);
15814
+ var geojson = exportDatasetAsGeoJSON(dataset, geojsonOpts);
15815
+ var kml = toKML(geojson);
15816
+ // TODO: add KMZ output
15817
+ // var useKmz = opts.file && isKmzFile(opts.file);
15818
+ var ofile = opts.file || getOutputFileBase(dataset) + '.kml';
15819
+ return [{
15820
+ content: kml,
15821
+ filename: ofile
15822
+ }];
15823
+ }
15824
+
15623
15825
  function buffersAreIdentical(a, b) {
15624
15826
  var alen = BinArray.bufferSize(a);
15625
15827
  var blen = BinArray.bufferSize(b);
@@ -17292,97 +17494,6 @@ ${svg}
17292
17494
  exportJSONTable: exportJSONTable
17293
17495
  });
17294
17496
 
17295
- // Guess the type of a data file from file extension, or return null if not sure
17296
- function guessInputFileType(file) {
17297
- var ext = getFileExtension(file || '').toLowerCase(),
17298
- type = null;
17299
- if (ext == 'dbf' || ext == 'shp' || ext == 'prj' || ext == 'shx' || ext == 'kml' || ext == 'cpg') {
17300
- type = ext;
17301
- } else if (/json$/.test(ext)) {
17302
- type = 'json';
17303
- } else if (ext == 'csv' || ext == 'tsv' || ext == 'txt' || ext == 'tab') {
17304
- type = 'text';
17305
- }
17306
- return type;
17307
- }
17308
-
17309
- function guessInputContentType(content) {
17310
- var type = null;
17311
- if (utils.isString(content)) {
17312
- type = stringLooksLikeJSON(content) && 'json' ||
17313
- stringLooksLikeKML(content) && 'kml' || 'text';
17314
- } else if (utils.isObject(content) && content.type || utils.isArray(content)) {
17315
- type = 'json';
17316
- }
17317
- return type;
17318
- }
17319
-
17320
- function guessInputType(file, content) {
17321
- return guessInputFileType(file) || guessInputContentType(content);
17322
- }
17323
-
17324
- function stringLooksLikeJSON(str) {
17325
- return /^\s*[{[]/.test(String(str));
17326
- }
17327
-
17328
- function stringLooksLikeKML(str) {
17329
- str = String(str);
17330
- return str.includes('<kml ') && str.includes('xmlns="http://www.opengis.net/kml/');
17331
- }
17332
-
17333
- function couldBeDsvFile(name) {
17334
- var ext = getFileExtension(name).toLowerCase();
17335
- return /csv|tsv|txt$/.test(ext);
17336
- }
17337
-
17338
- function isZipFile(file) {
17339
- return /\.zip$/i.test(file);
17340
- }
17341
-
17342
- function isSupportedOutputFormat(fmt) {
17343
- var types = ['geojson', 'topojson', 'json', 'dsv', 'dbf', 'shapefile', 'svg'];
17344
- return types.indexOf(fmt) > -1;
17345
- }
17346
-
17347
- function getFormatName(fmt) {
17348
- return {
17349
- geojson: 'GeoJSON',
17350
- topojson: 'TopoJSON',
17351
- json: 'JSON records',
17352
- dsv: 'CSV',
17353
- dbf: 'DBF',
17354
- shapefile: 'Shapefile',
17355
- svg: 'SVG'
17356
- }[fmt] || '';
17357
- }
17358
-
17359
- // Assumes file at @path is one of Mapshaper's supported file types
17360
- function isSupportedBinaryInputType(path) {
17361
- var ext = getFileExtension(path).toLowerCase();
17362
- return ext == 'shp' || ext == 'shx' || ext == 'dbf'; // GUI also supports zip files
17363
- }
17364
-
17365
- // Detect extensions of some unsupported file types, for cmd line validation
17366
- function filenameIsUnsupportedOutputType(file) {
17367
- var rxp = /\.(shx|prj|xls|xlsx|gdb|sbn|sbx|xml|kml)$/i;
17368
- return rxp.test(file);
17369
- }
17370
-
17371
- var FileTypes = /*#__PURE__*/Object.freeze({
17372
- __proto__: null,
17373
- guessInputFileType: guessInputFileType,
17374
- guessInputContentType: guessInputContentType,
17375
- guessInputType: guessInputType,
17376
- stringLooksLikeJSON: stringLooksLikeJSON,
17377
- stringLooksLikeKML: stringLooksLikeKML,
17378
- couldBeDsvFile: couldBeDsvFile,
17379
- isZipFile: isZipFile,
17380
- isSupportedOutputFormat: isSupportedOutputFormat,
17381
- getFormatName: getFormatName,
17382
- isSupportedBinaryInputType: isSupportedBinaryInputType,
17383
- filenameIsUnsupportedOutputType: filenameIsUnsupportedOutputType
17384
- });
17385
-
17386
17497
  function getOutputFormat(dataset, opts) {
17387
17498
  var outFile = opts.file || null,
17388
17499
  inFmt = dataset.info && dataset.info.input_formats && dataset.info.input_formats[0],
@@ -17458,7 +17569,7 @@ ${svg}
17458
17569
  function exportDatasets(datasets, opts) {
17459
17570
  var format = getOutputFormat(datasets[0], opts);
17460
17571
  var files;
17461
- if (format == 'svg' || format == 'topojson' || format == 'geojson' && opts.combine_layers) {
17572
+ if (format == 'kml' || format == 'svg' || format == 'topojson' || format == 'geojson' && opts.combine_layers) {
17462
17573
  // multi-layer formats: combine multiple datasets into one
17463
17574
  if (datasets.length > 1) {
17464
17575
  datasets = [mergeDatasetsForExport(datasets)];
@@ -17512,8 +17623,8 @@ ${svg}
17512
17623
  }, dataset);
17513
17624
 
17514
17625
  // Adjust layer names, so they can be used as output file names
17515
- // (except for multi-layer formats TopoJSON and SVG)
17516
- if (opts.file && outFmt != 'topojson' && outFmt != 'svg') {
17626
+ // (except for multi-layer formats TopoJSON, SVG, KML)
17627
+ if (opts.file && outFmt != 'topojson' && outFmt != 'svg'&& outFmt != 'kml') {
17517
17628
  dataset.layers.forEach(function(lyr) {
17518
17629
  lyr.name = getFileBase(opts.file);
17519
17630
  });
@@ -17558,7 +17669,8 @@ ${svg}
17558
17669
  dsv: exportDelim,
17559
17670
  dbf: exportDbf,
17560
17671
  json: exportJSON,
17561
- svg: exportSVG
17672
+ svg: exportSVG,
17673
+ kml: exportKML
17562
17674
  };
17563
17675
 
17564
17676
 
@@ -18545,9 +18657,19 @@ ${svg}
18545
18657
  // (cli.writeFile() now creates directories that don't exist)
18546
18658
  // cli.validateOutputDir(o.directory);
18547
18659
  }
18548
- if (pathInfo.extension == 'gz') {
18549
- o.file = pathInfo.basename;
18660
+ if (/gz/i.test(pathInfo.extension)) {
18661
+ // handle arguments like -o out.json.gz (the preferred format)
18662
+ if (parseLocalPath(pathInfo.basename).extension) {
18663
+ o.file = pathInfo.basename;
18664
+ } else {
18665
+ // handle arguments like -o out.gz
18666
+ o.file = pathInfo.filename;
18667
+ }
18550
18668
  o.gzip = true;
18669
+ } else if (/zip/i.test(pathInfo.extension)) {
18670
+ o.file = null;
18671
+ o.zipfile = pathInfo.filename;
18672
+ o.zip = true;
18551
18673
  } else {
18552
18674
  o.file = pathInfo.filename;
18553
18675
  }
@@ -19361,6 +19483,10 @@ ${svg}
19361
19483
  describe: 'apply gzip compression to output files',
19362
19484
  type: 'flag'
19363
19485
  })
19486
+ .option('zip', {
19487
+ describe: 'save all output files in a single .zip file',
19488
+ type: 'flag'
19489
+ })
19364
19490
  .option('dry-run', {
19365
19491
  // describe: 'do not output any files'
19366
19492
  type: 'flag'
@@ -23725,64 +23851,82 @@ ${svg}
23725
23851
  importFileContent: importFileContent
23726
23852
  });
23727
23853
 
23728
- // Import multiple files to a single dataset
23729
- function importFiles(files, opts) {
23730
- var unbuiltTopology = false;
23731
- var datasets = files.map(function(fname) {
23732
- // import without topology or snapping
23733
- var importOpts = utils.defaults({no_topology: true, snap: false, snap_interval: null, files: [fname]}, opts);
23734
- var dataset = importFile(fname, importOpts);
23735
- // check if dataset contains non-topological paths
23736
- // TODO: may also need to rebuild topology if multiple topojson files are merged
23737
- if (dataset.arcs && dataset.arcs.size() > 0 && dataset.info.input_formats[0] != 'topojson') {
23738
- unbuiltTopology = true;
23739
- }
23740
- return dataset;
23741
- });
23742
- var combined = mergeDatasets(datasets);
23743
- // Build topology, if needed
23744
- // TODO: consider updating topology of TopoJSON files instead of concatenating arcs
23745
- // (but problem of mismatched coordinates due to quantization in input files.)
23746
- if (unbuiltTopology && !opts.no_topology) {
23747
- cleanPathsAfterImport(combined, opts);
23748
- buildTopology(combined);
23749
- }
23750
- return combined;
23751
- }
23752
-
23753
- var MergeFiles = /*#__PURE__*/Object.freeze({
23754
- __proto__: null,
23755
- importFiles: importFiles
23756
- });
23757
-
23758
23854
  cmd.importFiles = function(opts) {
23759
- var files = opts.files || [],
23760
- dataset;
23855
+ var files = opts.files || [];
23856
+ var dataset;
23761
23857
 
23858
+ cli.checkCommandEnv('i');
23762
23859
  if (opts.stdin) {
23763
23860
  return importFile('/dev/stdin', opts);
23764
23861
  }
23765
23862
 
23863
+
23766
23864
  if (files.length > 0 === false) {
23767
23865
  stop('Missing input file(s)');
23768
23866
  }
23769
23867
 
23770
23868
  verbose("Importing: " + files.join(' '));
23771
23869
 
23870
+ // copy opts, so parameters can be modified within this command
23871
+ opts = Object.assign({}, opts);
23872
+ opts.input = Object.assign({}, opts.input); // make sure we have a cache
23873
+
23874
+ files = expandFiles(files, opts.input);
23875
+
23876
+ if (files.length === 0) {
23877
+ stop('Missing importable files');
23878
+ }
23879
+
23772
23880
  if (files.length == 1) {
23773
23881
  dataset = importFile(files[0], opts);
23774
- } else if (opts.merge_files) {
23882
+ } else {
23883
+ dataset = importFilesTogether(files, opts);
23884
+ }
23885
+
23886
+ if (opts.merge_files && files.length > 1) {
23775
23887
  // TODO: deprecate and remove this option (use -merge-layers cmd instead)
23776
- dataset = importFiles(files, opts);
23777
23888
  dataset.layers = cmd.mergeLayers(dataset.layers);
23778
- } else if (opts.combine_files) {
23779
- dataset = importFiles(files, opts);
23780
- } else {
23781
- stop('Invalid inputs');
23782
23889
  }
23783
23890
  return dataset;
23784
23891
  };
23785
23892
 
23893
+ function expandFiles(files, cache) {
23894
+ var files2 = [];
23895
+ files.forEach(function(file) {
23896
+ var expanded;
23897
+ if (isZipFile(file)) {
23898
+ expanded = expandZipFile(file, cache);
23899
+ } else if (isKmzFile(file)) {
23900
+ expanded = expandKmzFile(file, cache);
23901
+ } else {
23902
+ expanded = [file]; // ordinary file, no change
23903
+ }
23904
+ files2 = files2.concat(expanded);
23905
+ });
23906
+ return files2;
23907
+ }
23908
+
23909
+ function expandKmzFile(file, cache) {
23910
+ var files = expandZipFile(file, cache);
23911
+ var name = replaceFileExtension(parseLocalPath(file).filename, 'kml');
23912
+ if (files[0] == 'doc.kml') {
23913
+ files[0] = name;
23914
+ cache[name] = cache['doc.kml'];
23915
+ }
23916
+ return files;
23917
+ }
23918
+
23919
+ function expandZipFile(file, cache) {
23920
+ var input;
23921
+ if (file in cache) {
23922
+ input = cache[file];
23923
+ } else {
23924
+ input = file;
23925
+ cli.checkFileExists(file);
23926
+ }
23927
+ return extractFiles(input, cache);
23928
+ }
23929
+
23786
23930
  // Let the web UI replace importFile() with a browser-friendly version
23787
23931
  function replaceImportFile(func) {
23788
23932
  _importFile = func;
@@ -23801,6 +23945,7 @@ ${svg}
23801
23945
  content;
23802
23946
 
23803
23947
  cli.checkFileExists(path, cache);
23948
+
23804
23949
  if ((fileType == 'shp' || fileType == 'json' || fileType == 'text' || fileType == 'dbf') && !cached) {
23805
23950
  // these file types are read incrementally
23806
23951
  content = null;
@@ -23823,6 +23968,7 @@ ${svg}
23823
23968
  stop('Unrecognized file type:', path);
23824
23969
  }
23825
23970
  // TODO: consider using a temp file, to support incremental reading
23971
+ // read to buffer, even for string-based types (to support larger input files)
23826
23972
  content = require('zlib').gunzipSync(cli.readFile(pathgz));
23827
23973
 
23828
23974
  } else { // type can't be inferred from filename -- try reading as text
@@ -23848,6 +23994,49 @@ ${svg}
23848
23994
  return importContent(input, opts);
23849
23995
  };
23850
23996
 
23997
+
23998
+ function importZipFile(path, opts) {
23999
+ var cache = {};
24000
+ var input;
24001
+ if (opts.input && (path in opts.input)) {
24002
+ // reading from a buffer
24003
+ input = opts.input[path];
24004
+ } else {
24005
+ // reading from a file
24006
+ cli.checkFileExists(path);
24007
+ input = path;
24008
+ }
24009
+ var files = extractFiles(input, cache);
24010
+ var zipOpts = Object.assign({}, opts, {input: cache, files: files});
24011
+ return cmd.importFiles(zipOpts);
24012
+ }
24013
+
24014
+ // Import multiple files to a single dataset
24015
+ function importFilesTogether(files, opts) {
24016
+ var unbuiltTopology = false;
24017
+ var datasets = files.map(function(fname) {
24018
+ // import without topology or snapping
24019
+ var importOpts = utils.defaults({no_topology: true, snap: false, snap_interval: null, files: [fname]}, opts);
24020
+ var dataset = importFile(fname, importOpts);
24021
+ // check if dataset contains non-topological paths
24022
+ // TODO: may also need to rebuild topology if multiple topojson files are merged
24023
+ if (dataset.arcs && dataset.arcs.size() > 0 && dataset.info.input_formats[0] != 'topojson') {
24024
+ unbuiltTopology = true;
24025
+ }
24026
+ return dataset;
24027
+ });
24028
+ var combined = mergeDatasets(datasets);
24029
+ // Build topology, if needed
24030
+ // TODO: consider updating topology of TopoJSON files instead of concatenating arcs
24031
+ // (but problem of mismatched coordinates due to quantization in input files.)
24032
+ if (unbuiltTopology && !opts.no_topology) {
24033
+ cleanPathsAfterImport(combined, opts);
24034
+ buildTopology(combined);
24035
+ }
24036
+ return combined;
24037
+ }
24038
+
24039
+
23851
24040
  function getUnsupportedFileMessage(path) {
23852
24041
  var ext = getFileExtension(path);
23853
24042
  var msg = 'Unable to import ' + path;
@@ -23885,7 +24074,8 @@ ${svg}
23885
24074
  var FileImport = /*#__PURE__*/Object.freeze({
23886
24075
  __proto__: null,
23887
24076
  replaceImportFile: replaceImportFile,
23888
- importFile: importFile
24077
+ importFile: importFile,
24078
+ importFilesTogether: importFilesTogether
23889
24079
  });
23890
24080
 
23891
24081
  function convertSourceName(name, targets) {
@@ -28465,15 +28655,15 @@ ${svg}
28465
28655
  var brighter = 1 / darker;
28466
28656
 
28467
28657
  var reI = "\\s*([+-]?\\d+)\\s*",
28468
- reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
28469
- reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
28658
+ reN = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*",
28659
+ reP = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
28470
28660
  reHex = /^#([0-9a-f]{3,8})$/,
28471
- reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
28472
- reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
28473
- reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
28474
- reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
28475
- reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
28476
- reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
28661
+ reRgbInteger = new RegExp(`^rgb\\(${reI},${reI},${reI}\\)$`),
28662
+ reRgbPercent = new RegExp(`^rgb\\(${reP},${reP},${reP}\\)$`),
28663
+ reRgbaInteger = new RegExp(`^rgba\\(${reI},${reI},${reI},${reN}\\)$`),
28664
+ reRgbaPercent = new RegExp(`^rgba\\(${reP},${reP},${reP},${reN}\\)$`),
28665
+ reHslPercent = new RegExp(`^hsl\\(${reN},${reP},${reP}\\)$`),
28666
+ reHslaPercent = new RegExp(`^hsla\\(${reN},${reP},${reP},${reN}\\)$`);
28477
28667
 
28478
28668
  var named = {
28479
28669
  aliceblue: 0xf0f8ff,
@@ -28627,14 +28817,15 @@ ${svg}
28627
28817
  };
28628
28818
 
28629
28819
  define(Color, color, {
28630
- copy: function(channels) {
28820
+ copy(channels) {
28631
28821
  return Object.assign(new this.constructor, this, channels);
28632
28822
  },
28633
- displayable: function() {
28823
+ displayable() {
28634
28824
  return this.rgb().displayable();
28635
28825
  },
28636
28826
  hex: color_formatHex, // Deprecated! Use color.formatHex.
28637
28827
  formatHex: color_formatHex,
28828
+ formatHex8: color_formatHex8,
28638
28829
  formatHsl: color_formatHsl,
28639
28830
  formatRgb: color_formatRgb,
28640
28831
  toString: color_formatRgb
@@ -28644,6 +28835,10 @@ ${svg}
28644
28835
  return this.rgb().formatHex();
28645
28836
  }
28646
28837
 
28838
+ function color_formatHex8() {
28839
+ return this.rgb().formatHex8();
28840
+ }
28841
+
28647
28842
  function color_formatHsl() {
28648
28843
  return hslConvert(this).formatHsl();
28649
28844
  }
@@ -28699,18 +28894,21 @@ ${svg}
28699
28894
  }
28700
28895
 
28701
28896
  define(Rgb, rgb$1, extend(Color, {
28702
- brighter: function(k) {
28897
+ brighter(k) {
28703
28898
  k = k == null ? brighter : Math.pow(brighter, k);
28704
28899
  return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
28705
28900
  },
28706
- darker: function(k) {
28901
+ darker(k) {
28707
28902
  k = k == null ? darker : Math.pow(darker, k);
28708
28903
  return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
28709
28904
  },
28710
- rgb: function() {
28905
+ rgb() {
28711
28906
  return this;
28712
28907
  },
28713
- displayable: function() {
28908
+ clamp() {
28909
+ return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity));
28910
+ },
28911
+ displayable() {
28714
28912
  return (-0.5 <= this.r && this.r < 255.5)
28715
28913
  && (-0.5 <= this.g && this.g < 255.5)
28716
28914
  && (-0.5 <= this.b && this.b < 255.5)
@@ -28718,25 +28916,34 @@ ${svg}
28718
28916
  },
28719
28917
  hex: rgb_formatHex, // Deprecated! Use color.formatHex.
28720
28918
  formatHex: rgb_formatHex,
28919
+ formatHex8: rgb_formatHex8,
28721
28920
  formatRgb: rgb_formatRgb,
28722
28921
  toString: rgb_formatRgb
28723
28922
  }));
28724
28923
 
28725
28924
  function rgb_formatHex() {
28726
- return "#" + hex(this.r) + hex(this.g) + hex(this.b);
28925
+ return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`;
28926
+ }
28927
+
28928
+ function rgb_formatHex8() {
28929
+ return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`;
28727
28930
  }
28728
28931
 
28729
28932
  function rgb_formatRgb() {
28730
- var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
28731
- return (a === 1 ? "rgb(" : "rgba(")
28732
- + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
28733
- + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
28734
- + Math.max(0, Math.min(255, Math.round(this.b) || 0))
28735
- + (a === 1 ? ")" : ", " + a + ")");
28933
+ const a = clampa(this.opacity);
28934
+ return `${a === 1 ? "rgb(" : "rgba("}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? ")" : `, ${a})`}`;
28935
+ }
28936
+
28937
+ function clampa(opacity) {
28938
+ return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));
28939
+ }
28940
+
28941
+ function clampi(value) {
28942
+ return Math.max(0, Math.min(255, Math.round(value) || 0));
28736
28943
  }
28737
28944
 
28738
28945
  function hex(value) {
28739
- value = Math.max(0, Math.min(255, Math.round(value) || 0));
28946
+ value = clampi(value);
28740
28947
  return (value < 16 ? "0" : "") + value.toString(16);
28741
28948
  }
28742
28949
 
@@ -28785,15 +28992,15 @@ ${svg}
28785
28992
  }
28786
28993
 
28787
28994
  define(Hsl, hsl$2, extend(Color, {
28788
- brighter: function(k) {
28995
+ brighter(k) {
28789
28996
  k = k == null ? brighter : Math.pow(brighter, k);
28790
28997
  return new Hsl(this.h, this.s, this.l * k, this.opacity);
28791
28998
  },
28792
- darker: function(k) {
28999
+ darker(k) {
28793
29000
  k = k == null ? darker : Math.pow(darker, k);
28794
29001
  return new Hsl(this.h, this.s, this.l * k, this.opacity);
28795
29002
  },
28796
- rgb: function() {
29003
+ rgb() {
28797
29004
  var h = this.h % 360 + (this.h < 0) * 360,
28798
29005
  s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
28799
29006
  l = this.l,
@@ -28806,21 +29013,29 @@ ${svg}
28806
29013
  this.opacity
28807
29014
  );
28808
29015
  },
28809
- displayable: function() {
29016
+ clamp() {
29017
+ return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity));
29018
+ },
29019
+ displayable() {
28810
29020
  return (0 <= this.s && this.s <= 1 || isNaN(this.s))
28811
29021
  && (0 <= this.l && this.l <= 1)
28812
29022
  && (0 <= this.opacity && this.opacity <= 1);
28813
29023
  },
28814
- formatHsl: function() {
28815
- var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
28816
- return (a === 1 ? "hsl(" : "hsla(")
28817
- + (this.h || 0) + ", "
28818
- + (this.s || 0) * 100 + "%, "
28819
- + (this.l || 0) * 100 + "%"
28820
- + (a === 1 ? ")" : ", " + a + ")");
29024
+ formatHsl() {
29025
+ const a = clampa(this.opacity);
29026
+ return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`;
28821
29027
  }
28822
29028
  }));
28823
29029
 
29030
+ function clamph(value) {
29031
+ value = (value || 0) % 360;
29032
+ return value < 0 ? value + 360 : value;
29033
+ }
29034
+
29035
+ function clampt(value) {
29036
+ return Math.max(0, Math.min(1, value || 0));
29037
+ }
29038
+
28824
29039
  /* From FvD 13.37, CSS Color Module Level 3 */
28825
29040
  function hsl2rgb(h, m1, m2) {
28826
29041
  return (h < 60 ? m1 + (m2 - m1) * h / 60
@@ -28873,13 +29088,13 @@ ${svg}
28873
29088
  }
28874
29089
 
28875
29090
  define(Lab, lab$1, extend(Color, {
28876
- brighter: function(k) {
29091
+ brighter(k) {
28877
29092
  return new Lab(this.l + K * (k == null ? 1 : k), this.a, this.b, this.opacity);
28878
29093
  },
28879
- darker: function(k) {
29094
+ darker(k) {
28880
29095
  return new Lab(this.l - K * (k == null ? 1 : k), this.a, this.b, this.opacity);
28881
29096
  },
28882
- rgb: function() {
29097
+ rgb() {
28883
29098
  var y = (this.l + 16) / 116,
28884
29099
  x = isNaN(this.a) ? y : y + this.a / 500,
28885
29100
  z = isNaN(this.b) ? y : y - this.b / 200;
@@ -28941,13 +29156,13 @@ ${svg}
28941
29156
  }
28942
29157
 
28943
29158
  define(Hcl, hcl$2, extend(Color, {
28944
- brighter: function(k) {
29159
+ brighter(k) {
28945
29160
  return new Hcl(this.h, this.c, this.l + K * (k == null ? 1 : k), this.opacity);
28946
29161
  },
28947
- darker: function(k) {
29162
+ darker(k) {
28948
29163
  return new Hcl(this.h, this.c, this.l - K * (k == null ? 1 : k), this.opacity);
28949
29164
  },
28950
- rgb: function() {
29165
+ rgb() {
28951
29166
  return hcl2lab(this).rgb();
28952
29167
  }
28953
29168
  }));
@@ -28987,15 +29202,15 @@ ${svg}
28987
29202
  }
28988
29203
 
28989
29204
  define(Cubehelix, cubehelix$3, extend(Color, {
28990
- brighter: function(k) {
29205
+ brighter(k) {
28991
29206
  k = k == null ? brighter : Math.pow(brighter, k);
28992
29207
  return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
28993
29208
  },
28994
- darker: function(k) {
29209
+ darker(k) {
28995
29210
  k = k == null ? darker : Math.pow(darker, k);
28996
29211
  return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
28997
29212
  },
28998
- rgb: function() {
29213
+ rgb() {
28999
29214
  var h = isNaN(this.h) ? 0 : (this.h + 120) * radians,
29000
29215
  l = +this.l,
29001
29216
  a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
@@ -39352,12 +39567,12 @@ ${svg}
39352
39567
  var parser = getOptionParser();
39353
39568
  // support multiline string of commands pasted into console
39354
39569
  str = str.split(/\n+/g).map(function(str) {
39355
- var match = /^[a-z][\w-]*/.exec(str = str.trim());
39570
+ var match = /^[a-z][\w-]*/i.exec(str = str.trim());
39356
39571
  //if (match && parser.isCommandName(match[0])) {
39357
39572
  if (match) {
39358
39573
  // add hyphen prefix to bare command
39359
- // also add hyphen to non-command strings, for a better error message
39360
- // ("unsupported command" instead of "The -i command cannot be run in the browser")
39574
+ // also add hyphen to non-command strings, for a better error message
39575
+ // ("unsupported command" instead of "The -i command cannot be run in the browser")
39361
39576
  str = '-' + str;
39362
39577
  }
39363
39578
  return str;
@@ -39367,15 +39582,10 @@ ${svg}
39367
39582
 
39368
39583
  // Parse a command line string for the browser console
39369
39584
  function parseConsoleCommands(raw) {
39370
- var blocked = ['i', 'include', 'require', 'external'];
39371
39585
  var str = standardizeConsoleCommands(raw);
39372
- var parsed;
39373
- parsed = parseCommands(str);
39586
+ var parsed = parseCommands(str);
39374
39587
  parsed.forEach(function(cmd) {
39375
- var i = blocked.indexOf(cmd.name);
39376
- if (i > -1) {
39377
- stop("The -" + blocked[i] + " command cannot be run in the browser");
39378
- }
39588
+ cli.checkCommandEnv(cmd.name);
39379
39589
  });
39380
39590
  return parsed;
39381
39591
  }
@@ -42779,7 +42989,6 @@ ${svg}
42779
42989
  LayerUtils,
42780
42990
  Lines,
42781
42991
  Logging,
42782
- MergeFiles,
42783
42992
  Merging,
42784
42993
  MosaicIndex$1,
42785
42994
  OptionParsingUtils,