mapshaper 0.5.109 → 0.5.110

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.5.109";
3
+ var VERSION = "0.5.110";
4
4
 
5
5
 
6
6
  var utils = /*#__PURE__*/Object.freeze({
@@ -101,6 +101,37 @@
101
101
  get trimQuotes () { return trimQuotes; }
102
102
  });
103
103
 
104
+ // This module provides a way for multiple jobs to run together asynchronously
105
+ // while keeping job-level context variables (like "defs") separate.
106
+
107
+ var stash = {};
108
+
109
+ function stashVar(key, val) {
110
+ if (key in stash) {
111
+ error('Tried to replace a stashed variable:', key);
112
+ }
113
+ stash[key] = val;
114
+ }
115
+
116
+ function getStashedVar(key) {
117
+ if (key in stash === false) {
118
+ return undefined; // to support running commands in tests
119
+ // error('Tried to read a nonexistent variable from the stash:', key);
120
+ }
121
+ return stash[key];
122
+ }
123
+
124
+ function clearStash() {
125
+ stash = {};
126
+ }
127
+
128
+ var Stash = /*#__PURE__*/Object.freeze({
129
+ __proto__: null,
130
+ stashVar: stashVar,
131
+ getStashedVar: getStashedVar,
132
+ clearStash: clearStash
133
+ });
134
+
104
135
  var Buffer = require('buffer').Buffer; // works with browserify
105
136
 
106
137
  var uniqCount = 0;
@@ -1133,62 +1164,6 @@
1133
1164
  return raw;
1134
1165
  }
1135
1166
 
1136
- var context = createContext(); // command context (persist for the current command cycle)
1137
-
1138
- function runningInBrowser() {
1139
- return typeof window !== 'undefined' && typeof window.document !== 'undefined';
1140
- }
1141
-
1142
- function getStateVar(key) {
1143
- return context[key];
1144
- }
1145
-
1146
- function setStateVar(key, val) {
1147
- context[key] = val;
1148
- }
1149
-
1150
- function createContext() {
1151
- return {
1152
- DEBUG: false,
1153
- QUIET: false,
1154
- VERBOSE: false,
1155
- defs: {},
1156
- input_files: []
1157
- };
1158
- }
1159
-
1160
- // Install a new set of context variables, clear them when an async callback is called.
1161
- // @cb callback function to wrap
1162
- // returns wrapped callback function
1163
- function createAsyncContext(cb) {
1164
- context = createContext();
1165
- return function() {
1166
- cb.apply(null, utils.toArray(arguments));
1167
- // clear context after cb(), so output/errors can be handled in current context
1168
- context = createContext();
1169
- };
1170
- }
1171
-
1172
- // Save the current context, restore it when an async callback is called
1173
- // @cb callback function to wrap
1174
- // returns wrapped callback function
1175
- function preserveContext(cb) {
1176
- var ctx = context;
1177
- return function() {
1178
- context = ctx;
1179
- cb.apply(null, utils.toArray(arguments));
1180
- };
1181
- }
1182
-
1183
- var State = /*#__PURE__*/Object.freeze({
1184
- __proto__: null,
1185
- runningInBrowser: runningInBrowser,
1186
- getStateVar: getStateVar,
1187
- setStateVar: setStateVar,
1188
- createAsyncContext: createAsyncContext,
1189
- preserveContext: preserveContext
1190
- });
1191
-
1192
1167
  var LOGGING = false;
1193
1168
  var STDOUT = false; // use stdout for status messages
1194
1169
  var _error, _stop, _message;
@@ -1268,13 +1243,13 @@
1268
1243
 
1269
1244
  function verbose() {
1270
1245
  // verbose can be set globally with the -verbose command or separately for each command
1271
- if (getStateVar('VERBOSE') || getStateVar('verbose')) {
1246
+ if (getStashedVar('VERBOSE')) {
1272
1247
  message.apply(null, arguments);
1273
1248
  }
1274
1249
  }
1275
1250
 
1276
1251
  function debug() {
1277
- if (getStateVar('DEBUG') || getStateVar('debug')) {
1252
+ if (getStashedVar('DEBUG')) {
1278
1253
  logArgs(arguments);
1279
1254
  }
1280
1255
  }
@@ -1354,7 +1329,7 @@
1354
1329
 
1355
1330
  function messageArgs(args) {
1356
1331
  var arr = utils.toArray(args);
1357
- var cmd = getStateVar('current_command');
1332
+ var cmd = getStashedVar('current_command');
1358
1333
  if (cmd && cmd != 'help') {
1359
1334
  arr.unshift('[' + cmd + ']');
1360
1335
  }
@@ -1362,7 +1337,7 @@
1362
1337
  }
1363
1338
 
1364
1339
  function logArgs(args) {
1365
- if (!LOGGING || getStateVar('QUIET') || !utils.isArrayLike(args)) return;
1340
+ if (!LOGGING || getStashedVar('QUIET') || !utils.isArrayLike(args)) return;
1366
1341
  var msg = formatLogArgs(args);
1367
1342
  if (STDOUT) console.log(msg);
1368
1343
  else console.error(msg);
@@ -4122,6 +4097,7 @@
4122
4097
  s = [],
4123
4098
  dataNulls = 0,
4124
4099
  rec;
4100
+
4125
4101
  for (var i=0, n=shapes.length; i<n; i++) {
4126
4102
  if (types[i] != geoType) continue;
4127
4103
  if (geoType) s.push(shapes[i]);
@@ -4132,7 +4108,7 @@
4132
4108
  return {
4133
4109
  geometry_type: geoType,
4134
4110
  shapes: s,
4135
- data: dataNulls < s.length ? new DataTable(p) : null
4111
+ data: dataNulls < p.length ? new DataTable(p) : null
4136
4112
  };
4137
4113
  });
4138
4114
  return layers;
@@ -4742,9 +4718,9 @@
4742
4718
  defn = projectionAliases[str]; // defn is a function
4743
4719
  } else if (looksLikeInitString(str)) {
4744
4720
  defn = '+init=' + str.toLowerCase();
4745
- } else if (str in getStateVar('defs')) {
4721
+ } else if (str in (getStashedVar('defs') || {})) {
4746
4722
  // a proj4 alias could be dynamically created in a -calc expression
4747
- defn = getStateVar('defs')[str];
4723
+ defn = getStashedVar('defs')[str];
4748
4724
  } else {
4749
4725
  defn = parseCustomProjection(str);
4750
4726
  }
@@ -7031,6 +7007,15 @@
7031
7007
  transformPoints: transformPoints
7032
7008
  });
