| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 | 
							- #!/usr/bin/env node
 
- var fs = require("fs"),
 
-     vm = require("vm"),
 
-     commander = require("commander"),
 
-     topojson = require("../");
 
- commander
 
-     .version(require("../package.json").version)
 
-     .usage("[options] <target=source> [file]")
 
-     .description("Merges the source TopoJSON geometry collection, assigning to the target.")
 
-     .option("-o, --out <file>", "output topology file name; defaults to “-” for stdout", "-")
 
-     .option("-k, --key <expression>", "group geometries by key")
 
-     .option("-f, --filter <expression>", "filter merged geometries or meshed lines")
 
-     .option("--mesh", "mesh lines instead of merging polygons")
 
-     .parse(process.argv);
 
- if (commander.args.length < 1) {
 
-   console.error();
 
-   console.error("  error: missing source and target names");
 
-   console.error();
 
-   process.exit(1);
 
- } else if (commander.args.length > 2) {
 
-   console.error();
 
-   console.error("  error: multiple input files");
 
-   console.error();
 
-   process.exit(1);
 
- } else if (commander.args.length === 1) {
 
-   commander.args.push("-");
 
- }
 
- var keyFunction = function() {},
 
-     postfilterFunction = function() { return true; },
 
-     prefilterFunction = function() { return true; };
 
- if (commander.key != null) {
 
-   var keySandbox = {d: undefined, i: -1},
 
-       keyContext = new vm.createContext(keySandbox),
 
-       keyScript = new vm.Script("(" + commander.key + ")");
 
-   keyFunction = function(d, i) {
 
-     keySandbox.d = d;
 
-     keySandbox.i = i;
 
-     return keyScript.runInContext(keyContext);
 
-   };
 
- }
 
- if (commander.filter != null) {
 
-   if (commander.mesh) {
 
-     var filterSandbox = {a: undefined, b: undefined},
 
-         filterContext = new vm.createContext(filterSandbox),
 
-         filterScript = new vm.Script("(" + commander.filter + ")");
 
-     postfilterFunction = function(a, b) {
 
-       filterSandbox.a = a;
 
-       filterSandbox.b = b;
 
-       return filterScript.runInContext(filterContext);
 
-     };
 
-   } else {
 
-     var filterSandbox = {d: undefined, i: -1},
 
-         filterContext = new vm.createContext(filterSandbox),
 
-         filterScript = new vm.Script("(" + commander.filter + ")");
 
-     prefilterFunction = function(d, i) {
 
-       filterSandbox.d = d;
 
-       filterSandbox.i = i;
 
-       return filterScript.runInContext(filterContext);
 
-     };
 
-   }
 
- }
 
- read(commander.args[1]).then(merge).then(write(commander.out)).catch(abort);
 
- function read(file) {
 
-   return new Promise(function(resolve, reject) {
 
-     var data = [], stream = file === "-" ? process.stdin : fs.createReadStream(file);
 
-     stream
 
-         .on("data", function(d) { data.push(d); })
 
-         .on("end", function() { resolve(JSON.parse(Buffer.concat(data))); })
 
-         .on("error", reject);
 
-   });
 
- }
 
