Skip to content

chore(ci): lint cleanup#40

Merged
coryrylan merged 1 commit intomainfrom
topic-lint-fixup-5
Apr 30, 2026
Merged

chore(ci): lint cleanup#40
coryrylan merged 1 commit intomainfrom
topic-lint-fixup-5

Conversation

@coryrylan
Copy link
Copy Markdown
Collaborator

@coryrylan coryrylan commented Apr 29, 2026

Enabled following eslint rules:

  • max-nested-callbacks
  • max-statements
  • max-depth

Summary by CodeRabbit

  • Refactor

    • Internal logic consolidated into helpers across many modules to simplify behavior and improve robustness; editor and tooling initialization/teardown made more reliable.
    • ActionList width measurement improved for Shadow DOM scenarios.
  • Chores

    • Enforced stricter TypeScript linting limits (depth/callbacks/statements).
  • Tests

    • Adjusted tooltip benchmark threshold; added/updated validation and lint rule tests.
  • Documentation

    • Updated public description for the button‑group component.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 29, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Refactors internal logic by extracting helpers across multiple modules (formatting, merging, lint rules, monaco editor, utilities), tightens ESLint structural rules, updates tests and a lighthouse threshold, and makes a Shadow DOM DOM-query fix; no public API signature changes.

Changes

Cohort / File(s) Summary
Relative Time Formatting
projects/core/src/format-relative-time/format-relative-time.ts
Replaces hardcoded unit selection with data-driven thresholds and adds #resolveValueAndUnit(diffMs); simplifies #formattedRelativeTime.
Form Schema & Examples
projects/forms/src/internal/schema.ts, projects/core/src/forms/validation.examples.ts
parseControlValue returns directly per-case; removed file-scoped ESLint disable comment in example.
Object Utilities
projects/core/src/internal/utils/objects.ts
Extracts per-key merge logic into mergeProperty used by deepMerge.
Wireit Metadata Tasks
projects/internals/metadata/src/tasks/wireit.utils.ts
Adds addDependency helper to centralize dependency parsing/push and error handling.
HTML Condensing Utilities
projects/internals/tools/src/examples/utils.ts
Splits condense logic into condenseStep; factors block detection into isSelfContainedBlock and countTagDelta.
Lint Internals & Rules
projects/lint/src/eslint/internals/utils.ts, projects/lint/src/eslint/rules/no-missing-control-label.ts, projects/lint/src/eslint/rules/no-nested-container-types.ts, projects/lint/src/eslint/rules/no-nested-container-types.test.ts
Introduces attrsMatch and ancestorHasExternalLabel; expands no-nested-container-types to treat nve-card under nve-page-panel and adds tests/suggestion cases.
ESLint Config
projects/internals/eslint/src/configs/typescript.js
Enforces max-nested-callbacks, max-depth, and max-statements in base config; keeps test-file override for max-nested-callbacks.
Monaco: Input, Problems & Tests + Patch
projects/monaco/src/internal/base/input.ts, projects/monaco/src/internal/formats/problems-format.ts, projects/monaco/src/problems/problems.ts, projects/monaco/src/internal/base/input.test.ts, patches/monaco-editor.patch
Extracts validation/version handling and listener registration (#handleValidationVersion, #registerEditorListeners); centralizes editor init/teardown (#initEditorState, #resetEditorState); problems formatting uses an accumulator/helper; adds JSON diagnostics/versioning test; ActionList DOM query made Shadow DOM–aware.
Site: Search & Theme Preview
projects/site/src/_internal/search/search.ts, projects/site/src/_internal/theme-preview/theme-preview.ts
Extracts cache eviction to #evictOldestCacheEntryIfFull; factors CSS custom-property collection into a helper.
Tooltip Lighthouse Test
projects/core/src/tooltip/tooltip.test.lighthouse.ts
Loosened JS payload assertion from 14.4 KB to 14.6 KB.
Button Group Docs
projects/core/src/button-group/button-group.ts
Updated JSDoc @description for nve-button-group (docs-only).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested labels

scope(lint)

Suggested reviewers

  • johnyanarella

Poem

🐰 I hopped through files and hid small helpers neat,

pulled threads of logic into tidy little feet.
Tests woke with a blink, configs straightened their line—
I munched a carrot, code now trims and shines. 🥕

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'chore(ci): lint cleanup' is misleading. The PR enables strict ESLint complexity rules (max-nested-callbacks, max-statements, max-depth), but most changes are refactorings across multiple modules to comply with these rules, not CI configuration changes. Revise the title to accurately reflect the main changes, such as 'refactor: extract helpers and simplify complexity to meet ESLint limits' or 'chore: enforce stricter ESLint complexity rules and refactor accordingly'.
Docstring Coverage ⚠️ Warning Docstring coverage is 8.70% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch topic-lint-fixup-5

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: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@projects/core/src/format-relative-time/format-relative-time.ts`:
- Around line 74-81: The thresholds array is being recreated on every call to
the `#computeUnit` method; extract it to a single shared immutable value to avoid
per-call allocation. Create a module-level constant (or a static readonly field
on the class that contains `#computeUnit`) named e.g. THRESHOLDS with the same
structure and replace the inline thresholds declaration in `#computeUnit` with a
reference to THRESHOLDS; ensure the type annotation matches Array<{ unit:
Intl.RelativeTimeFormatUnit; divisor: number; max: number }> and that existing
logic still reads from the new constant.

In `@projects/core/src/internal/utils/objects.ts`:
- Line 38: Replace the Object.assign call that creates a temporary object with a
direct property assignment to avoid allocations: change the use of
Object.assign(target, { [key]: sourceValue }) to assign the value directly to
target using the existing identifiers (target, key, sourceValue) so the line
uses target[key] = sourceValue; in the function in objects.ts.

In `@projects/forms/src/internal/schema.ts`:
- Around line 176-178: In the switch branch that currently does `case 'array':
case 'object': return JSON.parse(value) as T;` wrap the JSON.parse in a
try/catch and return undefined on parse failure so the function honors the `T |
undefined` contract; update the branch in the function containing that switch
(the branch handling 'array'/'object') to catch and suppress parse errors
(optionally log or attach context) rather than letting the raw exception
propagate.
- Line 175: The boolean parsing currently returns (!!value || value === 'true')
which treats any non-empty string (including "false") as true; change the logic
to perform strict comparisons against true-like values instead (e.g. replace
that expression with (value === true || value === 'true') as T) so that "false"
correctly yields false; locate the return statement using the value variable in
this file and update it accordingly.
- Line 180: The enum check fails for numeric enums because it compares raw input
string to enum members; update the logic around the line using
schema.enum.includes(value) (in the enum parsing branch) to compare normalized
strings instead: find the enum member where String(member) === String(value) (or
map schema.enum to String values) and return that matched enum member cast as T
instead of returning the raw input string; this ensures numeric enum members
like 1 match form input "1" and the returned value preserves the original enum
member type.

In `@projects/internals/eslint/src/configs/typescript.js`:
- Line 140: The 'id-length' rule is currently disabled but still includes an
unused options object; simplify the rule entry by removing the array/options and
set the rule to just 'off' (replace the "'id-length': ['off', { min: 2,
exceptions: ['_'] }]" entry with a simple "'id-length': 'off'") so the disabled
rule configuration is clear and concise.

In `@projects/internals/tools/src/examples/utils.ts`:
- Around line 158-173: The code currently recompiles RegExp objects on every
line inside countTagDelta/findBlockEnd for the given tag; modify findBlockEnd so
it constructs and caches the three regexes (open, self-close, close) once per
call using an escaped tag string, then update countTagDelta to accept these
precomputed RegExp objects (or inline its logic into findBlockEnd) and use them
to compute opens/selfCloses/closes, ensuring isSelfContainedBlock(tag) is still
respected; this eliminates per-line RegExp allocations and makes tag escaping
explicit.

In `@projects/site/src/_internal/search/search.ts`:
- Around line 222-229: Eviction currently skips deleting the oldest cache entry
when the oldest key is an empty string because the condition uses truthiness;
update the guard in `#evictOldestCacheEntryIfFull` to treat empty-string keys as
valid by checking for undefined explicitly (e.g., test firstCacheKey !==
undefined or verify iterator has a value) before calling
this.#searchCache.delete(firstCacheKey), ensuring the cache never grows past
DocsSearch.CACHE_MAX_SIZE when search() stores '' as a key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 26fc3269-72a0-4093-9bb0-f51a55f60f9a

📥 Commits

Reviewing files that changed from the base of the PR and between c43ad8f and 9d7c8a8.

📒 Files selected for processing (14)
  • projects/core/src/format-relative-time/format-relative-time.ts
  • projects/core/src/forms/validation.examples.ts
  • projects/core/src/internal/utils/objects.ts
  • projects/forms/src/internal/schema.ts
  • projects/internals/eslint/src/configs/typescript.js
  • projects/internals/metadata/src/tasks/wireit.utils.ts
  • projects/internals/tools/src/examples/utils.ts
  • projects/lint/src/eslint/internals/utils.ts
  • projects/lint/src/eslint/rules/no-missing-control-label.ts
  • projects/monaco/src/internal/base/input.ts
  • projects/monaco/src/internal/formats/problems-format.ts
  • projects/monaco/src/problems/problems.ts
  • projects/site/src/_internal/search/search.ts
  • projects/site/src/_internal/theme-preview/theme-preview.ts
💤 Files with no reviewable changes (1)
  • projects/core/src/forms/validation.examples.ts

Comment thread projects/core/src/format-relative-time/format-relative-time.ts Outdated
Comment thread projects/core/src/internal/utils/objects.ts Outdated
Comment thread projects/forms/src/internal/schema.ts
Comment on lines +176 to +178
case 'array':
case 'object':
return JSON.parse(value) as T;
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

Handle invalid JSON input instead of throwing raw parse errors.

JSON.parse(value) can throw and bypass the T | undefined contract, causing unhandled exceptions in callers expecting parse failure signaling.

Proposed fix
     case 'array':
     case 'object':
