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 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}