Skip to main content

git_policy_cli/
js_text.rs

1//! What:
2//!  Text operations with the exact semantics of the JavaScript built-ins the incumbent
3//!       applies to strings it shares with the native wrapper.
4//! Why:
5//!  Durable strings such as process birth identities are produced by `.trim()` in the
6//!      incumbent;
7//!  the native wrapper must produce byte-identical strings,
8//!  and Rust's
9//!      `str::trim` uses a different whitespace set (it trims U+0085 and keeps U+FEFF).
10//!
11//! In TS you'd write (pseudocode):
12//! ```ts
13//! text.trim()
14//! ```
15
16/// What:
17///  Whether a character is whitespace or a line terminator to ECMAScript `trim`.
18///       `char` is one Unicode scalar value.
19/// Why:
20///   ECMA-262 `TrimString` removes `WhiteSpace` (tab,
21///  vertical tab,
22///  form feed,
23///  space,
24///       no-break space,
25///  U+FEFF and every `Zs` character) and `LineTerminator` (LF,
26///  CR,
27///       U+2028,
28///  U+2029);
29///  nothing else.
30///
31/// In TS you'd write (pseudocode):
32/// ```ts
33/// /^\s$/u.test(character) // JavaScript's \s is exactly this set
34/// ```
35pub fn is_javascript_whitespace(character: char) -> bool {
36    // The `Zs` block U+2000 to U+200A is a range; every other member is listed.
37    if ('\u{2000}'..='\u{200a}').contains(&character) {
38        return true;
39    }
40    // `matches!` tests a value against a pattern of alternatives.
41    return matches!(
42        character,
43        '\u{0009}'
44            | '\u{000a}'
45            | '\u{000b}'
46            | '\u{000c}'
47            | '\u{000d}'
48            | '\u{0020}'
49            | '\u{00a0}'
50            | '\u{1680}'
51            | '\u{2028}'
52            | '\u{2029}'
53            | '\u{202f}'
54            | '\u{205f}'
55            | '\u{3000}'
56            | '\u{feff}'
57    );
58}
59
60/// What:
61///  Remove leading and trailing JavaScript whitespace,
62///  as `String.prototype.trim`.
63///       `&str` borrows text;
64///  the result borrows a slice of it.
65/// Why:
66///   Shared strings must be trimmed exactly as the incumbent trims them.
67///
68/// In TS you'd write (pseudocode):
69/// ```ts
70/// function trimJavascript(text: string): string { return text.trim(); }
71/// ```
72pub fn trim_javascript(text: &str) -> &str {
73    return text.trim_matches(is_javascript_whitespace);
74}
75
76/// What:
77///  Remove trailing JavaScript whitespace,
78///  as `String.prototype.trimEnd`.
79///       `&str` borrows text;
80///  the result borrows a slice of it.
81/// Why:
82///   Git's PID file text is trimmed at the end only before its `pid ` prefix is read.
83///
84/// In TS you'd write (pseudocode):
85/// ```ts
86/// function trimJavascriptEnd(text: string): string { return text.trimEnd(); }
87/// ```
88pub fn trim_javascript_end(text: &str) -> &str {
89    return text.trim_end_matches(is_javascript_whitespace);
90}
91
92/// The whitespace table stays out of the release executable.
93#[cfg(test)]
94#[path = "js_text_tests.rs"]
95mod tests;