-      return JSON.parse(value) as T;
+      try {
+        return JSON.parse(value) as T;
+      } catch {
+        return undefined;
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case 'array':
case 'object':
return JSON.parse(value) as T;
case 'array':
case 'object':
try {
return JSON.parse(value) as T;
} catch {
return undefined;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` around lines 176 - 178, In the switch
branch that currently does `case 'array': case 'object': return
JSON.parse(value) as T;` wrap the JSON.parse in a try/catch and return undefined
on parse failure so the function honors the `T | undefined` contract; update the
branch in the function containing that switch (the branch handling
'array'/'object') to catch and suppress parse errors (optionally log or attach
context) rather than letting the raw exception propagate.

case 'object':
return JSON.parse(value) as T;
case 'enum':
return (schema.enum.includes(value) ? value : undefined) as T;
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

Enum parsing fails for numeric enum values from string form inputs.

Form input is string, so includes(value) won’t match numeric enum members (e.g., "1" vs 1).

Proposed fix
     case 'enum':
-      return (schema.enum.includes(value) ? value : undefined) as T;
+      if (schema.enum.includes(value)) return value as T;
+      const numericValue = Number(value);
+      return (Number.isNaN(numericValue) ? undefined : schema.enum.includes(numericValue) ? numericValue : undefined) as T;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (schema.enum.includes(value) ? value : undefined) as T;
if (schema.enum.includes(value)) return value as T;
const numericValue = Number(value);
return (Number.isNaN(numericValue) ? undefined : schema.enum.includes(numericValue) ? numericValue : undefined) as T;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` at line 180, The enum check fails for
numeric enums because it compares raw input string to enum members; update the
logic around the line using schema.enum.includes(value) (in the enum parsing
branch) to compare normalized strings instead: find the enum member where
String(member) === String(value) (or map schema.enum to String values) and
return that matched enum member cast as T instead of returning the raw input
string; this ensures numeric enum members like 1 match form input "1" and the
returned value preserves the original enum member type.

Comment thread projects/internals/eslint/src/configs/typescript.js
Comment thread projects/internals/tools/src/examples/utils.ts Outdated
Comment thread projects/site/src/_internal/search/search.ts
@coryrylan coryrylan force-pushed the topic-lint-fixup-5 branch from 9d7c8a8 to 0d392b5 Compare April 29, 2026 16:49
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: 3

♻️ Duplicate comments (1)
projects/site/src/_internal/search/search.ts (1)

222-229: ⚠️ Potential issue | 🟠 Major

Fix cache eviction guard to handle empty-string keys.

On Line 227, if (firstCacheKey) skips deletion when the oldest key is '', so cache eviction can fail and exceed DocsSearch.CACHE_MAX_SIZE.

Suggested fix
   `#evictOldestCacheEntryIfFull`() {
     if (this.#searchCache.size < DocsSearch.CACHE_MAX_SIZE) {
       return;
     }
-    const firstCacheKey = this.#searchCache.keys().next().value;
-    if (firstCacheKey) {
-      this.#searchCache.delete(firstCacheKey);
-    }
+    const firstEntry = this.#searchCache.keys().next();
+    if (!firstEntry.done) {
+      this.#searchCache.delete(firstEntry.value);
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/site/src/_internal/search/search.ts` around lines 222 - 229, The
cache-eviction guard in `#evictOldestCacheEntryIfFull` wrongly treats an
empty-string key as missing because it uses a truthy check on firstCacheKey;
change the condition to explicitly test for undefined (e.g., check that
firstCacheKey !== undefined or use the iterator's done flag) before calling
this.#searchCache.delete(firstCacheKey) so empty-string keys are evicted
correctly when this.#searchCache.size >= DocsSearch.CACHE_MAX_SIZE.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@projects/core/src/tooltip/tooltip.test.lighthouse.ts`:
- Line 20: The test loosened the JS payload threshold at the assertion
expect(report.payload.javascript.kb) — either revert to the previous numeric
limit or, if the increase is intentional, add an explicit regression rationale
immediately above the assertion describing the measured baseline value, test
environment, date, and a link to the PR/issue that justifies the change;
alternatively extract the threshold into a named constant (e.g.,
JS_PAYLOAD_KB_LIMIT) and add the same rationale comment above that constant so
future reviewers can see why
expect(report.payload.javascript.kb).toBeLessThan(...) was raised.

In `@projects/monaco/src/internal/base/input.ts`:
- Around line 446-469: In `#handleValidationVersion`, clear any pending validation
state before applying the required-field error: when the `#isRequiredAndEmpty`()
branch is taken, call this.#clearValidation() first, then call
this.#setRequiredValidationError() (and still dispatch the
'syntax-validation-changed' event as done in the other branches) so the
validating flag does not remain set after the value is emptied.

In `@projects/monaco/src/problems/problems.ts`:
- Around line 192-224: The teardown currently clears Monaco-related fields but
leaves the host state flag set to 'ready'; update the disposal path so that when
the editor is disposed (the onDidDispose handler) you also remove or clear the
ready flag from this._internals.states (e.g. delete or filter out the 'ready'
entry), by adding that mutation either inside the onDidDispose callback or
inside `#resetEditorState`(); refer to the onDidDispose listener, the
`#resetEditorState` method, and this._internals.states/'ready' symbol to locate
where to apply the change.

---

Duplicate comments:
In `@projects/site/src/_internal/search/search.ts`:
- Around line 222-229: The cache-eviction guard in `#evictOldestCacheEntryIfFull`
wrongly treats an empty-string key as missing because it uses a truthy check on
firstCacheKey; change the condition to explicitly test for undefined (e.g.,
check that firstCacheKey !== undefined or use the iterator's done flag) before
calling this.#searchCache.delete(firstCacheKey) so empty-string keys are evicted
correctly when this.#searchCache.size >= DocsSearch.CACHE_MAX_SIZE.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 1b440978-168d-40a2-b6f9-f0f44cf0e925

📥 Commits

Reviewing files that changed from the base of the PR and between 9d7c8a8 and 0d392b5.

📒 Files selected for processing (15)
  • projects/core/src/format-relative-time/format-relative-time.ts
  • projects/core/src/forms/validation.examples.ts
  • projects/core/src/internal/utils/objects.ts
  • projects/core/src/tooltip/tooltip.test.lighthouse.ts
  • projects/forms/src/internal/schema.ts
  • projects/internals/eslint/src/configs/typescript.js
  • projects/internals/metadata/src/tasks/wireit.utils.ts
  • projects/internals/tools/src/examples/utils.ts
  • projects/lint/src/eslint/internals/utils.ts
  • projects/lint/src/eslint/rules/no-missing-control-label.ts
  • projects/monaco/src/internal/base/input.ts
  • projects/monaco/src/internal/formats/problems-format.ts
  • projects/monaco/src/problems/problems.ts
  • projects/site/src/_internal/search/search.ts
  • projects/site/src/_internal/theme-preview/theme-preview.ts
💤 Files with no reviewable changes (1)
  • projects/core/src/forms/validation.examples.ts

Comment thread projects/core/src/tooltip/tooltip.test.lighthouse.ts
Comment thread projects/monaco/src/internal/base/input.ts
Comment thread projects/monaco/src/problems/problems.ts
@coryrylan coryrylan force-pushed the topic-lint-fixup-5 branch from 0d392b5 to 0086e2c Compare April 30, 2026 01:09
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: 2

Caution

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

⚠️ Outside diff range comments (2)
patches/monaco-editor.patch (2)

241-254: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Delayer.cancel() leaves in-flight promises unsettled.

Removing doReject(...) without an alternate settle path means previously returned promises can remain pending forever after cancellation.

Proposed fix
-            // this.doReject?.(new CancellationError());
+            // Treat cancellation as non-error, but still settle the pending promise.
+            this.task = null;
+            this.doResolve?.(null);
             this.completionPromise = null;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patches/monaco-editor.patch` around lines 241 - 254, Delayer.cancel currently
comments out this.doReject(...), leaving previously returned promises
unresolved; update Delayer.cancel to explicitly settle any pending promise
instead of throwing: if there's a pending resolver, call
this.doResolve?.(undefined) (or resolve with a suitable sentinel) then null out
this.doResolve and this.doReject and set this.completionPromise = null;
reference the Delayer.cancel method and the doResolve/doReject and
completionPromise fields when making the change so in-flight promises are always
settled on cancel without causing an unhandled rejection.

804-806: ⚠️ Potential issue | 🔴 Critical

Incorrect event method name causes runtime error.

The wrapper function onDidValidateModelVersion calls model.onDidValidateModelVersion(listener), but the model patch only adds the onDidValidateVersion(listener) method. This will throw "undefined is not a function" at runtime when listeners are registered.

Fix
 export function onDidValidateModelVersion(model, listener) {
-    return model.onDidValidateModelVersion(listener);
+    return model.onDidValidateVersion(listener);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patches/monaco-editor.patch` around lines 804 - 806, The exported wrapper
onDidValidateModelVersion currently calls
model.onDidValidateModelVersion(listener) which doesn't exist and causes a
runtime error; update the wrapper to call the actual patched method
model.onDidValidateVersion(listener) (or add a forwarding alias on the model) so
listeners are registered correctly; locate the onDidValidateModelVersion
function and replace the internal call to use
model.onDidValidateVersion(listener).
♻️ Duplicate comments (5)
projects/core/src/tooltip/tooltip.test.lighthouse.ts (1)

20-20: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document why the JS payload budget was increased.

Line 20 raises the threshold from the prior baseline, but there’s still no explicit rationale in-test (baseline measurement/date/link). Please either revert the limit or add a short regression note and a named constant so this doesn’t silently normalize a regression.

As per coding guidelines, "Review /projects/site/src/docs/internal/guidelines/testing-lighthouse.md before writing performance tests; verify performance, accessibility, and best practices scoring."

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

In `@projects/core/src/tooltip/tooltip.test.lighthouse.ts` at line 20, The JS
payload threshold in tooltip.test.lighthouse.ts (the assertion on
report.payload.javascript.kb) was raised without documentation; either revert
the numeric change or replace the magic number with a named constant (e.g.,
JS_PAYLOAD_KB_BUDGET) and add a short regression note/comment in the test that
states the reason, baseline value/date/measurement link, and reviewer who
approved the bump; update the test to use the named constant in
expect(report.payload.javascript.kb).toBeLessThan(JS_PAYLOAD_KB_BUDGET) so
future readers can see why the budget was increased.
projects/forms/src/internal/schema.ts (3)

176-178: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle invalid JSON input instead of throwing raw parse errors.

JSON.parse(value) can throw and bypass the T | undefined contract, causing unhandled exceptions in callers expecting parse failure signaling.

🛡️ Proposed fix
     case 'array':
     case 'object':
-      return JSON.parse(value) as T;
+      try {
+        return JSON.parse(value) as T;
+      } catch {
+        return undefined;
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` around lines 176 - 178, The code
currently returns JSON.parse(value) for the 'array' and 'object' branches which
can throw and violate the expected T | undefined contract; update the branches
handling 'array' and 'object' to wrap JSON.parse(value) in a try/catch,
returning the parsed value on success and undefined on any JSON.parse error
(optionally log/contextualize the error) so callers receive undefined instead of
an uncaught exception.

179-180: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enum parsing fails for numeric enum values from string form inputs.

Form input is string, so includes(value) won't match numeric enum members (e.g., "1" vs 1).

🛡️ Proposed fix
     case 'enum':
-      return (schema.enum.includes(value) ? value : undefined) as T;
+      if (schema.enum.includes(value)) return value as T;
+      const numericValue = Number(value);
+      return (Number.isNaN(numericValue) ? undefined : schema.enum.includes(numericValue) ? numericValue : undefined) as T;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` around lines 179 - 180, The enum case
currently uses schema.enum.includes(value) which fails when form inputs are
strings but enum members are numbers; update the 'enum' branch in the parser to
find a matching enum member by comparing String(member) === String(value) (or
coerce value to number if all enum members are numeric), then return the matched
enum member (not the raw input) cast to T; locate the case 'enum' block that
references schema.enum.includes(value) and replace it with a lookup that returns
the actual enum element when a stringified match is found.

174-175: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Boolean parsing is incorrect for "false" input.

!!value makes any non-empty string truthy, so "false" is parsed as true. This is a critical correctness issue.

🐛 Proposed fix
     case 'boolean':
-      return (!!value || value === 'true') as T;
+      if (value === 'true') return true as T;
+      if (value === 'false') return false as T;
+      return undefined;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` around lines 174 - 175, The boolean
branch (case 'boolean') incorrectly uses "!!value" which treats any non-empty
string like "false" as true; update the branch to explicitly handle boolean and
string inputs: if typeof value === 'boolean' return value, else if value ===
'true' return true, else if value === 'false' return false, otherwise fall back
to Boolean(value) or false as the desired default. Ensure you replace the
current return (!!value || value === 'true') as T with these explicit checks
referencing the same case 'boolean', value variable, and T generic.
projects/internals/tools/src/examples/utils.ts (1)

158-173: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Precompute and escape tag regexes once per findBlockEnd call.

countTagDelta currently recompiles three regexes for every scanned line and interpolates tag directly. Build escaped regexes once in findBlockEnd and pass them in.

♻️ Proposed fix
+function escapeRegex(value: string): string {
+  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+
+function buildTagRegex(tag: string): { open: RegExp; selfClose: RegExp; close: RegExp } {
+  const safeTag = escapeRegex(tag);
+  return {
+    open: new RegExp(`<${safeTag}[\\s>]`, 'g'),
+    selfClose: new RegExp(`<${safeTag}[^>]*/>`, 'g'),
+    close: new RegExp(`</${safeTag}>`, 'g')
+  };
+}
+
-function countTagDelta(line: string, tag: string): number {
-  const opens = (line.match(new RegExp(`<${tag}[\\s>]`, 'g')) || []).length;
-  const selfCloses = (line.match(new RegExp(`<${tag}[^>]*/>`, 'g')) || []).length;
-  const closes = (line.match(new RegExp(`</${tag}>`, 'g')) || []).length;
+function countTagDelta(line: string, regex: { open: RegExp; selfClose: RegExp; close: RegExp }): number {
+  const opens = (line.match(regex.open) || []).length;
+  const selfCloses = (line.match(regex.selfClose) || []).length;
+  const closes = (line.match(regex.close) || []).length;
   return opens - selfCloses - closes;
 }
 
 function findBlockEnd(lines: string[], start: number, tag: string): number {
   if (isSelfContainedBlock(lines[start]!, tag)) {
     return start;
   }
 
+  const regex = buildTagRegex(tag);
   let depth = 1;
   for (let i = start + 1; i < lines.length; i++) {
-    depth += countTagDelta(lines[i]!, tag);
+    depth += countTagDelta(lines[i]!, regex);
     if (depth <= 0) {
       return i;
     }
   }
#!/bin/bash
# Verify where tag values reach findBlockEnd/countTagDelta and confirm call-site shape.
rg -nP --type=ts -C3 '\bfunction\s+findBlockEnd\b|\bfindBlockEnd\s*\('
rg -nP --type=ts -C3 '\bfunction\s+countTagDelta\b|\bcountTagDelta\s*\('
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/internals/tools/src/examples/utils.ts` around lines 158 - 173,
countTagDelta is recompiling three tag regexes per line and interpolates raw tag
text; modify findBlockEnd to escape the tag once (e.g., via a safe escape
function), precompile the three RegExp objects (open, selfClose, close) there,
and either pass those RegExp instances into countTagDelta (change its signature)
or inline the counting logic in findBlockEnd; keep the isSelfContainedBlock
check intact and ensure behavior of countTagDelta(openRegex, selfCloseRegex,
closeRegex, line) matches the original opens - selfCloses - closes result.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@projects/core/src/button-group/button-group.ts`:
- Line 24: Update the JSDoc on the ButtonGroup declaration to tighten wording:
replace the existing description with something like "A button group organizes
related buttons and supports either single-select (mutually exclusive) or
multi-select behavior; prefer use in toolbars." Ensure this new prose replaces
the current line in the JSDoc for the ButtonGroup symbol and follows Google
style and write-good rules for Vale linting.

In `@projects/forms/src/internal/schema.ts`:
- Around line 172-173: The number branch in the parser (case 'number' in
projects/forms/src/internal/schema.ts) currently returns parseFloat(value) which
yields NaN for invalid input; change it to parseFloat the value into a temp
variable, check Number.isNaN(result) and return undefined on failure, otherwise
return the parsed number cast to T so the function adheres to the T | undefined
contract.

---

Outside diff comments:
In `@patches/monaco-editor.patch`:
- Around line 241-254: Delayer.cancel currently comments out this.doReject(...),
leaving previously returned promises unresolved; update Delayer.cancel to
explicitly settle any pending promise instead of throwing: if there's a pending
resolver, call this.doResolve?.(undefined) (or resolve with a suitable sentinel)
then null out this.doResolve and this.doReject and set this.completionPromise =
null; reference the Delayer.cancel method and the doResolve/doReject and
completionPromise fields when making the change so in-flight promises are always
settled on cancel without causing an unhandled rejection.
- Around line 804-806: The exported wrapper onDidValidateModelVersion currently
calls model.onDidValidateModelVersion(listener) which doesn't exist and causes a
runtime error; update the wrapper to call the actual patched method
model.onDidValidateVersion(listener) (or add a forwarding alias on the model) so
listeners are registered correctly; locate the onDidValidateModelVersion
function and replace the internal call to use
model.onDidValidateVersion(listener).

---

Duplicate comments:
In `@projects/core/src/tooltip/tooltip.test.lighthouse.ts`:
- Line 20: The JS payload threshold in tooltip.test.lighthouse.ts (the assertion
on report.payload.javascript.kb) was raised without documentation; either revert
the numeric change or replace the magic number with a named constant (e.g.,
JS_PAYLOAD_KB_BUDGET) and add a short regression note/comment in the test that
states the reason, baseline value/date/measurement link, and reviewer who
approved the bump; update the test to use the named constant in
expect(report.payload.javascript.kb).toBeLessThan(JS_PAYLOAD_KB_BUDGET) so
future readers can see why the budget was increased.

In `@projects/forms/src/internal/schema.ts`:
- Around line 176-178: The code currently returns JSON.parse(value) for the
'array' and 'object' branches which can throw and violate the expected T |
undefined contract; update the branches handling 'array' and 'object' to wrap
JSON.parse(value) in a try/catch, returning the parsed value on success and
undefined on any JSON.parse error (optionally log/contextualize the error) so
callers receive undefined instead of an uncaught exception.
- Around line 179-180: The enum case currently uses schema.enum.includes(value)
which fails when form inputs are strings but enum members are numbers; update
the 'enum' branch in the parser to find a matching enum member by comparing
String(member) === String(value) (or coerce value to number if all enum members
are numeric), then return the matched enum member (not the raw input) cast to T;
locate the case 'enum' block that references schema.enum.includes(value) and
replace it with a lookup that returns the actual enum element when a stringified
match is found.
- Around line 174-175: The boolean branch (case 'boolean') incorrectly uses
"!!value" which treats any non-empty string like "false" as true; update the
branch to explicitly handle boolean and string inputs: if typeof value ===
'boolean' return value, else if value === 'true' return true, else if value ===
'false' return false, otherwise fall back to Boolean(value) or false as the
desired default. Ensure you replace the current return (!!value || value ===
'true') as T with these explicit checks referencing the same case 'boolean',
value variable, and T generic.

In `@projects/internals/tools/src/examples/utils.ts`:
- Around line 158-173: countTagDelta is recompiling three tag regexes per line
and interpolates raw tag text; modify findBlockEnd to escape the tag once (e.g.,
via a safe escape function), precompile the three RegExp objects (open,
selfClose, close) there, and either pass those RegExp instances into
countTagDelta (change its signature) or inline the counting logic in
findBlockEnd; keep the isSelfContainedBlock check intact and ensure behavior of
countTagDelta(openRegex, selfCloseRegex, closeRegex, line) matches the original
opens - selfCloses - closes result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: ea5b9426-3e20-4cb8-a226-6f4445217387

📥 Commits

Reviewing files that changed from the base of the PR and between 0d392b5 and 0086e2c.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • patches/monaco-editor.patch
  • projects/core/src/button-group/button-group.ts
  • projects/core/src/format-relative-time/format-relative-time.ts
  • projects/core/src/forms/validation.examples.ts
  • projects/core/src/internal/utils/objects.ts
  • projects/core/src/tooltip/tooltip.test.lighthouse.ts
  • projects/forms/src/internal/schema.ts
  • projects/internals/eslint/src/configs/typescript.js
  • projects/internals/metadata/src/tasks/wireit.utils.ts
  • projects/internals/tools/src/examples/utils.ts
  • projects/lint/src/eslint/internals/utils.ts
  • projects/lint/src/eslint/rules/no-missing-control-label.ts
  • projects/lint/src/eslint/rules/no-nested-container-types.test.ts
  • projects/lint/src/eslint/rules/no-nested-container-types.ts
  • projects/monaco/src/internal/base/input.test.ts
  • projects/monaco/src/internal/base/input.ts
  • projects/monaco/src/internal/formats/problems-format.ts
  • projects/monaco/src/problems/problems.ts
  • projects/site/src/_internal/search/search.ts
  • projects/site/src/_internal/theme-preview/theme-preview.ts
💤 Files with no reviewable changes (1)
  • projects/core/src/forms/validation.examples.ts

Comment thread projects/core/src/button-group/button-group.ts
Comment on lines +172 to +173
case 'number':
return parseFloat(value) as T;
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 | ⚡ Quick win

Handle invalid numeric input by returning undefined instead of NaN.

parseFloat returns NaN for invalid input (e.g., "abc"), which violates the T | undefined contract. Callers expecting undefined for parse failures won't catch NaN, allowing invalid values to propagate.

🛡️ Proposed fix
     case 'number':
-      return parseFloat(value) as T;
+      const num = parseFloat(value);
+      return (Number.isNaN(num) ? undefined : num) as T;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case 'number':
return parseFloat(value) as T;
case 'number':
const num = parseFloat(value);
return (Number.isNaN(num) ? undefined : num) as T;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` around lines 172 - 173, The number
branch in the parser (case 'number' in projects/forms/src/internal/schema.ts)
currently returns parseFloat(value) which yields NaN for invalid input; change
it to parseFloat the value into a temp variable, check Number.isNaN(result) and
return undefined on failure, otherwise return the parsed number cast to T so the
function adheres to the T | undefined contract.

@coryrylan coryrylan force-pushed the topic-lint-fixup-5 branch 2 times, most recently from 298e0d8 to 5e95aa1 Compare April 30, 2026 01:35
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: 2

Caution

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

⚠️ Outside diff range comments (3)
projects/core/src/button-group/button-group.ts (1)

48-48: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix typo in JSDoc comment.

The word "selction" should be "selection".

📝 Proposed fix
-  /** By default the button group is stateless. Add the `behavior-select` attribute and set to `single` or `multi` to enable stateful selction handling. */
+  /** By default the button group is stateless. Add the `behavior-select` attribute and set to `single` or `multi` to enable stateful selection handling. */

As per coding guidelines, "Follow Google developer documentation style guide and write-good rules for prose linting using Vale on JSDoc comments."

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

In `@projects/core/src/button-group/button-group.ts` at line 48, Fix the typo in
the JSDoc above the ButtonGroup implementation: change "selction" to "selection"
in the comment that reads "By default the button group is stateless. Add the
`behavior-select` attribute and set to `single` or `multi` to enable stateful
selction handling." Update the JSDoc in
projects/core/src/button-group/button-group.ts (the JSDoc for the ButtonGroup
class) so it reads "selection" to comply with style/linting rules.
patches/monaco-editor.patch (2)

241-253: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Delayer.cancel() now leaves pending work unresolved.

Removing the reject path makes canceled completionPromise instances potentially never settle, which can hang awaiters and retain resources longer than intended.

Proposed fix
 if (this.completionPromise) {
-    // this.doReject?.(new CancellationError());
+    this.doReject?.(new CancellationError());
     this.completionPromise = null;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patches/monaco-editor.patch` around lines 241 - 253, The patch removed
calling this.doReject(new CancellationError()) in Delayer.cancel(), which leaves
completionPromise unresolved and can hang awaiters; restore proper settlement by
reintroducing the rejection: call this.doReject?.(new CancellationError())
before clearing this.completionPromise (and ensure any rejection is safe to
observe where callers await it). Update the Delayer.cancel() implementation
(references: Delayer.cancel, this.doReject, this.completionPromise,
CancellationError) so canceled promises are rejected with CancellationError and
then set completionPromise = null to avoid leaking unresolved promises.

804-805: ⚠️ Potential issue | 🔴 Critical

Use the correct model event API (onDidValidateVersion).

This code subscribes via model.onDidValidateModelVersion(...), but the model event added in this patch is onDidValidateVersion(...). At runtime, this will fail with a "is not a function" error.

Proposed fix
 export function onDidValidateModelVersion(model, listener) {
-    return model.onDidValidateModelVersion(listener);
+    return model.onDidValidateVersion(listener);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patches/monaco-editor.patch` around lines 804 - 805, The exported helper
onDidValidateModelVersion is calling a non-existent API; update it to subscribe
to the correct model event by replacing the call to
model.onDidValidateModelVersion(...) with model.onDidValidateVersion(...);
ensure the function name onDidValidateModelVersion remains as the exported
symbol but uses model.onDidValidateVersion(listener) so runtime will not error.
♻️ Duplicate comments (2)
projects/site/src/_internal/search/search.ts (1)

226-229: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix eviction guard for empty-string cache keys.

This issue was already flagged in a previous review: the truthiness check on Line 227 will skip deletion when the oldest cache key is an empty string (''), causing the cache to exceed CACHE_MAX_SIZE. Since input.value is passed directly to search() without validation, empty strings are valid cache keys.

🔧 Recommended fix (from previous review)
   `#evictOldestCacheEntryIfFull`() {
     if (this.#searchCache.size < DocsSearch.CACHE_MAX_SIZE) {
       return;
     }
-    const firstCacheKey = this.#searchCache.keys().next().value;
-    if (firstCacheKey) {
-      this.#searchCache.delete(firstCacheKey);
-    }
+    const firstEntry = this.#searchCache.keys().next();
+    if (!firstEntry.done) {
+      this.#searchCache.delete(firstEntry.value);
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/site/src/_internal/search/search.ts` around lines 226 - 229, The
eviction guard skips deletion when the oldest cache key is an empty string
because it checks truthiness; update the logic in the block that computes
firstCacheKey (used with this.#searchCache.delete) to test for presence
explicitly (e.g., check iterator result.done or compare firstCacheKey !==
undefined) so empty-string keys are treated as valid and the oldest entry is
removed when cache exceeds CACHE_MAX_SIZE; this change should be applied where
firstCacheKey is computed and used in the search() / `#searchCache` eviction code.
projects/core/src/internal/utils/objects.ts (1)

38-38: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Prefer direct assignment over Object.assign for a single key.

This can be simplified to target[key] = sourceValue; to avoid creating a temporary object.

Proposed simplification
-    Object.assign(target, { [key]: sourceValue });
+    target[key] = sourceValue;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/core/src/internal/utils/objects.ts` at line 38, Replace the
single-key Object.assign usage with a direct property set to avoid creating a
temporary object: change the call to Object.assign(target, { [key]: sourceValue
}) to assign the value directly via target[key] = sourceValue; locate the
occurrence where Object.assign is used with a single computed key (the
Object.assign call shown) and update it to use direct assignment to target using
the same key and sourceValue variables.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@projects/site/src/_internal/search/search.ts`:
- Around line 222-230: Add a JSDoc comment above the private helper
`#evictOldestCacheEntryIfFull` describing that it implements FIFO eviction using
Map insertion order, that it removes the oldest entry when
this.#searchCache.size >= DocsSearch.CACHE_MAX_SIZE, that it has no inputs and
returns void, and note constraints/side-effects (mutates this.#searchCache and
relies on Map iteration order) so callers understand behavior and limits.

In `@projects/site/src/_internal/theme-preview/theme-preview.ts`:
- Around line 40-46: Add a JSDoc comment above the helper function
collectCustomPropertiesFromRule explaining its purpose (extracts CSS custom
properties from a CSSStyleRule), describing parameters (rule: CSSStyleRule,
target: Map<string,string>), and documenting side effects (mutates the provided
target Map by setting property names to trimmed values). Also note that it only
considers properties starting with '--' and that values are trimmed, and mention
expected types to aid maintainability and IDE tooling.

---

Outside diff comments:
In `@patches/monaco-editor.patch`:
- Around line 241-253: The patch removed calling this.doReject(new
CancellationError()) in Delayer.cancel(), which leaves completionPromise
unresolved and can hang awaiters; restore proper settlement by reintroducing the
rejection: call this.doReject?.(new CancellationError()) before clearing
this.completionPromise (and ensure any rejection is safe to observe where
callers await it). Update the Delayer.cancel() implementation (references:
Delayer.cancel, this.doReject, this.completionPromise, CancellationError) so
canceled promises are rejected with CancellationError and then set
completionPromise = null to avoid leaking unresolved promises.
- Around line 804-805: The exported helper onDidValidateModelVersion is calling
a non-existent API; update it to subscribe to the correct model event by
replacing the call to model.onDidValidateModelVersion(...) with
model.onDidValidateVersion(...); ensure the function name
onDidValidateModelVersion remains as the exported symbol but uses
model.onDidValidateVersion(listener) so runtime will not error.

In `@projects/core/src/button-group/button-group.ts`:
- Line 48: Fix the typo in the JSDoc above the ButtonGroup implementation:
change "selction" to "selection" in the comment that reads "By default the
button group is stateless. Add the `behavior-select` attribute and set to
`single` or `multi` to enable stateful selction handling." Update the JSDoc in
projects/core/src/button-group/button-group.ts (the JSDoc for the ButtonGroup
class) so it reads "selection" to comply with style/linting rules.

---

Duplicate comments:
In `@projects/core/src/internal/utils/objects.ts`:
- Line 38: Replace the single-key Object.assign usage with a direct property set
to avoid creating a temporary object: change the call to Object.assign(target, {
[key]: sourceValue }) to assign the value directly via target[key] =
sourceValue; locate the occurrence where Object.assign is used with a single
computed key (the Object.assign call shown) and update it to use direct
assignment to target using the same key and sourceValue variables.

In `@projects/site/src/_internal/search/search.ts`:
- Around line 226-229: The eviction guard skips deletion when the oldest cache
key is an empty string because it checks truthiness; update the logic in the
block that computes firstCacheKey (used with this.#searchCache.delete) to test
for presence explicitly (e.g., check iterator result.done or compare
firstCacheKey !== undefined) so empty-string keys are treated as valid and the
oldest entry is removed when cache exceeds CACHE_MAX_SIZE; this change should be
applied where firstCacheKey is computed and used in the search() / `#searchCache`
eviction code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 1a92748a-fb1e-4191-a5db-0ab71443bcc7

📥 Commits

Reviewing files that changed from the base of the PR and between 0086e2c and 298e0d8.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • patches/monaco-editor.patch
  • projects/core/src/button-group/button-group.ts
  • projects/core/src/format-relative-time/format-relative-time.ts
  • projects/core/src/forms/validation.examples.ts
  • projects/core/src/internal/utils/objects.ts
  • projects/core/src/tooltip/tooltip.test.lighthouse.ts
  • projects/forms/src/internal/schema.ts
  • projects/internals/eslint/src/configs/typescript.js
  • projects/internals/metadata/src/tasks/wireit.utils.ts
  • projects/internals/tools/src/examples/utils.ts
  • projects/lint/src/eslint/internals/utils.ts
  • projects/lint/src/eslint/rules/no-missing-control-label.ts
  • projects/lint/src/eslint/rules/no-nested-container-types.test.ts
  • projects/lint/src/eslint/rules/no-nested-container-types.ts
  • projects/monaco/src/internal/base/input.test.ts
  • projects/monaco/src/internal/base/input.ts
  • projects/monaco/src/internal/formats/problems-format.ts
  • projects/monaco/src/problems/problems.ts
  • projects/site/src/_internal/search/search.ts
  • projects/site/src/_internal/theme-preview/theme-preview.ts
💤 Files with no reviewable changes (1)
  • projects/core/src/forms/validation.examples.ts

Comment thread projects/site/src/_internal/search/search.ts
Comment thread projects/site/src/_internal/theme-preview/theme-preview.ts
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: 2

Caution

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

⚠️ Outside diff range comments (2)
patches/monaco-editor.patch (2)

241-253: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Delayer.cancel() must still settle the pending promise.

Line 241 previously rejected the pending completion promise; removing that settlement path causes callers awaiting the returned promise to hang indefinitely after cancellation.

Suggested fix
-            // this.doReject?.(new CancellationError());
+            this.doResolve?.(undefined);
             this.completionPromise = null;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patches/monaco-editor.patch` around lines 241 - 253, The change removed
settling the pending promise in Delayer.cancel(), causing callers awaiting
completionPromise to hang; restore promise settlement by calling the appropriate
resolver instead of throwing: in the Delayer.cancel() implementation (look for
methods named cancel, this.doReject, this.doResolve, and the completionPromise
field), call this.doResolve?.(undefined) (or otherwise resolve the pending
completionPromise with a neutral value) before setting this.completionPromise =
null so the promise always settles on cancel while preserving the new behavior
of not treating cancellation as an exception.

804-806: ⚠️ Potential issue | 🟠 Major

onDidValidateModelVersion calls the wrong model method and will fail at runtime.

The patch defines onDidValidateVersion on the model (line 767 interface, line 567 implementation), but the exported function tries to call model.onDidValidateModelVersion(listener) which doesn't exist.

Suggested fix
 export function onDidValidateModelVersion(model, listener) {
-    return model.onDidValidateModelVersion(listener);
+    return model.onDidValidateVersion(listener);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@patches/monaco-editor.patch` around lines 804 - 806, The exported function
onDidValidateModelVersion calls a non-existent model method; change it to call
the actual implementation name onDidValidateVersion on the model (i.e., return
model.onDidValidateVersion(listener)), or rename the model method to
onDidValidateModelVersion so both names match; update the export in
onDidValidateModelVersion to reference the exact method name used by the model
implementation.
♻️ Duplicate comments (8)
projects/core/src/tooltip/tooltip.test.lighthouse.ts (1)

20-20: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document or revert the increased JS payload budget.

Line 20 raises the allowed JS size to 14.6 KB without test-local rationale, which can hide a real bundle regression. Please either revert to the previous threshold or add a measured justification (baseline/date/link) in the test.

Suggested guardrail update
-    expect(report.payload.javascript.kb).toBeLessThan(14.6);
+    // Baseline measured on YYYY-MM-DD in CI: X KB (see PR/issue: <link>)
+    const JS_PAYLOAD_KB_LIMIT = 14.4;
+    expect(report.payload.javascript.kb).toBeLessThan(JS_PAYLOAD_KB_LIMIT);

As per coding guidelines, "Review /projects/site/src/docs/internal/guidelines/testing-lighthouse.md before writing performance tests; verify performance, accessibility, and best practices scoring."

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

In `@projects/core/src/tooltip/tooltip.test.lighthouse.ts` at line 20, The test
raises the JS budget by asserting
expect(report.payload.javascript.kb).toBeLessThan(14.6) which lacks a documented
baseline; either revert that numeric threshold to the prior value (restore the
previous limit used before this change) or keep 14.6 but add an inline
justification comment in the tooltip.test.lighthouse.ts test referencing the
measurement details (baseline value, date, and a link or commit id) so future
reviewers can verify the increase—update the assertion line’s surrounding test
(the code that reads report.payload.javascript.kb) accordingly.
projects/internals/tools/src/examples/utils.ts (1)

158-173: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Precompute and escape tag regexes once per block scan.

countTagDelta recompiles three regexes per scanned line, which adds avoidable allocation churn in findBlockEnd. Build escaped regexes once per findBlockEnd call and pass them into countTagDelta.

♻️ Proposed fix
+function escapeRegex(value: string): string {
+  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+
+function buildTagRegex(tag: string): { open: RegExp; selfClose: RegExp; close: RegExp } {
+  const safeTag = escapeRegex(tag);
+  return {
+    open: new RegExp(`<${safeTag}[\\s>]`, 'g'),
+    selfClose: new RegExp(`<${safeTag}[^>]*/>`, 'g'),
+    close: new RegExp(`</${safeTag}>`, 'g')
+  };
+}
+
-function countTagDelta(line: string, tag: string): number {
-  const opens = (line.match(new RegExp(`<${tag}[\\s>]`, 'g')) || []).length;
-  const selfCloses = (line.match(new RegExp(`<${tag}[^>]*/>`, 'g')) || []).length;
-  const closes = (line.match(new RegExp(`</${tag}>`, 'g')) || []).length;
+function countTagDelta(line: string, regex: { open: RegExp; selfClose: RegExp; close: RegExp }): number {
+  const opens = (line.match(regex.open) || []).length;
+  const selfCloses = (line.match(regex.selfClose) || []).length;
+  const closes = (line.match(regex.close) || []).length;
   return opens - selfCloses - closes;
 }
 
 function findBlockEnd(lines: string[], start: number, tag: string): number {
   if (isSelfContainedBlock(lines[start]!, tag)) {
     return start;
   }
 
+  const regex = buildTagRegex(tag);
   let depth = 1;
   for (let i = start + 1; i < lines.length; i++) {
-    depth += countTagDelta(lines[i]!, tag);
+    depth += countTagDelta(lines[i]!, regex);
     if (depth <= 0) {
       return i;
     }
   }
#!/bin/bash
# Verify current hotspot and call path for repeated regex construction.
# Expected: three `new RegExp` calls in `countTagDelta`, and `findBlockEnd` invoking it in a loop.
rg -n -C2 'function countTagDelta|new RegExp|function findBlockEnd|depth \+= countTagDelta' projects/internals/tools/src/examples/utils.ts
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/internals/tools/src/examples/utils.ts` around lines 158 - 173,
countTagDelta currently creates three RegExp objects per line; change
findBlockEnd to build the escaped tag string and compile the three regexes once
(e.g., openRe, selfCloseRe, closeRe) before the loop (use a proper escape for
the tag), then update countTagDelta to accept those precompiled RegExp instances
(or inline its logic into findBlockEnd) and use them inside the loop, keeping
the existing behavior and continuing to call isSelfContainedBlock(lines[start],
tag) where needed.
projects/forms/src/internal/schema.ts (4)

172-173: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle invalid numeric input by returning undefined instead of NaN.

parseFloat returns NaN for invalid input (e.g., "abc"), which violates the T | undefined contract and allows invalid values to propagate to callers expecting undefined for parse failures.

🛡️ Proposed fix
     case 'number':
-      return parseFloat(value) as T;
+      const num = parseFloat(value);
+      return (Number.isNaN(num) ? undefined : num) as T;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` around lines 172 - 173, The 'case
"number"' branch currently returns parseFloat(value) as T which yields NaN on
invalid input; change it to parse the value into a number (e.g., const n =
parseFloat(value)), then if Number.isNaN(n) return undefined as T | undefined,
otherwise return n as T so invalid numeric input yields undefined instead of
NaN; update the branch replacing the direct parseFloat(...) return with this
NaN-check flow.

179-180: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enum parsing fails for numeric enum values from string form inputs.

Form input is always a string, so schema.enum.includes(value) won't match numeric enum members (e.g., the string "1" won't match the number 1 in the enum array).

🛡️ Proposed fix
     case 'enum':
-      return (schema.enum.includes(value) ? value : undefined) as T;
+      if (schema.enum.includes(value)) return value as T;
+      const numericValue = Number(value);
+      return (Number.isNaN(numericValue) ? undefined : schema.enum.includes(numericValue) ? numericValue : undefined) as T;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` around lines 179 - 180, The enum
branch currently checks schema.enum.includes(value) which fails when form inputs
are strings but enum members are numbers; update the 'case "enum"' logic
(referencing the switch case handling 'enum', the variables schema.enum and
value) to match by comparing stringified members to the input (e.g., find a
member where String(member) === String(value)) and return that matched enum
member (cast to T) or undefined if none match; this ensures numeric enum values
represented as strings from forms are correctly recognized.

176-178: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Handle invalid JSON input instead of throwing raw parse errors.

JSON.parse(value) throws on malformed JSON, bypassing the T | undefined contract and causing unhandled exceptions in callers expecting undefined to signal parse failure.

🛡️ Proposed fix
     case 'array':
     case 'object':
-      return JSON.parse(value) as T;
+      try {
+        return JSON.parse(value) as T;
+      } catch {
+        return undefined;
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` around lines 176 - 178, The switch
branch that handles 'array' and 'object' currently does "return
JSON.parse(value) as T" which throws on malformed JSON; wrap the parse in a
try/catch inside the same function (the branch handling case 'array' / case
'object') so that on successful parse you return the parsed value cast to T and
on any parse error you return undefined (or the expected failure sentinel)
instead of letting the raw exception propagate; use the existing variable names
(value) and keep the same return type T | undefined.

174-175: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Boolean parsing is incorrect for "false" input.

!!value coerces any non-empty string to true, so the string "false" incorrectly parses as true.

🐛 Proposed fix
     case 'boolean':
-      return (!!value || value === 'true') as T;
+      if (value === 'true') return true as T;
+      if (value === 'false') return false as T;
+      return undefined;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/forms/src/internal/schema.ts` around lines 174 - 175, The boolean
parsing branch (case 'boolean' in internal/schema.ts) wrongly treats any
non-empty string like "false" as true due to !!value; update the branch to
explicitly detect truth by checking if the input is the boolean true or if its
string representation lowercased equals "true" (avoid using coercion like
!!value); change the return logic in the case 'boolean' branch to perform these
explicit comparisons so "false" parses to false and "true" parses to true.
projects/monaco/src/problems/problems.ts (1)

211-224: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear ready state when resetting disposed editor state.

After disposal, Line 211–224 clears Monaco references but leaves _internals.states still advertising ready.

Suggested fix
   `#resetEditorState`() {
     this.#monaco = undefined;
     this.#editor = undefined;
     this.#model = undefined;
@@
     this.#selectedLineNumber = undefined;
     this.#downLineNumber = undefined;
 
     this.#getProblemByLine = undefined;
+    this._internals.states.delete('ready');
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/monaco/src/problems/problems.ts` around lines 211 - 224, The reset
routine `#resetEditorState` clears Monaco references but doesn't update the
internal readiness flag, leaving _internals.states.ready true after disposal;
update `#resetEditorState` to explicitly clear or set _internals.states.ready to
false (or reset the entire _internals.states object) so the editor is no longer
advertised as ready when disposed, ensuring any code that checks
_internals.states.ready observes the disposed state.
projects/monaco/src/internal/base/input.ts (1)

454-469: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Required-empty validation path should clear pending state before returning.

Line 454–457 can leave :state(validating) set from prior pending syntax validation, and returns before firing syntax-validation-changed.

Suggested fix
   `#handleValidationVersion`(model: monaco.editor.ITextModel, versionId: number) {
@@
     if (this.#isRequiredAndEmpty()) {
+      this.#clearValidation();
       this.#setRequiredValidationError();
+      this.dispatchEvent(new CustomEvent('syntax-validation-changed', { bubbles: true, composed: true }));
       return;
     }
@@
     this.dispatchEvent(new CustomEvent('syntax-validation-changed', { bubbles: true, composed: true }));
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@projects/monaco/src/internal/base/input.ts` around lines 454 - 469, The
required-empty branch in the validation flow can return while a prior
":state(validating)" remains set and no 'syntax-validation-changed' event is
dispatched; fix by clearing pending validation state and emitting the change
before returning: call the instance method `#clearValidation`() (or otherwise
clear the validating state) immediately before or after invoking
`#setRequiredValidationError`(), and ensure the existing dispatchEvent(new
CustomEvent('syntax-validation-changed', ...)) is executed on that path so
`#isRequiredAndEmpty`(), `#setRequiredValidationError`(), `#clearValidation`(), and
dispatchEvent are all used to reset state and notify listeners prior to the
early return.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@projects/internals/metadata/src/tasks/wireit.utils.ts`:
- Around line 98-107: Add a short JSDoc for the addDependency helper that
documents expected input types, its behavior and side-effects: state that first
param dep is expected to be a string or string-like dependency spec parsed by
parseDependency, second param script is an object with packagePath: string and
dependencies: string[] which will be mutated (script.dependencies will be
appended with `${packagePath}:${scriptName}`), and third param key is a
diagnostic string used in error logs; also note that the function swallows parse
errors and logs err.message. Place the JSDoc immediately above function
addDependency and reference parseDependency, script.dependencies mutation, and
the error logging behavior in the docstring.
- Line 105: Replace the interpolated console.error in wireit.utils.ts with
structured logging that emits fields for the dependency key and the full error
(message and stack) so parse failures are easily queryable; locate the call that
currently does console.error(`error parsing dependency in ${key}:`, (err as
Error).message) and change it to use the project's structured logger (e.g.,
logger.error or processLogger.error) and include properties like { event:
"dependency_parse_failure", key, error: err } or equivalent so both key and full
error details are recorded.

---

Outside diff comments:
In `@patches/monaco-editor.patch`:
- Around line 241-253: The change removed settling the pending promise in
Delayer.cancel(), causing callers awaiting completionPromise to hang; restore
promise settlement by calling the appropriate resolver instead of throwing: in
the Delayer.cancel() implementation (look for methods named cancel,
this.doReject, this.doResolve, and the completionPromise field), call
this.doResolve?.(undefined) (or otherwise resolve the pending completionPromise
with a neutral value) before setting this.completionPromise = null so the
promise always settles on cancel while preserving the new behavior of not
treating cancellation as an exception.
- Around line 804-806: The exported function onDidValidateModelVersion calls a
non-existent model method; change it to call the actual implementation name
onDidValidateVersion on the model (i.e., return
model.onDidValidateVersion(listener)), or rename the model method to
onDidValidateModelVersion so both names match; update the export in
onDidValidateModelVersion to reference the exact method name used by the model
implementation.

---

Duplicate comments:
In `@projects/core/src/tooltip/tooltip.test.lighthouse.ts`:
- Line 20: The test raises the JS budget by asserting
expect(report.payload.javascript.kb).toBeLessThan(14.6) which lacks a documented
baseline; either revert that numeric threshold to the prior value (restore the
previous limit used before this change) or keep 14.6 but add an inline
justification comment in the tooltip.test.lighthouse.ts test referencing the
measurement details (baseline value, date, and a link or commit id) so future
reviewers can verify the increase—update the assertion line’s surrounding test
(the code that reads report.payload.javascript.kb) accordingly.

In `@projects/forms/src/internal/schema.ts`:
- Around line 172-173: The 'case "number"' branch currently returns
parseFloat(value) as T which yields NaN on invalid input; change it to parse the
value into a number (e.g., const n = parseFloat(value)), then if Number.isNaN(n)
return undefined as T | undefined, otherwise return n as T so invalid numeric
input yields undefined instead of NaN; update the branch replacing the direct
parseFloat(...) return with this NaN-check flow.
- Around line 179-180: The enum branch currently checks
schema.enum.includes(value) which fails when form inputs are strings but enum
members are numbers; update the 'case "enum"' logic (referencing the switch case
handling 'enum', the variables schema.enum and value) to match by comparing
stringified members to the input (e.g., find a member where String(member) ===
String(value)) and return that matched enum member (cast to T) or undefined if
none match; this ensures numeric enum values represented as strings from forms
are correctly recognized.
- Around line 176-178: The switch branch that handles 'array' and 'object'
currently does "return JSON.parse(value) as T" which throws on malformed JSON;
wrap the parse in a try/catch inside the same function (the branch handling case
'array' / case 'object') so that on successful parse you return the parsed value
cast to T and on any parse error you return undefined (or the expected failure
sentinel) instead of letting the raw exception propagate; use the existing
variable names (value) and keep the same return type T | undefined.
- Around line 174-175: The boolean parsing branch (case 'boolean' in
internal/schema.ts) wrongly treats any non-empty string like "false" as true due
to !!value; update the branch to explicitly detect truth by checking if the
input is the boolean true or if its string representation lowercased equals
"true" (avoid using coercion like !!value); change the return logic in the case
'boolean' branch to perform these explicit comparisons so "false" parses to
false and "true" parses to true.

In `@projects/internals/tools/src/examples/utils.ts`:
- Around line 158-173: countTagDelta currently creates three RegExp objects per
line; change findBlockEnd to build the escaped tag string and compile the three
regexes once (e.g., openRe, selfCloseRe, closeRe) before the loop (use a proper
escape for the tag), then update countTagDelta to accept those precompiled
RegExp instances (or inline its logic into findBlockEnd) and use them inside the
loop, keeping the existing behavior and continuing to call
isSelfContainedBlock(lines[start], tag) where needed.

In `@projects/monaco/src/internal/base/input.ts`:
- Around line 454-469: The required-empty branch in the validation flow can
return while a prior ":state(validating)" remains set and no
'syntax-validation-changed' event is dispatched; fix by clearing pending
validation state and emitting the change before returning: call the instance
method `#clearValidation`() (or otherwise clear the validating state) immediately
before or after invoking `#setRequiredValidationError`(), and ensure the existing
dispatchEvent(new CustomEvent('syntax-validation-changed', ...)) is executed on
that path so `#isRequiredAndEmpty`(), `#setRequiredValidationError`(),
`#clearValidation`(), and dispatchEvent are all used to reset state and notify
listeners prior to the early return.

In `@projects/monaco/src/problems/problems.ts`:
- Around line 211-224: The reset routine `#resetEditorState` clears Monaco
references but doesn't update the internal readiness flag, leaving
_internals.states.ready true after disposal; update `#resetEditorState` to
explicitly clear or set _internals.states.ready to false (or reset the entire
_internals.states object) so the editor is no longer advertised as ready when
disposed, ensuring any code that checks _internals.states.ready observes the
disposed state.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: e8d2e033-da24-4a00-9b8f-4bbbef0c7625

📥 Commits

Reviewing files that changed from the base of the PR and between 298e0d8 and 5e95aa1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (20)
  • patches/monaco-editor.patch
  • projects/core/src/button-group/button-group.ts
  • projects/core/src/format-relative-time/format-relative-time.ts
  • projects/core/src/forms/validation.examples.ts
  • projects/core/src/internal/utils/objects.ts
  • projects/core/src/tooltip/tooltip.test.lighthouse.ts
  • projects/forms/src/internal/schema.ts
  • projects/internals/eslint/src/configs/typescript.js
  • projects/internals/metadata/src/tasks/wireit.utils.ts
  • projects/internals/tools/src/examples/utils.ts
  • projects/lint/src/eslint/internals/utils.ts
  • projects/lint/src/eslint/rules/no-missing-control-label.ts
  • projects/lint/src/eslint/rules/no-nested-container-types.test.ts
  • projects/lint/src/eslint/rules/no-nested-container-types.ts
  • projects/monaco/src/internal/base/input.test.ts
  • projects/monaco/src/internal/base/input.ts
  • projects/monaco/src/internal/formats/problems-format.ts
  • projects/monaco/src/problems/problems.ts
  • projects/site/src/_internal/search/search.ts
  • projects/site/src/_internal/theme-preview/theme-preview.ts
💤 Files with no reviewable changes (1)
  • projects/core/src/forms/validation.examples.ts

Comment thread projects/internals/metadata/src/tasks/wireit.utils.ts
Comment thread projects/internals/metadata/src/tasks/wireit.utils.ts
@coryrylan coryrylan force-pushed the topic-lint-fixup-5 branch 3 times, most recently from e6746bc to 427accc Compare April 30, 2026 03:13
const value = Math.round(absDiff / divisor);
if (value < max) return { value: sign * value, unit };
}
return { value: sign * Math.round(absDiff / 31536000000), unit: 'year' };
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Might just be me, but it's odd to see hoisting to a const THRESHOLDS lookup that omits one unit expressed in the type union and specifying that omitted unit inline.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Refactored this a bit split out the divisors

onMouseLeaveListener,
hoverProvider
];
for (const d of disposables) d.dispose();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This looks like an LLM was trying to work around the lint limits and produced something silly.

Likely the better (and symmetrical!) refactor would be to break out the listener registration like was done in monaco/src/internal/base/input.ts in this changeset?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Fixed, no idea why it did this. There was no line violation.

Copy link
Copy Markdown
Collaborator

@johnyanarella johnyanarella left a comment

Choose a reason for hiding this comment

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

I can revisit that monaco/problems note later if this PR is a blocker.

@coryrylan coryrylan force-pushed the topic-lint-fixup-5 branch from 427accc to a87ddfa Compare April 30, 2026 22:22
- max-nested-callbacks
- max-statements
- max-depth

Signed-off-by: Cory Rylan <crylan@nvidia.com>
@coryrylan coryrylan force-pushed the topic-lint-fixup-5 branch from a87ddfa to cb5fb8b Compare April 30, 2026 22:45
@coryrylan coryrylan merged commit 9b5509f into main Apr 30, 2026
8 checks passed
@coryrylan coryrylan deleted the topic-lint-fixup-5 branch April 30, 2026 23:02
@coryrylan
Copy link
Copy Markdown
Collaborator Author

🎉 This issue has been resolved in version 0.2.0 🎉

Changelog

@coryrylan
Copy link
Copy Markdown
Collaborator Author

🎉 This issue has been resolved in version 0.0.8 🎉

Changelog

@coryrylan
Copy link
Copy Markdown
Collaborator Author

🎉 This issue has been resolved in version 0.0.12 🎉

Changelog

@coryrylan
Copy link
Copy Markdown
Collaborator Author

🎉 This issue has been resolved in version 0.0.8 🎉

Changelog

@coryrylan
Copy link
Copy Markdown
Collaborator Author

🎉 This issue has been resolved in version 0.0.8 🎉

Changelog

1 similar comment
@coryrylan
Copy link
Copy Markdown
Collaborator Author

🎉 This issue has been resolved in version 0.0.8 🎉

Changelog

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants