Merge branch 'yaml-schemata' into calamares
This commit is contained in:
commit
066acdbbc6
116
ci/configvalidator.py
Normal file
116
ci/configvalidator.py
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
#
|
||||||
|
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
# License-Filename: LICENSES/BSD2
|
||||||
|
#
|
||||||
|
usage = """
|
||||||
|
Validates a Calamares config file -- YAML syntax -- against a schema.
|
||||||
|
|
||||||
|
The schema is also written in YAML syntax, but the schema itself
|
||||||
|
is JSON-schema. This is possible because all JSON is YAML, and most
|
||||||
|
YAML is JSON. The limited subset of YAML that Calamares uses is
|
||||||
|
JSON-representable, anyway.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
configvalidator.py <schema> <file> ...
|
||||||
|
"""
|
||||||
|
|
||||||
|
# The schemata originally lived outside the Calamares repository,
|
||||||
|
# without documented tooling. By putting them in the repository
|
||||||
|
# with the example files and explicit tooling, there's a better
|
||||||
|
# chance of them catching problems and acting as documentation.
|
||||||
|
|
||||||
|
dependencies = """
|
||||||
|
Dependencies for this tool are: py-yaml and py-jsonschema.
|
||||||
|
|
||||||
|
https://pyyaml.org/
|
||||||
|
https://github.com/Julian/jsonschema
|
||||||
|
|
||||||
|
Simple installation is `pip install pyyaml jsonschema`
|
||||||
|
"""
|
||||||
|
|
||||||
|
ERR_IMPORT, ERR_USAGE, ERR_FILE_NOT_FOUND, ERR_SYNTAX, ERR_INVALID = range(1,6)
|
||||||
|
|
||||||
|
### DEPENDENCIES
|
||||||
|
#
|
||||||
|
#
|
||||||
|
try:
|
||||||
|
from jsonschema import validate, SchemaError, ValidationError
|
||||||
|
from yaml import safe_load, YAMLError
|
||||||
|
except ImportError as e:
|
||||||
|
print(e)
|
||||||
|
print(dependencies)
|
||||||
|
exit(ERR_IMPORT)
|
||||||
|
|
||||||
|
from os.path import exists
|
||||||
|
import sys
|
||||||
|
|
||||||
|
### INPUT VALIDATION
|
||||||
|
#
|
||||||
|
#
|
||||||
|
if len(sys.argv) < 3:
|
||||||
|
print(usage)
|
||||||
|
exit(ERR_USAGE)
|
||||||
|
|
||||||
|
schema_file_name = sys.argv[1]
|
||||||
|
config_file_names = sys.argv[2:]
|
||||||
|
|
||||||
|
if not exists(schema_file_name):
|
||||||
|
print(usage)
|
||||||
|
print("\nSchema file '{}' does not exist.".format(schema_file_name))
|
||||||
|
exit(ERR_FILE_NOT_FOUND)
|
||||||
|
for f in config_file_names:
|
||||||
|
if not exists(f):
|
||||||
|
print(usage)
|
||||||
|
print("\nYAML file '{}' does not exist.".format(f))
|
||||||
|
exit(ERR_FILE_NOT_FOUND)
|
||||||
|
|
||||||
|
### FILES SYNTAX CHECK
|
||||||
|
#
|
||||||
|
#
|
||||||
|
with open(schema_file_name, "r") as data:
|
||||||
|
try:
|
||||||
|
schema = safe_load(data)
|
||||||
|
except YAMLError as e:
|
||||||
|
print("Schema error: {} {}.".format(e.problem, e.problem_mark))
|
||||||
|
print("\nSchema file '{}' is invalid YAML.".format(schema_file_name))
|
||||||
|
exit(ERR_SYNTAX)
|
||||||
|
|
||||||
|
try:
|
||||||
|
validate(instance={}, schema=schema)
|
||||||
|
# While developing the schemata, get full exceptions from schema failure
|
||||||
|
except SchemaError as e:
|
||||||
|
print(e)
|
||||||
|
print("\nSchema file '{}' is invalid JSON-Schema.".format(schema_file_name))
|
||||||
|
exit(ERR_INVALID)
|
||||||
|
except ValidationError:
|
||||||
|
# Just means that empty isn't valid, but the Schema itself is
|
||||||
|
pass
|
||||||
|
|
||||||
|
configs = []
|
||||||
|
for f in config_file_names:
|
||||||
|
config = None
|
||||||
|
with open(f, "r") as data:
|
||||||
|
try:
|
||||||
|
config = safe_load(data)
|
||||||
|
except YAMLError as e:
|
||||||
|
print("YAML error: {} {}.".format(e.problem, e.problem_mark))
|
||||||
|
print("\nYAML file '{}' is invalid.".format(f))
|
||||||
|
exit(ERR_SYNTAX)
|
||||||
|
if config is None:
|
||||||
|
print("YAML file '{}' is empty.".format(f))
|
||||||
|
configs.append(config)
|
||||||
|
|
||||||
|
assert len(configs) == len(config_file_names), "Not all configurations loaded."
|
||||||
|
|
||||||
|
### SCHEMA VALIDATION
|
||||||
|
#
|
||||||
|
#
|
||||||
|
for c, f in zip(configs, config_file_names):
|
||||||
|
try:
|
||||||
|
validate(instance=c, schema=schema)
|
||||||
|
except ValidationError as e:
|
||||||
|
print(e)
|
||||||
|
print("\nConfig file '{}' does not validate in schema.".format(f))
|
||||||
|
exit(ERR_INVALID)
|
@ -66,3 +66,21 @@ endforeach()
|
|||||||
|
|
||||||
include( CalamaresAddTranslations )
|
include( CalamaresAddTranslations )
|
||||||
add_calamares_python_translations( ${CALAMARES_TRANSLATION_LANGUAGES} )
|
add_calamares_python_translations( ${CALAMARES_TRANSLATION_LANGUAGES} )
|
||||||
|
|
||||||
|
# TODO:3.3: Use FindPython3
|
||||||
|
if ( BUILD_TESTING AND PYTHONINTERP_FOUND AND PYTHON_EXECUTABLE )
|
||||||
|
# The tests for each config file are independent of whether the
|
||||||
|
# module is enabled or not: the config file should match its schema
|
||||||
|
# regardless.
|
||||||
|
foreach( SUBDIRECTORY ${SUBDIRECTORIES} )
|
||||||
|
set( _schema_file "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/${SUBDIRECTORY}.schema.yaml" )
|
||||||
|
set( _conf_file "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}/${SUBDIRECTORY}.conf" )
|
||||||
|
if ( EXISTS "${_schema_file}" AND EXISTS "${_conf_file}" )
|
||||||
|
add_test(
|
||||||
|
NAME validate-${SUBDIRECTORY}
|
||||||
|
COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_SOURCE_DIR}/ci/configvalidator.py" "${_schema_file}" "${_conf_file}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
18
src/modules/bootloader/bootloader.schema.yaml
Normal file
18
src/modules/bootloader/bootloader.schema.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/bootloader
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
efiBootLoader: { type: string, required: true }
|
||||||
|
kernel: { type: string, required: true }
|
||||||
|
img: { type: string, required: true }
|
||||||
|
fallback: { type: str }
|
||||||
|
timeout: { type: str }
|
||||||
|
bootloaderEntryName: { type: str }
|
||||||
|
kernelLine: { type: str }
|
||||||
|
fallbackKernelLine: { type: str }
|
||||||
|
grubInstall: { type: string, required: true }
|
||||||
|
grubMkconfig: { type: string, required: true }
|
||||||
|
grubCfg: { type: string, required: true }
|
||||||
|
efiBootloaderId: { type: str }
|
16
src/modules/displaymanager/displaymanager.schema.yaml
Normal file
16
src/modules/displaymanager/displaymanager.schema.yaml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/displaymanager
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"displaymanagers":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- { type: string, required: true, enum: [slim, sddm, lightdm, gdm, mdm, lxdm, kdm] }
|
||||||
|
"defaultDesktopEnvironment":
|
||||||
|
type: map
|
||||||
|
mapping:
|
||||||
|
"executable": { type: str }
|
||||||
|
"desktopFile": { type: str }
|
||||||
|
"basicSetup": { type: boolean, default: false }
|
11
src/modules/finished/finished.schema.yaml
Normal file
11
src/modules/finished/finished.schema.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/finished
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
restartNowEnabled: { type: boolean, default: true } # TODO:3.3: remove
|
||||||
|
restartNowChecked: { type: boolean, default: false } # TODO:3.3: remove
|
||||||
|
restartNowCommand: { type: string }
|
||||||
|
restartNowMode: { type: string, enum: [ never, user-unchecked, user-checked, always ] }
|
||||||
|
notifyOnFinished: { type: boolean }
|
19
src/modules/fstab/fstab.schema.yaml
Normal file
19
src/modules/fstab/fstab.schema.yaml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/fstab
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"mountOptions":
|
||||||
|
type: map
|
||||||
|
mapping:
|
||||||
|
"default": { type: string, required: true }
|
||||||
|
"btrfs": { type: string, required: true }
|
||||||
|
"ssdExtraMountOptions":
|
||||||
|
type: map
|
||||||
|
mapping:
|
||||||
|
"ext4": { type: string, required: true }
|
||||||
|
"jfs": { type: string, required: true }
|
||||||
|
"xfs": { type: string, required: true }
|
||||||
|
"swap": { type: string, required: true }
|
||||||
|
"btrfs": { type: string, required: true }
|
15
src/modules/grubcfg/grubcfg.schema.yaml
Normal file
15
src/modules/grubcfg/grubcfg.schema.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/grubcfg
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"overwrite": { type: boolean, default: false }
|
||||||
|
"defaults":
|
||||||
|
type: map
|
||||||
|
mapping:
|
||||||
|
"GRUB_TIMEOUT": { type: int, required: true }
|
||||||
|
"GRUB_DEFAULT": { type: string, required: true }
|
||||||
|
"GRUB_DISABLE_SUBMENU": { type: boolean, default: true }
|
||||||
|
"GRUB_TERMINAL_OUTPUT": { type: string, required: true }
|
||||||
|
"GRUB_DISABLE_RECOVERY": { type: boolean, default: true }
|
7
src/modules/initcpio/initcpio.schema.yaml
Normal file
7
src/modules/initcpio/initcpio.schema.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/initcpio
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
kernel: { type: string, required: true }
|
8
src/modules/keyboard/keyboard.schema.yaml
Normal file
8
src/modules/keyboard/keyboard.schema.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/finished
|
||||||
|
additionalProperties: keyboard
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
xOrgConfFileName: { type: string, required: true }
|
||||||
|
convertedKeymapPath: { type: string, required: true }
|
17
src/modules/license/license.schema.yaml
Normal file
17
src/modules/license/license.schema.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/license
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"entries":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- type: map
|
||||||
|
mapping:
|
||||||
|
"id": { type: str }
|
||||||
|
"name": { type: str }
|
||||||
|
"vendor": { type: str }
|
||||||
|
"type": { type: str }
|
||||||
|
"url": { type: str }
|
||||||
|
"required": { type: boolean, default: false }
|
10
src/modules/locale/locale.schema.yaml
Normal file
10
src/modules/locale/locale.schema.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/locale
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"region": { type: str }
|
||||||
|
"zone": { type: str }
|
||||||
|
"localeGenPath": { type: string, required: true }
|
||||||
|
"geoipUrl": { type: str }
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/luksopenswaphookcfg
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"configFilePath": { type: string, required: true }
|
9
src/modules/machineid/machineid.schema.yaml
Normal file
9
src/modules/machineid/machineid.schema.yaml
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/machineid
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"systemd": { type: boolean, default: true }
|
||||||
|
"dbus": { type: boolean, default: true }
|
||||||
|
"symlink": { type: boolean, default: true }
|
24
src/modules/mount/mount.schema.yaml
Normal file
24
src/modules/mount/mount.schema.yaml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/mount
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"extraMounts":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- type: map
|
||||||
|
mapping:
|
||||||
|
"device": { type: string, required: true }
|
||||||
|
"fs": { type: str }
|
||||||
|
"mountPoint": { type: string, required: true }
|
||||||
|
"options": { type: str }
|
||||||
|
"extraMountsEfi":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- type: map
|
||||||
|
mapping:
|
||||||
|
"device": { type: string, required: true }
|
||||||
|
"fs": { type: str }
|
||||||
|
"mountPoint": { type: string, required: true }
|
||||||
|
"options": { type: str }
|
7
src/modules/netinstall/netinstall.schema.yaml
Normal file
7
src/modules/netinstall/netinstall.schema.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/netinstall
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
groupsUrl: { type: string, required: true }
|
33
src/modules/packages/packages.schema.yaml
Normal file
33
src/modules/packages/packages.schema.yaml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/packages
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"backend": { type: string, required: true, enum: [packagekit, zypp, yum, dnf, urpmi, apt, pacman, portage, entropy] }
|
||||||
|
"update_db": { type: boolean, default: true }
|
||||||
|
"operations":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- type: map
|
||||||
|
mapping:
|
||||||
|
"install":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- { type: text }
|
||||||
|
"remove":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- { type: text }
|
||||||
|
"localInstall":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- { type: text }
|
||||||
|
"try_install":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- { type: text }
|
||||||
|
"try_remove":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- { type: text }
|
11
src/modules/partition/partition.schema.yaml
Normal file
11
src/modules/partition/partition.schema.yaml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/partition
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
efiSystemPartition: { type: string, required: true }
|
||||||
|
ensureSuspendToDisk: { type: boolean, default: true }
|
||||||
|
drawNestedPartitions: { type: boolean, default: false }
|
||||||
|
alwaysShowPartitionLabels: { type: boolean, default: true }
|
||||||
|
defaultFileSystemType: { type: string, required: true }
|
7
src/modules/plymouthcfg/plymouthcfg.schema.yaml
Normal file
7
src/modules/plymouthcfg/plymouthcfg.schema.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/plymouthcfg
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
plymouth_theme: { type: str }
|
7
src/modules/removeuser/removeuser.schema.yaml
Normal file
7
src/modules/removeuser/removeuser.schema.yaml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/removeuser
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"username": { type: string, required: true }
|
8
src/modules/umount/umount.schema.yaml
Normal file
8
src/modules/umount/umount.schema.yaml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/umount
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"srcLog": { type: str }
|
||||||
|
"destLog": { type: str }
|
14
src/modules/unpackfs/unpackfs.schema.yaml
Normal file
14
src/modules/unpackfs/unpackfs.schema.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/unpackfs
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"unpack":
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- type: map
|
||||||
|
mapping:
|
||||||
|
"source": { type: string, required: true }
|
||||||
|
"sourcefs": { type: str }
|
||||||
|
"destination": { type: str }
|
18
src/modules/users/users.schema.yaml
Normal file
18
src/modules/users/users.schema.yaml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/users
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
"defaultGroups":
|
||||||
|
required: true
|
||||||
|
type: seq
|
||||||
|
sequence:
|
||||||
|
- { type: str }
|
||||||
|
"autologinGroup": { type: string, required: true }
|
||||||
|
"doAutologin": { type: boolean, default: true }
|
||||||
|
"sudoersGroup": { type: string, required: true }
|
||||||
|
"setRootPassword": { type: boolean, default: true }
|
||||||
|
"availableShells": { type: str }
|
||||||
|
"avatarFilePath": { type: str }
|
||||||
|
"doReusePassword": { type: boolean, default: true }
|
36
src/modules/welcome/welcome.schema.yaml
Normal file
36
src/modules/welcome/welcome.schema.yaml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
---
|
||||||
|
$schema: https://json-schema.org/schema#
|
||||||
|
$id: https://calamares.io/schemas/welcome
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
# TODO:3.3: drop the string alternatives and put the URL part in Branding
|
||||||
|
showSupportUrl: { anyOf: [ { type: boolean, default: true }, { type: string } ] }
|
||||||
|
showKnownIssuesUrl: { anyOf: [ { type: boolean, default: true }, { type: string } ] }
|
||||||
|
showReleaseNotesUrl: { anyOf: [ { type: boolean, default: true }, { type: string } ] }
|
||||||
|
showDonateUrl: { anyOf: [ { type: boolean, default: true }, { type: string } ] }
|
||||||
|
|
||||||
|
requirements:
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
requiredStorage: { type: number }
|
||||||
|
requiredRam: { type: number }
|
||||||
|
internetCheckUrl: { type: string }
|
||||||
|
check:
|
||||||
|
type: array
|
||||||
|
items: { type: string, enum: [storage, ram, power, internet, root, screen], unique: true }
|
||||||
|
required: # Key-name in the config-file
|
||||||
|
type: array
|
||||||
|
items: { type: string, enum: [storage, ram, power, internet, root, screen], unique: true }
|
||||||
|
required: [ requiredStorage, requiredRam, check ] # Schema keyword
|
||||||
|
|
||||||
|
# TODO: refactor, this is reused in locale
|
||||||
|
geoip:
|
||||||
|
additionalProperties: false
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
style: { type: string, enum: [ none, fixed, xml, json ] }
|
||||||
|
url: { type: string }
|
||||||
|
selector: { type: string }
|
||||||
|
required: [ style, url, selector ]
|
Loading…
Reference in New Issue
Block a user