headless_lms_server/programs/
sorter.rs

1//! Manually sorts...
2//! - ts_binding_generator's export blocks
3pub fn sort() -> anyhow::Result<()> {
4    sort_ts_binding_generator()?;
5    Ok(())
6}
7
8// sort export blocks in ts_binding_generator
9fn sort_ts_binding_generator() -> anyhow::Result<()> {
10    let path = concat!(env!("CARGO_MANIFEST_DIR"), "/src/ts_binding_generator.rs");
11    let contents = std::fs::read_to_string(path)?;
12
13    let mut file_lines_after_sorting = vec![];
14    let mut in_export = false;
15    let mut current_exports = vec![];
16
17    // process file line by line
18    for line in contents.lines() {
19        if in_export && line.contains('}') {
20            // end of export block
21            in_export = false;
22
23            if !current_exports.is_empty() {
24                // the first line should contain the target
25                let target = current_exports.remove(0);
26                file_lines_after_sorting.push(target);
27                file_lines_after_sorting.push("");
28
29                // sort all lines other than target
30                current_exports.sort_unstable();
31
32                // for large export blocks, group based on first letter
33                if current_exports.len() > 64 {
34                    let mut grouped_exports = Vec::new();
35                    let mut current_group_letter = None;
36
37                    // process export block line by line
38                    for export in current_exports {
39                        // trim starting whitespace to check the first letter
40                        let trimmed = export.trim_start();
41                        if current_group_letter
42                            .map(|p| !trimmed.starts_with(p))
43                            .unwrap_or(false)
44                        {
45                            // start of new group
46                            grouped_exports.push("");
47                        }
48                        current_group_letter = trimmed.chars().next();
49                        grouped_exports.push(export);
50                    }
51                    current_exports = grouped_exports;
52                }
53
54                file_lines_after_sorting.extend(current_exports.drain(0..));
55            }
56        }
57
58        if in_export {
59            if !line.trim().is_empty() {
60                current_exports.push(line);
61            }
62        } else {
63            // lines outside exports don't need to be sorted
64            file_lines_after_sorting.push(line);
65        }
66
67        if line.contains("export!") {
68            in_export = true;
69        }
70    }
71
72    file_lines_after_sorting.push(""); // trailing newline
73    std::fs::write(path, file_lines_after_sorting.join("\n"))?;
74    Ok(())
75}