mapshaper 0.6.46 → 0.6.48

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/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.46";
3
+ var VERSION = "0.6.48";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -14452,16 +14452,17 @@
14452
14452
  }, ctx);
14453
14453
  }
14454
14454
 
14455
- function getBaseContext() {
14455
+ function getBaseContext(ctx) {
14456
+ ctx = ctx || {};
14456
14457
  // Mask global properties (is this effective/worth doing?)
14457
- var obj = {globalThis: void 0}; // some globals are not iterable
14458
+ ctx.globalThis = void 0; // some globals are not iterable
14458
14459
  (function() {
14459
14460
  for (var key in this) {
14460
- obj[key] = void 0;
14461
+ ctx[key] = void 0;
14461
14462
  }
14462
14463
  }());
14463
- obj.console = console;
14464
- return obj;
14464
+ ctx.console = console;
14465
+ return ctx;
14465
14466
  }
14466
14467
 
14467
14468
  var Expressions = /*#__PURE__*/Object.freeze({
@@ -21359,7 +21360,7 @@ ${svg}
21359
21360
 
21360
21361
  // export layers as TopoJSON named objects
21361
21362
  topology.objects = dataset.layers.reduce(function(objects, lyr, i) {
21362
- var name = lyr.name || "layer" + (i + 1);
21363
+ var name = lyr.name || 'layer' + (i + 1);
21363
21364
  objects[name] = TopoJSON.exportLayer(lyr, dataset.arcs, opts);
21364
21365
  return objects;
21365
21366
  }, {});
@@ -21722,7 +21723,7 @@ ${svg}
21722
21723
  return files;
21723
21724
  }
21724
21725
 
21725
- // Return an array of objects with "filename" and "content" members.
21726
+ // Return an array of objects with 'filename' and 'content' members.
21726
21727
  //
21727
21728
  function exportFileContent(dataset, opts) {
21728
21729
  var outFmt = opts.format = getOutputFormat(dataset, opts),
@@ -21730,9 +21731,9 @@ ${svg}
21730
21731
  files = [];
21731
21732
 
21732
21733
  if (!outFmt) {
21733
- error("Missing output format");
21734
+ error('Missing output format');
21734
21735
  } else if (!exporter) {
21735
- error("Unknown output format:", outFmt);
21736
+ error('Unknown output format:', outFmt);
21736
21737
  }
21737
21738
 
21738
21739
  // shallow-copy dataset and layers, so layers can be renamed for export
@@ -21802,7 +21803,7 @@ ${svg}
21802
21803
 
21803
21804
  return {
21804
21805
  content: JSON.stringify(index),
21805
- filename: "bbox-index.json"
21806
+ filename: 'bbox-index.json'
21806
21807
  };
21807
21808
  }
21808
21809
 
@@ -21814,14 +21815,14 @@ ${svg}
21814
21815
  if (lyr.shapes && utils.some(lyr.shapes, function(o) {
21815
21816
  return !!o;
21816
21817
  })) {
21817
- error("A layer contains shape records and a null geometry type");
21818
+ error('A layer contains shape records and a null geometry type');
21818
21819
  }
21819
21820
  } else {
21820
21821
  if (!utils.contains(['polygon', 'polyline', 'point'], lyr.geometry_type)) {
21821
- error ("A layer has an invalid geometry type:", lyr.geometry_type);
21822
+ error ('A layer has an invalid geometry type:', lyr.geometry_type);
21822
21823
  }
21823
21824
  if (!lyr.shapes) {
21824
- error ("A layer is missing shape data");
21825
+ error ('A layer is missing shape data');
21825
21826
  }
21826
21827
  }
21827
21828
  });
@@ -21831,15 +21832,15 @@ ${svg}
21831
21832
  var index = {};
21832
21833
  files.forEach(function(file, i) {
21833
21834
  var filename = file.filename;
21834
- if (!filename) error("Missing a filename for file" + i);
21835
- if (filename in index) error("Duplicate filename", filename);
21835
+ if (!filename) error('Missing a filename for file' + i);
21836
+ if (filename in index) error('Duplicate filename', filename);
21836
21837
  index[filename] = true;
21837
21838
  });