7033
7009
 
7010
+ function runningInBrowser() {
7011
+ return typeof window !== 'undefined' && typeof window.document !== 'undefined';
7012
+ }
7013
+
7014
+ var State = /*#__PURE__*/Object.freeze({
7015
+ __proto__: null,
7016
+ runningInBrowser: runningInBrowser
7017
+ });
7018
+
7034
7019
  function getPathSep(path) {
7035
7020
  // TODO: improve
7036
7021
  return path.indexOf('/') == -1 && path.indexOf('\\') != -1 ? '\\' : '/';
@@ -7139,7 +7124,8 @@
7139
7124
  } else if (fname == '/dev/stdin') {
7140
7125
  content = require('rw').readFileSync(fname);
7141
7126
  } else {
7142
- getStateVar('input_files').push(fname);
7127
+ // kludge to prevent overwriting of input files
7128
+ (getStashedVar('input_files') || []).push(fname);
7143
7129
  content = require('fs').readFileSync(fname);
7144
7130
  }
7145
7131
  if (encoding && Buffer.isBuffer(content)) {
@@ -7164,7 +7150,7 @@
7164
7150
  var fs = require('rw');
7165
7151
  cli.createDirIfNeeded(fname);
7166
7152
  if (cb) {
7167
- fs.writeFile(fname, content, preserveContext(cb));
7153
+ fs.writeFile(fname, content, cb);
7168
7154
  } else {
7169
7155
  fs.writeFileSync(fname, content);
7170
7156
  }
@@ -7259,7 +7245,7 @@
7259
7245
  return cli.writeFile('/dev/stdout', exports[0].content, cb);
7260
7246
  } else {
7261
7247
  var paths = getOutputPaths(utils.pluck(exports, 'filename'), opts);
7262
- var inputFiles = getStateVar('input_files');
7248
+ var inputFiles = getStashedVar('input_files');
7263
7249
  exports.forEach(function(obj, i) {
7264
7250
  var path = paths[i];
7265
7251
  if (obj.content instanceof ArrayBuffer) {
@@ -9965,7 +9951,7 @@
9965
9951
  }
9966
9952
 
9967
9953
  function getExpressionContext(lyr, mixins, opts) {
9968
- var defs = getStateVar('defs');
9954
+ var defs = getStashedVar('defs');
9969
9955
  var env = getBaseContext();
9970
9956
  var ctx = {};
9971
9957
  var fields = lyr.data ? lyr.data.getFields() : [];
@@ -10154,7 +10140,7 @@
10154
10140
  }
10155
10141
  // Save any assigned variables to the defs object, so they will be available
10156
10142
  // for later -each expressions to use.
10157
- defs = getStateVar('defs');
10143
+ defs = getStashedVar('defs');
10158
10144
  compiled = compileCalcExpression(lyr, arcs, opts.expression);
10159
10145
  result = compiled(null, defs);
10160
10146
  message(msg + ": " + result);
@@ -14022,7 +14008,6 @@
14022
14008
  function parseStyleExpression(strVal, lyr) {
14023
14009
  var func;
14024
14010
  try {
14025
- // func = compileValueExpression(strVal, lyr, null, {context: getStateVar('defs'), no_warn: true});
14026
14011
  func = compileValueExpression(strVal, lyr, null, {no_warn: true});
14027
14012
  func(0); // check for runtime errors (e.g. undefined variables)
14028
14013
  } catch(e) {
@@ -16804,7 +16789,7 @@ ${svg}
16804
16789
  function guessInputFileType(file) {
16805
16790
  var ext = getFileExtension(file || '').toLowerCase(),
16806
16791
  type = null;
16807
- if (ext == 'dbf' || ext == 'shp' || ext == 'prj' || ext == 'shx') {
16792
+ if (ext == 'dbf' || ext == 'shp' || ext == 'prj' || ext == 'shx' || ext == 'kml') {
16808
16793
  type = ext;
16809
16794
  } else if (/json$/.test(ext)) {
16810
16795
  type = 'json';
@@ -16817,7 +16802,8 @@ ${svg}
16817
16802
  function guessInputContentType(content) {
16818
16803
  var type = null;
16819
16804
  if (utils.isString(content)) {
16820
- type = stringLooksLikeJSON(content) ? 'json' : 'text';
16805
+ type = stringLooksLikeJSON(content) && 'json' ||
16806
+ stringLooksLikeKML(content) && 'kml' || 'text';
16821
16807
  } else if (utils.isObject(content) && content.type || utils.isArray(content)) {
16822
16808
  type = 'json';
16823
16809
  }
@@ -16828,11 +16814,15 @@ ${svg}
16828
16814
  return guessInputFileType(file) || guessInputContentType(content);
16829
16815
  }
16830
16816
 
16831
- //
16832
16817
  function stringLooksLikeJSON(str) {
16833
16818
  return /^\s*[{[]/.test(String(str));
16834
16819
  }
16835
16820
 
16821
+ function stringLooksLikeKML(str) {
16822
+ str = String(str);
16823
+ return str.includes('<kml ') && str.includes('xmlns="http://www.opengis.net/kml/');
16824
+ }
16825
+
16836
16826
  function couldBeDsvFile(name) {
16837
16827
  var ext = getFileExtension(name).toLowerCase();
16838
16828
  return /csv|tsv|txt$/.test(ext);
@@ -16877,6 +16867,7 @@ ${svg}
16877
16867
  guessInputContentType: guessInputContentType,
16878
16868
  guessInputType: guessInputType,
16879
16869
  stringLooksLikeJSON: stringLooksLikeJSON,
16870
+ stringLooksLikeKML: stringLooksLikeKML,
16880
16871
  couldBeDsvFile: couldBeDsvFile,
16881
16872
  isZipFile: isZipFile,
16882
16873
  isSupportedOutputFormat: isSupportedOutputFormat,
@@ -17355,8 +17346,8 @@ ${svg}
17355
17346
  DEFAULT_CACHE_LEN = opts && opts.cacheSize || 0x1000000, // 16MB
17356
17347
  DEFAULT_BUFFER_LEN = opts && opts.bufferSize || 0x40000, // 256K
17357
17348
  fd, cacheOffs, cache, binArr;
17358
-
17359
- getStateVar('input_files').push(path); // bit of a kludge
17349
+ // kludge to let us check if input files are being overwritten
17350
+ (getStashedVar('input_files') || []).push(path);
17360
17351
 
17361
17352
  // Double the default size of the Buffer returned by readSync()
17362
17353
  this.expandBuffer = function() {
@@ -23158,6 +23149,13 @@ ${svg}
23158
23149
  importJSON: importJSON
23159
23150
  });
23160
23151
 
23152
+ function importKML(str, opts) {
23153
+ var togeojson = require("@tmcw/togeojson");
23154
+ var Parser = typeof DOMParser == 'undefined' ? require("@xmldom/xmldom").DOMParser : DOMParser;
23155
+ var geojson = togeojson.kml(new Parser().parseFromString(str, "text/xml"));
23156
+ return importGeoJSON(geojson, opts || {});
23157
+ }
23158
+
23161
23159
  // Parse content of one or more input files and return a dataset
23162
23160
  // @obj: file data, indexed by file type
23163
23161
  // File data objects have two properties:
@@ -23194,6 +23192,11 @@ ${svg}
23194
23192
  fileFmt = 'prj';
23195
23193
  data = obj.prj;
23196
23194
  dataset = {layers: [], info: {prj: data.content}};
23195
+
23196
+ } else if (obj.kml) {
23197
+ fileFmt = 'kml';
23198
+ data = obj.kml;
23199
+ dataset = importKML(data.content, opts);
23197
23200
  }
23198
23201
 
23199
23202
  if (!dataset) {
@@ -23375,7 +23378,7 @@ ${svg}
23375
23378
  stop('Expected binary content, received a string');
23376
23379
  }
23377
23380
 
23378
- } else if (fileType) { // string type
23381
+ } else if (fileType) { // string type, e.g. kml, geojson
23379
23382
  content = cli.readFile(path, encoding || 'utf-8', cache);
23380
23383
 
23381
23384
  } else { // type can't be inferred from filename -- try reading as text
@@ -23664,6 +23667,49 @@ ${svg}
23664
23667
  getFormattedLayerList: getFormattedLayerList
23665
23668
  });
23666
23669
 
23670
+ function Job(catalog) {
23671
+ var currentCmd;
23672
+
23673
+ var job = {
23674
+ catalog: catalog || new Catalog(),
23675
+ defs: {},
23676
+ settings: {},
23677
+ input_files: []
23678
+ };
23679
+
23680
+ job.initSettings = function(o) {
23681
+ job.settings = o;
23682
+ stashVars(job, {});
23683
+ };
23684
+
23685
+ job.startCommand = function(cmd) {
23686
+ currentCmd = cmd;
23687
+ stashVars(job, cmd);
23688
+ };
23689
+
23690
+ // Rejected the idea of passing a command reference to compare with the initial command
23691
+ // (for error checking) ... the "-run" command inserts other commands before this call
23692
+ job.endCommand = function() {
23693
+ currentCmd = null;
23694
+ clearStash();
23695
+ };
23696
+
23697
+ job.resumeCommand = function() {
23698
+ stashVars(job, currentCmd);
23699
+ };
23700
+
23701
+ return job;
23702
+ }
23703
+
23704
+ function stashVars(job, cmd) {
23705
+ clearStash(); // prevent errors from overwriting stash
23706
+ stashVar('current_command', cmd.name);
23707
+ stashVar('DEBUG', job.settings.DEBUG || cmd.debug);
23708
+ stashVar('QUIET', job.settings.QUIET || cmd.quiet);
23709
+ stashVar('defs', job.defs);
23710
+ stashVar('input_files', job.input_files);
23711
+ }
23712
+
23667
23713
  const epsilon = 1.1102230246251565e-16;
23668
23714
  const splitter = 134217729;
23669
23715
  const resulterrbound = (3 + 8 * epsilon) * epsilon;
@@ -30407,7 +30453,7 @@ ${svg}
30407
30453
  if (isReservedName(opts.name)) {
30408
30454
  stop('"' + opts.name + '" is a reserved name');
30409
30455
  }
30410
- getStateVar('defs')[opts.name] = getColorizerFunction(opts);
30456
+ getStashedVar('defs')[opts.name] = getColorizerFunction(opts);
30411
30457
  };
30412
30458
 
30413
30459
  function isReservedName(name) {
@@ -30526,7 +30572,7 @@ ${svg}
30526
30572
 
30527
30573
  cmd.dashlines = function(lyr, dataset, opts) {
30528
30574
  var crs = getDatasetCRS(dataset);
30529
- var defs = getStateVar('defs');
30575
+ var defs = getStashedVar('defs');
30530
30576
  var exp = `this.geojson = splitFeature(this.geojson)`;
30531
30577
  requirePolylineLayer(lyr);
30532
30578
  defs.splitFeature = getSplitFeatureFunction(crs, opts);
@@ -30930,7 +30976,7 @@ ${svg}
30930
30976
  if (!opts.expression) {
30931
30977
  stop('Missing an assignment expression');
30932
30978
  }
30933
- var defs = getStateVar('defs');
30979
+ var defs = getStashedVar('defs');
30934
30980
  var compiled = compileFeatureExpression(opts.expression, {}, null, {no_warn: true});
30935
30981
  var result = compiled(null, defs);
30936
30982
  };
@@ -32202,8 +32248,6 @@ ${svg}
32202
32248
  if (opts && opts.where) {
32203
32249
  filter = compileValueExpression(opts.where, lyr, arcs);
32204
32250
  }
32205
- // 'defs' are now added to the context of all expressions
32206
- // compiled = compileFeatureExpression(exp, lyr, arcs, {context: getStateVar('defs')});
32207
32251
  compiled = compileFeatureExpression(exp, lyr, arcs, exprOpts);
32208
32252
  // call compiled expression with id of each record
32209
32253
  for (var i=0; i<n; i++) {
@@ -34612,39 +34656,37 @@ ${svg}
34612
34656
  };
34613
34657
  }
34614
34658
 
34615
- function resetControlFlow() {
34616
- setStateVar('control', null);
34659
+ function resetControlFlow(job) {
34660
+ job.control = null;
34617
34661
  }
34618
34662
 
34619
- function inControlBlock() {
34620
- var state = getState();
34621
- return !!state.inControlBlock;
34663
+ function inControlBlock(job) {
34664
+ return !!getState(job).inControlBlock;
34622
34665
  }
34623
34666
 
34624
- function enterActiveBranch() {
34625
- var state = getState();
34667
+ function enterActiveBranch(job) {
34668
+ var state = getState(job);
34626
34669
  state.inControlBlock = true;
34627
34670
  state.active = true;
34628
34671
  state.complete = true;
34629
34672
  }
34630
34673
 
34631
- function enterInactiveBranch() {
34632
- var state = getState();
34674
+ function enterInactiveBranch(job) {
34675
+ var state = getState(job);
34633
34676
  state.inControlBlock = true;
34634
34677
  state.active = false;
34635
34678
  }
34636
34679
 
34637
- function blockWasActive() {
34638
- return !!getState().complete;
34680
+ function blockWasActive(job) {
34681
+ return !!getState(job).complete;
34639
34682
  }
34640
34683
 
34641
- function inActiveBranch() {
34642
- return !!getState().active;
34684
+ function inActiveBranch(job) {
34685
+ return !!getState(job).active;
34643
34686
  }
34644
34687
 
34645
- function getState() {
34646
- var o = getStateVar('control') || setStateVar('control', {}) || getStateVar('control');
34647
- return o;
34688
+ function getState(job) {
34689
+ return job.control || (job.control = {});
34648
34690
  }
34649
34691
 
34650
34692
  function compileIfCommandExpression(expr, catalog, targ, opts) {
@@ -34670,42 +34712,42 @@ ${svg}
34670
34712
  };
34671
34713
  }
34672
34714
 
34673
- function skipCommand(cmdName) {
34715
+ function skipCommand(cmdName, job) {
34674
34716
  // allow all control commands to run
34675
34717
  if (isControlFlowCommand(cmdName)) return false;
34676
- return inControlBlock() && !inActiveBranch();
34718
+ return inControlBlock(job) && !inActiveBranch(job);
34677
34719
  }
34678
34720
 
34679
- cmd.if = function(catalog, opts) {
34680
- if (inControlBlock()) {
34721
+ cmd.if = function(job, opts) {
34722
+ if (inControlBlock(job)) {
34681
34723
  stop('Nested -if commands are not supported.');
34682
34724
  }
34683
- evaluateIf(catalog, opts);
34725
+ evaluateIf(job, opts);
34684
34726
  };
34685
34727
 
34686
- cmd.elif = function(catalog, opts) {
34687
- if (!inControlBlock()) {
34728
+ cmd.elif = function(job, opts) {
34729
+ if (!inControlBlock(job)) {
34688
34730
  stop('-elif command must be preceded by an -if command.');
34689
34731
  }
34690
- evaluateIf(catalog, opts);
34732
+ evaluateIf(job, opts);
34691
34733
  };
34692
34734
 
34693
- cmd.else = function() {
34694
- if (!inControlBlock()) {
34735
+ cmd.else = function(job) {
34736
+ if (!inControlBlock(job)) {
34695
34737
  stop('-else command must be preceded by an -if command.');
34696
34738
  }
34697
- if (blockWasActive()) {
34698
- enterInactiveBranch();
34739
+ if (blockWasActive(job)) {
34740
+ enterInactiveBranch(job);
34699
34741
  } else {
34700
- enterActiveBranch();
34742
+ enterActiveBranch(job);
34701
34743
  }
34702
34744
  };
34703
34745
 
34704
- cmd.endif = function() {
34705
- if (!inControlBlock()) {
34746
+ cmd.endif = function(job) {
34747
+ if (!inControlBlock(job)) {
34706
34748
  stop('-endif command must be preceded by an -if command.');
34707
34749
  }
34708
- resetControlFlow();
34750
+ resetControlFlow(job);
34709
34751
  };
34710
34752
 
34711
34753
  function isControlFlowCommand(cmd) {
@@ -34726,11 +34768,11 @@ ${svg}
34726
34768
  return true;
34727
34769
  }
34728
34770
 
34729
- function evaluateIf(catalog, opts) {
34730
- if (!blockWasActive() && testLayer(catalog, opts)) {
34731
- enterActiveBranch();
34771
+ function evaluateIf(job, opts) {
34772
+ if (!blockWasActive(job) && testLayer(job.catalog, opts)) {
34773
+ enterActiveBranch(job);
34732
34774
  } else {
34733
- enterInactiveBranch();
34775
+ enterInactiveBranch(job);
34734
34776
  }
34735
34777
  }
34736
34778
 
@@ -34790,7 +34832,7 @@ ${svg}
34790
34832
  obj = content;
34791
34833
  }
34792
34834
 
34793
- utils.extend(getStateVar('defs'), obj);
34835
+ utils.extend(getStashedVar('defs'), obj);
34794
34836
  };
34795
34837
 
34796
34838
  var MAX_RULE_LEN = 50;
@@ -34849,7 +34891,7 @@ ${svg}
34849
34891
  null_shape_count: 0,
34850
34892
  null_data_count: lyr.data ? countNullRecords(lyr.data.getRecords()) : n
34851
34893
  };
34852
- if (lyr.shapes) {
34894
+ if (lyr.shapes && lyr.shapes.length > 0) {
34853
34895
  o.null_shape_count = countNullShapes(lyr.shapes);
34854
34896
  o.bbox =getLayerBounds(lyr, dataset.arcs).toArray();
34855
34897
  o.proj4 = getProjInfo(dataset);
@@ -37122,7 +37164,7 @@ ${svg}
37122
37164
  parseConsoleCommands: parseConsoleCommands
37123
37165
  });
37124
37166
 
37125
- cmd.run = function(targets, catalog, opts, cb) {
37167
+ cmd.run = function(job, targets, opts, cb) {
37126
37168
  var commandStr, commands;
37127
37169
  if (opts.include) {
37128
37170
  cmd.include({file: opts.include});
@@ -37133,7 +37175,7 @@ ${svg}
37133
37175
  commandStr = runGlobalExpression(opts.commands, targets);
37134
37176
  if (commandStr) {
37135
37177
  commands = parseCommands(commandStr);
37136
- runParsedCommands(commands, catalog, cb);
37178
+ runParsedCommands(commands, job, cb);
37137
37179
  } else {
37138
37180
  cb(null);
37139
37181
  }
@@ -37147,7 +37189,7 @@ ${svg}
37147
37189
  targetData = getRunCommandData(targets[0]);
37148
37190
  Object.defineProperty(ctx, 'target', {value: targetData});
37149
37191
  }
37150
- utils.extend(ctx, getStateVar('defs'));
37192
+ utils.extend(ctx, getStashedVar('defs'));
37151
37193
  try {
37152
37194
  output = Function('ctx', 'with(ctx) {return (' + expression + ');}').call({}, ctx);
37153
37195
  } catch(e) {
@@ -37166,7 +37208,7 @@ ${svg}
37166
37208
  }
37167
37209
 
37168
37210
  cmd.require = function(targets, opts) {
37169
- var defs = getStateVar('defs');
37211
+ var defs = getStashedVar('defs');
37170
37212
  var moduleFile, moduleName, mod;
37171
37213
  if (!opts.module) {
37172
37214
  stop("Missing module name or path to module");
@@ -39468,7 +39510,7 @@ ${svg}
39468
39510
  return [lyr1, lyr2];
39469
39511
  }
39470
39512
 
39471
- function runCommand(command, catalog, cb) {
39513
+ function runCommand(command, job, cb) {
39472
39514
  var name = command.name,
39473
39515
  opts = command.options,
39474
39516
  source,
@@ -39481,18 +39523,20 @@ ${svg}
39481
39523
  target,
39482
39524
  arcs;
39483
39525
 
39484
- if (skipCommand(name)) {
39526
+ if (skipCommand(name, job)) {
39485
39527
  return done(null);
39486
39528
  }
39487
39529
 
39530
+ if (!job) job = new Job();
39531
+ job.startCommand(command);
39532
+
39488
39533
  try { // catch errors from synchronous functions
39489
39534
 
39490
39535
  T$1.start();
39491
- if (!catalog) catalog = new Catalog();
39492
39536
 
39493
39537
  if (name == 'rename-layers') {
39494
39538
  // default target is all layers
39495
- targets = catalog.findCommandTargets(opts.target || '*');
39539
+ targets = job.catalog.findCommandTargets(opts.target || '*');
39496
39540
  targetLayers = targets.reduce(function(memo, obj) {
39497
39541
  return memo.concat(obj.layers);
39498
39542
  }, []);
@@ -39500,19 +39544,19 @@ ${svg}
39500
39544
  } else if (name == 'o') {
39501
39545
  // when combining GeoJSON layers, default is all layers
39502
39546
  // TODO: check that combine_layers is only used w/ GeoJSON output
39503
- targets = catalog.findCommandTargets(opts.target || opts.combine_layers && '*');
39547
+ targets = job.catalog.findCommandTargets(opts.target || opts.combine_layers && '*');
39504
39548
 
39505
39549
  } else if (name == 'rotate' || name == 'info' || name == 'proj' || name == 'drop' || name == 'target') {
39506
39550
  // these commands accept multiple target datasets
39507
- targets = catalog.findCommandTargets(opts.target);
39551
+ targets = job.catalog.findCommandTargets(opts.target);
39508
39552
 
39509
39553
  } else {
39510
- targets = catalog.findCommandTargets(opts.target);
39554
+ targets = job.catalog.findCommandTargets(opts.target);
39511
39555
 
39512
39556
  // special case to allow -merge-layers and -union to combine layers from multiple datasets
39513
39557
  // TODO: support multi-dataset targets for other commands
39514
39558
  if (targets.length > 1 && (name == 'merge-layers' || name == 'union')) {
39515
- targets = mergeCommandTargets(targets, catalog);
39559
+ targets = mergeCommandTargets(targets, job.catalog);
39516
39560
  }
39517
39561
 
39518
39562
  if (targets.length == 1) {
@@ -39520,7 +39564,7 @@ ${svg}
39520
39564
  arcs = targetDataset.arcs;
39521
39565
  targetLayers = targets[0].layers;
39522
39566
  // target= option sets default target
39523
- catalog.setDefaultTarget(targetLayers, targetDataset);
39567
+ job.catalog.setDefaultTarget(targetLayers, targetDataset);
39524
39568
 
39525
39569
  } else if (targets.length > 1) {
39526
39570
  stop("This command does not support targetting layers from different datasets");
@@ -39530,7 +39574,7 @@ ${svg}
39530
39574
  if (targets.length === 0) {
39531
39575
  if (opts.target) {
39532
39576
  stop(utils.format('Missing target: %s\nAvailable layers: %s',
39533
- opts.target, getFormattedLayerList(catalog)));
39577
+ opts.target, getFormattedLayerList(job.catalog)));
39534
39578
  }
39535
39579
  if (!(name == 'graticule' || name == 'i' || name == 'help' ||
39536
39580
  name == 'point-grid' || name == 'shape' || name == 'rectangle' ||
@@ -39540,7 +39584,7 @@ ${svg}
39540
39584
  }
39541
39585
 
39542
39586
  if (opts.source) {
39543
- source = findCommandSource(convertSourceName(opts.source, targets), catalog, opts);
39587
+ source = findCommandSource(convertSourceName(opts.source, targets), job.catalog, opts);
39544
39588
  }
39545
39589
 
39546
39590
  if (name == 'affine') {
@@ -39594,7 +39638,7 @@ ${svg}
39594
39638
  outputLayers = applyCommandToEachLayer(cmd.dots, targetLayers, arcs, opts);
39595
39639
 
39596
39640
  } else if (name == 'drop') {
39597
- cmd.drop2(catalog, targets, opts);
39641
+ cmd.drop2(job.catalog, targets, opts);
39598
39642
  // cmd.drop(catalog, targetLayers, targetDataset, opts);
39599
39643
 
39600
39644
  } else if (name == 'each') {
@@ -39631,33 +39675,33 @@ ${svg}
39631
39675
  applyCommandToEachLayer(cmd.filterSlivers, targetLayers, targetDataset, opts);
39632
39676
 
39633
39677
  } else if (name == 'frame') {
39634
- cmd.frame(catalog, source, opts);
39678
+ cmd.frame(job.catalog, source, opts);
39635
39679
 
39636
39680
  } else if (name == 'fuzzy-join') {
39637
39681
  applyCommandToEachLayer(cmd.fuzzyJoin, targetLayers, arcs, source, opts);
39638
39682
 
39639
39683
  } else if (name == 'graticule') {
39640
- catalog.addDataset(cmd.graticule(targetDataset, opts));
39684
+ job.catalog.addDataset(cmd.graticule(targetDataset, opts));
39641
39685
 
39642
39686
  } else if (name == 'help') {
39643
39687
  // placing this here to handle errors from invalid command names
39644
39688
  getOptionParser().printHelp(command.options.command);
39645
39689
 
39646
39690
  } else if (name == 'i') {
39647
- if (opts.replace) catalog = new Catalog();
39691
+ if (opts.replace) job.catalog = new Catalog(); // is this what we want?
39648
39692
  targetDataset = cmd.importFiles(command.options);
39649
39693
  if (targetDataset) {
39650
- catalog.addDataset(targetDataset);
39694
+ job.catalog.addDataset(targetDataset);
39651
39695
  outputLayers = targetDataset.layers; // kludge to allow layer naming below
39652
39696
  }
39653
39697
 
39654
39698
  } else if (name == 'if' || name == 'elif') {
39655
39699
  // target = findSingleTargetLayer(opts.layer, targets[0], catalog);
39656
39700
  // cmd[name](target.layer, target.dataset, opts);
39657
- cmd[name](catalog, opts);
39701
+ cmd[name](job, opts);
39658
39702
 
39659
39703
  } else if (name == 'else' || name == 'endif') {
39660
- cmd[name]();
39704
+ cmd[name](job);
39661
39705
 
39662
39706
  } else if (name == 'ignore') {
39663
39707
  applyCommandToEachLayer(cmd.ignore, targetLayers, targetDataset, opts);
@@ -39697,14 +39741,16 @@ ${svg}
39697
39741
  outputFiles = exportTargetLayers(targets, opts);
39698
39742
  if (opts.final) {
39699
39743
  // don't propagate data if output is final
39700
- catalog = null;
39744
+ //// catalog = null;
39745
+ job.catalog = new Catalog();
39701
39746
  }
39702
- return writeFiles(outputFiles, opts, done);
39747
+ writeFiles(outputFiles, opts, done);
39748
+ return; // async command
39703
39749
 
39704
39750
  } else if (name == 'point-grid') {
39705
39751
  outputLayers = [cmd.pointGrid(targetDataset, opts)];
39706
39752
  if (!targetDataset) {
39707
- catalog.addDataset({layers: outputLayers});
39753
+ job.catalog.addDataset({layers: outputLayers});
39708
39754
  }
39709
39755
 
39710
39756
  } else if (name == 'point-to-grid') {
@@ -39724,10 +39770,11 @@ ${svg}
39724
39770
 
39725
39771
  } else if (name == 'proj') {
39726
39772
  initProjLibrary(opts, function() {
39773
+ job.resumeCommand();
39727
39774
  var err = null;
39728
39775
  try {
39729
39776
  targets.forEach(function(targ) {
39730
- cmd.proj(targ.dataset, catalog, opts);
39777
+ cmd.proj(targ.dataset, job.catalog, opts);
39731
39778
  });
39732
39779
  } catch(e) {
39733
39780
  err = e;
@@ -39738,7 +39785,7 @@ ${svg}
39738
39785
 
39739
39786
  } else if (name == 'rectangle') {
39740
39787
  if (source || opts.bbox || targets.length === 0) {
39741
- catalog.addDataset(cmd.rectangle(source, opts));
39788
+ job.catalog.addDataset(cmd.rectangle(source, opts));
39742
39789
  } else {
39743
39790
  outputLayers = cmd.rectangle2(targets[0], opts);
39744
39791
  }
@@ -39750,7 +39797,7 @@ ${svg}
39750
39797
  applyCommandToEachLayer(cmd.renameFields, targetLayers, opts.fields);
39751
39798
 
39752
39799
  } else if (name == 'rename-layers') {
39753
- cmd.renameLayers(targetLayers, opts.names, catalog);
39800
+ cmd.renameLayers(targetLayers, opts.names, job.catalog);
39754
39801
 
39755
39802
  } else if (name == 'require') {
39756
39803
  cmd.require(targets, opts);
@@ -39761,14 +39808,14 @@ ${svg}
39761
39808
  });
39762
39809
 
39763
39810
  } else if (name == 'run') {
39764
- cmd.run(targets, catalog, opts, done);
39765
- return;
39811
+ cmd.run(job, targets, opts, done);
39812
+ return; // async command
39766
39813
 
39767
39814
  } else if (name == 'scalebar') {
39768
- cmd.scalebar(catalog, opts);
39815
+ cmd.scalebar(job.catalog, opts);
39769
39816
 
39770
39817
  } else if (name == 'shape') {
39771
- catalog.addDataset(cmd.shape(targetDataset, opts));
39818
+ job.catalog.addDataset(cmd.shape(targetDataset, opts));
39772
39819
 
39773
39820
  } else if (name == 'shapes') {
39774
39821
  outputLayers = applyCommandToEachLayer(cmd.shapes, targetLayers, targetDataset, opts);
@@ -39808,7 +39855,7 @@ ${svg}
39808
39855
  outputLayers = applyCommandToEachLayer(cmd.subdivideLayer, targetLayers, arcs, opts.expression);
39809
39856
 
39810
39857
  } else if (name == 'target') {
39811
- cmd.target(catalog, opts);
39858
+ cmd.target(job.catalog, opts);
39812
39859
 
39813
39860
  } else if (name == 'union') {
39814
39861
  outputLayers = cmd.union(targetLayers, targetDataset, opts);
@@ -39818,7 +39865,7 @@ ${svg}
39818
39865
 
39819
39866
  } else {
39820
39867
  // throws error if command is not registered
39821
- cmd.runExternalCommand(command, catalog);
39868
+ cmd.runExternalCommand(command, job.catalog);
39822
39869
  }
39823
39870
 
39824
39871
  // apply name parameter
@@ -39830,12 +39877,12 @@ ${svg}
39830
39877
  }
39831
39878
 
39832
39879
  if (outputDataset) {
39833
- catalog.addDataset(outputDataset); // also sets default target
39880
+ job.catalog.addDataset(outputDataset); // also sets default target
39834
39881
  outputLayers = outputDataset.layers;
39835
39882
  if (targetLayers && !opts.no_replace) {
39836
39883
  // remove target layers from target dataset
39837
39884
  targetLayers.forEach(function(lyr) {
39838
- catalog.deleteLayer(lyr, targetDataset);
39885
+ job.catalog.deleteLayer(lyr, targetDataset);
39839
39886
  });
39840
39887
  }
39841
39888
  } else if (outputLayers && targetDataset && outputLayers != targetDataset.layers) {
@@ -39858,7 +39905,7 @@ ${svg}
39858
39905
  }
39859
39906
 
39860
39907
  if (opts.apart) {
39861
- catalog.setDefaultTargets(splitApartLayers( targetDataset, outputLayers).map(function(dataset) {
39908
+ job.catalog.setDefaultTargets(splitApartLayers( targetDataset, outputLayers).map(function(dataset) {
39862
39909
  return {
39863
39910
  dataset: dataset,
39864
39911
  layers: dataset.layers.concat()
@@ -39866,9 +39913,8 @@ ${svg}
39866
39913
  }));
39867
39914
  } else {
39868
39915
  // use command output as new default target
39869
- catalog.setDefaultTarget(outputLayers, targetDataset);
39916
+ job.catalog.setDefaultTarget(outputLayers, targetDataset);
39870
39917
  }
39871
-
39872
39918
  }
39873
39919
 
39874
39920
  // delete arcs if no longer needed (e.g. after -points command)
@@ -39880,11 +39926,13 @@ ${svg}
39880
39926
  return done(e);
39881
39927
  }
39882
39928
 
39929
+ // non-erroring synchronous commands are done
39883
39930
  done(null);
39884
39931
 
39885
39932
  function done(err) {
39933
+ job.endCommand();
39886
39934
  verbose('-', T$1.stop());
39887
- cb(err, err ? null : catalog);
39935
+ cb(err, err ? null : job);
39888
39936
  }
39889
39937
  }
39890
39938
 
@@ -39894,7 +39942,6 @@ ${svg}
39894
39942
  });
39895
39943
  }
39896
39944
 
39897
-
39898
39945
  // Apply a command to an array of target layers
39899
39946
  function applyCommandToEachLayer(func, targetLayers) {
39900
39947
  var args = utils.toArray(arguments).slice(2);
@@ -40028,7 +40075,7 @@ ${svg}
40028
40075
  }
40029
40076
 
40030
40077
  // add options to -i -o -join -clip -erase commands to bypass file i/o
40031
- // TODO: find a less kludgy solution, e.g. storing input data using setStateVar()
40078
+ // TODO: find a less kludgy solution
40032
40079
  commands.forEach(function(cmd) {
40033
40080
  if (commandTakesFileInput(cmd.name) && inputObj) {
40034
40081
  cmd.options.input = inputObj;
@@ -40074,8 +40121,8 @@ ${svg}
40074
40121
 
40075
40122
  // TODO: rewrite tests and remove this function
40076
40123
  function testCommands(argv, done) {
40077
- _runCommands(argv, {}, function(err, catalog) {
40078
- var targets = catalog ? catalog.getDefaultTargets() : [];
40124
+ _runCommands(argv, {}, function(err, job) {
40125
+ var targets = job ? job.catalog.getDefaultTargets() : [];
40079
40126
  var output;
40080
40127
  if (!err && targets.length > 0) {
40081
40128
  // returns dataset for compatibility with some older tests
@@ -40087,15 +40134,12 @@ ${svg}
40087
40134
 
40088
40135
  // Execute a sequence of parsed commands
40089
40136
  // @commands Array of parsed commands
40090
- // @catalog: Optional Catalog object containing previously imported data
40137
+ // @job: Optional Job object containing previously imported data
40091
40138
  // @cb: function(<error>, <catalog>)
40092
40139
  //
40093
- function runParsedCommands(commands, catalog, cb) {
40094
- if (!catalog) {
40095
- cb = createAsyncContext(cb); // use new context when creating new catalog
40096
- catalog = new Catalog();
40097
- } else if (catalog instanceof Catalog === false) {
40098
- error("Changed in v0.4: runParsedCommands() takes a Catalog object");
40140
+ function runParsedCommands(commands, job, cb) {
40141
+ if (!job) {
40142
+ job = new Job();
40099
40143
  }
40100
40144
 
40101
40145
  if (!utils.isArray(commands)) {
@@ -40105,7 +40149,7 @@ ${svg}
40105
40149
  if (commands.length === 0) {
40106
40150
  return done(new UserError("No commands to run"));
40107
40151
  }
40108
- commands = readAndRemoveSettings(commands);
40152
+ commands = readAndRemoveSettings(job, commands);
40109
40153
  if (!runningInBrowser()) {
40110
40154
  printStartupMessages();
40111
40155
  }
@@ -40122,25 +40166,22 @@ ${svg}
40122
40166
  var groups = divideImportCommand(commands);
40123
40167
  if (groups.length == 1) {
40124
40168
  // run a simple sequence of commands (input files are not batched)
40125
- return runParsedCommands2(commands, catalog, done);
40169
+ return runParsedCommands2(commands, job, done);
40126
40170
  }
40127
40171
 
40128
40172
  // run duplicated commands (i.e. batch mode)
40129
- utils.reduceAsync(groups, catalog, nextGroup, done);
40173
+ utils.reduceAsync(groups, job, nextGroup, done);
40130
40174
 
40131
- function nextGroup(catalog, commands, next) {
40132
- runParsedCommands2(commands, catalog, function(err, catalog) {
40175
+ function nextGroup(job, commands, next) {
40176
+ runParsedCommands2(commands, job, function(err, job) {
40133
40177
  err = filterError(err);
40134
- next(err, catalog);
40178
+ next(err, job);
40135
40179
  });
40136
40180
  }
40137
40181
 
40138
- function done(err, catalog) {
40182
+ function done(err, job) {
40139
40183
  err = filterError(err);
40140
- cb(err, catalog);
40141
- setStateVar('current_command', null);
40142
- setStateVar('verbose', false);
40143
- setStateVar('debug', false);
40184
+ cb(err, job);
40144
40185
  }
40145
40186
  }
40146
40187
 
@@ -40152,16 +40193,13 @@ ${svg}
40152
40193
  return err;
40153
40194
  }
40154
40195
 
40155
- function runParsedCommands2(commands, catalog, cb) {
40196
+ function runParsedCommands2(commands, job, cb) {
40156
40197
  // resetting closes any unterminated -if blocks from a previous command sequence
40157
- resetControlFlow();
40158
- utils.reduceAsync(commands, catalog, nextCommand, cb);
40198
+ resetControlFlow(job);
40199
+ utils.reduceAsync(commands, job, nextCommand, cb);
40159
40200
 
40160
- function nextCommand(catalog, cmd, next) {
40161
- setStateVar('current_command', cmd.name); // for log msgs
40162
- setStateVar('verbose', !!cmd.options.verbose);
40163
- setStateVar('debug', !!cmd.options.debug);
40164
- runCommand(cmd, catalog, next);
40201
+ function nextCommand(job, cmd, next) {
40202
+ runCommand(cmd, job, next);
40165
40203
  }
40166
40204
  }
40167
40205
 
@@ -40207,19 +40245,22 @@ ${svg}
40207
40245
  }
40208
40246
 
40209
40247
  // Some settings use command syntax and are parsed as commands.
40210
- function readAndRemoveSettings(commands) {
40211
- return commands.filter(function(cmd) {
40248
+ function readAndRemoveSettings(job, commands) {
40249
+ var settings = {VERBOSE: false, QUIET: false, DEBUG: false};
40250
+ var filtered = commands.filter(function(cmd) {
40212
40251
  if (cmd.name == 'verbose') {
40213
- setStateVar('VERBOSE', true);
40252
+ settings.VERBOSE = true;
40214
40253
  } else if (cmd.name == 'quiet') {
40215
- setStateVar('QUIET', true);
40254
+ settings.QUIET = true;
40216
40255
  } else if (cmd.name == 'debug') {
40217
- setStateVar('DEBUG', true);
40256
+ settings.DEBUG = true;
40218
40257
  } else {
40219
40258
  return true;
40220
40259
  }
40221
40260
  return false;
40222
40261
  });
40262
+ job.initSettings(settings);
40263
+ return filtered;
40223
40264
  }
40224
40265
 
40225
40266
  // Run informational commands and remove them from the array of parsed commands
@@ -40571,6 +40612,7 @@ ${svg}
40571
40612
  // to maintain compatibility with tests and to expose (some of) them to the GUI.
40572
40613
 
40573
40614
  Object.assign(internal, {
40615
+ Job,
40574
40616
  Dbf,
40575
40617
  DbfReader,
40576
40618
  DouglasPeucker,
@@ -40694,6 +40736,7 @@ ${svg}
40694
40736
  SourceUtils,
40695
40737
  Split,
40696
40738
  State,
40739
+ Stash,
40697
40740
  Stringify,
40698
40741
  Svg,
40699
40742
  SvgProperties,