UNPKG

ogr2ogr

Version:

ogr2ogr wrapper w/ multiple format support

156 lines (155 loc) 4.31 kB
// index.ts import archiver from "archiver"; import { execFile } from "child_process"; import { createReadStream } from "fs"; import { tmpdir } from "os"; import { extname, join } from "path"; import { Readable } from "stream"; var stdoutRe = /csv|geojson|georss|gml|gmt|gpx|jml|kml|mapml|pdf|vdv/i; var vsiStdIn = "/vsistdin/"; var vsiStdOut = "/vsistdout/"; var uniq = Date.now(); var Ogr2ogr = class { inputStream; inputPath; outputPath; outputFormat; outputExt; customCommand; customOptions; customDestination; customEnv; timeout; maxBuffer; skipFailures; constructor(input, opts = {}) { this.inputPath = opts.inputFormat ? opts.inputFormat + ":" + vsiStdIn : vsiStdIn; this.outputFormat = opts.format ?? "GeoJSON"; this.customCommand = opts.command; this.customOptions = opts.options; this.customDestination = opts.destination; this.customEnv = opts.env; this.timeout = opts.timeout ?? 0; this.maxBuffer = opts.maxBuffer ?? 1024 * 1024 * 50; this.skipFailures = opts.skipFailures ?? true; let { path, ext } = this.newOutputPath(this.outputFormat); this.outputPath = path; this.outputExt = ext; if (input instanceof Readable) { this.inputStream = input; } else if (typeof input === "string") { this.inputPath = this.newInputPath(input); } else { this.inputStream = Readable.from([JSON.stringify(input)]); } } exec(cb) { this.run().then((res) => cb(null, res)).catch((err) => cb(err)); } then(onfulfilled, onrejected) { return this.run().then(onfulfilled, onrejected); } newInputPath(p) { let path = ""; let ext = extname(p); switch (ext) { case ".zip": path = "/vsizip/"; break; case ".gz": path = "/vsigzip/"; break; case ".tar": path = "/vsitar/"; break; } if (/^(http|ftp)/.test(p)) { path += "/vsicurl/" + p; return path; } path += p; return path; } newOutputPath(f) { let ext = "." + f.toLowerCase(); if (stdoutRe.test(this.outputFormat)) { return { path: vsiStdOut, ext }; } let path = join(tmpdir(), "/ogr_" + uniq++); switch (f.toLowerCase()) { case "esri shapefile": path += ".shz"; ext = ".shz"; break; case "mapinfo file": case "flatgeobuf": ext = ".zip"; break; default: path += ext; } return { path, ext }; } createZipStream(p) { let archive = archiver("zip"); archive.directory(p, false); archive.on("error", console.error); archive.finalize(); return archive; } async run() { let command = this.customCommand ?? "ogr2ogr"; let args = ["-f", this.outputFormat]; if (this.skipFailures) args.push("-skipfailures"); args.push(this.customDestination || this.outputPath, this.inputPath); if (this.customOptions) args.push(...this.customOptions); let env = this.customEnv ? { ...process.env, ...this.customEnv } : void 0; let { stdout, stderr } = await new Promise((res2, rej) => { let proc = execFile( command, args, { env, timeout: this.timeout, maxBuffer: this.maxBuffer }, (err, stdout2, stderr2) => { if (err) rej(err); res2({ stdout: stdout2, stderr: stderr2 }); } ); if (this.inputStream && proc.stdin) this.inputStream.pipe(proc.stdin); }); let res = { cmd: [command, ...args].join(" "), text: stdout, details: stderr, extname: this.outputExt }; if (/^geojson$/i.test(this.outputFormat)) { try { res.data = JSON.parse(stdout); } catch (_err) { } } if (!this.customDestination && this.outputPath !== vsiStdOut) { if (this.outputExt === ".zip") { res.stream = this.createZipStream(this.outputPath); } else { res.stream = createReadStream(this.outputPath); } } return res; } }; function ogr2ogr(input, opts) { return new Ogr2ogr(input, opts); } ogr2ogr.version = async () => { let vers = await new Promise((res, rej) => { execFile("ogr2ogr", ["--version"], {}, (err, stdout) => { if (err) rej(err); res(stdout); }); }); return vers.trim(); }; export { ogr2ogr };