Skip to main content

smelt_stdlib/
classes.rs

1//! Synthetic standard-library class recognition shared by frontends and codegen.
2
3/// Standard-library class modeled with dedicated runtime support instead of
4/// user-defined struct emission.
5#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
6#[non_exhaustive]
7pub enum StdlibClass {
8    /// JavaScript `Date`, represented by timestamp and date helper operations.
9    Date,
10    /// JavaScript `Map`, represented by dictionary HIR values.
11    Map,
12    /// Synthetic `RegExp` match result (`RegExp.exec` / `String.matchAll`),
13    /// backed by the generated concrete `SmeltMatch` runtime type. Consumer
14    /// reads (`m[0]`, `m.index`, `m.input`, `m.groups.name`) resolve to typed
15    /// accessors on `SmeltMatch` instead of the erased `SmeltUnknown` path.
16    Match,
17    /// Synthetic named-capture-group accessor for `matchResult.groups`. It is
18    /// the same underlying `SmeltMatch` value; a `.name` read on it resolves to
19    /// the typed named-group accessor.
20    MatchGroups,
21    /// Remeda parser helper result class synthesized during TypeScript lowering.
22    MatchFnResult,
23    /// JavaScript `RegExp`, backed by the generated regex runtime shim.
24    RegExp,
25    /// JavaScript `Set`, represented by set HIR values.
26    Set,
27}
28
29/// Reserved synthetic class name for a `RegExp` match result value.
30///
31/// The name is not writable in user TypeScript (double-underscore prefix), so
32/// it never collides with a source class; it exists only to carry the concrete
33/// match shape through the internal type system.
34pub const MATCH_CLASS_NAME: &str = "__SmeltMatch";
35
36/// Reserved synthetic class name for `matchResult.groups` named-group access.
37pub const MATCH_GROUPS_CLASS_NAME: &str = "__SmeltMatchGroups";
38
39/// Return the stdlib class modeled by a TypeScript class type name.
40///
41/// Codegen consults this instead of comparing class symbol names inline so
42/// stdlib class identities stay in one registry.
43#[must_use]
44pub fn typescript_stdlib_class(name: &str) -> Option<StdlibClass> {
45    match name {
46        "Date" => Some(StdlibClass::Date),
47        "Map" => Some(StdlibClass::Map),
48        MATCH_CLASS_NAME => Some(StdlibClass::Match),
49        MATCH_GROUPS_CLASS_NAME => Some(StdlibClass::MatchGroups),
50        "MatchFnResult" => Some(StdlibClass::MatchFnResult),
51        "RegExp" => Some(StdlibClass::RegExp),
52        "Set" => Some(StdlibClass::Set),
53        _ => None,
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::*;
60
61    /// Exact stdlib class names resolve to their registry identity.
62    #[test]
63    fn recognizes_stdlib_class_names() {
64        assert_eq!(typescript_stdlib_class("Date"), Some(StdlibClass::Date));
65        assert_eq!(typescript_stdlib_class("Map"), Some(StdlibClass::Map));
66        assert_eq!(
67            typescript_stdlib_class(MATCH_CLASS_NAME),
68            Some(StdlibClass::Match)
69        );
70        assert_eq!(
71            typescript_stdlib_class(MATCH_GROUPS_CLASS_NAME),
72            Some(StdlibClass::MatchGroups)
73        );
74        assert_eq!(
75            typescript_stdlib_class("MatchFnResult"),
76            Some(StdlibClass::MatchFnResult)
77        );
78        assert_eq!(typescript_stdlib_class("RegExp"), Some(StdlibClass::RegExp));
79        assert_eq!(typescript_stdlib_class("Set"), Some(StdlibClass::Set));
80    }
81
82    /// User class names never resolve to a stdlib identity.
83    #[test]
84    fn rejects_user_class_names() {
85        for name in ["Regexp", "RegExpLike", "Dates", "HashMap", "MyClass"] {
86            assert_eq!(typescript_stdlib_class(name), None);
87        }
88    }
89}