-
-
Notifications
You must be signed in to change notification settings - Fork 482
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(codegen): print jsdoc comments that are attached to statements a…
…nd class elements (#5845) I am unable to print all comments correctly. Comments have way too much semantic meaning in JavaScript. This PR reduces the scope to only print jsdoc comments that are attached to statements and class elements, in order to get isolated declarations shipped.
- Loading branch information
Showing
8 changed files
with
363 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
use oxc_syntax::identifier::is_line_terminator; | ||
use rustc_hash::FxHashMap; | ||
|
||
use oxc_ast::{Comment, CommentKind, Trivias}; | ||
|
||
use crate::Codegen; | ||
|
||
pub type CommentsMap = FxHashMap</* attached_to */ u32, Vec<Comment>>; | ||
|
||
impl<'a> Codegen<'a> { | ||
pub(crate) fn build_leading_comments(&mut self, source_text: &str, trivias: &Trivias) { | ||
let mut leading_comments: CommentsMap = FxHashMap::default(); | ||
for comment in trivias | ||
.comments() | ||
.copied() | ||
.filter(|comment| Self::should_keep_comment(comment, source_text)) | ||
{ | ||
leading_comments.entry(comment.attached_to).or_default().push(comment); | ||
} | ||
self.leading_comments = leading_comments; | ||
} | ||
|
||
fn should_keep_comment(comment: &Comment, source_text: &str) -> bool { | ||
comment.is_jsdoc(source_text) | ||
&& comment.preceded_by_newline | ||
// webpack comment `/*****/` | ||
&& !comment.span.source_text(source_text).chars().all(|c| c == '*') | ||
} | ||
|
||
pub(crate) fn print_leading_comments(&mut self, start: u32) { | ||
if self.options.minify { | ||
return; | ||
} | ||
let Some(source_text) = self.source_text else { return }; | ||
let Some(comments) = self.leading_comments.remove(&start) else { return }; | ||
|
||
let first = comments.first().unwrap(); | ||
if first.preceded_by_newline { | ||
// Skip printing newline if this comment is already on a newline. | ||
if self.peek_nth(0).is_some_and(|c| c != '\n' && c != '\t') { | ||
self.print_char(b'\n'); | ||
self.print_indent(); | ||
} | ||
} | ||
|
||
for comment in &comments { | ||
let s = comment.real_span().source_text(source_text); | ||
match comment.kind { | ||
CommentKind::Line => { | ||
self.print_str(s); | ||
} | ||
CommentKind::Block => { | ||
// Print block comments with our own indentation. | ||
let lines = s.split(is_line_terminator); | ||
for line in lines { | ||
if !line.starts_with("/*") { | ||
self.print_indent(); | ||
} | ||
self.print_str(line.trim_start()); | ||
if !line.ends_with("*/") { | ||
self.print_hard_newline(); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
let last = comments.last().unwrap(); | ||
if last.is_line() || last.followed_by_newline { | ||
self.print_hard_newline(); | ||
self.print_indent(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
use crate::snapshot; | ||
|
||
#[test] | ||
fn comment() { | ||
let cases = vec![ | ||
r" | ||
/** This is a description of the foo function. */ | ||
function foo() { | ||
} | ||
/** | ||
* Represents a book. | ||
* @constructor | ||
* @param {string} title - The title of the book. | ||
* @param {string} author - The author of the book. | ||
*/ | ||
function Book(title, author) { | ||
} | ||
/** Class representing a point. */ | ||
class Point { | ||
/** | ||
* Create a point. | ||
* @param {number} x - The x value. | ||
* @param {number} y - The y value. | ||
*/ | ||
constructor(x, y) { | ||
} | ||
/** | ||
* Get the x value. | ||
* @return {number} The x value. | ||
*/ | ||
getX() { | ||
} | ||
/** | ||
* Get the y value. | ||
* @return {number} The y value. | ||
*/ | ||
getY() { | ||
} | ||
/** | ||
* Convert a string containing two comma-separated numbers into a point. | ||
* @param {string} str - The string containing two comma-separated numbers. | ||
* @return {Point} A Point object. | ||
*/ | ||
static fromString(str) { | ||
} | ||
} | ||
/** Class representing a point. */ | ||
const Point = class { | ||
} | ||
/** | ||
* Shirt module. | ||
* @module my/shirt | ||
*/ | ||
/** Button the shirt. */ | ||
exports.button = function() { | ||
}; | ||
/** Unbutton the shirt. */ | ||
exports.unbutton = function() { | ||
}; | ||
this.Book = function(title) { | ||
/** The title of the book. */ | ||
this.title = title; | ||
} | ||
", | ||
]; | ||
|
||
snapshot("jsodc", &cases); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
121 changes: 121 additions & 0 deletions
121
crates/oxc_codegen/tests/integration/snapshots/jsodc.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
--- | ||
source: crates/oxc_codegen/tests/integration/main.rs | ||
--- | ||
########## 0 | ||
|
||
/** This is a description of the foo function. */ | ||
function foo() { | ||
} | ||
|
||
/** | ||
* Represents a book. | ||
* @constructor | ||
* @param {string} title - The title of the book. | ||
* @param {string} author - The author of the book. | ||
*/ | ||
function Book(title, author) { | ||
} | ||
|
||
/** Class representing a point. */ | ||
class Point { | ||
/** | ||
* Create a point. | ||
* @param {number} x - The x value. | ||
* @param {number} y - The y value. | ||
*/ | ||
constructor(x, y) { | ||
} | ||
|
||
/** | ||
* Get the x value. | ||
* @return {number} The x value. | ||
*/ | ||
getX() { | ||
} | ||
|
||
/** | ||
* Get the y value. | ||
* @return {number} The y value. | ||
*/ | ||
getY() { | ||
} | ||
|
||
/** | ||
* Convert a string containing two comma-separated numbers into a point. | ||
* @param {string} str - The string containing two comma-separated numbers. | ||
* @return {Point} A Point object. | ||
*/ | ||
static fromString(str) { | ||
} | ||
} | ||
|
||
/** Class representing a point. */ | ||
const Point = class { | ||
} | ||
|
||
/** | ||
* Shirt module. | ||
* @module my/shirt | ||
*/ | ||
|
||
/** Button the shirt. */ | ||
exports.button = function() { | ||
}; | ||
|
||
/** Unbutton the shirt. */ | ||
exports.unbutton = function() { | ||
}; | ||
|
||
this.Book = function(title) { | ||
/** The title of the book. */ | ||
this.title = title; | ||
} | ||
|
||
---------- | ||
/** This is a description of the foo function. */ | ||
function foo() {} | ||
/** | ||
* Represents a book. | ||
* @constructor | ||
* @param {string} title - The title of the book. | ||
* @param {string} author - The author of the book. | ||
*/ | ||
function Book(title, author) {} | ||
/** Class representing a point. */ | ||
class Point { | ||
/** | ||
* Create a point. | ||
* @param {number} x - The x value. | ||
* @param {number} y - The y value. | ||
*/ | ||
constructor(x, y) {} | ||
/** | ||
* Get the x value. | ||
* @return {number} The x value. | ||
*/ | ||
getX() {} | ||
/** | ||
* Get the y value. | ||
* @return {number} The y value. | ||
*/ | ||
getY() {} | ||
/** | ||
* Convert a string containing two comma-separated numbers into a point. | ||
* @param {string} str - The string containing two comma-separated numbers. | ||
* @return {Point} A Point object. | ||
*/ | ||
static fromString(str) {} | ||
} | ||
/** Class representing a point. */ | ||
const Point = class {}; | ||
/** | ||
* Shirt module. | ||
* @module my/shirt | ||
*//** Button the shirt. */ | ||
exports.button = function() {}; | ||
/** Unbutton the shirt. */ | ||
exports.unbutton = function() {}; | ||
this.Book = function(title) { | ||
/** The title of the book. */ | ||
this.title = title; | ||
}; |
Oops, something went wrong.