feat(search): improve filename normalization for better auto results#414
feat(search): improve filename normalization for better auto results#414
Conversation
- Add regex pattern to remove 'read by' / 'narrated by' with narrator names - Add regex pattern to remove part/volume/book/chapter indicators - Add regex pattern to remove years in parentheses/brackets and standalone 4-digit years - Add unit tests for normalize_name method Improves ASIN auto-matching by cleaning up common audiobook filename patterns.
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds ARIA semantics, keyboard navigation, focus management, and defensive guards to the book-tabs UI; extends SearchTool.normalize_name to strip narrator phrases and avoid empty results after year removal; and adds unit tests for tab behavior and name normalization. Changes
sequenceDiagram
participant User as User
participant Browser as Browser (DOM)
participant TabScript as book_tabs.js
participant SR as AssistiveTech
Note over Browser,TabScript: initializeTabs runs on window load
Browser->>TabScript: window.onload → initializeTabs(document)
TabScript->>Browser: query tabs, attach keydown listeners, set ARIA roles/attributes
User->>Browser: click or keydown on tab anchor
Browser->>TabScript: event → openTab(event, tabId, userInitiated?)
TabScript->>Browser: preventDefault(), validate elements, hide/show panels
TabScript->>Browser: update aria-selected and tabindex on anchors
alt userInitiated true
TabScript->>Browser: focus(active anchor)
end
Browser->>SR: updated ARIA state announced
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Important Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional. ❌ Failed checks (1 warning, 2 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
importer/templates/base.htmlimporter/templates/book_list.htmlimporter/templates/book_tabs.htmlutils/search_tools.pyutils/tests.py
🧰 Additional context used
📓 Path-based instructions (1)
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/base.htmlutils/search_tools.pyutils/tests.pyimporter/templates/book_tabs.htmlimporter/templates/book_list.html
🧬 Code graph analysis (1)
utils/tests.py (1)
utils/search_tools.py (1)
normalize_name(61-106)
🪛 Ruff (0.15.1)
utils/tests.py
[warning] 292-292: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 293-293: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 294-294: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 295-295: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 300-300: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 301-301: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 302-302: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 303-303: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 308-308: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 309-309: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 310-310: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 315-315: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 316-316: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
🔇 Additional comments (2)
importer/templates/book_list.html (1)
30-32: LGTM!The CSS class application correctly enables word-wrapping for long book descriptions. The styling integration with
base.htmlis appropriate.utils/tests.py (1)
289-295: Regarding Ruff PT009 warnings: this is a false positive.The static analysis hints suggest using plain
assertinstead ofassertIn/assertNotIn. However, this is a DjangoTestCasewhich extendsunittest.TestCase. The unittest-style assertions provide better error messages on failure (showing actual vs expected values) and are idiomatic for this test framework.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/base.html`:
- Around line 207-213: The .book-description CSS block contains redundant and
deprecated properties: remove the legacy "word-wrap" declaration, replace the
deprecated "word-break: break-word" with "overflow-wrap: anywhere" (or adjust
overflow-wrap if already present) and drop the unnecessary "max-height: none"
since it's the default; update the .book-description rule to keep only the
needed properties (e.g., overflow-wrap / hyphens and any other necessary rules)
to eliminate redundancy and deprecated usage.
In `@importer/templates/book_tabs.html`:
- Around line 6-8: Add ARIA tab semantics: on the tab anchors (inside elements
with IDs done-tab, processing-tab, error-tab) add role="tab" and ensure an
aria-selected attribute is present and updated by the openTab function; when
openTab switches active tabs it should set aria-selected="true" on the newly
active anchor and aria-selected="false" on the others (in addition to toggling
the "is-active" class) so screen readers get correct selected state.
In `@utils/search_tools.py`:
- Around line 97-98: The current re.sub call assigning to name uses a two-part
regex `[\(\[]\s*\d{4}\s*[\)\]]|\b(19|20)\d{2}\b` but the bracket-case is dead
because earlier code already strips bracketed content (`\[[^"]*\]`) and later
removes all special chars (`[^\w\s]`); either simplify the expression to only
remove standalone years by replacing the pattern with `\b(19|20)\d{2}\b`, or
move this year-removal line to run before the bracket/special-character
stripping so the `[\(\[]\s*\d{4}\s*[\)\]]` branch can match — update the re.sub
call that assigns to name accordingly.
- Around line 86-89: The current re.sub call that cleans narrator phrases (the
assignment to the variable name using re.sub for the pattern matching
"read|narrated by") uses a greedy [^\[\]]+ which can remove unrelated trailing
title text; update that re.sub invocation to use a non-greedy or word-limited
pattern that only captures the narrator name (for example, match a few words
after "by" or use a non-greedy quantifier and stop at end/extra spacing) and
remove the redundant bracket-exclusion (since brackets are already stripped
earlier); locate the re.sub that removes "read by"/"narrated by" and replace the
pattern accordingly so only the narrator token(s) are removed and not the rest
of the title.
In `@utils/tests.py`:
- Around line 282-316: Add unit tests to TestSearchToolNormalizeName to cover
missing normalization cases: add a test method for the "narrated by" variant
(call self.tool.normalize_name on "Great Book narrated by Jane Doe" and assert
neither "narrated by" nor "jane doe" appear), a test for standalone years (e.g.,
"Book Title 2020 Edition" asserting "2020" is removed but "edition" remains), a
test for volume/chapter indicators (e.g., "Epic Saga Volume 2" asserting "volume
2" is removed and title words remain), and an edge-case test for trailing text
after a narrator (e.g., "Great Book read by John Smith The Sequel" asserting
that "sequel" is preserved) so normalize_name is exercised against the
greedy-regex bug.
- Remove deprecated CSS properties (overflow-wrap, word-wrap, word-break) and replace with modern overflow-wrap: anywhere - Add ARIA role attributes (role=tablist, role=tab, role=tabpanel) for proper accessibility tree - Add aria-selected state management in JavaScript for screen readers - Add aria-controls and aria-labelledby relationships for tab panels Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
- Limit narrator name capture to 2-3 words to prevent over-matching - Preserve trailing text after narrator patterns (e.g., sequels) - Add unit tests for narrator removal, year removal, and volume indicators Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (5)
importer/templates/base.htmlimporter/templates/book_tabs.htmlimporter/templates/book_tabs.jsutils/search_tools.pyutils/tests.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.jsimporter/templates/book_tabs.htmlimporter/templates/base.htmlutils/tests.pyutils/search_tools.py
🪛 Ruff (0.15.1)
utils/tests.py
[warning] 292-292: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 293-293: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 294-294: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 295-295: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 300-300: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 301-301: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 302-302: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 303-303: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 308-308: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 309-309: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 310-310: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 315-315: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 316-316: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 321-321: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 322-322: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 323-323: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 324-324: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 329-329: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 330-330: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 331-331: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 332-332: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 337-337: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 338-338: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 339-339: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 340-340: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 345-345: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 346-346: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 347-347: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 348-348: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 349-349: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
🔇 Additional comments (5)
importer/templates/book_tabs.js (2)
14-22: ARIA selected-state sync looks correct.Nice update to keep
aria-selectedaligned with the active tab.
1-23: Remove reference to non-existent AGENTS.md file.The AGENTS.md file referenced in this review does not exist in the repository. The actual project uses Biome for linting (configured in biome.json with recommended rules enabled) and Node.js test runner. No specific coverage thresholds (85%+ statements/lines/functions, 80%+ branches) are documented in the project standards.
If coverage requirements should be enforced, they need to be explicitly configured in package.json or a dedicated test configuration file.
Likely an incorrect or invalid review comment.
utils/search_tools.py (1)
86-99: Normalization additions look good.The narrator and part/volume cleanup improves title matching without overreaching.
utils/tests.py (1)
282-349: Solid test coverage for new normalization behavior.Good additions covering narrator, part/volume, and year cases, plus trailing-text preservation.
importer/templates/base.html (1)
207-210: CSS addition looks good.The
book-descriptionclass provides sensible wrapping without extra baggage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.html`:
- Around line 6-8: The tab anchors (ids done-tab, processing-tab, error-tab) are
not keyboard-focusable because they lack href/tabindex; update each <a> to
include either a usable href (e.g. href="#") or explicit tabindex attributes so
they enter the tab order (set tabindex="0" for the active tab and tabindex="-1"
for inactive tabs), and ensure the click handler still calls
openTab('done'/'processing'/'error'); also update the openTab function to set
the active/inactive tabindex values (and call event.preventDefault() if you use
href="#") so keyboard users can focus and navigate tabs properly.
In `@utils/search_tools.py`:
- Around line 100-101: The current regex that strips years into the variable
name can produce an empty string for titles that are just a year (the re.sub
call assigning to name); change the flow so you first compute the stripped value
(e.g., stripped = re.sub(...)) and if stripped.strip() is empty then retain the
original name (or detect that the original is a pure year and keep it) instead
of overwriting name with an empty string — update the assignment around the
re.sub in utils/search_tools.py so name is only replaced when stripped is
non-empty.
…ty string bug - Add href and tabindex attributes to tab anchors in book_tabs.html - Update openTab() to manage tabindex and focus for keyboard accessibility - Fix empty string bug when year removal would result in empty title
There was a problem hiding this comment.
Actionable comments posted: 3
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
importer/templates/book_tabs.htmlimporter/templates/book_tabs.jsutils/search_tools.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.jsutils/search_tools.pyimporter/templates/book_tabs.html
🔇 Additional comments (3)
utils/search_tools.py (1)
93-99: Part/volume indicator cleanup looks solid.
The pattern is clear, scoped, and consistent with the existing normalization flow.importer/templates/book_tabs.js (1)
15-25: ARIA selected + tabindex synchronization is correct.
This keeps visual and accessibility states aligned when switching tabs.importer/templates/book_tabs.html (1)
4-4: Good addition ofrole="tablist".
Matches the ARIA tabs pattern and improves screen reader context.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.html`:
- Around line 6-8: The tab anchors use href="#" which causes navigation unless
prevented; update the click handling so openTab accepts the event and calls
event.preventDefault(). Change the onclick invocations for the tab elements (ids
done-tab, processing-tab, error-tab) to pass the event and the tab name (e.g.,
onclick="openTab(event, 'done')"), and update the openTab function to accept
(event, tabName) and invoke event.preventDefault() at the start before
performing tab switching logic.
- Around line 13-19: The tab panels (divs with id="done", id="processing",
id="error") currently set aria-labelledby to the parent <li> instead of the
actionable tab element; update the corresponding <a> elements that have
role="tab" by adding unique ids (e.g. done-tab-anchor, processing-tab-anchor,
error-tab-anchor) and change each panel's aria-labelledby to reference those
anchor ids (replace existing aria-labelledby values on the divs for "done",
"processing", and "error"); ensure the <a> ids are unique and match exactly the
new aria-labelledby values.
In `@utils/search_tools.py`:
- Around line 86-92: The regex that strips narrator credits in
utils/search_tools.py currently requires 2–3 words after "by" (pattern using
\w+(?:\s+\w+){1,2}), so single-word narrators like "read by Cher" are missed;
update the pattern used in the re.sub that assigns to name (the block that
removes "read by"/"narrated by" patterns) to allow 1–3 words after "by" by
changing the quantifier to {0,2} (i.e., make the group optional for additional
words) so single-word names are matched and removed.
---
Duplicate comments:
In `@utils/search_tools.py`:
- Around line 100-104: The bracketed-year alternative in the regex used when
cleaning `name` (the pattern `[\(\[]\s*\d{4}\s*[\)\]]`) is dead because
punctuation was already removed earlier; either remove that bracketed-year
branch from the `re.sub` (leave just the `\b(19|20)\d{2}\b` year matcher) or
move the year-stripping step so it runs before the punctuation stripping logic
earlier in this function; update references to `name_before_year_removal` and
`name` accordingly so the fallback behavior still preserves the original when
stripping produces an empty string.
Resolved conflicts: - base.html: use develop's book-description CSS (more comprehensive) - book_tabs.html: keep accessibility fix from feature branch
- Fix tab click handling with event.preventDefault() to prevent navigation
- Add proper aria-labelledby references to tab anchors
- Update narrator regex to match single-word names (changed {1,2} to {0,2})
- Remove dead bracketed-year pattern from year regex
There was a problem hiding this comment.
Actionable comments posted: 3
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
importer/templates/book_tabs.htmlimporter/templates/book_tabs.jsutils/search_tools.py
🧰 Additional context used
📓 Path-based instructions (2)
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.htmlimporter/templates/book_tabs.jsutils/search_tools.py
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
🔇 Additional comments (7)
utils/search_tools.py (3)
86-92: LGTM! Narrator pattern correctly handles single-word names.The regex
{0,2}quantifier properly allows 1-3 word narrator names (e.g., "read by Cher", "read by John Smith", "read by Mary Jane Watson").
93-99: LGTM! Part/volume indicator removal is well-designed.The regex correctly handles various formats like "Part 1", "Volume 2", "Book 3 of 5", and "Chapter 10" with appropriate optional spacing and case insensitivity.
100-104: LGTM! Year removal correctly preserves year-only titles.The implementation properly guards against erasing legitimate year-only titles (e.g., "1984") by checking if removal would result in an empty string and preserving the original in that case.
importer/templates/book_tabs.js (2)
1-3: LGTM! Properly prevents default anchor navigation.The
event.preventDefault()call correctly prevents thehref="#"from causing page jumps when tabs are clicked.
17-27: LGTM! ARIA state management follows accessibility best practices.The implementation correctly updates
aria-selectedandtabindexattributes, and properly focuses the active tab anchor for keyboard navigation.importer/templates/book_tabs.html (2)
6-8: LGTM! Tab links implement proper ARIA tabs pattern.The implementation correctly includes:
role="tab"with unique IDs for anchorsaria-selectedandtabindexfor roving tabindex patternaria-controlslinking to panel IDs- Descriptive
aria-labelwith book counts
13-21: LGTM! Tab panels correctly reference their controlling tabs.The
aria-labelledbyattributes now properly reference the anchor elements withrole="tab"(e.g.,done-tab-anchor), which is the correct ARIA pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.html`:
- Line 4: The data-default attribute in the div
(importer/templates/book_tabs.html) is missing quotes around the template
variable; update the element that currently contains data-default={{
default_view }} to include quotes around the template expression
(data-default="{{ default_view }}") so the attribute value is valid HTML and
handles special characters in default_view correctly.
In `@importer/templates/book_tabs.js`:
- Around line 14-15: The current tab-showing code uses
document.getElementById(tabId) and document.getElementById(`${tabId}-tab`)
without null checks, which can throw if an element is missing; update the code
that sets style.display and classList (the lines referencing tabId and
`${tabId}-tab`) to first store each lookup in a local variable, check for
truthiness (e.g., if (tabElem) ...) and only then set style.display = "block"
and call classList.add("is-active"); optionally log a warning if an expected
element is not found to aid debugging.
- Around line 30-32: The current load handler reads const defaultTab =
document.querySelector(".tabs").dataset.default and immediately calls
openTab(..., defaultTab) which can pass undefined if data-default is missing;
update the handler to guard against a missing dataset.default by checking
document.querySelector(".tabs") exists and that dataset.default is truthy, and
if not choose a safe fallback (e.g., the id of the first tab button or a known
default string) before calling openTab; reference the defaultTab variable, the
querySelector(".tabs") call, and the openTab(...) invocation when making the
change.
- Quote data-default attribute to handle special characters correctly - Add null checks for document.getElementById calls with console warnings - Guard against missing data-default with fallback to first tab - Add trailing newline for style consistency
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
importer/templates/book_tabs.htmlimporter/templates/book_tabs.js
🧰 Additional context used
📓 Path-based instructions (2)
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.htmlimporter/templates/book_tabs.js
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
🔇 Additional comments (3)
importer/templates/book_tabs.js (2)
1-25: Defensive null checks and warnings are solid.You avoid null dereferences and provide helpful diagnostics when elements are missing.
41-59: Fallback default-tab selection is robust.The staged fallback with warnings prevents runtime errors when
.tabsordata-defaultare missing.importer/templates/book_tabs.html (1)
4-19: ARIA wiring and metadata look consistent.Tablist roles,
aria-controls/aria-labelledbylinkage, and quoteddata-defaultimprove semantics and robustness.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Around line 27-36: The current roving tabindex (in the tabAnchors.forEach
block) sets inactive tabs to tabindex="-1" but lacks keyboard handlers, so
implement arrow-key navigation: add a keydown listener on each anchor (the
tabAnchors NodeList / anchor elements) that handles
ArrowLeft/ArrowRight/Home/End to move focus to the previous/next/first/last tab,
and on focus update aria-selected and tabindex values for all anchors (set the
active anchor to '0' and others to '-1') to maintain the roving pattern;
alternatively, if you prefer not to implement arrow-key behavior, change the
code that sets tabindex to always set tabindex="0" for all anchors so every tab
remains keyboard-focusable.
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
importer/templates/book_tabs.js
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.js
🔇 Additional comments (1)
importer/templates/book_tabs.js (1)
71-96: LGTM! Robust fallback logic for default tab selection.The implementation properly handles edge cases:
- Missing
.tabscontainer with warning- Missing
data-defaultattribute with fallback to first tab- Ultimate fallback to
"done"if no tabs existThe keydown handlers are correctly attached to enable keyboard navigation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Around line 66-68: The code calls nextTab.getAttribute('aria-controls') and
passes the result (tabId) directly to openTab, which can be null; update the
logic around tabAnchors/nextIndex (where nextTab is retrieved) to check that
nextTab and its aria-controls attribute are non-null before calling openTab — if
tabId is falsy, skip calling openTab (or select the next valid anchor) and
optionally log or handle the missing attribute; reference the nextTab variable,
the getAttribute('aria-controls') call, and the openTab(...) invocation when
making the change.
- Around line 27-37: The code unconditionally calls anchor.focus() inside the
tab update loop which can steal focus on page load; modify openTab to accept a
user-initiated flag (or the original event) and only call anchor.focus() when
that flag/event indicates a real user interaction (e.g., userInitiated === true
or event.isTrusted). Update callers: when wiring tab clicks pass true (or the
click event), and when invoking openTab on window load pass false (or null) so
focus is not set. Keep references: change function openTab(...), the
tabAnchors.forEach(...) block where anchor.focus() is called, and all places
that call openTab (click handler and window load).
- Add userInitiated parameter to openTab to prevent focus stealing on page load - Add null check for aria-controls attribute in handleKeyDown - Preserve series indicators in search (book/part/vol/chapter) for better matching
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
utils/tests.py (1)
292-390:⚠️ Potential issue | 🟡 MinorResolve PT009 lint findings in the new test class.
Static analysis flags repeated PT009 warnings across this block (e.g.,
assertIn/assertNotIn/assertNotEqual). Please align these assertions with the project’s lint configuration or explicitly scope-ignore PT009 for unittest-style Django tests.As per coding guidelines, "PR must pass linting according to AGENTS.md standards".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@utils/tests.py` around lines 292 - 390, The tests trigger repeated PT009 lint warnings due to many direct calls to self.assertIn/assertNotIn/assertNotEqual across test methods (e.g., test_normalize_name_preserves_part_indicators, test_normalize_name_removes_years, test_normalize_name_preserves_trailing_text_after_narrator, test_normalize_name_preserves_series_position_info); fix by either adding a scoped lint-ignore for PT009 on the test class (place the project's accepted ignore directive immediately above the class containing these test_* methods) or consolidate repetitive assertions into small loops/table-driven checks inside the same test methods to reduce duplication, ensuring the suppression or refactor references the class name and these test_* method names so the linter no longer raises PT009.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Around line 1-3: The call to event.preventDefault() in openTab(event, tabId,
userInitiated = false) is unsafe when openTab is invoked with a non-Event value;
guard the call by checking that event exists and has a preventDefault function
(e.g., if (event && typeof event.preventDefault === 'function')
event.preventDefault()), then proceed to update tab state and other logic;
update any internal callers that pass null/undefined accordingly and keep the
original default for userInitiated behavior.
- Around line 89-94: The current fallback derives defaultTab by munging
firstTabButton.id with replace("-tab","") which breaks if the id format differs;
update the logic in the block that sets defaultTab (the code using
firstTabButton and defaultTab and querySelector(".tab")) to prefer the button's
aria-controls value (use firstTabButton.getAttribute("aria-controls") and strip
any leading "#" if present) to compute the pane name, fall back to id parsing
only if aria-controls is missing, and finally default to "done" if neither
yields a valid name.
In `@utils/tests.py`:
- Around line 326-333: Add a unit test named something like
test_normalize_name_preserves_year_only_title that calls
self.tool.normalize_name("1984") and asserts the result is not empty (e.g.,
non-blank after strip()) and still contains the year token ("1984") to cover the
new preservation branch in normalize_name; place it alongside other
normalize_name tests in utils/tests.py and use the same test class and assertion
style (assertTrue/assertIn) as existing tests.
---
Duplicate comments:
In `@utils/tests.py`:
- Around line 292-390: The tests trigger repeated PT009 lint warnings due to
many direct calls to self.assertIn/assertNotIn/assertNotEqual across test
methods (e.g., test_normalize_name_preserves_part_indicators,
test_normalize_name_removes_years,
test_normalize_name_preserves_trailing_text_after_narrator,
test_normalize_name_preserves_series_position_info); fix by either adding a
scoped lint-ignore for PT009 on the test class (place the project's accepted
ignore directive immediately above the class containing these test_* methods) or
consolidate repetitive assertions into small loops/table-driven checks inside
the same test methods to reduce duplication, ensuring the suppression or
refactor references the class name and these test_* method names so the linter
no longer raises PT009.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
importer/templates/book_tabs.jsutils/search_tools.pyutils/tests.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.jsutils/tests.pyutils/search_tools.py
🧬 Code graph analysis (1)
utils/tests.py (1)
utils/search_tools.py (1)
normalize_name(61-105)
🪛 Ruff (0.15.2)
utils/tests.py
[warning] 292-292: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 293-293: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 294-294: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 295-295: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 300-300: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 301-301: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 302-302: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 303-303: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 308-308: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 309-309: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 310-310: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 315-315: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 316-316: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 321-321: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 322-322: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 323-323: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 324-324: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 329-329: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 330-330: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 331-331: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 332-332: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 337-337: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 338-338: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 339-339: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 344-344: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 345-345: Use a regular assert instead of unittest-style assertNotIn
Replace assertNotIn(...) with assert ...
(PT009)
[warning] 346-346: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 347-347: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 348-348: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 353-353: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 354-354: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 355-355: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 360-360: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 361-361: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 362-362: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 367-367: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 368-368: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 369-369: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 374-374: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 375-375: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 380-380: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 381-381: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 382-382: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 388-388: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 389-389: Use a regular assert instead of unittest-style assertIn
Replace assertIn(...) with assert ...
(PT009)
[warning] 390-390: Use a regular assert instead of unittest-style assertNotEqual
Replace assertNotEqual(...) with assert ...
(PT009)
🔇 Additional comments (2)
utils/search_tools.py (1)
93-97: Year-removal fallback is well implemented.Line 93 through Line 97 correctly preserve the pre-stripped value when year removal would empty the normalized name, which protects year-only titles from being erased.
importer/templates/book_tabs.js (1)
42-75: Keyboard tab navigation handling looks good.ArrowLeft/ArrowRight/Home/End behavior is implemented cleanly, and Line 67 prevents default scrolling side effects.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
importer/templates/book_tabs.js (1)
91-101:⚠️ Potential issue | 🟠 MajorFallback tab resolution still reads
aria-controlsfrom the wrong element.
document.querySelector(".tab")typically returns the tab container/list item, not the tab anchor. That makes the "preferaria-controls" branch unreliable and can still collapse to brittle id parsing.Proposed fix
- const firstTabButton = document.querySelector(".tab"); - if (firstTabButton) { - // Prefer aria-controls for pane name derivation - let ariaControls = firstTabButton.getAttribute("aria-controls"); + const firstTabButton = document.querySelector(".tab"); + const firstTabAnchor = document.querySelector('.tab a[role="tab"][aria-controls]'); + if (firstTabAnchor || firstTabButton) { + // Prefer aria-controls from the tab anchor for pane name derivation + let ariaControls = firstTabAnchor?.getAttribute("aria-controls"); if (ariaControls) { // Strip leading "#" if present defaultTab = ariaControls.replace(/^#/, ""); } else { // Fall back to id parsing - const parsed = firstTabButton.id.replace("-tab", ""); + const parsed = firstTabButton?.id?.replace(/-tab$/, ""); defaultTab = parsed || "done"; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@importer/templates/book_tabs.js` around lines 91 - 101, The code uses document.querySelector(".tab") (firstTabButton) and then reads aria-controls from that element which is often the tab container rather than the actual tab anchor; update the logic in the block that sets defaultTab so it first attempts to locate an element with an aria-controls attribute inside or on firstTabButton (e.g. check firstTabButton.getAttribute("aria-controls") and if absent try firstTabButton.querySelector('[aria-controls]') and use its attribute), then strip a leading "#" and fall back to parsing the anchor id (or the container id minus "-tab") only if no aria-controls is found; adjust references to firstTabButton and defaultTab accordingly so aria-controls is read from the correct element.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Around line 71-73: The tab ID read from attributes (e.g.,
nextTab.getAttribute('aria-controls') and the data-default/keyboard paths) may
include a leading '#', causing getElementById(tabId) in openTab to fail;
normalize the ID before calling openTab by stripping a leading '#' (e.g., remove
/^#/ from the string) so calls like openTab(..., tabId, true) always receive a
plain element id; update all call sites (the nextTab/aria-controls branch and
the keyboard/data-default branch) to perform this normalization and pass the
cleaned id to openTab.
---
Duplicate comments:
In `@importer/templates/book_tabs.js`:
- Around line 91-101: The code uses document.querySelector(".tab")
(firstTabButton) and then reads aria-controls from that element which is often
the tab container rather than the actual tab anchor; update the logic in the
block that sets defaultTab so it first attempts to locate an element with an
aria-controls attribute inside or on firstTabButton (e.g. check
firstTabButton.getAttribute("aria-controls") and if absent try
firstTabButton.querySelector('[aria-controls]') and use its attribute), then
strip a leading "#" and fall back to parsing the anchor id (or the container id
minus "-tab") only if no aria-controls is found; adjust references to
firstTabButton and defaultTab accordingly so aria-controls is read from the
correct element.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
importer/templates/book_tabs.jsutils/tests.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.jsutils/tests.py
🧬 Code graph analysis (1)
utils/tests.py (1)
utils/search_tools.py (1)
normalize_name(61-105)
🔇 Additional comments (8)
utils/tests.py (6)
11-11: LGTM!Import is correctly placed and necessary for the new test class.
282-296: LGTM!The test class setup is clean, and the
# ruff: noqa: PT009directive is appropriate since Django'sTestCaseuses unittest-style assertions. The first test correctly validates the "read by" pattern removal while preserving title words.
298-304: PR objectives state indicators should be removed, but tests verify they are preserved.The PR objectives describe "Added regex to remove part/volume/book/chapter indicators (e.g., 'Part 1 of 3', 'Volume 2')". However, these tests (and subsequent tests at lines 341-346, 357-376, 378-389, 391-397) assert that such indicators are preserved, which aligns with the actual
normalize_nameimplementation that has no such removal regex.Please clarify whether the intended behavior is preservation (as implemented/tested) or removal (as documented in PR objectives). If preservation is correct, update the PR description to avoid confusion.
306-339: LGTM!The year-related tests comprehensively cover:
- Years in parentheses (line 308)
- Standalone years within text (line 329)
- Year-only titles like "1984" where removal would produce empty result (lines 335-339)
These align well with the implementation's year-removal logic and the preservation guard.
319-355: LGTM!The "narrated by" test (lines 319-325) and trailing text preservation test (lines 348-355) correctly validate the narrator regex behavior. The regex
\w+(?:\s+\w+){0,2}captures 1-3 words after "read/narrated by", which means in "Great Book read by John Smith The Sequel", the pattern "read by John Smith The" is removed while "Sequel" is preserved.
357-397: LGTM!These tests provide comprehensive coverage for series indicator preservation:
- Book, chapter, part, and volume indicators with various numbering
- The
test_normalize_name_preserves_series_position_infotest (lines 391-397) adds good value by verifying that different book numbers produce distinct normalized results, which is essential for accurate series matching.importer/templates/book_tabs.js (2)
2-4: DefensivepreventDefaultguard is a good improvement.This safely supports both real DOM events and synthetic callers without crashing.
44-113: Add unit tests for keyboard/focus/default-tab logic in book_tabs.js.These are behavior-critical UI paths handling keyboard navigation (arrow keys, Home, End), focus management, and ARIA attributes. Add tests covering
openTab(),handleKeyDown(), and the tab initialization logic.Likely an incorrect or invalid review comment.
- Strip leading '#' from tab IDs in keyboard navigation (handleKeyDown) - Normalize data-default attribute to remove '#' prefix - Fix aria-controls lookup to search child anchor elements when not on container - Ensures getElementById always receives plain IDs without hash prefix Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Around line 16-27: Before clearing/hiding other panes, first query and
validate the target tab elements (tabElem via document.getElementById(tabId) and
tabButton via document.getElementById(`${tabId}-tab`)); if either is missing,
log a warning and return early so you don't leave the UI with no visible pane.
Move the element lookups and the existence checks for tabElem/tabButton to the
start of the routine, and only proceed to hide other panes / remove "is-active"
from siblings and then show tabElem and add "is-active" to tabButton when both
exist.
- Around line 44-117: Add unit/DOM tests for the new keyboard navigation and
default tab resolution: write tests that simulate keydown events on the
handleKeyDown handler (ArrowLeft, ArrowRight, Home, End) and assert openTab is
called with the expected tab id and wrap-around behavior; test cases should
include anchors with and without aria-controls to verify the console warning
path and correct extraction logic. Also add tests for the window load
initialization that set up a .tabs container with data-default, without
data-default, and missing .tabs to verify defaultTab resolution (data-default
value, first .tab's aria-controls, fallback to id.replace("-tab",""), and final
"done" fallback) and ensure openTab is invoked with the resolved id. Mock or spy
on openTab and ensure listeners are attached to '.tab a[role="tab"]' so keyboard
handling is wired.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
importer/templates/book_tabs.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.js
🔇 Additional comments (1)
importer/templates/book_tabs.js (1)
44-77: Keyboard navigation implementation is solid.Arrow/Home/End handling, wrap-around behavior, and roving tabindex synchronization look correct and materially improve keyboard accessibility.
| function handleKeyDown(event) { | ||
| const tabAnchors = Array.from(document.querySelectorAll('.tab a[role="tab"]')); | ||
| const currentIndex = tabAnchors.indexOf(document.activeElement); | ||
|
|
||
| if (currentIndex === -1 || tabAnchors.length === 0) return; | ||
|
|
||
| let nextIndex = currentIndex; | ||
|
|
||
| switch (event.key) { | ||
| case 'ArrowLeft': | ||
| nextIndex = currentIndex > 0 ? currentIndex - 1 : tabAnchors.length - 1; | ||
| break; | ||
| case 'ArrowRight': | ||
| nextIndex = currentIndex < tabAnchors.length - 1 ? currentIndex + 1 : 0; | ||
| break; | ||
| case 'Home': | ||
| nextIndex = 0; | ||
| break; | ||
| case 'End': | ||
| nextIndex = tabAnchors.length - 1; | ||
| break; | ||
| default: | ||
| return; | ||
| } | ||
|
|
||
| event.preventDefault(); | ||
| const nextTab = tabAnchors[nextIndex]; | ||
| const tabIdRaw = nextTab.getAttribute('aria-controls'); | ||
| if (tabIdRaw) { | ||
| const tabId = tabIdRaw.replace(/^#/, ""); | ||
| openTab({ preventDefault: () => {} }, tabId, true); | ||
| } else { | ||
| console.warn(`Tab anchor at index ${nextIndex} missing aria-controls attribute`); | ||
| } | ||
| } | ||
|
|
||
| window.addEventListener('load', function () { | ||
| const defaultTab = document.querySelector(".tabs").dataset.default | ||
| openTab(defaultTab); | ||
| }); No newline at end of file | ||
| const tabsContainer = document.querySelector(".tabs"); | ||
| let defaultTab; | ||
|
|
||
| if (tabsContainer && tabsContainer.dataset.default) { | ||
| defaultTab = tabsContainer.dataset.default.replace(/^#/, ""); | ||
| } else { | ||
| if (!tabsContainer) { | ||
| console.warn(".tabs container not found, using fallback tab"); | ||
| } else { | ||
| console.warn("data-default attribute missing or empty, using fallback tab"); | ||
| } | ||
| const firstTabButton = document.querySelector(".tab"); | ||
| if (firstTabButton) { | ||
| let ariaControls = firstTabButton.getAttribute("aria-controls"); | ||
| if (!ariaControls) { | ||
| const anchorWithControls = firstTabButton.querySelector('[aria-controls]'); | ||
| if (anchorWithControls) { | ||
| ariaControls = anchorWithControls.getAttribute("aria-controls"); | ||
| } | ||
| } | ||
| if (ariaControls) { | ||
| defaultTab = ariaControls.replace(/^#/, ""); | ||
| } else { | ||
| const parsed = firstTabButton.id.replace("-tab", ""); | ||
| defaultTab = parsed || "done"; | ||
| } | ||
| } else { | ||
| defaultTab = "done"; | ||
| } | ||
| } | ||
| openTab({ preventDefault: () => {} }, defaultTab, false); | ||
|
|
||
| const tabAnchors = document.querySelectorAll('.tab a[role="tab"]'); | ||
| tabAnchors.forEach(anchor => { | ||
| anchor.addEventListener('keydown', handleKeyDown); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify test presence and references for book tab behavior.
echo "== AGENTS / standards files =="
fd --type f AGENTS.md
echo
echo "== package.json / test configuration =="
fd --type f package.json
echo
echo "== Candidate JS/TS test files =="
fd --type f -g '*{test,spec}*.{js,jsx,ts,tsx}'
echo
echo "== Test references to tab behavior =="
rg -n -C2 --glob '*{test,spec}*.{js,jsx,ts,tsx}' \
'openTab|handleKeyDown|ArrowLeft|ArrowRight|Home|End|aria-selected|tabindex|data-default' || echo "No matches found"
echo
echo "== Check importer directory structure =="
fd --type f . importer/ | head -30Repository: djdembeck/bragibooks
Length of output: 1260
🏁 Script executed:
#!/bin/bash
# Check existing test file content and look for AGENTS documentation
echo "== Content of existing test file =="
cat -n importer/templates/importer.test.js
echo
echo "== Search for AGENTS in all files =="
rg -i 'AGENTS' --type-list | head -5
rg -i 'AGENTS' . 2>/dev/null || echo "No AGENTS references found"
echo
echo "== Search for standards or coverage documentation =="
fd --type f \( -name '*AGENT*' -o -name '*standard*' -o -name '*test*config*' -o -name '*jest*' \)
echo
echo "== Content of package.json (relevant sections) =="
cat package.json | grep -A 20 -B 2 '"test"\|"jest"\|"coverage"' || cat package.jsonRepository: djdembeck/bragibooks
Length of output: 34574
Add tests for keyboard navigation and default tab initialization logic.
No test file exists for book_tabs.js. The new code introduces substantial behavior changes (handleKeyDown function, keyboard navigation for ArrowLeft/ArrowRight/Home/End keys, and complex fallback logic for determining the default tab), yet there is no corresponding test coverage. Tests must cover at minimum:
- Keyboard navigation (ArrowLeft, ArrowRight, Home, End key handling)
- Tab wrapping behavior (wrap-around navigation)
- Default tab resolution with fallback logic
- aria-controls attribute handling
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@importer/templates/book_tabs.js` around lines 44 - 117, Add unit/DOM tests
for the new keyboard navigation and default tab resolution: write tests that
simulate keydown events on the handleKeyDown handler (ArrowLeft, ArrowRight,
Home, End) and assert openTab is called with the expected tab id and wrap-around
behavior; test cases should include anchors with and without aria-controls to
verify the console warning path and correct extraction logic. Also add tests for
the window load initialization that set up a .tabs container with data-default,
without data-default, and missing .tabs to verify defaultTab resolution
(data-default value, first .tab's aria-controls, fallback to
id.replace("-tab",""), and final "done" fallback) and ensure openTab is invoked
with the resolved id. Mock or spy on openTab and ensure listeners are attached
to '.tab a[role="tab"]' so keyboard handling is wired.
…hensive tests - Move element lookups (tabElem, tabButton) before clearing/hiding panes - Add early return if either element is missing to prevent UI with no visible pane - Add browser/Node.js compatibility check for window object - Export functions for testing - Add 19 unit tests for openTab, handleKeyDown, and default tab resolution - Fix existing failing test in importer.test.js (pre-loader element)
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
importer/templates/book_tabs.js (1)
1-8:⚠️ Potential issue | 🟠 MajorNormalize tab IDs inside
openTabbefore both lookup and ARIA comparison.
handleKeyDownstrips#, butopenTabstill compares rawaria-controlstotabId. Witharia-controls="#done", the pane activates but ARIA state/tabindex can remain incorrect.Normalization fix
function openTab(event, tabId, userInitiated = false) { + const normalizedTabId = String(tabId ?? "").trim().replace(/^#/, ""); if (event && typeof event.preventDefault === 'function') { event.preventDefault(); } // Validate target tab elements before clearing/hiding other panes - const tabElem = document.getElementById(tabId); - const tabButton = document.getElementById(`${tabId}-tab`); + const tabElem = document.getElementById(normalizedTabId); + const tabButton = document.getElementById(`${normalizedTabId}-tab`); @@ - if (!tabElem) { - console.warn(`Tab element with id '${tabId}' not found`); + if (!tabElem) { + console.warn(`Tab element with id '${normalizedTabId}' not found`); return; } - if (!tabButton) { - console.warn(`Tab button with id '${tabId}-tab' not found`); + if (!tabButton) { + console.warn(`Tab button with id '${normalizedTabId}-tab' not found`); return; } @@ const tabAnchors = document.querySelectorAll('.tab a[role="tab"]'); tabAnchors.forEach(anchor => { - if (anchor.getAttribute('aria-controls') === tabId) { + const controlsId = (anchor.getAttribute('aria-controls') || "").replace(/^#/, ""); + if (controlsId === normalizedTabId) { anchor.setAttribute('aria-selected', 'true'); anchor.setAttribute('tabindex', '0'); if (userInitiated) { anchor.focus(); }Also applies to: 31-33, 75-76
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@importer/templates/book_tabs.js` around lines 1 - 8, Normalize the incoming tabId (strip any leading '#' characters) at the start of openTab so lookups and ARIA comparisons use a consistent id; update the code in openTab to set const normalizedId = tabId && tabId.toString().replace(/^#/, '') and then use normalizedId for document.getElementById calls (replace tabId with normalizedId for tabElem and tabButton) and when comparing against element.getAttribute('aria-controls')/setting aria-hidden/aria-selected/tabindex; apply the same normalization wherever the code compares or uses aria-controls/tabId (e.g., the blocks that reference aria-controls and set aria-hidden/aria-selected) so IDs with leading '#' behave correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.test.js`:
- Around line 716-719: The tests stub global.openTab and collect openTabCalls
but handleKeyDown invokes the module-scoped openTab (not the global), so the
stub never intercepts calls and assertions can false-pass; update the tests to
spy or stub the actual module export used by handleKeyDown (the openTab function
referenced in the module under test) or refactor the module to export/openTab so
tests can replace it, then assert against that spy (replace references to
global.openTab and openTabCalls with a spy on the module's openTab used by
handleKeyDown and update assertions accordingly).
- Around line 834-1078: Tests duplicate the defaultTab selection logic instead
of invoking the real runtime initialization; update each spec to load or require
the module that sets up the window load handler (book_tabs.js) and trigger the
actual handler instead of recomputing defaultTab inline. Specifically, replace
the inline defaultTab computation with: require/import the module (or call its
exported initializer, e.g., initializeTabs or the function that registers
window.addEventListener('load')), then simulate the load event or call the
initializer directly, and assert that global.openTab was invoked with the
expected tab id (e.g., 'processing', 'error', 'done') — reference symbols: the
module book_tabs.js, the window load handler/initializeTabs, and
global.openTab/openTab to locate code to change. Ensure you restore
global.document and global.openTab in finally blocks as before.
- Around line 766-793: The test temporarily replaces console.warn to capture
warnings but currently restores it inside the try block, so if an assertion
throws the mock leaks; update the test around handleKeyDown so that the original
console.warn (stored in originalWarn) is restored inside the existing finally
block (and likewise restore global.document there) instead of inside the try;
locate the test case that calls handleKeyDown and uses originalWarn and
originalDoc and move the cleanup lines (console.warn = originalWarn and
global.document = originalDoc) into the finally block to ensure safe teardown.
In `@importer/templates/importer.test.js`:
- Around line 257-263: The tests still reference the old "loading-overlay" id so
they don't exercise the updated hideLoadingOverlay path; update the remaining
two test cases in importer.test.js to use the new "pre-loader" element like the
first case (modify their MockDocument.setElement calls and any
selectors/assertions that look for 'loading-overlay' to 'pre-loader') so all
three tests validate hideLoadingOverlay against the migrated element and its
classList behavior.
---
Duplicate comments:
In `@importer/templates/book_tabs.js`:
- Around line 1-8: Normalize the incoming tabId (strip any leading '#'
characters) at the start of openTab so lookups and ARIA comparisons use a
consistent id; update the code in openTab to set const normalizedId = tabId &&
tabId.toString().replace(/^#/, '') and then use normalizedId for
document.getElementById calls (replace tabId with normalizedId for tabElem and
tabButton) and when comparing against
element.getAttribute('aria-controls')/setting
aria-hidden/aria-selected/tabindex; apply the same normalization wherever the
code compares or uses aria-controls/tabId (e.g., the blocks that reference
aria-controls and set aria-hidden/aria-selected) so IDs with leading '#' behave
correctly.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
importer/templates/book_tabs.jsimporter/templates/book_tabs.test.jsimporter/templates/importer.test.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.test.jsimporter/templates/importer.test.jsimporter/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.test.jsimporter/templates/importer.test.jsimporter/templates/book_tabs.js
🧠 Learnings (1)
📚 Learning: 2026-02-15T07:14:12.686Z
Learnt from: CR
Repo: djdembeck/bragibooks PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-02-15T07:14:12.686Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
Applied to files:
importer/templates/book_tabs.js
🧬 Code graph analysis (2)
importer/templates/book_tabs.test.js (2)
importer/templates/importer.js (1)
id(335-335)importer/templates/book_tabs.js (8)
tabButton(8-8)tabsContainer(85-85)tabId(75-75)defaultTab(86-86)firstTabButton(96-96)ariaControls(98-98)anchorWithControls(100-100)parsed(108-108)
importer/templates/importer.test.js (1)
importer/templates/importer.js (1)
preLoader(143-143)
🪛 GitHub Check: CodeFactor
importer/templates/book_tabs.test.js
[notice] 161-192: importer/templates/book_tabs.test.js#L161-L192
Complex Method
[notice] 77-108: importer/templates/book_tabs.test.js#L77-L108
Complex Method
| it('should add hidden class to pre-loader when element exists', () => { | ||
| const mockDoc = new MockDocument(); | ||
| const loadingOverlay = new MockElement(); | ||
| mockDoc.setElement('loading-overlay', loadingOverlay); | ||
| const preLoader = new MockElement(); | ||
| mockDoc.setElement('pre-loader', preLoader); | ||
| hideLoadingOverlay(mockDoc); | ||
| assert.strictEqual(loadingOverlay.style.display, 'none'); | ||
| assert.strictEqual(preLoader.classList.contains('hidden'), true); | ||
| }); |
There was a problem hiding this comment.
Complete the pre-loader migration in this test block.
This hunk updates only the first case; the remaining two tests still target loading-overlay, so they no longer validate the active hideLoadingOverlay path.
Suggested test alignment
- it('should not throw error when loading-overlay element does not exist', () => {
+ it('should not throw error when pre-loader element does not exist', () => {
const mockDoc = new MockDocument();
assert.doesNotThrow(() => hideLoadingOverlay(mockDoc));
});
- it('should not throw error when element has no style property', () => {
+ it('should not throw error when pre-loader element has no classList', () => {
const mockDoc = new MockDocument();
- mockDoc.setElement('loading-overlay', {});
+ mockDoc.setElement('pre-loader', {});
assert.doesNotThrow(() => hideLoadingOverlay(mockDoc));
});As per coding guidelines: "Unit tests are included with proper coverage".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@importer/templates/importer.test.js` around lines 257 - 263, The tests still
reference the old "loading-overlay" id so they don't exercise the updated
hideLoadingOverlay path; update the remaining two test cases in importer.test.js
to use the new "pre-loader" element like the first case (modify their
MockDocument.setElement calls and any selectors/assertions that look for
'loading-overlay' to 'pre-loader') so all three tests validate
hideLoadingOverlay against the migrated element and its classList behavior.
- Normalize tabId by stripping leading '#' in openTab for consistent lookups - Add initializeTabs export to allow tests to invoke actual runtime init - Fix tests: remove ineffective global.openTab stubs, verify DOM state instead - Fix test cleanup: move console.warn restoration to finally blocks - Fix importer.test: update to use 'pre-loader' element instead of loading-overlay
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Around line 7-19: Guard against blank or whitespace-only tab IDs by trimming
and validating normalizedId before doing DOM lookups: after computing
normalizedId (from tabId), run normalizedId = normalizedId.trim() and if the
result is empty (""), log a clear warning and return early instead of calling
document.getElementById; then continue to resolve tabElem and tabButton as
before. This change touches the normalizedId, tabElem and tabButton checks in
book_tabs.js.
- Around line 120-123: The initializeTabs function currently attaches
handleKeyDown to every tab anchor each time it runs, causing duplicate handlers;
make the binding idempotent by ensuring you don't re-add the listener if it's
already bound on the same element—e.g., in initializeTabs (where tabAnchors and
handleKeyDown are used) either remove any existing listener before adding (call
removeEventListener(handleKeyDown) then addEventListener) or set/check a marker
on the anchor (like anchor.dataset.keydownBound) and only add the event listener
and mark it when not already marked; update initializeTabs to use one of these
approaches so repeated initializations do not register duplicate keydown
handlers.
In `@importer/templates/book_tabs.test.js`:
- Around line 878-883: The test must also verify that initializeTabs wired the
keydown listener; after calling initializeTabs(mockDoc) add an assertion that
mockDoc.addEventListener was invoked with the 'keydown' event and a function
handler (e.g., assert(mockDoc.addEventListener.calledWith('keydown',
sinon.match.func))). This ensures initializeTabs's listener registration (called
on mockDoc in the test) is covered in addition to the existing
tab-selection/display assertions.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
importer/templates/book_tabs.jsimporter/templates/book_tabs.test.jsimporter/templates/importer.test.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/importer.test.jsimporter/templates/book_tabs.jsimporter/templates/book_tabs.test.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/importer.test.jsimporter/templates/book_tabs.jsimporter/templates/book_tabs.test.js
🧠 Learnings (1)
📚 Learning: 2026-02-15T07:14:12.686Z
Learnt from: CR
Repo: djdembeck/bragibooks PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-02-15T07:14:12.686Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
Applied to files:
importer/templates/book_tabs.js
🧬 Code graph analysis (2)
importer/templates/importer.test.js (1)
importer/templates/importer.js (1)
preLoader(143-143)
importer/templates/book_tabs.test.js (1)
importer/templates/book_tabs.js (3)
tabButton(11-11)tabsContainer(88-88)defaultTab(89-89)
🪛 GitHub Check: CodeFactor
importer/templates/book_tabs.test.js
[notice] 161-192: importer/templates/book_tabs.test.js#L161-L192
Complex Method
[notice] 77-108: importer/templates/book_tabs.test.js#L77-L108
Complex Method
🔇 Additional comments (2)
importer/templates/importer.test.js (1)
257-263: Pre-loader test migration looks correct.These updates now align with the runtime selector (
pre-loader) and validate the current hidden-class behavior cleanly.Also applies to: 270-274
importer/templates/book_tabs.js (1)
51-85: Keyboard navigation behavior is implemented well.Arrow/Home/End routing and wrap-around handling are clean and readable.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
importer/templates/book_tabs.js (1)
7-7:⚠️ Potential issue | 🟡 MinorNormalize by trimming before stripping
#to avoid whitespace-prefixed IDs failing lookup.Inputs like
'#processing'currently normalize to'#processing', which then missesgetElementById. Applytrim()beforereplace(/^#/, '')consistently.♻️ Suggested normalization hardening
- const normalizedId = tabId && tabId.toString().replace(/^#/, '').trim(); + const normalizedId = String(tabId ?? '').trim().replace(/^#/, ''); @@ - const tabId = tabIdRaw.replace(/^#/, ""); + const tabId = tabIdRaw.trim().replace(/^#/, ""); @@ - defaultTab = tabsContainer.dataset.default.replace(/^#/, ""); + defaultTab = tabsContainer.dataset.default.trim().replace(/^#/, ""); @@ - defaultTab = ariaControls.replace(/^#/, ""); + defaultTab = ariaControls.trim().replace(/^#/, "");Also applies to: 86-87, 98-99, 115-116
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@importer/templates/book_tabs.js` at line 7, The normalization currently does tabId.toString().replace(/^#/, '').trim(), which will fail for inputs with leading whitespace like ' `#processing`'; change each occurrence (e.g., the normalizedId assignment using tabId, and the similar normalizations around lines referenced) to trim before stripping the leading hash: use tabId && tabId.toString().trim().replace(/^#/, '') so leading/trailing spaces are removed prior to the /^#/ replace; update all similar instances (the other normalizedId/normalizedTabId expressions) to the same ordering.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.test.js`:
- Around line 137-140: The mock DOM's setElement method updates this.elements
but the test's querySelectorAll('.tab') / querySelectorAll('.tab-pane') only
iterate this._mockElements, so many elements added via setElement are never
returned and tab-reset logic in openTab() is not exercised; fix by making
setElement also register the element in the mock collection used by
querySelectorAll (or alternatively update querySelectorAll to read from
this.elements), ensuring calls to setElement(...) populate the same backing
store that querySelectorAll('.tab') and querySelectorAll('.tab-pane') use so
openTab() clearing/hiding loops run against the correct nodes.
---
Duplicate comments:
In `@importer/templates/book_tabs.js`:
- Line 7: The normalization currently does tabId.toString().replace(/^#/,
'').trim(), which will fail for inputs with leading whitespace like '
`#processing`'; change each occurrence (e.g., the normalizedId assignment using
tabId, and the similar normalizations around lines referenced) to trim before
stripping the leading hash: use tabId && tabId.toString().trim().replace(/^#/,
'') so leading/trailing spaces are removed prior to the /^#/ replace; update all
similar instances (the other normalizedId/normalizedTabId expressions) to the
same ordering.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
importer/templates/book_tabs.jsimporter/templates/book_tabs.test.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.jsimporter/templates/book_tabs.test.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.jsimporter/templates/book_tabs.test.js
🧠 Learnings (1)
📚 Learning: 2026-02-15T07:14:12.686Z
Learnt from: CR
Repo: djdembeck/bragibooks PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-02-15T07:14:12.686Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
Applied to files:
importer/templates/book_tabs.js
🪛 GitHub Check: CodeFactor
importer/templates/book_tabs.test.js
[notice] 161-192: importer/templates/book_tabs.test.js#L161-L192
Complex Method
[notice] 77-108: importer/templates/book_tabs.test.js#L77-L108
Complex Method
🔇 Additional comments (2)
importer/templates/book_tabs.test.js (1)
783-795: Cleanup infinallyis correctly preventing cross-test leakage.Good restoration of both
global.documentandconsole.warninfinally.importer/templates/book_tabs.js (1)
15-25: Early target validation before clearing UI state is solid.Validating pane/button existence up front avoids blanking the interface on invalid tab targets.
- Fix MockDocument.setElement to sync elements with _mockElements for querySelectorAll - Fix whitespace normalization order (trim before stripping hash) in tab ID processing - All 19 tests passing
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Around line 97-99: The code sets defaultTab from tabsContainer.dataset.default
without checking the normalized value, so whitespace-only or "#" becomes empty
and causes openTab (function openTab) to return early; update the logic that
sets defaultTab (the block using tabsContainer.dataset.default and variable
defaultTab) to trim/strip the leading '#' and then only assign or use defaultTab
if the normalized value is non-empty, or alternatively guard the call site that
invokes openTab so it only calls openTab(defaultTab) when defaultTab is a
non-empty string; ensure this check is applied wherever defaultTab is used to
activate the initial tab.
- Around line 93-124: initializeTabs(doc) accepts an injected document but still
calls openTab which uses the global document, breaking isolation; update the
code so openTab accepts a document parameter (e.g., openTab(event, tabId,
updateHistory, doc)) or provide a wrapper that binds the injected doc, then
change the call in initializeTabs from openTab({preventDefault:()=>{}},
defaultTab, false) to pass the injected doc (e.g.,
openTab({preventDefault:()=>{}}, defaultTab, false, doc) or use the binder).
Modify the openTab function signature and all its callers (and any code inside
openTab that references global document) to use the passed doc instead of the
global document to ensure proper doc-scoped behavior.
In `@importer/templates/book_tabs.test.js`:
- Around line 77-108: The mock querySelectorAll implementations (in
MockElement.querySelectorAll and MockDocument.querySelectorAll) duplicate
selector-branching for selectors like '.tab', '.tab-pane', '.tab a[role="tab"]'
and '.tabs'; extract the shared logic into a helper function (e.g.,
buildQuerySelectorAllResults(selector, rootChildren)) and call it from both
querySelectorAll methods so both classes delegate to the single helper, keeping
behavior identical while removing duplicated loops and conditionals.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
importer/templates/book_tabs.jsimporter/templates/book_tabs.test.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.test.jsimporter/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.test.jsimporter/templates/book_tabs.js
🧠 Learnings (1)
📚 Learning: 2026-02-15T07:14:12.686Z
Learnt from: CR
Repo: djdembeck/bragibooks PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-02-15T07:14:12.686Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
Applied to files:
importer/templates/book_tabs.js
🧬 Code graph analysis (1)
importer/templates/book_tabs.test.js (1)
importer/templates/book_tabs.js (3)
tabButton(17-17)tabsContainer(94-94)defaultTab(95-95)
🪛 GitHub Check: CodeFactor
importer/templates/book_tabs.test.js
[notice] 77-108: importer/templates/book_tabs.test.js#L77-L108
Complex Method
[notice] 165-196: importer/templates/book_tabs.test.js#L165-L196
Complex Method
🔇 Additional comments (2)
importer/templates/book_tabs.js (1)
57-91: Keyboard navigation logic is solid.ArrowLeft/ArrowRight/Home/End handling, wrap behavior, and
aria-controlsnormalization are implemented cleanly here.importer/templates/book_tabs.test.js (1)
342-836: Great test coverage for the new tab behavior.The suite exercises keyboard navigation, warnings, hash-normalization, and initialization fallbacks thoroughly.
Also applies to: 838-1018
…st isolation - Add doc parameter to openTab function with default document - Add doc parameter to handleKeyDown function - Guard against blank/whitespace-only data-default values - Extract shared querySelectorAll logic into buildQuerySelectorAllResults helper
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Around line 94-106: The code can emit two warnings when
tabsContainer.dataset.default normalizes to an empty string; fix by preventing
the outer fallback from running when the inner guard already handled the
normalized-empty case—e.g., change the outer "if (!defaultTab) { ..." to "else
if (!defaultTab) { ..." or otherwise short-circuit after the inner console.warn
so only one warning is logged; update the logic around the tabsContainer and
defaultTab checks to ensure a single, clear warning path.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
importer/templates/book_tabs.jsimporter/templates/book_tabs.test.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.jsimporter/templates/book_tabs.test.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.jsimporter/templates/book_tabs.test.js
🧠 Learnings (1)
📚 Learning: 2026-02-15T07:14:12.686Z
Learnt from: CR
Repo: djdembeck/bragibooks PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-02-15T07:14:12.686Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
Applied to files:
importer/templates/book_tabs.js
🧬 Code graph analysis (1)
importer/templates/book_tabs.test.js (1)
importer/templates/book_tabs.js (3)
tabButton(14-14)tabsContainer(91-91)defaultTab(92-92)
🪛 GitHub Check: CodeFactor
importer/templates/book_tabs.test.js
[notice] 5-36: importer/templates/book_tabs.test.js#L5-L36
Complex Method
🔇 Additional comments (10)
importer/templates/book_tabs.test.js (6)
1-36: Well-structured shared helper for selector logic.The
buildQuerySelectorAllResultshelper effectively consolidates duplicated selector-branching that was previously in bothMockElement.querySelectorAllandMockDocument.querySelectorAll. This addresses the earlier consolidation suggestion.The static analysis flagging this as "Complex Method" is acceptable given the tradeoff: the complexity is inherent to selector matching, and centralizing it reduces maintenance overhead and potential inconsistencies.
141-148: Mock selector coverage issue addressed.The
setElementmethod now correctly registers elements in boththis.elements(forgetElementById) andthis._mockElements(forquerySelectorAll), ensuring thatopenTab()'s clearing/hiding loops are properly exercised against all registered nodes.
176-315: ComprehensiveopenTabtest coverage.The test suite covers:
- Successful tab activation with ARIA attribute updates
- Early return behavior when tab element or button is missing
- Conditional focus based on
userInitiatedflagThe tests properly verify that guarded updates prevent partial UI state changes when elements are missing.
747-775: Console.warn cleanup now correctly in finally block.The
console.warnrestoration has been moved to thefinallyblock (line 773), ensuring cleanup occurs even if assertions fail. This prevents mock leakage into subsequent tests.
857-864: Keydown listener wiring now verified.The test now includes assertions for keydown listener registration on tab anchors (lines 862-863), ensuring
initializeTabsproperly wires event handling. This addresses the earlier coverage gap.
813-993: Initialization tests now exercise actual runtime behavior.The tests correctly call
initializeTabs(mockDoc)directly rather than duplicating the default tab selection logic. This ensures the actual initialization code path is tested, catching any regressions in the production wiring.The fallback chain is well-tested:
data-defaultattribute on.tabsaria-controlson first.tab- Nested anchor's
aria-controls- ID-based parsing with
-tabsuffix removal- Final
"done"fallbackimporter/templates/book_tabs.js (4)
1-52:openTabimplementation is well-guarded.The function correctly:
- Guards
event.preventDefault()against non-Event objects (lines 2-4)- Normalizes and validates
tabIdbefore any DOM mutations (lines 6-22)- Validates both
tabElemandtabButtonexist before clearing UI state, preventing a broken UI when IDs are invalid- Uses the injected
docparameter consistently for testability
54-88: Keyboard navigation implementation is solid.The
handleKeyDownfunction properly:
- Handles ArrowLeft/Right with wrap-around navigation
- Supports Home/End keys for first/last tab access
- Calls
preventDefault()only after confirming a handled key (line 79)- Normalizes
aria-controlsvalues and warns when missing
128-134: Idempotent keydown binding correctly implemented.The
dataset.keydownBoundmarker prevents duplicate event handlers from being attached ifinitializeTabsruns multiple times. This addresses the earlier concern about repeated initializations causing duplicate tab transitions.
139-149: Browser detection and exports are correct.The
typeof window !== 'undefined'check properly gates browser-only initialization, and the CommonJS exports enable comprehensive testing without side effects during Node.js test runs.
There was a problem hiding this comment.
♻️ Duplicate comments (1)
importer/templates/book_tabs.js (1)
94-125:⚠️ Potential issue | 🟠 MajorFallback is skipped when
data-defaultnormalizes to empty.At Line 94, a truthy
data-defaultenters the first branch, but if normalization at Line 95 yields""(e.g.," "or"#"), Line 97 only warns and theelse iffallback path is never executed. Then Line 125 callsopenTabwith an empty ID, leaving no tab activated.💡 Suggested fix
- if (tabsContainer && tabsContainer.dataset.default) { - defaultTab = tabsContainer.dataset.default.trim().replace(/^#/, ""); - // Guard against blank or whitespace-only values after normalization - if (!defaultTab) { - console.warn("data-default normalized to empty, using fallback tab"); - } - } else if (!defaultTab) { + const normalizedDefault = tabsContainer?.dataset?.default?.trim().replace(/^#/, ""); + if (normalizedDefault) { + defaultTab = normalizedDefault; + } else { if (!tabsContainer) { console.warn(".tabs container not found, using fallback tab"); + } else if (tabsContainer.dataset.default) { + console.warn("data-default normalized to empty, using fallback tab"); } else { - console.warn("data-default attribute missing or empty, using fallback tab"); + console.warn("data-default attribute missing, using fallback tab"); } const firstTabButton = doc.querySelector(".tab"); if (firstTabButton) { @@ } else { defaultTab = "done"; } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@importer/templates/book_tabs.js` around lines 94 - 125, The code allows a truthy tabsContainer.dataset.default to be normalized to an empty string and then only logs a warning instead of falling back, which leads openTab(defaultTab) to be called with an empty id; update the logic in the block handling tabsContainer.dataset.default (and/or the surrounding defaultTab initialization) so that after normalizing (defaultTab = tabsContainer.dataset.default.trim().replace(/^#/, "")) you treat an empty result the same as the missing-case: perform the fallback resolution used in the else-if branch (inspect doc.querySelector(".tab"), read aria-controls from the button or nested anchor, strip "-tab" from id or use "done") or refactor that fallback into a helper and call it from both places, ensuring openTab({preventDefault:()=>{}}, defaultTab, false, doc) always receives a non-empty valid tab id; reference symbols: tabsContainer, defaultTab, doc, firstTabButton, openTab.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@importer/templates/book_tabs.js`:
- Around line 94-125: The code allows a truthy tabsContainer.dataset.default to
be normalized to an empty string and then only logs a warning instead of falling
back, which leads openTab(defaultTab) to be called with an empty id; update the
logic in the block handling tabsContainer.dataset.default (and/or the
surrounding defaultTab initialization) so that after normalizing (defaultTab =
tabsContainer.dataset.default.trim().replace(/^#/, "")) you treat an empty
result the same as the missing-case: perform the fallback resolution used in the
else-if branch (inspect doc.querySelector(".tab"), read aria-controls from the
button or nested anchor, strip "-tab" from id or use "done") or refactor that
fallback into a helper and call it from both places, ensuring
openTab({preventDefault:()=>{}}, defaultTab, false, doc) always receives a
non-empty valid tab id; reference symbols: tabsContainer, defaultTab, doc,
firstTabButton, openTab.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
importer/templates/book_tabs.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.js
🧠 Learnings (1)
📚 Learning: 2026-02-15T07:14:12.686Z
Learnt from: CR
Repo: djdembeck/bragibooks PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-02-15T07:14:12.686Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
Applied to files:
importer/templates/book_tabs.js
🔇 Additional comments (3)
importer/templates/book_tabs.js (3)
1-52:openTabhardening looks good.Nice defensive flow here: ID normalization, early target validation before UI reset, and ARIA/tabindex synchronization are all correctly structured.
54-88: Keyboard navigation handling is implemented cleanly.The Arrow/Home/End logic, wrap behavior, and graceful warning path for missing
aria-controlsare solid.
127-148: Initialization wiring/export surface looks good.Idempotent keydown binding and explicit browser/CommonJS wiring are clean and test-friendly.
…empty data-default
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Around line 114-130: The code currently trusts a non-empty data-default value
and passes it to openTab, which can be invalid; update the initialization to
verify that defaultTab corresponds to an actual tab element before first
activation: after computing defaultTab from tabsContainer.dataset.default, try
to locate the matching tab element (using the same selector logic used by
openTab or the tab lookup routine), and if no element is found, log a warning
and call resolveDefaultTab(tabsContainer, doc) to obtain a fallback; then call
openTab with the validated/fallback defaultTab. Ensure you reference and update
the logic around tabsContainer, defaultTab, resolveDefaultTab, and the openTab
invocation so invalid data-default values are handled consistently.
- Around line 100-105: The resolveDefaultTab function can return an empty string
when ariaControls is just whitespace or "#" — update resolveDefaultTab to trim
and strip the leading "#" from ariaControls, then check if the resulting string
is non-empty; if empty, fall back to parsing firstTabButton.id
(firstTabButton.id.replace("-tab", "")) and finally default to "done" before
returning so openTab is never called with an empty id.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
importer/templates/book_tabs.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.js
🧠 Learnings (1)
📚 Learning: 2026-02-15T07:14:12.686Z
Learnt from: CR
Repo: djdembeck/bragibooks PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-02-15T07:14:12.686Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
Applied to files:
importer/templates/book_tabs.js
🔇 Additional comments (1)
importer/templates/book_tabs.js (1)
1-52: Solid defensive/tab-accessibility update inopenTab.The early validation before state clearing plus ARIA/tabindex synchronization is a strong improvement and avoids the previous “blank UI” failure mode.
…trols Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@importer/templates/book_tabs.js`:
- Line 79: The exported handleKeyDown currently calls event.preventDefault()
unconditionally which can throw if invoked from tests or non-DOM paths; update
handleKeyDown to first check that event is truthy and has a callable
preventDefault (e.g., if (event && typeof event.preventDefault === 'function')
event.preventDefault();) before calling it, and ensure the rest of the
navigation logic (inside handleKeyDown) still executes when event is absent or
synthetic; reference the handleKeyDown function to locate where to add this
defensive guard and consider providing a safe default for the event parameter if
helpful.
ℹ️ Review info
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (1)
importer/templates/book_tabs.js
📜 Review details
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (Custom checks)
**/*.{ts,tsx,js,jsx}: PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
PR must pass linting according to AGENTS.md standards
Files:
importer/templates/book_tabs.js
**/*
⚙️ CodeRabbit configuration file
**/*: Please review focusing on:
- Code quality and consistency with existing patterns
- Adherence to TypeScript best practices
- Test coverage for any new code
- Security implications of changes
- Performance considerations
- Documentation updates where needed
This project follows the AGENTS.md repository standards. Please ensure:
- Conventional commit format is followed
- Unit tests are included with proper coverage
- No breaking changes are introduced without proper discussion
Files:
importer/templates/book_tabs.js
🧠 Learnings (1)
📚 Learning: 2026-02-15T07:14:12.686Z
Learnt from: CR
Repo: djdembeck/bragibooks PR: 0
File: coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt:0-0
Timestamp: 2026-02-15T07:14:12.686Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : PR must follow all standards in AGENTS.md including test coverage thresholds (85%+ statements/lines/functions, 80%+ branches)
Applied to files:
importer/templates/book_tabs.js
🔇 Additional comments (3)
importer/templates/book_tabs.js (3)
1-52: Strong defensiveopenTabflow with correct pre-validation before UI mutation.This is a solid fix: normalization + early existence checks prevent clearing state on invalid targets, and ARIA/tabindex updates are now consistent with activation.
90-110:resolveDefaultTabfallback chain is robust and clear.Good normalization and fallback ordering (
aria-controls→ parsed id →"done"), including protection against normalized-empty values.
112-162: Initialization and export surface look clean and test-friendly.
initializeTabs(doc)with scoped document access plus guarded browser-load bootstrap and CommonJS exports is a good maintainability/testability improvement.
Summary
Improves the
normalize_namemethod inSearchToolto clean up search strings more effectively, resulting in better ASIN auto-search results for audiobooks.Changes
utils/search_tools.pyutils/tests.pyTestSearchToolNormalizeNametest class with 4 test methods covering all new patternsTest Results
All tests pass:
Related Issue
#159
Summary by CodeRabbit
New Features
Tests