Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion src/print.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ export function print(node) {
case "ChainExpression":
return print(node.expression);

case "V8IntrinsicExpression": {
const name = typeof node.name === "string" ? node.name : print(node.name);
const args = (node.arguments ?? []).map(print).join(", ");
return `%${name}(${args})`;
}

case "ParenthesizedExpression":
return `(${print(node.expression)})`;

Expand Down Expand Up @@ -544,6 +550,16 @@ export function print(node) {
case "TSParenthesizedType":
return `(${print(node.typeAnnotation)})`;

// JSDoc type syntax (`?Foo`, `!Foo`, `?`) — `postfix` flips prefix/suffix.
case "TSJSDocNullableType":
return node.postfix ? `${print(node.typeAnnotation)}?` : `?${print(node.typeAnnotation)}`;

case "TSJSDocNonNullableType":
return node.postfix ? `${print(node.typeAnnotation)}!` : `!${print(node.typeAnnotation)}`;

case "TSJSDocUnknownType":
return "?";

case "TSTupleType": {
const elems = (node.elementTypes ?? []).map(print).join(", ");
return `[${elems}]`;
Expand Down Expand Up @@ -683,10 +699,17 @@ export function print(node) {
const declare = node.declare ? "declare " : "";
const constKw = node.const ? "const " : "";
const id = print(node.id);
const members = (node.members ?? []).map(print).join(",\n");
// Newer oxc nests members in a TSEnumBody child; older versions put
// `members` directly on the declaration.
const members = (node.body?.members ?? node.members ?? []).map(print).join(",\n");
return `${declare}${constKw}enum ${id} {\n${members}\n}`;
}

case "TSEnumBody": {
const members = (node.members ?? []).map(print).join(",\n");
return `{\n${members}\n}`;
}

case "TSEnumMember": {
const id = print(node.id);
return node.initializer ? `${id} = ${print(node.initializer)}` : id;
Expand Down
22 changes: 19 additions & 3 deletions tests/parse-print-gts.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,25 @@ const Badge = <template><span>hi</span></template>;
],
};
const printed = print(enumNode);
expect(printed).toContain("enum Color");
expect(printed).toContain("Red");
expect(printed).toContain("Blue = 1");
expect(printed).toMatchInlineSnapshot(`
"enum Color {
Red,
Blue = 1
}"
`);
});

it("preserves enum members through parse + print", () => {
// Newer oxc nests members under a TSEnumBody; the printed enum must
// still contain them rather than collapsing to an empty body.
const printed = print(parse(`enum Color { Red, Green, Blue }`, { filePath: "x.gts" }).program);
expect(printed).toMatchInlineSnapshot(`
"enum Color {
Red,
Green,
Blue
}"
`);
});

it("handles filePath with gts extension", () => {
Expand Down
45 changes: 45 additions & 0 deletions tests/print.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,51 @@ describe("print", () => {
expect(print(node)).toBe("(string | number)");
});

it("prints JSDoc type nodes", () => {
const str = { type: "TSStringKeyword" };
expect(print({ type: "TSJSDocNullableType", typeAnnotation: str })).toBe("?string");
expect(print({ type: "TSJSDocNullableType", typeAnnotation: str, postfix: true })).toBe(
"string?",
);
expect(print({ type: "TSJSDocNonNullableType", typeAnnotation: str })).toBe("!string");
expect(print({ type: "TSJSDocUnknownType" })).toBe("?");
});

it("prints V8IntrinsicExpression", () => {
const node = {
type: "V8IntrinsicExpression",
name: "DebugPrint",
arguments: [{ type: "Identifier", name: "x" }],
};
expect(print(node)).toBe("%DebugPrint(x)");
});

it("prints TSEnumBody", () => {
const node = {
type: "TSEnumBody",
members: [
{ type: "TSEnumMember", id: { type: "Identifier", name: "A" } },
{ type: "TSEnumMember", id: { type: "Identifier", name: "B" } },
],
};
expect(print(node)).toBe("{\nA,\nB\n}");
});

it("prints TSEnumDeclaration with a TSEnumBody (newer oxc shape)", () => {
const node = {
type: "TSEnumDeclaration",
id: { type: "Identifier", name: "Color" },
body: {
type: "TSEnumBody",
members: [
{ type: "TSEnumMember", id: { type: "Identifier", name: "Red" } },
{ type: "TSEnumMember", id: { type: "Identifier", name: "Green" } },
],
},
};
expect(print(node)).toBe("enum Color {\nRed,\nGreen\n}");
});

it("prints TSTupleType", () => {
const node = {
type: "TSTupleType",
Expand Down
Loading