Repository navigation
fix(formatter): stop the error message regexes from retrying each position - #241
Open
musatoktas wants to merge 2 commits into
Open
musatoktas wants to merge 2 commits into
musatoktas wants to merge 2 commits into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #187
The regexes in #187 are slow on a line where a rule finds its start many times but cannot complete a match. The engine tries every start again, and each try reads to the end of the line, so the time grows with the square of the line length.
What changes
errorMessagePrettifier.tsgets a last alternative after its start:(?<rest>.*). When a rule cannot match from a start, no later start on the same line can match either, because the content parts are.*?or.*(a match from a later start is also a match from the earlier one). So therestgroup takes the rest of the line in one step. For the['“]([^>]*)['”] (type|...)rule the rest is[^>]*, and for the last rule it is(?:(?!["]).)*: the same characters as their content.createErrorMessagePrettifierkeeps a match with arestgroup as it is.addMissingParentheses.ts:54: the content cannot go past a(that starts another(name:. The match then ends at the same), so the result is the same. InaddMissingParenthesesthe old regex was not slow, because the function adds a)for each unclosed(. This change only makes the regex itself linear.Apart from that, the regexes and their captures do not change. I did not use negated character classes: TypeScript writes quoted property names with single quotes (
{ 'first-name': string; }), and a class like[^']*changes the output for those (errorWithDashInObjectKeys,errorWithSpecialCharsInObjectKeysand theis missing the following propertiescase).Checks
recheck 4: before, all 13 regexes from the issue table are
vulnerable(polynomial). After, all 13 aresafe.The attack strings from the issue, through the prettifier, Node 20 on GitHub Actions:
Same output: I compared main and this branch on 8,506 messages, with the test stub and with
hoverCodeBlock. The messages are the 22 mocks and the 2,121 messages of TypeScript 5.9.3'sdiagnosticMessages.json, each filled 4 times with different types. There are 0 differences.Tests: one new test per attack string, which must finish in under 500 ms. Without the source change, all 12 fail (1.4 s to 7.2 s each). With it, the 39 formatter tests and the 10 vscode-formatter tests pass, and
format:checkand the build pass.This covers the 13 regexes in the issue table.