mapshaper 0.6.61 → 0.6.63

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
@@ -13419,7 +13419,7 @@
13419
13419
 
13420
13420
  // Accepts a single value or a list of four values. List order is l,b,t,r
13421
13421
  function convertFourSides(opt, crs, bounds) {
13422
- var arr = opt.split(',');
13422
+ var arr = opt.includes(',') ? opt.split(',') : opt.split(' ');
13423
13423
  if (arr.length == 1) {
13424
13424
  arr = [arr[0], arr[0], arr[0], arr[0]];
13425
13425
  } else if (arr.length != 4) {
@@ -24550,6 +24550,9 @@ ${svg}
24550
24550
  DEFAULT: true,
24551
24551
  describe: 'JS expression to apply to each target feature'
24552
24552
  })
24553
+ .option('ids', { // undocumented, used by GUI
24554
+ type: 'numbers'
24555
+ })
24553
24556
  .option('where', whereOpt)
24554
24557
  .option('target', targetOpt);
24555
24558
 
@@ -24684,7 +24687,7 @@ ${svg}
24684
24687
  parser.command('graticule')
24685
24688
  .describe('create a graticule layer')
24686
24689
  .option('interval', {
24687
- describe: 'size of grid cells in degrees (options: 5 10 15 30 45, default is 10)',
24690
+ describe: 'size of grid cells in degrees (default is 10)',
24688
24691
  type: 'number'
24689
24692
  })
24690
24693
  .option('polygon', {
@@ -36955,128 +36958,6 @@ ${svg}
36955
36958
  }
36956
36959
  };
36957
36960
 
36958
- cmd.evaluateEachFeature = function(lyr, dataset, exp, opts) {
36959
- var n = getFeatureCount(lyr),
36960
- arcs = dataset.arcs,
36961
- compiled, filter;
36962
-
36963
- var exprOpts = {
36964
- no_return: true,
36965
- geojson_editor: expressionUsesGeoJSON(exp) ? getFeatureEditor(lyr, dataset) : null
36966
- };
36967
-
36968
- // TODO: consider not creating a data table -- not needed if expression only references geometry
36969
- if (n > 0 && !lyr.data) {
36970
- lyr.data = new DataTable(n);
36971
- }
36972
- if (opts && opts.where) {
36973
- filter = compileFeatureExpression(opts.where, lyr, arcs);
36974
- }
36975
- compiled = compileFeatureExpression(exp, lyr, arcs, exprOpts);
36976
- // call compiled expression with id of each record
36977
- for (var i=0; i<n; i++) {
36978
- if (!filter || filter(i)) {
36979
- compiled(i);
36980
- }
36981
- }
36982
-
36983
- var replacement = exprOpts.geojson_editor ? exprOpts.geojson_editor.done() : null;
36984
- if (replacement) {
36985
- replaceLayerContents(lyr, dataset, replacement);
36986
- }
36987
- };
36988
-
36989
- var externalCommands = {};
36990
-
36991
- cmd.registerCommand = function(name, params) {
36992
- var defn = {name: name, options: params.options || []};
36993
- // Add definitions of options common to all commands (TODO: remove duplication)
36994
- defn.options.push({name: 'target'});
36995
- utils.defaults(defn, params);
36996
- validateExternalCommand(defn);
36997
- externalCommands[name] = defn;
36998
- };
36999
-
37000
- function isValidExternalCommand(defn) {
37001
- try {
37002
- validateExternalCommand(defn);
37003
- return true;
37004
- } catch(e) {}
37005
- return false;
37006
- }
37007
-
37008
- function validateExternalCommand(defn) {
37009
- var targetTypes = ['layer', 'layers'];
37010
- if (typeof defn.command != 'function') {
37011
- stop('Expected "command" parameter function');
37012
- }
37013
- if (!defn.target) {
37014
- stop('Missing required "target" parameter');
37015
- }
37016
- if (!targetTypes.includes(defn.target)) {
37017
- stop('Unrecognized command target type:', defn.target);
37018
- }
37019
- }
37020
-
37021
- cmd.runExternalCommand = function(cmdOpts, catalog) {
37022
- var name = cmdOpts.name;
37023
- var cmdDefn = externalCommands[name];
37024
- if (!cmdDefn) {
37025
- stop('Unsupported command:', name);
37026
- }
37027
- var targetType = cmdDefn.target;
37028
- var opts = parseExternalCommand(name, cmdDefn, cmdOpts._);
37029
- var targets = catalog.findCommandTargets(opts.target || '*');
37030
- var target = targets[0];
37031
- var output;
37032
- if (!target) {
37033
- stop('Missing a target');
37034
- }
37035
- if (targetType == 'layer' && (target.layers.length != 1 || targets.length > 1)) {
37036
- stop('This command only supports targeting a single layer');
37037
- }
37038
- if (targets.length > 1) {
37039
- stop("Targetting layers from multiple datasets is not supported");
37040
- }
37041
- if (targetType == 'layer') {
37042
- output = cmdDefn.command(target.layers[0], target.dataset, opts.options);
37043
- } else if (targetType == 'layers') {
37044
- output = cmdDefn.command(target.layers, target.dataset, opts.options);
37045
- }
37046
- if (output) {
37047
- integrateOutput(output, target, catalog, opts);
37048
- }
37049
- };
37050
-
37051
- // TODO: remove restrictions on output data
37052
- function integrateOutput(output, input, catalog, opts) {
37053
- if (!output.dataset || !output.layers || output.layers.length > 0 === false) {
37054
- stop('Invalid command output');
37055
- }
37056
- if (output.dataset == input.dataset) {
37057
- stop('External commands are not currently allowed to modify input datasets');
37058
- }
37059
- if (output.dataset.layers.length != output.layers.length) {
37060
- stop('Currently not supported: targetting a subset of output layers');
37061
- }
37062
- if (!opts.no_replace) {
37063
- input.layers.forEach(function(lyr) {
37064
- catalog.deleteLayer(lyr, input.dataset);
37065
- });
37066
- }
37067
- catalog.addDataset(output.dataset);
37068
- }
37069
-
37070
- function parseExternalCommand(name, cmdDefn, tokens) {
37071
- var parser = new CommandParser();
37072
- var cmd = parser.command(name);
37073
- (cmdDefn.options || []).forEach(function(o) {
37074
- cmd.option(o.name, o);
37075
- });
37076
- var parsed = parser.parseArgv(['-' + name].concat(tokens));
37077
- return parsed[0];
37078
- }
37079
-
37080
36961
  cmd.filterGeom = function(lyr, arcs, opts) {
37081
36962
  if (!layerHasGeometry(lyr)) {
37082
36963
  stop("Layer is missing geometry");
@@ -37293,6 +37174,131 @@ ${svg}
37293
37174
  }) || a || b;