- function merge(topology) {
 
-   var name = commander.args[0], i = name.indexOf("="),
 
-       sourceName = i >= 0 ? name.slice(i + 1) : name,
 
-       targetName = i >= 0 ? name.slice(0, i) : name,
 
-       source = topology.objects[sourceName],
 
-       target = topology.objects[targetName] = {type: "GeometryCollection", geometries: []},
 
-       geometries = target.geometries,
 
-       geometriesByKey = {},
 
-       k;
 
-   if (!source) {
 
-     console.error();
 
-     console.error("  error: source object “" + name + "” not found");
 
-     console.error();
 
-     process.exit(1);
 
-   }
 
-   if (source.type !== "GeometryCollection") {
 
-     console.error();
 
-     console.error("  error: expected GeometryCollection, not " + source.type);
 
-     console.error();
 
-     process.exit(1);
 
-   }
 
-   source.geometries.forEach(function(geometry, i) {
 
-     if (!prefilterFunction(geometry, i)) return;
 
-     var k = stringify(keyFunction(geometry, i)), v;
 
-     if (v = geometriesByKey[k]) v.push(geometry);
 
-     else geometriesByKey[k] = v = [geometry];
 
-   });
 
-   if (commander.mesh) {
 
-     for (k in geometriesByKey) {
 
-       var v = geometriesByKey[k],
 
-           o = topojson.meshArcs(topology, {type: "GeometryCollection", geometries: v}, postfilterFunction);
 
-       o.id = k.length > 1 ? k.slice(1) : undefined;
 
-       o.properties = properties(v);
 
-       geometries.push(o);
 
-     }
 
-   } else {
 
-     for (k in geometriesByKey) {
 
-       var v = geometriesByKey[k],
 
-           o = topojson.mergeArcs(topology, v);
 
-       o.id = k.length > 1 ? k.slice(1) : undefined;
 
-       o.properties = properties(v);
 
-       geometries.push(o);
 
-     }
 
-   }
 
-   return topology;
 
- }
 
- function stringify(key) {
 
-   return key == null ? "$" : "$" + key;
 
- }
 
- function properties(objects) {
 
-   var properties = undefined, hasProperties;
 
-   objects.forEach(function(object) {
 
-     var newProperties = object.properties, key;
 
-     // If no properties have yet been merged,
 
-     // then we need to initialize the merged properties object.
 
-     if (properties === undefined) {
 
-       // If the first set of properties is null, undefined or empty,
 
-       // then the result of the merge will be the empty set.
 
-       // Otherwise, the new properties can copied into the merged object.
 
-       if (newProperties != null) for (key in newProperties) {
 
-         properties = {};
 
-         for (key in newProperties) properties[key] = newProperties[key];
 
-         return;
 
-       }
 
-       properties = null;
 
-       return;
 
-     }
 
-     // If any of the new properties are null or undefined,
 
-     // then the result of the merge will be the empty set.
 
-     if (newProperties == null) properties = null;
 
-     if (properties === null) return;
 
-     // Now mark as inconsistent any of the properties
 
-     // that differ from previously-merged values.
 
-     for (key in newProperties) {
 
-       if ((key in properties) && !is(properties[key], newProperties[key])) {
 
-         properties[key] = undefined;
 
-       }
 
-     }
 
-     // And mark as inconsistent any of the properties
 
-     // that are missing from this new set of merged values.
 
-     for (key in properties) {
 
-       if (!(key in newProperties)) {
 
-         properties[key] = undefined;
 
-       }
 
-     }
 
-     return object;
 
-   });
 
-   // Return undefined if there are no properties.
 
-   for (var key in properties) {
 
-     if (properties[key] !== undefined) {
 
-       return properties;
 
-     }
 
-   }
 
- };
 
- function write(file) {
 
-   var stream = (file === "-" ? process.stdout : fs.createWriteStream(file)).on("error", handleEpipe);
 
-   return function(topology) {
 
-     return new Promise(function(resolve, reject) {
 
-       stream.on("error", reject)[stream === process.stdout ? "write" : "end"](JSON.stringify(topology) + "\n", function(error) {
 
-         if (error) reject(error);
 
-         else resolve();
 
-       });
 
-     });
 
-   };
 
- }
 
- function handleEpipe(error) {
 
-   if (error.code === "EPIPE" || error.errno === "EPIPE") {
 
-     process.exit(0);
 
-   }
 
- }
 
- function abort(error) {
 
-   console.error(error.stack);
 
- }
 
- function is(x, y) {
 
-   return x === y ? x !== 0 || 1 / x === 1 / y : x !== x && y !== y;
 
- }
 
 
  |