mapshaper 0.6.55 → 0.6.57

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,8 +1,5 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.55";
4
-
5
-
6
3
  var utils = /*#__PURE__*/Object.freeze({
7
4
  __proto__: null,
8
5
  get default () { return utils; },
@@ -1403,6 +1400,14 @@
1403
1400
  else console.error(msg);
1404
1401
  }
1405
1402
 
1403
+ function truncateString(str, maxLen) {
1404
+ maxLen = maxLen || 80;
1405
+ if (str.length > maxLen) {
1406
+ str = str.substring(0, maxLen - 3).trimEnd() + '...';
1407
+ }
1408
+ return str;
1409
+ }
1410
+
1406
1411
  var Logging = /*#__PURE__*/Object.freeze({
1407
1412
  __proto__: null,
1408
1413
  getLoggingSetter: getLoggingSetter,
@@ -1424,7 +1429,8 @@
1424
1429
  formatColumns: formatColumns,
1425
1430
  formatStringsAsGrid: formatStringsAsGrid,
1426
1431
  formatLogArgs: formatLogArgs,
1427
- logArgs: logArgs
1432
+ logArgs: logArgs,
1433
+ truncateString: truncateString
1428
1434
  });
1429
1435
 
1430
1436
  function Transform() {
@@ -14209,6 +14215,87 @@
14209
14215
  };
14210
14216
  }
14211
14217
 
14218
+ // Return array of variables on the left side of assignment operations
14219
+ // @hasDot (bool) Return property assignments via dot notation
14220
+ function getAssignedVars(exp, hasDot) {
14221
+ var rxp = /[a-z_$][.a-z0-9_$]*(?= *=[^>=])/ig; // ignore arrow functions and comparisons
14222
+ var matches = exp.match(rxp) || [];
14223
+ var f = function(s) {
14224
+ var i = s.indexOf('.');
14225
+ return hasDot ? i > -1 : i == -1;
14226
+ };
14227
+ var vars = utils.uniq(matches.filter(f));
14228
+ return vars;
14229
+ }
14230
+
14231
+ // Return array of objects with properties assigned via dot notation
14232
+ // e.g. 'd.value = 45' -> ['d']
14233
+ // export function getAssignmentObjects(exp) {
14234
+ // var matches = getAssignedVars(exp, true),
14235
+ // names = [];
14236
+ // matches.forEach(function(s) {
14237
+ // var match = /^([^.]+)\.[^.]+$/.exec(s);
14238
+ // var name = match ? match[1] : null;
14239
+ // if (name && name != 'this') {
14240
+ // names.push(name);
14241
+ // }
14242
+ // });
14243
+ // return utils.uniq(names);
14244
+ // }
14245
+
14246
+ function getExpressionFunction(exp, opts) {
14247
+ var func = compileExpressionToFunction(exp, opts);
14248
+ return function(rec, ctx) {
14249
+ var val;
14250
+ try {
14251
+ val = func.call(ctx.$, rec, ctx);
14252
+ } catch(e) {
14253
+ stop(e.name, "in expression [" + exp + "]:", e.message);
14254
+ }
14255
+ return val;
14256
+ };
14257
+ }
14258
+
14259
+ function compileExpressionToFunction(exp, opts) {
14260
+ // $$ added to avoid duplication with data field variables (an error condition)
14261
+ var functionBody, func;
14262
+ if (opts.returns) {
14263
+ // functionBody = 'return ' + functionBody;
14264
+ functionBody = 'var $$retn = ' + exp + '; return $$retn;';
14265
+ } else {
14266
+ functionBody = exp;
14267
+ }
14268
+ functionBody = 'with($$env){with($$record){ ' + functionBody + '}}';
14269
+ try {
14270
+ func = new Function('$$record,$$env', functionBody);
14271
+ } catch(e) {
14272
+ // if (opts.quiet) throw e;
14273
+ stop(e.name, 'in expression [' + exp + ']');
14274
+ }
14275
+ return func;
14276
+ }
14277
+
14278
+ function getBaseContext(ctx) {
14279
+ ctx = ctx || {};
14280
+ // Mask global properties (is this effective/worth doing?)
14281
+ ctx.globalThis = void 0; // some globals are not iterable
14282
+ (function() {
14283
+ for (var key in this) {
14284
+ ctx[key] = void 0;
14285
+ }
14286
+ }());
14287
+ ctx.console = console;
14288
+ return ctx;
14289
+ }
14290
+
14291
+ var Expressions = /*#__PURE__*/Object.freeze({
14292
+ __proto__: null,
14293
+ getAssignedVars: getAssignedVars,
14294
+ getExpressionFunction: getExpressionFunction,
14295
+ compileExpressionToFunction: compileExpressionToFunction,
14296
+ getBaseContext: getBaseContext
14297
+ });
14298
+
14212
14299
  // Compiled expression returns a value
14213
14300
  function compileValueExpression(exp, lyr, arcs, opts) {
14214
14301
  opts = opts || {};
@@ -14216,7 +14303,6 @@
14216
14303
  return compileFeatureExpression(exp, lyr, arcs, opts);
14217
14304
  }
14218
14305
 
