diff --git a/CHANGELOG.md b/CHANGELOG.md index 55606fac..d85fc872 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/crates/aiken-project/src/telemetry.rs b/crates/aiken-project/src/telemetry.rs index 3a8dee75..fb59c5d0 100644 --- a/crates/aiken-project/src/telemetry.rs +++ b/crates/aiken-project/src/telemetry.rs @@ -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, diff --git a/crates/aiken-project/src/telemetry/json.rs b/crates/aiken-project/src/telemetry/json.rs index 52aa01fa..45c5fab5 100644 --- a/crates/aiken-project/src/telemetry/json.rs +++ b/crates/aiken-project/src/telemetry/json.rs @@ -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 + } + }) +} diff --git a/crates/aiken/src/cmd/check.rs b/crates/aiken/src/cmd/check.rs index b145b8ea..ef96c771 100644 --- a/crates/aiken/src/cmd/check.rs +++ b/crates/aiken/src/cmd/check.rs @@ -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#"Output JSON schema: - type: object - properties: - seed: &type_integer - type: integer - summary: - type: object - properties: &type_summary - total: *type_integer - passed: *type_integer - failed: *type_integer - kind: - type: object - properties: - unit: *type_integer - property: *type_integer - modules: - type: array - items: - type: object - properties: - name: &type_string - type: string - summary: *type_summary - test: - type: array - items: - oneOf: - - type: object - required: - - kind - - title - - status - - on_failure - - execution_units - properties: - kind - type: string - enum: [ "unit" ] - title: *type_string - status: &type_status - type: string - enum: [ "pass", "fail" ] - on_failure: &type_on_failure - type: string - enum: - - fail_immediately - - succeed_immediately - - succeed_eventually - execution_units: - type: object - properties: - mem: *type_integer - cpu: *type_integer - assertion: *type_string - - type: object - required: - - kind - - title - - status - - on_failure - - iterations - - counterexample - properties: - kind - type: string - enum: [ "property" ] - title: *type_string - status: *type_status - on_failure: *type_on_failure - iterations: *type_integer - labels: - type: object - additionalProperties: *type_integer - counterexample: - oneOf: - - *type_string - - type: "null" - - type: object - properties: - error: *type_string - -Note: - 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());