1mod decode;
50mod encode;
51
52use std::collections::HashMap;
53use std::fmt;
54
55pub use decode::decode_scopes;
56pub use encode::encode_scopes;
57
58use srcmap_codec::DecodeError;
59
60const TAG_ORIGINAL_SCOPE_START: u64 = 0x1;
63const TAG_ORIGINAL_SCOPE_END: u64 = 0x2;
64const TAG_ORIGINAL_SCOPE_VARIABLES: u64 = 0x3;
65const TAG_GENERATED_RANGE_START: u64 = 0x4;
66const TAG_GENERATED_RANGE_END: u64 = 0x5;
67const TAG_GENERATED_RANGE_BINDINGS: u64 = 0x6;
68const TAG_GENERATED_RANGE_SUB_RANGE_BINDINGS: u64 = 0x7;
69const TAG_GENERATED_RANGE_CALL_SITE: u64 = 0x8;
70
71const OS_FLAG_HAS_NAME: u64 = 0x1;
75const OS_FLAG_HAS_KIND: u64 = 0x2;
76const OS_FLAG_IS_STACK_FRAME: u64 = 0x4;
77
78const GR_FLAG_HAS_LINE: u64 = 0x1;
80const GR_FLAG_HAS_DEFINITION: u64 = 0x2;
81const GR_FLAG_IS_STACK_FRAME: u64 = 0x4;
82const GR_FLAG_IS_HIDDEN: u64 = 0x8;
83
84#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
88pub struct Position {
89 pub line: u32,
90 pub column: u32,
91}
92
93#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct OriginalScope {
96 pub start: Position,
97 pub end: Position,
98 pub name: Option<String>,
100 pub kind: Option<String>,
102 pub is_stack_frame: bool,
104 pub variables: Vec<String>,
106 pub children: Vec<OriginalScope>,
108}
109
110#[derive(Debug, Clone, PartialEq, Eq)]
112pub enum Binding {
113 Expression(String),
115 Unavailable,
117 SubRanges(Vec<SubRangeBinding>),
119}
120
121#[derive(Debug, Clone, PartialEq, Eq)]
123pub struct SubRangeBinding {
124 pub expression: Option<String>,
126 pub from: Position,
128}
129
130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
132pub struct CallSite {
133 pub source_index: u32,
134 pub line: u32,
135 pub column: u32,
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
140pub struct GeneratedRange {
141 pub start: Position,
142 pub end: Position,
143 pub is_stack_frame: bool,
145 pub is_hidden: bool,
147 pub definition: Option<u32>,
149 pub call_site: Option<CallSite>,
151 pub bindings: Vec<Binding>,
153 pub children: Vec<GeneratedRange>,
155}
156
157#[derive(Debug, Clone, PartialEq, Eq)]
159pub struct ScopeInfo {
160 pub scopes: Vec<Option<OriginalScope>>,
163 pub ranges: Vec<GeneratedRange>,
165}
166
167impl ScopeInfo {
168 pub fn original_scope_for_definition(&self, definition: u32) -> Option<&OriginalScope> {
173 let mut count = 0u32;
174 for scope in self.scopes.iter().flatten() {
175 if let Some(result) = find_nth_scope(scope, definition, &mut count) {
176 return Some(result);
177 }
178 }
179 None
180 }
181}
182
183fn find_nth_scope<'a>(
184 scope: &'a OriginalScope,
185 target: u32,
186 count: &mut u32,
187) -> Option<&'a OriginalScope> {
188 let mut stack: Vec<&'a OriginalScope> = vec![scope];
190
191 while let Some(node) = stack.pop() {
192 if *count == target {
193 return Some(node);
194 }
195 *count += 1;
196 for child in node.children.iter().rev() {
198 stack.push(child);
199 }
200 }
201 None
202}
203
204#[derive(Debug, Clone, PartialEq, Eq)]
208pub enum ScopesError {
209 Vlq(DecodeError),
211 UnmatchedScopeEnd,
213 UnclosedScope,
215 UnmatchedRangeEnd,
217 UnclosedRange,
219 InvalidNameIndex(i64),
221}
222
223impl fmt::Display for ScopesError {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 match self {
226 Self::Vlq(e) => write!(f, "VLQ decode error: {e}"),
227 Self::UnmatchedScopeEnd => write!(f, "scope end without matching start"),
228 Self::UnclosedScope => write!(f, "scope opened but never closed"),
229 Self::UnmatchedRangeEnd => write!(f, "range end without matching start"),
230 Self::UnclosedRange => write!(f, "range opened but never closed"),
231 Self::InvalidNameIndex(idx) => write!(f, "invalid name index: {idx}"),
232 }
233 }
234}
235
236impl std::error::Error for ScopesError {}
237
238impl From<DecodeError> for ScopesError {
239 fn from(e: DecodeError) -> Self {
240 Self::Vlq(e)
241 }
242}
243
244fn resolve_name(names: &[String], index: i64) -> Result<String, ScopesError> {
248 if index < 0 || index as usize >= names.len() {
249 return Err(ScopesError::InvalidNameIndex(index));
250 }
251 Ok(names[index as usize].clone())
252}
253
254fn resolve_binding(names: &[String], index: u64) -> Result<Option<String>, ScopesError> {
256 if index == 0 {
257 return Ok(None);
258 }
259 let actual = (index - 1) as usize;
260 if actual >= names.len() {
261 return Err(ScopesError::InvalidNameIndex(index as i64));
262 }
263 Ok(Some(names[actual].clone()))
264}
265
266fn resolve_or_add_name(
268 name: &str,
269 names: &mut Vec<String>,
270 name_map: &mut HashMap<String, u32>,
271) -> u32 {
272 if let Some(&idx) = name_map.get(name) {
273 return idx;
274 }
275 let idx = names.len() as u32;
276 names.push(name.to_string());
277 name_map.insert(name.to_string(), idx);
278 idx
279}
280
281#[cfg(test)]
284mod tests {
285 use super::*;
286
287 #[test]
288 fn empty_scopes() {
289 let info = decode_scopes("", &[], 0).unwrap();
290 assert!(info.scopes.is_empty());
291 assert!(info.ranges.is_empty());
292 }
293
294 #[test]
295 fn empty_scopes_with_sources() {
296 let info = decode_scopes(",", &[], 2).unwrap();
298 assert_eq!(info.scopes.len(), 2);
299 assert!(info.scopes[0].is_none());
300 assert!(info.scopes[1].is_none());
301 }
302
303 #[test]
304 fn single_global_scope_roundtrip() {
305 let info = ScopeInfo {
306 scopes: vec![Some(OriginalScope {
307 start: Position { line: 0, column: 0 },
308 end: Position {
309 line: 10,
310 column: 0,
311 },
312 name: None,
313 kind: Some("global".to_string()),
314 is_stack_frame: false,
315 variables: vec!["x".to_string(), "y".to_string()],
316 children: vec![],
317 })],
318 ranges: vec![],
319 };
320
321 let mut names = vec![];
322 let encoded = encode_scopes(&info, &mut names);
323 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
324
325 assert_eq!(decoded.scopes.len(), 1);
326 let scope = decoded.scopes[0].as_ref().unwrap();
327 assert_eq!(scope.start, Position { line: 0, column: 0 });
328 assert_eq!(
329 scope.end,
330 Position {
331 line: 10,
332 column: 0
333 }
334 );
335 assert_eq!(scope.kind.as_deref(), Some("global"));
336 assert_eq!(scope.name, None);
337 assert!(!scope.is_stack_frame);
338 assert_eq!(scope.variables, vec!["x", "y"]);
339 }
340
341 #[test]
342 fn nested_scopes_roundtrip() {
343 let info = ScopeInfo {
344 scopes: vec![Some(OriginalScope {
345 start: Position { line: 0, column: 0 },
346 end: Position {
347 line: 10,
348 column: 1,
349 },
350 name: None,
351 kind: Some("global".to_string()),
352 is_stack_frame: false,
353 variables: vec!["z".to_string()],
354 children: vec![OriginalScope {
355 start: Position { line: 1, column: 0 },
356 end: Position { line: 5, column: 1 },
357 name: Some("hello".to_string()),
358 kind: Some("function".to_string()),
359 is_stack_frame: true,
360 variables: vec!["msg".to_string(), "result".to_string()],
361 children: vec![],
362 }],
363 })],
364 ranges: vec![],
365 };
366
367 let mut names = vec![];
368 let encoded = encode_scopes(&info, &mut names);
369 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
370
371 let scope = decoded.scopes[0].as_ref().unwrap();
372 assert_eq!(scope.children.len(), 1);
373 let child = &scope.children[0];
374 assert_eq!(child.start, Position { line: 1, column: 0 });
375 assert_eq!(child.end, Position { line: 5, column: 1 });
376 assert_eq!(child.name.as_deref(), Some("hello"));
377 assert_eq!(child.kind.as_deref(), Some("function"));
378 assert!(child.is_stack_frame);
379 assert_eq!(child.variables, vec!["msg", "result"]);
380 }
381
382 #[test]
383 fn multiple_sources_with_gaps() {
384 let info = ScopeInfo {
385 scopes: vec![
386 Some(OriginalScope {
387 start: Position { line: 0, column: 0 },
388 end: Position { line: 5, column: 0 },
389 name: None,
390 kind: None,
391 is_stack_frame: false,
392 variables: vec![],
393 children: vec![],
394 }),
395 None, Some(OriginalScope {
397 start: Position { line: 0, column: 0 },
398 end: Position { line: 3, column: 0 },
399 name: None,
400 kind: None,
401 is_stack_frame: false,
402 variables: vec![],
403 children: vec![],
404 }),
405 ],
406 ranges: vec![],
407 };
408
409 let mut names = vec![];
410 let encoded = encode_scopes(&info, &mut names);
411 let decoded = decode_scopes(&encoded, &names, 3).unwrap();
412
413 assert_eq!(decoded.scopes.len(), 3);
414 assert!(decoded.scopes[0].is_some());
415 assert!(decoded.scopes[1].is_none());
416 assert!(decoded.scopes[2].is_some());
417 }
418
419 #[test]
420 fn generated_ranges_roundtrip() {
421 let info = ScopeInfo {
422 scopes: vec![Some(OriginalScope {
423 start: Position { line: 0, column: 0 },
424 end: Position {
425 line: 10,
426 column: 0,
427 },
428 name: None,
429 kind: Some("global".to_string()),
430 is_stack_frame: false,
431 variables: vec!["x".to_string()],
432 children: vec![],
433 })],
434 ranges: vec![GeneratedRange {
435 start: Position { line: 0, column: 0 },
436 end: Position {
437 line: 10,
438 column: 0,
439 },
440 is_stack_frame: false,
441 is_hidden: false,
442 definition: Some(0),
443 call_site: None,
444 bindings: vec![Binding::Expression("_x".to_string())],
445 children: vec![],
446 }],
447 };
448
449 let mut names = vec![];
450 let encoded = encode_scopes(&info, &mut names);
451 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
452
453 assert_eq!(decoded.ranges.len(), 1);
454 let range = &decoded.ranges[0];
455 assert_eq!(range.start, Position { line: 0, column: 0 });
456 assert_eq!(
457 range.end,
458 Position {
459 line: 10,
460 column: 0
461 }
462 );
463 assert_eq!(range.definition, Some(0));
464 assert_eq!(range.bindings, vec![Binding::Expression("_x".to_string())]);
465 }
466
467 #[test]
468 fn nested_ranges_with_inlining() {
469 let info = ScopeInfo {
470 scopes: vec![Some(OriginalScope {
471 start: Position { line: 0, column: 0 },
472 end: Position {
473 line: 10,
474 column: 0,
475 },
476 name: None,
477 kind: Some("global".to_string()),
478 is_stack_frame: false,
479 variables: vec!["x".to_string()],
480 children: vec![OriginalScope {
481 start: Position { line: 1, column: 0 },
482 end: Position { line: 5, column: 1 },
483 name: Some("fn1".to_string()),
484 kind: Some("function".to_string()),
485 is_stack_frame: true,
486 variables: vec!["a".to_string()],
487 children: vec![],
488 }],
489 })],
490 ranges: vec![GeneratedRange {
491 start: Position { line: 0, column: 0 },
492 end: Position {
493 line: 10,
494 column: 0,
495 },
496 is_stack_frame: false,
497 is_hidden: false,
498 definition: Some(0),
499 call_site: None,
500 bindings: vec![Binding::Expression("_x".to_string())],
501 children: vec![GeneratedRange {
502 start: Position { line: 6, column: 0 },
503 end: Position {
504 line: 8,
505 column: 20,
506 },
507 is_stack_frame: true,
508 is_hidden: false,
509 definition: Some(1),
510 call_site: Some(CallSite {
511 source_index: 0,
512 line: 7,
513 column: 0,
514 }),
515 bindings: vec![Binding::Expression("\"hello\"".to_string())],
516 children: vec![],
517 }],
518 }],
519 };
520
521 let mut names = vec![];
522 let encoded = encode_scopes(&info, &mut names);
523 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
524
525 assert_eq!(decoded.ranges.len(), 1);
526 let outer = &decoded.ranges[0];
527 assert_eq!(outer.children.len(), 1);
528 let inner = &outer.children[0];
529 assert!(inner.is_stack_frame);
530 assert_eq!(inner.definition, Some(1));
531 assert_eq!(
532 inner.call_site,
533 Some(CallSite {
534 source_index: 0,
535 line: 7,
536 column: 0,
537 })
538 );
539 assert_eq!(
540 inner.bindings,
541 vec![Binding::Expression("\"hello\"".to_string())]
542 );
543 }
544
545 #[test]
546 fn unavailable_bindings() {
547 let info = ScopeInfo {
548 scopes: vec![Some(OriginalScope {
549 start: Position { line: 0, column: 0 },
550 end: Position { line: 5, column: 0 },
551 name: None,
552 kind: None,
553 is_stack_frame: false,
554 variables: vec!["a".to_string(), "b".to_string()],
555 children: vec![],
556 })],
557 ranges: vec![GeneratedRange {
558 start: Position { line: 0, column: 0 },
559 end: Position { line: 5, column: 0 },
560 is_stack_frame: false,
561 is_hidden: false,
562 definition: Some(0),
563 call_site: None,
564 bindings: vec![Binding::Expression("_a".to_string()), Binding::Unavailable],
565 children: vec![],
566 }],
567 };
568
569 let mut names = vec![];
570 let encoded = encode_scopes(&info, &mut names);
571 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
572
573 assert_eq!(
574 decoded.ranges[0].bindings,
575 vec![Binding::Expression("_a".to_string()), Binding::Unavailable,]
576 );
577 }
578
579 #[test]
580 fn sub_range_bindings_roundtrip() {
581 let info = ScopeInfo {
582 scopes: vec![Some(OriginalScope {
583 start: Position { line: 0, column: 0 },
584 end: Position {
585 line: 20,
586 column: 0,
587 },
588 name: None,
589 kind: None,
590 is_stack_frame: false,
591 variables: vec!["x".to_string(), "y".to_string()],
592 children: vec![],
593 })],
594 ranges: vec![GeneratedRange {
595 start: Position { line: 0, column: 0 },
596 end: Position {
597 line: 20,
598 column: 0,
599 },
600 is_stack_frame: false,
601 is_hidden: false,
602 definition: Some(0),
603 call_site: None,
604 bindings: vec![
605 Binding::SubRanges(vec![
606 SubRangeBinding {
607 expression: Some("a".to_string()),
608 from: Position { line: 0, column: 0 },
609 },
610 SubRangeBinding {
611 expression: Some("b".to_string()),
612 from: Position { line: 5, column: 0 },
613 },
614 SubRangeBinding {
615 expression: None,
616 from: Position {
617 line: 10,
618 column: 0,
619 },
620 },
621 ]),
622 Binding::Expression("_y".to_string()),
623 ],
624 children: vec![],
625 }],
626 };
627
628 let mut names = vec![];
629 let encoded = encode_scopes(&info, &mut names);
630 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
631
632 let bindings = &decoded.ranges[0].bindings;
633 assert_eq!(bindings.len(), 2);
634
635 match &bindings[0] {
636 Binding::SubRanges(subs) => {
637 assert_eq!(subs.len(), 3);
638 assert_eq!(subs[0].expression.as_deref(), Some("a"));
639 assert_eq!(subs[0].from, Position { line: 0, column: 0 });
640 assert_eq!(subs[1].expression.as_deref(), Some("b"));
641 assert_eq!(subs[1].from, Position { line: 5, column: 0 });
642 assert_eq!(subs[2].expression, None);
643 assert_eq!(
644 subs[2].from,
645 Position {
646 line: 10,
647 column: 0,
648 }
649 );
650 }
651 other => panic!("expected SubRanges, got {other:?}"),
652 }
653 assert_eq!(bindings[1], Binding::Expression("_y".to_string()));
654 }
655
656 #[test]
657 fn hidden_range() {
658 let info = ScopeInfo {
659 scopes: vec![Some(OriginalScope {
660 start: Position { line: 0, column: 0 },
661 end: Position { line: 5, column: 0 },
662 name: None,
663 kind: None,
664 is_stack_frame: false,
665 variables: vec![],
666 children: vec![],
667 })],
668 ranges: vec![GeneratedRange {
669 start: Position { line: 0, column: 0 },
670 end: Position { line: 5, column: 0 },
671 is_stack_frame: true,
672 is_hidden: true,
673 definition: Some(0),
674 call_site: None,
675 bindings: vec![],
676 children: vec![],
677 }],
678 };
679
680 let mut names = vec![];
681 let encoded = encode_scopes(&info, &mut names);
682 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
683
684 assert!(decoded.ranges[0].is_stack_frame);
685 assert!(decoded.ranges[0].is_hidden);
686 }
687
688 #[test]
689 fn definition_resolution() {
690 let info = ScopeInfo {
691 scopes: vec![Some(OriginalScope {
692 start: Position { line: 0, column: 0 },
693 end: Position {
694 line: 10,
695 column: 0,
696 },
697 name: None,
698 kind: Some("global".to_string()),
699 is_stack_frame: false,
700 variables: vec![],
701 children: vec![
702 OriginalScope {
703 start: Position { line: 1, column: 0 },
704 end: Position { line: 4, column: 1 },
705 name: Some("foo".to_string()),
706 kind: Some("function".to_string()),
707 is_stack_frame: true,
708 variables: vec![],
709 children: vec![],
710 },
711 OriginalScope {
712 start: Position { line: 5, column: 0 },
713 end: Position { line: 9, column: 1 },
714 name: Some("bar".to_string()),
715 kind: Some("function".to_string()),
716 is_stack_frame: true,
717 variables: vec![],
718 children: vec![],
719 },
720 ],
721 })],
722 ranges: vec![],
723 };
724
725 let scope0 = info.original_scope_for_definition(0).unwrap();
727 assert_eq!(scope0.kind.as_deref(), Some("global"));
728
729 let scope1 = info.original_scope_for_definition(1).unwrap();
731 assert_eq!(scope1.name.as_deref(), Some("foo"));
732
733 let scope2 = info.original_scope_for_definition(2).unwrap();
735 assert_eq!(scope2.name.as_deref(), Some("bar"));
736
737 assert!(info.original_scope_for_definition(3).is_none());
739 }
740
741 #[test]
742 fn scopes_only_no_ranges() {
743 let info = ScopeInfo {
744 scopes: vec![Some(OriginalScope {
745 start: Position { line: 0, column: 0 },
746 end: Position { line: 5, column: 0 },
747 name: None,
748 kind: None,
749 is_stack_frame: false,
750 variables: vec![],
751 children: vec![],
752 })],
753 ranges: vec![],
754 };
755
756 let mut names = vec![];
757 let encoded = encode_scopes(&info, &mut names);
758 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
759
760 assert_eq!(decoded.scopes.len(), 1);
761 assert!(decoded.scopes[0].is_some());
762 assert!(decoded.ranges.is_empty());
763 }
764
765 #[test]
766 fn ranges_only_no_scopes() {
767 let info = ScopeInfo {
768 scopes: vec![None],
769 ranges: vec![GeneratedRange {
770 start: Position { line: 0, column: 0 },
771 end: Position { line: 5, column: 0 },
772 is_stack_frame: false,
773 is_hidden: false,
774 definition: None,
775 call_site: None,
776 bindings: vec![],
777 children: vec![],
778 }],
779 };
780
781 let mut names = vec![];
782 let encoded = encode_scopes(&info, &mut names);
783 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
784
785 assert_eq!(decoded.scopes.len(), 1);
786 assert!(decoded.scopes[0].is_none());
787 assert_eq!(decoded.ranges.len(), 1);
788 }
789
790 #[test]
791 fn range_no_definition() {
792 let info = ScopeInfo {
793 scopes: vec![],
794 ranges: vec![GeneratedRange {
795 start: Position { line: 0, column: 0 },
796 end: Position { line: 5, column: 0 },
797 is_stack_frame: false,
798 is_hidden: false,
799 definition: None,
800 call_site: None,
801 bindings: vec![],
802 children: vec![],
803 }],
804 };
805
806 let mut names = vec![];
807 let encoded = encode_scopes(&info, &mut names);
808 let decoded = decode_scopes(&encoded, &names, 0).unwrap();
809
810 assert_eq!(decoded.ranges.len(), 1);
811 assert_eq!(decoded.ranges[0].definition, None);
812 }
813
814 #[test]
815 fn scopes_error_display() {
816 let err = ScopesError::UnmatchedScopeEnd;
817 assert_eq!(err.to_string(), "scope end without matching start");
818
819 let err = ScopesError::UnclosedScope;
820 assert_eq!(err.to_string(), "scope opened but never closed");
821
822 let err = ScopesError::UnmatchedRangeEnd;
823 assert_eq!(err.to_string(), "range end without matching start");
824
825 let err = ScopesError::UnclosedRange;
826 assert_eq!(err.to_string(), "range opened but never closed");
827
828 let err = ScopesError::InvalidNameIndex(42);
829 assert_eq!(err.to_string(), "invalid name index: 42");
830
831 let vlq_err = srcmap_codec::DecodeError::UnexpectedEof { offset: 5 };
832 let err = ScopesError::Vlq(vlq_err);
833 assert!(err.to_string().contains("VLQ decode error"));
834 }
835
836 #[test]
837 fn scopes_error_from_decode_error() {
838 let vlq_err = srcmap_codec::DecodeError::UnexpectedEof { offset: 0 };
839 let err: ScopesError = vlq_err.into();
840 assert!(matches!(err, ScopesError::Vlq(_)));
841 }
842
843 #[test]
844 fn invalid_name_index_error() {
845 let info = ScopeInfo {
847 scopes: vec![Some(OriginalScope {
848 start: Position { line: 0, column: 0 },
849 end: Position { line: 5, column: 0 },
850 name: Some("test".to_string()),
851 kind: None,
852 is_stack_frame: false,
853 variables: vec![],
854 children: vec![],
855 })],
856 ranges: vec![],
857 };
858
859 let mut names = vec![];
860 let encoded = encode_scopes(&info, &mut names);
861 let err = decode_scopes(&encoded, &[], 1).unwrap_err();
863 assert!(matches!(err, ScopesError::InvalidNameIndex(_)));
864 }
865
866 #[test]
867 fn invalid_binding_index_error() {
868 let info = ScopeInfo {
870 scopes: vec![Some(OriginalScope {
871 start: Position { line: 0, column: 0 },
872 end: Position { line: 5, column: 0 },
873 name: None,
874 kind: None,
875 is_stack_frame: false,
876 variables: vec!["x".to_string()],
877 children: vec![],
878 })],
879 ranges: vec![GeneratedRange {
880 start: Position { line: 0, column: 0 },
881 end: Position { line: 5, column: 0 },
882 is_stack_frame: false,
883 is_hidden: false,
884 definition: Some(0),
885 call_site: None,
886 bindings: vec![Binding::Expression("_x".to_string())],
887 children: vec![],
888 }],
889 };
890
891 let mut names = vec![];
892 let encoded = encode_scopes(&info, &mut names);
893 let short_names: Vec<String> = names.iter().take(1).cloned().collect();
895 let err = decode_scopes(&encoded, &short_names, 1).unwrap_err();
896 assert!(matches!(err, ScopesError::InvalidNameIndex(_)));
897 }
898
899 #[test]
900 fn scope_same_line_end() {
901 let info = ScopeInfo {
903 scopes: vec![Some(OriginalScope {
904 start: Position {
905 line: 5,
906 column: 10,
907 },
908 end: Position {
909 line: 5,
910 column: 30,
911 },
912 name: None,
913 kind: None,
914 is_stack_frame: false,
915 variables: vec![],
916 children: vec![],
917 })],
918 ranges: vec![],
919 };
920
921 let mut names = vec![];
922 let encoded = encode_scopes(&info, &mut names);
923 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
924
925 let scope = decoded.scopes[0].as_ref().unwrap();
926 assert_eq!(
927 scope.start,
928 Position {
929 line: 5,
930 column: 10
931 }
932 );
933 assert_eq!(
934 scope.end,
935 Position {
936 line: 5,
937 column: 30
938 }
939 );
940 }
941
942 #[test]
943 fn range_same_line() {
944 let info = ScopeInfo {
946 scopes: vec![Some(OriginalScope {
947 start: Position { line: 0, column: 0 },
948 end: Position {
949 line: 10,
950 column: 0,
951 },
952 name: None,
953 kind: None,
954 is_stack_frame: false,
955 variables: vec![],
956 children: vec![],
957 })],
958 ranges: vec![GeneratedRange {
959 start: Position { line: 3, column: 5 },
960 end: Position {
961 line: 3,
962 column: 25,
963 },
964 is_stack_frame: false,
965 is_hidden: false,
966 definition: Some(0),
967 call_site: None,
968 bindings: vec![],
969 children: vec![],
970 }],
971 };
972
973 let mut names = vec![];
974 let encoded = encode_scopes(&info, &mut names);
975 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
976
977 let range = &decoded.ranges[0];
978 assert_eq!(range.start, Position { line: 3, column: 5 });
979 assert_eq!(
980 range.end,
981 Position {
982 line: 3,
983 column: 25
984 }
985 );
986 }
987
988 #[test]
989 fn scopes_first_empty_second_populated() {
990 let info = ScopeInfo {
991 scopes: vec![
992 None, Some(OriginalScope {
994 start: Position { line: 0, column: 0 },
995 end: Position { line: 5, column: 0 },
996 name: None,
997 kind: None,
998 is_stack_frame: false,
999 variables: vec![],
1000 children: vec![],
1001 }),
1002 ],
1003 ranges: vec![],
1004 };
1005
1006 let mut names = vec![];
1007 let encoded = encode_scopes(&info, &mut names);
1008 let decoded = decode_scopes(&encoded, &names, 2).unwrap();
1009
1010 assert!(decoded.scopes[0].is_none());
1011 assert!(decoded.scopes[1].is_some());
1012 }
1013
1014 #[test]
1015 fn ranges_only_no_scopes_multi_source() {
1016 let info = ScopeInfo {
1017 scopes: vec![None, None],
1018 ranges: vec![GeneratedRange {
1019 start: Position { line: 0, column: 0 },
1020 end: Position { line: 5, column: 0 },
1021 is_stack_frame: false,
1022 is_hidden: false,
1023 definition: None,
1024 call_site: None,
1025 bindings: vec![],
1026 children: vec![],
1027 }],
1028 };
1029
1030 let mut names = vec![];
1031 let encoded = encode_scopes(&info, &mut names);
1032 let decoded = decode_scopes(&encoded, &names, 2).unwrap();
1033
1034 assert_eq!(decoded.scopes.len(), 2);
1035 assert!(decoded.scopes[0].is_none());
1036 assert!(decoded.scopes[1].is_none());
1037 assert_eq!(decoded.ranges.len(), 1);
1038 }
1039
1040 #[test]
1041 fn range_no_definition_explicit() {
1042 let info = ScopeInfo {
1043 scopes: vec![None],
1044 ranges: vec![GeneratedRange {
1045 start: Position { line: 0, column: 0 },
1046 end: Position { line: 5, column: 0 },
1047 is_stack_frame: false,
1048 is_hidden: false,
1049 definition: None,
1050 call_site: None,
1051 bindings: vec![],
1052 children: vec![],
1053 }],
1054 };
1055
1056 let mut names = vec![];
1057 let encoded = encode_scopes(&info, &mut names);
1058 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1059
1060 assert_eq!(decoded.ranges[0].definition, None);
1061 }
1062
1063 #[test]
1064 fn sub_range_same_line_bindings() {
1065 let info = ScopeInfo {
1067 scopes: vec![Some(OriginalScope {
1068 start: Position { line: 0, column: 0 },
1069 end: Position {
1070 line: 10,
1071 column: 0,
1072 },
1073 name: None,
1074 kind: None,
1075 is_stack_frame: false,
1076 variables: vec!["x".to_string()],
1077 children: vec![],
1078 })],
1079 ranges: vec![GeneratedRange {
1080 start: Position { line: 0, column: 0 },
1081 end: Position {
1082 line: 10,
1083 column: 0,
1084 },
1085 is_stack_frame: false,
1086 is_hidden: false,
1087 definition: Some(0),
1088 call_site: None,
1089 bindings: vec![Binding::SubRanges(vec![
1090 SubRangeBinding {
1091 expression: Some("a".to_string()),
1092 from: Position { line: 0, column: 0 },
1093 },
1094 SubRangeBinding {
1095 expression: Some("b".to_string()),
1096 from: Position {
1097 line: 0,
1098 column: 15,
1099 },
1100 },
1101 ])],
1102 children: vec![],
1103 }],
1104 };
1105
1106 let mut names = vec![];
1107 let encoded = encode_scopes(&info, &mut names);
1108 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1109
1110 match &decoded.ranges[0].bindings[0] {
1111 Binding::SubRanges(subs) => {
1112 assert_eq!(subs.len(), 2);
1113 assert_eq!(subs[0].from, Position { line: 0, column: 0 });
1114 assert_eq!(
1115 subs[1].from,
1116 Position {
1117 line: 0,
1118 column: 15
1119 }
1120 );
1121 }
1122 other => panic!("expected SubRanges, got {other:?}"),
1123 }
1124 }
1125
1126 #[test]
1127 fn call_site_with_nonzero_values() {
1128 let info = ScopeInfo {
1129 scopes: vec![Some(OriginalScope {
1130 start: Position { line: 0, column: 0 },
1131 end: Position {
1132 line: 20,
1133 column: 0,
1134 },
1135 name: None,
1136 kind: None,
1137 is_stack_frame: false,
1138 variables: vec![],
1139 children: vec![],
1140 })],
1141 ranges: vec![GeneratedRange {
1142 start: Position { line: 0, column: 0 },
1143 end: Position {
1144 line: 20,
1145 column: 0,
1146 },
1147 is_stack_frame: false,
1148 is_hidden: false,
1149 definition: Some(0),
1150 call_site: Some(CallSite {
1151 source_index: 2,
1152 line: 15,
1153 column: 8,
1154 }),
1155 bindings: vec![],
1156 children: vec![],
1157 }],
1158 };
1159
1160 let mut names = vec![];
1161 let encoded = encode_scopes(&info, &mut names);
1162 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1163
1164 let cs = decoded.ranges[0].call_site.as_ref().unwrap();
1165 assert_eq!(cs.source_index, 2);
1166 assert_eq!(cs.line, 15);
1167 assert_eq!(cs.column, 8);
1168 }
1169
1170 #[test]
1173 fn scope_with_name_and_kind_roundtrip() {
1174 let info = ScopeInfo {
1177 scopes: vec![Some(OriginalScope {
1178 start: Position { line: 2, column: 4 },
1179 end: Position {
1180 line: 15,
1181 column: 1,
1182 },
1183 name: Some("myFunc".to_string()),
1184 kind: Some("function".to_string()),
1185 is_stack_frame: true,
1186 variables: vec!["arg1".to_string(), "arg2".to_string()],
1187 children: vec![OriginalScope {
1188 start: Position { line: 3, column: 8 },
1189 end: Position {
1190 line: 14,
1191 column: 5,
1192 },
1193 name: Some("innerBlock".to_string()),
1194 kind: Some("block".to_string()),
1195 is_stack_frame: false,
1196 variables: vec!["tmp".to_string()],
1197 children: vec![],
1198 }],
1199 })],
1200 ranges: vec![],
1201 };
1202
1203 let mut names = vec![];
1204 let encoded = encode_scopes(&info, &mut names);
1205 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1206
1207 let scope = decoded.scopes[0].as_ref().unwrap();
1208 assert_eq!(scope.name.as_deref(), Some("myFunc"));
1209 assert_eq!(scope.kind.as_deref(), Some("function"));
1210 assert!(scope.is_stack_frame);
1211 assert_eq!(scope.variables, vec!["arg1", "arg2"]);
1212
1213 let child = &scope.children[0];
1214 assert_eq!(child.name.as_deref(), Some("innerBlock"));
1215 assert_eq!(child.kind.as_deref(), Some("block"));
1216 assert!(!child.is_stack_frame);
1217 assert_eq!(child.variables, vec!["tmp"]);
1218 }
1219
1220 #[test]
1221 fn range_end_multiline_2vlq() {
1222 let info = ScopeInfo {
1226 scopes: vec![],
1227 ranges: vec![GeneratedRange {
1228 start: Position { line: 0, column: 0 },
1229 end: Position {
1230 line: 7,
1231 column: 15,
1232 },
1233 is_stack_frame: false,
1234 is_hidden: false,
1235 definition: None,
1236 call_site: None,
1237 bindings: vec![],
1238 children: vec![GeneratedRange {
1239 start: Position { line: 1, column: 5 },
1240 end: Position {
1241 line: 4,
1242 column: 10,
1243 },
1244 is_stack_frame: false,
1245 is_hidden: false,
1246 definition: None,
1247 call_site: None,
1248 bindings: vec![],
1249 children: vec![],
1250 }],
1251 }],
1252 };
1253
1254 let mut names = vec![];
1255 let encoded = encode_scopes(&info, &mut names);
1256 let decoded = decode_scopes(&encoded, &names, 0).unwrap();
1257
1258 let outer = &decoded.ranges[0];
1259 assert_eq!(
1260 outer.end,
1261 Position {
1262 line: 7,
1263 column: 15
1264 }
1265 );
1266 let inner = &outer.children[0];
1267 assert_eq!(inner.start, Position { line: 1, column: 5 });
1268 assert_eq!(
1269 inner.end,
1270 Position {
1271 line: 4,
1272 column: 10
1273 }
1274 );
1275 }
1276
1277 #[test]
1278 fn binding_unavailable_roundtrip() {
1279 let info = ScopeInfo {
1282 scopes: vec![Some(OriginalScope {
1283 start: Position { line: 0, column: 0 },
1284 end: Position {
1285 line: 10,
1286 column: 0,
1287 },
1288 name: None,
1289 kind: None,
1290 is_stack_frame: false,
1291 variables: vec!["a".to_string(), "b".to_string(), "c".to_string()],
1292 children: vec![],
1293 })],
1294 ranges: vec![GeneratedRange {
1295 start: Position { line: 0, column: 0 },
1296 end: Position {
1297 line: 10,
1298 column: 0,
1299 },
1300 is_stack_frame: false,
1301 is_hidden: false,
1302 definition: Some(0),
1303 call_site: None,
1304 bindings: vec![
1305 Binding::Unavailable,
1306 Binding::Expression("_b".to_string()),
1307 Binding::Unavailable,
1308 ],
1309 children: vec![],
1310 }],
1311 };
1312
1313 let mut names = vec![];
1314 let encoded = encode_scopes(&info, &mut names);
1315 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1316
1317 assert_eq!(decoded.ranges[0].bindings.len(), 3);
1318 assert_eq!(decoded.ranges[0].bindings[0], Binding::Unavailable);
1319 assert_eq!(
1320 decoded.ranges[0].bindings[1],
1321 Binding::Expression("_b".to_string())
1322 );
1323 assert_eq!(decoded.ranges[0].bindings[2], Binding::Unavailable);
1324 }
1325
1326 #[test]
1327 fn sub_range_with_none_expression() {
1328 let info = ScopeInfo {
1332 scopes: vec![Some(OriginalScope {
1333 start: Position { line: 0, column: 0 },
1334 end: Position {
1335 line: 20,
1336 column: 0,
1337 },
1338 name: None,
1339 kind: None,
1340 is_stack_frame: false,
1341 variables: vec!["x".to_string()],
1342 children: vec![],
1343 })],
1344 ranges: vec![GeneratedRange {
1345 start: Position { line: 0, column: 0 },
1346 end: Position {
1347 line: 20,
1348 column: 0,
1349 },
1350 is_stack_frame: false,
1351 is_hidden: false,
1352 definition: Some(0),
1353 call_site: None,
1354 bindings: vec![Binding::SubRanges(vec![
1355 SubRangeBinding {
1356 expression: Some("a".to_string()),
1357 from: Position { line: 0, column: 0 },
1358 },
1359 SubRangeBinding {
1360 expression: None,
1361 from: Position { line: 5, column: 0 },
1362 },
1363 SubRangeBinding {
1364 expression: Some("c".to_string()),
1365 from: Position {
1366 line: 10,
1367 column: 0,
1368 },
1369 },
1370 ])],
1371 children: vec![],
1372 }],
1373 };
1374
1375 let mut names = vec![];
1376 let encoded = encode_scopes(&info, &mut names);
1377 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1378
1379 match &decoded.ranges[0].bindings[0] {
1380 Binding::SubRanges(subs) => {
1381 assert_eq!(subs.len(), 3);
1382 assert_eq!(subs[0].expression.as_deref(), Some("a"));
1383 assert_eq!(subs[1].expression, None);
1384 assert_eq!(subs[2].expression.as_deref(), Some("c"));
1385 }
1386 other => panic!("expected SubRanges, got {other:?}"),
1387 }
1388 }
1389
1390 #[test]
1391 fn sub_range_multiple_variables() {
1392 let info = ScopeInfo {
1396 scopes: vec![Some(OriginalScope {
1397 start: Position { line: 0, column: 0 },
1398 end: Position {
1399 line: 30,
1400 column: 0,
1401 },
1402 name: None,
1403 kind: None,
1404 is_stack_frame: false,
1405 variables: vec!["x".to_string(), "y".to_string(), "z".to_string()],
1406 children: vec![],
1407 })],
1408 ranges: vec![GeneratedRange {
1409 start: Position { line: 0, column: 0 },
1410 end: Position {
1411 line: 30,
1412 column: 0,
1413 },
1414 is_stack_frame: false,
1415 is_hidden: false,
1416 definition: Some(0),
1417 call_site: None,
1418 bindings: vec![
1419 Binding::SubRanges(vec![
1421 SubRangeBinding {
1422 expression: Some("_x1".to_string()),
1423 from: Position { line: 0, column: 0 },
1424 },
1425 SubRangeBinding {
1426 expression: Some("_x2".to_string()),
1427 from: Position {
1428 line: 10,
1429 column: 0,
1430 },
1431 },
1432 ]),
1433 Binding::Expression("_y".to_string()),
1435 Binding::SubRanges(vec![
1437 SubRangeBinding {
1438 expression: Some("_z1".to_string()),
1439 from: Position { line: 0, column: 0 },
1440 },
1441 SubRangeBinding {
1442 expression: None,
1443 from: Position {
1444 line: 15,
1445 column: 5,
1446 },
1447 },
1448 SubRangeBinding {
1449 expression: Some("_z3".to_string()),
1450 from: Position {
1451 line: 20,
1452 column: 0,
1453 },
1454 },
1455 ]),
1456 ],
1457 children: vec![],
1458 }],
1459 };
1460
1461 let mut names = vec![];
1462 let encoded = encode_scopes(&info, &mut names);
1463 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1464
1465 let bindings = &decoded.ranges[0].bindings;
1466 assert_eq!(bindings.len(), 3);
1467
1468 match &bindings[0] {
1470 Binding::SubRanges(subs) => {
1471 assert_eq!(subs.len(), 2);
1472 assert_eq!(subs[0].expression.as_deref(), Some("_x1"));
1473 assert_eq!(subs[1].expression.as_deref(), Some("_x2"));
1474 assert_eq!(
1475 subs[1].from,
1476 Position {
1477 line: 10,
1478 column: 0
1479 }
1480 );
1481 }
1482 other => panic!("expected SubRanges for x, got {other:?}"),
1483 }
1484
1485 assert_eq!(bindings[1], Binding::Expression("_y".to_string()));
1487
1488 match &bindings[2] {
1490 Binding::SubRanges(subs) => {
1491 assert_eq!(subs.len(), 3);
1492 assert_eq!(subs[0].expression.as_deref(), Some("_z1"));
1493 assert_eq!(subs[1].expression, None);
1494 assert_eq!(
1495 subs[1].from,
1496 Position {
1497 line: 15,
1498 column: 5
1499 }
1500 );
1501 assert_eq!(subs[2].expression.as_deref(), Some("_z3"));
1502 }
1503 other => panic!("expected SubRanges for z, got {other:?}"),
1504 }
1505 }
1506
1507 #[test]
1508 fn call_site_on_standalone_range() {
1509 let info = ScopeInfo {
1512 scopes: vec![Some(OriginalScope {
1513 start: Position { line: 0, column: 0 },
1514 end: Position {
1515 line: 30,
1516 column: 0,
1517 },
1518 name: None,
1519 kind: Some("global".to_string()),
1520 is_stack_frame: false,
1521 variables: vec![],
1522 children: vec![OriginalScope {
1523 start: Position { line: 5, column: 0 },
1524 end: Position {
1525 line: 10,
1526 column: 1,
1527 },
1528 name: Some("inlined".to_string()),
1529 kind: Some("function".to_string()),
1530 is_stack_frame: true,
1531 variables: vec!["p".to_string()],
1532 children: vec![],
1533 }],
1534 })],
1535 ranges: vec![GeneratedRange {
1536 start: Position { line: 0, column: 0 },
1537 end: Position {
1538 line: 30,
1539 column: 0,
1540 },
1541 is_stack_frame: false,
1542 is_hidden: false,
1543 definition: Some(0),
1544 call_site: None,
1545 bindings: vec![],
1546 children: vec![GeneratedRange {
1547 start: Position {
1548 line: 12,
1549 column: 0,
1550 },
1551 end: Position {
1552 line: 18,
1553 column: 0,
1554 },
1555 is_stack_frame: true,
1556 is_hidden: false,
1557 definition: Some(1),
1558 call_site: Some(CallSite {
1559 source_index: 0,
1560 line: 20,
1561 column: 4,
1562 }),
1563 bindings: vec![Binding::Expression("arg0".to_string())],
1564 children: vec![],
1565 }],
1566 }],
1567 };
1568
1569 let mut names = vec![];
1570 let encoded = encode_scopes(&info, &mut names);
1571 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1572
1573 let inner = &decoded.ranges[0].children[0];
1574 assert!(inner.is_stack_frame);
1575 assert_eq!(inner.definition, Some(1));
1576 let cs = inner.call_site.as_ref().unwrap();
1577 assert_eq!(cs.source_index, 0);
1578 assert_eq!(cs.line, 20);
1579 assert_eq!(cs.column, 4);
1580 assert_eq!(
1581 inner.bindings,
1582 vec![Binding::Expression("arg0".to_string())]
1583 );
1584 }
1585
1586 #[test]
1587 fn unknown_tag_skipped() {
1588 let info = ScopeInfo {
1594 scopes: vec![Some(OriginalScope {
1595 start: Position { line: 0, column: 0 },
1596 end: Position { line: 5, column: 0 },
1597 name: None,
1598 kind: None,
1599 is_stack_frame: false,
1600 variables: vec![],
1601 children: vec![],
1602 })],
1603 ranges: vec![],
1604 };
1605
1606 let mut names = vec![];
1607 let encoded = encode_scopes(&info, &mut names);
1608
1609 let mut crafted = Vec::new();
1612 srcmap_codec::vlq_encode_unsigned(&mut crafted, 18); srcmap_codec::vlq_encode_unsigned(&mut crafted, 42); srcmap_codec::vlq_encode_unsigned(&mut crafted, 7); crafted.push(b',');
1616 crafted.extend_from_slice(encoded.as_bytes());
1617
1618 let crafted_str = std::str::from_utf8(&crafted).unwrap();
1619 let decoded = decode_scopes(crafted_str, &names, 1).unwrap();
1620
1621 assert_eq!(decoded.scopes.len(), 1);
1622 assert!(decoded.scopes[0].is_some());
1623 let scope = decoded.scopes[0].as_ref().unwrap();
1624 assert_eq!(scope.start, Position { line: 0, column: 0 });
1625 assert_eq!(scope.end, Position { line: 5, column: 0 });
1626 }
1627
1628 #[test]
1629 fn first_source_none_exercises_empty_path() {
1630 let info = ScopeInfo {
1634 scopes: vec![
1635 None,
1636 None,
1637 Some(OriginalScope {
1638 start: Position { line: 0, column: 0 },
1639 end: Position { line: 5, column: 0 },
1640 name: None,
1641 kind: None,
1642 is_stack_frame: false,
1643 variables: vec![],
1644 children: vec![],
1645 }),
1646 ],
1647 ranges: vec![],
1648 };
1649
1650 let mut names = vec![];
1651 let encoded = encode_scopes(&info, &mut names);
1652 let decoded = decode_scopes(&encoded, &names, 3).unwrap();
1653
1654 assert_eq!(decoded.scopes.len(), 3);
1655 assert!(decoded.scopes[0].is_none());
1656 assert!(decoded.scopes[1].is_none());
1657 assert!(decoded.scopes[2].is_some());
1658 }
1659
1660 #[test]
1661 fn scope_end_same_line_as_child_end() {
1662 let info = ScopeInfo {
1666 scopes: vec![Some(OriginalScope {
1667 start: Position { line: 0, column: 0 },
1668 end: Position {
1669 line: 10,
1670 column: 20,
1671 },
1672 name: None,
1673 kind: None,
1674 is_stack_frame: false,
1675 variables: vec![],
1676 children: vec![OriginalScope {
1677 start: Position { line: 5, column: 0 },
1678 end: Position {
1679 line: 10,
1680 column: 10,
1681 },
1682 name: None,
1683 kind: None,
1684 is_stack_frame: false,
1685 variables: vec![],
1686 children: vec![],
1687 }],
1688 })],
1689 ranges: vec![],
1690 };
1691
1692 let mut names = vec![];
1693 let encoded = encode_scopes(&info, &mut names);
1694 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1695
1696 let scope = decoded.scopes[0].as_ref().unwrap();
1697 assert_eq!(
1698 scope.end,
1699 Position {
1700 line: 10,
1701 column: 20
1702 }
1703 );
1704 assert_eq!(
1705 scope.children[0].end,
1706 Position {
1707 line: 10,
1708 column: 10
1709 }
1710 );
1711 }
1712
1713 #[test]
1714 fn generated_range_has_line_flag() {
1715 let info = ScopeInfo {
1719 scopes: vec![],
1720 ranges: vec![
1721 GeneratedRange {
1722 start: Position { line: 0, column: 5 },
1723 end: Position {
1724 line: 0,
1725 column: 50,
1726 },
1727 is_stack_frame: false,
1728 is_hidden: false,
1729 definition: None,
1730 call_site: None,
1731 bindings: vec![],
1732 children: vec![],
1733 },
1734 GeneratedRange {
1735 start: Position {
1736 line: 3,
1737 column: 10,
1738 },
1739 end: Position {
1740 line: 8,
1741 column: 20,
1742 },
1743 is_stack_frame: false,
1744 is_hidden: false,
1745 definition: None,
1746 call_site: None,
1747 bindings: vec![],
1748 children: vec![],
1749 },
1750 ],
1751 };
1752
1753 let mut names = vec![];
1754 let encoded = encode_scopes(&info, &mut names);
1755 let decoded = decode_scopes(&encoded, &names, 0).unwrap();
1756
1757 assert_eq!(decoded.ranges.len(), 2);
1758 assert_eq!(decoded.ranges[0].start, Position { line: 0, column: 5 });
1759 assert_eq!(
1760 decoded.ranges[0].end,
1761 Position {
1762 line: 0,
1763 column: 50
1764 }
1765 );
1766 assert_eq!(
1767 decoded.ranges[1].start,
1768 Position {
1769 line: 3,
1770 column: 10
1771 }
1772 );
1773 assert_eq!(
1774 decoded.ranges[1].end,
1775 Position {
1776 line: 8,
1777 column: 20
1778 }
1779 );
1780 }
1781
1782 #[test]
1783 fn scope_variables_decode_path() {
1784 let info = ScopeInfo {
1787 scopes: vec![Some(OriginalScope {
1788 start: Position { line: 0, column: 0 },
1789 end: Position {
1790 line: 20,
1791 column: 0,
1792 },
1793 name: None,
1794 kind: None,
1795 is_stack_frame: false,
1796 variables: vec!["alpha".to_string(), "beta".to_string(), "gamma".to_string()],
1797 children: vec![OriginalScope {
1798 start: Position { line: 2, column: 0 },
1799 end: Position {
1800 line: 18,
1801 column: 0,
1802 },
1803 name: None,
1804 kind: None,
1805 is_stack_frame: false,
1806 variables: vec!["delta".to_string(), "epsilon".to_string()],
1807 children: vec![],
1808 }],
1809 })],
1810 ranges: vec![],
1811 };
1812
1813 let mut names = vec![];
1814 let encoded = encode_scopes(&info, &mut names);
1815 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1816
1817 let scope = decoded.scopes[0].as_ref().unwrap();
1818 assert_eq!(scope.variables, vec!["alpha", "beta", "gamma"]);
1819 assert_eq!(scope.children[0].variables, vec!["delta", "epsilon"]);
1820 }
1821
1822 #[test]
1823 fn sub_range_first_expression_none() {
1824 let info = ScopeInfo {
1827 scopes: vec![Some(OriginalScope {
1828 start: Position { line: 0, column: 0 },
1829 end: Position {
1830 line: 20,
1831 column: 0,
1832 },
1833 name: None,
1834 kind: None,
1835 is_stack_frame: false,
1836 variables: vec!["v".to_string()],
1837 children: vec![],
1838 })],
1839 ranges: vec![GeneratedRange {
1840 start: Position { line: 0, column: 0 },
1841 end: Position {
1842 line: 20,
1843 column: 0,
1844 },
1845 is_stack_frame: false,
1846 is_hidden: false,
1847 definition: Some(0),
1848 call_site: None,
1849 bindings: vec![Binding::SubRanges(vec![
1850 SubRangeBinding {
1851 expression: None,
1852 from: Position { line: 0, column: 0 },
1853 },
1854 SubRangeBinding {
1855 expression: Some("_v".to_string()),
1856 from: Position { line: 8, column: 0 },
1857 },
1858 ])],
1859 children: vec![],
1860 }],
1861 };
1862
1863 let mut names = vec![];
1864 let encoded = encode_scopes(&info, &mut names);
1865 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
1866
1867 match &decoded.ranges[0].bindings[0] {
1868 Binding::SubRanges(subs) => {
1869 assert_eq!(subs.len(), 2);
1870 assert_eq!(subs[0].expression, None);
1871 assert_eq!(subs[0].from, Position { line: 0, column: 0 });
1872 assert_eq!(subs[1].expression.as_deref(), Some("_v"));
1873 assert_eq!(subs[1].from, Position { line: 8, column: 0 });
1874 }
1875 other => panic!("expected SubRanges, got {other:?}"),
1876 }
1877 }
1878
1879 #[test]
1880 fn comprehensive_roundtrip() {
1881 let info = ScopeInfo {
1884 scopes: vec![
1885 Some(OriginalScope {
1886 start: Position { line: 0, column: 0 },
1887 end: Position {
1888 line: 50,
1889 column: 0,
1890 },
1891 name: None,
1892 kind: Some("module".to_string()),
1893 is_stack_frame: false,
1894 variables: vec!["exports".to_string()],
1895 children: vec![
1896 OriginalScope {
1897 start: Position { line: 2, column: 0 },
1898 end: Position {
1899 line: 20,
1900 column: 1,
1901 },
1902 name: Some("add".to_string()),
1903 kind: Some("function".to_string()),
1904 is_stack_frame: true,
1905 variables: vec!["a".to_string(), "b".to_string()],
1906 children: vec![],
1907 },
1908 OriginalScope {
1909 start: Position {
1910 line: 22,
1911 column: 0,
1912 },
1913 end: Position {
1914 line: 40,
1915 column: 1,
1916 },
1917 name: Some("multiply".to_string()),
1918 kind: Some("function".to_string()),
1919 is_stack_frame: true,
1920 variables: vec!["x".to_string(), "y".to_string()],
1921 children: vec![],
1922 },
1923 ],
1924 }),
1925 None, ],
1927 ranges: vec![GeneratedRange {
1928 start: Position { line: 0, column: 0 },
1929 end: Position {
1930 line: 25,
1931 column: 0,
1932 },
1933 is_stack_frame: false,
1934 is_hidden: false,
1935 definition: Some(0),
1936 call_site: None,
1937 bindings: vec![Binding::Expression("module.exports".to_string())],
1938 children: vec![
1939 GeneratedRange {
1940 start: Position { line: 1, column: 0 },
1941 end: Position {
1942 line: 10,
1943 column: 0,
1944 },
1945 is_stack_frame: true,
1946 is_hidden: false,
1947 definition: Some(1),
1948 call_site: Some(CallSite {
1949 source_index: 0,
1950 line: 45,
1951 column: 2,
1952 }),
1953 bindings: vec![Binding::Expression("_a".to_string()), Binding::Unavailable],
1954 children: vec![],
1955 },
1956 GeneratedRange {
1957 start: Position {
1958 line: 12,
1959 column: 0,
1960 },
1961 end: Position {
1962 line: 20,
1963 column: 0,
1964 },
1965 is_stack_frame: true,
1966 is_hidden: true,
1967 definition: Some(2),
1968 call_site: Some(CallSite {
1969 source_index: 0,
1970 line: 46,
1971 column: 0,
1972 }),
1973 bindings: vec![
1974 Binding::SubRanges(vec![
1975 SubRangeBinding {
1976 expression: Some("p1".to_string()),
1977 from: Position {
1978 line: 12,
1979 column: 0,
1980 },
1981 },
1982 SubRangeBinding {
1983 expression: Some("p2".to_string()),
1984 from: Position {
1985 line: 16,
1986 column: 0,
1987 },
1988 },
1989 ]),
1990 Binding::Expression("_y".to_string()),
1991 ],
1992 children: vec![],
1993 },
1994 ],
1995 }],
1996 };
1997
1998 let mut names = vec![];
1999 let encoded = encode_scopes(&info, &mut names);
2000 let decoded = decode_scopes(&encoded, &names, 2).unwrap();
2001
2002 assert_eq!(decoded.scopes.len(), 2);
2004 assert!(decoded.scopes[1].is_none());
2005 let root = decoded.scopes[0].as_ref().unwrap();
2006 assert_eq!(root.kind.as_deref(), Some("module"));
2007 assert_eq!(root.children.len(), 2);
2008 assert_eq!(root.children[0].name.as_deref(), Some("add"));
2009 assert_eq!(root.children[1].name.as_deref(), Some("multiply"));
2010
2011 assert_eq!(decoded.ranges.len(), 1);
2013 let outer = &decoded.ranges[0];
2014 assert_eq!(outer.children.len(), 2);
2015
2016 let add_range = &outer.children[0];
2018 assert!(add_range.is_stack_frame);
2019 assert!(!add_range.is_hidden);
2020 assert_eq!(add_range.definition, Some(1));
2021 assert_eq!(
2022 add_range.call_site,
2023 Some(CallSite {
2024 source_index: 0,
2025 line: 45,
2026 column: 2
2027 })
2028 );
2029 assert_eq!(add_range.bindings[0], Binding::Expression("_a".to_string()));
2030 assert_eq!(add_range.bindings[1], Binding::Unavailable);
2031
2032 let mul_range = &outer.children[1];
2034 assert!(mul_range.is_stack_frame);
2035 assert!(mul_range.is_hidden);
2036 assert_eq!(mul_range.definition, Some(2));
2037 match &mul_range.bindings[0] {
2038 Binding::SubRanges(subs) => {
2039 assert_eq!(subs.len(), 2);
2040 assert_eq!(subs[0].expression.as_deref(), Some("p1"));
2041 assert_eq!(subs[1].expression.as_deref(), Some("p2"));
2042 }
2043 other => panic!("expected SubRanges, got {other:?}"),
2044 }
2045 assert_eq!(mul_range.bindings[1], Binding::Expression("_y".to_string()));
2046 }
2047
2048 #[test]
2049 fn range_end_column_only_1vlq() {
2050 let info = ScopeInfo {
2054 scopes: vec![],
2055 ranges: vec![GeneratedRange {
2056 start: Position { line: 0, column: 0 },
2057 end: Position {
2058 line: 5,
2059 column: 50,
2060 },
2061 is_stack_frame: false,
2062 is_hidden: false,
2063 definition: None,
2064 call_site: None,
2065 bindings: vec![],
2066 children: vec![GeneratedRange {
2067 start: Position { line: 2, column: 0 },
2068 end: Position {
2069 line: 5,
2070 column: 30,
2071 },
2072 is_stack_frame: false,
2073 is_hidden: false,
2074 definition: None,
2075 call_site: None,
2076 bindings: vec![],
2077 children: vec![],
2078 }],
2079 }],
2080 };
2081
2082 let mut names = vec![];
2083 let encoded = encode_scopes(&info, &mut names);
2084 let decoded = decode_scopes(&encoded, &names, 0).unwrap();
2085
2086 let outer = &decoded.ranges[0];
2087 assert_eq!(
2088 outer.end,
2089 Position {
2090 line: 5,
2091 column: 50
2092 }
2093 );
2094 let inner = &outer.children[0];
2095 assert_eq!(
2096 inner.end,
2097 Position {
2098 line: 5,
2099 column: 30
2100 }
2101 );
2102 }
2103
2104 #[test]
2105 fn all_sources_none_with_ranges() {
2106 let info = ScopeInfo {
2109 scopes: vec![None, None, None],
2110 ranges: vec![GeneratedRange {
2111 start: Position { line: 0, column: 0 },
2112 end: Position {
2113 line: 10,
2114 column: 0,
2115 },
2116 is_stack_frame: false,
2117 is_hidden: false,
2118 definition: None,
2119 call_site: None,
2120 bindings: vec![],
2121 children: vec![],
2122 }],
2123 };
2124
2125 let mut names = vec![];
2126 let encoded = encode_scopes(&info, &mut names);
2127 let decoded = decode_scopes(&encoded, &names, 3).unwrap();
2128
2129 assert_eq!(decoded.scopes.len(), 3);
2130 assert!(decoded.scopes.iter().all(|s| s.is_none()));
2131 assert_eq!(decoded.ranges.len(), 1);
2132 }
2133
2134 #[test]
2135 fn scope_name_only_no_kind() {
2136 let info = ScopeInfo {
2138 scopes: vec![Some(OriginalScope {
2139 start: Position { line: 0, column: 0 },
2140 end: Position { line: 5, column: 0 },
2141 name: Some("myVar".to_string()),
2142 kind: None,
2143 is_stack_frame: false,
2144 variables: vec![],
2145 children: vec![],
2146 })],
2147 ranges: vec![],
2148 };
2149
2150 let mut names = vec![];
2151 let encoded = encode_scopes(&info, &mut names);
2152 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
2153
2154 let scope = decoded.scopes[0].as_ref().unwrap();
2155 assert_eq!(scope.name.as_deref(), Some("myVar"));
2156 assert_eq!(scope.kind, None);
2157 }
2158
2159 #[test]
2160 fn generated_range_with_definition_on_nonzero_line() {
2161 let info = ScopeInfo {
2164 scopes: vec![Some(OriginalScope {
2165 start: Position { line: 0, column: 0 },
2166 end: Position {
2167 line: 50,
2168 column: 0,
2169 },
2170 name: None,
2171 kind: None,
2172 is_stack_frame: false,
2173 variables: vec![],
2174 children: vec![],
2175 })],
2176 ranges: vec![GeneratedRange {
2177 start: Position {
2178 line: 10,
2179 column: 5,
2180 },
2181 end: Position {
2182 line: 40,
2183 column: 0,
2184 },
2185 is_stack_frame: true,
2186 is_hidden: false,
2187 definition: Some(0),
2188 call_site: None,
2189 bindings: vec![],
2190 children: vec![],
2191 }],
2192 };
2193
2194 let mut names = vec![];
2195 let encoded = encode_scopes(&info, &mut names);
2196 let decoded = decode_scopes(&encoded, &names, 1).unwrap();
2197
2198 let range = &decoded.ranges[0];
2199 assert_eq!(
2200 range.start,
2201 Position {
2202 line: 10,
2203 column: 5
2204 }
2205 );
2206 assert_eq!(
2207 range.end,
2208 Position {
2209 line: 40,
2210 column: 0
2211 }
2212 );
2213 assert!(range.is_stack_frame);
2214 assert_eq!(range.definition, Some(0));
2215 }
2216
2217 #[test]
2220 fn decode_unmatched_scope_end() {
2221 let raw = "CAA";
2224 let names: Vec<String> = vec![];
2225 let err = decode_scopes(raw, &names, 1).unwrap_err();
2226 assert!(matches!(err, ScopesError::UnmatchedScopeEnd));
2227 }
2228
2229 #[test]
2230 fn decode_unclosed_scope() {
2231 let raw = "BAAA";
2234 let names: Vec<String> = vec![];
2235 let err = decode_scopes(raw, &names, 1).unwrap_err();
2236 assert!(matches!(err, ScopesError::UnclosedScope));
2237 }
2238
2239 #[test]
2240 fn decode_unmatched_range_end() {
2241 let raw = ",FA";
2245 let names: Vec<String> = vec![];
2246 let err = decode_scopes(raw, &names, 1).unwrap_err();
2247 assert!(matches!(err, ScopesError::UnmatchedRangeEnd));
2248 }
2249
2250 #[test]
2251 fn decode_unclosed_range() {
2252 let raw = ",EAAA";
2255 let names: Vec<String> = vec![];
2256 let err = decode_scopes(raw, &names, 1).unwrap_err();
2257 assert!(matches!(err, ScopesError::UnclosedRange));
2258 }
2259}