mirror of
https://github.com/sbrl/terrain50-cli.git
synced 2024-11-26 07:33:00 +00:00
Add new analyse-frequencies subcommand
This commit is contained in:
parent
0ffbfc42bd
commit
460e2bc1aa
6 changed files with 129 additions and 4 deletions
|
@ -13,9 +13,15 @@ npm install --save terrain50-cli
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
## v1.5
|
||||||
|
- Update dependencies
|
||||||
|
- Add new `analyse-frequencies` subcommand
|
||||||
|
|
||||||
|
|
||||||
## v1.4.1
|
## v1.4.1
|
||||||
- `validate` subcommand in `stream` mode: Write aggregated stats when validation is complete
|
- `validate` subcommand in `stream` mode: Write aggregated stats when validation is complete
|
||||||
|
|
||||||
|
|
||||||
## v1.4
|
## v1.4
|
||||||
- [BREAKING] Add new `--use-regex` flag to `validate` subcommand (only takes effect in stream mode: `--mode stream`)
|
- [BREAKING] Add new `--use-regex` flag to `validate` subcommand (only takes effect in stream mode: `--mode stream`)
|
||||||
|
|
||||||
|
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -338,9 +338,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"terrain50": {
|
"terrain50": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/terrain50/-/terrain50-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/terrain50/-/terrain50-1.8.1.tgz",
|
||||||
"integrity": "sha512-G6wJw0ysZMet0KCqOZr9Cr0OWTjXn00BpZy0SVMfgIE/GiDTeFbCt2EeHANBwKwc93ItLxGua4nWI+5v42jHmw==",
|
"integrity": "sha512-bPAOCOcDHgHoLf2Y7uvk09kDZBRKSkIjBNH5kLzufjzaimxaWVJiALegO9RYw5sHRlU+nzbPZ/0trdJjSs/CRQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"nexline": "^1.2.1",
|
"nexline": "^1.2.1",
|
||||||
"nnng": "^1.0.0"
|
"nnng": "^1.0.0"
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
"chroma-js": "^2.1.0",
|
"chroma-js": "^2.1.0",
|
||||||
"image-encode": "^1.3.0",
|
"image-encode": "^1.3.0",
|
||||||
"nexline": "^1.2.1",
|
"nexline": "^1.2.1",
|
||||||
"terrain50": "^1.8.0"
|
"terrain50": "^1.8.1"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"terrain50": "./src/index.mjs"
|
"terrain50": "./src/index.mjs"
|
||||||
|
|
50
src/Helpers/StreamHelpers.mjs
Normal file
50
src/Helpers/StreamHelpers.mjs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes data to a stream, automatically waiting for the drain event if asked.
|
||||||
|
* See also write_safe.
|
||||||
|
* @param {stream.Writable} stream_out The writable stream to write to.
|
||||||
|
* @param {string|Buffer|Uint8Array} data The data to write.
|
||||||
|
* @return {Promise} A promise that resolves when writing is complete.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function write_safe(stream_out, data) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
// Handle errors
|
||||||
|
let handler_error = (error) => {
|
||||||
|
stream_out.off("error", handler_error);
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
stream_out.on("error", handler_error);
|
||||||
|
|
||||||
|
if(typeof data == "string" ? stream_out.write(data, "utf-8") : stream_out.write(data)) {
|
||||||
|
// We're good to go
|
||||||
|
stream_out.off("error", handler_error);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// We need to wait for the drain event before continuing
|
||||||
|
stream_out.once("drain", () => {
|
||||||
|
stream_out.off("error", handler_error);
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for the given stream to end and finish writing data.
|
||||||
|
* NOTE: This function is not tested and guaranteed yet. (ref #10 the HydroIndexWriter bug)
|
||||||
|
* @param {stream.Writable} stream The stream to end.
|
||||||
|
* @param {Buffer|string} [chunk=undefined] Optional. A chunk to write when calling .end().
|
||||||
|
* @return {Promise} A Promise that resolves when writing is complete.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function end_safe(stream, chunk = undefined) {
|
||||||
|
return new Promise((resolve, _reject) => {
|
||||||
|
if(typeof chunk == "undefined") stream.end(resolve);
|
||||||
|
else stream.end(chunk, resolve);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { write_safe, end_safe };
|
50
src/Subcommands/analyse-frequencies/index.mjs
Normal file
50
src/Subcommands/analyse-frequencies/index.mjs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
|
import Terrain50 from 'terrain50';
|
||||||
|
|
||||||
|
import a from '../../Helpers/Ansi.mjs';
|
||||||
|
import l from '../../Helpers/Log.mjs';
|
||||||
|
|
||||||
|
import { percentage } from '../../Helpers/MathsHelpers.mjs';
|
||||||
|
import { write_safe, end_safe } from '../../Helpers/StreamHelpers.mjs';
|
||||||
|
|
||||||
|
export default async function(settings) {
|
||||||
|
// 1: Parse settings
|
||||||
|
let stream_in = process.stdin;
|
||||||
|
if(settings.cli.input !== "-") {
|
||||||
|
l.log(`Reading from ${a.hicol}${settings.cli.input}${a.reset}`);
|
||||||
|
stream_in = fs.createReadStream(settings.cli.input);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
l.log(`Reading from stdin`);
|
||||||
|
|
||||||
|
let stream_out = process.stdout;
|
||||||
|
if(settings.cli.output !== "-") {
|
||||||
|
l.log(`Writing to ${a.hicol}${settings.cli.output}${a.reset}`);
|
||||||
|
stream_out = fs.createWriteStream(settings.cli.output);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
l.log(`Writing to stdout`);
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
let result_map = await Terrain50.AnalyseFrequencies(
|
||||||
|
Terrain50.ParseStream(stream_in),
|
||||||
|
settings.cli.ignore_nodata
|
||||||
|
);
|
||||||
|
|
||||||
|
let result_arr = [];
|
||||||
|
for(const [ key, value ] of result_map) {
|
||||||
|
result_arr.push([ key, value ]);
|
||||||
|
}
|
||||||
|
result_arr.sort((a, b) => a[0] - b[0]);
|
||||||
|
|
||||||
|
for(const [ key, value ] of result_arr) {
|
||||||
|
await write_safe(stream_out, `${key} ${value}\n`);
|
||||||
|
}
|
||||||
|
await end_safe(stream_out);
|
||||||
|
|
||||||
|
stream_in.destroy();
|
||||||
|
}
|
19
src/Subcommands/analyse-frequencies/meta.toml
Normal file
19
src/Subcommands/analyse-frequencies/meta.toml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
description = "Count the frequencies of data values. Data values are rounded down before counting."
|
||||||
|
|
||||||
|
[[arguments]]
|
||||||
|
name = "input"
|
||||||
|
description = "The input file to analyse (default: stdin)"
|
||||||
|
default_value = "-"
|
||||||
|
type = "string"
|
||||||
|
|
||||||
|
[[arguments]]
|
||||||
|
name = "output"
|
||||||
|
description = "The output file to write the results to as tab-separated-values (default: stdout)"
|
||||||
|
default_value = "-"
|
||||||
|
type = "string"
|
||||||
|
|
||||||
|
[[arguments]]
|
||||||
|
name = "ignore-nodata"
|
||||||
|
description = "Ignore NODATA values when analysing."
|
||||||
|
default_value = false
|
||||||
|
type = "boolean"
|
Loading…
Reference in a new issue