topo2geo 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. #!/usr/bin/env node
  2. var fs = require("fs"),
  3. path = require("path"),
  4. commander = require("commander"),
  5. topojson = require("../");
  6. commander
  7. .version(require("../package.json").version)
  8. .usage("[options] <name=file>…")
  9. .description("Converts TopoJSON objects to GeoJSON features.")
  10. .option("-i, --in <file>", "input topology file name; defaults to “-” for stdin", "-")
  11. .option("-l, --list", "list the object names on the input topology")
  12. .option("-n, --newline-delimited", "output newline-delimited JSON")
  13. .parse(process.argv);
  14. if (!commander.list === commander.args.length < 1) {
  15. console.error();
  16. console.error(" error: " + (commander.list ? "--list does not take arguments" : "no arguments specified"));
  17. console.error();
  18. process.exit(1);
  19. }
  20. read(commander.in).then(write).catch(abort);
  21. function read(file) {
  22. return new Promise(function(resolve, reject) {
  23. var data = [];
  24. readStream(file)
  25. .on("data", function(d) { data.push(d); })
  26. .on("end", function() { resolve(JSON.parse(Buffer.concat(data))); })
  27. .on("error", reject);
  28. });
  29. }
  30. function readStream(file) {
  31. return file === "-" ? process.stdin : fs.createReadStream(file);
  32. }
  33. function write(topology) {
  34. var write, writer = commander.newlineDelimited ? writeNewlineDelimitedFeature : writeFeature, name;
  35. if (commander.list) {
  36. for (name in topology.objects) {
  37. console.log(name);
  38. }
  39. return;
  40. }
  41. write = Promise.resolve();
  42. commander.args.forEach(function(specifier) {
  43. var i = specifier.indexOf("="),
  44. file = i >= 0 ? specifier.slice(i + 1) : specifier,
  45. name = i >= 0 ? specifier.slice(0, i) : path.basename(specifier, path.extname(specifier));
  46. if (!(name in topology.objects)) {
  47. console.error();
  48. console.error(" error: object “" + name + "” not found");
  49. console.error();
  50. process.exit(1);
  51. }
  52. write = write.then(writer(file, topojson.feature(topology, topology.objects[name])));
  53. });
  54. return write;
  55. }
  56. function writeStream(file) {
  57. return (file === "-" ? process.stdout : fs.createWriteStream(file)).on("error", handleEpipe);
  58. }
  59. function writeFeature(file, feature) {
  60. return new Promise(function(resolve, reject) {
  61. writeStream(file).on("error", reject)[file === "-" ? "write" : "end"](JSON.stringify(feature) + "\n", function(error) {
  62. if (error) reject(error);
  63. else resolve();
  64. });
  65. });
  66. }
  67. function writeNewlineDelimitedFeature(file, feature) {
  68. return feature == null || feature.type != "FeatureCollection" ? writeFeature(file, feature) : new Promise(function(resolve, reject) {
  69. var stream = writeStream(file).on("error", reject), i = -1, n = feature.features.length;
  70. (function writeNext(error) {
  71. if (error) return void reject(error);
  72. if (++i >= n) {
  73. if (file !== "-") stream.end(writeEnd);
  74. else writeEnd();
  75. } else {
  76. stream.write(JSON.stringify(feature.features[i]) + "\n", writeNext);
  77. }
  78. })(null);
  79. function writeEnd(error) {
  80. if (error) return void reject(error);
  81. resolve();
  82. }
  83. });
  84. }
  85. function handleEpipe(error) {
  86. if (error.code === "EPIPE" || error.errno === "EPIPE") {
  87. process.exit(0);
  88. }
  89. }
  90. function abort(error) {
  91. console.error(error.stack);
  92. }