///|
fn main {
println(csvlite_run(csvlite_drop_program_name(@env.args())))
}
///|
fn csvlite_run(args : Array[String]) -> String {
if args.length() == 0 {
return csvlite_help()
}
match args[0] {
"help" | "--help" | "-h" => csvlite_help()
"version" | "--version" => "moon-csv-lite 0.1.0"
"profile" => csvlite_command_profile(args)
"sniff" => csvlite_command_sniff(args)
"schema" => csvlite_command_schema(args)
"score" => csvlite_command_score(args)
"drift" => csvlite_command_drift(args)
"drift-json" => csvlite_command_drift_json(args)
"gate" => csvlite_command_gate(args)
"gate-json" => csvlite_command_gate_json(args)
"infer-contract" => csvlite_command_infer_contract(args)
"contract" => csvlite_command_contract(args)
"contract-json" => csvlite_command_contract_json(args)
"passport" => csvlite_command_passport(args)
"passport-json" => csvlite_command_passport_json(args)
"audit" => csvlite_command_audit(args)
"audit-html" => csvlite_command_audit_html(args)
"audit-json" => csvlite_command_audit_json(args)
"chart-json" => csvlite_command_chart_json(args)
"chart-svg" => csvlite_command_chart_svg(args)
"chart-html" => csvlite_command_chart_html(args)
"check" => csvlite_command_check(args)
"markdown" => csvlite_command_markdown(args)
"jsonl" => csvlite_command_jsonl(args)
"html" => csvlite_command_html(args)
"group-sum" => csvlite_command_group_sum(args)
"select" => csvlite_command_select(args)
"missing" => csvlite_command_missing(args)
other => "Unknown command: " + other + "\n\n" + csvlite_help()
}
}
///|
fn csvlite_help() -> String {
(
#|csvlite - lightweight CSV utilities for MoonBit
#|
#|Usage:
#| csvlite profile
#| csvlite sniff
#| csvlite schema
#| csvlite score
#| csvlite drift
#| csvlite drift-json
#| csvlite gate
#| csvlite gate-json
#| csvlite infer-contract
#| csvlite contract
#| csvlite contract-json
#| csvlite passport [dataset-name]
#| csvlite passport-json [dataset-name]
#| csvlite audit
#| csvlite audit-html
#| csvlite audit-json
#| csvlite chart-json [kind] [label-column] [value-column]
#| csvlite chart-svg [kind] [label-column] [value-column]
#| csvlite chart-html [kind] [label-column] [value-column]
#| csvlite check
#| csvlite markdown
#| csvlite jsonl
#| csvlite html
#| csvlite group-sum
#| csvlite select
#| csvlite missing
#|
#|Notes:
#| Pass \n in CSV text to represent a newline in shell-friendly examples.
)
}
///|
fn csvlite_command_sniff(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.sniff_dialect_summary(input)
None => "Usage: csvlite sniff "
}
}
///|
fn csvlite_command_schema(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.table_schema_markdown(@csv.parse_table_auto(input))
None => "Usage: csvlite schema "
}
}
///|
fn csvlite_command_score(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.audit_quality_score_text(@csv.audit_csv_score(input))
None => "Usage: csvlite score "
}
}
///|
fn csvlite_command_drift(args : Array[String]) -> String {
match csvlite_two_csv_args(args) {
Some((baseline, candidate)) =>
@csv.audit_drift_markdown(baseline, candidate)
None => "Usage: csvlite drift "
}
}
///|
fn csvlite_command_drift_json(args : Array[String]) -> String {
match csvlite_two_csv_args(args) {
Some((baseline, candidate)) => @csv.audit_drift_json(baseline, candidate)
None => "Usage: csvlite drift-json "
}
}
///|
fn csvlite_command_gate(args : Array[String]) -> String {
match csvlite_two_csv_args(args) {
Some((baseline, candidate)) =>
@csv.audit_quality_gate_markdown(baseline, candidate)
None => "Usage: csvlite gate "
}
}
///|
fn csvlite_command_gate_json(args : Array[String]) -> String {
match csvlite_two_csv_args(args) {
Some((baseline, candidate)) =>
@csv.audit_quality_gate_json(baseline, candidate)
None => "Usage: csvlite gate-json "
}
}
///|
fn csvlite_command_infer_contract(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.quality_contract_infer_csv(input)
None => "Usage: csvlite infer-contract "
}
}
///|
fn csvlite_command_contract(args : Array[String]) -> String {
match csvlite_csv_and_contract_args(args) {
Some((input, contract)) =>
@csv.audit_quality_contract_markdown(input, contract)
None => "Usage: csvlite contract "
}
}
///|
fn csvlite_command_contract_json(args : Array[String]) -> String {
match csvlite_csv_and_contract_args(args) {
Some((input, contract)) => @csv.audit_quality_contract_json(input, contract)
None => "Usage: csvlite contract-json "
}
}
///|
fn csvlite_command_passport(args : Array[String]) -> String {
match csvlite_csv_and_name_arg(args) {
Some((input, name)) => @csv.csv_data_passport_markdown(input, name)
None => "Usage: csvlite passport [dataset-name]"
}
}
///|
fn csvlite_command_passport_json(args : Array[String]) -> String {
match csvlite_csv_and_name_arg(args) {
Some((input, name)) => @csv.csv_data_passport_json(input, name)
None => "Usage: csvlite passport-json [dataset-name]"
}
}
///|
fn csvlite_command_audit(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.audit_csv_markdown(input)
None => "Usage: csvlite audit "
}
}
///|
fn csvlite_command_audit_html(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.audit_csv_html(input)
None => "Usage: csvlite audit-html "
}
}
///|
fn csvlite_command_audit_json(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.audit_csv_json(input)
None => "Usage: csvlite audit-json "
}
}
///|
fn csvlite_command_chart_json(args : Array[String]) -> String {
match csvlite_chart_args(args) {
Some((input, kind, label, value)) =>
match (label, value) {
(Some(label_column), Some(value_column)) =>
@csv.chart_csv_json_with_columns(
input, kind, label_column, value_column,
)
_ => @csv.chart_csv_json(input, kind)
}
None =>
"Usage: csvlite chart-json [kind] [label-column] [value-column]"
}
}
///|
fn csvlite_command_chart_svg(args : Array[String]) -> String {
match csvlite_chart_args(args) {
Some((input, kind, label, value)) =>
match (label, value) {
(Some(label_column), Some(value_column)) =>
@csv.chart_csv_svg_with_columns(
input, kind, label_column, value_column,
)
_ => @csv.chart_csv_svg(input, kind)
}
None =>
"Usage: csvlite chart-svg [kind] [label-column] [value-column]"
}
}
///|
fn csvlite_command_chart_html(args : Array[String]) -> String {
match csvlite_chart_args(args) {
Some((input, kind, label, value)) =>
match (label, value) {
(Some(label_column), Some(value_column)) =>
@csv.chart_csv_html_with_columns(
input, kind, label_column, value_column,
)
_ => @csv.chart_csv_html(input, kind)
}
None =>
"Usage: csvlite chart-html [kind] [label-column] [value-column]"
}
}
///|
fn csvlite_command_profile(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.profile_report(@csv.parse_table(input))
None => "Usage: csvlite profile "
}
}
///|
fn csvlite_command_check(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => {
let report = @csv.parse_table_checked(input)
@csv.parse_issues_to_text(report.issues)
}
None => "Usage: csvlite check "
}
}
///|
fn csvlite_command_markdown(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.table_to_markdown(@csv.parse_table(input))
None => "Usage: csvlite markdown "
}
}
///|
fn csvlite_command_jsonl(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.table_to_json_lines(@csv.parse_table(input))
None => "Usage: csvlite jsonl "
}
}
///|
fn csvlite_command_html(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) => @csv.table_to_html(@csv.parse_table(input))
None => "Usage: csvlite html "
}
}
///|
fn csvlite_command_group_sum(args : Array[String]) -> String {
if args.length() < 4 {
return "Usage: csvlite group-sum "
}
let input = csvlite_decode_escapes(args[1])
let grouped = @csv.table_group_sum(@csv.parse_table(input), args[2], args[3])
@csv.table_to_markdown(grouped)
}
///|
fn csvlite_command_select(args : Array[String]) -> String {
if args.length() < 3 {
return "Usage: csvlite select "
}
let input = csvlite_decode_escapes(args[1])
let columns = csvlite_parse_columns(args[2])
@csv.table_to_markdown(
@csv.table_select_columns(@csv.parse_table(input), columns),
)
}
///|
fn csvlite_command_missing(args : Array[String]) -> String {
match csvlite_csv_arg(args) {
Some(input) =>
@csv.table_to_markdown(
@csv.table_missing_summary(@csv.parse_table(input)),
)
None => "Usage: csvlite missing "
}
}
///|
fn csvlite_csv_arg(args : Array[String]) -> String? {
if args.length() < 2 {
None
} else {
Some(csvlite_decode_escapes(args[1]))
}
}
///|
fn csvlite_two_csv_args(args : Array[String]) -> (String, String)? {
if args.length() < 3 {
None
} else {
Some((csvlite_decode_escapes(args[1]), csvlite_decode_escapes(args[2])))
}
}
///|
fn csvlite_csv_and_contract_args(args : Array[String]) -> (String, String)? {
if args.length() < 3 {
None
} else {
Some((csvlite_decode_escapes(args[1]), csvlite_decode_escapes(args[2])))
}
}
///|
fn csvlite_csv_and_name_arg(args : Array[String]) -> (String, String)? {
if args.length() < 2 {
None
} else {
let name = if args.length() >= 3 { args[2] } else { "csv-dataset" }
Some((csvlite_decode_escapes(args[1]), name))
}
}
///|
fn csvlite_chart_args(
args : Array[String],
) -> (String, String, String?, String?)? {
if args.length() < 2 {
None
} else {
let input = csvlite_decode_escapes(args[1])
let kind = if args.length() >= 3 { args[2] } else { "bar" }
let label = if args.length() >= 4 { Some(args[3]) } else { None }
let value = if args.length() >= 5 { Some(args[4]) } else { None }
Some((input, kind, label, value))
}
}
///|
fn csvlite_parse_columns(columns : String) -> Array[String] {
let parsed = @csv.parse(columns)
if parsed.length() == 0 {
[]
} else {
parsed[0]
}
}
///|
fn csvlite_decode_escapes(input : String) -> String {
let out = StringBuilder()
let mut escaping = false
for ch in input.iter() {
if escaping {
if ch == 'n' {
out.write_char('\n')
} else if ch == 'r' {
out.write_char('\r')
} else if ch == 't' {
out.write_char('\t')
} else {
out.write_char(ch)
}
escaping = false
} else if ch == '\\' {
escaping = true
} else {
out.write_char(ch)
}
}
if escaping {
out.write_char('\\')
}
out.to_string()
}
///|
fn csvlite_drop_program_name(args : Array[String]) -> Array[String] {
let result : Array[String] = Array::new()
if args.length() <= 1 {
return result
}
for i in 1..