next_custom_transforms/transforms/
lint_codemod_comments.rs1use 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
23const 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 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}