1use super::value::Value;
2use super::errors::*;
3use js_sandbox::{Script, AnyError};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::fs;
7
8#[derive(Deserialize, Serialize, Clone)]
10pub struct ExtensionTable(HashMap<String, Extension>);
11impl ExtensionTable {
12 pub fn new() -> Self {
14 Self(HashMap::new())
15 }
16
17 pub fn add(&mut self, filename: &str, extension: Extension) {
23 self.0.insert(filename.to_string(), extension);
24 }
25
26 pub fn load(&mut self, filename: &str) -> Result<Extension, ParserError> {
31 let e = Extension::new(filename)?;
32 self.0.insert(filename.to_string(), e.clone());
33 Ok(e)
34 }
35
36 pub fn load_all(&mut self, path: &str) -> Result<Vec<Extension>, ParserError> {
38 let e = Extension::load_all(path)?;
39 for extension in &e {
40 self.0.insert(extension.filename().to_string(), extension.clone());
41 }
42 Ok(e)
43 }
44
45 pub fn remove(&mut self, filename: &str) {
47 self.0.remove(filename);
48 }
49
50 pub fn all(&self) -> Vec<Extension> {
52 Vec::from_iter(self.0.values().cloned())
53 }
54
55 pub fn has_function(&self, name: &str) -> bool {
60 for extension in self.all() {
61 if extension.has_function(name) {
62 return true;
63 }
64 }
65 false
66 }
67
68 pub fn call_function(&self, name: &str, args: &[Value]) -> Result<Value, ParserError> {
70 for mut extension in self.all() {
71 if extension.has_function(name) {
72 return extension.call_function(name, args);
73 }
74 }
75 Err(ParserError::FunctionName(FunctionNameError::new(name)))
76 }
77
78 pub fn has_decorator(&self, name: &str) -> bool {
83 for extension in self.all() {
84 if extension.has_decorator(name) {
85 return true;
86 }
87 }
88 false
89 }
90
91 pub fn call_decorator(&self, name: &str, arg: &Value) -> Result<String, ParserError> {
93 for mut extension in self.all() {
94 if extension.has_decorator(name) {
95 return extension.call_decorator(name, arg);
96 }
97 }
98 Err(ParserError::FunctionName(FunctionNameError::new(&format!("@{}", name))))
99 }
100}
101impl Default for ExtensionTable {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107fn default_name() -> String { "Unnamed Extension".to_string() }
108fn default_author() -> String { "Anonymous".to_string() }
109fn default_version() -> String { "0.0.0".to_string() }
110
111#[derive(Deserialize, Serialize, Clone, Debug, Eq, PartialEq)]
117pub struct Extension {
118 #[serde(default)]
119 filename: String,
120
121 #[serde(default = "default_name")]
122 name: String,
123
124 #[serde(default = "default_author")]
125 author: String,
126
127 #[serde(default = "default_version")]
128 version: String,
129
130 #[serde(default)]
131 contents: String,
132
133 #[serde(default)]
134 functions: HashMap<String, String>,
135
136 #[serde(default)]
137 decorators: HashMap<String, String>
138}
139
140impl std::fmt::Display for Extension {
141 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
142 write!(f, "{} v{}, by {}", self.name, self.version, self.author)
143 }
144}
145
146unsafe impl Send for Extension {}
147impl Extension {
148 pub fn new(filename: &str) -> Result<Extension, std::io::Error> {
153 match fs::read_to_string(filename) {
154 Ok(s) => {
155 match script_from_string(filename, &s) {
156 Ok(v) => Ok(v),
157 Err(e) => Err(std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string()))
158 }
159 },
160 Err(e) => Err(e)
161 }
162 }
163
164 pub fn new_stub(name: Option<&str>, author: Option<&str>, version: Option<&str>, functions: Vec<String>, decorators: Vec<String>) -> Self {
174 let mut stub = Self {
175 name: name.unwrap_or(&default_name()).to_string(),
176 author: author.unwrap_or(&default_author()).to_string(),
177 version: version.unwrap_or(&default_version()).to_string(),
178 contents: "".to_string(),
179 filename: "".to_string(),
180 functions: HashMap::new(),
181 decorators: HashMap::new()
182 };
183
184 for f in functions { stub.functions.insert(f.clone(), f); }
185 for d in decorators { stub.decorators.insert(d.clone(), d); }
186
187 stub
188 }
189
190 pub fn load_all(directory: &str) -> Result<Vec<Extension>, std::io::Error> {
192 let mut extensions : Vec<Extension> = Vec::new();
193
194 match fs::read_dir(directory) {
195 Ok(entries) => {
196 for file in entries.flatten() {
197 if let Some(filename) = file.path().to_str() {
198 if let Ok(extension) = Extension::new(filename) {
199 if filename.ends_with("js") {
200 extensions.push(extension);
201 }
202 }
203 }
204 }
205 },
206 Err(e) => {
207 return Err(e);
208 }
209 }
210
211 Ok(extensions)
212 }
213
214 pub fn has_function(&self, name: &str) -> bool {
219 self.functions.contains_key(name)
220 }
221
222 pub fn load_script(&mut self) -> Result<Script, ParserError> {
224 match Script::from_string(&self.contents) {
225 Ok(s) => Ok(s),
226 Err(e) => Err(ParserError::Script(ScriptError::new(&e.to_string())))
227 }
228 }
229
230 pub fn call_function(&mut self, name: &str, args: &[Value]) -> Result<Value, ParserError> {
236 match self.load_script() {
237 Ok(mut script) => {
238 let fname = self.functions.get(name).ok_or_else(|| ParserError::FunctionName(FunctionNameError::new(name)))?;
239 let result : Result<Value, AnyError> = script.call(fname, &args.to_vec());
240 match result {
241 Ok(v) => Ok(v),
242 Err(e) => Err(ParserError::Script(ScriptError::new(&e.to_string())))
243 }
244 },
245 Err(e) => Err(e)
246 }
247 }
248
249 pub fn has_decorator(&self, name: &str) -> bool {
254 self.decorators.contains_key(name)
255 }
256
257 pub fn call_decorator(&mut self, name: &str, arg: &Value) -> Result<String, ParserError> {
263 match self.load_script() {
264 Ok(mut script) => {
265 let fname = self.decorators.get(name).ok_or_else(|| ParserError::DecoratorName(DecoratorNameError::new(name)))?;
266 let result : Result<String, AnyError> = script.call(fname, &arg);
267 match result {
268 Ok(v) => Ok(v),
269 Err(e) => Err(ParserError::Script(ScriptError::new(&e.to_string())))
270 }
271 },
272 Err(e) => Err(e)
273 }
274 }
275
276 pub fn filename(&self) -> &str {
278 &self.filename
279 }
280
281 pub fn name(&self) -> &str {
283 &self.name
284 }
285
286 pub fn author(&self) -> &str {
288 &self.author
289 }
290
291 pub fn version(&self) -> &str {
293 &self.version
294 }
295
296 pub fn functions(&self) -> Vec<String> {
298 self.functions.keys().cloned().collect()
299 }
300
301 pub fn decorators(&self) -> Vec<String> {
303 self.decorators.keys().cloned().collect()
304 }
305}
306
307fn script_from_string(filename: &str, code: &str) -> Result<Extension, AnyError> {
312 let mut script = Script::from_string(code)?;
313 let mut e : Extension = script.call("extension", &())?;
314 e.contents = code.to_string();
315 e.filename = filename.to_string();
316 Ok(e)
317}
318
319#[cfg(test)]
320mod test_extensions {
321 use super::*;
322
323 #[test]
324 fn test_new() {
325 let e = Extension::new("example_extensions/colour_utils.js").unwrap();
326 assert_eq!("HTML Colour Utilities", e.name);
327 }
328
329 #[test]
330 fn test_to_string() {
331 let e = Extension::new("example_extensions/colour_utils.js").unwrap();
332 assert_eq!("HTML Colour Utilities v0.2.0, by @rscarson", e.to_string());
333 }
334
335 #[test]
336 fn test_has_function() {
337 let e = Extension::new("example_extensions/colour_utils.js").unwrap();
338 assert_eq!(true, e.has_function("complement"));
339 assert_eq!(false, e.has_function("foobar"));
340 }
341
342 #[test]
343 fn test_call_function() {
344 let mut e = Extension::new("example_extensions/colour_utils.js").unwrap();
345 assert_eq!(Value::Integer(0x00FFFF), e.call_function("complement", &[Value::Integer(0xFFAA00)]).unwrap());
346 assert_eq!(Value::Integer(0xFFF), e.call_function("color", &[Value::String("white".to_string())]).unwrap());
347 }
348
349 #[test]
350 fn test_can_fail() {
351 let mut e = Extension::new("example_extensions/colour_utils.js").unwrap();
352 assert_eq!(true, matches!(e.call_function("complement", &[]), Err(_)));
353 }
354
355 #[test]
356 fn test_has_decorator() {
357 let e = Extension::new("example_extensions/colour_utils.js").unwrap();
358 assert_eq!(true, e.has_decorator("color"));
359 assert_eq!(false, e.has_decorator("foobar"));
360 }
361
362 #[test]
363 fn test_call_decorator() {
364 let mut e = Extension::new("example_extensions/colour_utils.js").unwrap();
365 assert_eq!("#ff0000", e.call_decorator("color", &Value::Integer(0xFF)).unwrap());
366 }
367
368 #[test]
369 fn test_load_all() {
370 let e = Extension::load_all("example_extensions").unwrap();
371 assert_eq!(true, e.len() > 0);
372 }
373
374 #[test]
375 fn test_color() {
376 let mut e = Extension::new("example_extensions/colour_utils.js").unwrap();
377 assert_eq!(Value::Integer(0x00FFFF), e.call_function("complement", &[Value::Integer(0xFFAA00)]).unwrap());
378 }
379}