From 40f00e0c9a1701b77cdb1a2b9176161d402b6e7d Mon Sep 17 00:00:00 2001 From: Matthew Bloch Date: Sun, 11 Feb 2024 20:49:44 -0500 Subject: [PATCH] Run commands can support multiple targets --- src/expressions/mapshaper-target-proxy.mjs | 13 ++++++------- .../mapshaper-template-expressions.mjs | 17 +++++++++++++++-- test/run-test.mjs | 17 +++++++++++++++++ 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/expressions/mapshaper-target-proxy.mjs b/src/expressions/mapshaper-target-proxy.mjs index 1ced56dd..1bc3030f 100644 --- a/src/expressions/mapshaper-target-proxy.mjs +++ b/src/expressions/mapshaper-target-proxy.mjs @@ -4,22 +4,21 @@ import { addGetters } from '../expressions/mapshaper-expression-utils'; // import { importGeoJSON } from '../geojson/geojson-import'; export function getTargetProxy(target) { - var lyr = target.layers[0]; - var data = getLayerInfo(lyr, target.dataset); // layer_name, feature_count etc - data.layer = lyr; - data.dataset = target.dataset; - addGetters(data, { + var proxy = getLayerInfo(target.layer, target.dataset); // layer_name, feature_count etc + proxy.layer = target.layer; + proxy.dataset = target.dataset; + addGetters(proxy, { // export as an object, not a string or buffer geojson: getGeoJSON }); function getGeoJSON() { - var features = exportLayerAsGeoJSON(lyr, target.dataset, {rfc7946: true}, true); + var features = exportLayerAsGeoJSON(target.layer, target.dataset, {rfc7946: true}, true); return { type: 'FeatureCollection', features: features }; } - return data; + return proxy; } diff --git a/src/expressions/mapshaper-template-expressions.mjs b/src/expressions/mapshaper-template-expressions.mjs index 9754565a..d183acdb 100644 --- a/src/expressions/mapshaper-template-expressions.mjs +++ b/src/expressions/mapshaper-template-expressions.mjs @@ -3,6 +3,7 @@ import { getStashedVar } from '../mapshaper-stash'; import { getTargetProxy } from '../expressions/mapshaper-target-proxy'; import { stop, error } from '../utils/mapshaper-logging'; import utils from '../utils/mapshaper-utils'; +import { expandCommandTargets } from '../dataset/mapshaper-target-utils'; // Support for evaluating expressions embedded in curly-brace templates @@ -10,8 +11,20 @@ import utils from '../utils/mapshaper-utils'; export async function evalTemplateExpression(expression, targets, ctx) { ctx = ctx || getBaseContext(); // TODO: throw an error if target is used when there are multiple targets - if (targets && targets.length == 1) { - Object.defineProperty(ctx, 'target', {value: getTargetProxy(targets[0])}); + if (targets) { + var proxies = expandCommandTargets(targets).reduce(function(memo, target) { + var proxy = getTargetProxy(target); + memo.push(proxy); + // index targets by layer name too + if (target.layer.name) { + memo[target.layer.name] = proxy; + } + return memo; + }, []); + Object.defineProperty(ctx, 'targets', {value: proxies}); + if (proxies.length == 1) { + Object.defineProperty(ctx, 'target', {value: proxies[0]}); + } } // Add global functions and data to the expression context // (e.g. functions imported via the -require command) diff --git a/test/run-test.mjs b/test/run-test.mjs index 0621dea4..d9563258 100644 --- a/test/run-test.mjs +++ b/test/run-test.mjs @@ -57,6 +57,23 @@ describe('mapshaper-run.js', function () { assert.deepEqual(JSON.parse(out['selection.json']), [{foo: 'bam'}]) }) + it('supports targets getter for multiple targets', async function() { + var a = { + type: 'LineString', + coordinates: [[0, 0], [1, 1]] + }; + var b = { + type: 'LineString', + coordinates: [[0, 0], [2, 2]] + }; + // test that targets can be referenced by name in a run expression + var cmd = `-i a.json b.json combine-files + -run '-merge-layers name={targets.a.layer_name + targets.b.layer_name}' + -o`; + var out = await api.applyCommands(cmd, {'a.json': a, 'b.json': b}); + assert(!!out['ab.json']); + }); + it('supports io.ifile() alias', async function() { var data = [{foo: 'bar'}, {foo: 'baz'}, {foo: 'bam'}]; var include = '{ \