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 inputs: Vec<InputDef>,
114 #[serde(default)]
115 pub steps: Vec<Step>,
116}
117
118#[derive(Debug, Serialize, Deserialize)]
119#[serde(tag = "type", rename_all = "snake_case")]
120pub enum Step {
121 Copy(CopyStep),
122 Create(CreateStep),
123 Inject(InjectStep),
124 Replace(ReplaceStep),
125 Append(AppendStep),
126 Delete(DeleteStep),
127 Rename(RenameStep),
128 Move(MoveStep),
129}
130
131#[derive(Debug, Serialize, Deserialize)]
132pub struct CopyStep {
133 pub src: String,
134 pub dest: String,
135 #[serde(default)]
136 pub if_exists: IfExists,
137}
138
139#[derive(Debug, Serialize, Deserialize)]
140pub struct CreateStep {
141 pub path: String,
142 pub content: String,
143 #[serde(default)]
144 pub if_exists: IfExists,
145}
146
147#[derive(Debug, Serialize, Deserialize)]
148pub struct InjectStep {
149 pub target: Target,
150 pub content: String,
151 pub after: Option<String>,
152 pub before: Option<String>,
153 #[serde(default)]
154 pub if_not_found: IfNotFound,
155}
156
157#[derive(Debug, Serialize, Deserialize)]
158pub struct ReplaceStep {
159 pub target: Target,
160 pub find: String,
161 pub replace: String,
162 #[serde(default)]
163 pub if_not_found: IfNotFound,
164}
165
166#[derive(Debug, Serialize, Deserialize)]
167pub struct AppendStep {
168 pub target: Target,
169 pub content: String,
170}
171
172#[derive(Debug, Serialize, Deserialize)]
173pub struct DeleteStep {
174 pub target: Target,
175}
176
177#[derive(Debug, Serialize, Deserialize)]
178pub struct RenameStep {
179 pub from: String,
180 pub to: String,
181}
182
183#[derive(Debug, Serialize, Deserialize)]
184pub struct MoveStep {
185 pub from: String,
186 pub to: String,
187}
188
189#[derive(Debug, Serialize, Deserialize)]
190#[serde(tag = "type", rename_all = "snake_case")]
191pub enum Target {
192 File { file: String },
193 Glob { glob: String },
194}
195
196#[derive(Debug, Default, Serialize, Deserialize)]
197#[serde(rename_all = "snake_case")]
198pub enum IfExists {
199 Ask,
200 #[default]
201 Overwrite,
202 Skip,
203}
204
205#[derive(Debug, Default, Serialize, Deserialize)]
206#[serde(rename_all = "snake_case")]
207pub enum IfNotFound {
208 #[default]
209 WarnAndAsk,
210 Skip,
211 Error,
212}