#!/usr/bin/env node var fs = require("fs"), path = require("path"), readline = require("readline"), commander = require("commander"), topojson = require("../"); commander .version(require("../package.json").version) .usage("[options] <[name=]file>…") .description("Converts GeoJSON features to TopoJSON objects.") .option("-o, --out ", "output file name; defaults to “-” for stdout", "-") .option("-n, --newline-delimited", "accept newline-delimited JSON") .option("-q, --quantization ", "pre-quantization parameter; 0 disables quantization", 0) .parse(process.argv); if (commander.args.length < 1) commander.args[0] = "-"; var nullType = {}, nullObject = {type: nullType}, objects = {}, out = (commander.out === "-" ? process.stdout : fs.createWriteStream(commander.out)).on("error", handleEpipe); Promise.all(commander.args.map(read)).then(write).catch(abort); function read(specifier) { var i = specifier.indexOf("="), file = i >= 0 ? specifier.slice(i + 1) : specifier, name = i >= 0 ? specifier.slice(0, i) : path.basename(specifier, path.extname(specifier)); if (name in objects) { console.error(); console.error(" error: object “" + name + "” is not unique"); console.error(); process.exit(1); } objects[name] = undefined; return (commander.newlineDelimited ? readNewlineDelimitedObject : readObject)(file === "-" ? process.stdin : fs.createReadStream(file)) .then(function(object) { objects[name] = object; }); } function readNewlineDelimitedObject(stream) { return new Promise(function(resolve, reject) { var collection; readline.createInterface({ input: stream, output: null }).on("line", function(line) { var object = JSON.parse(line); if (object == null) object = nullObject; switch (object.type) { case "Feature": { if (collection) { if (collection.type !== "FeatureCollection") { console.error(); console.error(" error: expected geometry, not Feature"); console.error(); process.exit(1); } collection.features.push(object); } else { collection = {type: "FeatureCollection", features: [object]}; } break; } case nullType: case "GeometryCollection": case "MultiLineString": case "LineString": case "Polygon": case "MultiPolygon": case "Point": case "MultiPoint": { if (collection) { if (collection.type !== "GeometryCollection") { console.error(); console.error(" error: expected Feature, not " + object.type); console.error(); process.exit(1); } collection.geometries.push(object); } else { collection = {type: "GeometryCollection", geometries: [object]}; } break; } default: { console.error(); console.error(" error: expected Feature or geometry, not " + object.type); console.error(); process.exit(1); break; } } }).on("close", function() { resolve(collection || {type: "FeatureCollection", features: []}); }).on("error", reject); }); } function readObject(stream) { return new Promise(function(resolve, reject) { var data = []; stream .on("data", function(d) { data.push(d); }) .on("end", function() { resolve(JSON.parse(Buffer.concat(data))); }) .on("error", reject); }); } function write() { out.write(JSON.stringify(topojson.topology(objects, +commander.quantization))); out[out === process.stdout ? "write" : "end"]("\n"); } function handleEpipe(error) { if (error.code === "EPIPE" || error.errno === "EPIPE") { process.exit(0); } } function abort(error) { console.error(error.stack); }