fix: apply search and replace in a single pass - #287
Open
rajanpanth wants to merge 2 commits into
Open
Conversation
Replacements ran sequentially over accumulated content, so a later pair could rewrite an earlier pair's output. Renaming the counter template to my-counter produced my-mycounter, because the compact name variant then matched the counter inside the kebab result. All patterns now match in one pass, longest first, so replaced text is never rescanned. The same replacer is used for path renames. Fixes solana-foundation#192
馃 Changeset detectedLatest commit: 0b07569 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
Greptile SummaryThis PR changes template content and path renaming to apply all literal replacements in one pass, preventing later pairs from rewriting earlier output.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Reviews (2): Last reviewed commit: "chore: add changeset for the single-pass..." | Re-trigger Greptile |
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 #192.
@beeman's diagnosis on the issue was right, and the loop is in
searchAndReplaceitself: replacements are applied sequentially over the accumulated content, so a later pair can rewrite an earlier pair's output.Renaming the
countertemplate tomy-counterpasses several name variants, all of which search forcounter:which is exactly the
mymymycounterin the report. It is not specific to kebab case or to thecountertemplate: it triggers whenever a replacement value contains another search string.The general shape is worth calling out too, since it corrupts values that have nothing to do with package names:
Fix
All pairs are compiled into one alternation and applied in a single pass, so replaced text is never rescanned. Search strings are sorted longest-first, so the most specific pattern wins (
my_counteris preferred overcounter), and the first pair for a duplicated search string is the one that applies, matching the previous first-write-wins behavior.The same replacer now drives path renaming, which had an identical sequential loop and the same bug for file and directory names.
Verification
test/search-and-replace.test.tspass, 4 added: the issue's exact shape, the general rescan case, longest-match preference, and the path-rename path.search-and-replace.tsalone fails all 4 new tests.pnpm lintandpnpm test:typesclean.Relationship to #286
I have a separate open PR, #286, that dedupes package-name variants in
init-script-rename.ts. That reduces how often duplicate pairs are generated, but it does not fix the underlying rescan, which still corrupts any content where one replacement contains another search string. This PR fixes the root cause and is independent; either can land first, and #286 becomes a tidiness improvement rather than a fix.