Skip to content

Commit 2984e7b

Browse files
authored
perf: Replace most sticky regexs with pure parser combinators (#52)
1 parent 5c7a5a5 commit 2984e7b

File tree

5 files changed

+319
-270
lines changed

5 files changed

+319
-270
lines changed

.changeset/red-turkeys-flash.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@0no-co/graphql.web': minor
3+
---
4+
5+
Improve parser performance (up to ~25% higher ops/s) by rewriting part of the parsing that runs in tight loops. Previously, the purer parser combinators w/o regexs wouldn't have been as significant of an improvement, but they now clearly are

scripts/eslint-preset.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,6 @@ module.exports = {
6969
selector: 'AssignmentExpression[operator="??="]',
7070
message: 'Nullish coalescing assignment (??=) is outside of specified browser support',
7171
},
72-
{
73-
selector: 'SequenceExpression',
74-
message: 'Sequence expressions are to be avoided since they can be confusing',
75-
},
7672
{
7773
selector: ':not(ForStatement) > VariableDeclaration[declarations.length>1]',
7874
message: 'Only one variable declarator per variable declaration is preferred',

scripts/rollup.config.mjs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,7 @@ const outputPlugins = [
142142
booleans_as_integers: false,
143143
keep_fnames: true,
144144
keep_fargs: true,
145-
if_return: false,
146145
ie8: false,
147-
sequences: false,
148-
loops: false,
149146
conditionals: false,
150147
join_vars: false,
151148
},

src/__tests__/parser.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ describe('parse', () => {
4242
expect(() => {
4343
return parse('{ ...on }');
4444
}).toThrow();
45+
// But does accept "oN"
46+
expect(parse('{ ...oN }')).toHaveProperty(
47+
'definitions.0.selectionSet.selections.0.name.value',
48+
'oN'
49+
);
4550
});
4651

4752
it('parses directives on fragment spread', () => {
@@ -123,6 +128,16 @@ describe('parse', () => {
123128
}).not.toThrow();
124129
});
125130

131+
it('throws on invalid operations', () => {
132+
expect(() => {
133+
return parse(`
134+
invalid {
135+
field
136+
}
137+
`);
138+
}).toThrow();
139+
});
140+
126141
it('parses named mutation operations', () => {
127142
expect(() => {
128143
return parse(`
@@ -255,6 +270,7 @@ describe('parse', () => {
255270
expect(() => parse('{ ... on Test }')).toThrow();
256271
expect(() => parse('{ ... {} }')).toThrow();
257272
expect(() => parse('{ ... }')).toThrow();
273+
expect(() => parse('{ . }')).toThrow();
258274

259275
expect(parse('{ ... on Test { field } }')).toHaveProperty(
260276
'definitions.0.selectionSet.selections.0',
@@ -497,6 +513,19 @@ describe('parseValue', () => {
497513
expect(parseValue({ body: 'null' })).toEqual({ kind: Kind.NULL });
498514
});
499515

516+
it('parses scalars', () => {
517+
expect(parseValue('null')).toEqual({ kind: Kind.NULL });
518+
expect(parseValue('true')).toEqual({ kind: Kind.BOOLEAN, value: true });
519+
expect(parseValue('false')).toEqual({ kind: Kind.BOOLEAN, value: false });
520+
});
521+
522+
it('parses scalars without optimistic failures', () => {
523+
// for *n*ull, *f*alse, *t*rue
524+
expect(parseValue('n')).toEqual({ kind: Kind.ENUM, value: 'n' });
525+
expect(parseValue('f')).toEqual({ kind: Kind.ENUM, value: 'f' });
526+
expect(parseValue('t')).toEqual({ kind: Kind.ENUM, value: 't' });
527+
});
528+
500529
it('parses list values', () => {
501530
const result = parseValue('[123 "abc"]');
502531
expect(result).toEqual({
@@ -542,6 +571,8 @@ describe('parseValue', () => {
542571
kind: Kind.FLOAT,
543572
value: '-1.2e+3',
544573
});
574+
575+
expect(() => parseValue('12e')).toThrow();
545576
});
546577

547578
it('parses strings', () => {
@@ -580,6 +611,10 @@ describe('parseValue', () => {
580611
value: ' " ',
581612
block: false,
582613
});
614+
615+
expect(() => parseValue('"')).toThrow();
616+
expect(() => parseValue('"\n')).toThrow();
617+
expect(() => parseValue('"\r')).toThrow();
583618
});
584619

585620
it('parses objects', () => {
@@ -674,6 +709,8 @@ describe('parseValue', () => {
674709
value: ' """ ',
675710
block: true,
676711
});
712+
713+
expect(() => parseValue('"""')).toThrow();
677714
});
678715

679716
it('allows variables', () => {

0 commit comments

Comments
 (0)