swc_bundler/
hash.rs

1use std::io;
2
3use anyhow::{Context, Error};
4use crc::{Crc, Digest, CRC_64_ECMA_182};
5use swc_common::{sync::Lrc, BytePos, SourceMap, Span};
6use swc_ecma_ast::Module;
7use swc_ecma_codegen::{text_writer::WriteJs, Emitter};
8
9pub(crate) fn calc_hash(cm: Lrc<SourceMap>, m: &Module) -> Result<String, Error> {
10    let crc = Crc::<u64>::new(&CRC_64_ECMA_182);
11    let digest = crc.digest();
12    let mut buf = Hasher { digest };
13
14    {
15        let mut emitter = Emitter {
16            cfg: Default::default(),
17            cm,
18            comments: None,
19            wr: Box::new(&mut buf) as Box<dyn WriteJs>,
20        };
21
22        emitter
23            .emit_module(m)
24            .context("failed to emit module to calculate hash")?;
25    }
26    //
27
28    let result = buf.digest.finalize();
29    Ok(radix_fmt::radix(result, 36).to_string())
30}
31
32struct Hasher<'a> {
33    digest: Digest<'a, u64>,
34}
35
36impl Hasher<'_> {
37    fn w(&mut self, s: &str) {
38        self.digest.update(s.as_bytes());
39    }
40}
41
42impl WriteJs for &mut Hasher<'_> {
43    fn increase_indent(&mut self) -> io::Result<()> {
44        Ok(())
45    }
46
47    fn decrease_indent(&mut self) -> io::Result<()> {
48        Ok(())
49    }
50
51    fn write_semi(&mut self, _: Option<Span>) -> io::Result<()> {
52        self.w(";");
53        Ok(())
54    }
55
56    fn write_space(&mut self) -> io::Result<()> {
57        self.w(" ");
58        Ok(())
59    }
60
61    fn write_keyword(&mut self, _: Option<Span>, s: &'static str) -> io::Result<()> {
62        self.w(s);
63        Ok(())
64    }
65
66    fn write_operator(&mut self, _: Option<Span>, s: &str) -> io::Result<()> {
67        self.w(s);
68        Ok(())
69    }
70
71    fn write_param(&mut self, s: &str) -> io::Result<()> {
72        self.w(s);
73        Ok(())
74    }
75
76    fn write_property(&mut self, s: &str) -> io::Result<()> {
77        self.w(s);
78        Ok(())
79    }
80
81    fn write_line(&mut self) -> io::Result<()> {
82        self.w("\n");
83        Ok(())
84    }
85
86    fn write_lit(&mut self, _: Span, s: &str) -> io::Result<()> {
87        self.w(s);
88        Ok(())
89    }
90
91    fn write_comment(&mut self, s: &str) -> io::Result<()> {
92        self.w(s);
93        Ok(())
94    }
95
96    fn write_str_lit(&mut self, _: Span, s: &str) -> io::Result<()> {
97        self.w(s);
98        Ok(())
99    }
100
101    fn write_str(&mut self, s: &str) -> io::Result<()> {
102        self.w(s);
103        Ok(())
104    }
105
106    fn write_symbol(&mut self, _: Span, s: &str) -> io::Result<()> {
107        self.w(s);
108        Ok(())
109    }
110
111    fn write_punct(&mut self, _: Option<Span>, s: &'static str) -> io::Result<()> {
112        self.w(s);
113        Ok(())
114    }
115
116    #[inline]
117    fn care_about_srcmap(&self) -> bool {
118        false
119    }
120
121    #[inline]
122    fn add_srcmap(&mut self, _: BytePos) -> io::Result<()> {
123        Ok(())
124    }
125
126    fn commit_pending_semi(&mut self) -> io::Result<()> {
127        Ok(())
128    }
129
130    fn can_ignore_invalid_unicodes(&mut self) -> bool {
131        true
132    }
133}