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
88 changes: 88 additions & 0 deletions graphql/codegen/src/__tests__/codegen/jsdoc-comment.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* Tests for JSDoc comment sanitization in babel-ast and hooks-ast
*/
import * as t from '@babel/types';

import {
addJSDocComment,
generateCode,
} from '../../core/codegen/babel-ast';
import { addJSDocComment as addJSDocCommentHooks } from '../../core/codegen/hooks-ast';

describe('addJSDocComment', () => {
describe('babel-ast', () => {
it('produces valid JSDoc for simple descriptions', () => {
const node = t.identifier('x');
addJSDocComment(node, ['A simple description']);
const code = generateCode([
t.variableDeclaration('const', [
t.variableDeclarator(node, t.numericLiteral(1)),
]),
]);
expect(code).toContain('/** A simple description */');
expect(code).not.toContain('*/\n');
});

it('sanitizes */ in single-line descriptions', () => {
const node = t.identifier('x');
addJSDocComment(node, [
'Reads and enables pagination through a set of */ values.',
]);
const code = generateCode([
t.variableDeclaration('const', [
t.variableDeclarator(node, t.numericLiteral(1)),
]),
]);
expect(code).toContain('*\\/');
expect(code).not.toMatch(/\/\*.*\*\/.*\*\//);
});

it('sanitizes */ in multi-line descriptions', () => {
const node = t.identifier('x');
addJSDocComment(node, [
'First line with */ embedded',
'Second line is fine',
'Third line also has */ inside',
]);
const code = generateCode([
t.variableDeclaration('const', [
t.variableDeclarator(node, t.numericLiteral(1)),
]),
]);
const commentMatch = code.match(/\/\*[\s\S]*?\*\//);
expect(commentMatch).not.toBeNull();
const comment = commentMatch![0];
const innerSlashes = comment.slice(2, -2);
expect(innerSlashes).not.toContain('*/');
});
});

describe('hooks-ast', () => {
it('produces valid JSDoc for simple descriptions', () => {
const node = t.identifier('y');
addJSDocCommentHooks(node, ['A simple description']);
expect(node.leadingComments).toHaveLength(1);
expect(node.leadingComments![0].value).toBe('* A simple description ');
});

it('sanitizes */ in single-line descriptions', () => {
const node = t.identifier('y');
addJSDocCommentHooks(node, [
'Reads and enables pagination through a set of */ values.',
]);
expect(node.leadingComments![0].value).not.toContain('*/');
expect(node.leadingComments![0].value).toContain('*\\/');
});

it('sanitizes */ in multi-line descriptions', () => {
const node = t.identifier('y');
addJSDocCommentHooks(node, [
'Line with */ problem',
'Normal line',
]);
const commentValue = node.leadingComments![0].value;
expect(commentValue).not.toContain('*/');
expect(commentValue).toContain('*\\/');
});
});
});
7 changes: 4 additions & 3 deletions graphql/codegen/src/core/codegen/babel-ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,11 @@ export const commentLine = (value: string): t.CommentLine => {
* Add a leading JSDoc comment to a node
*/
export function addJSDocComment<T extends t.Node>(node: T, lines: string[]): T {
const sanitized = lines.map((line) => line.replace(/\*\//g, '*\\/'));
const commentText =
lines.length === 1
? `* ${lines[0]} `
: `*\n${lines.map((line) => ` * ${line}`).join('\n')}\n `;
sanitized.length === 1
? `* ${sanitized[0]} `
: `*\n${sanitized.map((line) => ` * ${line}`).join('\n')}\n `;

if (!node.leadingComments) {
node.leadingComments = [];
Expand Down
7 changes: 4 additions & 3 deletions graphql/codegen/src/core/codegen/hooks-ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -570,10 +570,11 @@ export function destructureParamsWithSelectionAndScope(
// ============================================================================

export function addJSDocComment<T extends t.Node>(node: T, lines: string[]): T {
const sanitized = lines.map((line) => line.replace(/\*\//g, '*\\/'));
const text =
lines.length === 1
? `* ${lines[0]} `
: `*\n${lines.map((line) => ` * ${line}`).join('\n')}\n `;
sanitized.length === 1
? `* ${sanitized[0]} `
: `*\n${sanitized.map((line) => ` * ${line}`).join('\n')}\n `;
if (!node.leadingComments) {
node.leadingComments = [];
}
Expand Down
Loading