Move JSON-schema help for check behind dedicated flag

1. A new option `show_json_schema` which, when enabled, will print the JSON schema of the command output if the target isn't an ANSI-capable terminal.
   2. Some modifications to the help message and error handling for the new option `show_json_schema`.

   This is now done to avoid flooding the help screen with an entire
   JSON schema. Plus, it makes the schema more easily exportable as an
   actual JSON schema.
This commit is contained in:
KtorZ 2024-11-19 15:48:35 +01:00
parent 7a93c55d0b
commit e12d7e807d
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
4 changed files with 153 additions and 87 deletions

View File

@ -4,6 +4,7 @@
### Changed
- **aiken**: Move JSON schema help for `check` under a new dedicated flag `--show-json-schema`. @KtorZ
- **aiken-lang**: Fix pattern-matching on list wildcard sometimes causing compiler crash following the new _decision trees_ approach. @MicroProofs
- **uplc**, **aiken**, **aiken-lang**: Update internal dependencies to pallas-0.31.0. @KtorZ

View File

@ -2,7 +2,7 @@ use aiken_lang::{
expr::UntypedExpr,
test_framework::{PropertyTestResult, TestResult, UnitTestResult},
};
pub use json::Json;
pub use json::{json_schema, Json};
use std::{
collections::BTreeMap,
fmt::Display,

View File

@ -137,3 +137,137 @@ where
.filter(|t| matches!(t, TestResult::PropertyTestResult { .. }))
.count()
}
pub fn json_schema() -> serde_json::Value {
let definitions = json!({
"Summary": {
"type": "object",
"required": ["total", "passed", "failed", "kind"],
"properties": {
"total": { "type": "integer" },
"passed": { "type": "integer" },
"failed": { "type": "integer" },
"kind": {
"type": "object",
"required": ["unit", "property"],
"properties": {
"unit": { "type": "integer" },
"property": { "type": "integer" }
}
}
}
},
"Status": {
"type": "string",
"enum": [ "pass", "fail" ]
},
"OnFailure": {
"type": "string",
"enum": [
"fail_immediately",
"succeed_immediately",
"succeed_eventually"
]
}
});
let unit_test = json!({
"type": "object",
"required": [
"kind",
"title",
"status",
"on_failure",
"execution_units"
],
"properties": {
"kind": {
"type": "string",
"enum": [ "unit" ]
},
"title": { "type": "string" },
"status": { "$ref": "#/properties/definitions/Status" },
"on_failure": { "$ref": "#/properties/definitions/OnFailure" },
"execution_units": {
"type": "object",
"properties": {
"mem": { "type": "integer" },
"cpu": { "type": "integer" }
}
},
"assertion": { "type": "string" },
}
});
let property_test = json!({
"type": "object",
"required": [
"kind",
"title",
"status",
"on_failure",
"iterations",
"counterexample"
],
"properties": {
"kind": {
"type": "string",
"enum": [ "property" ]
},
"title": { "type": "string" },
"status": { "$ref": "#/properties/definitions/Status" },
"on_failure": { "$ref": "#/properties/definitions/OnFailure" },
"iterations": { "type": "integer" },
"labels": {
"type": "object",
"additionalProperties": { "type": "integer" }
},
"counterexample": {
"oneOf": [
{ "type": "string" },
{ "type": "null" },
{
"type": "object",
"properties": {
"error": { "type": "string" }
}
}
]
}
}
});
json!({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$vocabulary": {
"https://json-schema.org/draft/2020-12/vocab/core": true,
"https://json-schema.org/draft/2020-12/vocab/applicator": true,
"https://json-schema.org/draft/2020-12/vocab/validation": true
},
"title": "Aiken CLI JSON Schema",
"type": "object",
"properties": {
"command[check]": {
"seed": { "type": "integer" },
"summary": { "$ref": "#/properties/definitions/Summary" },
"modules": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"summary": { "$ref": "#/properties/definitions/Summary" },
"test": {
"type": "array",
"items": {
"oneOf": [ unit_test, property_test ]
}
}
}
}
}
},
"definitions": definitions
}
})
}

View File

