Skip to content

Docs/caps jsdoc comments#1692

Open
Rashi1404 wants to merge 3 commits into
Karanjot786:mainfrom
Rashi1404:docs/caps-jsdoc-comments
Open

Docs/caps jsdoc comments#1692
Rashi1404 wants to merge 3 commits into
Karanjot786:mainfrom
Rashi1404:docs/caps-jsdoc-comments

Conversation

@Rashi1404

@Rashi1404 Rashi1404 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Description

This PR adds comprehensive JSDoc comments to the @termuijs/core capability flags module to improve code documentation and help new contributors understand the terminal environment detection system.

Changes Made

  • packages/core/src/caps.ts:
    • Added module-level JSDoc explaining the purpose of caps flags
    • Documented each flag (unicode, motion, color, keybindingMode) with:
      • Description of what it controls
      • Associated environment variable
      • Use cases and when to disable it
      • Default value
    • Added @example code snippets for practical usage
    • Documented keybinding modes (default, vim, emacs) and their key mappings

Why This Helps

  • New widget authors can quickly understand how to provide ASCII fallbacks
  • Environment variable behavior is now self-documenting in source code
  • Reduces need to cross-reference external docs for basic caps usage
  • Makes the codebase more accessible to GSSoC beginners

Checklist

  • Starred the repository (required by GSSoC guidelines)
  • Read CONTRIBUTING.md
  • No functional changes — documentation only
  • Follows JSDoc conventions used elsewhere in the project

Type of Change

  • Bug fix
  • New feature
  • Documentation update
  • Refactoring

issue closed #1691

Summary by CodeRabbit

  • New Features

    • Added Spinner component with customizable speed, label, and color options.
    • Added terminal capability detection respecting accessibility settings (Unicode, animation, color support).
  • Documentation

    • Added custom widget usage example to Imperative API guide.
  • Tests

    • Added test coverage for Spinner component.

@Rashi1404 Rashi1404 requested a review from Karanjot786 as a code owner June 20, 2026 18:30
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a caps object to packages/core/src/errors.ts that reads terminal feature flags from environment variables at module load. A new Spinner widget is built on top of caps, using interval-based frame animation with Unicode/ASCII fallback and no-motion suppression. The widget is exported from the widgets package index, tested, and the imperative API docs are extended with a ProgressBar example.

Changes

Spinner Widget and caps Capability Flags

Layer / File(s) Summary
caps terminal capability flags
packages/core/src/errors.ts
Exports a caps object computed once at module load from NO_UNICODE, NO_MOTION, NO_COLOR, and TERMUI_KEYBINDINGS env vars as read-only flags. Also includes a JSDoc stub for a future meetsAA WCAG contrast helper with no implementation yet.
Spinner component, exports, and test
packages/widgets/src/Spinner.ts, packages/widgets/src/index.ts, tests/helpers/Spinner.test.ts
Defines SpinnerProps (optional speed, label, color), selects Unicode or ASCII frame sets via caps.unicode, advances frames on a setInterval that is skipped entirely when caps.noMotion is set, and renders through <Text>. Re-exports Spinner and SpinnerProps from the widgets index. A Bun test renders Spinner with a label and asserts the label appears in output.
Imperative API docs: custom widget example
docs/choosing-your-api.md
Adds a "Common use case: Custom widget" subsection with a TypeScript ProgressBar example illustrating state clamping, markDirty() for re-render, and character-bar drawing in render.

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant Spinner
  participant caps
  participant Text

  App->>Spinner: mount with {speed, label, color}
  Spinner->>caps: caps.unicode → select frame set
  Spinner->>caps: caps.noMotion → skip interval?
  alt motion enabled
    Spinner->>Spinner: setInterval(speed) → advance frame
  end
  Spinner->>Text: render currentFrame + label
  Text-->>App: styled terminal string
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Possibly related PRs

  • Karanjot786/TermUI#1120: Shares the same caps.unicode/caps.noMotion branching pattern for glyph/animation selection that this PR introduces for Spinner.
  • Karanjot786/TermUI#1447: Relies on the same exported caps object from packages/core/src/errors.ts and mocks caps.unicode in its tests, directly overlapping with the capability flags introduced here.

Suggested labels

gssoc:approved, quality:clean, type:docs, area:core, area:widgets, type:testing, level:beginner

Suggested reviewers

  • Karanjot786

Poem