37294
37175
  }
37295
37176
 
37177
+ cmd.evaluateEachFeature = function(lyr, dataset, exp, opts) {
37178
+ var n = getFeatureCount(lyr),
37179
+ arcs = dataset.arcs,
37180
+ compiled, filter;
37181
+
37182
+ var exprOpts = {
37183
+ no_return: true,
37184
+ geojson_editor: expressionUsesGeoJSON(exp) ? getFeatureEditor(lyr, dataset) : null
37185
+ };
37186
+
37187
+ // TODO: consider not creating a data table -- not needed if expression only references geometry
37188
+ if (n > 0 && !lyr.data) {
37189
+ lyr.data = new DataTable(n);
37190
+ }
37191
+ if (opts && opts.where) {
37192
+ filter = compileFeatureExpression(opts.where, lyr, arcs);
37193
+ }
37194
+ if (opts && opts.ids) {
37195
+ filter = combineFilters(filter, getIdFilter(opts.ids));
37196
+ }
37197
+ compiled = compileFeatureExpression(exp, lyr, arcs, exprOpts);
37198
+ // call compiled expression with id of each record
37199
+ for (var i=0; i<n; i++) {
37200
+ if (!filter || filter(i)) {
37201
+ compiled(i);
37202
+ }
37203
+ }
37204
+
37205
+ var replacement = exprOpts.geojson_editor ? exprOpts.geojson_editor.done() : null;
37206
+ if (replacement) {
37207
+ replaceLayerContents(lyr, dataset, replacement);
37208
+ }
37209
+ };
37210
+
37211
+ var externalCommands = {};
37212
+
37213
+ cmd.registerCommand = function(name, params) {
37214
+ var defn = {name: name, options: params.options || []};
37215
+ // Add definitions of options common to all commands (TODO: remove duplication)
37216
+ defn.options.push({name: 'target'});
37217
+ utils.defaults(defn, params);
37218
+ validateExternalCommand(defn);
37219
+ externalCommands[name] = defn;
37220
+ };
37221
+
37222
+ function isValidExternalCommand(defn) {
37223
+ try {
37224
+ validateExternalCommand(defn);
37225
+ return true;
37226
+ } catch(e) {}
37227
+ return false;
37228
+ }
37229
+
37230
+ function validateExternalCommand(defn) {
37231
+ var targetTypes = ['layer', 'layers'];
37232
+ if (typeof defn.command != 'function') {
37233
+ stop('Expected "command" parameter function');
37234
+ }
37235
+ if (!defn.target) {
37236
+ stop('Missing required "target" parameter');
37237
+ }
37238
+ if (!targetTypes.includes(defn.target)) {
37239
+ stop('Unrecognized command target type:', defn.target);
37240
+ }
37241
+ }
37242
+
37243
+ cmd.runExternalCommand = function(cmdOpts, catalog) {
37244
+ var name = cmdOpts.name;
37245
+ var cmdDefn = externalCommands[name];
37246
+ if (!cmdDefn) {
37247
+ stop('Unsupported command:', name);
37248
+ }
37249
+ var targetType = cmdDefn.target;
37250
+ var opts = parseExternalCommand(name, cmdDefn, cmdOpts._);
37251
+ var targets = catalog.findCommandTargets(opts.target || '*');
37252
+ var target = targets[0];
37253
+ var output;
37254
+ if (!target) {
37255
+ stop('Missing a target');
37256
+ }
37257
+ if (targetType == 'layer' && (target.layers.length != 1 || targets.length > 1)) {
37258
+ stop('This command only supports targeting a single layer');
37259
+ }
37260
+ if (targets.length > 1) {
37261
+ stop("Targetting layers from multiple datasets is not supported");
37262
+ }
37263
+ if (targetType == 'layer') {
37264
+ output = cmdDefn.command(target.layers[0], target.dataset, opts.options);
37265
+ } else if (targetType == 'layers') {
37266
+ output = cmdDefn.command(target.layers, target.dataset, opts.options);
37267
+ }
37268
+ if (output) {
37269
+ integrateOutput(output, target, catalog, opts);
37270
+ }
37271
+ };
37272
+
37273
+ // TODO: remove restrictions on output data
37274
+ function integrateOutput(output, input, catalog, opts) {
37275
+ if (!output.dataset || !output.layers || output.layers.length > 0 === false) {
37276
+ stop('Invalid command output');
37277
+ }
37278
+ if (output.dataset == input.dataset) {
37279
+ stop('External commands are not currently allowed to modify input datasets');
37280
+ }
37281
+ if (output.dataset.layers.length != output.layers.length) {
37282
+ stop('Currently not supported: targetting a subset of output layers');
37283
+ }
37284
+ if (!opts.no_replace) {
37285
+ input.layers.forEach(function(lyr) {
37286
+ catalog.deleteLayer(lyr, input.dataset);
37287
+ });
37288
+ }
37289
+ catalog.addDataset(output.dataset);
37290
+ }
37291
+
37292
+ function parseExternalCommand(name, cmdDefn, tokens) {
37293
+ var parser = new CommandParser();
37294
+ var cmd = parser.command(name);
37295
+ (cmdDefn.options || []).forEach(function(o) {
37296
+ cmd.option(o.name, o);
37297
+ });
37298
+ var parsed = parser.parseArgv(['-' + name].concat(tokens));
37299
+ return parsed[0];
37300
+ }
37301
+
37296
37302
  cmd.filterIslands = function(lyr, dataset, optsArg) {
37297
37303
  var opts = utils.extend({sliver_control: 0}, optsArg); // no sliver control
37298
37304
  var arcs = dataset.arcs;
@@ -39228,7 +39234,9 @@ ${svg}
39228
39234
  //
39229
39235
  function createGraticule(P, outlined, opts) {
39230
39236
  var interval = opts.interval || 10;
39231
- if (![5,10,15,20,30,45].includes(interval)) stop('Invalid interval:', interval);
39237
+ if (Math.round(interval) != interval || interval > 0 === false) {
39238
+ stop('Invalid interval:', interval);
39239
+ }
39232
39240
  P.lam0 * 180 / Math.PI;
39233
39241
  var precision = interval > 10 ? 1 : 0.5; // degrees between each vertex
39234
39242
  var xstep = interval;
@@ -39269,6 +39277,7 @@ ${svg}
39269
39277
  return Math.abs(a - b) < interval / 5;
39270
39278
  }
39271
39279
 
39280
+ // extended: meridian extends to pole
39272
39281
  function createMeridian(x, extended) {
39273
39282
  var y0 = ystep <= 15 ? ystep : 0;
39274
39283
  createMeridianPart(x, -90 + y0, 90 - y0);
@@ -39319,58 +39328,74 @@ ${svg}
39319
39328
  print(str);
39320
39329
  };
39321
39330
 
39322
- function resetControlFlow(job) {
39323
- job.control = null;
39324
- }
39325
-
39326
39331
  function stopJob(job) {
39327
- getState(job).stopped = true;
39332
+ job.stopped = true;
39328
39333
  }
39329
39334
 
39330
39335
  function jobIsStopped(job) {
39331
- return getState(job).stopped === true;
39336
+ return job.stopped === true;
39332
39337
  }
39333
39338
 
39334
39339
  function inControlBlock(job) {
39335
- return !!getState(job).inControlBlock;
39340
+ return getStack(job).length > 0;
39341
+ }
39342
+
39343
+ function enterBlock(job) {
39344
+ var stack = getStack(job);
39345
+ // skip over a block if it is inside an inactive branch
39346
+ stack.push({
39347
+ active: false,
39348
+ complete: !inActiveBranch(job)
39349
+ });
39350
+ }
39351
+
39352
+ function leaveBlock(job) {
39353
+ var stack = getStack(job);
39354
+ stack.pop();
39336
39355
  }
39337
39356
 
39338
39357
  function enterActiveBranch(job) {
39339
- var state = getState(job);
39340
- state.inControlBlock = true;
39341
- state.active = true;
39342
- state.complete = true;
39358
+ var block = getCurrentBlock(job);
39359
+ block.active = true;
39360
+ block.complete = true;
39343
39361
  }
39344
39362
 
39345
39363
  function enterInactiveBranch(job) {
39346
- var state = getState(job);
39347
- state.inControlBlock = true;
39348
- state.active = false;
39364
+ var block = getCurrentBlock(job);
39365
+ block.active = false;
39366
+ }
39367
+
39368
+ function blockIsComplete(job) {
39369
+ var block = getCurrentBlock(job);
39370
+ return block.complete;
39349
39371
  }
39350
39372
 
39351
- function blockWasActive(job) {
39352
- return !!getState(job).complete;
39373
+ function getCurrentBlock(job) {
39374
+ var stack = getStack(job);
39375
+ return stack[stack.length-1];
39353
39376
  }
39354
39377
 
39378
+ // A branch is considered to be active if it and all its parents are active
39379
+ // (Main branch is considered to be active)
39355
39380
  function inActiveBranch(job) {
39356
- return !!getState(job).active;
39381
+ var stack = getStack(job);
39382
+ return stack.length === 0 || stack.every(block => block.active);
39357
39383
  }
39358
39384
 
39359
- function getState(job) {
39360
- return job.control || (job.control = {});
39385
+ function getStack(job) {
39386
+ job.control = job.control || {stack: []};
39387
+ return job.control.stack;
39361
39388
  }
39362
39389
 
39363
39390
  function skipCommand(cmdName, job) {
39364
39391
  // allow all control commands to run
39365
39392
  if (jobIsStopped(job)) return true;
39366
39393
  if (isControlFlowCommand(cmdName)) return false;
39367
- return inControlBlock(job) && !inActiveBranch(job);
39394
+ return !inActiveBranch(job);
39368
39395
  }
39369
39396
 
39370
39397
  cmd.if = function(job, opts) {
39371
- if (inControlBlock(job)) {
39372
- stop('Nested -if commands are not supported.');
39373
- }
39398
+ enterBlock(job);
39374
39399
  evaluateIf(job, opts);
39375
39400
  };
39376
39401
 
@@ -39385,7 +39410,7 @@ ${svg}
39385
39410
  if (!inControlBlock(job)) {
39386
39411
  stop('-else command must be preceded by an -if command.');
39387
39412
  }
39388
- if (blockWasActive(job)) {
39413
+ if (blockIsComplete(job)) {
39389
39414
  enterInactiveBranch(job);
39390
39415
  } else {
39391
39416
  enterActiveBranch(job);
@@ -39396,7 +39421,7 @@ ${svg}
39396
39421
  if (!inControlBlock(job)) {
39397
39422
  stop('-endif command must be preceded by an -if command.');
39398
39423
  }
39399
- resetControlFlow(job);
39424
+ leaveBlock(job);
39400
39425
  };
39401
39426
 
39402
39427
  function isControlFlowCommand(cmd) {
@@ -39404,21 +39429,14 @@ ${svg}
39404
39429
  }
39405
39430
 
39406
39431
  function test(catalog, opts) {
39407
- // var targ = getTargetLayer(catalog, opts);
39408
39432
  if (opts.expression) {
39409
39433
  return compileIfCommandExpression(opts.expression, catalog, opts)();
39410
39434
  }
39411
- // if (opts.empty) {
39412
- // return layerIsEmpty(targ.layer);
39413
- // }
39414
- // if (opts.not_empty) {
39415
- // return !layerIsEmpty(targ.layer);
39416
- // }
39417
39435
  return true;
39418
39436
  }
39419
39437
 
39420
39438
  function evaluateIf(job, opts) {
39421
- if (!blockWasActive(job) && test(job.catalog, opts)) {
39439
+ if (!blockIsComplete(job) && test(job.catalog, opts)) {
39422
39440
  enterActiveBranch(job);
39423
39441
  } else {
39424
39442
  enterInactiveBranch(job);
@@ -42016,24 +42034,23 @@ ${svg}
42016
42034
  // import { importGeoJSON } from '../geojson/geojson-import';
42017
42035
 
42018
42036
  function getTargetProxy(target) {
42019
- var lyr = target.layers[0];
42020
- var data = getLayerInfo(lyr, target.dataset); // layer_name, feature_count etc
42021
- data.layer = lyr;
42022
- data.dataset = target.dataset;
42023
- addGetters(data, {
42037
+ var proxy = getLayerInfo(target.layer, target.dataset); // layer_name, feature_count etc
42038
+ proxy.layer = target.layer;
42039
+ proxy.dataset = target.dataset;
42040
+ addGetters(proxy, {
42024
42041
  // export as an object, not a string or buffer
42025
42042
  geojson: getGeoJSON
42026
42043
  });
42027
42044
 
42028
42045
  function getGeoJSON() {
42029
- var features = exportLayerAsGeoJSON(lyr, target.dataset, {rfc7946: true}, true);
42046
+ var features = exportLayerAsGeoJSON(target.layer, target.dataset, {rfc7946: true}, true);
42030
42047
  return {
42031
42048
  type: 'FeatureCollection',
42032
42049
  features: features
42033
42050
  };
42034
42051
  }
42035
42052
 
42036
- return data;
42053
+ return proxy;
42037
42054
  }
42038
42055
 
42039
42056
  // Support for evaluating expressions embedded in curly-brace templates
@@ -42042,8 +42059,20 @@ ${svg}
42042
42059
  async function evalTemplateExpression(expression, targets, ctx) {
42043
42060
  ctx = ctx || getBaseContext();
42044
42061
  // TODO: throw an error if target is used when there are multiple targets
42045
- if (targets && targets.length == 1) {
42046
- Object.defineProperty(ctx, 'target', {value: getTargetProxy(targets[0])});
42062
+ if (targets) {
42063
+ var proxies = expandCommandTargets(targets).reduce(function(memo, target) {
42064
+ var proxy = getTargetProxy(target);
42065
+ memo.push(proxy);
42066
+ // index targets by layer name too
42067
+ if (target.layer.name) {
42068
+ memo[target.layer.name] = proxy;
42069
+ }
42070
+ return memo;
42071
+ }, []);
42072
+ Object.defineProperty(ctx, 'targets', {value: proxies});
42073
+ if (proxies.length == 1) {
42074
+ Object.defineProperty(ctx, 'target', {value: proxies[0]});
42075
+ }
42047
42076
  }
42048
42077
  // Add global functions and data to the expression context
42049
42078
  // (e.g. functions imported via the -require command)
@@ -42093,7 +42122,12 @@ ${svg}
42093
42122
  function applyReplacements(template, replacements) {
42094
42123
  var parts = parseTemplateParts(template);
42095
42124
  return parts.reduce(function(memo, s, i) {
42096
- return i % 2 == 1 ? memo + (replacements.shift() || '') : memo + s;
42125
+ if (i % 2 == 1) {
42126
+ memo += replacements.length ? replacements.shift() : '';
42127
+ } else {
42128
+ memo += s;
42129
+ }
42130
+ return memo;
42097
42131
  }, '');
42098
42132
  }
42099
42133
 
@@ -44958,7 +44992,7 @@ ${svg}
44958
44992
  });
44959
44993
  }
44960
44994
 
44961
- var version = "0.6.61";
44995
+ var version = "0.6.63";
44962
44996
 
44963
44997
  // Parse command line args into commands and run them
44964
44998
  // 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.61",
3
+ "version": "0.6.63",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",