Skip to content

Commit

Permalink
perf: Replace most sticky regexs with pure parser combinators (#52)
Browse files Browse the repository at this point in the history
  • Loading branch information
kitten authored Feb 13, 2025
1 parent 5c7a5a5 commit 2984e7b
Show file tree
Hide file tree
Showing 5 changed files with 319 additions and 270 deletions.
5 changes: 5 additions & 0 deletions .changeset/red-turkeys-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@0no-co/graphql.web': minor
---

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
4 changes: 0 additions & 4 deletions scripts/eslint-preset.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,6 @@ module.exports = {
selector: 'AssignmentExpression[operator="??="]',
message: 'Nullish coalescing assignment (??=) is outside of specified browser support',
},
{
selector: 'SequenceExpression',
message: 'Sequence expressions are to be avoided since they can be confusing',
},
{
selector: ':not(ForStatement) > VariableDeclaration[declarations.length>1]',
message: 'Only one variable declarator per variable declaration is preferred',
Expand Down
3 changes: 0 additions & 3 deletions scripts/rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,7 @@ const outputPlugins = [
booleans_as_integers: false,
keep_fnames: true,
keep_fargs: true,
if_return: false,
ie8: false,
sequences: false,
loops: false,
conditionals: false,
join_vars: false,
},
Expand Down
37 changes: 37 additions & 0 deletions src/__tests__/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ describe('parse', () => {
expect(() => {
return parse('{ ...on }');
}).toThrow();
// But does accept "oN"
expect(parse('{ ...oN }')).toHaveProperty(
'definitions.0.selectionSet.selections.0.name.value',
'oN'
);
});

it('parses directives on fragment spread', () => {
Expand Down Expand Up @@ -123,6 +128,16 @@ describe('parse', () => {
}).not.toThrow();
});

it('throws on invalid operations', () => {
expect(() => {
return parse(`
invalid {
field
}
`);
}).toThrow();
});

it('parses named mutation operations', () => {
expect(() => {
return parse(`
Expand Down Expand Up @@ -255,6 +270,7 @@ describe('parse', () => {
expect(() => parse('{ ... on Test }')).toThrow();
expect(() => parse('{ ... {} }')).toThrow();
expect(() => parse('{ ... }')).toThrow();
expect(() => parse('{ . }')).toThrow();

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

it('parses scalars', () => {
expect(parseValue('null')).toEqual({ kind: Kind.NULL });
expect(parseValue('true')).toEqual({ kind: Kind.BOOLEAN, value: true });
expect(parseValue('false')).toEqual({ kind: Kind.BOOLEAN, value: false });
});

it('parses scalars without optimistic failures', () => {
// for *n*ull, *f*alse, *t*rue
expect(parseValue('n')).toEqual({ kind: Kind.ENUM, value: 'n' });
expect(parseValue('f')).toEqual({ kind: Kind.ENUM, value: 'f' });
expect(parseValue('t')).toEqual({ kind: Kind.ENUM, value: 't' });
});

it('parses list values', () => {
const result = parseValue('[123 "abc"]');
expect(result).toEqual({
Expand Down Expand Up @@ -542,6 +571,8 @@ describe('parseValue', () => {
kind: Kind.FLOAT,
value: '-1.2e+3',
});

expect(() => parseValue('12e')).toThrow();
});

it('parses strings', () => {
Expand Down Expand Up @@ -580,6 +611,10 @@ describe('parseValue', () => {
value: ' " ',
block: false,
});

expect(() => parseValue('"')).toThrow();
expect(() => parseValue('"\n')).toThrow();
expect(() => parseValue('"\r')).toThrow();
});

it('parses objects', () => {
Expand Down Expand Up @@ -674,6 +709,8 @@ describe('parseValue', () => {
value: ' """ ',
block: true,
});

expect(() => parseValue('"""')).toThrow();
});

it('allows variables', () => {
Expand Down
Loading

0 comments on commit 2984e7b

Please sign in to comment.