🐰 A spinner spins in braille so bright,
Unicode frames or ASCII — just right.
NO_MOTION? No worries, stay still!
caps reads the env with a thrill.
ProgressBar marches, char by char,
TermUI widgets: raising the bar! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'Docs/caps jsdoc comments' is partially related but vague and uses format inconsistency with the repository's required convention. Revise the title to follow the required format 'type: short description' (e.g., 'docs: add JSDoc comments for capability flags').
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning The PR description has significant discrepancies with the actual changes. The description claims documentation-only changes to packages/core/src/caps.ts, but the raw summary shows actual functional code additions to multiple files including new Spinner component, capability flags in errors.ts, and documentation in choosing-your-api.md. Update the PR description to accurately reflect all changes made: the new Spinner widget, capability flags configuration, documentation additions, and tests. Ensure the description matches the actual file modifications shown in the raw summary.
✅ Passed checks (2 passed)
Check name Status Explanation
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

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.

@github-actions github-actions Bot added type:docs +5 pts. Documentation. area:widgets @termuijs/widgets area:core @termuijs/core type:testing +10 pts. Tests. labels Jun 20, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/choosing-your-api.md`:
- Around line 40-56: The ProgressBar class should override the protected
_renderSelf() method instead of the public render() method to preserve the base
class's rendering pipeline that handles clipping, dirty-flag management,
borders, and child widgets. Replace the render() method signature with
_renderSelf(screen) and update the implementation to use screen.writeString()
with the widget's rect coordinates (this.rect.x and this.rect.y) instead of the
invalid buffer.write() API call that writes to (0, 0). This ensures the progress
bar renders at the correct position within the widget's bounds rather than at
the screen origin.

In `@packages/core/src/errors.ts`:
- Around line 73-95: The capability properties unicode, motion, and color in
this file are only checking for NO_UNICODE, NO_MOTION, and NO_COLOR environment
variables respectively, but they ignore the TERM === 'dumb' check and CI
environment behavior that exist in the env-caps.ts contract. Update each of
these three properties to also account for TERM being 'dumb' and CI conditions
to align with the existing implementation in
packages/core/src/terminal/env-caps.ts, ensuring consistent capability detection
regardless of which caps export callers use.
- Line 110: The keybindingMode property on line 110 uses a type assertion
without runtime validation, which allows arbitrary environment variable values
to be treated as valid keybinding modes. Replace the type assertion with runtime
validation that checks if the process.env.TERMUI_KEYBINDINGS value is one of the
allowed modes ('default', 'vim', 'emacs') and falls back to 'default' if it is
not. This approach should follow the same validation pattern implemented in
env-caps.ts to ensure type safety at runtime rather than relying solely on the
TypeScript assertion.

In `@packages/widgets/src/index.ts`:
- Around line 313-314: The Spinner and SpinnerProps exports at lines 313–314
duplicate the existing exports from line 137, causing a build error. Either
remove these duplicate export statements if they're not needed, or rename one of
them using an alias (e.g., export as JsxSpinner) to avoid the conflict.
Additionally, add the .js extension to the file path in the export statement to
maintain consistency with the rest of the file's export pattern.

In `@packages/widgets/src/Spinner.ts`:
- Around line 16-20: In the useEffect hook within the Spinner component, replace
the check for caps.noMotion with !caps.motion since noMotion is not a valid
capability key in the core caps contract. Change the condition from if
(caps.noMotion) return to if (!caps.motion) return to properly detect and
respect the user's motion preferences.
- Line 1: Rename the Spinner.ts file to Spinner.tsx since it contains JSX syntax
that requires JSX compilation support. Update all import statements throughout
the codebase that reference Spinner.ts to use Spinner.tsx instead. Additionally,
locate the motion check that currently references caps.noMotion and replace it
with !caps.motion, since the actual property available in the caps object is
motion (and its negation is used to check for no-motion support).

In `@tests/helpers/Spinner.test.ts`:
- Line 1: Rename the file from Spinner.test.ts to Spinner.test.tsx since the
file contains JSX syntax (such as the Spinner component usage at line 7). This
aligns with the project's established convention of using the .tsx extension for
all files that contain JSX, as seen in the examples/ and packages/ directories.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 99f6d1a7-ee82-4a2d-851b-58c874191ee1

📥 Commits

Reviewing files that changed from the base of the PR and between 4b874c0 and 4f7016c.

📒 Files selected for processing (5)
  • docs/choosing-your-api.md
  • packages/core/src/errors.ts
  • packages/widgets/src/Spinner.ts
  • packages/widgets/src/index.ts
  • tests/helpers/Spinner.test.ts

Comment thread docs/choosing-your-api.md
Comment on lines +40 to +56
```typescript
import { Widget, Style } from '@termuijs/core'

