feat(codegen): print comments in TSTypeLiteral (#8679)

fixes #8665
This commit is contained in:
Boshen 2025-01-23 14:31:55 +00:00
parent 23b49a665f
commit 99607d3f82
11 changed files with 168 additions and 122 deletions

View file

@ -59,6 +59,9 @@ impl Codegen<'_> {
} }
pub(crate) fn print_leading_comments(&mut self, start: u32) { pub(crate) fn print_leading_comments(&mut self, start: u32) {
if !self.print_comments {
return;
}
let Some(comments) = self.comments.remove(&start) else { let Some(comments) = self.comments.remove(&start) else {
return; return;
}; };

View file

@ -2350,9 +2350,7 @@ impl Gen for ClassBody<'_> {
p.print_curly_braces(self.span, self.body.is_empty(), |p| { p.print_curly_braces(self.span, self.body.is_empty(), |p| {
for item in &self.body { for item in &self.body {
p.print_semicolon_if_needed(); p.print_semicolon_if_needed();
if p.print_comments { p.print_leading_comments(item.span().start);
p.print_leading_comments(item.span().start);
}
p.print_indent(); p.print_indent();
item.print(p, ctx); item.print(p, ctx);
} }
@ -3296,21 +3294,15 @@ impl Gen for TSTemplateLiteralType<'_> {
impl Gen for TSTypeLiteral<'_> { impl Gen for TSTypeLiteral<'_> {
fn gen(&self, p: &mut Codegen, ctx: Context) { fn gen(&self, p: &mut Codegen, ctx: Context) {
let single_line = self.members.len() <= 1; p.print_curly_braces(self.span, self.members.is_empty(), |p| {
p.print_curly_braces(self.span, single_line, |p| {
for item in &self.members { for item in &self.members {
if single_line { p.print_leading_comments(item.span().start);
p.print_soft_space(); p.print_indent();
} else {
p.print_indent();
}
item.print(p, ctx); item.print(p, ctx);
if single_line { if p.options.minify {
p.print_soft_space();
} else {
p.print_semicolon(); p.print_semicolon();
p.print_soft_newline();
} }
p.print_soft_newline();
} }
}); });
} }
@ -3399,36 +3391,7 @@ impl Gen for TSSignature<'_> {
fn gen(&self, p: &mut Codegen, ctx: Context) { fn gen(&self, p: &mut Codegen, ctx: Context) {
match self { match self {
Self::TSIndexSignature(signature) => signature.print(p, ctx), Self::TSIndexSignature(signature) => signature.print(p, ctx),
Self::TSPropertySignature(signature) => { Self::TSPropertySignature(signature) => signature.r#gen(p, ctx),
if signature.readonly {
p.print_str("readonly ");
}
if signature.computed {
p.print_ascii_byte(b'[');
signature.key.print(p, ctx);
p.print_ascii_byte(b']');
} else {
match &signature.key {
PropertyKey::StaticIdentifier(key) => {
key.print(p, ctx);
}
PropertyKey::PrivateIdentifier(key) => {
p.print_str(key.name.as_str());
}
key => {
key.to_expression().print_expr(p, Precedence::Comma, ctx);
}
}
}
if signature.optional {
p.print_str("?");
}
if let Some(type_annotation) = &signature.type_annotation {
p.print_colon();
p.print_soft_space();
type_annotation.print(p, ctx);
}
}
Self::TSCallSignatureDeclaration(signature) => { Self::TSCallSignatureDeclaration(signature) => {
if let Some(type_parameters) = signature.type_parameters.as_ref() { if let Some(type_parameters) = signature.type_parameters.as_ref() {
type_parameters.print(p, ctx); type_parameters.print(p, ctx);
@ -3512,6 +3475,39 @@ impl Gen for TSSignature<'_> {
} }
} }
impl Gen for TSPropertySignature<'_> {
fn gen(&self, p: &mut Codegen, ctx: Context) {
if self.readonly {
p.print_str("readonly ");
}
if self.computed {
p.print_ascii_byte(b'[');
self.key.print(p, ctx);
p.print_ascii_byte(b']');
} else {
match &self.key {
PropertyKey::StaticIdentifier(key) => {
key.print(p, ctx);
}
PropertyKey::PrivateIdentifier(key) => {
p.print_str(key.name.as_str());
}
key => {
key.to_expression().print_expr(p, Precedence::Comma, ctx);
}
}
}
if self.optional {
p.print_str("?");
}
if let Some(type_annotation) = &self.type_annotation {
p.print_colon();
p.print_soft_space();
type_annotation.print(p, ctx);
}
}
}
impl Gen for TSTypeQuery<'_> { impl Gen for TSTypeQuery<'_> {
fn gen(&self, p: &mut Codegen, ctx: Context) { fn gen(&self, p: &mut Codegen, ctx: Context) {
p.print_str("typeof "); p.print_str("typeof ");
@ -3742,9 +3738,7 @@ impl Gen for TSInterfaceDeclaration<'_> {
p.print_soft_space(); p.print_soft_space();
p.print_curly_braces(self.body.span, self.body.body.is_empty(), |p| { p.print_curly_braces(self.body.span, self.body.body.is_empty(), |p| {
for item in &self.body.body { for item in &self.body.body {
if p.print_comments { p.print_leading_comments(item.span().start);
p.print_leading_comments(item.span().start);
}
p.print_indent(); p.print_indent();
item.print(p, ctx); item.print(p, ctx);
p.print_semicolon(); p.print_semicolon();
@ -3778,9 +3772,7 @@ impl Gen for TSEnumDeclaration<'_> {
p.print_space_before_identifier(); p.print_space_before_identifier();
p.print_curly_braces(self.span, self.members.is_empty(), |p| { p.print_curly_braces(self.span, self.members.is_empty(), |p| {
for member in &self.members { for member in &self.members {
if p.print_comments { p.print_leading_comments(member.span().start);
p.print_leading_comments(member.span().start);
}
p.print_indent(); p.print_indent();
member.print(p, ctx); member.print(p, ctx);
p.print_comma(); p.print_comma();

View file

@ -1,6 +1,5 @@
--- ---
source: crates/oxc_codegen/tests/integration/main.rs source: crates/oxc_codegen/tests/integration/main.rs
snapshot_kind: text
--- ---
########## 0 ########## 0
let x: string = `\x01`; let x: string = `\x01`;
@ -79,11 +78,11 @@ class A{readonly type="frame"}
########## 17 ########## 17
let foo: { <T>(t: T): void } let foo: { <T>(t: T): void }
---------- ----------
let foo:{<T>(t:T):void}; let foo:{<T>(t:T):void;};
########## 18 ########## 18
let foo: { new <T>(t: T): void } let foo: { new <T>(t: T): void }
---------- ----------
let foo:{new <T>(t:T):void}; let foo:{new <T>(t:T):void;};
########## 19 ########## 19
function <const T>(){} function <const T>(){}
---------- ----------

View file

@ -1,6 +1,5 @@
--- ---
source: crates/oxc_codegen/tests/integration/main.rs source: crates/oxc_codegen/tests/integration/main.rs
snapshot_kind: text
--- ---
########## 0 ########## 0
let x: string = `\x01`; let x: string = `\x01`;
@ -112,12 +111,16 @@ class A {
########## 17 ########## 17
let foo: { <T>(t: T): void } let foo: { <T>(t: T): void }
---------- ----------
let foo: { <T>(t: T): void }; let foo: {
<T>(t: T): void
};
########## 18 ########## 18
let foo: { new <T>(t: T): void } let foo: { new <T>(t: T): void }
---------- ----------
let foo: { new <T>(t: T): void }; let foo: {
new <T>(t: T): void
};
########## 19 ########## 19
function <const T>(){} function <const T>(){}

View file

@ -1,9 +1,18 @@
export interface X { export interface X {
/**
* Comment
*/
set value(_: string); set value(_: string);
} }
export type A = { export type A = {
/**
* Comment
*/
set value({ a, b, c }: { a: string; b: string; c: string }); set value({ a, b, c }: { a: string; b: string; c: string });
/**
* Comment
*/
get value(); get value();
}; };

View file

@ -1,24 +1,25 @@
--- ---
source: crates/oxc_isolated_declarations/tests/mod.rs source: crates/oxc_isolated_declarations/tests/mod.rs
input_file: crates/oxc_isolated_declarations/tests/fixtures/as-const.ts input_file: crates/oxc_isolated_declarations/tests/fixtures/as-const.ts
snapshot_kind: text
--- ---
``` ```
==================== .D.TS ==================== ==================== .D.TS ====================
declare const F: { declare const F: {
readonly string: "string"; readonly string: "string"
readonly templateLiteral: "templateLiteral"; readonly templateLiteral: "templateLiteral"
readonly number: 1.23; readonly number: 1.23
readonly bigint: -123n; readonly bigint: -123n
readonly boolean: true; readonly boolean: true
readonly null: null; readonly null: null
readonly undefined: undefined; readonly undefined: undefined
readonly function: (a: string) => void; readonly function: (a: string) => void
readonly arrow: (a: string) => void; readonly arrow: (a: string) => void
readonly object: { readonly object: {
readonly a: "a"; readonly a: "a"
readonly b: "b"; readonly b: "b"
}; }
readonly array: readonly ["a", undefined, { readonly b: "\n" }]; readonly array: readonly ["a", undefined, {
readonly b: "\n"
}]
}; };

View file

@ -8,5 +8,7 @@ input_file: crates/oxc_isolated_declarations/tests/fixtures/empty-export.ts
type A = string; type A = string;
export declare function a(): A; export declare function a(): A;
export declare const ShallowReactiveMarker: unique symbol; export declare const ShallowReactiveMarker: unique symbol;
export type ShallowReactive<T> = T & { [ShallowReactiveMarker]?: true }; export type ShallowReactive<T> = T & {
[ShallowReactiveMarker]?: true
};
export {}; export {};

View file

@ -8,8 +8,8 @@ input_file: crates/oxc_isolated_declarations/tests/fixtures/infer-template-liter
export declare const CSS_VARS_HELPER = "useCssVars"; export declare const CSS_VARS_HELPER = "useCssVars";
export declare function g(func?: string): void; export declare function g(func?: string): void;
export declare const F: { export declare const F: {
readonly a: "a"; readonly a: "a"
readonly b: readonly ["b"]; readonly b: readonly ["b"]
}; };
export declare let GOOD: string; export declare let GOOD: string;
export declare const BAD: unknown; export declare const BAD: unknown;

View file

@ -5,5 +5,7 @@ input_file: crates/oxc_isolated_declarations/tests/fixtures/readonly.ts
``` ```
==================== .D.TS ==================== ==================== .D.TS ====================
export declare const EMPTY_OBJ: { readonly [key: string]: any }; export declare const EMPTY_OBJ: {
readonly [key: string]: any
};
export declare const EMPTY_ARR: readonly never[]; export declare const EMPTY_ARR: readonly never[];

View file

@ -6,19 +6,28 @@ input_file: crates/oxc_isolated_declarations/tests/fixtures/signatures.ts
==================== .D.TS ==================== ==================== .D.TS ====================
export interface X { export interface X {
/**
* Comment
*/
set value(_: string); set value(_: string);
} }
export type A = { export type A = {
/**
* Comment
*/
set value({ a, b, c }: { set value({ a, b, c }: {
a: string; a: string
b: string; b: string
c: string; c: string
}); })
/**
* Comment
*/
get value(): { get value(): {
a: string; a: string
b: string; b: string
c: string; c: string
}; }
}; };
export interface I { export interface I {
set value(_: string); set value(_: string);

View file

@ -12,17 +12,17 @@ export namespace presentNs {
} }
const aliasing = Symbol; const aliasing = Symbol;
export type A = { export type A = {
[missing]: number; [missing]: number
[ns.missing]: number; [ns.missing]: number
[presentNs.a]: number; [presentNs.a]: number
[Symbol.iterator]: number; [Symbol.iterator]: number
[globalThis.Symbol.toStringTag]: number; [globalThis.Symbol.toStringTag]: number
[globalThis.Symbol.unscopables]: number; [globalThis.Symbol.unscopables]: number
[aliasing.isConcatSpreadable]: number; [aliasing.isConcatSpreadable]: number
[1]: number; [1]: number
["2"]: number; ["2"]: number
[missing2]: number; [missing2]: number
[Math.random() > .5 ? "f1" : "f2"]: number; [Math.random() > .5 ? "f1" : "f2"]: number
}; };
export interface B { export interface B {
[missing]: number; [missing]: number;
@ -70,17 +70,17 @@ export declare namespace presentNs {
} }
declare const aliasing: unknown; declare const aliasing: unknown;
export type A = { export type A = {
[missing]: number; [missing]: number
[ns.missing]: number; [ns.missing]: number
[presentNs.a]: number; [presentNs.a]: number
[Symbol.iterator]: number; [Symbol.iterator]: number
[globalThis.Symbol.toStringTag]: number; [globalThis.Symbol.toStringTag]: number
[globalThis.Symbol.unscopables]: number; [globalThis.Symbol.unscopables]: number
[aliasing.isConcatSpreadable]: number; [aliasing.isConcatSpreadable]: number
[1]: number; [1]: number
["2"]: number; ["2"]: number
[missing2]: number; [missing2]: number
[Math.random() > .5 ? "f1" : "f2"]: number; [Math.random() > .5 ? "f1" : "f2"]: number
}; };
export interface B { export interface B {
[missing]: number; [missing]: number;
@ -102,10 +102,10 @@ export declare class C {
["2"]: number; ["2"]: number;
} }
export declare const D: { export declare const D: {
Symbol.iterator: number; Symbol.iterator: number
globalThis.Symbol.toStringTag: number; globalThis.Symbol.toStringTag: number
1: number; 1: number
"2": number; "2": number
}; };
export {}; export {};
@ -318,11 +318,15 @@ export function fnDeclBasic3(p: new () => any = class {}, rParam: string): void
; ;
export function fnDeclBasic4(p: [T] = [[]], rParam: string): void {} export function fnDeclBasic4(p: [T] = [[]], rParam: string): void {}
; ;
export function fnDeclBasic5(p: { a: T } = { a: [] }, rParam: string): void {} export function fnDeclBasic5(p: {
a: T
} = { a: [] }, rParam: string): void {}
; ;
export function fnDeclBasic6(p: `_${string}` = "_", rParam: string): void {} export function fnDeclBasic6(p: `_${string}` = "_", rParam: string): void {}
; ;
export function fnDeclBasic7(p: { a?: string } & number[] = [], rParam: string): void {} export function fnDeclBasic7(p: {
a?: string
} & number[] = [], rParam: string): void {}
; ;
export function fnDeclBasic8(p: (number[] | string[]) | number = [], rParam: string): void {} export function fnDeclBasic8(p: (number[] | string[]) | number = [], rParam: string): void {}
; ;
@ -388,9 +392,13 @@ export declare function fnDeclBasic1(p: number[] | string[] | [T] | undefined, r
export declare function fnDeclBasic2(p: (n: T) => T | undefined, rParam: string): void; export declare function fnDeclBasic2(p: (n: T) => T | undefined, rParam: string): void;
export declare function fnDeclBasic3(p: new () => any | undefined, rParam: string): void; export declare function fnDeclBasic3(p: new () => any | undefined, rParam: string): void;
export declare function fnDeclBasic4(p: [T] | undefined, rParam: string): void; export declare function fnDeclBasic4(p: [T] | undefined, rParam: string): void;
export declare function fnDeclBasic5(p: { a: T } | undefined, rParam: string): void; export declare function fnDeclBasic5(p: {
a: T
} | undefined, rParam: string): void;
export declare function fnDeclBasic6(p: `_${string}` | undefined, rParam: string): void; export declare function fnDeclBasic6(p: `_${string}` | undefined, rParam: string): void;
export declare function fnDeclBasic7(p: { a?: string } & number[] | undefined, rParam: string): void; export declare function fnDeclBasic7(p: {
a?: string
} & number[] | undefined, rParam: string): void;
export declare function fnDeclBasic8(p: (number[] | string[]) | number | undefined, rParam: string): void; export declare function fnDeclBasic8(p: (number[] | string[]) | number | undefined, rParam: string): void;
export declare function fnDeclHasUndefined(p: T | undefined, rParam: string): void; export declare function fnDeclHasUndefined(p: T | undefined, rParam: string): void;
export declare function fnDeclBad(p: T, rParam: string): void; export declare function fnDeclBad(p: T, rParam: string): void;
@ -400,15 +408,33 @@ export declare const fnExprBad: (array: T, rParam: string) => void;
export declare const arrowOk1: (array: number[] | undefined, rParam: string) => void; export declare const arrowOk1: (array: number[] | undefined, rParam: string) => void;
export declare const arrowOk2: (array: T | undefined, rParam: string) => void; export declare const arrowOk2: (array: T | undefined, rParam: string) => void;
export declare const arrowBad: (array: T, rParam: string) => void; export declare const arrowBad: (array: T, rParam: string) => void;
export declare const inObjectLiteralFnExprOk1: { o: (array: number[] | undefined, rParam: string) => void }; export declare const inObjectLiteralFnExprOk1: {
export declare const inObjectLiteralFnExprOk2: { o: (array: T | undefined, rParam: string) => void }; o: (array: number[] | undefined, rParam: string) => void
export declare const inObjectLiteralFnExprBad: { o: (array: T, rParam: string) => void }; };
export declare const inObjectLiteralArrowOk1: { o: (array: number[] | undefined, rParam: string) => void }; export declare const inObjectLiteralFnExprOk2: {
export declare const inObjectLiteralArrowOk2: { o: (array: T | undefined, rParam: string) => void }; o: (array: T | undefined, rParam: string) => void
export declare const inObjectLiteralArrowBad: { o: (array: T, rParam: string) => void }; };
export declare const inObjectLiteralMethodOk1: { o(array: number[] | undefined, rParam: string): void }; export declare const inObjectLiteralFnExprBad: {
export declare const inObjectLiteralMethodOk2: { o(array: T | undefined, rParam: string): void }; o: (array: T, rParam: string) => void
export declare const inObjectLiteralMethodBad: { o(array: T, rParam: string): void }; };
export declare const inObjectLiteralArrowOk1: {
o: (array: number[] | undefined, rParam: string) => void
};
export declare const inObjectLiteralArrowOk2: {
o: (array: T | undefined, rParam: string) => void
};
export declare const inObjectLiteralArrowBad: {
o: (array: T, rParam: string) => void
};
export declare const inObjectLiteralMethodOk1: {
o(array: number[] | undefined, rParam: string): void
};
export declare const inObjectLiteralMethodOk2: {
o(array: T | undefined, rParam: string): void
};
export declare const inObjectLiteralMethodBad: {
o(array: T, rParam: string): void
};
export declare class InClassFnExprOk1 { export declare class InClassFnExprOk1 {
o: (array: number[] | undefined, rParam: string) => void; o: (array: number[] | undefined, rParam: string) => void;
} }