Skip to content

Conversation

@rtibbles
Copy link
Member

Summary

Implements no-undefined-translator-keys rule that prevents destructuring undefined keys from createTranslator objects. Validates both same-file and cross-file imports using AST parsing and Node.js module resolution.

References

No open issue, but observed as a problem during recent string updates for release

Reviewer guidance

🤖 This was created by Claude Code. @rtibbles then reviewed the generated output, and did iterative rounds of updates before making it ready for review 🤖

@github-actions github-actions bot added DEV: tools Internal tooling for development SIZE: very large labels Nov 22, 2025
@rtibbles
Copy link
Member Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 22, 2025

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 22, 2025

Walkthrough

Introduces a new ESLint rule no-undefined-translator-keys that validates translator object destructuring. The implementation includes AST parsing for translator discovery, import resolution, and destructuring validation to ensure all accessed keys exist and use trailing '$' suffixes. Test fixtures demonstrate various export patterns and a comprehensive test suite covers valid and invalid scenarios.

Changes

Cohort / File(s) Change Summary
Rule Implementation
packages/eslint-plugin-kolibri/lib/rules/no-undefined-translator-keys.js
New ESLint rule with parser utilities, translator discovery via AST walking, import resolution (relative and external), destructuring validation, error reporting with suggested fixes, and ESLint rule definition with meta, messages, and create handler.
Test Fixtures
packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/defaultExport.js, malformed.js, reExport.js, testStrings.js
Four new test fixture files demonstrating translator patterns: default export, re-export, malformed/invalid syntax, and multiple translator instances with various message formats (primitive strings and object-format with metadata).
Test Suite
packages/eslint-plugin-kolibri/tests/lib/rules/no-undefined-translator-keys.spec.js
Comprehensive ESLint RuleTester test suite with valid cases covering destructuring patterns, cross-file imports, and object-format messages; invalid cases asserting errors for undefined keys, missing '$' suffix, and incorrect key usage.
Configuration
packages/kolibri-format/.eslintrc.js
New ESLint rule entry: kolibri/no-undefined-translator-keys set to ERROR in module.exports.rules.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Rule implementation complexity: The main rule file contains dense logic including AST parsing with caching, recursive translator discovery, multi-stage import resolution (relative imports, named/default imports, re-exports), and stateful validation across multiple AST event handlers.
  • Key validation logic: The destructuring validation logic that strips '$' suffix and compares against collected keys requires careful scrutiny for edge cases (aliasing, nested destructuring, cross-translator scenarios).
  • Import resolution: The logic for resolving relative imports and chained imports needs verification to prevent false positives/negatives, especially for re-export patterns.
  • Test coverage breadth: While test cases follow repetitive patterns, the sheer number of valid and invalid scenarios warrants careful verification that all edge cases are properly handled by the implementation.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main change: adding an ESLint rule to validate translator key destructuring, which aligns with the primary implementation of the no-undefined-translator-keys rule.
Description check ✅ Passed The description is directly related to the changeset, explaining the rule's purpose, validation approach, and context for the implementation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/translator-destructuring-support-01LaLgvzVYK5N2GWsDHXyzPt

Tip

📝 Customizable high-level summaries are now available in beta!

You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.

  • Provide your own instructions using the high_level_summary_instructions setting.
  • Format the summary however you like (bullet lists, tables, multi-section layouts, contributor stats, etc.).
  • Use high_level_summary_in_walkthrough to move the summary from the description to the walkthrough section.

Example instruction:

"Divide the high-level summary into five sections:

  1. 📝 Description — Summarize the main change in 50–60 words, explaining what was done.
  2. 📓 References — List relevant issues, discussions, documentation, or related PRs.
  3. 📦 Dependencies & Requirements — Mention any new/updated dependencies, environment variable changes, or configuration updates.
  4. 📊 Contributor Summary — Include a Markdown table showing contributions:
    | Contributor | Lines Added | Lines Removed | Files Changed |
  5. ✔️ Additional Notes — Add any extra reviewer context.
    Keep each section concise (under 200 words) and use bullet or numbered lists for clarity."

Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/eslint-plugin-kolibri/lib/rules/no-undefined-translator-keys.js (1)

11-13: Consider cache invalidation strategy.

The global cache improves performance but has no invalidation mechanism. In long-running processes (like IDE language servers), this could serve stale data if source files change, or grow unbounded over time. For typical CLI usage this is fine, but consider adding cache clearing on file changes or a size limit for language server scenarios.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 66a435a and f35c2db.

📒 Files selected for processing (7)
  • packages/eslint-plugin-kolibri/lib/rules/no-undefined-translator-keys.js (1 hunks)
  • packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/defaultExport.js (1 hunks)
  • packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/malformed.js (1 hunks)
  • packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/reExport.js (1 hunks)
  • packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/testStrings.js (1 hunks)
  • packages/eslint-plugin-kolibri/tests/lib/rules/no-undefined-translator-keys.spec.js (1 hunks)
  • packages/kolibri-format/.eslintrc.js (1 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/malformed.js

[error] 6-6: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)


[error] 6-6: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)


[error] 6-6: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)


[error] 6-6: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)


[error] 6-6: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)


[error] 6-6: Expected a semicolon or an implicit semicolon after a statement, but found none

An explicit or implicit semicolon is expected here...

...Which is required to end this statement

(parse)


[error] 6-6: expected } but instead the file ends

the file ends here