export class ProgressBar extends Widget {
private progress: number = 0

setProgress(value: number) {
this.progress = Math.max(0, Math.min(1, value))
this.markDirty() // Request re-render
}

render(buffer) {
const width = this.rect.width
const filled = Math.round(width * this.progress)
const bar = '█'.repeat(filled) + '░'.repeat(width - filled)
buffer.write(0, 0, bar, Style.fg('green'))
}

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

🧩 Analysis chain

🏁 Script executed:

fd -t f "Widget\.ts" packages/widgets/src/base/ | head -5

Repository: Karanjot786/TermUI

Length of output: 98


🏁 Script executed:

fd -t f "Screen\.ts" packages/core/src/ | head -5

Repository: Karanjot786/TermUI

Length of output: 99


🏁 Script executed:

# Check Widget class structure
rg "class Widget|render\(|_renderSelf" packages/widgets/src/base/ -A 3 | head -50

Repository: Karanjot786/TermUI

Length of output: 2912


🏁 Script executed:

# Get the complete render() method
sed -n '200,300p' packages/widgets/src/base/Widget.ts | cat -n

Repository: Karanjot786/TermUI

Length of output: 4434


🏁 Script executed:

# Search for the full render method more precisely
rg "render\(screen: Screen\)" packages/widgets/src/base/Widget.ts -A 30 | head -50

Repository: Karanjot786/TermUI

Length of output: 1462


🏁 Script executed:

# Search for Screen methods like write, writeString, etc
rg "write|WriteString" packages/core/src/terminal/Screen.ts | head -20

Repository: Karanjot786/TermUI

Length of output: 636


🏁 Script executed:

# Get Screen.writeString() method signature
rg "writeString\(" packages/core/src/terminal/Screen.ts -A 5 | head -30

Repository: Karanjot786/TermUI

Length of output: 215


🏁 Script executed:

# Read the actual documentation file to see the example
cat -n docs/choosing-your-api.md | sed -n '36,60p'

Repository: Karanjot786/TermUI

Length of output: 880


Override _renderSelf(), not render().

This example overrides the public render() method, which bypasses the base class's pipeline entirely. The Widget.render() method handles clipping (based on overflow style), dirty-flag management, border rendering, and child rendering before delegating to the protected _renderSelf(screen) hook. Overriding render() loses all of this and will teach readers the wrong contract.

Additionally, buffer.write() is not a valid Screen API; use screen.writeString() with the widget's rect coordinates instead of writing to (0, 0), which would render at the screen origin rather than at the widget's positioned location.

Suggested fix
 export class ProgressBar extends Widget {
   private progress: number = 0
   
