fix: read plugin metadata by scanning the source, not one regex #1
Loading…
Reference in a new issue
No description provided.
Delete branch "(deleted):fix/plugin-meta-parser"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What breaks
getPluginMetareads a plugin's index file withPLUGIN_META_REGEX, and that regex only matches when nothing but whitespace or comments sits between thenameanddescriptionkeys. Plenty of plugins put another key in that gap. When they do, the match returns null,getPluginMetathrows onrawMeta![1], and thePromise.allSettledfilter ingetUserpluginsdrops the plugin without a word.The plugin is still installed and still runs, so it shows up in the normal Plugins list, but it is completely absent from the UserPlugins tab. The uninstall and update buttons are rendered from that same list, so neither works for it either. Reinstalling looks broken in its own way: the clone lands on disk and the review window never opens, which reads as the installer doing nothing at all.
I hit this with a userplugin that has a
versionkey between the two, then checked how far it goes. Of the 42 repos in theuserpluginsorg, 37 ship an index file, and 2 of those are invisible in the tab right now: the one I was installing, andamrpcstatusdisplaytype.desktop, which hastags: ["AppleMusicRichPresence"]betweennameanddescription. Vencord's own tree says the same thing about how common the shape is, for what it is worth: 29 of 170 plugins fail the regex, mostly by listingauthorsbeforedescription. Those never appear in this tab, so they are not affected, but they are written by the same people following the same habits.What this changes
Metadata is now read by scanning the
definePluginobject as tokens instead of matching one fixed shape. The new scanner lives inmisc/pluginMeta.tsand exports a singleparsePluginMeta(source). It walks top-level keys, steps over strings, template literals, regex literals, comments and nested brackets, and returns null rather than a guess whenever it loses track of where it is.It stops as soon as both keys are found. That also keeps it out of the JSX further down the file, which matters more than it sounds: JSX text is not JavaScript, so an apostrophe in something like
the artist's nameopens a string literal that never closes as far as a tokenizer is concerned. Scanning the whole object without that early exit fails on real plugins.The second change is smaller. Picking the index file used to be four
ifs that each assigned on a match, so the last matching entry won and a plugin shipping bothindex.jsandindex.tsxgot parsed from whichever onereaddirhappened to return last. It now uses explicit precedence in the order esbuild resolves a directory, so we read the file that actually ends up in the build.Testing
I cross-checked the parser against the TypeScript compiler AST, which is the same source of truth Vencord's own
generatePluginListreads. Over all 189 files undersrc/pluginsandsrc/userpluginsthat define a plugin: 187 agree, 2 are files that only mentiondefinePluginin passing and both return null, 0 disagree.On top of that, 21 hand-written cases covering regex literals containing quotes and braces, JSX tags, method shorthand, spreads, computed keys, comments that mention
description, template literals with and without substitutions, and truncated or unterminated files. Plus a false-positive pass over files that define no plugin.The index-file order was checked against esbuild 0.28.1 rather than assumed:
.tsxwins over.ts, which wins over.js.For regressions I ran the old code path and the new one side by side over every plugin repo in the
userpluginsorg, comparing which index file gets picked and what metadata comes back. Old code lists 36 of 37, new code lists 37, nothing is lost, no name or description text differs anywhere. Same comparison over the local tree: 0 lost, 30 gained, 0 text changes. And the failure mode is unchanged for anything I could not test, since the parser returns null rather than throwing, which lands on the sameInvalid pluginrejection the old code produced.Build side,
pnpm build --devexits 0 andtsc --noEmitreports nothing new (the one error it does print is pre-existing, incomponents/SettingsTab.tsx, untouched here). With the built output loaded, the userplugin that started this now appears in the UserPlugins tab with its description, source link and delete button.Notes
The parser has no dependencies and does not touch
CLONE_LINK_REGEXor anything else innative.tsbeyond the metadata read. If you would rather have the self-test harness in the repo than only in this description, say the word and I will add it as a file.AI slop
your entire account also seems to be made with as sole intent to contribute slop so I have blocked it from this git instance altogether. if you ever intent to make a good faith contribution, contact me
Pull request closed