feat(plugins): add json schema definition for plugin manifest
This commit is contained in:
parent
d321d0f93c
commit
688090aa82
|
@ -30,7 +30,13 @@
|
|||
"spark": "php",
|
||||
"env": "dotenv",
|
||||
".rsync-filter": "diff"
|
||||
}
|
||||
},
|
||||
"json.schemas": [
|
||||
{
|
||||
"fileMatch": ["plugins/**/manifest.json"],
|
||||
"url": "/workspaces/castopod/modules/Plugins/manifest.schema.json"
|
||||
}
|
||||
]
|
||||
},
|
||||
"extensions": [
|
||||
"bmewburn.vscode-intelephense-client",
|
||||
|
|
|
@ -1 +1 @@
|
|||
<svg viewBox="0 0 24 24" fill="currentColor" width="1em" height="1em"><path d="M16.455 10.658c0 1.09-.705 2.244-2.098 3.443a13.447 13.447 0 0 1-2.381 1.62 14.102 14.102 0 0 1-2.381-1.629c-1.4-1.2-2.106-2.353-2.106-3.443 0-1.346.887-2.298 2.106-2.298.558 0 .888.054 1.263.238.22.1.412.237.577.403l.541.55.532-.55a2.07 2.07 0 0 1 .586-.421c.366-.166.678-.22 1.254-.22 1.209.018 2.107.988 2.107 2.307Z" clip-rule="evenodd"/><path d="M22 3.915v16.17A1.911 1.911 0 0 1 20.085 22H3.915A1.911 1.911 0 0 1 2 20.085V3.915C2 2.855 2.854 2 3.915 2h8.066c.267 0 .503.107.68.282a.986.986 0 0 1 .281.68v2.807a.962.962 0 0 1-1.922 0V3.923H4.83a.919.919 0 0 0-.916.916v14.346c0 .51.413.915.916.915h14.346a.914.914 0 0 0 .916-.915V4.839a.942.942 0 0 0-.275-.649s-.214-.206-.48-.252c-.032-.008-.07-.008-.07-.008-.03 0-.061-.007-.09-.007h-2.504a.967.967 0 0 1-.96-.962c0-.526.434-.961.96-.961h3.41A1.907 1.907 0 0 1 22 3.915Z"/></svg>
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" width="1em" height="1em"><path d="M16.455 10.658c0 1.09-.705 2.244-2.098 3.443a13.447 13.447 0 0 1-2.381 1.62 14.102 14.102 0 0 1-2.381-1.629c-1.4-1.2-2.106-2.353-2.106-3.443 0-1.346.887-2.298 2.106-2.298.558 0 .888.054 1.263.238.22.1.412.237.577.403l.541.55.532-.55a2.07 2.07 0 0 1 .586-.421c.366-.166.678-.22 1.254-.22 1.209.018 2.107.988 2.107 2.307Z" clip-rule="evenodd"/><path d="M22 3.915v16.17A1.911 1.911 0 0 1 20.085 22H3.915A1.911 1.911 0 0 1 2 20.085V3.915C2 2.855 2.854 2 3.915 2h8.066c.267 0 .503.107.68.282a.986.986 0 0 1 .281.68v2.807a.962.962 0 0 1-1.922 0V3.923H4.83a.919.919 0 0 0-.916.916v14.346c0 .51.413.915.916.915h14.346a.914.914 0 0 0 .916-.915V4.839a.942.942 0 0 0-.275-.649s-.214-.206-.48-.252c-.032-.008-.07-.008-.07-.008-.03 0-.061-.007-.09-.007h-2.504a.967.967 0 0 1-.96-.962c0-.526.434-.961.96-.961h3.41A1.907 1.907 0 0 1 22 3.915Z"/></svg>
|
Before Width: | Height: | Size: 915 B After Width: | Height: | Size: 915 B |
|
@ -1 +1 @@
|
|||
<svg viewBox="0 0 24 24" fill="currentColor" width="1em" height="1em"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10s10-4.48 10-10S17.52 2 12 2m4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19c-.14.75-.42 1-.68 1.03c-.58.05-1.02-.38-1.58-.75c-.88-.58-1.38-.94-2.23-1.5c-.99-.65-.35-1.01.22-1.59c.15-.15 2.71-2.48 2.76-2.69a.2.2 0 0 0-.05-.18c-.06-.05-.14-.03-.21-.02c-.09.02-1.49.95-4.22 2.79c-.4.27-.76.41-1.08.4c-.36-.01-1.04-.2-1.55-.37c-.63-.2-1.12-.31-1.08-.66c.02-.18.27-.36.74-.55c2.92-1.27 4.86-2.11 5.83-2.51c2.78-1.16 3.35-1.36 3.73-1.36c.08 0 .27.02.39.12c.1.08.13.19.14.27c-.01.06.01.24 0 .38"/></svg>
|
||||
<svg fill="currentColor" viewBox="0 0 24 24" width="1em" height="1em"><path fill="currentColor" d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10s10-4.48 10-10S17.52 2 12 2m4.64 6.8c-.15 1.58-.8 5.42-1.13 7.19c-.14.75-.42 1-.68 1.03c-.58.05-1.02-.38-1.58-.75c-.88-.58-1.38-.94-2.23-1.5c-.99-.65-.35-1.01.22-1.59c.15-.15 2.71-2.48 2.76-2.69a.2.2 0 0 0-.05-.18c-.06-.05-.14-.03-.21-.02c-.09.02-1.49.95-4.22 2.79c-.4.27-.76.41-1.08.4c-.36-.01-1.04-.2-1.55-.37c-.63-.2-1.12-.31-1.08-.66c.02-.18.27-.36.74-.55c2.92-1.27 4.86-2.11 5.83-2.51c2.78-1.16 3.35-1.36 3.73-1.36c.08 0 .27.02.39.12c.1.08.13.19.14.27c-.01.06.01.24 0 .38"/></svg>
|
Before Width: | Height: | Size: 622 B After Width: | Height: | Size: 622 B |
|
@ -53,7 +53,7 @@ abstract class BasePlugin implements PluginInterface
|
|||
*/
|
||||
public function __set(string $name, array|string $value): void
|
||||
{
|
||||
$this->{$name} = $name === 'releaseDate' ? Time::createFromFormat('Y-m-d', $value) : $value;
|
||||
$this->{$name} = $value;
|
||||
}
|
||||
|
||||
public function init(): void
|
||||
|
@ -161,14 +161,17 @@ abstract class BasePlugin implements PluginInterface
|
|||
|
||||
if (array_key_exists('settings', $manifest)) {
|
||||
$fieldRules = [
|
||||
'key' => 'required|alpha_numeric',
|
||||
'name' => 'required|max_length[32]',
|
||||
'description' => 'permit_empty|max_length[128]',
|
||||
'key' => 'required|alpha_numeric',
|
||||
'label' => 'required|max_length[32]',
|
||||
'hint' => 'permit_empty|max_length[128]',
|
||||
'helper' => 'permit_empty|max_length[128]',
|
||||
];
|
||||
$defaultField = [
|
||||
'key' => '',
|
||||
'name' => '',
|
||||
'description' => '',
|
||||
'key' => '',
|
||||
'label' => '',
|
||||
'hint' => '',
|
||||
'helper' => '',
|
||||
'optional' => false,
|
||||
];
|
||||
$validation->setRules($fieldRules);
|
||||
foreach ($manifest['settings'] as $key => $settings) {
|
||||
|
@ -185,14 +188,12 @@ abstract class BasePlugin implements PluginInterface
|
|||
$rules = [
|
||||
'name' => 'required|max_length[32]',
|
||||
'version' => 'required|regex_match[/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/]',
|
||||
'compatible' => 'required|in_list[1.0]',
|
||||
'description' => 'max_length[128]',
|
||||
'releaseDate' => 'valid_date[Y-m-d]',
|
||||
'license' => 'in_list[MIT]',
|
||||
'author.name' => 'permit_empty|max_length[32]',
|
||||
'author.email' => 'permit_empty|valid_email',
|
||||
'author.url' => 'permit_empty|valid_url_strict',
|
||||
'website' => 'valid_url_strict',
|
||||
'homepage' => 'valid_url_strict',
|
||||
'keywords.*' => 'permit_empty|in_list[seo,podcasting20,analytics]',
|
||||
'hooks.*' => 'permit_empty|in_list[' . implode(',', Plugins::HOOKS) . ']',
|
||||
'settings' => 'permit_empty',
|
||||
|
@ -206,10 +207,9 @@ abstract class BasePlugin implements PluginInterface
|
|||
|
||||
$defaultAttributes = [
|
||||
'description' => '',
|
||||
'releaseDate' => '',
|
||||
'license' => '',
|
||||
'author' => [],
|
||||
'website' => '',
|
||||
'homepage' => '',
|
||||
'hooks' => [],
|
||||
'keywords' => [],
|
||||
'settings' => [
|
||||
|
|
|
@ -0,0 +1,191 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "/schemas/manifest.json",
|
||||
"title": "JSON schema for Castopod Plugins's manifest.json files",
|
||||
"description": "The Castopod plugin manifest defines both metadata and behavior of a plugin",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "The plugin name, including 'vendor-name/' prefix",
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9]([_.-]?[a-z0-9]+)*/[a-z0-9]([_.-]?[a-z0-9]+)*$",
|
||||
"examples": ["acme/hello-world"]
|
||||
},
|
||||
"version": {
|
||||
"description": "The plugin's semantic version. See https://semver.org/",
|
||||
"type": "string",
|
||||
"pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$",
|
||||
"examples": ["1.0.0"]
|
||||
},
|
||||
"description": {
|
||||
"description": "This helps people discover your plugin as it's listed in repositories",
|
||||
"type": "string"
|
||||
},
|
||||
"author": {
|
||||
"$ref": "#/$defs/person"
|
||||
},
|
||||
"authors": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/person"
|
||||
}
|
||||
},
|
||||
"homepage": {
|
||||
"description": "The URL to the plugin homepage",
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"license": {
|
||||
"description": "You should specify a license for your plugin so that people know how they are permitted to use it, and any restrictions you're placing on it.",
|
||||
"default": "UNLICENSED",
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"AGPL-3.0-only",
|
||||
"AGPL-3.0-or-later",
|
||||
"Apache-2.0",
|
||||
"BSL-1.0",
|
||||
"GPL-3.0-only",
|
||||
"GPL-3.0-or-later",
|
||||
"LGPL-3.0-only",
|
||||
"LGPL-3.0-or-later",
|
||||
"MIT",
|
||||
"MPL-2.0",
|
||||
"Unlicense",
|
||||
"UNLICENSED"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"private": {
|
||||
"type": "boolean",
|
||||
"description": "If set to true, then repositories should refuse to publish it."
|
||||
},
|
||||
"keywords": {
|
||||
"description": "This helps people discover your plugin as it's listed in repositories",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"accessibility",
|
||||
"analytics",
|
||||
"monetization",
|
||||
"podcasting2",
|
||||
"privacy",
|
||||
"seo"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"hooks": {
|
||||
"description": "The hooks used by the plugin.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"enum": ["channelTag", "itemTag", "siteHead"]
|
||||
},
|
||||
"uniqueItems": true
|
||||
},
|
||||
"settings": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"general": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/settings-field"
|
||||
}
|
||||
},
|
||||
"podcast": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/settings-field"
|
||||
}
|
||||
},
|
||||
"episode": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/$defs/settings-field"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"files": {
|
||||
"description": "List of files to include in your plugin package. If you include a folder in the array, all files inside it will also be included.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"description": "Specify the place where your plugin code lives. This is helpful for people who want to contribute.",
|
||||
"type": ["object", "string"],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"type": "string"
|
||||
},
|
||||
"directory": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["name", "version"],
|
||||
"additionalProperties": false,
|
||||
"$defs": {
|
||||
"person": {
|
||||
"description": "A person who has been involved in creating or maintaining this plugin.",
|
||||
"type": ["object", "string"],
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string",
|
||||
"format": "email"
|
||||
},
|
||||
"url": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
}
|
||||
}
|
||||
},
|
||||
"settings-field": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["text", "email", "url", "markdown", "number", "switch"],
|
||||
"default": "text"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"type": "string"
|
||||
},
|
||||
"hint": {
|
||||
"type": "string"
|
||||
},
|
||||
"helper": {
|
||||
"type": "string"
|
||||
},
|
||||
"optional": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": ["key", "label"],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
<p class="mt-2 text-gray-600"><?= $plugin->getDescription() ?></p>
|
||||
</div>
|
||||
<footer class="flex items-center justify-between mt-4">
|
||||
<a href="<?= $plugin->website ?>" class="inline-flex items-center text-sm font-semibold underline hover:no-underline gap-x-1" target="_blank" rel="noopener noreferrer"><?= icon('link', [
|
||||
<a href="<?= $plugin->homepage ?>" class="inline-flex items-center text-sm font-semibold underline hover:no-underline gap-x-1" target="_blank" rel="noopener noreferrer"><?= icon('link', [
|
||||
'class' => 'text-gray-500',
|
||||
]) . lang('Plugins.website') ?></a>
|
||||
<div class="flex gap-x-2">
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
<?= csrf_field() ?>
|
||||
<?php foreach ($plugin->settings[$type] as $field): ?>
|
||||
<Forms.Field
|
||||
name="<?= $field['key'] ?>"
|
||||
label="<?= $field['name'] ?>"
|
||||
hint="<?= $field['description'] ?>"
|
||||
name="<?= esc($field['key']) ?>"
|
||||
label="<?= esc($field['label']) ?>"
|
||||
hint="<?= esc($field['hint']) ?>"
|
||||
helper="<?= esc($field['helper']) ?>"
|
||||
required="<?= $field['optional'] === 'true' ? 'false' : 'true' ?>"
|
||||
value="<?= get_plugin_option($plugin->getKey(), $field['key'], $context) ?>"
|
||||
/>
|
||||
<?php endforeach; ?>
|
||||
|
|
Loading…
Reference in New Issue