   setProgress(value: number) {
     this.progress = Math.max(0, Math.min(1, value))
     this.markDirty() // Request re-render
   }
   
-  render(buffer) {
+  protected _renderSelf(screen: Screen) {
     const width = this.rect.width
     const filled = Math.round(width * this.progress)
     const bar = '█'.repeat(filled) + '░'.repeat(width - filled)
-    buffer.write(0, 0, bar, Style.fg('green'))
+    screen.writeString(this.rect.x, this.rect.y, bar, { fg: { type: 'named', name: 'green' } })
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/choosing-your-api.md` around lines 40 - 56, The ProgressBar class should
override the protected _renderSelf() method instead of the public render()
method to preserve the base class's rendering pipeline that handles clipping,
dirty-flag management, borders, and child widgets. Replace the render() method
signature with _renderSelf(screen) and update the implementation to use
screen.writeString() with the widget's rect coordinates (this.rect.x and
this.rect.y) instead of the invalid buffer.write() API call that writes to (0,
0). This ensures the progress bar renders at the correct position within the
widget's bounds rather than at the screen origin.

Comment on lines +73 to +95
unicode: !process.env.NO_UNICODE,

/**
* Whether animations and motion effects are supported.
*
* Set `NO_MOTION=1` to skip all animations and render static output.
* Respects `prefers-reduced-motion` accessibility preference.
*
* @default true (when NO_MOTION is not set)
*/
motion: !process.env.NO_MOTION,

/**
* Whether ANSI color codes are supported.
*
* Set `NO_COLOR=1` to disable all color output. Useful for:
* - Piping output to files
* - Terminals without color support
* - User preference for plain text
*
* @default true (when NO_COLOR is not set)
*/
color: !process.env.NO_COLOR,

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

Align capability mapping with the existing core env-cap contract.

Line 73, Line 83, and Line 95 currently ignore TERM === 'dumb' and CI behavior, which diverges from packages/core/src/terminal/env-caps.ts and can produce inconsistent widget behavior depending on which caps export callers use.

Suggested fix
 export const caps = {
-  unicode: !process.env.NO_UNICODE,
+  unicode: !process.env.NO_UNICODE && process.env.TERM !== 'dumb',
@@
-  motion: !process.env.NO_MOTION,
+  motion: !process.env.NO_MOTION && !process.env.CI,
@@
-  color: !process.env.NO_COLOR,
+  color: !process.env.NO_COLOR && process.env.TERM !== 'dumb',
📝 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
unicode: !process.env.NO_UNICODE,
/**
* Whether animations and motion effects are supported.
*
* Set `NO_MOTION=1` to skip all animations and render static output.
* Respects `prefers-reduced-motion` accessibility preference.
*
* @default true (when NO_MOTION is not set)
*/
motion: !process.env.NO_MOTION,
/**
* Whether ANSI color codes are supported.
*
* Set `NO_COLOR=1` to disable all color output. Useful for:
* - Piping output to files
* - Terminals without color support
* - User preference for plain text
*
* @default true (when NO_COLOR is not set)
*/
color: !process.env.NO_COLOR,
unicode: !process.env.NO_UNICODE && process.env.TERM !== 'dumb',
/**
* Whether animations and motion effects are supported.
*
* Set `NO_MOTION=1` to skip all animations and render static output.
* Respects `prefers-reduced-motion` accessibility preference.
*
* `@default` true (when NO_MOTION is not set)
*/
motion: !process.env.NO_MOTION && !process.env.CI,
/**
* Whether ANSI color codes are supported.
*
* Set `NO_COLOR=1` to disable all color output. Useful for:
* - Piping output to files
* - Terminals without color support
* - User preference for plain text
*
* `@default` true (when NO_COLOR is not set)
*/
color: !process.env.NO_COLOR && process.env.TERM !== 'dumb',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/errors.ts` around lines 73 - 95, The capability properties
unicode, motion, and color in this file are only checking for NO_UNICODE,
NO_MOTION, and NO_COLOR environment variables respectively, but they ignore the
TERM === 'dumb' check and CI environment behavior that exist in the env-caps.ts
contract. Update each of these three properties to also account for TERM being
'dumb' and CI conditions to align with the existing implementation in
packages/core/src/terminal/env-caps.ts, ensuring consistent capability detection
regardless of which caps export callers use.

*
* @default "default"
*/
keybindingMode: (process.env.TERMUI_KEYBINDINGS as 'default' | 'vim' | 'emacs') || 'default',

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify the current keybinding assignment and type assertion usage.
rg -n "keybindingMode|TERMUI_KEYBINDINGS|as 'default' \| 'vim' \| 'emacs'" packages/core/src/errors.ts

# Verify canonical env-caps behavior for comparison.
rg -n "export const caps|TERM !== 'dumb'|NO_MOTION|CI|keybindingMode" packages/core/src/terminal/env-caps.ts

Repository: Karanjot786/TermUI

Length of output: 715


🏁 Script executed:

# Read the full context around line 110 in errors.ts
sed -n '100,120p' packages/core/src/errors.ts

# Get the full keybindingMode implementation in env-caps.ts
sed -n '15,35p' packages/core/src/terminal/env-caps.ts

Repository: Karanjot786/TermUI

Length of output: 1526


Add inline comment or implement runtime validation for type assertion.

Line 110 uses a type assertion without an inline comment explaining why, which violates the coding guidelines. Additionally, the assertion allows arbitrary strings to be treated as valid keybinding modes; the proper approach is runtime validation as implemented in env-caps.ts:

Suggested fix
-  keybindingMode: (process.env.TERMUI_KEYBINDINGS as 'default' | 'vim' | 'emacs') || 'default',
+  keybindingMode:
+    process.env.TERMUI_KEYBINDINGS === 'vim' || process.env.TERMUI_KEYBINDINGS === 'emacs'
+      ? process.env.TERMUI_KEYBINDINGS
+      : 'default',
📝 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
keybindingMode: (process.env.TERMUI_KEYBINDINGS as 'default' | 'vim' | 'emacs') || 'default',
keybindingMode:
process.env.TERMUI_KEYBINDINGS === 'vim' || process.env.TERMUI_KEYBINDINGS === 'emacs'
? process.env.TERMUI_KEYBINDINGS
: 'default',
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/errors.ts` at line 110, The keybindingMode property on line
110 uses a type assertion without runtime validation, which allows arbitrary
environment variable values to be treated as valid keybinding modes. Replace the
type assertion with runtime validation that checks if the
process.env.TERMUI_KEYBINDINGS value is one of the allowed modes ('default',
'vim', 'emacs') and falls back to 'default' if it is not. This approach should
follow the same validation pattern implemented in env-caps.ts to ensure type
safety at runtime rather than relying solely on the TypeScript assertion.

Source: Coding guidelines

Comment on lines +313 to +314
export { Spinner } from './Spinner'
export type { SpinnerProps } from './Spinner' No newline at end of file

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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify duplicate Spinner exports in the index.
rg -n "export \\{[^}]*\\bSpinner\\b" packages/widgets/src/index.ts

# Verify extensionless Spinner re-exports.
rg -n "from './Spinner'" packages/widgets/src/index.ts

Repository: Karanjot786/TermUI

Length of output: 261


🏁 Script executed:

# Check if Spinner files exist in packages/widgets/src
fd -t f "Spinner" packages/widgets/src/ | head -20

# Check the directory structure
ls -la packages/widgets/src/ | grep -i spinner || echo "No direct spinner file found"

Repository: Karanjot786/TermUI

Length of output: 242


🏁 Script executed:

# Check tsconfig to confirm moduleResolution
cat packages/widgets/tsconfig.json | grep -A 2 "moduleResolution" || cat tsconfig.json | grep -A 2 "moduleResolution" || echo "Check compilerOptions"

Repository: Karanjot786/TermUI

Length of output: 148


🏁 Script executed:

# Get the full context around lines 313-314 to understand intent
sed -n '310,320p' packages/widgets/src/index.ts

Repository: Karanjot786/TermUI

Length of output: 328


🏁 Script executed:

# Check packages/widgets tsconfig
cat packages/widgets/tsconfig.json | grep -A 5 "moduleResolution\|compilerOptions"

Repository: Karanjot786/TermUI

Length of output: 188


🏁 Script executed:

# Read the new Spinner.ts file to understand its purpose
cat packages/widgets/src/Spinner.ts

Repository: Karanjot786/TermUI

Length of output: 949


🏁 Script executed:

# Check the existing feedback/Spinner.ts
cat packages/widgets/src/feedback/Spinner.ts

Repository: Karanjot786/TermUI

Length of output: 8580


🏁 Script executed:

# Check the full tsconfig.json to see moduleResolution
cat packages/widgets/tsconfig.json

Repository: Karanjot786/TermUI

Length of output: 308


🏁 Script executed:

# Check the base tsconfig to see moduleResolution setting
cat packages/tsconfig.base.json | grep -A 5 "moduleResolution"

Repository: Karanjot786/TermUI

Length of output: 122


🏁 Script executed:

# Verify both Spinner types to confirm they're truly different
echo "=== feedback/Spinner.ts class definition ===" && head -20 packages/widgets/src/feedback/Spinner.ts
echo "=== Spinner.ts function definition ===" && head -20 packages/widgets/src/Spinner.ts

Repository: Karanjot786/TermUI

Length of output: 1573


Duplicate Spinner export breaks the build.

Lines 313–314 export Spinner again, conflicting with the existing export at Line 137. TypeScript will reject duplicate identifiers in the same module. Additionally, both new re-exports are missing the .js extension used consistently throughout the rest of this file.

Choose one approach:

  • Remove lines 313–314 if you don't need the JSX Spinner exported from the main index.
  • Or alias one of them to avoid the conflict (e.g., export { Spinner as JsxSpinner } from './Spinner.js').
  • Add .js extension either way to match the codebase pattern.
🧰 Tools
🪛 GitHub Actions: CI / 0_build-and-test.txt

[error] 313-313: Build failed (esbuild): Multiple exports with the same name "Spinner". Previously exported at src/index.ts:137:9.


[error] 313-313: Build failed (TypeScript): TS2300 Duplicate identifier 'Spinner'.


[error] 313-313: Build failed (TypeScript): TS2835 Relative import paths need explicit file extensions in ECMAScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './Spinner.js'?


[error] 314-314: Build failed (TypeScript): TS2835 Relative import paths need explicit file extensions in ECMAScript imports when '--moduleResolution' is 'node16' or 'nodenext'. Did you mean './Spinner.js'?

🪛 GitHub Actions: CI / build-and-test

[error] 313-313: esbuild error: Multiple exports with the same name "Spinner". Initially exported at src/index.ts:137: export { Spinner, SPINNER_FRAMES } from './feedback/Spinner.js';


[error] 313-313: TypeScript error TS2300: Duplicate identifier 'Spinner' (duplicate export at src/index.ts:313).


[error] 313-314: TypeScript error TS2835: Relative import paths need explicit file extensions in ECMAScript imports when moduleResolution is node16/nodenext. Did you mean './Spinner.js'?


[error] 313-314: TypeScript error TS2835: Relative import paths need explicit file extensions in ECMAScript imports when moduleResolution is node16/nodenext. Did you mean './Spinner.js'?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/widgets/src/index.ts` around lines 313 - 314, The Spinner and
SpinnerProps exports at lines 313–314 duplicate the existing exports from line
137, causing a build error. Either remove these duplicate export statements if
they're not needed, or rename one of them using an alias (e.g., export as
JsxSpinner) to avoid the conflict. Additionally, add the .js extension to the
file path in the export statement to maintain consistency with the rest of the
file's export pattern.

Source: Pipeline failures

@@ -0,0 +1,32 @@
import { useEffect, useState } from '@termuijs/jsx'

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 | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Confirm compiler settings relevant to JSX parsing and module resolution.
fd -i 'tsconfig*.json' -x sh -c 'echo "== $1 =="; rg -n "\"jsx\"|\"moduleResolution\"" "$1" || true' sh {}

# Find JSX-like syntax inside .ts files in touched areas.
rg -n --iglob '*.ts' 'return\s*<|render\(<|<[A-Z][A-Za-z0-9]*\b' packages/widgets/src tests/helpers

Repository: Karanjot786/TermUI

Length of output: 21395


🏁 Script executed:

cat -n packages/widgets/src/Spinner.ts | head -40

Repository: Karanjot786/TermUI

Length of output: 1173


🏁 Script executed:

cat packages/widgets/tsconfig.json

Repository: Karanjot786/TermUI

Length of output: 308


🏁 Script executed:

cat ../../tsconfig.base.json 2>/dev/null || cat tsconfig.base.json 2>/dev/null || find . -name "tsconfig.base.json" -exec cat {} \;

Repository: Karanjot786/TermUI

Length of output: 564


🏁 Script executed:

rg -A 20 "interface.*[Cc]aps|type.*[Cc]aps|export.*caps" packages/core/src --type ts | head -100

Repository: Karanjot786/TermUI

Length of output: 4761


File won't compile as .ts because it contains JSX. Also, the motion check references a nonexistent property.

Line 31 uses JSX syntax in a .ts file without JSX compiler configuration. Rename to .tsx (and update imports accordingly).

Additionally, line 19 checks caps.noMotion, but the actual property is caps.motion (available as !caps.motion for the no-motion check).

🧰 Tools
🪛 GitHub Actions: CI / 0_build-and-test.txt

[error] 1-1: Command failed: bun run build exited with code 1.

🪛 GitHub Actions: CI / build-and-test

[error] 1-1: Build failed: script "build" exited with code 1 (bun run build).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/widgets/src/Spinner.ts` at line 1, Rename the Spinner.ts file to
Spinner.tsx since it contains JSX syntax that requires JSX compilation support.
Update all import statements throughout the codebase that reference Spinner.ts
to use Spinner.tsx instead. Additionally, locate the motion check that currently
references caps.noMotion and replace it with !caps.motion, since the actual
property available in the caps object is motion (and its negation is used to
check for no-motion support).

Sources: Linters/SAST tools, Pipeline failures

Comment on lines +16 to +20
const frames = caps.unicode ? FRAMES_UNICODE : FRAMES_ASCII

useEffect(() => {
if (caps.noMotion) return

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

Use caps.motion (or !caps.motion) instead of caps.noMotion.

Line 19 references a capability key that doesn’t exist in the provided core caps contract (motion), so reduced-motion behavior won’t trigger correctly.

Suggested fix
-    if (caps.noMotion) return
+    if (!caps.motion) return
📝 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
const frames = caps.unicode ? FRAMES_UNICODE : FRAMES_ASCII
useEffect(() => {
if (caps.noMotion) return
const frames = caps.unicode ? FRAMES_UNICODE : FRAMES_ASCII
useEffect(() => {
if (!caps.motion) return
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/widgets/src/Spinner.ts` around lines 16 - 20, In the useEffect hook
within the Spinner component, replace the check for caps.noMotion with
!caps.motion since noMotion is not a valid capability key in the core caps
contract. Change the condition from if (caps.noMotion) return to if
(!caps.motion) return to properly detect and respect the user's motion
preferences.

@@ -0,0 +1,11 @@
import { describe, it, expect } from 'bun:test'

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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate JSX usage in .ts tests.
rg -n --iglob '*.ts' '<Spinner|render\(<|<[A-Z][A-Za-z0-9]*\b' tests/helpers

Repository: Karanjot786/TermUI

Length of output: 144


🏁 Script executed:

# Verify the file exists and check its actual extension
ls -la tests/helpers/Spinner.test.ts 2>&1 || echo "File check result: $?"

Repository: Karanjot786/TermUI

Length of output: 140


🏁 Script executed:

# Read the test file to confirm JSX usage and context
head -20 tests/helpers/Spinner.test.ts

Repository: Karanjot786/TermUI

Length of output: 403


🏁 Script executed:

# Check if there are any other .ts files in the same directory with JSX
find tests/helpers -name "*.ts" -type f -exec grep -l "^import.*JSX\|<[A-Z][A-Za-z]*" {} \;

Repository: Karanjot786/TermUI

Length of output: 92


🏁 Script executed:

# Check for TypeScript and Bun configuration
find . -maxdepth 2 -type f \( -name "tsconfig.json" -o -name "tsconfig*.json" -o -name "bunfig.toml" -o -name "tsconfig*.js" \)

Repository: Karanjot786/TermUI

Length of output: 97


🏁 Script executed:

# Check if there's a jsx compiler option in tsconfig
cat tsconfig.json 2>/dev/null | head -50

Repository: Karanjot786/TermUI

Length of output: 44


🏁 Script executed:

# Check for Bun configuration
cat bunfig.toml 2>/dev/null

Repository: Karanjot786/TermUI

Length of output: 250


🏁 Script executed:

# Check the base tsconfig for JSX settings
cat tsconfig.base.json | head -60

Repository: Karanjot786/TermUI

Length of output: 564


🏁 Script executed:

# Also check if there's a tsconfig.json in the tests directory
find . -name "tsconfig.json" -type f

Repository: Karanjot786/TermUI

Length of output: 1417


🏁 Script executed:

# Look at the actual error by checking if a build/type check would fail
# Check for any build scripts or test scripts in package.json
head -50 package.json 2>/dev/null || echo "No package.json at root"

Repository: Karanjot786/TermUI

Length of output: 1295


🏁 Script executed:

# Check if tsconfig.base.json includes jsx option (which would allow JSX in .ts files)
grep -A 5 -B 5 '"jsx"' tsconfig.base.json

Repository: Karanjot786/TermUI

Length of output: 44


🏁 Script executed:

# Check if tests directory has its own tsconfig or if files extend the base
find tests -name "tsconfig.json" -o -name "tsconfig*.json"

Repository: Karanjot786/TermUI

Length of output: 44


🏁 Script executed:

# Look for .tsx files in the project to understand the pattern
find . -name "*.tsx" -type f | head -20

Repository: Karanjot786/TermUI

Length of output: 841


🏁 Script executed:

# Check the Bun documentation/config to see if it handles JSX in .ts files natively
# Also check if there are Bun-specific JSX settings
grep -r "jsx" bunfig.toml package.json tsconfig.base.json 2>/dev/null || echo "No jsx config found"

Repository: Karanjot786/TermUI

Length of output: 82


🏁 Script executed:

# Check what the jsx compiler option is set to in the full tsconfig.base.json
cat tsconfig.base.json

Repository: Karanjot786/TermUI

Length of output: 564


🏁 Script executed:

# Check if there's a vitest/bun config that handles JSX transpilation
find . -maxdepth 2 -name "vite.config.*" -o -name "vitest.config.*" -o -name ".bun*"

Repository: Karanjot786/TermUI

Length of output: 106


🏁 Script executed:

# Check if the packages/testing package has JSX configuration
cat packages/testing/tsconfig.json 2>/dev/null | head -30

Repository: Karanjot786/TermUI

Length of output: 363


🏁 Script executed:

# Verify if Bun's test runner properly handles JSX in .ts files by checking the testing package
cat packages/testing/package.json 2>/dev/null | grep -A 10 -B 10 "main\|export"

Repository: Karanjot786/TermUI

Length of output: 676


🏁 Script executed:

# Check the vitest.config.ts to see how it handles JSX
cat vitest.config.ts

Repository: Karanjot786/TermUI

Length of output: 777


🏁 Script executed:

# Check if tests directory has configuration that allows JSX
find tests -name "*.json" -o -name "*.ts" -o -name "*.config.*"

Repository: Karanjot786/TermUI

Length of output: 149


🏁 Script executed:

# Search for how the test file is actually being transpiled - check if vitest or bun has built-in JSX support
# Also check what happens when we look at actual .tsx test files in the project
find . -path "*/tests/*" -name "*.test.tsx" | head -5

Repository: Karanjot786/TermUI

Length of output: 44


🏁 Script executed:

# Let's verify if static analysis really reports parser errors by checking if there are TypeScript type-check issues
# Look for any test configuration in the packages/testing
cat packages/testing/tsconfig.json

Repository: Karanjot786/TermUI

Length of output: 363


🏁 Script executed:

# Verify if the tests/helpers/Spinner.test.ts is actually being run by checking if it's in any test glob patterns
grep -r "tests/helpers" . --include="*.json" --include="*.ts" --include="*.js" | grep -i "test\|glob\|pattern"

Repository: Karanjot786/TermUI

Length of output: 211


🏁 Script executed:

# Double-check the vitest include patterns more carefully
grep -A 5 "include:" vitest.config.ts

Repository: Karanjot786/TermUI

Length of output: 493


🏁 Script executed:

# Check if there's a separate test configuration that would pick up tests/helpers files
find . -maxdepth 2 -name "vitest.config.*" -o -name "vite.config.*" -o -name "jest.config.*"

Repository: Karanjot786/TermUI

Length of output: 106


🏁 Script executed:

# Check if there's a tsconfig.json specifically for tests/helpers that might configure JSX
find tests -type f -name "tsconfig.json"

Repository: Karanjot786/TermUI

Length of output: 44


🏁 Script executed:

# Verify the actual structure - is tests/helpers meant to be test files or utility helpers?
ls -la tests/helpers/

Repository: Karanjot786/TermUI

Length of output: 361


🏁 Script executed:

# Check if any other test file in tests/helpers exists
find tests -name "*.test.ts" -o -name "*.test.tsx"

Repository: Karanjot786/TermUI

Length of output: 92


🏁 Script executed:

# Check if tests/helpers is imported or referenced anywhere in the actual test files
grep -r "tests/helpers/Spinner" . --include="*.ts" --include="*.tsx" --include="*.js"

Repository: Karanjot786/TermUI

Length of output: 44


🏁 Script executed:

# Verify if the base tsconfig is being used for this file or if there's a different resolution
# Check the compiler options that would apply to tests/helpers/Spinner.test.ts
cat tsconfig.json 2>/dev/null || echo "No root tsconfig.json"

Repository: Karanjot786/TermUI

Length of output: 84


🏁 Script executed:

# Check what the purpose of this file is - is it actually a test or just misnamed?
# Look at the content and see if it's meant to be a test
cat tests/helpers/Spinner.test.ts

Repository: Karanjot786/TermUI

Length of output: 403


🏁 Script executed:

# Verify the vitest include pattern one more time to confirm tests/helpers is not covered
grep -E "include|pattern" vitest.config.ts

Repository: Karanjot786/TermUI

Length of output: 193


🏁 Script executed:

# Check if any configuration extends or applies to tests/ directory
find . -maxdepth 3 -name "tsconfig.json" -exec grep -l "tests" {} \;

Repository: Karanjot786/TermUI

Length of output: 44


Rename test file to .tsx to follow project conventions.

File uses JSX (line 7: <Spinner label="Loading" />) but is currently named .ts. While Bun's test runner handles JSX in .ts files natively, the project consistently uses .tsx for all JSX-containing files (see examples/ and packages/). Rename to .tsx for consistency with TypeScript conventions and the project's established pattern.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/helpers/Spinner.test.ts` at line 1, Rename the file from
Spinner.test.ts to Spinner.test.tsx since the file contains JSX syntax (such as
the Spinner component usage at line 7). This aligns with the project's
established convention of using the .tsx extension for all files that contain
JSX, as seen in the examples/ and packages/ directories.

Source: Linters/SAST tools

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

Labels

area:core @termuijs/core area:widgets @termuijs/widgets type:docs +5 pts. Documentation. type:testing +10 pts. Tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs: Add code comments for capability flags in caps module

1 participant