fix(douban): inline normalizeText into splitDoubanTitle for page eval#1854
Open
Benjamin-eecs wants to merge 1 commit into
Open
fix(douban): inline normalizeText into splitDoubanTitle for page eval#1854Benjamin-eecs wants to merge 1 commit into
Benjamin-eecs wants to merge 1 commit into
Conversation
splitDoubanTitle is serialized via toString() into loadDoubanMovieSubject's page.evaluate, so its closure reference to the module-level normalizeText raised ReferenceError in the browser scope and broke douban subject. Fixes jackwener#1851
e9403eb to
0b563e1
Compare
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR addresses a regression where splitDoubanTitle fails when its implementation is stringified and executed inside page.evaluate, and adds a regression test to prevent future breakage.
Changes:
- Inline
normalizeTextinsidesplitDoubanTitleto remove dependency on a module-scope helper duringFunction.toString()injection. - Add a dedicated VM-based evaluation helper for movie subject pages in tests.
- Add a regression test for loading a movie subject when
splitDoubanTitleis toString-injected (issue #1851).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| clis/douban/utils.js | Removes closure dependency in splitDoubanTitle by inlining normalization logic. |
| clis/douban/utils.test.js | Adds VM evaluation helper + regression test to ensure movie subject parsing doesn’t throw under toString-injection. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+71
to
75
| // Inline normalizeText so the toString-injected copy inside | ||
| // loadDoubanMovieSubject's page.evaluate runs without a closure reference | ||
| // to the module-level helper (which does not survive Function.toString()). | ||
| const normalizeText = (value) => String(value || '').replace(/\s+/g, ' ').trim(); | ||
| const normalized = normalizeText(fullTitle); |
Comment on lines
+86
to
+88
| querySelectorAll() { | ||
| return []; | ||
| }, |
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.
Description
opencli douban subject <id>fails withReferenceError: normalizeText is not definedthrown atsplitDoubanTitle (<anonymous>:5:24), matching the symptom reported in #1851.loadDoubanMovieSubjectinclis/douban/utils.js:217builds itspage.evaluatescript by inliningsplitDoubanTitle.toString()directly into the expression at line 227.Function.prototype.toString()returns only the source of the function body, never its closure, so when the page eval runs in the browser scope it sees a freshsplitDoubanTitlewhose body references the module-level helpernormalizeText(defined atclis/douban/utils.js:11) that does not exist in that scope. The same eval block already declares a localnormalizehelper at line 226, but the name does not match whatsplitDoubanTitlereaches for.The minimal fix is to make
splitDoubanTitleself-contained: inline anormalizeTextconst at the top of the function so the toString-injected copy carries its own helper. The three existingnormalizeText(...)call sites inside the function continue to work, behavior is unchanged, no other caller exists (the function is only invoked in this one page.evaluate, never directly in Node), and the daemon protocol surface is untouched.Audit of every other
*.toString()-injected helper inclis/confirms none has the same closure-leak shape:resolveDoubanPhotoAssetUrl(clis/douban/utils.js:143) uses onlyString/URL/ regex literals;inferDoubanSearchResultType(clis/douban/utils.js:556) uses onlyString/Array.isArray/ regex literals;looksAuthWallText(clis/reuters/utils.js:94) uses onlyString/ regex;collectCodexProjectsFromDocument(clis/codex/sidebar.js:56) andextractSearchRows(clis/gov-policy/search.js:28) andextractRecentRows(clis/gov-policy/recent.js:28) all define their helpers inside their own function body.splitDoubanTitlewas the only outlier; the codebase idiom is that injected helpers must be self-contained, and this PR bringssplitDoubanTitleback into that idiom.Related issue: fixes #1851.
Type of Change
Checklist
Screenshots / Output
Pre-fix live repro on upstream main
944ca3a1:Post-fix live verify on this branch with the same subject id from the issue:
A new regression test under
describe('douban utils')inclis/douban/utils.test.jsexercisesloadDoubanSubjectDetail(page, '37116446', 'movie')end-to-end by routing the secondpage.evaluate(...)call throughvm.runInNewContext(script, { document, URL }), the same harnessrunMovieHotEvaluatealready uses atclis/douban/utils.test.js:71. The newrunMovieSubjectEvaluate(script, elementMap)helper sits next to it at module scope so the two share the same shape and discoverability. Without this PR's fix the test fails with the exactReferenceError: normalizeText is not defined; with the fix the test assertstitle === '海贼王:黄金大冒险'andoriginalTitle === 'One Piece Gold'. Full douban suite continues to pass: 24/24.cli-manifest.jsonuntouched, no source other thanclis/douban/utils.jsis touched.