Skip to content

Commit 6080749

Browse files
authored
Merge pull request #1084 from constructive-io/fix/jsdoc-comment-sanitization
fix(codegen): sanitize */ in JSDoc comments to prevent syntax errors
2 parents c6e143b + c25a5e1 commit 6080749

3 files changed

Lines changed: 96 additions & 6 deletions

File tree

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* Tests for JSDoc comment sanitization in babel-ast and hooks-ast
3+
*/
4+
import * as t from '@babel/types';
5+
6+
import {
7+
addJSDocComment,
8+
generateCode,
9+
} from '../../core/codegen/babel-ast';
10+
import { addJSDocComment as addJSDocCommentHooks } from '../../core/codegen/hooks-ast';
11+
12+
describe('addJSDocComment', () => {
13+
describe('babel-ast', () => {
14+
it('produces valid JSDoc for simple descriptions', () => {
15+
const node = t.identifier('x');
16+
addJSDocComment(node, ['A simple description']);
17+
const code = generateCode([
18+
t.variableDeclaration('const', [
19+
t.variableDeclarator(node, t.numericLiteral(1)),
20+
]),
21+
]);
22+
expect(code).toContain('/** A simple description */');
23+
expect(code).not.toContain('*/\n');
24+
});
25+
26+
it('sanitizes */ in single-line descriptions', () => {
27+
const node = t.identifier('x');
28+
addJSDocComment(node, [
29+
'Reads and enables pagination through a set of */ values.',
30+
]);
31+
const code = generateCode([
32+
t.variableDeclaration('const', [
33+
t.variableDeclarator(node, t.numericLiteral(1)),
34+
]),
35+
]);
36+
expect(code).toContain('*\\/');
37+
expect(code).not.toMatch(/\/\*.*\*\/.*\*\//);
38+
});
39+
40+
it('sanitizes */ in multi-line descriptions', () => {
41+
const node = t.identifier('x');
42+
addJSDocComment(node, [
43+
'First line with */ embedded',
44+
'Second line is fine',
45+
'Third line also has */ inside',
46+
]);
47+
const code = generateCode([
48+
t.variableDeclaration('const', [
49+
t.variableDeclarator(node, t.numericLiteral(1)),
50+
]),
51+
]);
52+
const commentMatch = code.match(/\/\*[\s\S]*?\*\//);
53+
expect(commentMatch).not.toBeNull();
54+
const comment = commentMatch![0];
55+
const innerSlashes = comment.slice(2, -2);
56+
expect(innerSlashes).not.toContain('*/');
57+
});
58+
});
59+
60+
describe('hooks-ast', () => {
61+
it('produces valid JSDoc for simple descriptions', () => {
62+
const node = t.identifier('y');
63+
addJSDocCommentHooks(node, ['A simple description']);
64+
expect(node.leadingComments).toHaveLength(1);
65+
expect(node.leadingComments![0].value).toBe('* A simple description ');
66+
});
67+
68+
it('sanitizes */ in single-line descriptions', () => {
69+
const node = t.identifier('y');
70+
addJSDocCommentHooks(node, [
71+
'Reads and enables pagination through a set of */ values.',
72+
]);
73+
expect(node.leadingComments![0].value).not.toContain('*/');
74+
expect(node.leadingComments![0].value).toContain('*\\/');
75+
});
76+
77+
it('sanitizes */ in multi-line descriptions', () => {
78+
const node = t.identifier('y');
79+
addJSDocCommentHooks(node, [
80+
'Line with */ problem',
81+
'Normal line',
82+
]);
83+
const commentValue = node.leadingComments![0].value;
84+
expect(commentValue).not.toContain('*/');
85+
expect(commentValue).toContain('*\\/');
86+
});
87+
});
88+
});

graphql/codegen/src/core/codegen/babel-ast.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,11 @@ export const commentLine = (value: string): t.CommentLine => {
5050
* Add a leading JSDoc comment to a node
5151
*/
5252
export function addJSDocComment<T extends t.Node>(node: T, lines: string[]): T {
53+
const sanitized = lines.map((line) => line.replace(/\*\//g, '*\\/'));
5354
const commentText =
54-
lines.length === 1
55-
? `* ${lines[0]} `
56-
: `*\n${lines.map((line) => ` * ${line}`).join('\n')}\n `;
55+
sanitized.length === 1
56+
? `* ${sanitized[0]} `
57+
: `*\n${sanitized.map((line) => ` * ${line}`).join('\n')}\n `;
5758

5859
if (!node.leadingComments) {
5960
node.leadingComments = [];

graphql/codegen/src/core/codegen/hooks-ast.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -570,10 +570,11 @@ export function destructureParamsWithSelectionAndScope(
570570
// ============================================================================
571571

572572
export function addJSDocComment<T extends t.Node>(node: T, lines: string[]): T {
573+
const sanitized = lines.map((line) => line.replace(/\*\//g, '*\\/'));
573574
const text =
574-
lines.length === 1
575-
? `* ${lines[0]} `
576-
: `*\n${lines.map((line) => ` * ${line}`).join('\n')}\n `;
575+
sanitized.length === 1
576+
? `* ${sanitized[0]} `
577+
: `*\n${sanitized.map((line) => ` * ${line}`).join('\n')}\n `;
577578
if (!node.leadingComments) {
578579
node.leadingComments = [];
579580
}

0 commit comments

Comments
 (0)