14219
-
14220
14306
  function compileFeaturePairFilterExpression(exp, lyr, arcs) {
14221
14307
  var func = compileFeaturePairExpression(exp, lyr, arcs);
14222
14308
  return function(idA, idB) {
@@ -14232,13 +14318,16 @@
14232
14318
  var exp = cleanExpression(rawExp);
14233
14319
  // don't add layer data to the context
14234
14320
  // (fields are not added to the pair expression context)
14235
- var ctx = getExpressionContext({});
14321
+ var ctx = getFeatureExpressionContext({});
14236
14322
  var getA = getProxyFactory(lyr, arcs);
14237
14323
  var getB = getProxyFactory(lyr, arcs);
14238
14324
  var vars = getAssignedVars(exp);
14239
14325
  var functionBody = "with($$env){with($$record){return " + exp + "}}";
14240
14326
  var func;
14241
14327
 
14328
+ // protect global object from assigned values
14329
+ nullifyUnsetProperties(vars, ctx);
14330
+
14242
14331
  try {
14243
14332
  func = new Function("$$record,$$env", functionBody);
14244
14333
  } catch(e) {
@@ -14246,9 +14335,6 @@
14246
14335
  stop(e.name, "in expression [" + exp + "]");
14247
14336
  }
14248
14337
 
14249
- // protect global object from assigned values
14250
- nullifyUnsetProperties(vars, ctx);
14251
-
14252
14338
  function getProxyFactory(lyr, arcs) {
14253
14339
  var records = lyr.data ? lyr.data.getRecords() : [];
14254
14340
  var getFeatureById = initFeatureProxy(lyr, arcs);
@@ -14284,12 +14370,12 @@
14284
14370
  };
14285
14371
  }
14286
14372
 
14287
- function compileFeatureExpression(rawExp, lyr, arcs, opts_) {
14288
- var opts = utils.extend({}, opts_),
14373
+ function compileFeatureExpression(rawExp, lyr, arcs, optsArg) {
14374
+ var opts = optsArg || {},
14375
+ ctx = opts.context || {},
14289
14376
  exp = cleanExpression(rawExp || ''),
14290
14377
  mutable = !opts.no_assign, // block assignment expressions
14291
- vars = getAssignedVars(exp),
14292
- func, records;
14378
+ vars = getAssignedVars(exp);
14293
14379
 
14294
14380
  if (mutable && vars.length > 0 && !lyr.data) {
14295
14381
  initDataTable(lyr);
@@ -14297,110 +14383,45 @@
14297
14383
 
14298
14384
  if (!mutable) {
14299
14385
  // protect global object from assigned values
14300
- opts.context = opts.context || {};
14301
- nullifyUnsetProperties(vars, opts.context);
14386
+ nullifyUnsetProperties(vars, ctx);
14302
14387
  }
14303
14388
 
14304
- records = lyr.data ? lyr.data.getRecords() : [];
14305
- func = getExpressionFunction(exp, lyr, arcs, opts);
14389
+ var records = lyr.data ? lyr.data.getRecords() : [];
14390
+ var getFeatureById = initFeatureProxy(lyr, arcs, opts);
14391
+ var layerOnlyProxy = addLayerGetters({}, lyr, arcs);
14392
+ var func = getExpressionFunction(exp, opts);
14393
+ ctx = getFeatureExpressionContext(lyr, ctx, opts);
14306
14394
 
14307
- // @destRec (optional) substitute for records[recId] (used by -calc)
14395
+ // recId: index of a data record in the records array.
14396
+ // destRec: (optional argument, used by -calc) an object used to capture assignments
14397
+ // By default, assignments are captured by records[recId]
14398
+ //
14308
14399
  return function(recId, destRec) {
14309
- var record;
14400
+ var rec;
14310
14401
  if (destRec) {
14311
- record = destRec;
14402
+ rec = destRec;
14312
14403
  } else {
14313
- record = records[recId] || (records[recId] = {});
14314
- }
14404
+ rec = records[recId] || (records[recId] = {});
14405
+ }
14406
+ // Assigning feature/layer proxy to '$' ... ctx.$ is also exposed as 'this'
14407
+ // in the expression context.
14408
+ ctx.$ = recId >= 0 ? getFeatureById(recId) : layerOnlyProxy;
14409
+ // "_" is used as an alias for the expression context, so functions can still
14410
+ // be used when masked by variables of the same name.
14411
+ ctx._ = ctx;
14412
+ // Expose data properties using "d", like d3 does. (data propertries are
14413
+ // also available as "this.properties")
14414
+ ctx.d = rec || null;
14315
14415
 
14316
- // initialize new fields to null so assignments work
14317
14416
  if (mutable) {
14318
- nullifyUnsetProperties(vars, record);
14319
- }
14320
- return func(record, recId);
14321
- };
14322
- }
14323
-
14324
- // Return array of variables on the left side of assignment operations
14325
- // @hasDot (bool) Return property assignments via dot notation
14326
- function getAssignedVars(exp, hasDot) {
14327
- var rxp = /[a-z_$][.a-z0-9_$]*(?= *=[^>=])/ig; // ignore arrow functions and comparisons
14328
- var matches = exp.match(rxp) || [];
14329
- var f = function(s) {
14330
- var i = s.indexOf('.');
14331
- return hasDot ? i > -1 : i == -1;
14332
- };
14333
- var vars = utils.uniq(matches.filter(f));
14334
- return vars;
14335
- }
14336
-
14337
- // Return array of objects with properties assigned via dot notation
14338
- // e.g. 'd.value = 45' -> ['d']
14339
- function getAssignmentObjects(exp) {
14340
- var matches = getAssignedVars(exp, true),
14341
- names = [];
14342
- matches.forEach(function(s) {
14343
- var match = /^([^.]+)\.[^.]+$/.exec(s);
14344
- var name = match ? match[1] : null;
14345
- if (name && name != 'this') {
14346
- names.push(name);
14347
- }
14348
- });
14349
- return utils.uniq(names);
14350
- }
14351
-
14352
- function compileExpressionToFunction(exp, opts) {
14353
- // $$ added to avoid duplication with data field variables (an error condition)
14354
- var functionBody, func;
14355
- if (opts.returns) {
14356
- // functionBody = 'return ' + functionBody;
14357
- functionBody = 'var $$retn = ' + exp + '; return $$retn;';
14358
- } else {
14359
- functionBody = exp;
14360
- }
14361
- functionBody = 'with($$env){with($$record){ ' + functionBody + '}}';
14362
- try {
14363
- func = new Function('$$record,$$env', functionBody);
14364
- } catch(e) {
14365
- // if (opts.quiet) throw e;
14366
- stop(e.name, 'in expression [' + exp + ']');
14367
- }
14368
- return func;
14369
- }
14370
-
14371
- function getExpressionFunction(exp, lyr, arcs, opts) {
14372
- var getFeatureById = initFeatureProxy(lyr, arcs, opts);
14373
- var layerOnlyProxy = addLayerGetters({}, lyr, arcs);
14374
- var ctx = getExpressionContext(lyr, opts.context, opts);
14375
- var func = compileExpressionToFunction(exp, opts);
14376
- return function(rec, i) {
14377
- var val;
14378
- // Assigning feature/layer proxy to '$' -- maybe this should be removed,
14379
- // since it is also exposed as "this".
14380
- // (kludge) i is undefined in calc expressions ... we still
14381
- // may need layer data (but not single-feature data)
14382
- ctx.$ = i >= 0 ? getFeatureById(i) : layerOnlyProxy;
14383
- ctx._ = ctx; // provide access to functions when masked by variable names
14384
- ctx.d = rec || null; // expose data properties a la d3 (also exposed as this.properties)
14385
- try {
14386
- val = func.call(ctx.$, rec, ctx);
14387
- } catch(e) {
14388
- // if (opts.quiet) throw e;
14389
- stop(e.name, "in expression [" + exp + "]:", e.message);
14417
+ // initialize assigned variables to rec.null so rec can capture them
14418
+ nullifyUnsetProperties(vars, rec);
14390
14419
  }
14391
- return val;
14420
+ return func(rec, ctx);
14392
14421
  };
14393
14422
  }
14394
14423
 
14395
- function nullifyUnsetProperties(vars, obj) {
14396
- for (var i=0; i<vars.length; i++) {
14397
- if (vars[i] in obj === false) {
14398
- obj[vars[i]] = null;
14399
- }
14400
- }
14401
- }
14402
-
14403
- function getExpressionContext(lyr, mixins, opts) {
14424
+ function getFeatureExpressionContext(lyr, mixins, opts) {
14404
14425
  var defs = getStashedVar('defs');
14405
14426
  var env = getBaseContext();
14406
14427
  var ctx = {};
@@ -14446,29 +14467,20 @@
14446
14467
  }, ctx);
14447
14468
  }
14448
14469
 
14449
- function getBaseContext(ctx) {
14450
- ctx = ctx || {};
14451
- // Mask global properties (is this effective/worth doing?)
14452
- ctx.globalThis = void 0; // some globals are not iterable
14453
- (function() {
14454
- for (var key in this) {
14455
- ctx[key] = void 0;
14470
+ function nullifyUnsetProperties(vars, obj) {
14471
+ for (var i=0; i<vars.length; i++) {
14472
+ if (vars[i] in obj === false) {
14473
+ obj[vars[i]] = null;
14456
14474
  }
14457
- }());
14458
- ctx.console = console;
14459
- return ctx;
14475
+ }
14460
14476
  }
14461
14477
 
14462
- var Expressions = /*#__PURE__*/Object.freeze({
14478
+ var FeatureExpressions = /*#__PURE__*/Object.freeze({
14463
14479
  __proto__: null,
14464
14480
  compileValueExpression: compileValueExpression,
14465
14481
  compileFeaturePairFilterExpression: compileFeaturePairFilterExpression,
14466
14482
  compileFeaturePairExpression: compileFeaturePairExpression,
14467
- compileFeatureExpression: compileFeatureExpression,
14468
- getAssignedVars: getAssignedVars,
14469
- getAssignmentObjects: getAssignmentObjects,
14470
- compileExpressionToFunction: compileExpressionToFunction,
14471
- getBaseContext: getBaseContext
14483
+ compileFeatureExpression: compileFeatureExpression
14472
14484
  });
14473
14485
 
14474
14486
  function getMode(values) {
@@ -25221,11 +25233,12 @@ ${svg}
25221
25233
  describe: 'use field values to calculate data island weights'
25222
25234
  });
25223
25235
 
25224
- parser.command('external')
25225
- .option('module', {
25226
- DEFAULT: true,
25227
- describe: 'name of Node module containing the command'
25228
- });
25236
+ // replaced by -require
25237
+ // parser.command('external')
25238
+ // .option('module', {
25239
+ // DEFAULT: true,
25240
+ // describe: 'name of Node module containing the command'
25241
+ // });
25229
25242
 
25230
25243
  parser.command('filter-points')
25231
25244
  // .describe('remove points that are not part of a group')
@@ -25311,17 +25324,17 @@ ${svg}
25311
25324
  .option('no-replace', noReplaceOpt);
25312
25325
 
25313
25326
  parser.command('require')
25314
- .describe('require a Node module for use in -each expressions')
25327
+ .describe('require a Node module or ES module to use in JS expressions')
25315
25328
  .option('module', {
25316
25329
  DEFAULT: true,
25317
- describe: 'name of Node module or path to module file'
25330
+ describe: 'name of installed module or path to module file'
25318
25331
  })
25319
25332
  .option('alias', {
25320
25333
  describe: 'Set the module name to an alias'
25321
- })
25322
- .option('init', {
25323
- describe: 'JS expression to run after the module loads'
25324
25334
  });
25335
+ // .option('init', {
25336
+ // describe: 'JS expression to run after the module loads'
25337
+ // });
25325
25338
 
25326
25339
  parser.command('rotate')
25327
25340
  // .describe('apply d3-style 3-axis rotation to a lat-long dataset')
@@ -35318,7 +35331,6 @@ ${svg}
35318
35331
  if (targets.length === 0 && targetId) {
35319
35332
  stop('Layer not found:', targetId);
35320
35333
  }
35321
- // var vars = getAssignedVars(exp);
35322
35334
  var defs = getStashedVar('defs') || {};
35323
35335
 
35324
35336
  var ctx;
@@ -41983,8 +41995,8 @@ ${svg}
41983
41995
  return true;
41984
41996
  }
41985
41997
 
41986
- cmd.require = async function(targets, opts) {
41987
- var defs = getStashedVar('defs');
41998
+ cmd.require = async function(opts) {
41999
+ var globals = getStashedVar('defs');
41988
42000
  var moduleFile, moduleName, mod;
41989
42001
  if (!opts.module) {
41990
42002
  stop("Missing module name or path to module");
@@ -42000,25 +42012,33 @@ ${svg}
42000
42012
  moduleFile = require$1('path').join(process.cwd(), moduleFile);
42001
42013
  }
42002
42014
  try {
42003
- mod = require$1(moduleFile || moduleName);
42015
+ // import CJS and ES modules
42016
+ mod = await import(moduleFile || moduleName);
42017
+ if (mod.default) {
42018
+ mod = mod.default;
42019
+ }
42004
42020
  if (typeof mod == 'function') {
42005
- // -require now includes the functionality of the old -external command
42021
+ // assuming that functions are mapshpaper command generators...
42022
+ // this MUST be changed asap.
42006
42023
  var retn = mod(api);
42007
42024
  if (retn && isValidExternalCommand(retn)) {
42008
42025
  cmd.registerCommand(retn.name, retn);
42009
42026
  }
42010
42027
  }
42011
42028
  } catch(e) {
42012
- stop('Unable to load external module:', e.message, getErrorDetail(e));
42029
+ if (!mod) {
42030
+ stop('Unable to load external module:', e.message, getErrorDetail(e));
42031
+ }
42013
42032
  }
42014
42033
  if (moduleName || opts.alias) {
42015
- defs[opts.alias || moduleName] = mod;
42034
+ globals[opts.alias || moduleName] = mod;
42016
42035
  } else {
42017
- Object.assign(defs, mod);
42018
- }
42019
- if (opts.init) {
42020
- await evalTemplateExpression(opts.init, targets);
42036
+ Object.assign(globals, mod);
42021
42037
  }
42038
+ // instead of an init expression, you could use -run <expression>
42039
+ // if (opts.init) {
42040
+ // await evalTemplateExpression(opts.init, targets);
42041
+ // }
42022
42042
  };
42023
42043
 
42024
42044
  // Parse an array or a string of command line tokens into an array of
@@ -42074,13 +42094,19 @@ ${svg}
42074
42094
  });
42075
42095
 
42076
42096
  function getIOProxy(job) {
42077
- var obj = {
42078
- _cache: {}
42079
- };
42080
- obj.addInputFile = function(filename, content) {
42081
- obj._cache[filename] = content;
42097
+ async function addInputFile(filename, content) {
42098
+ if (utils.isPromise(content)) {
42099
+ content = await content;
42100
+ }
42101
+ io._cache[filename] = content;
42102
+ return filename; // return filename to support -run '-i {io.ifile()}'
42103
+ }
42104
+ var io = {
42105
+ _cache: {},
42106
+ addInputFile,
42107
+ ifile: addInputFile // ifile() is an alias for addInputFile
42082
42108
  };
42083
- return obj;
42109
+ return io;
42084
42110
  }
42085
42111
 
42086
42112
  function commandTakesFileInput(name) {
@@ -42123,7 +42149,8 @@ ${svg}
42123
42149
  stop('Expected a string containing mapshaper commands; received:', tmp);
42124
42150
  }
42125
42151
  if (tmp) {
42126
- message(`command: [${tmp}]`);
42152
+ // truncate message (command might include a large GeoJSON string in an -i command)
42153
+ message(`command: [${truncateString(tmp, 150)}]`);
42127
42154
  commands = parseCommands(tmp);
42128
42155
 
42129
42156
  // TODO: remove duplication with mapshaper-run-commands.mjs
@@ -44473,9 +44500,9 @@ ${svg}
44473
44500
  } else if (name == 'explode') {
44474
44501
  outputLayers = applyCommandToEachLayer(cmd.explodeFeatures, targetLayers, arcs, opts);
44475
44502
 
44476
- } else if (name == 'external') {
44477
- // -require now incorporates -external
44478
- cmd.require(targets, opts);
44503
+ // -require now incorporates functionality of -external
44504
+ // } else if (name == 'external') {
44505
+ // cmd.require(targets, opts);
44479
44506
 
44480
44507
  } else if (name == 'filter') {
44481
44508
  outputLayers = applyCommandToEachLayer(cmd.filterFeatures, targetLayers, arcs, opts);
@@ -44617,7 +44644,7 @@ ${svg}
44617
44644
  cmd.renameLayers(targetLayers, opts.names, job.catalog);
44618
44645
 
44619
44646
  } else if (name == 'require') {
44620
- cmd.require(targets, opts);
44647
+ await cmd.require(opts);
44621
44648
 
44622
44649
  } else if (name == 'rotate') {
44623
44650
  targets.forEach(function(targ) {
@@ -44766,6 +44793,8 @@ ${svg}
44766
44793
  });
44767
44794
  }
44768
44795
 
44796
+ var version = "0.6.57";
44797
+
44769
44798
  // Parse command line args into commands and run them
44770
44799
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
44771
44800
  // function(argv[, input], callback)
@@ -45069,7 +45098,7 @@ ${svg}
45069
45098
  function runAndRemoveInfoCommands(commands) {
45070
45099
  return commands.filter(function(cmd) {
45071
45100
  if (cmd.name == 'version') {
45072
- print(typeof VERSION == 'undefined' ? '' : VERSION);
45101
+ print(version);
45073
45102
  } else if (cmd.name == 'encodings') {
45074
45103
  printEncodings();
45075
45104
  } else if (cmd.name == 'colors') {
@@ -45445,6 +45474,7 @@ ${svg}
45445
45474
  Explode,
45446
45475
  Export,
45447
45476
  Expressions,
45477
+ FeatureExpressions,
45448
45478
  FileExport,
45449
45479
  FileImport,
45450
45480
  FilenameUtils,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.6.55",
3
+ "version": "0.6.57",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -64,6 +64,7 @@
64
64
  "tinyqueue": "^2.0.3"
65
65
  },
66
66
  "devDependencies": {
67
+ "@rollup/plugin-json": "^6.0.1",
67
68
  "@rollup/plugin-node-resolve": "^13.3.0",
68
69
  "browserify": "^17.0.0",
69
70
  "csv-spectrum": "^1.0.0",
package/www/index.html CHANGED
@@ -309,7 +309,7 @@ encoding=big5</span>. Click to see all options.</div></div></div></div>
309
309
  <div class="coordinate-info colored-text selectable"></div>
310
310
  <div class="intersection-display">
311
311
  <span class="intersection-check text-btn colored-text">Check line intersections</span><span class="intersection-count">0 line intersections</span>
312
- <img class="close-btn" src="images/close.png">
312
+ <img class="close-btn" draggable="false" src="images/close.png">
313
313
  <div class="repair-btn text-btn colored-text">Repair</div>
314
314
 
315
315
  </div>
@@ -5374,6 +5374,14 @@
5374
5374
  else console.error(msg);
5375
5375
  }
5376
5376
 
5377
+ function truncateString(str, maxLen) {
5378
+ maxLen = maxLen || 80;
5379
+ if (str.length > maxLen) {
5380
+ str = str.substring(0, maxLen - 3).trimEnd() + '...';
5381
+ }
5382
+ return str;
5383
+ }
5384
+
5377
5385
  var uniqCount = 0;
5378
5386
  function getUniqueName(prefix) {
5379
5387
  return (prefix || "__id_") + (++uniqCount);
package/www/mapshaper.js CHANGED
@@ -1,8 +1,5 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.6.55";
4
-
5
-
6
3
  var utils = /*#__PURE__*/Object.freeze({
7
4
  __proto__: null,
8
5
  get default () { return utils; },
@@ -1403,6 +1400,14 @@
1403
1400
  else console.error(msg);
1404
1401
  }
1405
1402
 
1403
+ function truncateString(str, maxLen) {
1404
+ maxLen = maxLen || 80;
1405
+ if (str.length > maxLen) {
1406
+ str = str.substring(0, maxLen - 3).trimEnd() + '...';
1407
+ }
1408
+ return str;
1409
+ }
1410
+
1406
1411
  var Logging = /*#__PURE__*/Object.freeze({
1407
1412
  __proto__: null,
1408
1413
  getLoggingSetter: getLoggingSetter,
@@ -1424,7 +1429,8 @@
1424
1429
  formatColumns: formatColumns,
1425
1430
  formatStringsAsGrid: formatStringsAsGrid,
1426
1431
  formatLogArgs: formatLogArgs,
1427
- logArgs: logArgs
1432
+ logArgs: logArgs,
1433
+ truncateString: truncateString
1428
1434
  });
1429
1435
 
1430
1436
  function Transform() {
@@ -14209,6 +14215,87 @@
14209
14215
  };
14210
14216
  }
14211
14217
 
14218
+ // Return array of variables on the left side of assignment operations
14219
+ // @hasDot (bool) Return property assignments via dot notation
14220
+ function getAssignedVars(exp, hasDot) {
14221
+ var rxp = /[a-z_$][.a-z0-9_$]*(?= *=[^>=])/ig; // ignore arrow functions and comparisons
14222
+ var matches = exp.match(rxp) || [];
14223
+ var f = function(s) {
14224
+ var i = s.indexOf('.');
14225
+ return hasDot ? i > -1 : i == -1;
14226
+ };
14227
+ var vars = utils.uniq(matches.filter(f));
14228
+ return vars;
14229
+ }
14230
+
14231
+ // Return array of objects with properties assigned via dot notation
14232
+ // e.g. 'd.value = 45' -> ['d']
14233
+ // export function getAssignmentObjects(exp) {
14234
+ // var matches = getAssignedVars(exp, true),
14235
+ // names = [];
14236
+ // matches.forEach(function(s) {
14237
+ // var match = /^([^.]+)\.[^.]+$/.exec(s);
14238
+ // var name = match ? match[1] : null;
14239
+ // if (name && name != 'this') {
14240
+ // names.push(name);
14241
+ // }
14242
+ // });
14243
+ // return utils.uniq(names);
14244
+ // }
14245
+
14246
+ function getExpressionFunction(exp, opts) {
14247
+ var func = compileExpressionToFunction(exp, opts);
14248
+ return function(rec, ctx) {
14249
+ var val;
14250
+ try {
14251
+ val = func.call(ctx.$, rec, ctx);
14252
+ } catch(e) {
14253
+ stop(e.name, "in expression [" + exp + "]:", e.message);
14254
+ }
14255
+ return val;
14256
+ };
14257
+ }
14258
+
14259
+ function compileExpressionToFunction(exp, opts) {
14260
+ // $$ added to avoid duplication with data field variables (an error condition)
14261
+ var functionBody, func;
14262
+ if (opts.returns) {
14263
+ // functionBody = 'return ' + functionBody;
14264
+ functionBody = 'var $$retn = ' + exp + '; return $$retn;';
14265
+ } else {
14266
+ functionBody = exp;
14267
+ }
14268
+ functionBody = 'with($$env){with($$record){ ' + functionBody + '}}';
14269
+ try {
14270
+ func = new Function('$$record,$$env', functionBody);
14271
+ } catch(e) {
14272
+ // if (opts.quiet) throw e;
14273
+ stop(e.name, 'in expression [' + exp + ']');
14274
+ }
14275
+ return func;
14276
+ }
14277
+
14278
+ function getBaseContext(ctx) {
14279
+ ctx = ctx || {};
14280
+ // Mask global properties (is this effective/worth doing?)
14281
+ ctx.globalThis = void 0; // some globals are not iterable
14282
+ (function() {
14283
+ for (var key in this) {
14284
+ ctx[key] = void 0;
14285
+ }
14286
+ }());
14287
+ ctx.console = console;
14288
+ return ctx;
14289
+ }
14290
+
14291
+ var Expressions = /*#__PURE__*/Object.freeze({
14292
+ __proto__: null,
14293
+ getAssignedVars: getAssignedVars,
14294
+ getExpressionFunction: getExpressionFunction,
14295
+ compileExpressionToFunction: compileExpressionToFunction,
14296
+ getBaseContext: getBaseContext
14297
+ });
14298
+
14212
14299
  // Compiled expression returns a value
14213
14300
  function compileValueExpression(exp, lyr, arcs, opts) {
14214
14301
  opts = opts || {};
@@ -14216,7 +14303,6 @@
14216
14303
  return compileFeatureExpression(exp, lyr, arcs, opts);
14217
14304
  }
14218
14305
 
14219
-
14220
14306
  function compileFeaturePairFilterExpression(exp, lyr, arcs) {
14221
14307
  var func = compileFeaturePairExpression(exp, lyr, arcs);
14222
14308
  return function(idA, idB) {
@@ -14232,13 +14318,16 @@
14232
14318
  var exp = cleanExpression(rawExp);
14233
14319
  // don't add layer data to the context
14234
14320
  // (fields are not added to the pair expression context)
14235
- var ctx = getExpressionContext({});
14321
+ var ctx = getFeatureExpressionContext({});
14236
14322
  var getA = getProxyFactory(lyr, arcs);
14237
14323
  var getB = getProxyFactory(lyr, arcs);
14238
14324
  var vars = getAssignedVars(exp);
14239
14325
  var functionBody = "with($$env){with($$record){return " + exp + "}}";
14240
14326
  var func;
14241
14327
 
14328
+ // protect global object from assigned values
14329
+ nullifyUnsetProperties(vars, ctx);
14330
+
14242
14331
  try {
14243
14332
  func = new Function("$$record,$$env", functionBody);
14244
14333
  } catch(e) {
@@ -14246,9 +14335,6 @@
14246
14335
  stop(e.name, "in expression [" + exp + "]");
14247
14336
  }
14248
14337
 
14249
- // protect global object from assigned values
14250
- nullifyUnsetProperties(vars, ctx);
14251
-
14252
14338
  function getProxyFactory(lyr, arcs) {
14253
14339
  var records = lyr.data ? lyr.data.getRecords() : [];
14254
14340
  var getFeatureById = initFeatureProxy(lyr, arcs);
@@ -14284,12 +14370,12 @@
14284
14370
  };
14285
14371
  }
14286
14372
 
14287
- function compileFeatureExpression(rawExp, lyr, arcs, opts_) {
14288
- var opts = utils.extend({}, opts_),
14373
+ function compileFeatureExpression(rawExp, lyr, arcs, optsArg) {
14374
+ var opts = optsArg || {},
14375
+ ctx = opts.context || {},
14289
14376
  exp = cleanExpression(rawExp || ''),
14290
14377
  mutable = !opts.no_assign, // block assignment expressions
14291
- vars = getAssignedVars(exp),
14292
- func, records;
14378
+ vars = getAssignedVars(exp);
14293
14379
 
14294
14380
  if (mutable && vars.length > 0 && !lyr.data) {
14295
14381
  initDataTable(lyr);
@@ -14297,110 +14383,45 @@
14297
14383
 
14298
14384
  if (!mutable) {
14299
14385
  // protect global object from assigned values
14300
- opts.context = opts.context || {};
14301
- nullifyUnsetProperties(vars, opts.context);
14386
+ nullifyUnsetProperties(vars, ctx);
14302
14387
  }
14303
14388
 
14304
- records = lyr.data ? lyr.data.getRecords() : [];
14305
- func = getExpressionFunction(exp, lyr, arcs, opts);
14389
+ var records = lyr.data ? lyr.data.getRecords() : [];
14390
+ var getFeatureById = initFeatureProxy(lyr, arcs, opts);
14391
+ var layerOnlyProxy = addLayerGetters({}, lyr, arcs);
14392
+ var func = getExpressionFunction(exp, opts);
14393
+ ctx = getFeatureExpressionContext(lyr, ctx, opts);
14306
14394
 
14307
- // @destRec (optional) substitute for records[recId] (used by -calc)
14395
+ // recId: index of a data record in the records array.
14396
+ // destRec: (optional argument, used by -calc) an object used to capture assignments
14397
+ // By default, assignments are captured by records[recId]
14398
+ //
14308
14399
  return function(recId, destRec) {
14309
- var record;
14400
+ var rec;
14310
14401
  if (destRec) {
14311
- record = destRec;
14402
+ rec = destRec;
14312
14403
  } else {
14313
- record = records[recId] || (records[recId] = {});
14314
- }
14404
+ rec = records[recId] || (records[recId] = {});
14405
+ }
14406
+ // Assigning feature/layer proxy to '$' ... ctx.$ is also exposed as 'this'
14407
+ // in the expression context.
14408
+ ctx.$ = recId >= 0 ? getFeatureById(recId) : layerOnlyProxy;
14409
+ // "_" is used as an alias for the expression context, so functions can still
14410
+ // be used when masked by variables of the same name.
14411
+ ctx._ = ctx;
14412
+ // Expose data properties using "d", like d3 does. (data propertries are
14413
+ // also available as "this.properties")
14414
+ ctx.d = rec || null;
14315
14415
 
14316
- // initialize new fields to null so assignments work
14317
14416
  if (mutable) {
14318
- nullifyUnsetProperties(vars, record);
14319
- }
14320
- return func(record, recId);
14321
- };
14322
- }
14323
-
14324
- // Return array of variables on the left side of assignment operations
14325
- // @hasDot (bool) Return property assignments via dot notation
14326
- function getAssignedVars(exp, hasDot) {
14327
- var rxp = /[a-z_$][.a-z0-9_$]*(?= *=[^>=])/ig; // ignore arrow functions and comparisons
14328
- var matches = exp.match(rxp) || [];
14329
- var f = function(s) {
14330
- var i = s.indexOf('.');
14331
- return hasDot ? i > -1 : i == -1;
14332
- };
14333
- var vars = utils.uniq(matches.filter(f));
14334
- return vars;
14335
- }
14336
-
14337
- // Return array of objects with properties assigned via dot notation
14338
- // e.g. 'd.value = 45' -> ['d']
14339
- function getAssignmentObjects(exp) {
14340
- var matches = getAssignedVars(exp, true),
14341
- names = [];
14342
- matches.forEach(function(s) {
14343
- var match = /^([^.]+)\.[^.]+$/.exec(s);
14344
- var name = match ? match[1] : null;
14345
- if (name && name != 'this') {
14346
- names.push(name);
14347
- }
14348
- });
14349
- return utils.uniq(names);
14350
- }
14351
-
14352
- function compileExpressionToFunction(exp, opts) {
14353
- // $$ added to avoid duplication with data field variables (an error condition)
14354
- var functionBody, func;
14355
- if (opts.returns) {
14356
- // functionBody = 'return ' + functionBody;
14357
- functionBody = 'var $$retn = ' + exp + '; return $$retn;';
14358
- } else {
14359
- functionBody = exp;
14360
- }
14361
- functionBody = 'with($$env){with($$record){ ' + functionBody + '}}';
14362
- try {
14363
- func = new Function('$$record,$$env', functionBody);
14364
- } catch(e) {
14365
- // if (opts.quiet) throw e;
14366
- stop(e.name, 'in expression [' + exp + ']');
14367
- }
14368
- return func;
14369
- }
14370
-
14371
- function getExpressionFunction(exp, lyr, arcs, opts) {
14372
- var getFeatureById = initFeatureProxy(lyr, arcs, opts);
14373
- var layerOnlyProxy = addLayerGetters({}, lyr, arcs);
14374
- var ctx = getExpressionContext(lyr, opts.context, opts);
14375
- var func = compileExpressionToFunction(exp, opts);
14376
- return function(rec, i) {
14377
- var val;
14378
- // Assigning feature/layer proxy to '$' -- maybe this should be removed,
14379
- // since it is also exposed as "this".
14380
- // (kludge) i is undefined in calc expressions ... we still
14381
- // may need layer data (but not single-feature data)
14382
- ctx.$ = i >= 0 ? getFeatureById(i) : layerOnlyProxy;
14383
- ctx._ = ctx; // provide access to functions when masked by variable names
14384
- ctx.d = rec || null; // expose data properties a la d3 (also exposed as this.properties)
14385
- try {
14386
- val = func.call(ctx.$, rec, ctx);
14387
- } catch(e) {
14388
- // if (opts.quiet) throw e;
14389
- stop(e.name, "in expression [" + exp + "]:", e.message);
14417
+ // initialize assigned variables to rec.null so rec can capture them
14418
+ nullifyUnsetProperties(vars, rec);
14390
14419
  }
14391
- return val;
14420
+ return func(rec, ctx);
14392
14421
  };
14393
14422
  }
14394
14423
 
14395
- function nullifyUnsetProperties(vars, obj) {
14396
- for (var i=0; i<vars.length; i++) {
14397
- if (vars[i] in obj === false) {
14398
- obj[vars[i]] = null;
14399
- }
14400
- }
14401
- }
14402
-
14403
- function getExpressionContext(lyr, mixins, opts) {
14424
+ function getFeatureExpressionContext(lyr, mixins, opts) {
14404
14425
  var defs = getStashedVar('defs');
14405
14426
  var env = getBaseContext();
14406
14427
  var ctx = {};
@@ -14446,29 +14467,20 @@
14446
14467
  }, ctx);
14447
14468
  }
14448
14469
 
14449
- function getBaseContext(ctx) {
14450
- ctx = ctx || {};
14451
- // Mask global properties (is this effective/worth doing?)
14452
- ctx.globalThis = void 0; // some globals are not iterable
14453
- (function() {
14454
- for (var key in this) {
14455
- ctx[key] = void 0;
14470
+ function nullifyUnsetProperties(vars, obj) {
14471
+ for (var i=0; i<vars.length; i++) {
14472
+ if (vars[i] in obj === false) {
14473
+ obj[vars[i]] = null;
14456
14474
  }
14457
- }());
14458
- ctx.console = console;
14459
- return ctx;
14475
+ }
14460
14476
  }
14461
14477
 
14462
- var Expressions = /*#__PURE__*/Object.freeze({
14478
+ var FeatureExpressions = /*#__PURE__*/Object.freeze({
14463
14479
  __proto__: null,
14464
14480
  compileValueExpression: compileValueExpression,
14465
14481
  compileFeaturePairFilterExpression: compileFeaturePairFilterExpression,
14466
14482
  compileFeaturePairExpression: compileFeaturePairExpression,
14467
- compileFeatureExpression: compileFeatureExpression,
14468
- getAssignedVars: getAssignedVars,
14469
- getAssignmentObjects: getAssignmentObjects,
14470
- compileExpressionToFunction: compileExpressionToFunction,
14471
- getBaseContext: getBaseContext
14483
+ compileFeatureExpression: compileFeatureExpression
14472
14484
  });
14473
14485
 
14474
14486
  function getMode(values) {
@@ -25221,11 +25233,12 @@ ${svg}
25221
25233
  describe: 'use field values to calculate data island weights'
25222
25234
  });
25223
25235
 
25224
- parser.command('external')
25225
- .option('module', {
25226
- DEFAULT: true,
25227
- describe: 'name of Node module containing the command'
25228
- });
25236
+ // replaced by -require
25237
+ // parser.command('external')
25238
+ // .option('module', {
25239
+ // DEFAULT: true,
25240
+ // describe: 'name of Node module containing the command'
25241
+ // });
25229
25242
 
25230
25243
  parser.command('filter-points')
25231
25244
  // .describe('remove points that are not part of a group')
@@ -25311,17 +25324,17 @@ ${svg}
25311
25324
  .option('no-replace', noReplaceOpt);
25312
25325
 
25313
25326
  parser.command('require')
25314
- .describe('require a Node module for use in -each expressions')
25327
+ .describe('require a Node module or ES module to use in JS expressions')
25315
25328
  .option('module', {
25316
25329
  DEFAULT: true,
25317
- describe: 'name of Node module or path to module file'
25330
+ describe: 'name of installed module or path to module file'
25318
25331
  })
25319
25332
  .option('alias', {
25320
25333
  describe: 'Set the module name to an alias'
25321
- })
25322
- .option('init', {
25323
- describe: 'JS expression to run after the module loads'
25324
25334
  });
25335
+ // .option('init', {
25336
+ // describe: 'JS expression to run after the module loads'
25337
+ // });
25325
25338
 
25326
25339
  parser.command('rotate')
25327
25340
  // .describe('apply d3-style 3-axis rotation to a lat-long dataset')
@@ -35318,7 +35331,6 @@ ${svg}
35318
35331
  if (targets.length === 0 && targetId) {
35319
35332
  stop('Layer not found:', targetId);
35320
35333
  }
35321
- // var vars = getAssignedVars(exp);
35322
35334
  var defs = getStashedVar('defs') || {};
35323
35335
 
35324
35336
  var ctx;
@@ -41983,8 +41995,8 @@ ${svg}
41983
41995
  return true;
41984
41996
  }
41985
41997
 
41986
- cmd.require = async function(targets, opts) {
41987
- var defs = getStashedVar('defs');
41998
+ cmd.require = async function(opts) {
41999
+ var globals = getStashedVar('defs');
41988
42000
  var moduleFile, moduleName, mod;
41989
42001
  if (!opts.module) {
41990
42002
  stop("Missing module name or path to module");
@@ -42000,25 +42012,33 @@ ${svg}
42000
42012
  moduleFile = require$1('path').join(process.cwd(), moduleFile);
42001
42013
  }
42002
42014
  try {
42003
- mod = require$1(moduleFile || moduleName);
42015
+ // import CJS and ES modules
42016
+ mod = await import(moduleFile || moduleName);
42017
+ if (mod.default) {
42018
+ mod = mod.default;
42019
+ }
42004
42020
  if (typeof mod == 'function') {
42005
- // -require now includes the functionality of the old -external command
42021
+ // assuming that functions are mapshpaper command generators...
42022
+ // this MUST be changed asap.
42006
42023
  var retn = mod(api);
42007
42024
  if (retn && isValidExternalCommand(retn)) {
42008
42025
  cmd.registerCommand(retn.name, retn);
42009
42026
  }
42010
42027
  }
42011
42028
  } catch(e) {
42012
- stop('Unable to load external module:', e.message, getErrorDetail(e));
42029
+ if (!mod) {
42030
+ stop('Unable to load external module:', e.message, getErrorDetail(e));
42031
+ }
42013
42032
  }
42014
42033
  if (moduleName || opts.alias) {
42015
- defs[opts.alias || moduleName] = mod;
42034
+ globals[opts.alias || moduleName] = mod;
42016
42035
  } else {
42017
- Object.assign(defs, mod);
42018
- }
42019
- if (opts.init) {
42020
- await evalTemplateExpression(opts.init, targets);
42036
+ Object.assign(globals, mod);
42021
42037
  }
42038
+ // instead of an init expression, you could use -run <expression>
42039
+ // if (opts.init) {
42040
+ // await evalTemplateExpression(opts.init, targets);
42041
+ // }
42022
42042
  };
42023
42043
 
42024
42044
  // Parse an array or a string of command line tokens into an array of
@@ -42074,13 +42094,19 @@ ${svg}
42074
42094
  });
42075
42095
 
42076
42096
  function getIOProxy(job) {
42077
- var obj = {
42078
- _cache: {}
42079
- };
42080
- obj.addInputFile = function(filename, content) {
42081
- obj._cache[filename] = content;
42097
+ async function addInputFile(filename, content) {
42098
+ if (utils.isPromise(content)) {
42099
+ content = await content;
42100
+ }
42101
+ io._cache[filename] = content;
42102
+ return filename; // return filename to support -run '-i {io.ifile()}'
42103
+ }
42104
+ var io = {
42105
+ _cache: {},
42106
+ addInputFile,
42107
+ ifile: addInputFile // ifile() is an alias for addInputFile
42082
42108
  };
42083
- return obj;
42109
+ return io;
42084
42110
  }
42085
42111
 
42086
42112
  function commandTakesFileInput(name) {
@@ -42123,7 +42149,8 @@ ${svg}
42123
42149
  stop('Expected a string containing mapshaper commands; received:', tmp);
42124
42150
  }
42125
42151
  if (tmp) {
42126
- message(`command: [${tmp}]`);
42152
+ // truncate message (command might include a large GeoJSON string in an -i command)
42153
+ message(`command: [${truncateString(tmp, 150)}]`);
42127
42154
  commands = parseCommands(tmp);
42128
42155
 
42129
42156
  // TODO: remove duplication with mapshaper-run-commands.mjs
@@ -44473,9 +44500,9 @@ ${svg}
44473
44500
  } else if (name == 'explode') {
44474
44501
  outputLayers = applyCommandToEachLayer(cmd.explodeFeatures, targetLayers, arcs, opts);
44475
44502
 
44476
- } else if (name == 'external') {
44477
- // -require now incorporates -external
44478
- cmd.require(targets, opts);
44503
+ // -require now incorporates functionality of -external
44504
+ // } else if (name == 'external') {
44505
+ // cmd.require(targets, opts);
44479
44506
 
44480
44507
  } else if (name == 'filter') {
44481
44508
  outputLayers = applyCommandToEachLayer(cmd.filterFeatures, targetLayers, arcs, opts);
@@ -44617,7 +44644,7 @@ ${svg}
44617
44644
  cmd.renameLayers(targetLayers, opts.names, job.catalog);
44618
44645
 
44619
44646
  } else if (name == 'require') {
44620
- cmd.require(targets, opts);
44647
+ await cmd.require(opts);
44621
44648
 
44622
44649
  } else if (name == 'rotate') {
44623
44650
  targets.forEach(function(targ) {
@@ -44766,6 +44793,8 @@ ${svg}
44766
44793
  });
44767
44794
  }
44768
44795
 
44796
+ var version = "0.6.57";
44797
+
44769
44798
  // Parse command line args into commands and run them
44770
44799
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
44771
44800
  // function(argv[, input], callback)
@@ -45069,7 +45098,7 @@ ${svg}
45069
45098
  function runAndRemoveInfoCommands(commands) {
45070
45099
  return commands.filter(function(cmd) {
45071
45100
  if (cmd.name == 'version') {
45072
- print(typeof VERSION == 'undefined' ? '' : VERSION);
45101
+ print(version);
45073
45102
  } else if (cmd.name == 'encodings') {
45074
45103
  printEncodings();
45075
45104
  } else if (cmd.name == 'colors') {
@@ -45445,6 +45474,7 @@ ${svg}
45445
45474
  Explode,
45446
45475
  Export,
45447
45476
  Expressions,
45477
+ FeatureExpressions,
45448
45478
  FileExport,
45449
45479
  FileImport,
45450
45480
  FilenameUtils,