Early preview: syntax, standard library APIs, and tooling may change.

Working ProgramsJSON and CSV

JSON and CSV

Use format modules to parse data, inspect it, validate it, and encode output.

Parse

json.parse_json and csv.parse_csv turn text into structured values.

parsed: Result[JsonValue, String] = parse_json(text)

Inspect

JSON accessors return Option so missing fields stay explicit.

name: Option[String] = value
	.get_field("name")
	.and_then(func(v): v.as_string())

Validate

A pure field decoder returns Result[String, String]. Missing name and a wrong field type are different failures; an explicitly empty string is still a string.

import:
	json: JsonValue, as_string, get_field, parse_json


pure func user_name(value: JsonValue) -> Result[String, String]:
	field ?= value.get_field("name").to_result("missing name")
	field.as_string().to_result("expected a string")


func main(args: List[String]) -> Int:
	text: String = args.get(1).get_or("{\"name\":\"Ada\"}")
	result: Result[String, String] = parse_json(text).and_then(user_name)
	match result:
		Ok(name):
			print(name) -- default output: Ada
			0
		Err(message):
			print_error(message) -- {}: missing name; {"name":42}: expected a string
			1

Encode

CSV rows can be formatted back into text.

csv_text: String = format_csv([["name"], ["Ada"]])

Example

Require a JSON array and a string name on every user. Reject the whole conversion on the first invalid user, print the error to stderr, and exit with status 1 -- never silently substitute a blank field. An empty array produces just the header. The optional first argument supplies JSON; otherwise the built-in Ada example is used.

users-csv.brp
import:
	csv: format_csv
	json: JsonValue(JsonVector), as_string, get_field, parse_json


pure func user_name(value: JsonValue) -> Result[String, String]:
	field ?= value.get_field("name").to_result("missing name")
	field.as_string().to_result("expected a string")


-- Reject the entire input on the first invalid user; never invent a blank name.
pure func users_csv(text: String) -> Result[String, String]:
	match parse_json(text):
		Ok(JsonVector(users)):
			var rows: Result[List[List[String]], String] = Ok([["name"]])
			for user in users:
				match rows:
					Ok(validated):
						rows = match user_name(user):
							Ok(name): Ok(validated.append([name]))
							Err(message): Err(message)
					Err(_): break
			rows.map(format_csv)
		Ok(_): Err("expected array")
		Err(message): Err(message)


func main(args: List[String]) -> Int:
	text: String = args.get(1).get_or("[{\"name\":\"Ada\"}]")
	match users_csv(text):
		Ok(csv_text):
			print(csv_text) -- default output bytes: name\r\nAda\n
			0
		Err(message):
			print_error(message) -- {}: expected array; [{}]: missing name; [{"name":42}]: expected a string
			1

Try it

terminal
blorp run users-csv.brp