@ -3,7 +3,10 @@ use aiken_lang::{
ast::{TraceLevel, Tracing},
test_framework::PropertyTest,
};
use aiken_project::watch::{self, watch_project, with_project};
use aiken_project::{
telemetry::json_schema,
watch::{self, watch_project, with_project},
};
use rand::prelude::*;
use std::{
io::{self, IsTerminal},
@ -19,92 +22,9 @@ Type-check an Aiken project and run any tests found.
Test results are printed as stylized outputs when `stdout` is a TTY-capable terminal. If it
isn't, (e.g. because you are redirecting the output to a file), test results are printed as
a JSON structured object. Use `--help` to see the whole schema.
a JSON structured object. Use `--show-json-schema` to see the whole schema.
"#),
after_long_help = color_print::cstr!(r#"<bold><underline>Output JSON schema:</underline></bold>
<bold>type</bold>: object
<bold>properties</bold>:
<bold>seed</bold>: <cyan>&type_integer</cyan>
<bold>type</bold>: integer
<bold>summary</bold>:
<bold>type</bold>: object
<bold>properties</bold>: <cyan>&type_summary</cyan>
<bold>total</bold>: *type_integer
<bold>passed</bold>: *type_integer
<bold>failed</bold>: *type_integer
<bold>kind</bold>:
<bold>type</bold>: object
<bold>properties</bold>:
<bold>unit</bold>: *type_integer
<bold>property</bold>: *type_integer
<bold>modules</bold>:
<bold>type</bold>: array
<bold>items</bold>:
<bold>type</bold>: object
<bold>properties</bold>:
<bold>name</bold>: <cyan>&type_string</cyan>
<bold>type</bold>: string
<bold>summary</bold>: *type_summary
<bold>test</bold>:
<bold>type</bold>: array
<bold>items</bold>:
<bold>oneOf</bold>:
- <bold>type</bold>: object
<bold>required</bold>:
- kind
- title
- status
- on_failure
- execution_units
<bold>properties</bold>:
<bold>kind</bold>
<bold>type</bold>: string
<bold>enum</bold>: [ "unit" ]
<bold>title</bold>: *type_string
<bold>status</bold>: <cyan>&type_status</cyan>
<bold>type</bold>: string
<bold>enum</bold>: [ "pass", "fail" ]
<bold>on_failure</bold>: <cyan>&type_on_failure</cyan>
<bold>type</bold>: string
<bold>enum</bold>:
- fail_immediately
- succeed_immediately
- succeed_eventually
<bold>execution_units</bold>:
<bold>type</bold>: object
<bold>properties</bold>:
<bold>mem</bold>: *type_integer
<bold>cpu</bold>: *type_integer
<bold>assertion</bold>: *type_string
- <bold>type</bold>: object
<bold>required</bold>:
- kind
- title
- status
- on_failure
- iterations
- counterexample
<bold>properties</bold>:
<bold>kind</bold>
<bold>type</bold>: string
<bold>enum</bold>: [ "property" ]
<bold>title</bold>: *type_string
<bold>status</bold>: *type_status
<bold>on_failure</bold>: *type_on_failure
<bold>iterations</bold>: *type_integer
<bold>labels</bold>:
<bold>type</bold>: object
<bold>additionalProperties</bold>: *type_integer
<bold>counterexample</bold>:
<bold>oneOf</bold>:
- *type_string
- <bold>type</bold>: "null"
- <bold>type</bold>: object
<bold>properties</bold>:
<bold>error</bold>: *type_string
<bold><underline>Note:</underline></bold>
You are seeing the extended help. Use `-h` instead of `--help` for a more compact view.
after_long_help = color_print::cstr!(r#"You are seeing the extended help. Use `-h` instead of `--help` for a more compact view.
"#
))]
pub struct Args {
@ -123,6 +43,11 @@ pub struct Args {
#[clap(long)]
debug: bool,
/// When enabled, print-out the JSON-schema of the command output when the target isn't an
/// ANSI-capable terminal
#[clap(long, required = false)]
show_json_schema: bool,
/// When enabled, re-run the command on file changes instead of exiting
#[clap(long)]
watch: bool,
@ -185,6 +110,7 @@ pub fn exec(
deny,
skip_tests,
debug,
show_json_schema,
match_tests,
exact_match,
watch,
@ -195,6 +121,11 @@ pub fn exec(
env,
}: Args,
) -> miette::Result<()> {
if show_json_schema {
println!("{}", serde_json::to_string_pretty(&json_schema()).unwrap());
std::process::exit(0);
}
let mut rng = rand::thread_rng();
let seed = seed.unwrap_or_else(|| rng.gen());