21838
21839
  }
21839
21840
 
21840
21841
  function assignUniqueLayerNames(layers) {
21841
21842
  var names = layers.map(function(lyr) {
21842
- return lyr.name || "layer";
21843
+ return lyr.name || 'layer';
21843
21844
  });
21844
21845
  var uniqueNames = utils.uniqifyNames(names);
21845
21846
  layers.forEach(function(lyr, i) {
@@ -22674,12 +22675,9 @@ ${svg}
22674
22675
  });
22675
22676
 
22676
22677
  function validateInputOpts(cmd) {
22677
- var o = cmd.options,
22678
- _ = cmd._;
22678
+ var o = cmd.options;
22679
+ cmd._;
22679
22680
 
22680
- if (_.length > 0 && !o.files) {
22681
- o.files = _;
22682
- }
22683
22681
  if (o.files) {
22684
22682
  o.files = cli.expandInputFiles(o.files);
22685
22683
  if (o.files[0] == '-' || o.files[0] == '/dev/stdin') {
@@ -22688,8 +22686,8 @@ ${svg}
22688
22686
  }
22689
22687
  }
22690
22688
 
22691
- if ("precision" in o && o.precision > 0 === false) {
22692
- error("precision= option should be a positive number");
22689
+ if ('precision' in o && o.precision > 0 === false) {
22690
+ error('precision= option should be a positive number');
22693
22691
  }
22694
22692
 
22695
22693
  if (o.encoding) {
@@ -22698,36 +22696,15 @@ ${svg}
22698
22696
  }
22699
22697
 
22700
22698
  function validateSimplifyOpts(cmd) {
22701
- var o = cmd.options,
22702
- arg = cmd._[0];
22703
-
22704
- if (arg) {
22705
- if (/^[0-9.]+%?$/.test(arg)) {
22706
- o.percentage = utils.parsePercent(arg);
22707
- } else {
22708
- error("Unparsable option:", arg);
22709
- }
22710
- }
22711
-
22699
+ var o = cmd.options;
22712
22700
  if (!o.interval && !o.percentage && !o.resolution) {
22713
- error("Command requires an interval, percentage or resolution parameter");
22701
+ error('Command requires an interval, percentage or resolution parameter');
22714
22702
  }
22715
22703
  }
22716
22704
 
22717
22705
  function validateProjOpts(cmd) {
22718
- var _ = cmd._;
22719
-
22720
- if (_.length > 0 && !cmd.options.crs) {
22721
- cmd.options.crs = _.join(' ');
22722
- _ = [];
22723
- }
22724
-
22725
- if (_.length > 0) {
22726
- error("Received one or more unexpected parameters: " + _.join(', '));
22727
- }
22728
-
22729
22706
  if (!(cmd.options.crs || cmd.options.match || cmd.options.init)) {
22730
- stop("Missing projection data");
22707
+ stop('Missing projection data');
22731
22708
  }
22732
22709
  }
22733
22710
 
@@ -22742,25 +22719,24 @@ ${svg}
22742
22719
 
22743
22720
  function validateExpressionOpt(cmd) {
22744
22721
  if (!cmd.options.expression) {
22745
- error("Command requires a JavaScript expression");
22722
+ error('Command requires a JavaScript expression');
22746
22723
  }
22747
22724
  }
22748
22725
 
22749
22726
  function validateOutputOpts(cmd) {
22750
- var _ = cmd._,
22751
- o = cmd.options,
22752
- arg = _[0] || "",
22727
+ var o = cmd.options,
22728
+ arg = o._ || '',
22753
22729
  pathInfo = parseLocalPath(arg);
22754
22730
 
22755
- if (_.length > 1) {
22756
- error("Command takes one file or directory argument");
22757
- }
22731
+ // if (!arg) {
22732
+ // error('Command requires an output file or directory.');
22733
+ // }
22758
22734
 
22759
22735
  if (arg == '-' || arg == '/dev/stdout') {
22760
22736
  o.stdout = true;
22761
22737
  } else if (arg && !pathInfo.extension) {
22762
22738
  if (!cli.isDirectory(arg)) {
22763
- error("Unknown output option:", arg);
22739
+ error('Unknown output option:', arg);
22764
22740
  }
22765
22741
  o.directory = arg;
22766
22742
  } else if (arg) {
@@ -22788,7 +22764,7 @@ ${svg}
22788
22764
  }
22789
22765
 
22790
22766
  if (filenameIsUnsupportedOutputType(o.file)) {
22791
- error("Output file looks like an unsupported file type:", o.file);
22767
+ error('Output file looks like an unsupported file type:', o.file);
22792
22768
  }
22793
22769
  }
22794
22770
 
@@ -22802,15 +22778,15 @@ ${svg}
22802
22778
  o.delimiter = o.delimiter || '\t';
22803
22779
  }
22804
22780
  if (!isSupportedOutputFormat(o.format)) {
22805
- error("Unsupported output format:", o.format);
22781
+ error('Unsupported output format:', o.format);
22806
22782
  }
22807
22783
  }
22808
22784
 
22809
22785
  if (o.delimiter) {
22810
- // convert "\t" '\t' \t to tab
22786
+ // convert '\t' '\t' \t to tab
22811
22787
  o.delimiter = o.delimiter.replace(/^["']?\\t["']?$/, '\t');
22812
22788
  if (!isSupportedDelimiter(o.delimiter)) {
22813
- error("Unsupported delimiter:", o.delimiter);
22789
+ error('Unsupported delimiter:', o.delimiter);
22814
22790
  }
22815
22791
  }
22816
22792
 
@@ -22823,12 +22799,12 @@ ${svg}
22823
22799
  }
22824
22800
 
22825
22801
  // topojson-specific
22826
- if ("quantization" in o && o.quantization > 0 === false) {
22827
- error("quantization= option should be a nonnegative integer");
22802
+ if ('quantization' in o && o.quantization > 0 === false) {
22803
+ error('quantization= option should be a nonnegative integer');
22828
22804
  }
22829
22805
 
22830
- if ("topojson_precision" in o && o.topojson_precision > 0 === false) {
22831
- error("topojson-precision= option should be a positive number");
22806
+ if ('topojson_precision' in o && o.topojson_precision > 0 === false) {
22807
+ error('topojson-precision= option should be a positive number');
22832
22808
  }
22833
22809
  }
22834
22810
 
@@ -23014,14 +22990,18 @@ ${svg}
23014
22990
  if (!cmdName) {
23015
22991
  stop("Invalid command:", argv[0]);
23016
22992
  }
23017
- cmdDef = findCommandDefn(cmdName, commandDefs);
22993
+ cmdDef = findCommandDefn(cmdName, commandDefs) || null;
23018
22994
  if (!cmdDef) {
23019
- // In order to support adding commands at runtime, unknown commands
23020
- // are parsed without options (tokens get stored for later parsing)
23021
- // stop("Unknown command:", cmdName);
23022
- cmdDef = {name: cmdName, options: [], multi_arg: true};
22995
+ cmd = parseUnknownCommandOptions(argv, cmdName);
22996
+ } else {
22997
+ cmd = parseCommandOptions(argv, cmdDef);
23023
22998
  }
23024
- cmd = {
22999
+ commands.push(cmd);
23000
+ }
23001
+ return commands;
23002
+
23003
+ function parseCommandOptions(argv, cmdDef) {
23004
+ var cmd = {
23025
23005
  name: cmdDef.name,
23026
23006
  options: {},
23027
23007
  _: []
@@ -23032,25 +23012,32 @@ ${svg}
23032
23012
  }
23033
23013
 
23034
23014
  try {
23035
- if (cmd._.length > 0 && cmdDef.no_arg) {
23036
- error("Received one or more unexpected parameters:", cmd._.join(' '));
23037
- }
23038
- if (cmd._.length > 1 && !cmdDef.multi_arg) {
23039
- error("Command expects a single value. Received:", cmd._.join(' '));
23040
- }
23041
- if (cmdDef.default && cmd._.length == 1) {
23042
- // TODO: support multiple-token values, like -i filenames
23015
+ if (cmd._.length > 0) {
23043
23016
  readDefaultOptionValue(cmd, cmdDef);
23044
23017
  }
23045
23018
  if (cmdDef.validate) {
23046
23019
  cmdDef.validate(cmd);
23047
23020
  }
23021
+ delete cmd.options._; // kludge to remove -o placeholder option
23048
23022
  } catch(e) {
23049
23023
  stop("[" + cmdName + "] " + e.message);
23050
23024
  }
23051
- commands.push(cmd);
23025
+ return cmd;
23026
+ }
23027
+
23028
+ function parseUnknownCommandOptions(argv, cmdName) {
23029
+ // In order to support adding commands at runtime, unknown commands
23030
+ // are parsed without options (tokens get stored for later parsing)
23031
+ var cmd = {
23032
+ name: cmdName,
23033
+ options: {},
23034
+ _: []
23035
+ };
23036
+ while (argv.length > 0 && !tokenLooksLikeCommand(argv[0])) {
23037
+ cmd._.push(argv.shift());
23038
+ }
23039
+ return cmd;
23052
23040
  }
23053
- return commands;
23054
23041
 
23055
23042
  function tokenLooksLikeCommand(s) {
23056
23043
  if (invalidCommandRxp.test(s)) {
@@ -23080,11 +23067,7 @@ ${svg}
23080
23067
  }
23081
23068
 
23082
23069
  if (!optDef) {
23083
- // REMOVING quote trimming -- it prevents the use of quoted commands in -run (for example)
23084
- // token is not a defined option; add it to _ array for later processing
23085
- // Stripping surrounding quotes here, although this may not be necessary since
23086
- // (some, most, all?) shells seem to remove quotes.
23087
- // cmd._.push(utils.trimQuotes(token));
23070
+ // token is not a known option -- add to array of unnamed options
23088
23071
  cmd._.push(token);
23089
23072
  return;
23090
23073
  }
@@ -23113,9 +23096,36 @@ ${svg}
23113
23096
  return parseOptionValue(argv.shift(), optDef); // remove token from argv
23114
23097
  }
23115
23098
 
23099
+ // convert strings in cmd._ array to command parameers in cmd.options object
23100
+ //
23116
23101
  function readDefaultOptionValue(cmd, cmdDef) {
23117
- var optDef = findOptionDefn(cmdDef.default, cmdDef);
23118
- cmd.options[cmdDef.default] = readOptionValue(cmd._, optDef);
23102
+ var optDef = findDefaultOptionDefn(cmdDef);
23103
+ var argv = cmd._;
23104
+ var value;
23105
+ if (cmdDef)
23106
+ if (!optDef) {
23107
+ // no option has been specified as the default option
23108
+ error('Received one or more unexpected parameters:', argv.join(' '));
23109
+ }
23110
+ // DEFAULT may be true (simple case of one argument) or an object
23111
+ var argDef = optDef.DEFAULT === true ? {} : optDef.DEFAULT;
23112
+ argDef.type = argDef.type || optDef.type || 'string';
23113
+ argDef.name = optDef.name; // used in parse error message
23114
+
23115
+ if (argv.length > 1 && !argDef.multi_arg) {
23116
+ error((argDef.multi_error_msg || 'Command expects a single value.'),
23117
+ 'Received:', argv.join(' '));
23118
+ }
23119
+
23120
+ argv = argv.map(arg => parseOptionValue(arg, argDef));
23121
+ if (!argDef.multi_arg) {
23122
+ value = argv[0];
23123
+ } else if (utils.isString(argDef.join)) {
23124
+ value = argv.join(argDef.join);
23125
+ } else {
23126
+ value = argv;
23127
+ }
23128
+ cmd.options[optDef.name] = value;
23119
23129
  }
23120
23130
 
23121
23131
  function parseOptionValue(token, optDef) {
@@ -23193,15 +23203,15 @@ ${svg}
23193
23203
 
23194
23204
  function getSingleCommandLines(cmd) {
23195
23205
  var lines = [];
23196
- // command name
23197
- lines.push('COMMAND', getCommandLine(cmd));
23206
+ var options = [];
23207
+ cmd.options.forEach(function(opt) {
23208
+ options = options.concat(getOptionLines(opt));
23209
+ });
23198
23210
 
23199
- // options
23200
- if (cmd.options.length > 0) {
23211
+ lines.push('COMMAND', getCommandLine(cmd));
23212
+ if (options.length > 0) {
23201
23213
  lines.push('', 'OPTIONS');
23202
- cmd.options.forEach(function(opt) {
23203
- lines = lines.concat(getOptionLines(opt, cmd));
23204
- });
23214
+ lines = lines.concat(options);
23205
23215
  }
23206
23216
 
23207
23217
  // examples
@@ -23223,7 +23233,7 @@ ${svg}
23223
23233
  var label;
23224
23234
  if (!description) ; else if (opt.label) {
23225
23235
  lines.push([opt.label, description]);
23226
- } else if (opt.name == cmd.default) {
23236
+ } else if (opt.DEFAULT) {
23227
23237
  label = opt.name + '=';
23228
23238
  lines.push(['<' + opt.name + '>', 'shortcut for ' + label]);
23229
23239
  lines.push([label, description]);
@@ -23305,6 +23315,12 @@ ${svg}
23305
23315
  return o.name === name || o.alias === name || o.old_alias === name;
23306
23316
  });
23307
23317
  }
23318
+
23319
+ function findDefaultOptionDefn(cmdDef) {
23320
+ return utils.find(cmdDef.options, function(o) {
23321
+ return !!o.DEFAULT;
23322
+ });
23323
+ }
23308
23324
  }
23309
23325
 
23310
23326
  function CommandOptions(name) {
@@ -23348,17 +23364,10 @@ ${svg}
23348
23364
  return this;
23349
23365
  };
23350
23366
 
23351
- this.flag = function(name) {
23352
- _command[name] = true;
23353
- return this;
23354
- };
23355
-
23356
23367
  this.option = function(name, opts) {
23357
23368
  opts = utils.extend({}, opts); // accept just a name -- some options don't need properties
23358
23369
  if (!utils.isString(name) || !name) error("Missing option name");
23359
23370
  if (!utils.isObject(opts)) error("Invalid option definition:", opts);
23360
- // default option -- assign unnamed argument to this option
23361
- if (opts.DEFAULT) _command.default = name;
23362
23371
  opts.name = name;
23363
23372
  _command.options.push(opts);
23364
23373
  return this;
@@ -23480,9 +23489,11 @@ ${svg}
23480
23489
  parser.command('i')
23481
23490
  .describe('input one or more files')
23482
23491
  .validate(validateInputOpts)
23483
- .flag('multi_arg')
23484
23492
  .option('files', {
23485
- DEFAULT: true,
23493
+ DEFAULT: {
23494
+ multi_arg: true,
23495
+ type: 'string'
23496
+ },
23486
23497
  type: 'strings',
23487
23498
  describe: 'one or more files to import, or - to use stdin'
23488
23499
  })
@@ -23573,7 +23584,10 @@ ${svg}
23573
23584
  .validate(validateOutputOpts)
23574
23585
  .option('_', {
23575
23586
  label: '<file|directory>',
23576
- describe: '(optional) name of output file or directory, - for stdout'
23587
+ describe: '(optional) name of output file or directory, - for stdout',
23588
+ DEFAULT: {
23589
+ multi_error_msg: 'Command takes one file or directory argument.'
23590
+ }
23577
23591
  })
23578
23592
  .option('format', {
23579
23593
  describe: 'options: shapefile,geojson,topojson,json,dbf,csv,tsv,svg'
@@ -23757,7 +23771,6 @@ ${svg}
23757
23771
 
23758
23772
  parser.command('affine')
23759
23773
  .describe('transform coordinates by shifting, scaling and rotating')
23760
- .flag('no_args')
23761
23774
  .option('shift', {
23762
23775
  type: 'strings',
23763
23776
  describe: 'x,y offsets in source units (e.g. 5000,-5000)'
@@ -23996,7 +24009,6 @@ ${svg}
23996
24009
 
23997
24010
  parser.command('colorizer')
23998
24011
  .describe('define a function to convert data values to color classes')
23999
- .flag('no_arg')
24000
24012
  .option('colors', {
24001
24013
  describe: 'comma-separated list of CSS colors',
24002
24014
  type: 'colors'
@@ -24185,7 +24197,6 @@ ${svg}
24185
24197
 
24186
24198
  parser.command('drop')
24187
24199
  .describe('delete layer(s) or elements within the target layer(s)')
24188
- .flag('no_arg') // prevent trying to pass a list of layer names as default option
24189
24200
  .option('geometry', {
24190
24201
  describe: 'delete all geometry from the target layer(s)',
24191
24202
  type: 'flag'
@@ -24392,7 +24403,6 @@ ${svg}
24392
24403
 
24393
24404
  parser.command('innerlines')
24394
24405
  .describe('convert polygons to polylines along shared edges')
24395
- .flag('no_arg')
24396
24406
  .option('where', whereOpt2)
24397
24407
  // .option('each', eachOpt2)
24398
24408
  .option('name', nameOpt)
@@ -24508,7 +24518,6 @@ ${svg}
24508
24518
 
24509
24519
  parser.command('merge-layers')
24510
24520
  .describe('merge multiple layers into as few layers as possible')
24511
- .flag('no_arg')
24512
24521
  .option('force', {
24513
24522
  type: 'flag',
24514
24523
  describe: 'merge layers with inconsistent data fields'
@@ -24530,9 +24539,10 @@ ${svg}
24530
24539
  parser.command('point-grid')
24531
24540
  .describe('create a rectangular grid of points')
24532
24541
  .validate(validateGridOpts)
24533
- .option('-', {
24542
+ .option('_', {
24534
24543
  label: '<cols,rows>',
24535
- describe: 'size of the grid, e.g. -point-grid 100,100'
24544
+ describe: 'size of the grid, e.g. -point-grid 100,100',
24545
+ DEFAULT: true
24536
24546
  })
24537
24547
  .option('interval', {
24538
24548
  describe: 'distance between adjacent points, in source units',
@@ -24554,7 +24564,6 @@ ${svg}
24554
24564
 
24555
24565
  parser.command('points')
24556
24566
  .describe('create a point layer from a different layer type')
24557
- .flag('no_arg')
24558
24567
  .option('x', {
24559
24568
  describe: 'field containing x coordinate'
24560
24569
  })
@@ -24616,9 +24625,11 @@ ${svg}
24616
24625
 
24617
24626
  parser.command('proj')
24618
24627
  .describe('project your data (using Proj.4)')
24619
- .flag('multi_arg')
24620
24628
  .option('crs', {
24621
- DEFAULT: true,
24629
+ DEFAULT: {
24630
+ multi_arg: true,
24631
+ join: ' '
24632
+ },
24622
24633
  describe: 'set destination CRS using a Proj.4 definition or alias'
24623
24634
  })
24624
24635
  .option('projection', {
@@ -24694,7 +24705,6 @@ ${svg}
24694
24705
  })
24695
24706
  .option('target', targetOpt);
24696
24707
 
24697
-
24698
24708
  parser.command('simplify')
24699
24709
  .validate(validateSimplifyOpts)
24700
24710
  .example('Retain 10% of removable vertices\n$ mapshaper input.shp -simplify 10%')
@@ -24848,7 +24858,8 @@ ${svg}
24848
24858
  parser.command('split-on-grid')
24849
24859
  .describe('split features into separate layers using a grid')
24850
24860
  .validate(validateGridOpts)
24851
- .option('-', {
24861
+ .option('_', {
24862
+ DEFAULT: true,
24852
24863
  label: '<cols,rows>',
24853
24864
  describe: 'size of the grid, e.g. -split-on-grid 12,10'
24854
24865
  })
@@ -25445,7 +25456,12 @@ ${svg}
25445
25456
 
25446
25457
  parser.command('comment')
25447
25458
  .describe('add a comment to the sequence of commands')
25448
- .flag('multi_arg');
25459
+ .option('message', {
25460
+ DEFAULT: {
25461
+ multi_arg: true,
25462
+ join: ' '
25463
+ }
25464
+ });
25449
25465
 
25450
25466
  parser.command('encodings')
25451
25467
  .describe('print list of supported text encodings (for .dbf import)');
@@ -25476,7 +25492,12 @@ ${svg}
25476
25492
 
25477
25493
  parser.command('print')
25478
25494
  .describe('print a message to stdout')
25479
- .flag('multi_arg');
25495
+ .option('message', {
25496
+ DEFAULT: {
25497
+ multi_arg: true,
25498
+ join: ' '
25499
+ }
25500
+ });
25480
25501
 
25481
25502
  parser.command('projections')
25482
25503
  .describe('print list of supported projections');
@@ -28108,6 +28129,8 @@ ${svg}
28108
28129
  opts = Object.assign({}, opts);
28109
28130
  opts.input = Object.assign({}, opts.input); // make sure we have a cache
28110
28131
 
28132
+ convertDataObjects(files, opts.input);
28133
+
28111
28134
  files = expandFiles(files, opts.input);
28112
28135
 
28113
28136
  if (files.length === 0) {
@@ -28138,6 +28161,22 @@ ${svg}
28138
28161
  return dataset;
28139
28162
  };
28140
28163
 
28164
+ // replace any JSON data objects with filenames and cache the data
28165
+ function convertDataObjects(files, cache) {
28166
+ var names = files.map(str => stringLooksLikeJSON(str) ? 'layer.json' : null).filter(Boolean);
28167
+ if (names.length === 0) return;
28168
+ if (names.length > 1) {
28169
+ // make unique names if importing multiple objects
28170
+ names = utils.uniqifyNames(names, formatVersionedFileName);
28171
+ }
28172
+ files.forEach((str, i) => {
28173
+ if (!stringLooksLikeJSON(str)) return;
28174
+ var name = names.shift();
28175
+ cache[name] = str;
28176
+ files[i] = name;
28177
+ });
28178
+ }
28179
+
28141
28180
  async function importMshpFile(file, catalog, opts) {
28142
28181
  var buf = cli.readFile(file, null, opts.input);
28143
28182
  var obj = await unpackSessionData(buf);
@@ -41464,31 +41503,106 @@ ${svg}
41464
41503
  parseConsoleCommands: parseConsoleCommands
41465
41504
  });
41466
41505
 
41506
+ // import { importGeoJSON } from '../geojson/geojson-import';
41507
+
41508
+ function getTargetProxy(target) {
41509
+ var lyr = target.layers[0];
41510
+ var data = getLayerInfo(lyr, target.dataset); // layer_name, feature_count etc
41511
+ data.layer = lyr;
41512
+ data.dataset = target.dataset;
41513
+ addGetters(data, {
41514
+ // export as an object, not a string or buffer
41515
+ geojson: getGeoJSON
41516
+ });
41517
+
41518
+ function getGeoJSON() {
41519
+ var features = exportLayerAsGeoJSON(lyr, target.dataset, {}, true);
41520
+ return {
41521
+ type: 'FeatureCollection',
41522
+ features: features
41523
+ };
41524
+ }
41525
+
41526
+ return data;
41527
+ }
41528
+
41529
+ function getIOProxy(job) {
41530
+ var obj = {
41531
+ _cache: {}
41532
+ };
41533
+ obj.addInputFile = function(filename, content) {
41534
+ obj._cache[filename] = content;
41535
+ };
41536
+ return obj;
41537
+ }
41538
+
41539
+ function commandTakesFileInput(name) {
41540
+ return (name == 'i' || name == 'join' || name == 'erase' || name == 'clip' || name == 'include');
41541
+ }
41542
+
41543
+ // TODO: implement these and other functions
41544
+ // TODO: move this info into individual command definitions (to make
41545
+ // commands more modular and support a future plugin system)
41546
+
41547
+ // export function commandMayRemoveArcs(cmd) {
41548
+
41549
+ // }
41550
+
41551
+ // export function commandMayChangeArcs(cmd) {
41552
+ // // return arcsMayHaveChanged({[cmd]: true});
41553
+ // }
41554
+
41555
+ // export function arcsMayNeedCleanup(flags) {
41556
+ // return flags.clip || flags.erase || flags.slice || flags.rectangle || flags.buffer ||
41557
+ // flags.union || flags.clean || flags.drop || false;
41558
+ // }
41559
+
41560
+ // export function arcsMayBeChanged(flags) {
41561
+ // return arcsMayNeedCleanup(flags) || flags.proj || flags.simplify ||
41562
+ // flags.simplify_method || flags.arc_count || flags.repair || flags.affine ||
41563
+ // flags.mosaic || flags.snap;
41564
+ // }
41565
+
41467
41566
  cmd.run = async function(job, targets, opts) {
41468
- var commandStr, commands;
41567
+ var tmp, commands;
41469
41568
  if (!opts.expression) {
41470
41569
  stop("Missing expression parameter");
41471
41570
  }
41472
- commandStr = runGlobalExpression(opts.expression, targets);
41571
+
41572
+ // io proxy adds ability to add datasets dynamically in a required function
41573
+ var ctx = getBaseContext();
41574
+ ctx.io = getIOProxy();
41575
+ tmp = runGlobalExpression(opts.expression, targets, ctx);
41576
+
41473
41577
  // Support async functions as expressions
41474
- if (utils.isPromise(commandStr)) {
41475
- commandStr = await commandStr;
41578
+ if (utils.isPromise(tmp)) {
41579
+ tmp = await tmp;
41476
41580
  }
41477
- if (commandStr) {
41478
- message(`command: [${commandStr}]`);
41479
- commands = parseCommands(commandStr);
41581
+ if (tmp && !utils.isString(tmp)) {
41582
+ stop('Expected a string containing mapshaper commands; received:', tmp);
41583
+ }
41584
+ if (tmp) {
41585
+ message(`command: [${tmp}]`);
41586
+ commands = parseCommands(tmp);
41587
+
41588
+ // TODO: remove duplication with mapshaper-run-commands.mjs
41589
+ commands.forEach(function(cmd) {
41590
+ if (commandTakesFileInput(cmd.name)) {
41591
+ cmd.options.input = ctx.io._cache;
41592
+ }
41593
+ });
41594
+
41480
41595
  await utils.promisify(runParsedCommands)(commands, job);
41481
41596
  }
41482
41597
  };
41483
41598
 
41484
41599
  // This could return a Promise or a value or nothing
41485
- function runGlobalExpression(expression, targets) {
41486
- var ctx = getBaseContext();
41487
- var output, targetData;
41600
+ function runGlobalExpression(expression, targets, ctx) {
41601
+ ctx = ctx || getBaseContext();
41602
+ var output;
41488
41603
  // TODO: throw an informative error if target is used when there are multiple targets
41489
41604
  if (targets && targets.length == 1) {
41490
- targetData = getRunCommandData(targets[0]);
41491
- Object.defineProperty(ctx, 'target', {value: targetData});
41605
+ Object.defineProperty(ctx, 'target', {value: getTargetProxy(targets[0])});
41492
41606
  }
41493
41607
  // Add defined functions and data to the expression context
41494
41608
  // (Such as functions imported via the -require command)
@@ -41501,15 +41615,6 @@ ${svg}
41501
41615
  return output;
41502
41616
  }
41503
41617
 
41504
-
41505
- function getRunCommandData(target) {
41506
- var lyr = target.layers[0];
41507
- var data = getLayerInfo(lyr, target.dataset);
41508
- data.layer = lyr;
41509
- data.dataset = target.dataset;
41510
- return data;
41511
- }
41512
-
41513
41618
  cmd.require = function(targets, opts) {
41514
41619
  var defs = getStashedVar('defs');
41515
41620
  var moduleFile, moduleName, mod;
@@ -44281,6 +44386,7 @@ ${svg}
44281
44386
  commands;
44282
44387
  try {
44283
44388
  commands = parseCommands(argv);
44389
+
44284
44390
  } catch(e) {
44285
44391
  printError(e);
44286
44392
  return callback(e);
@@ -44334,9 +44440,6 @@ ${svg}
44334
44440
  }
44335
44441
  }
44336
44442
 
44337
- function commandTakesFileInput(name) {
44338
- return (name == 'i' || name == 'join' || name == 'erase' || name == 'clip' || name == 'include');
44339
- }
44340
44443
 
44341
44444
  function toLegacyOutputFormat(arr) {
44342
44445
  if (arr.length > 1) {