Skip to content

Linting updates#487

Merged
tracygardner merged 4 commits intomainfrom
linting-updates
Mar 29, 2026
Merged

Linting updates#487
tracygardner merged 4 commits intomainfrom
linting-updates

Conversation

@tracygardner
Copy link
Copy Markdown
Contributor

@tracygardner tracygardner commented Mar 29, 2026

Summary by CodeRabbit

  • New Features

    • Enhanced screen reader announcements for keyboard navigation accessibility.
  • Bug Fixes

    • Improved Escape key behavior for UI element interaction.
    • Updated validation rules for event naming.
  • Localization

    • Adjusted gesture detection options in device input blocks.
    • Cleaned up translation strings across multiple languages.

tracygardner and others added 4 commits March 29, 2026 09:56
Remove unnecessary backslash escapes: double quotes in template literals
and over-escaped characters in regex character classes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
These languages are pending human review and will be added back once
reviewed. Removes dead loadSavedLanguage/applySavedLanguageTranslations
functions and the corresponding branches in setLanguage.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rename second pin_h_option (Gesture: ScreenDown) to pin_g_option in
  all locale files; update sensing.js dropdown to use getOption("pin_g")
  with value "g" — restoring the previously shadowed "Logo pressed" entry
- Remove duplicate __fonts_FreeSans_Bold_json_option in sv/pl/pt (identical value)
- Remove duplicate loading_success_ui in fr (keep the more complete translation)
- Remove duplicate about_heading_ui in fr (identical value)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- api/xr.js: import translate from translation.js
- blocks/blocks.js: import categoryColours from toolbox.js
- main/input.js: import Blockly; promote announceToScreenReader to
  exported module-level function (was nested inside setupInput)
- main/blockhandling.js: import announceToScreenReader from input.js
- ui/gizmos.js: replace undefined areGizmosEnabled guard with direct
  call (function never existed; typeof guard always fell back to true);
  use window.selectedColor consistently

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 29, 2026

📝 Walkthrough

Walkthrough

This pull request consolidates multiple updates across translation files, block definitions, and utility modules. Changes include renaming a gesture option key from pin_h to pin_g across all locale files, simplifying translation initialization logic, exporting a screen-reader announcement function, updating regex patterns and string escaping in various files, and refining UI event handlers.

Changes

Cohort / File(s) Summary
Translation and API Module Updates
api/xr.js, main/translation.js
Added translate import to XR module for dynamic message text. Removed legacy language-initialization logic (localStorage loading and per-language Blockly message patching for fr/it/sv/pt/pl/de); now relies on initializeSavedLanguage() for language application.
Block Definitions
blocks/blocks.js, blocks/condition.js, blocks/events.js, blocks/sensing.js
Imported categoryColours from toolbox; updated SVG markup escaping (unescaped quotes in data URIs); adjusted event-name validation regex for special-character disallowance; changed microbit gesture option from pin_h to pin_g.
Locale Files
locale/en.js, locale/es.js, locale/fr.js, locale/it.js, locale/pl.js, locale/pt.js, locale/sv.js
Renamed translation key pin_h_option to pin_g_option for gesture ScreenDown across all locales. Additionally removed loading_success_ui (fr), about_heading_ui (fr), and __fonts_FreeSans_Bold_json_option (pl, pt, sv) entries.
Accessibility and Input
main/input.js, main/blockhandling.js
Exported new announceToScreenReader(message) function from input module for reusability; used it in blockhandling for Alt+M keyboard shortcut to announce focus to screen readers.
UI and Script Utilities
ui/gizmos.js, scripts/check-link-security.mjs, scripts/utils/parse-jsdoc.mjs
Simplified Escape key handler to unconditionally disable gizmos; updated color picking to use window.selectedColor; fixed string escaping in security violation message; adjusted JSDoc parameter parsing regex for bracket removal.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Tests update #486 — Modifies api/xr.js and adjusts flockXR XR-related behaviors; overlaps with this PR's XR API translation changes.

Poem

🐰 From pin_h to pin_g the gestures now bound,
Locales harmonized all around!
Screen readers announce with delight,
Blockly messages streamlined just right,
With escapes fixed and handlers cleaned bright! ✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'Linting updates' is vague and does not accurately reflect the substantial functional changes across multiple files beyond just linting. Replace with a more descriptive title that captures the main changes, such as 'Replace pin_h with pin_g in microbit gestures and refactor translation loading' or similar.
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch linting-updates

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
Copy Markdown

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
main/translation.js (2)

111-113: ⚠️ Potential issue | 🟠 Major

Potential runtime error when selecting unsupported languages.

If a user selects a language not in the translations object (e.g., "fr" which is commented out), translations[currentLanguage] will be undefined, and Object.keys(undefined) will throw a TypeError.

Consider adding a guard:

🐛 Proposed fix to guard against undefined translations
-  // Apply custom translations for the selected language
-  Object.keys(translations[currentLanguage]).forEach((key) => {
-    Blockly.Msg[key] = translations[currentLanguage][key];
-  });
+  // Apply custom translations for the selected language
+  const currentTranslations = translations[currentLanguage];
+  if (currentTranslations) {
+    Object.keys(currentTranslations).forEach((key) => {
+      Blockly.Msg[key] = currentTranslations[key];
+    });
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main/translation.js` around lines 111 - 113, The loop that assigns
Blockly.Msg from translations uses Object.keys(translations[currentLanguage])
which will throw if translations[currentLanguage] is undefined; update the
assignment logic in the block where Object.keys(...) is called (the loop
referencing translations and currentLanguage) to first guard that
translations[currentLanguage] exists (e.g., use a fallback object like
translations[currentLanguage] || translations['en'] || {} or skip assignment and
warn) and only iterate keys when that object is defined, ensuring Blockly.Msg is
not updated from undefined and optionally logging a warning about unsupported
currentLanguage.

86-106: ⚠️ Potential issue | 🟠 Major

Reduce language support to English and Spanish only—UI mismatch creates broken user experience.

The setLanguage function now only activates Spanish (es) translations; all other languages fall back to English. This is confirmed by the commented-out imports (lines 10-25) and the reduced translations object (lines 31-40). However, index.html still presents language menu options for French, Italian, Swedish, Portuguese, Polish, and German (lines 455-490).

Users selecting these unavailable languages will silently receive English without any indication the selection failed—a UX regression. Either restore support for these languages or remove their menu options from the HTML and clarify whether this is intentional given the PR title is "Linting updates".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@main/translation.js` around lines 86 - 106, The language selector currently
only applies Spanish ("es") and otherwise forces English in setLanguage (the
translations object and the language switch block in main/translation.js), while
index.html still shows other language options—fix by either restoring the
missing locale imports and entries in translations so setLanguage supports
French/Italian/Swedish/Portuguese/Polish/German (re-add locale modules and their
keys used by translations), or remove those language menu entries from
index.html and update the UI flow: change setLanguage to detect unsupported
codes and show a clear user-facing message (toast/alert) when a user picks an
unavailable language; reference the setLanguage function, the translations
mapping in main/translation.js, and the language menu in index.html when making
edits.
scripts/check-link-security.mjs (2)

88-88: ⚠️ Potential issue | 🟡 Minor

Regex pattern cannot handle nested parentheses in window.open arguments, but no such calls exist in the codebase.

The pattern /window\.open\s*\(([^)]*)\)/g uses [^)]*, which would fail to match window.open calls with nested parentheses (e.g., window.open(url, name, getFeatures())).

Search found only two window.open calls in the codebase:

  • ui/designview.js:7: window.open("https://flockxr.com/", "_blank", "noopener,noreferrer");
  • main/menu.js:379: window.open("https://hub.flockxr.com/", "_blank", "noopener,noreferrer");

