Finished migration to commander.js, updated table rendering engine to use code blocks for resource Guids.
All checks were successful
build / build (push) Successful in 8s
All checks were successful
build / build (push) Successful in 8s
This commit is contained in:
@@ -2,26 +2,41 @@
|
||||
|
||||
The `sk-tools` package provides generic CLI utilities not tied to a specific cloud provider.
|
||||
|
||||
## Global Options
|
||||
|
||||
These options apply to all commands unless stated otherwise:
|
||||
|
||||
- `--query`, `-q` <jmespath> - Apply JMESPath filter before output rendering.
|
||||
- `--output`, `-o` <format> - Output format: `table|t|alignedtable|at|prettytable|pt|tsv`.
|
||||
- `--columns`, `-C` <definition> - Column selection for table outputs:
|
||||
- `col1` - Select column (case-insensitive match), keep raw header label.
|
||||
- `col1:` - Select column (case-insensitive match), use auto-generated header label.
|
||||
- `col1: Label 1` - Select column (case-insensitive match), use custom header label.
|
||||
- Prefix token with `=` for exact column-name match: `=col1`, `=col1:`, `=col1:Label`.
|
||||
- Tokens are comma-separated and rendered in the specified order.
|
||||
- `--help`, `-h` - Show help.
|
||||
|
||||
## Table
|
||||
|
||||
**Command name:** `table`
|
||||
**Command name:** `table` (alias: `t`)
|
||||
|
||||
**Usage:** `sk-tools table [--from|-F <json|csv|tsv>] [--columns|-C <definition>] [global options]`
|
||||
|
||||
**Options:**
|
||||
|
||||
- `--from`, `-F` <json|csv|tsv> - Input format read from stdin. Default: `json`.
|
||||
- `--columns`, `-C` <definition> - Column definition. Possible values:
|
||||
- `col1` - Select column (case-insensitive match), keep raw header label.
|
||||
- `col1:` - Select column (case-insensitive match), use auto-generated header label.
|
||||
- `col1: Label 1` - Select column (case-insensitive match), use custom header label.
|
||||
- Prefix token with `=` for exact column-name match: `=col1`, `=col1:`, `=col1:Label`.
|
||||
- Tokens are comma-separated and rendered in the specified order.
|
||||
|
||||
**Global options:**
|
||||
|
||||
- `--query`, `-q` <jmespath> - JMESPath filter applied before rendering.
|
||||
- `--output`, `-o` <format> - Output format: `table|t|alignedtable|at|prettytable|pt|tsv`.
|
||||
- `--help`, `-h` - Show help.
|
||||
- `--columns`, `-C` <definition> - Column definition (see global options).
|
||||
|
||||
**Description:** The `table` command transforms stdin data into tabular output. It accepts JSON, CSV, or TSV input and renders either Markdown table variants or TSV output.
|
||||
|
||||
## Table Info
|
||||
|
||||
**Command name:** `table-info` (alias: `ti`)
|
||||
|
||||
**Usage:** `sk-tools table-info [--from|-F <json|csv|tsv>]`
|
||||
|
||||
**Options:**
|
||||
|
||||
- `--from`, `-F` <json|csv|tsv> - Input format read from stdin. Default: `json`.
|
||||
|
||||
**Description:** The `table-info` command reads stdin data and prints basic diagnostics: number of rows, number of columns, and inferred type for each column.
|
||||
|
||||
18
package-lock.json
generated
18
package-lock.json
generated
@@ -9,6 +9,7 @@
|
||||
"version": "0.3.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^14.0.3",
|
||||
"d3-dsv": "^3.0.1",
|
||||
"jmespath": "^0.16.0",
|
||||
"semver": "^7.7.4",
|
||||
@@ -52,12 +53,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
|
||||
"version": "14.0.3",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz",
|
||||
"integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-dsv": {
|
||||
@@ -85,6 +86,15 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-dsv/node_modules/commander": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
|
||||
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@slawek/sk-tools",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"type": "module",
|
||||
"files": [
|
||||
"dist",
|
||||
@@ -17,6 +17,7 @@
|
||||
},
|
||||
"description": "A set of generic NodeJS utilities shared by Slawek tools.",
|
||||
"dependencies": {
|
||||
"commander": "^14.0.3",
|
||||
"d3-dsv": "^3.0.1",
|
||||
"jmespath": "^0.16.0",
|
||||
"semver": "^7.7.4",
|
||||
|
||||
@@ -36,8 +36,9 @@ const program = new Command();
|
||||
program
|
||||
.name('bump-patch')
|
||||
.description('Bump the version in package.json')
|
||||
.addOption(new Option('-r, --release-type <type>', 'Release type (major, minor, patch)', 'patch')
|
||||
.choices('release-type', ['major', 'minor', 'patch'])
|
||||
.addOption(new Option('-r, --release-type <type>', 'Release type (major, minor, patch)')
|
||||
.choices(['major', 'minor', 'patch'])
|
||||
.default('patch')
|
||||
)
|
||||
.parse(process.argv);
|
||||
|
||||
|
||||
115
src/cli.ts
115
src/cli.ts
@@ -1,98 +1,53 @@
|
||||
#!/usr/bin/env node
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { parseArgs } from "node:util";
|
||||
import { Command, Option } from "commander";
|
||||
|
||||
import { runCommand } from "./cli/commands.ts";
|
||||
import { usageTableInfo } from "./cli/commands/table-info.ts";
|
||||
import { usageTable } from "./cli/commands/table.ts";
|
||||
import { runTableInfoCommand } from "./cli/commands/table-info.ts";
|
||||
import { runTableCommand } from "./cli/commands/table.ts";
|
||||
import { renderCliOutput } from "./cli/utils.ts";
|
||||
|
||||
type CliValues = {
|
||||
help?: boolean;
|
||||
from?: string;
|
||||
query?: string;
|
||||
columns?: string;
|
||||
output?: string;
|
||||
[key: string]: string | boolean | undefined;
|
||||
};
|
||||
|
||||
function usage(): string {
|
||||
return `Usage: sk-tools <command> [options]
|
||||
|
||||
Commands:
|
||||
table, t Render stdin data as Markdown table
|
||||
table-info, ti Print row/column stats and inferred column types
|
||||
|
||||
Global options (all commands):
|
||||
--query, -q <jmespath>
|
||||
--output, -o <format> table|t|alignedtable|at|prettytable|pt|tsv
|
||||
--help, -h
|
||||
|
||||
Use: sk-tools --help <command>
|
||||
or: sk-tools <command> --help`;
|
||||
}
|
||||
|
||||
function usageCommand(command: string): string {
|
||||
switch (command) {
|
||||
case "table":
|
||||
case "t":
|
||||
return usageTable();
|
||||
case "table-info":
|
||||
case "ti":
|
||||
return usageTableInfo();
|
||||
default:
|
||||
return `Unknown command: ${command}\n\n${usage()}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const argv = process.argv.slice(2);
|
||||
const command = argv[0];
|
||||
const skTools = new Command();
|
||||
|
||||
if (!command) {
|
||||
console.log(usage());
|
||||
process.exit(0);
|
||||
}
|
||||
skTools
|
||||
.name("sk-tools")
|
||||
.description("A set of generic NodeJS utilities shared by Slawek tools.")
|
||||
.option("-q, --query <jmespath>", "JMESPath query to filter output")
|
||||
.option("-C, --columns <definition>", "Column tokens: col (raw), col: (auto), col:Label (custom), exact via = prefix")
|
||||
.addOption(new Option("-o, --output <format>", "Output format: table|t|alignedtable|at|prettytable|pt|tsv")
|
||||
.choices(["table", "t", "alignedtable", "at", "prettytable", "pt", "tsv"]));
|
||||
|
||||
if (command === "-h" || command === "--help") {
|
||||
const helpCommand = argv[1];
|
||||
console.log(helpCommand ? usageCommand(helpCommand) : usage());
|
||||
process.exit(0);
|
||||
}
|
||||
skTools
|
||||
.command("table")
|
||||
.alias("t")
|
||||
.description("Render stdin data as Markdown table")
|
||||
.addOption(new Option("-F, --from <json|csv|tsv>", "Input format on stdin")
|
||||
.choices(["json", "csv", "tsv"])
|
||||
.default("json"))
|
||||
.action(async (options, command) => {
|
||||
const allOptions = command.optsWithGlobals();
|
||||
const output = await runTableCommand(options);
|
||||
renderCliOutput(output, allOptions.output ?? "alignedtable", allOptions.query, allOptions.columns);
|
||||
});
|
||||
|
||||
const { values } = parseArgs({
|
||||
args: argv.slice(1),
|
||||
options: {
|
||||
help: { type: "boolean", short: "h" },
|
||||
from: { type: "string", short: "F" },
|
||||
query: { type: "string", short: "q" },
|
||||
columns: { type: "string", short: "C" },
|
||||
output: { type: "string", short: "o" },
|
||||
},
|
||||
strict: true,
|
||||
allowPositionals: false,
|
||||
});
|
||||
skTools
|
||||
.command("table-info")
|
||||
.alias("ti")
|
||||
.description("Print row/column stats and inferred column types")
|
||||
.addOption(new Option("-F, --from <json|csv|tsv>", "Input format on stdin")
|
||||
.choices(["json", "csv", "tsv"])
|
||||
.default("json"))
|
||||
.action(async (options) => {
|
||||
const output = await runTableInfoCommand(options);
|
||||
console.log(output);
|
||||
});
|
||||
|
||||
const typedValues = values as CliValues;
|
||||
|
||||
if (typedValues.help) {
|
||||
console.log(usageCommand(command));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const output = await runCommand(command, typedValues);
|
||||
if (typeof output === "string") {
|
||||
console.log(output);
|
||||
return;
|
||||
}
|
||||
|
||||
renderCliOutput(output, typedValues.output, typedValues.query, typedValues.columns);
|
||||
await skTools.parseAsync(process.argv);
|
||||
}
|
||||
|
||||
main().catch((err: unknown) => {
|
||||
const error = err as Error;
|
||||
console.error(`Error: ${error.message}`);
|
||||
console.error(usage());
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { runTableCommand } from "./commands/table.ts";
|
||||
import { runTableInfoCommand } from "./commands/table-info.ts";
|
||||
|
||||
type CommandValues = {
|
||||
[key: string]: string | boolean | undefined;
|
||||
};
|
||||
|
||||
export async function runCommand(command: string, values: CommandValues): Promise<unknown> {
|
||||
switch (command) {
|
||||
case "table":
|
||||
case "t":
|
||||
return runTableCommand(values);
|
||||
case "table-info":
|
||||
case "ti":
|
||||
return runTableInfoCommand(values);
|
||||
default:
|
||||
throw new Error(`Unknown command: ${command}`);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
|
||||
type TableInfoCommandValues = {
|
||||
from?: string;
|
||||
[key: string]: string | boolean | undefined;
|
||||
};
|
||||
|
||||
type RowObject = Record<string, unknown>;
|
||||
@@ -102,13 +101,6 @@ function buildInfo(input: unknown): string {
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
export function usageTableInfo(): string {
|
||||
return `Usage: sk-tools table-info [--from|-F <json|csv|tsv>]
|
||||
|
||||
Options:
|
||||
--from, -F <json|csv|tsv> Input format on stdin (default: json)`;
|
||||
}
|
||||
|
||||
export async function runTableInfoCommand(values: TableInfoCommandValues): Promise<string> {
|
||||
const from = (values.from ?? "json").toString().trim().toLowerCase();
|
||||
|
||||
|
||||
@@ -7,17 +7,8 @@ import {
|
||||
|
||||
type TableCommandValues = {
|
||||
from?: string;
|
||||
[key: string]: string | boolean | undefined;
|
||||
};
|
||||
|
||||
export function usageTable(): string {
|
||||
return `Usage: sk-tools table [--from|-F <json|csv|tsv>] [--columns|-C <columns>] [global options]
|
||||
|
||||
Options:
|
||||
--from, -F <json|csv|tsv> Input format on stdin (default: json)
|
||||
--columns, -C <value> Column tokens: col (raw), col: (auto), col:Label (custom), with exact match via = prefix (e.g. =col:)`;
|
||||
}
|
||||
|
||||
export async function runTableCommand(values: TableCommandValues): Promise<unknown> {
|
||||
const from = (values.from ?? "json").toString().trim().toLowerCase();
|
||||
|
||||
|
||||
@@ -27,6 +27,14 @@ function formatCell(value: unknown): string {
|
||||
|
||||
const inlineCodePredicates = [
|
||||
(value: Scalar): boolean => typeof value === "string" && validateUuid(value),
|
||||
(value: Scalar): boolean => {
|
||||
if (typeof value !== "string" || !value.toLowerCase().startsWith("/subscriptions/")) {
|
||||
return false;
|
||||
}
|
||||
const rest = value.slice("/subscriptions/".length);
|
||||
const subscriptionId = rest.split("/", 1)[0];
|
||||
return validateUuid(subscriptionId);
|
||||
},
|
||||
(value: Scalar): boolean =>
|
||||
typeof value === "string"
|
||||
&& /^(?:\d{1,3}\.){3}\d{1,3}(?:\/(?:\d{1,2}|(?:\d{1,3}\.){3}\d{1,3}))?$/.test(value),
|
||||
|
||||
Reference in New Issue
Block a user