Skip to content

Commit

Permalink
feat: generate extension manifest schema (#3806)
Browse files Browse the repository at this point in the history
  • Loading branch information
ericswanson-dfinity authored Jun 25, 2024
1 parent 9123924 commit e7b89d7
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 7 deletions.
1 change: 1 addition & 0 deletions .github/workflows/update-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
cargo run -- schema --outfile docs/dfx-json-schema.json
cargo run -- schema --for networks --outfile docs/networks-json-schema.json
cargo run -- schema --for dfx-metadata --outfile docs/dfx-metadata-schema.json
cargo run -- schema --for extension-manifest --outfile docs/extension-manifest-schema.json
echo "JSON Schema changes:"
if git diff --exit-code ; then
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

# UNRELEASED

### feat: add `dfx schema --for extension-manifest`

The schema command can now output the schema for extension.json files.

# 0.21.0

### feat: dfx killall
Expand Down
2 changes: 1 addition & 1 deletion docs/cli-reference/dfx-schema.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ You can use the following option with the `dfx schema` command.

| Option | Description |
|------------------------|--------------------------------------------------------------------------------------------------|
| `--for <dfx/networks>` | Display schema for which JSON file. (default: dfx, possible values: dfx, networks, dfx-metadata) |
| `--for <which>` | Display schema for which JSON file. (default: dfx, possible values: dfx, networks, dfx-metadata, extension-manifest) |
| `--outfile <outfile>` | Specifies a file to output the schema to instead of printing it to stdout. |

## Examples
Expand Down
233 changes: 233 additions & 0 deletions docs/extension-manifest-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ExtensionManifest",
"type": "object",
"required": [
"categories",
"homepage",
"name",
"summary",
"version"
],
"properties": {
"authors": {
"type": [
"string",
"null"
]
},
"canister_type": {
"anyOf": [
{
"$ref": "#/definitions/ExtensionCanisterType"
},
{
"type": "null"
}
]
},
"categories": {
"type": "array",
"items": {
"type": "string"
}
},
"dependencies": {
"type": [
"object",
"null"
],
"additionalProperties": {
"type": "string"
}
},
"description": {
"type": [
"string",
"null"
]
},
"homepage": {
"type": "string"
},
"keywords": {
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"name": {
"type": "string"
},
"subcommands": {
"anyOf": [
{
"$ref": "#/definitions/ExtensionSubcommandsOpts"
},
{
"type": "null"
}
]
},
"summary": {
"type": "string"
},
"version": {
"type": "string"
}
},
"additionalProperties": false,
"definitions": {
"ArgNumberOfValues": {
"oneOf": [
{
"description": "zero or more values",
"type": "object",
"required": [
"Number"
],
"properties": {
"Number": {
"type": "integer",
"format": "uint",
"minimum": 0.0
}
},
"additionalProperties": false
},
{
"description": "non-inclusive range",
"type": "object",
"required": [
"Range"
],
"properties": {
"Range": {
"$ref": "#/definitions/Range_of_uint"
}
},
"additionalProperties": false
},
{
"description": "unlimited values",
"type": "string",
"enum": [
"Unlimited"
]
}
]
},
"ExtensionCanisterType": {
"type": "object",
"properties": {
"defaults": {
"description": "Default values for the canister type. These values are used when the user does not provide values in dfx.json. The \"metadata\" field, if present, is appended to the metadata field from dfx.json, which has the effect of providing defaults. The \"tech_stack field, if present, it merged with the tech_stack field from dfx.json, which also has the effect of providing defaults.",
"default": {},
"type": "object",
"additionalProperties": true
},
"evaluation_order": {
"description": "If one field depends on another and both specify a handlebars expression, list the fields in the order that they should be evaluated.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
}
}
},
"ExtensionSubcommandArgOpts": {
"type": "object",
"properties": {
"about": {
"type": [
"string",
"null"
]
},
"long": {
"type": [
"string",
"null"
]
},
"multiple": {
"default": false,
"deprecated": true,
"type": "boolean"
},
"short": {
"type": [
"string",
"null"
],
"maxLength": 1,
"minLength": 1
},
"values": {
"$ref": "#/definitions/ArgNumberOfValues"
}
},
"additionalProperties": false
},
"ExtensionSubcommandOpts": {
"type": "object",
"properties": {
"about": {
"type": [
"string",
"null"
]
},
"args": {
"type": [
"object",
"null"
],
"additionalProperties": {
"$ref": "#/definitions/ExtensionSubcommandArgOpts"
}
},
"subcommands": {
"anyOf": [
{
"$ref": "#/definitions/ExtensionSubcommandsOpts"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
},
"ExtensionSubcommandsOpts": {
"type": "object",
"additionalProperties": {
"$ref": "#/definitions/ExtensionSubcommandOpts"
}
},
"Range_of_uint": {
"type": "object",
"required": [
"end",
"start"
],
"properties": {
"end": {
"type": "integer",
"format": "uint",
"minimum": 0.0
},
"start": {
"type": "integer",
"format": "uint",
"minimum": 0.0
}
}
}
}
}
13 changes: 7 additions & 6 deletions src/dfx-core/src/extension/manifest/extension.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::error::extension::{
ConvertExtensionSubcommandIntoClapArgError, ConvertExtensionSubcommandIntoClapCommandError,
LoadExtensionManifestError,
};
use schemars::JsonSchema;
use serde::{Deserialize, Deserializer};
use serde_json::Value;
use std::path::PathBuf;
Expand All @@ -15,7 +16,7 @@ pub static MANIFEST_FILE_NAME: &str = "extension.json";
type SubcmdName = String;
type ArgName = String;

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ExtensionManifest {
pub name: String,
Expand Down Expand Up @@ -62,7 +63,7 @@ impl ExtensionManifest {
}
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, JsonSchema)]
pub struct ExtensionCanisterType {
/// If one field depends on another and both specify a handlebars expression,
/// list the fields in the order that they should be evaluated.
Expand All @@ -79,18 +80,18 @@ pub struct ExtensionCanisterType {
pub defaults: BTreeMap<String, Value>,
}

#[derive(Debug, Deserialize, Default)]
#[derive(Debug, Deserialize, Default, JsonSchema)]
pub struct ExtensionSubcommandsOpts(BTreeMap<SubcmdName, ExtensionSubcommandOpts>);

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ExtensionSubcommandOpts {
pub about: Option<String>,
pub args: Option<BTreeMap<ArgName, ExtensionSubcommandArgOpts>>,
pub subcommands: Option<ExtensionSubcommandsOpts>,
}

#[derive(Debug, Deserialize)]
#[derive(Debug, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct ExtensionSubcommandArgOpts {
pub about: Option<String>,
Expand All @@ -103,7 +104,7 @@ pub struct ExtensionSubcommandArgOpts {
pub values: ArgNumberOfValues,
}

#[derive(Debug)]
#[derive(Debug, JsonSchema)]
pub enum ArgNumberOfValues {
/// zero or more values
Number(usize),
Expand Down
4 changes: 4 additions & 0 deletions src/dfx/src/commands/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ enum ForFile {
Dfx,
Networks,
DfxMetadata,
ExtensionManifest,
}

/// Prints the schema for dfx.json.
Expand All @@ -27,6 +28,9 @@ pub fn exec(opts: SchemaOpts) -> DfxResult {
let schema = match opts.r#for {
Some(ForFile::Networks) => schema_for!(TopLevelConfigNetworks),
Some(ForFile::DfxMetadata) => schema_for!(DfxMetadata),
Some(ForFile::ExtensionManifest) => {
schema_for!(dfx_core::extension::manifest::ExtensionManifest)
}
_ => schema_for!(ConfigInterface),
};
let nice_schema =
Expand Down

0 comments on commit e7b89d7

Please sign in to comment.