Both use only string literal arguments with no nested parentheses. The script includes a sophisticated splitTopLevelArgs() function (lines 34–84) that properly handles nested structures by tracking depth and quotes, so even if future code introduces such calls, consider whether a more robust regex or a proper JavaScript parser would improve reliability.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/check-link-security.mjs` at line 88, The regex openRegex using
/window\.open\s*\(([^)]*)\)/g fails on nested parentheses; update the detection
to use the existing robust splitTopLevelArgs() approach instead of relying on
that fragile regex (or switch to a JS parser) — locate openRegex in
scripts/check-link-security.mjs and replace the simple capturing-regex usage
with logic that finds "window.open(" and then extracts the argument substring by
walking characters and feeding it into splitTopLevelArgs(), ensuring nested
parentheses and quoted strings are handled correctly.

16-16: ⚠️ Potential issue | 🔴 Critical

Regex pattern misses single-quoted and unquoted rel attributes.

The pattern /\brel\s*=\s*"([^"]*)"/i only matches double-quoted attributes, missing valid HTML forms like rel='noopener' and rel=noopener. This allows security violations to go undetected.

The proposed fix in the review handles single quotes but still misses unquoted attribute values. Use this more complete pattern instead:

🔒 Complete fix for all valid quote styles
-    const relMatch = tag.match(/\brel\s*=\s*"([^"]*)"/i);
+    const relMatch = tag.match(/\brel\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+))/i);
+    const relValue = (relMatch?.[1] || relMatch?.[2] || relMatch?.[3])?.toLowerCase();

Note: Update line 25 to extract the matched group correctly from the new pattern structure.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/check-link-security.mjs` at line 16, The current tag.match call using
relMatch only handles double-quoted rel attributes; update the regex used in
tag.match (the expression assigned to relMatch) to accept double-quoted,
single-quoted, or unquoted attribute values (i.e. rel=\s*(double-quoted |
single-quoted | unquoted token)), then adjust the code that reads the captured
group (where you currently extract the rel value from relMatch) to use the
correct capture index for the new pattern so single-quoted and unquoted rel
attributes are detected as well.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@main/translation.js`:
- Around line 111-113: The loop that assigns Blockly.Msg from translations uses
Object.keys(translations[currentLanguage]) which will throw if
translations[currentLanguage] is undefined; update the assignment logic in the
block where Object.keys(...) is called (the loop referencing translations and
currentLanguage) to first guard that translations[currentLanguage] exists (e.g.,
use a fallback object like translations[currentLanguage] || translations['en']
|| {} or skip assignment and warn) and only iterate keys when that object is
defined, ensuring Blockly.Msg is not updated from undefined and optionally
logging a warning about unsupported currentLanguage.
- Around line 86-106: The language selector currently only applies Spanish
("es") and otherwise forces English in setLanguage (the translations object and
the language switch block in main/translation.js), while index.html still shows
other language options—fix by either restoring the missing locale imports and
entries in translations so setLanguage supports
French/Italian/Swedish/Portuguese/Polish/German (re-add locale modules and their
keys used by translations), or remove those language menu entries from
index.html and update the UI flow: change setLanguage to detect unsupported
codes and show a clear user-facing message (toast/alert) when a user picks an
unavailable language; reference the setLanguage function, the translations
mapping in main/translation.js, and the language menu in index.html when making
edits.

In `@scripts/check-link-security.mjs`:
- Line 88: The regex openRegex using /window\.open\s*\(([^)]*)\)/g fails on
nested parentheses; update the detection to use the existing robust
splitTopLevelArgs() approach instead of relying on that fragile regex (or switch
to a JS parser) — locate openRegex in scripts/check-link-security.mjs and
replace the simple capturing-regex usage with logic that finds "window.open("
and then extracts the argument substring by walking characters and feeding it
into splitTopLevelArgs(), ensuring nested parentheses and quoted strings are
handled correctly.
- Line 16: The current tag.match call using relMatch only handles double-quoted
rel attributes; update the regex used in tag.match (the expression assigned to
relMatch) to accept double-quoted, single-quoted, or unquoted attribute values
(i.e. rel=\s*(double-quoted | single-quoted | unquoted token)), then adjust the
code that reads the captured group (where you currently extract the rel value
from relMatch) to use the correct capture index for the new pattern so
single-quoted and unquoted rel attributes are detected as well.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c069b692-9b98-41f0-b1ec-094689b9158a

📥 Commits

Reviewing files that changed from the base of the PR and between 3cc3db1 and 96772a3.

📒 Files selected for processing (18)
  • api/xr.js
  • blocks/blocks.js
  • blocks/condition.js
  • blocks/events.js
  • blocks/sensing.js
  • locale/en.js
  • locale/es.js
  • locale/fr.js
  • locale/it.js
  • locale/pl.js
  • locale/pt.js
  • locale/sv.js
  • main/blockhandling.js
  • main/input.js
  • main/translation.js
  • scripts/check-link-security.mjs
  • scripts/utils/parse-jsdoc.mjs
  • ui/gizmos.js

Comment on lines +67 to +69
disableGizmos();
e.stopPropagation(); // avoid duplicate handlers upstream
// don't e.preventDefault() globally unless you *need* to stop other Esc behavior
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Unconditional capture-phase Escape propagation stop breaks other key handlers

On Line 68, e.stopPropagation() now runs for every plain Escape, and because this listener runs in capture phase (Line 79), other Escape handlers won’t receive the event. That can break modal/dialog/feature-specific Escape behavior outside gizmos.

💡 Proposed fix
       try {
-        disableGizmos();
-        e.stopPropagation(); // avoid duplicate handlers upstream
+        const hadActiveGizmo =
+          Boolean(gizmoManager?.positionGizmoEnabled) ||
+          Boolean(gizmoManager?.rotationGizmoEnabled) ||
+          Boolean(gizmoManager?.scaleGizmoEnabled) ||
+          Boolean(gizmoManager?.boundingBoxGizmoEnabled) ||
+          Boolean(gizmoManager?.selectGizmoEnabled) ||
+          colorPickingKeyboardMode;
+
+        disableGizmos();
+        if (hadActiveGizmo) {
+          e.stopPropagation(); // avoid duplicate handlers only when we actually handled gizmo state
+        }
         // don't e.preventDefault() globally unless you *need* to stop other Esc behavior
       } catch {

Also applies to: 79-79

@tracygardner tracygardner merged commit 47abd17 into main Mar 29, 2026
9 checks passed
@tracygardner tracygardner deleted the linting-updates branch March 29, 2026 09:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant