Skip to main content

oxilean_parse/sourcemap/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::types::{BidiMapper, SortedSourceMap, SourceMapDiff};
6
7#[cfg(test)]
8mod tests {
9    use super::*;
10    use crate::sourcemap::*;
11    use crate::tokens::Span;
12    fn mk_span(start: usize, end: usize, line: usize, col: usize) -> Span {
13        Span::new(start, end, line, col)
14    }
15    #[test]
16    fn test_line_offsets_single_line() {
17        let sm = SourceMap::new("hello world");
18        assert_eq!(sm.line_count(), 1);
19        assert_eq!(sm.line_content(1), "hello world");
20    }
21    #[test]
22    fn test_line_offsets_multi_line() {
23        let sm = SourceMap::new("line1\nline2\nline3");
24        assert_eq!(sm.line_count(), 3);
25        assert_eq!(sm.line_content(1), "line1");
26        assert_eq!(sm.line_content(2), "line2");
27        assert_eq!(sm.line_content(3), "line3");
28    }
29    #[test]
30    fn test_line_content_out_of_bounds() {
31        let sm = SourceMap::new("hello");
32        assert_eq!(sm.line_content(0), "");
33        assert_eq!(sm.line_content(99), "");
34    }
35    #[test]
36    fn test_offset_to_position_first_line() {
37        let sm = SourceMap::new("hello\nworld");
38        assert_eq!(sm.offset_to_position(0), (1, 1));
39        assert_eq!(sm.offset_to_position(4), (1, 5));
40    }
41    #[test]
42    fn test_offset_to_position_second_line() {
43        let sm = SourceMap::new("hello\nworld");
44        assert_eq!(sm.offset_to_position(6), (2, 1));
45        assert_eq!(sm.offset_to_position(10), (2, 5));
46    }
47    #[test]
48    fn test_position_to_offset_roundtrip() {
49        let sm = SourceMap::new("abc\ndef\nghi");
50        for offset in 0..11 {
51            let (line, col) = sm.offset_to_position(offset);
52            let back = sm.position_to_offset(line, col);
53            assert_eq!(back, offset, "roundtrip failed for offset {}", offset);
54        }
55    }
56    #[test]
57    fn test_position_to_offset_clamped() {
58        let sm = SourceMap::new("abc");
59        let off = sm.position_to_offset(1, 100);
60        assert_eq!(off, 3);
61    }
62    #[test]
63    fn test_builder_basic() {
64        let mut builder = SourceMapBuilder::new("def foo := 42");
65        builder.add_definition(mk_span(4, 7, 1, 5), "foo");
66        builder.add_literal(mk_span(11, 13, 1, 12));
67        let sm = builder.build();
68        assert_eq!(sm.entries().len(), 2);
69    }
70    #[test]
71    fn test_builder_add_reference() {
72        let mut builder = SourceMapBuilder::new("foo + bar");
73        builder.add_reference(mk_span(0, 3, 1, 1), "foo");
74        builder.add_reference(mk_span(6, 9, 1, 7), "bar");
75        let sm = builder.build();
76        let refs = sm.references_to("foo");
77        assert_eq!(refs.len(), 1);
78        assert_eq!(refs[0].span.start, 0);
79    }
80    #[test]
81    fn test_builder_entry_count() {
82        let mut builder = SourceMapBuilder::new("test");
83        assert_eq!(builder.entry_count(), 0);
84        builder.add_keyword(mk_span(0, 4, 1, 1));
85        assert_eq!(builder.entry_count(), 1);
86    }
87    #[test]
88    fn test_builder_sorted_output() {
89        let mut builder = SourceMapBuilder::new("a b c");
90        builder.add_entry(
91            mk_span(4, 5, 1, 5),
92            EntryKind::Reference,
93            Some("c".to_string()),
94        );
95        builder.add_entry(
96            mk_span(0, 1, 1, 1),
97            EntryKind::Reference,
98            Some("a".to_string()),
99        );
100        builder.add_entry(
101            mk_span(2, 3, 1, 3),
102            EntryKind::Reference,
103            Some("b".to_string()),
104        );
105        let sm = builder.build();
106        let entries = sm.entries();
107        assert!(entries[0].span.start <= entries[1].span.start);
108        assert!(entries[1].span.start <= entries[2].span.start);
109    }
110    #[test]
111    fn test_entry_at() {
112        let mut builder = SourceMapBuilder::new("def foo := 42");
113        builder.add_keyword(mk_span(0, 3, 1, 1));
114        builder.add_definition(mk_span(4, 7, 1, 5), "foo");
115        builder.add_literal(mk_span(11, 13, 1, 12));
116        let sm = builder.build();
117        let kw = sm.entry_at(1, 2);
118        assert!(kw.is_some());
119        assert_eq!(
120            kw.expect("test operation should succeed").kind,
121            EntryKind::Keyword
122        );
123        let def = sm.entry_at(1, 5);
124        assert!(def.is_some());
125        assert_eq!(
126            def.expect("type conversion should succeed").name.as_deref(),
127            Some("foo")
128        );
129    }
130    #[test]
131    fn test_entry_at_empty() {
132        let sm = SourceMap::new("hello");
133        assert!(sm.entry_at(1, 1).is_none());
134    }
135    #[test]
136    fn test_definitions_query() {
137        let mut builder = SourceMapBuilder::new("def a def b");
138        builder.add_definition(mk_span(4, 5, 1, 5), "a");
139        builder.add_definition(mk_span(10, 11, 1, 11), "b");
140        builder.add_reference(mk_span(0, 1, 1, 1), "a");
141        let sm = builder.build();
142        let defs = sm.definitions();
143        assert_eq!(defs.len(), 2);
144    }
145    #[test]
146    fn test_references_to() {
147        let mut builder = SourceMapBuilder::new("foo foo bar foo");
148        builder.add_reference(mk_span(0, 3, 1, 1), "foo");
149        builder.add_reference(mk_span(4, 7, 1, 5), "foo");
150        builder.add_reference(mk_span(8, 11, 1, 9), "bar");
151        builder.add_reference(mk_span(12, 15, 1, 13), "foo");
152        let sm = builder.build();
153        assert_eq!(sm.references_to("foo").len(), 3);
154        assert_eq!(sm.references_to("bar").len(), 1);
155        assert_eq!(sm.references_to("baz").len(), 0);
156    }
157    #[test]
158    fn test_entries_in_range() {
159        let mut builder = SourceMapBuilder::new("abcdefghij");
160        builder.add_entry(
161            mk_span(0, 3, 1, 1),
162            EntryKind::Reference,
163            Some("a".to_string()),
164        );
165        builder.add_entry(
166            mk_span(4, 7, 1, 5),
167            EntryKind::Reference,
168            Some("b".to_string()),
169        );
170        builder.add_entry(
171            mk_span(8, 10, 1, 9),
172            EntryKind::Reference,
173            Some("c".to_string()),
174        );
175        let sm = builder.build();
176        let range_start = mk_span(2, 2, 1, 3);
177        let range_end = mk_span(6, 6, 1, 7);
178        let in_range = sm.entries_in_range(&range_start, &range_end);
179        assert_eq!(in_range.len(), 2);
180    }
181    #[test]
182    fn test_hover_info_on_definition() {
183        let mut builder = SourceMapBuilder::new("def foo := 42");
184        builder.add_definition_with_type(mk_span(4, 7, 1, 5), "foo", "Nat");
185        let sm = builder.build();
186        let hover = sm.hover_info(1, 5);
187        assert!(hover.is_some());
188        let info = hover.expect("test operation should succeed");
189        assert_eq!(info.name, "foo");
190        assert_eq!(info.kind, EntryKind::Definition);
191        assert_eq!(info.ty.as_deref(), Some("Nat"));
192        assert!(info.definition_span.is_some());
193    }
194    #[test]
195    fn test_hover_info_on_reference() {
196        let mut builder = SourceMapBuilder::new("def foo := foo");
197        builder.add_definition(mk_span(4, 7, 1, 5), "foo");
198        builder.add_reference(mk_span(11, 14, 1, 12), "foo");
199        let sm = builder.build();
200        let hover = sm.hover_info(1, 12);
201        assert!(hover.is_some());
202        let info = hover.expect("test operation should succeed");
203        assert_eq!(info.name, "foo");
204        assert_eq!(info.kind, EntryKind::Reference);
205        assert!(info.definition_span.is_some());
206        assert_eq!(
207            info.definition_span.expect("span should be present").start,
208            4
209        );
210    }
211    #[test]
212    fn test_hover_info_no_entry() {
213        let sm = SourceMap::new("hello");
214        assert!(sm.hover_info(1, 1).is_none());
215    }
216    #[test]
217    fn test_hover_info_with_doc_comment() {
218        let source = "/-- A doc comment -/
219def foo := 42";
220        let mut builder = SourceMapBuilder::new(source);
221        builder.add_doc_comment(mk_span(0, 20, 1, 1), "A doc comment");
222        builder.add_definition(mk_span(25, 28, 2, 5), "foo");
223        let sm = builder.build();
224        let hover = sm.hover_info(2, 5);
225        assert!(hover.is_some());
226        let info = hover.expect("test operation should succeed");
227        assert_eq!(info.name, "foo");
228        assert_eq!(info.doc.as_deref(), Some("A doc comment"));
229    }
230    #[test]
231    fn test_hover_info_doc_comment_separated_by_non_whitespace() {
232        let source = "/-- doc -/ something def foo := 42";
233        let mut builder = SourceMapBuilder::new(source);
234        builder.add_doc_comment(mk_span(0, 10, 1, 1), "doc");
235        builder.add_reference(mk_span(11, 20, 1, 12), "something");
236        builder.add_definition(mk_span(25, 28, 1, 26), "foo");
237        let sm = builder.build();
238        let hover = sm.hover_info(1, 26);
239        assert!(hover.is_some());
240        let info = hover.expect("test operation should succeed");
241        assert!(info.doc.is_none());
242    }
243    #[test]
244    fn test_hover_info_doc_comment_via_reference() {
245        let source = "/-- bar docs -/
246def bar := 0
247bar";
248        let mut builder = SourceMapBuilder::new(source);
249        builder.add_doc_comment(mk_span(0, 15, 1, 1), "bar docs");
250        builder.add_definition(mk_span(20, 23, 2, 5), "bar");
251        builder.add_reference(mk_span(29, 32, 3, 1), "bar");
252        let sm = builder.build();
253        let hover = sm.hover_info(3, 1);
254        assert!(hover.is_some());
255        let info = hover.expect("test operation should succeed");
256        assert_eq!(info.name, "bar");
257        assert_eq!(info.doc.as_deref(), Some("bar docs"));
258    }
259    #[test]
260    fn test_semantic_tokens_from_entries() {
261        let mut builder = SourceMapBuilder::new("def foo := 42");
262        builder.add_keyword(mk_span(0, 3, 1, 1));
263        builder.add_definition(mk_span(4, 7, 1, 5), "foo");
264        builder.add_literal(mk_span(11, 13, 1, 12));
265        let sm = builder.build();
266        let tokens = sm.semantic_tokens();
267        assert_eq!(tokens.len(), 3);
268        assert_eq!(tokens[0].token_type, SemanticTokenType::Keyword);
269        assert_eq!(tokens[1].token_type, SemanticTokenType::Function);
270        assert!(tokens[1].modifiers.contains(&SemanticModifier::Definition));
271        assert_eq!(tokens[2].token_type, SemanticTokenType::Number);
272    }
273    #[test]
274    fn test_semantic_tokens_precomputed() {
275        let mut builder = SourceMapBuilder::new("x");
276        builder.add_semantic_token(SemanticToken::new(
277            mk_span(0, 1, 1, 1),
278            SemanticTokenType::Variable,
279        ));
280        let sm = builder.build();
281        let tokens = sm.semantic_tokens();
282        assert_eq!(tokens.len(), 1);
283        assert_eq!(tokens[0].token_type, SemanticTokenType::Variable);
284    }
285    #[test]
286    fn test_go_to_definition() {
287        let mut builder = SourceMapBuilder::new("def foo := foo");
288        builder.add_definition(mk_span(4, 7, 1, 5), "foo");
289        builder.add_reference(mk_span(11, 14, 1, 12), "foo");
290        let sm = builder.build();
291        let def_span = sm.go_to_definition(1, 12);
292        assert!(def_span.is_some());
293        assert_eq!(def_span.expect("span should be present").start, 4);
294    }
295    #[test]
296    fn test_find_all_occurrences() {
297        let mut builder = SourceMapBuilder::new("def foo := foo + foo");
298        builder.add_definition(mk_span(4, 7, 1, 5), "foo");
299        builder.add_reference(mk_span(11, 14, 1, 12), "foo");
300        builder.add_reference(mk_span(17, 20, 1, 18), "foo");
301        let sm = builder.build();
302        let all = sm.find_all_occurrences(1, 5);
303        assert_eq!(all.len(), 3);
304    }
305    #[test]
306    fn test_span_text() {
307        let sm = SourceMap::new("hello world");
308        let span = mk_span(6, 11, 1, 7);
309        assert_eq!(sm.span_text(&span), "world");
310    }
311    #[test]
312    fn test_source_entry_contains_offset() {
313        let entry = SourceEntry::new(mk_span(5, 10, 1, 6), EntryKind::Reference);
314        assert!(!entry.contains_offset(4));
315        assert!(entry.contains_offset(5));
316        assert!(entry.contains_offset(9));
317        assert!(!entry.contains_offset(10));
318    }
319    #[test]
320    fn test_source_entry_with_name() {
321        let entry = SourceEntry::with_name(mk_span(0, 3, 1, 1), EntryKind::Definition, "foo");
322        assert_eq!(entry.name.as_deref(), Some("foo"));
323        assert!(entry.ty_info.is_none());
324    }
325    #[test]
326    fn test_source_entry_with_name_and_type() {
327        let entry = SourceEntry::with_name_and_type(
328            mk_span(0, 3, 1, 1),
329            EntryKind::Definition,
330            "foo",
331            "Nat",
332        );
333        assert_eq!(entry.name.as_deref(), Some("foo"));
334        assert_eq!(entry.ty_info.as_deref(), Some("Nat"));
335    }
336    #[test]
337    fn test_entries_of_kind() {
338        let mut builder = SourceMapBuilder::new("test");
339        builder.add_keyword(mk_span(0, 1, 1, 1));
340        builder.add_keyword(mk_span(1, 2, 1, 2));
341        builder.add_literal(mk_span(2, 3, 1, 3));
342        let sm = builder.build();
343        assert_eq!(sm.entries_of_kind(&EntryKind::Keyword).len(), 2);
344        assert_eq!(sm.entries_of_kind(&EntryKind::Literal).len(), 1);
345        assert_eq!(sm.entries_of_kind(&EntryKind::Definition).len(), 0);
346    }
347    #[test]
348    fn test_builder_add_various_kinds() {
349        let mut builder = SourceMapBuilder::new("test source");
350        builder.add_binder(mk_span(0, 1, 1, 1), "x");
351        builder.add_constructor(mk_span(1, 2, 1, 2), "Foo");
352        builder.add_operator(mk_span(2, 3, 1, 3), "+");
353        builder.add_comment(mk_span(3, 4, 1, 4));
354        builder.add_doc_comment(mk_span(4, 5, 1, 5), "docs");
355        builder.add_tactic(mk_span(5, 6, 1, 6), "simp");
356        builder.add_pattern(mk_span(6, 7, 1, 7), Some("pat"));
357        builder.add_type_annotation(mk_span(7, 8, 1, 8));
358        let sm = builder.build();
359        assert_eq!(sm.entries().len(), 8);
360    }
361    #[test]
362    fn test_semantic_token_constructors() {
363        let tok = SemanticToken::new(mk_span(0, 1, 1, 1), SemanticTokenType::Keyword);
364        assert!(tok.modifiers.is_empty());
365        let tok2 = SemanticToken::with_modifiers(
366            mk_span(0, 1, 1, 1),
367            SemanticTokenType::Function,
368            vec![SemanticModifier::Definition, SemanticModifier::Declaration],
369        );
370        assert_eq!(tok2.modifiers.len(), 2);
371    }
372}
373#[cfg(test)]
374mod extended_sourcemap_tests {
375    use super::*;
376    use crate::sourcemap::*;
377    use crate::tokens::Span;
378    fn mk_span(start: usize, end: usize, line: usize, col: usize) -> Span {
379        Span::new(start, end, line, col)
380    }
381    #[test]
382    fn test_source_position_origin() {
383        let pos = SourcePosition::origin();
384        assert_eq!(pos.offset, 0);
385        assert_eq!(pos.line, 1);
386        assert_eq!(pos.column, 1);
387    }
388    #[test]
389    fn test_source_position_advance_col() {
390        let pos = SourcePosition::origin().advance_col(1);
391        assert_eq!(pos.offset, 1);
392        assert_eq!(pos.column, 2);
393        assert_eq!(pos.line, 1);
394    }
395    #[test]
396    fn test_source_position_advance_line() {
397        let pos = SourcePosition::origin().advance_line(1);
398        assert_eq!(pos.line, 2);
399        assert_eq!(pos.column, 1);
400    }
401    #[test]
402    fn test_source_position_ordering() {
403        let a = SourcePosition::new(5, 1, 5);
404        let b = SourcePosition::new(10, 2, 3);
405        assert!(a.is_before(&b));
406        assert!(b.is_after(&a));
407    }
408    #[test]
409    fn test_source_region_contains() {
410        let span = mk_span(10, 20, 1, 10);
411        let region = SourceRegion::new("body", span);
412        assert!(region.contains_offset(15));
413        assert!(!region.contains_offset(25));
414        assert_eq!(region.byte_len(), 10);
415    }
416    #[test]
417    fn test_definition_index_basic() {
418        let mut idx = DefinitionIndex::new();
419        idx.register("foo", mk_span(0, 3, 1, 1));
420        idx.register("foo", mk_span(10, 13, 2, 1));
421        assert_eq!(idx.lookup("foo").len(), 2);
422        assert!(idx.contains("foo"));
423        assert!(!idx.contains("bar"));
424    }
425    #[test]
426    fn test_definition_index_merge() {
427        let mut a = DefinitionIndex::new();
428        a.register("foo", mk_span(0, 3, 1, 1));
429        let mut b = DefinitionIndex::new();
430        b.register("bar", mk_span(5, 8, 2, 1));
431        a.merge(b);
432        assert_eq!(a.len(), 2);
433        assert!(a.contains("foo"));
434        assert!(a.contains("bar"));
435    }
436    #[test]
437    fn test_reference_index_basic() {
438        let mut idx = ReferenceIndex::new();
439        idx.record("add", mk_span(0, 3, 1, 1));
440        idx.record("add", mk_span(10, 13, 2, 1));
441        idx.record("sub", mk_span(5, 8, 1, 5));
442        assert_eq!(idx.uses_of("add").len(), 2);
443        assert_eq!(idx.total_references(), 3);
444    }
445    #[test]
446    fn test_document_symbol_flatten() {
447        let mut sym = DocumentSymbol::new(
448            "Foo".to_string(),
449            SymbolKind::Structure,
450            mk_span(0, 100, 1, 1),
451            mk_span(0, 3, 1, 1),
452        );
453        let child = DocumentSymbol::new(
454            "bar".to_string(),
455            SymbolKind::Field,
456            mk_span(10, 20, 2, 3),
457            mk_span(10, 13, 2, 3),
458        );
459        sym.add_child(child);
460        let flat = sym.flatten();
461        assert_eq!(flat.len(), 2);
462        assert_eq!(flat[0].name, "Foo");
463        assert_eq!(flat[1].name, "bar");
464    }
465    #[test]
466    fn test_document_symbol_find_by_name() {
467        let mut sym = DocumentSymbol::new(
468            "Root".to_string(),
469            SymbolKind::Namespace,
470            mk_span(0, 200, 1, 1),
471            mk_span(0, 4, 1, 1),
472        );
473        let inner = DocumentSymbol::new(
474            "inner_fn".to_string(),
475            SymbolKind::Definition,
476            mk_span(10, 50, 2, 1),
477            mk_span(10, 18, 2, 1),
478        );
479        sym.add_child(inner);
480        assert!(sym.find_by_name("inner_fn").is_some());
481        assert!(sym.find_by_name("missing").is_none());
482    }
483    #[test]
484    fn test_source_index_symbol_at_offset() {
485        let mut idx = SourceIndex::new();
486        let sym = DocumentSymbol::new(
487            "myDef".to_string(),
488            SymbolKind::Definition,
489            mk_span(5, 50, 1, 5),
490            mk_span(5, 10, 1, 5),
491        );
492        idx.add_symbol(sym);
493        assert!(idx.symbol_at_offset(10).is_some());
494        assert!(idx.symbol_at_offset(100).is_none());
495    }
496    #[test]
497    fn test_goto_definition_result() {
498        let spans = vec![mk_span(0, 5, 1, 1)];
499        let result = GoToDefinitionResult::new("foo".to_string(), spans, true);
500        assert!(result.found());
501        assert!(result.is_local);
502        assert_eq!(
503            result.primary_span().expect("span should be present").start,
504            0
505        );
506    }
507    #[test]
508    fn test_goto_definition_not_found() {
509        let result = GoToDefinitionResult::new("unknown".to_string(), vec![], false);
510        assert!(!result.found());
511        assert!(result.primary_span().is_none());
512    }
513    #[test]
514    fn test_diagnostic_severity_ordering() {
515        assert!(DiagnosticSeverity::Hint < DiagnosticSeverity::Warning);
516        assert!(DiagnosticSeverity::Warning < DiagnosticSeverity::Error);
517    }
518    #[test]
519    fn test_source_diagnostic_constructors() {
520        let span = mk_span(0, 5, 1, 1);
521        let err = SourceDiagnostic::error(span.clone(), "bad token");
522        assert!(err.is_error());
523        assert!(!err.is_warning());
524        let warn = SourceDiagnostic::warning(span, "maybe bad");
525        assert!(warn.is_warning());
526    }
527    #[test]
528    fn test_source_diagnostic_with_code() {
529        let span = mk_span(0, 5, 1, 1);
530        let diag = SourceDiagnostic::error(span, "msg").with_code("E001");
531        assert_eq!(diag.code.as_deref(), Some("E001"));
532    }
533    #[test]
534    fn test_source_map_stats() {
535        let entries = vec![
536            SourceEntry::new(mk_span(0, 1, 1, 1), EntryKind::Definition),
537            SourceEntry::new(mk_span(1, 2, 1, 2), EntryKind::Reference),
538            SourceEntry::new(mk_span(2, 3, 1, 3), EntryKind::Tactic),
539            SourceEntry::new(mk_span(3, 4, 1, 4), EntryKind::Comment),
540            SourceEntry::new(mk_span(4, 5, 1, 5), EntryKind::Operator),
541        ];
542        let stats = SourceMapStats::from_entries(&entries);
543        assert_eq!(stats.total_entries, 5);
544        assert_eq!(stats.definitions, 1);
545        assert_eq!(stats.references, 1);
546        assert_eq!(stats.tactics, 1);
547        assert_eq!(stats.comments, 1);
548        assert_eq!(stats.operators, 1);
549    }
550}
551#[cfg(test)]
552mod sourcemap_ext_tests {
553    use super::*;
554    use crate::sourcemap::*;
555    use crate::tokens::Span;
556    #[test]
557    fn test_bidi_mapper() {
558        let mut m = BidiMapper::new();
559        m.add(0, 0);
560        m.add(5, 10);
561        m.add(10, 20);
562        assert_eq!(m.to_gen(0), Some(0));
563        assert_eq!(m.to_gen(7), Some(10));
564        assert_eq!(m.to_orig(15), Some(5));
565    }
566    #[test]
567    fn test_range_transform() {
568        let rt = RangeTransform::new(0, 10, 0, 10);
569        assert!(rt.is_length_preserving());
570        let rt2 = RangeTransform::new(0, 10, 0, 20);
571        assert!(!rt2.is_length_preserving());
572    }
573    #[test]
574    fn test_map_chain() {
575        let mut m1 = BidiMapper::new();
576        m1.add(0, 0);
577        m1.add(5, 5);
578        let mut m2 = BidiMapper::new();
579        m2.add(0, 0);
580        m2.add(5, 10);
581        let chain = MapChain::new(m1, m2);
582        let c = chain.a_to_c(5);
583        assert_eq!(c, Some(10));
584    }
585}
586/// Compare two BidiMappers and return a diff.
587#[allow(dead_code)]
588#[allow(missing_docs)]
589pub fn diff_mappers(old: &BidiMapper, new: &BidiMapper) -> SourceMapDiff {
590    let old_set: std::collections::HashSet<(usize, usize)> = old.forward.iter().cloned().collect();
591    let new_set: std::collections::HashSet<(usize, usize)> = new.forward.iter().cloned().collect();
592    let added = new_set.difference(&old_set).count();
593    let removed = old_set.difference(&new_set).count();
594    SourceMapDiff {
595        added,
596        removed,
597        modified: 0,
598    }
599}
600#[cfg(test)]
601mod sourcemap_ext2_tests {
602    use super::*;
603    use crate::sourcemap::*;
604    use crate::tokens::Span;
605    #[test]
606    fn test_source_map_cache() {
607        let mut cache = SourceMapCache::new();
608        cache.insert(1, 5, 10, 3);
609        assert_eq!(cache.lookup(1, 5), Some((10, 3)));
610        assert_eq!(cache.lookup(2, 0), None);
611    }
612    #[test]
613    fn test_diff_mappers() {
614        let mut m1 = BidiMapper::new();
615        m1.add(0, 0);
616        m1.add(5, 10);
617        let mut m2 = BidiMapper::new();
618        m2.add(0, 0);
619        m2.add(6, 12);
620        let diff = diff_mappers(&m1, &m2);
621        assert_eq!(diff.added, 1);
622        assert_eq!(diff.removed, 1);
623    }
624}
625#[cfg(test)]
626mod sorted_sourcemap_tests {
627    use super::*;
628    use crate::sourcemap::*;
629    use crate::tokens::Span;
630    #[test]
631    fn test_sorted_source_map() {
632        let mut sm = SortedSourceMap::new();
633        sm.add(0, 0);
634        sm.add(10, 5);
635        sm.add(20, 15);
636        assert_eq!(sm.lookup(0), Some(0));
637        assert_eq!(sm.lookup(15), Some(5));
638        assert_eq!(sm.lookup(100), Some(15));
639    }
640}
641/// A source map entry formatter (JSON-like).
642#[allow(dead_code)]
643#[allow(missing_docs)]
644pub fn format_map_entry_json(
645    orig_line: usize,
646    orig_col: usize,
647    gen_line: usize,
648    gen_col: usize,
649) -> String {
650    format!(
651        r#"{{"origLine":{},"origCol":{},"genLine":{},"genCol":{}}}"#,
652        orig_line, orig_col, gen_line, gen_col
653    )
654}
655#[cfg(test)]
656mod sourcemap_batch_tests {
657    use super::*;
658    use crate::sourcemap::*;
659    use crate::tokens::Span;
660    #[test]
661    fn test_format_map_entry_json() {
662        let s = format_map_entry_json(1, 0, 2, 5);
663        assert!(s.contains("origLine"));
664        assert!(s.contains("genLine"));
665    }
666    #[test]
667    fn test_source_map_batch() {
668        let mut batch = SourceMapBatch::new();
669        batch.add(RangeTransform::new(0, 10, 0, 10));
670        batch.add(RangeTransform::new(10, 20, 10, 25));
671        assert_eq!(batch.total_coverage(), 20);
672        assert_eq!(batch.length_preserving_count(), 1);
673    }
674}
675/// Merges two sorted source maps.
676#[allow(dead_code)]
677#[allow(missing_docs)]
678pub fn merge_sorted_maps(a: SortedSourceMap, b: SortedSourceMap) -> SortedSourceMap {
679    let mut result = SortedSourceMap::new();
680    for (gen, orig) in a.pairs.into_iter().chain(b.pairs) {
681        result.add(gen, orig);
682    }
683    result
684}
685/// Returns true if a sorted source map has no duplicate gen offsets.
686#[allow(dead_code)]
687#[allow(missing_docs)]
688pub fn is_injective(map: &SortedSourceMap) -> bool {
689    let gens: Vec<usize> = map.pairs.iter().map(|(g, _)| *g).collect();
690    let mut seen = std::collections::HashSet::new();
691    gens.iter().all(|g| seen.insert(*g))
692}
693#[cfg(test)]
694mod sourcemap_pad {
695    use super::*;
696    use crate::sourcemap::*;
697    use crate::tokens::Span;
698    #[test]
699    fn test_merge_sorted_maps() {
700        let mut a = SortedSourceMap::new();
701        a.add(0, 0);
702        let mut b = SortedSourceMap::new();
703        b.add(5, 10);
704        let merged = merge_sorted_maps(a, b);
705        assert_eq!(merged.len(), 2);
706    }
707    #[test]
708    fn test_is_injective() {
709        let mut m = SortedSourceMap::new();
710        m.add(0, 0);
711        m.add(5, 10);
712        assert!(is_injective(&m));
713    }
714}
715/// Returns the total number of mappings in a sorted source map.
716#[allow(dead_code)]
717#[allow(missing_docs)]
718pub fn total_mappings(m: &SortedSourceMap) -> usize {
719    m.len()
720}
721/// Returns the maximum generated offset in a source map, if any.
722#[allow(dead_code)]
723#[allow(missing_docs)]
724pub fn max_gen_offset(m: &SortedSourceMap) -> Option<usize> {
725    m.pairs.iter().map(|(g, _)| *g).max()
726}
727/// Returns the minimum generated offset in a source map, if any.
728#[allow(dead_code)]
729#[allow(missing_docs)]
730pub fn min_gen_offset(m: &SortedSourceMap) -> Option<usize> {
731    m.pairs.iter().map(|(g, _)| *g).min()
732}
733/// Returns true if a source map covers a generated offset.
734#[allow(dead_code)]
735#[allow(missing_docs)]
736pub fn covers_gen_offset(m: &SortedSourceMap, gen: usize) -> bool {
737    m.pairs.iter().any(|(g, _)| *g == gen)
738}
739/// Returns all original offsets in a source map.
740#[allow(dead_code)]
741#[allow(missing_docs)]
742pub fn all_orig_offsets(m: &SortedSourceMap) -> Vec<usize> {
743    m.pairs.iter().map(|(_, o)| *o).collect()
744}
745#[cfg(test)]
746mod sourcemap_pad2 {
747    use super::*;
748    use crate::sourcemap::*;
749    use crate::tokens::Span;
750    #[test]
751    fn test_max_min_gen_offset() {
752        let mut m = SortedSourceMap::new();
753        m.add(5, 10);
754        m.add(2, 4);
755        m.add(8, 20);
756        assert_eq!(max_gen_offset(&m), Some(8));
757        assert_eq!(min_gen_offset(&m), Some(2));
758    }
759    #[test]
760    fn test_covers_gen_offset() {
761        let mut m = SortedSourceMap::new();
762        m.add(3, 6);
763        assert!(covers_gen_offset(&m, 3));
764        assert!(!covers_gen_offset(&m, 4));
765    }
766}
767/// Returns true if all generated offsets in the map are in ascending order.
768#[allow(dead_code)]
769#[allow(missing_docs)]
770pub fn is_sorted_ascending(m: &SortedSourceMap) -> bool {
771    m.pairs.windows(2).all(|w| w[0].0 <= w[1].0)
772}
773/// Filters a source map to only entries where the generated offset is >= lo and < hi.
774#[allow(dead_code)]
775#[allow(missing_docs)]
776pub fn filter_gen_range(m: &SortedSourceMap, lo: usize, hi: usize) -> SortedSourceMap {
777    let mut result = SortedSourceMap::new();
778    for &(gen, orig) in &m.pairs {
779        if gen >= lo && gen < hi {
780            result.add(gen, orig);
781        }
782    }
783    result
784}
785/// Returns the number of mappings that map to a specific original offset.
786#[allow(dead_code)]
787#[allow(missing_docs)]
788pub fn count_to_orig(m: &SortedSourceMap, orig: usize) -> usize {
789    m.pairs.iter().filter(|(_, o)| *o == orig).count()
790}