Json-schema: extend interface by header to allow schema spec and arbitrary extensions
This commit is contained in:
@@ -1,2 +0,0 @@
|
||||
module: "clan.lol/inventory"
|
||||
language: version: "v0.8.2"
|
||||
@@ -1,23 +0,0 @@
|
||||
package inventory
|
||||
|
||||
import (
|
||||
"clan.lol/inventory/schema"
|
||||
)
|
||||
|
||||
@jsonschema(schema="http://json-schema.org/schema#")
|
||||
#Root: {
|
||||
meta: {
|
||||
// A name of the clan (primarily shown by the UI)
|
||||
name: string
|
||||
// A description of the clan
|
||||
description?: string
|
||||
// The icon path
|
||||
icon?: string
|
||||
}
|
||||
|
||||
// // A map of services
|
||||
schema.#service
|
||||
|
||||
// // A map of machines
|
||||
schema.#machine
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package schema
|
||||
|
||||
#machine: machines: [string]: {
|
||||
name: string,
|
||||
description?: string,
|
||||
icon?: string
|
||||
tags: [...string]
|
||||
system?: string
|
||||
}
|
||||
|
||||
#role: string
|
||||
|
||||
#service: services: [string]: [string]: {
|
||||
// Required meta fields
|
||||
meta: {
|
||||
name: string,
|
||||
icon?: string
|
||||
description?: string,
|
||||
},
|
||||
// We moved the machine sepcific config to "machines".
|
||||
// It may be moved back depending on what makes more sense in the future.
|
||||
roles: [#role]: {
|
||||
machines: [...string],
|
||||
tags: [...string],
|
||||
}
|
||||
machines?: {
|
||||
[string]: {
|
||||
config?: {
|
||||
...
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Global Configuration for the service
|
||||
config?: {
|
||||
// Schema depends on the module.
|
||||
// It declares the interface how the service can be configured.
|
||||
...
|
||||
}
|
||||
}
|
||||
@@ -47,22 +47,35 @@ rec {
|
||||
let
|
||||
evaled = lib.evalModules { modules = [ module ]; };
|
||||
in
|
||||
{ "$schema" = "http://json-schema.org/draft-07/schema#"; } // parseOptions evaled.options;
|
||||
parseOptions evaled.options { };
|
||||
|
||||
parseOptions' = lib.flip parseOptions { addHeader = false; };
|
||||
|
||||
# parses a set of evaluated nixos options to a jsonschema
|
||||
parseOptions =
|
||||
options':
|
||||
options:
|
||||
{
|
||||
# The top-level header object should specify at least the schema version
|
||||
# Can be customized if needed
|
||||
header ? {
|
||||
"$schema" = "http://json-schema.org/draft-07/schema#";
|
||||
},
|
||||
# By default the header is not added to the schema
|
||||
addHeader ? true,
|
||||
}:
|
||||
let
|
||||
options = filterInvisibleOpts (filterExcludedAttrs (clean options'));
|
||||
options' = filterInvisibleOpts (filterExcludedAttrs (clean options));
|
||||
# parse options to jsonschema properties
|
||||
properties = lib.mapAttrs (_name: option: parseOption option) options;
|
||||
properties = lib.mapAttrs (_name: option: parseOption option) options';
|
||||
# TODO: figure out how to handle if prop.anyOf is used
|
||||
isRequired = prop: !(prop ? default || prop.type or null == "object");
|
||||
requiredProps = lib.filterAttrs (_: prop: isRequired prop) properties;
|
||||
required = lib.optionalAttrs (requiredProps != { }) { required = lib.attrNames requiredProps; };
|
||||
header' = if addHeader then header else { };
|
||||
in
|
||||
# return jsonschema
|
||||
required
|
||||
header'
|
||||
// required
|
||||
// {
|
||||
type = "object";
|
||||
inherit properties;
|
||||
@@ -108,7 +121,7 @@ rec {
|
||||
|
||||
# handle nested options (not a submodule)
|
||||
else if !option ? _type then
|
||||
parseOptions option
|
||||
parseOptions' option
|
||||
|
||||
# throw if not an option
|
||||
else if option._type != "option" && option._type != "option-type" then
|
||||
@@ -231,7 +244,7 @@ rec {
|
||||
// description
|
||||
// {
|
||||
type = "array";
|
||||
items = parseOptions (option.type.functor.wrapped.getSubOptions option.loc);
|
||||
items = parseOptions' (option.type.functor.wrapped.getSubOptions option.loc);
|
||||
}
|
||||
|
||||
# parse list
|
||||
@@ -271,7 +284,7 @@ rec {
|
||||
// description
|
||||
// {
|
||||
type = "object";
|
||||
additionalProperties = parseOptions (option.type.nestedTypes.elemType.getSubOptions option.loc);
|
||||
additionalProperties = parseOptions' (option.type.nestedTypes.elemType.getSubOptions option.loc);
|
||||
}
|
||||
|
||||
# parse attrs
|
||||
@@ -322,7 +335,7 @@ rec {
|
||||
# return jsonschema property definition for submodule
|
||||
# then (lib.attrNames (option.type.getSubOptions option.loc).opt)
|
||||
then
|
||||
parseOptions (option.type.getSubOptions option.loc)
|
||||
parseOptions' (option.type.getSubOptions option.loc)
|
||||
|
||||
# throw error if option type is not supported
|
||||
else
|
||||
|
||||
@@ -17,8 +17,9 @@
|
||||
};
|
||||
in
|
||||
{
|
||||
expr = slib.parseOptions evaled.options;
|
||||
expr = slib.parseOptions evaled.options { };
|
||||
expected = {
|
||||
"$schema" = "http://json-schema.org/draft-07/schema#";
|
||||
additionalProperties = false;
|
||||
properties = {
|
||||
foo = {
|
||||
|
||||
@@ -18,13 +18,13 @@
|
||||
if (eval.options.clan ? "${mName}") then eval.options.clan.${mName} else { };
|
||||
|
||||
clanModuleSchemas = lib.mapAttrs (
|
||||
modulename: _: self.lib.jsonschema.parseOptions (optionsFromModule modulename)
|
||||
modulename: _: self.lib.jsonschema.parseOptions (optionsFromModule modulename) { }
|
||||
) clanModules;
|
||||
|
||||
clanModuleFunctionSchemas = lib.mapAttrsFlatten (modulename: _: {
|
||||
name = modulename;
|
||||
description = self.lib.modules.getShortDescription modulename;
|
||||
parameters = self.lib.jsonschema.parseOptions (optionsFromModule modulename);
|
||||
parameters = self.lib.jsonschema.parseOptions (optionsFromModule modulename) { };
|
||||
}) clanModules;
|
||||
in
|
||||
rec {
|
||||
|
||||
Reference in New Issue
Block a user