Skip to content

Commit 5a5825c

Browse files
committed
Added support to maintain comments when parsing
Signed-off-by: Naveen Jain <[email protected]>
1 parent 3f859d4 commit 5a5825c

File tree

7 files changed

+115
-2
lines changed

7 files changed

+115
-2
lines changed

src/language/__tests__/parser-test.js

+35
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,39 @@ describe('Parser', () => {
147147
);
148148
});
149149

150+
it('Add comments from type in AST', () => {
151+
const ast = parse(`
152+
#This comment has a \u0A0A multi-byte character.
153+
type alpha{ field(arg: string):string }
154+
`);
155+
156+
expect(ast).to.have.nested.property(
157+
'comments[0].value',
158+
'This comment has a \u0A0A multi-byte character.',
159+
);
160+
expect(ast.comments).to.have.length(1);
161+
});
162+
163+
it('Add multiple comments in AST', () => {
164+
const ast = parse(`
165+
type alpha{
166+
#This comment is demo comment.
167+
field(arg: string):string
168+
#This is another demo comment having # inside
169+
}
170+
`);
171+
172+
expect(ast).to.have.nested.property(
173+
'comments[0].value',
174+
'This comment is demo comment.',
175+
);
176+
expect(ast).to.have.nested.property(
177+
'comments[1].value',
178+
'This is another demo comment having # inside',
179+
);
180+
expect(ast.comments).to.have.length(2);
181+
});
182+
150183
it('parses kitchen sink', () => {
151184
expect(() => parse(kitchenSinkQuery)).to.not.throw();
152185
});
@@ -231,6 +264,7 @@ describe('Parser', () => {
231264

232265
expect(toJSONDeep(result)).to.deep.equal({
233266
kind: Kind.DOCUMENT,
267+
comments: [],
234268
loc: { start: 0, end: 41 },
235269
definitions: [
236270
{
@@ -321,6 +355,7 @@ describe('Parser', () => {
321355

322356
expect(toJSONDeep(result)).to.deep.equal({
323357
kind: Kind.DOCUMENT,
358+
comments: [],
324359
loc: { start: 0, end: 30 },
325360
definitions: [
326361
{

src/language/__tests__/schema-parser-test.js

+29
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ describe('Schema Parser', () => {
7979

8080
expect(toJSONDeep(doc)).to.deep.equal({
8181
kind: 'Document',
82+
comments: [],
8283
definitions: [
8384
{
8485
kind: 'ObjectTypeDefinition',
@@ -176,6 +177,7 @@ describe('Schema Parser', () => {
176177

177178
expect(toJSONDeep(doc)).to.deep.equal({
178179
kind: 'Document',
180+
comments: [],
179181
definitions: [
180182
{
181183
kind: 'ObjectTypeExtension',
@@ -201,6 +203,7 @@ describe('Schema Parser', () => {
201203

202204
expect(toJSONDeep(doc)).to.deep.equal({
203205
kind: 'Document',
206+
comments: [],
204207
definitions: [
205208
{
206209
kind: 'ObjectTypeExtension',
@@ -219,6 +222,7 @@ describe('Schema Parser', () => {
219222
const doc = parse('extend interface Hello implements Greeting');
220223
expect(toJSONDeep(doc)).to.deep.equal({
221224
kind: 'Document',
225+
comments: [],
222226
definitions: [
223227
{
224228
kind: 'InterfaceTypeExtension',
@@ -242,6 +246,7 @@ describe('Schema Parser', () => {
242246

243247
expect(toJSONDeep(doc)).to.deep.equal({
244248
kind: 'Document',
249+
comments: [],
245250
definitions: [
246251
{
247252
kind: 'ObjectTypeExtension',
@@ -304,6 +309,7 @@ describe('Schema Parser', () => {
304309
`);
305310
expect(toJSONDeep(doc)).to.deep.equal({
306311
kind: 'Document',
312+
comments: [],
307313
definitions: [
308314
{
309315
kind: 'InterfaceTypeExtension',
@@ -376,6 +382,7 @@ describe('Schema Parser', () => {
376382
const doc = parse(body);
377383
expect(toJSONDeep(doc)).to.deep.equal({
378384
kind: 'Document',
385+
comments: [],
379386
definitions: [
380387
{
381388
kind: 'SchemaExtension',
@@ -400,6 +407,7 @@ describe('Schema Parser', () => {
400407
const doc = parse(body);
401408
expect(toJSONDeep(doc)).to.deep.equal({
402409
kind: 'Document',
410+
comments: [],
403411
definitions: [
404412
{
405413
kind: 'SchemaExtension',
@@ -442,6 +450,7 @@ describe('Schema Parser', () => {
442450

443451
expect(toJSONDeep(doc)).to.deep.equal({
444452
kind: 'Document',
453+
comments: [],
445454
definitions: [
446455
{
447456
kind: 'ObjectTypeDefinition',
@@ -471,6 +480,7 @@ describe('Schema Parser', () => {
471480
const doc = parse('interface Hello implements World { field: String }');
472481
expect(toJSONDeep(doc)).to.deep.equal({
473482
kind: 'Document',
483+
comments: [],
474484
definitions: [
475485
{
476486
kind: 'InterfaceTypeDefinition',
@@ -497,6 +507,7 @@ describe('Schema Parser', () => {
497507

498508
expect(toJSONDeep(doc)).to.deep.equal({
499509
kind: 'Document',
510+
comments: [],
500511
definitions: [
501512
{
502513
kind: 'ObjectTypeDefinition',
@@ -523,6 +534,7 @@ describe('Schema Parser', () => {
523534

524535
expect(toJSONDeep(doc)).to.deep.equal({
525536
kind: 'Document',
537+
comments: [],
526538
definitions: [
527539
{
528540
kind: 'ObjectTypeDefinition',
@@ -551,6 +563,7 @@ describe('Schema Parser', () => {
551563
const doc = parse('interface Hello implements Wo & rld { field: String }');
552564
expect(toJSONDeep(doc)).to.deep.equal({
553565
kind: 'Document',
566+
comments: [],
554567
definitions: [
555568
{
556569
kind: 'InterfaceTypeDefinition',
@@ -580,6 +593,7 @@ describe('Schema Parser', () => {
580593

581594
expect(toJSONDeep(doc)).to.deep.equal({
582595
kind: 'Document',
596+
comments: [],
583597
definitions: [
584598
{
585599
kind: 'ObjectTypeDefinition',
@@ -610,6 +624,7 @@ describe('Schema Parser', () => {
610624
);
611625
expect(toJSONDeep(doc)).to.deep.equal({
612626
kind: 'Document',
627+
comments: [],
613628
definitions: [
614629
{
615630
kind: 'InterfaceTypeDefinition',
@@ -639,6 +654,7 @@ describe('Schema Parser', () => {
639654

640655
expect(toJSONDeep(doc)).to.deep.equal({
641656
kind: 'Document',
657+
comments: [],
642658
definitions: [
643659
{
644660
kind: 'EnumTypeDefinition',
@@ -658,6 +674,7 @@ describe('Schema Parser', () => {
658674

659675
expect(toJSONDeep(doc)).to.deep.equal({
660676
kind: 'Document',
677+
comments: [],
661678
definitions: [
662679
{
663680
kind: 'EnumTypeDefinition',
@@ -684,6 +701,7 @@ describe('Schema Parser', () => {
684701

685702
expect(toJSONDeep(doc)).to.deep.equal({
686703
kind: 'Document',
704+
comments: [],
687705
definitions: [
688706
{
689707
kind: 'InterfaceTypeDefinition',
@@ -714,6 +732,7 @@ describe('Schema Parser', () => {
714732

715733
expect(toJSONDeep(doc)).to.deep.equal({
716734
kind: 'Document',
735+
comments: [],
717736
definitions: [
718737
{
719738
kind: 'ObjectTypeDefinition',
@@ -752,6 +771,7 @@ describe('Schema Parser', () => {
752771

753772
expect(toJSONDeep(doc)).to.deep.equal({
754773
kind: 'Document',
774+
comments: [],
755775
definitions: [
756776
{
757777
kind: 'ObjectTypeDefinition',
@@ -794,6 +814,7 @@ describe('Schema Parser', () => {
794814

795815
expect(toJSONDeep(doc)).to.deep.equal({
796816
kind: 'Document',
817+
comments: [],
797818
definitions: [
798819
{
799820
kind: 'ObjectTypeDefinition',
@@ -836,6 +857,7 @@ describe('Schema Parser', () => {
836857

837858
expect(toJSONDeep(doc)).to.deep.equal({
838859
kind: 'Document',
860+
comments: [],
839861
definitions: [
840862
{
841863
kind: 'ObjectTypeDefinition',
@@ -876,6 +898,7 @@ describe('Schema Parser', () => {
876898

877899
expect(toJSONDeep(doc)).to.deep.equal({
878900
kind: 'Document',
901+
comments: [],
879902
definitions: [
880903
{
881904
kind: 'UnionTypeDefinition',
@@ -895,6 +918,7 @@ describe('Schema Parser', () => {
895918

896919
expect(toJSONDeep(doc)).to.deep.equal({
897920
kind: 'Document',
921+
comments: [],
898922
definitions: [
899923
{
900924
kind: 'UnionTypeDefinition',
@@ -917,6 +941,7 @@ describe('Schema Parser', () => {
917941

918942
expect(toJSONDeep(doc)).to.deep.equal({
919943
kind: 'Document',
944+
comments: [],
920945
definitions: [
921946
{
922947
kind: 'UnionTypeDefinition',
@@ -967,6 +992,7 @@ describe('Schema Parser', () => {
967992

968993
expect(toJSONDeep(doc)).to.deep.equal({
969994
kind: 'Document',
995+
comments: [],
970996
definitions: [
971997
{
972998
kind: 'ScalarTypeDefinition',
@@ -988,6 +1014,7 @@ input Hello {
9881014

9891015
expect(toJSONDeep(doc)).to.deep.equal({
9901016
kind: 'Document',
1017+
comments: [],
9911018
definitions: [
9921019
{
9931020
kind: 'InputObjectTypeDefinition',
@@ -1026,6 +1053,7 @@ input Hello {
10261053

10271054
expect(toJSONDeep(doc)).to.deep.equal({
10281055
kind: 'Document',
1056+
comments: [],
10291057
definitions: [
10301058
{
10311059
kind: 'DirectiveDefinition',
@@ -1062,6 +1090,7 @@ input Hello {
10621090

10631091
expect(toJSONDeep(doc)).to.deep.equal({
10641092
kind: 'Document',
1093+
comments: [],
10651094
definitions: [
10661095
{
10671096
kind: 'DirectiveDefinition',

src/language/ast.d.ts

+10
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,16 @@ export interface DocumentNode {
204204
readonly kind: 'Document';
205205
readonly loc?: Location;
206206
readonly definitions: ReadonlyArray<DefinitionNode>;
207+
readonly comments: ReadonlyArray<CommentNode>;
208+
}
209+
210+
export interface CommentNode {
211+
readonly kind: 'Comment';
212+
readonly start: number;
213+
readonly end: number;
214+
readonly column: number;
215+
readonly line: number;
216+
readonly value: string | void;
207217
}
208218

209219
export type DefinitionNode =

src/language/ast.js

+10
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,23 @@ export type DocumentNode = {|
240240
+kind: 'Document',
241241
+loc?: Location,
242242
+definitions: $ReadOnlyArray<DefinitionNode>,
243+
+comments: $ReadOnlyArray<CommentNode>,
243244
|};
244245

245246
export type DefinitionNode =
246247
| ExecutableDefinitionNode
247248
| TypeSystemDefinitionNode
248249
| TypeSystemExtensionNode;
249250

251+
export type CommentNode = {|
252+
+kind: 'Comment',
253+
+start: number,
254+
+end: number,
255+
+column: number,
256+
+line: number,
257+
+value: string | void,
258+
|};
259+
250260
export type ExecutableDefinitionNode =
251261
| OperationDefinitionNode
252262
| FragmentDefinitionNode;

src/language/lexer.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export class Lexer {
2222
*/
2323
token: Token;
2424

25+
commentsList: Array<CommentNode>;
2526
/**
2627
* The (1-indexed) line containing the current token.
2728
*/

src/language/lexer.js

+26-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import { syntaxError } from '../error/syntaxError';
44

5-
import { Token } from './ast';
5+
import { Token, type CommentNode } from './ast';
66
import { type Source } from './source';
77
import { dedentBlockStringValue } from './blockString';
88
import { type TokenKindEnum, TokenKind } from './tokenKind';
@@ -28,6 +28,10 @@ export class Lexer {
2828
*/
2929
token: Token;
3030

31+
/**
32+
* The list of comments token encountered so far
33+
*/
34+
commentsList: Array<CommentNode>;
3135
/**
3236
* The (1-indexed) line containing the current token.
3337
*/
@@ -44,6 +48,7 @@ export class Lexer {
4448
this.source = source;
4549
this.lastToken = startOfFileToken;
4650
this.token = startOfFileToken;
51+
this.commentsList = [];
4752
this.line = 1;
4853
this.lineStart = 0;
4954
}
@@ -67,12 +72,32 @@ export class Lexer {
6772
do {
6873
// Note: next is only mutable during parsing, so we cast to allow this.
6974
token = token.next ?? ((token: any).next = readToken(this, token));
75+
if (token.kind === TokenKind.COMMENT) {
76+
addCommentNodeToList(this, token);
77+
continue;
78+
}
7079
} while (token.kind === TokenKind.COMMENT);
7180
}
7281
return token;
7382
}
7483
}
7584

85+
function addCommentNodeToList(lexer: Lexer, commentToken: Token) {
86+
if (commentToken.kind !== TokenKind.COMMENT) {
87+
return;
88+
}
89+
const { start, end, column, line, value } = commentToken;
90+
91+
lexer.commentsList.push({
92+
kind: 'Comment',
93+
start,
94+
end,
95+
column,
96+
line,
97+
value,
98+
});
99+
}
100+
76101
/**
77102
* @internal
78103
*/

0 commit comments

Comments
 (0)