next_custom_transforms/transforms/
lint_codemod_comments.rs

1use swc_core::{
2    common::{
3        comments::{Comment, Comments},
4        errors::HANDLER,
5    },
6    ecma::{utils::swc_common::Span, visit::Visit},
7};
8
9struct LintErrorComment<C>
10where
11    C: Comments,
12{
13    comments: C,
14}
15
16pub fn lint_codemod_comments<C>(comments: C) -> impl Visit
17where
18    C: Comments,
19{
20    LintErrorComment { comments }
21}
22
23// declare a const of comment prefix
24const COMMENT_ERROR_PREFIX: &str = "@next-codemod-error";
25const COMMENT_BYPASS_PREFIX: &str = "@next-codemod-ignore";
26
27impl<C> LintErrorComment<C>
28where
29    C: Comments,
30{
31    fn lint(&self, comment: &Comment, is_leading: bool) {
32        let trimmed_text = comment.text.trim();
33        // if comment contains @next/codemod comment "@next-codemod-error",
34        // report an error from the linter to fail the build
35        if trimmed_text.contains(COMMENT_ERROR_PREFIX) {
36            let span = if is_leading {
37                comment
38                    .span
39                    .with_lo(comment.span.lo() - swc_core::common::BytePos(1))
40            } else {
41                comment
42                    .span
43                    .with_hi(comment.span.hi() + swc_core::common::BytePos(1))
44            };
45            let action = trimmed_text.replace(COMMENT_ERROR_PREFIX, "");
46            let err_message = format!(
47                "You have an unresolved @next/codemod comment \"{}\" that needs review.\nAfter \
48                 review, either remove the comment if you made the necessary changes or replace \
49                 \"{}\" with \"{}\" to bypass the build error if no action at this line can be \
50                 taken.\n",
51                action.trim(),
52                COMMENT_ERROR_PREFIX,
53                COMMENT_BYPASS_PREFIX
54            );
55            report(span, &err_message);
56        }
57    }
58}
59
60fn report(span: Span, msg: &str) {
61    HANDLER.with(|handler| {
62        handler.struct_span_err(span, msg).emit();
63    })
64}
65
66impl<C> Visit for LintErrorComment<C>
67where
68    C: Comments,
69{
70    fn visit_span(&mut self, s: &Span) {
71        self.comments.with_leading(s.lo, |comments| {
72            for c in comments {
73                self.lint(c, true);
74            }
75        });
76
77        self.comments.with_trailing(s.hi, |comments| {
78            for c in comments {
79                self.lint(c, false);
80            }
81        });
82    }
83}