1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Serialize, Deserialize)]
4pub struct AddonManifest {
5 pub schema_version: String,
6 pub id: String,
7 pub name: String,
8 pub version: String,
9 pub description: String,
10 pub author: String,
11 #[serde(default)]
12 pub requires: Vec<String>,
13 #[serde(default)]
14 pub inputs: Vec<InputDef>,
15 #[serde(default)]
16 pub detect: Vec<DetectBlock>,
17 #[serde(default)]
18 pub variants: Vec<Variant>,
19}
20
21#[derive(Debug, Serialize, Deserialize)]
22pub struct InputDef {
23 pub name: String,
24 #[serde(rename = "type")]
25 pub input_type: InputType,
26 #[serde(default)]
27 pub description: String,
28 pub default: Option<String>,
29 #[serde(default)]
30 pub required: bool,
31 #[serde(default)]
32 pub options: Vec<String>,
33}
34
35#[derive(Debug, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case")]
37pub enum InputType {
38 Text,
39 Boolean,
40 Select,
41}
42
43#[derive(Debug, Serialize, Deserialize)]
44pub struct DetectBlock {
45 pub id: String,
46 pub rules: Vec<DetectRule>,
47 #[serde(rename = "match", default)]
48 pub match_mode: MatchMode,
49}
50
51#[derive(Debug, Serialize, Deserialize)]
52#[serde(tag = "type", rename_all = "snake_case")]
53pub enum DetectRule {
54 FileExists {
55 file: String,
56 #[serde(default)]
57 negate: bool,
58 },
59 FileContains {
60 file: String,
61 contains: String,
62 #[serde(default)]
63 negate: bool,
64 },
65 JsonContains {
66 file: String,
67 key_path: String,
68 value: Option<String>,
69 #[serde(default)]
70 negate: bool,
71 },
72 TomlContains {
73 file: String,
74 key_path: String,
75 value: Option<String>,
76 #[serde(default)]
77 negate: bool,
78 },
79 YamlContains {
80 file: String,
81 key_path: String,
82 value: Option<String>,
83 #[serde(default)]
84 negate: bool,
85 },
86}
87
88#[derive(Debug, Default, Serialize, Deserialize)]
89#[serde(rename_all = "snake_case")]
90pub enum MatchMode {
91 All,
92 #[default]
93 Any,
94}
95
96#[derive(Debug, Serialize, Deserialize)]
97pub struct Variant {
98 pub when: Option<String>,
99 #[serde(default)]
100 pub commands: Vec<AddonCommand>,
101}
102
103#[derive(Debug, Serialize, Deserialize)]
104pub struct AddonCommand {
105 pub name: String,
106 #[serde(default)]
107 pub description: String,
108 #[serde(default)]
109 pub once: bool,
110 #[serde(default)]
111 pub requires_commands: Vec<String>,
112 #[serde(default)]
113 pub steps: Vec<Step>,
114}
115
116#[derive(Debug, Serialize, Deserialize)]
117#[serde(tag = "type", rename_all = "snake_case")]
118pub enum Step {
119 Copy(CopyStep),
120 Create(CreateStep),
121 Inject(InjectStep),
122 Replace(ReplaceStep),
123 Append(AppendStep),
124 Delete(DeleteStep),
125 Rename(RenameStep),
126 Move(MoveStep),
127}
128
129#[derive(Debug, Serialize, Deserialize)]
130pub struct CopyStep {
131 pub src: String,
132 pub dest: String,
133 #[serde(default)]
134 pub if_exists: IfExists,
135}
136
137#[derive(Debug, Serialize, Deserialize)]
138pub struct CreateStep {
139 pub path: String,
140 pub content: String,
141 #[serde(default)]
142 pub if_exists: IfExists,
143}
144
145#[derive(Debug, Serialize, Deserialize)]
146pub struct InjectStep {
147 pub target: Target,
148 pub content: String,
149 pub after: Option<String>,
150 pub before: Option<String>,
151 #[serde(default)]
152 pub if_not_found: IfNotFound,
153}
154
155#[derive(Debug, Serialize, Deserialize)]
156pub struct ReplaceStep {
157 pub target: Target,
158 pub find: String,
159 pub replace: String,
160 #[serde(default)]
161 pub if_not_found: IfNotFound,
162}
163
164#[derive(Debug, Serialize, Deserialize)]
165pub struct AppendStep {
166 pub target: Target,
167 pub content: String,
168}
169
170#[derive(Debug, Serialize, Deserialize)]
171pub struct DeleteStep {
172 pub target: Target,
173}
174
175#[derive(Debug, Serialize, Deserialize)]
176pub struct RenameStep {
177 pub from: String,
178 pub to: String,
179}
180
181#[derive(Debug, Serialize, Deserialize)]
182pub struct MoveStep {
183 pub from: String,
184 pub to: String,
185}
186
187#[derive(Debug, Serialize, Deserialize)]
188#[serde(rename_all = "snake_case")]
189pub enum Target {
190 File { file: String },
191 Glob { glob: String },
192}
193
194#[derive(Debug, Default, Serialize, Deserialize)]
195#[serde(rename_all = "snake_case")]
196pub enum IfExists {
197 Ask,
198 #[default]
199 Overwrite,
200 Skip,
201}
202
203#[derive(Debug, Default, Serialize, Deserialize)]
204#[serde(rename_all = "snake_case")]
205pub enum IfNotFound {
206 #[default]
207 WarnAndAsk,
208 Skip,
209 Error,
210}