(parse)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: Python unit tests on Mac OS (3.10)
  • GitHub Check: Python unit tests for currently supported Python versions (3.13)
  • GitHub Check: Python unit tests for currently supported Python versions (3.11)
  • GitHub Check: Python unit tests for currently supported Python versions (3.12)
  • GitHub Check: Python unit tests for currently supported Python versions (3.10)
  • GitHub Check: Python unit tests for currently supported Python versions (3.9)
  • GitHub Check: Python unit tests on Windows Server (3.8)
  • GitHub Check: Python unit tests for EOL Python versions (3.7)
  • GitHub Check: Python unit tests for EOL Python versions (3.8)
  • GitHub Check: Python unit tests for EOL Python versions (3.6)
  • GitHub Check: Python postgres unit tests
  • GitHub Check: Frontend tests
  • GitHub Check: All file linting
  • GitHub Check: Build WHL file / Build WHL
🔇 Additional comments (14)
packages/kolibri-format/.eslintrc.js (1)

255-255: LGTM!

The rule is correctly configured with ERROR severity and appropriately placed among the other translator-related rules.

packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/defaultExport.js (1)

1-7: LGTM!

This fixture correctly demonstrates the default export pattern for translators, providing good test coverage for that scenario.

packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/malformed.js (1)

1-6: LGTM!

This malformed fixture correctly serves its purpose of testing the rule's resilience to parsing errors. The static analysis errors are expected and intentional for this test file.

packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/reExport.js (1)

1-9: LGTM!

This fixture effectively demonstrates the re-export pattern (separate declaration and export), providing necessary test coverage for this common code pattern.

packages/eslint-plugin-kolibri/tests/lib/rules/no-undefined-translator-keys.spec.js (1)

1-691: Excellent test coverage!

This test suite is comprehensive and well-structured:

  • Covers a wide range of valid scenarios (basic destructuring, cross-file imports, default/re-exports, object-format messages, aliasing)
  • Thoroughly tests invalid cases with precise error message validation
  • Clear section organization with helpful comments
  • Proper handling of edge cases (malformed files, non-existent imports, empty destructuring)

The test quality demonstrates careful consideration of real-world usage patterns.

packages/eslint-plugin-kolibri/tests/lib/rules/fixtures/testStrings.js (1)

1-32: LGTM!

This fixture provides excellent test coverage with:

  • Multiple translator instances for testing cross-translator scenarios
  • Both string and object-format message patterns
  • Clear demonstration of the message-with-context pattern used in Kolibri

The variety helps ensure the rule handles different translation patterns correctly.

packages/eslint-plugin-kolibri/lib/rules/no-undefined-translator-keys.js (8)

20-54: LGTM!

These helper functions correctly identify createTranslator calls and extract message keys, properly handling both identifier and literal property keys.


61-97: LGTM!

These functions correctly traverse the AST to extract variable names and export names, handling the appropriate node types and parent relationships.


104-158: LGTM!

The import resolution logic correctly handles both relative and absolute imports with appropriate error handling. The use of require.resolve for absolute imports (like kolibri/utils/i18n) is wrapped in try-catch, gracefully skipping validation when modules can't be resolved.


165-262: LGTM!

The AST walking logic comprehensively handles all translator export patterns:

  • Direct named exports
  • Default exports
  • Re-export patterns (declare then export)

The recursive walking correctly traverses the entire AST to discover all translator definitions.


270-302: LGTM!

The file parsing logic correctly:

  • Leverages caching for performance
  • Handles parse failures gracefully by returning null
  • Uses appropriate espree configuration for modern JavaScript

Note: TypeScript files (.ts, .tsx) will fail to parse with espree and be silently skipped, which is acceptable per the design.


311-369: LGTM!

The validation logic correctly:

  • Requires trailing $ suffix on destructured keys
  • Validates keys exist in the translator definition
  • Provides helpful error messages with available keys
  • Properly handles spread operators, aliasing, and computed properties

371-462: LGTM!

The rule implementation correctly:

  • Tracks local translator definitions from createTranslator calls
  • Resolves and tracks imported translators (both named and default imports)
  • Validates destructuring against both local and imported translators
  • Properly integrates with ESLint's visitor pattern

464-481: LGTM!

The rule metadata and message definitions follow ESLint conventions correctly:

  • Appropriate rule type and category
  • Clear, actionable error messages
  • Standard module exports structure

@rtibbles rtibbles force-pushed the claude/translator-destructuring-support-01LaLgvzVYK5N2GWsDHXyzPt branch 2 times, most recently from 87879db to ee70880 Compare November 22, 2025 01:11
@github-actions
Copy link
Contributor

github-actions bot commented Nov 22, 2025

@rtibbles rtibbles force-pushed the claude/translator-destructuring-support-01LaLgvzVYK5N2GWsDHXyzPt branch 2 times, most recently from ba86935 to 53ac121 Compare November 22, 2025 01:46
Implements no-undefined-translator-keys rule that prevents destructuring
undefined keys from createTranslator objects. Validates both same-file and
cross-file imports using AST parsing and Node.js module resolution.
@rtibbles rtibbles force-pushed the claude/translator-destructuring-support-01LaLgvzVYK5N2GWsDHXyzPt branch from 53ac121 to 9834a4d Compare November 22, 2025 01:48
Copy link
Member Author

@rtibbles rtibbles left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This provides good test coverage of the rule, so I feel pretty confident about our using this.

},
});

tester.run('no-undefined-translator-keys', rule, {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that this seamlessly integrates with jest - as when I run this locally, it reports 52 tests running and passing.

@rtibbles rtibbles marked this pull request as ready for review November 26, 2025 21:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

DEV: tools Internal tooling for development SIZE: very large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants