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
|
let
|
||||||
evaled = lib.evalModules { modules = [ module ]; };
|
evaled = lib.evalModules { modules = [ module ]; };
|
||||||
in
|
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
|
# parses a set of evaluated nixos options to a jsonschema
|
||||||
parseOptions =
|
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
|
let
|
||||||
options = filterInvisibleOpts (filterExcludedAttrs (clean options'));
|
options' = filterInvisibleOpts (filterExcludedAttrs (clean options));
|
||||||
# parse options to jsonschema properties
|
# 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
|
# TODO: figure out how to handle if prop.anyOf is used
|
||||||
isRequired = prop: !(prop ? default || prop.type or null == "object");
|
isRequired = prop: !(prop ? default || prop.type or null == "object");
|
||||||
requiredProps = lib.filterAttrs (_: prop: isRequired prop) properties;
|
requiredProps = lib.filterAttrs (_: prop: isRequired prop) properties;
|
||||||
required = lib.optionalAttrs (requiredProps != { }) { required = lib.attrNames requiredProps; };
|
required = lib.optionalAttrs (requiredProps != { }) { required = lib.attrNames requiredProps; };
|
||||||
|
header' = if addHeader then header else { };
|
||||||
in
|
in
|
||||||
# return jsonschema
|
# return jsonschema
|
||||||
required
|
header'
|
||||||
|
// required
|
||||||
// {
|
// {
|
||||||
type = "object";
|
type = "object";
|
||||||
inherit properties;
|
inherit properties;
|
||||||
@@ -108,7 +121,7 @@ rec {
|
|||||||
|
|
||||||
# handle nested options (not a submodule)
|
# handle nested options (not a submodule)
|
||||||
else if !option ? _type then
|
else if !option ? _type then
|
||||||
parseOptions option
|
parseOptions' option
|
||||||
|
|
||||||
# throw if not an option
|
# throw if not an option
|
||||||
else if option._type != "option" && option._type != "option-type" then
|
else if option._type != "option" && option._type != "option-type" then
|
||||||
@@ -231,7 +244,7 @@ rec {
|
|||||||
// description
|
// description
|
||||||
// {
|
// {
|
||||||
type = "array";
|
type = "array";
|
||||||
items = parseOptions (option.type.functor.wrapped.getSubOptions option.loc);
|
items = parseOptions' (option.type.functor.wrapped.getSubOptions option.loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
# parse list
|
# parse list
|
||||||
@@ -271,7 +284,7 @@ rec {
|
|||||||
// description
|
// description
|
||||||
// {
|
// {
|
||||||
type = "object";
|
type = "object";
|
||||||
additionalProperties = parseOptions (option.type.nestedTypes.elemType.getSubOptions option.loc);
|
additionalProperties = parseOptions' (option.type.nestedTypes.elemType.getSubOptions option.loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
# parse attrs
|
# parse attrs
|
||||||
@@ -322,7 +335,7 @@ rec {
|
|||||||
# return jsonschema property definition for submodule
|
# return jsonschema property definition for submodule
|
||||||
# then (lib.attrNames (option.type.getSubOptions option.loc).opt)
|
# then (lib.attrNames (option.type.getSubOptions option.loc).opt)
|
||||||
then
|
then
|
||||||
parseOptions (option.type.getSubOptions option.loc)
|
parseOptions' (option.type.getSubOptions option.loc)
|
||||||
|
|
||||||
# throw error if option type is not supported
|
# throw error if option type is not supported
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -17,8 +17,9 @@
|
|||||||
};
|
};
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
expr = slib.parseOptions evaled.options;
|
expr = slib.parseOptions evaled.options { };
|
||||||
expected = {
|
expected = {
|
||||||
|
"$schema" = "http://json-schema.org/draft-07/schema#";
|
||||||
additionalProperties = false;
|
additionalProperties = false;
|
||||||
properties = {
|
properties = {
|
||||||
foo = {
|
foo = {
|
||||||
|
|||||||
@@ -18,13 +18,13 @@
|
|||||||
if (eval.options.clan ? "${mName}") then eval.options.clan.${mName} else { };
|
if (eval.options.clan ? "${mName}") then eval.options.clan.${mName} else { };
|
||||||
|
|
||||||
clanModuleSchemas = lib.mapAttrs (
|
clanModuleSchemas = lib.mapAttrs (
|
||||||
modulename: _: self.lib.jsonschema.parseOptions (optionsFromModule modulename)
|
modulename: _: self.lib.jsonschema.parseOptions (optionsFromModule modulename) { }
|
||||||
) clanModules;
|
) clanModules;
|
||||||
|
|
||||||
clanModuleFunctionSchemas = lib.mapAttrsFlatten (modulename: _: {
|
clanModuleFunctionSchemas = lib.mapAttrsFlatten (modulename: _: {
|
||||||
name = modulename;
|
name = modulename;
|
||||||
description = self.lib.modules.getShortDescription modulename;
|
description = self.lib.modules.getShortDescription modulename;
|
||||||
parameters = self.lib.jsonschema.parseOptions (optionsFromModule modulename);
|
parameters = self.lib.jsonschema.parseOptions (optionsFromModule modulename) { };
|
||||||
}) clanModules;
|
}) clanModules;
|
||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
|
|||||||
Reference in New Issue
Block a user