1use super::ids::{ExportId, ImportId};
3use serde_json::{Number, Value as JsonValue};
4use std::collections::HashMap;
5
6#[derive(Debug, Clone, PartialEq)]
8pub enum Expression {
9 Null,
11 Bool(bool),
12 Number(Number),
13 String(String),
14 Array(Vec<Expression>),
15 Object(std::collections::HashMap<String, Box<Expression>>),
16
17 EscapedArray(Vec<Expression>),
19 Date(f64),
20 Error(ErrorExpression),
21 Import(ImportExpression),
22 Pipeline(PipelineExpression),
23 Remap(RemapExpression),
24 Export(ExportExpression),
25 Promise(PromiseExpression),
26}
27
28impl Expression {
29 pub fn from_json(value: &JsonValue) -> Result<Self, ExpressionError> {
31 match value {
32 JsonValue::Null => Ok(Expression::Null),
33 JsonValue::Bool(b) => Ok(Expression::Bool(*b)),
34 JsonValue::Number(n) => Ok(Expression::Number(n.clone())),
35 JsonValue::String(s) => Ok(Expression::String(s.clone())),
36
37 JsonValue::Array(arr) if arr.is_empty() => Ok(Expression::Array(Vec::new())),
38
39 JsonValue::Array(arr) => {
40 if let Some(JsonValue::String(type_code)) = arr.first() {
42 Self::parse_typed_array(type_code, arr)
43 } else if let Some(JsonValue::Array(inner)) = arr.first() {
44 if arr.len() == 1 {
46 let elements = inner
47 .iter()
48 .map(Self::from_json)
49 .collect::<Result<Vec<_>, _>>()?;
50 Ok(Expression::EscapedArray(elements))
51 } else {
52 let elements = arr
54 .iter()
55 .map(Self::from_json)
56 .collect::<Result<Vec<_>, _>>()?;
57 Ok(Expression::Array(elements))
58 }
59 } else {
60 let elements = arr
62 .iter()
63 .map(Self::from_json)
64 .collect::<Result<Vec<_>, _>>()?;
65 Ok(Expression::Array(elements))
66 }
67 }
68
69 JsonValue::Object(obj) => {
70 let mut map = HashMap::new();
71 for (key, val) in obj {
72 map.insert(key.clone(), Box::new(Self::from_json(val)?));
73 }
74 Ok(Expression::Object(map))
75 }
76 }
77 }
78
79 pub fn to_json(&self) -> JsonValue {
81 match self {
82 Expression::Null => JsonValue::Null,
83 Expression::Bool(b) => JsonValue::Bool(*b),
84 Expression::Number(n) => JsonValue::Number(n.clone()),
85 Expression::String(s) => JsonValue::String(s.clone()),
86
87 Expression::Array(elements) => {
88 JsonValue::Array(elements.iter().map(|e| e.to_json()).collect())
89 }
90
91 Expression::Object(map) => {
92 let mut obj = serde_json::Map::new();
93 for (key, val) in map {
94 obj.insert(key.clone(), val.to_json());
95 }
96 JsonValue::Object(obj)
97 }
98
99 Expression::EscapedArray(elements) => {
100 let inner = elements.iter().map(|e| e.to_json()).collect();
102 JsonValue::Array(vec![JsonValue::Array(inner)])
103 }
104
105 Expression::Date(millis) => {
106 serde_json::json!(["date", millis])
107 }
108
109 Expression::Error(err) => {
110 if let Some(stack) = &err.stack {
111 serde_json::json!(["error", &err.error_type, &err.message, stack])
112 } else {
113 serde_json::json!(["error", &err.error_type, &err.message])
114 }
115 }
116
117 Expression::Import(import) => import.to_json(),
118 Expression::Pipeline(pipeline) => pipeline.to_json(),
119 Expression::Remap(remap) => remap.to_json(),
120 Expression::Export(export) => export.to_json(),
121 Expression::Promise(promise) => promise.to_json(),
122 }
123 }
124
125 fn parse_typed_array(type_code: &str, arr: &[JsonValue]) -> Result<Self, ExpressionError> {
126 match type_code {
127 "date" => {
128 if arr.len() != 2 {
129 return Err(ExpressionError::InvalidDate);
130 }
131 let millis = arr[1].as_f64().ok_or(ExpressionError::InvalidDate)?;
132 Ok(Expression::Date(millis))
133 }
134
135 "error" => {
136 if arr.len() < 3 || arr.len() > 4 {
137 return Err(ExpressionError::InvalidError);
138 }
139 let error_type = arr[1]
140 .as_str()
141 .ok_or(ExpressionError::InvalidError)?
142 .to_string();
143 let message = arr[2]
144 .as_str()
145 .ok_or(ExpressionError::InvalidError)?
146 .to_string();
147 let stack = arr.get(3).and_then(|v| v.as_str()).map(String::from);
148
149 Ok(Expression::Error(ErrorExpression {
150 error_type,
151 message,
152 stack,
153 }))
154 }
155
156 "import" => ImportExpression::from_array(arr).map(Expression::Import),
157
158 "pipeline" => PipelineExpression::from_array(arr).map(Expression::Pipeline),
159
160 "remap" => RemapExpression::from_array(arr).map(Expression::Remap),
161
162 "export" => ExportExpression::from_array(arr).map(Expression::Export),
163
164 "promise" => PromiseExpression::from_array(arr).map(Expression::Promise),
165
166 _ => {
167 let elements = arr
169 .iter()
170 .map(Self::from_json)
171 .collect::<Result<Vec<_>, _>>()?;
172 Ok(Expression::Array(elements))
173 }
174 }
175 }
176}
177
178#[derive(Debug, Clone, PartialEq)]
179pub struct ErrorExpression {
180 pub error_type: String,
181 pub message: String,
182 pub stack: Option<String>,
183}
184
185#[derive(Debug, Clone, PartialEq)]
186pub struct ImportExpression {
187 pub import_id: ImportId,
188 pub property_path: Option<Vec<PropertyKey>>,
189 pub call_arguments: Option<Box<Expression>>,
190}
191
192impl ImportExpression {
193 fn from_array(arr: &[JsonValue]) -> Result<Self, ExpressionError> {
194 if arr.len() < 2 || arr.len() > 4 {
195 return Err(ExpressionError::InvalidImport);
196 }
197
198 let import_id = arr[1].as_i64().ok_or(ExpressionError::InvalidImport)?;
199
200 let property_path = arr.get(2).map(PropertyKey::parse_path).transpose()?;
201
202 let call_arguments = arr
203 .get(3)
204 .map(|v| Expression::from_json(v).map(Box::new))
205 .transpose()?;
206
207 Ok(ImportExpression {
208 import_id: ImportId(import_id),
209 property_path,
210 call_arguments,
211 })
212 }
213
214 fn to_json(&self) -> JsonValue {
215 let mut arr = vec![
216 JsonValue::String("import".to_string()),
217 JsonValue::Number(Number::from(self.import_id.0)),
218 ];
219
220 if let Some(path) = &self.property_path {
221 arr.push(PropertyKey::path_to_json(path));
222 }
223
224 if let Some(args) = &self.call_arguments {
225 arr.push(args.to_json());
226 }
227
228 JsonValue::Array(arr)
229 }
230}
231
232#[derive(Debug, Clone, PartialEq)]
233pub struct PipelineExpression {
234 pub import_id: ImportId,
235 pub property_path: Option<Vec<PropertyKey>>,
236 pub call_arguments: Option<Box<Expression>>,
237}
238
239impl PipelineExpression {
240 fn from_array(arr: &[JsonValue]) -> Result<Self, ExpressionError> {
241 if arr.len() < 2 || arr.len() > 4 {
242 return Err(ExpressionError::InvalidPipeline);
243 }
244
245 let import_id = arr[1].as_i64().ok_or(ExpressionError::InvalidPipeline)?;
246
247 let property_path = arr.get(2).map(PropertyKey::parse_path).transpose()?;
248
249 let call_arguments = arr
250 .get(3)
251 .map(|v| Expression::from_json(v).map(Box::new))
252 .transpose()?;
253
254 Ok(PipelineExpression {
255 import_id: ImportId(import_id),
256 property_path,
257 call_arguments,
258 })
259 }
260
261 fn to_json(&self) -> JsonValue {
262 let mut arr = vec![
263 JsonValue::String("pipeline".to_string()),
264 JsonValue::Number(Number::from(self.import_id.0)),
265 ];
266
267 if let Some(path) = &self.property_path {
268 arr.push(PropertyKey::path_to_json(path));
269 }
270
271 if let Some(args) = &self.call_arguments {
272 arr.push(args.to_json());
273 }
274
275 JsonValue::Array(arr)
276 }
277}
278
279#[derive(Debug, Clone, PartialEq)]
280pub struct RemapExpression {
281 pub import_id: ImportId,
282 pub property_path: Option<Vec<PropertyKey>>,
283 pub captures: Vec<CaptureRef>,
284 pub instructions: Vec<Expression>,
285}
286
287impl RemapExpression {
288 fn from_array(arr: &[JsonValue]) -> Result<Self, ExpressionError> {
289 if arr.len() != 5 {
290 return Err(ExpressionError::InvalidRemap);
291 }
292
293 let import_id = arr[1].as_i64().ok_or(ExpressionError::InvalidRemap)?;
294
295 let property_path = if !arr[2].is_null() {
296 Some(PropertyKey::parse_path(&arr[2])?)
297 } else {
298 None
299 };
300
301 let captures = arr[3]
302 .as_array()
303 .ok_or(ExpressionError::InvalidRemap)?
304 .iter()
305 .map(CaptureRef::from_json)
306 .collect::<Result<Vec<_>, _>>()?;
307
308 let instructions = arr[4]
309 .as_array()
310 .ok_or(ExpressionError::InvalidRemap)?
311 .iter()
312 .map(Expression::from_json)
313 .collect::<Result<Vec<_>, _>>()?;
314
315 Ok(RemapExpression {
316 import_id: ImportId(import_id),
317 property_path,
318 captures,
319 instructions,
320 })
321 }
322
323 fn to_json(&self) -> JsonValue {
324 let path = self
325 .property_path
326 .as_ref()
327 .map(|p| PropertyKey::path_to_json(p))
328 .unwrap_or(JsonValue::Null);
329
330 let captures: Vec<JsonValue> = self.captures.iter().map(|c| c.to_json()).collect();
331
332 let instructions: Vec<JsonValue> = self.instructions.iter().map(|i| i.to_json()).collect();
333
334 serde_json::json!(["remap", self.import_id.0, path, captures, instructions])
335 }
336}
337
338#[derive(Debug, Clone, PartialEq)]
339pub struct ExportExpression {
340 pub export_id: ExportId,
341}
342
343impl ExportExpression {
344 fn from_array(arr: &[JsonValue]) -> Result<Self, ExpressionError> {
345 if arr.len() != 2 {
346 return Err(ExpressionError::InvalidExport);
347 }
348
349 let export_id = arr[1].as_i64().ok_or(ExpressionError::InvalidExport)?;
350
351 Ok(ExportExpression {
352 export_id: ExportId(export_id),
353 })
354 }
355
356 fn to_json(&self) -> JsonValue {
357 serde_json::json!(["export", self.export_id.0])
358 }
359}
360
361#[derive(Debug, Clone, PartialEq)]
362pub struct PromiseExpression {
363 pub export_id: ExportId,
364}
365
366impl PromiseExpression {
367 fn from_array(arr: &[JsonValue]) -> Result<Self, ExpressionError> {
368 if arr.len() != 2 {
369 return Err(ExpressionError::InvalidPromise);
370 }
371
372 let export_id = arr[1].as_i64().ok_or(ExpressionError::InvalidPromise)?;
373
374 Ok(PromiseExpression {
375 export_id: ExportId(export_id),
376 })
377 }
378
379 fn to_json(&self) -> JsonValue {
380 serde_json::json!(["promise", self.export_id.0])
381 }
382}
383
384#[derive(Debug, Clone, PartialEq)]
385pub enum PropertyKey {
386 String(String),
387 Number(usize),
388}
389
390impl PropertyKey {
391 fn parse_path(value: &JsonValue) -> Result<Vec<PropertyKey>, ExpressionError> {
392 let arr = value
393 .as_array()
394 .ok_or(ExpressionError::InvalidPropertyPath)?;
395
396 arr.iter()
397 .map(|v| {
398 if let Some(s) = v.as_str() {
399 Ok(PropertyKey::String(s.to_string()))
400 } else if let Some(n) = v.as_u64() {
401 Ok(PropertyKey::Number(n as usize))
402 } else {
403 Err(ExpressionError::InvalidPropertyPath)
404 }
405 })
406 .collect()
407 }
408
409 fn path_to_json(path: &[PropertyKey]) -> JsonValue {
410 let elements: Vec<JsonValue> = path
411 .iter()
412 .map(|key| match key {
413 PropertyKey::String(s) => JsonValue::String(s.clone()),
414 PropertyKey::Number(n) => JsonValue::Number(Number::from(*n)),
415 })
416 .collect();
417
418 JsonValue::Array(elements)
419 }
420}
421
422#[derive(Debug, Clone, PartialEq)]
423pub enum CaptureRef {
424 Import(ImportId),
425 Export(ExportId),
426}
427
428impl CaptureRef {
429 fn from_json(value: &JsonValue) -> Result<Self, ExpressionError> {
430 let arr = value.as_array().ok_or(ExpressionError::InvalidCapture)?;
431
432 if arr.len() != 2 {
433 return Err(ExpressionError::InvalidCapture);
434 }
435
436 let type_str = arr[0].as_str().ok_or(ExpressionError::InvalidCapture)?;
437
438 let id = arr[1].as_i64().ok_or(ExpressionError::InvalidCapture)?;
439
440 match type_str {
441 "import" => Ok(CaptureRef::Import(ImportId(id))),
442 "export" => Ok(CaptureRef::Export(ExportId(id))),
443 _ => Err(ExpressionError::InvalidCapture),
444 }
445 }
446
447 fn to_json(&self) -> JsonValue {
448 match self {
449 CaptureRef::Import(id) => serde_json::json!(["import", id.0]),
450 CaptureRef::Export(id) => serde_json::json!(["export", id.0]),
451 }
452 }
453}
454
455#[derive(Debug, thiserror::Error)]
456pub enum ExpressionError {
457 #[error("Invalid date expression")]
458 InvalidDate,
459
460 #[error("Invalid error expression")]
461 InvalidError,
462
463 #[error("Invalid import expression")]
464 InvalidImport,
465
466 #[error("Invalid pipeline expression")]
467 InvalidPipeline,
468
469 #[error("Invalid remap expression")]
470 InvalidRemap,
471
472 #[error("Invalid export expression")]
473 InvalidExport,
474
475 #[error("Invalid promise expression")]
476 InvalidPromise,
477
478 #[error("Invalid property path")]
479 InvalidPropertyPath,
480
481 #[error("Invalid capture reference")]
482 InvalidCapture,
483}
484
485#[cfg(test)]
486mod tests {
487 use super::*;
488 use serde_json::json;
489
490 #[test]
491 fn test_literal_expressions() {
492 assert_eq!(
493 Expression::from_json(&json!(null)).unwrap(),
494 Expression::Null
495 );
496
497 assert_eq!(
498 Expression::from_json(&json!(true)).unwrap(),
499 Expression::Bool(true)
500 );
501
502 assert_eq!(
503 Expression::from_json(&json!(42)).unwrap(),
504 Expression::Number(Number::from(42))
505 );
506
507 assert_eq!(
508 Expression::from_json(&json!("hello")).unwrap(),
509 Expression::String("hello".to_string())
510 );
511 }
512
513 #[test]
514 fn test_date_expression() {
515 let json = json!(["date", 1234567890.0]);
516 let expr = Expression::from_json(&json).unwrap();
517
518 match expr {
519 Expression::Date(millis) => assert_eq!(millis, 1234567890.0),
520 _ => panic!("Expected Date expression"),
521 }
522
523 assert_eq!(expr.to_json(), json);
524 }
525
526 #[test]
527 fn test_error_expression() {
528 let json = json!(["error", "TypeError", "Something went wrong", "stack trace"]);
529 let expr = Expression::from_json(&json).unwrap();
530
531 match expr {
532 Expression::Error(err) => {
533 assert_eq!(err.error_type, "TypeError");
534 assert_eq!(err.message, "Something went wrong");
535 assert_eq!(err.stack, Some("stack trace".to_string()));
536 }
537 _ => panic!("Expected Error expression"),
538 }
539 }
540
541 #[test]
542 fn test_import_expression() {
543 let json = json!(["import", 42, ["method"], [1, 2, 3]]);
544 let expr = Expression::from_json(&json).unwrap();
545
546 match expr {
547 Expression::Import(import) => {
548 assert_eq!(import.import_id, ImportId(42));
549 assert_eq!(
550 import.property_path,
551 Some(vec![PropertyKey::String("method".to_string())])
552 );
553 assert!(import.call_arguments.is_some());
554 }
555 _ => panic!("Expected Import expression"),
556 }
557 }
558
559 #[test]
560 fn test_escaped_array() {
561 let json = json!([["just", "an", "array"]]);
562 let expr = Expression::from_json(&json).unwrap();
563
564 match expr {
565 Expression::EscapedArray(elements) => {
566 assert_eq!(elements.len(), 3);
567 assert_eq!(elements[0], Expression::String("just".to_string()));
568 }
569 _ => panic!("Expected EscapedArray expression"),
570 }
571 }
572}