Skip to content

Conversation

@thatblindgeye
Copy link
Collaborator

@thatblindgeye thatblindgeye commented Jan 20, 2026

Closes #172

Summary by CodeRabbit

  • New Features

    • Added three API endpoints to list token categories, fetch tokens by category (with optional case-insensitive filter), and fetch all tokens grouped by category; category lists are sorted. Added server-side utilities to extract, group, cache, and filter design tokens. Improved error responses for missing/invalid parameters.
  • Tests

    • Added comprehensive test suites covering responses, status codes, filtering, ordering, caching, and error cases.
  • Documentation

    • Updated OpenAPI spec with new token endpoints and response schemas.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 20, 2026

Walkthrough

Adds design-token API endpoints and utilities: GET /api/{version}/tokens, GET /api/{version}/tokens/{category}, GET /api/{version}/tokens/all; a new tokens utility module; OpenAPI spec entries; and Jest tests covering retrieval, filtering, errors, and caching.

Changes

Cohort / File(s) Summary
API Routes: Token Endpoints
src/pages/api/[version]/tokens.ts, src/pages/api/[version]/tokens/[category].ts, src/pages/api/[version]/tokens/all.ts
New GET handlers (export const GET) validating version (400), checking existence via fetchApiIndex (404), retrieving tokens (by category or grouped), optional filter handling, JSON responses, error handling (500), and prerender = false.
Token Utilities
src/utils/tokens.ts
New module exporting Token and TokensByCategory plus functions: getAllTokens(), getTokenCategories(), getTokensByCategory(), getTokensForCategory(), filterTokens(), filterTokensByCategory(). Implements in-memory caching, category derivation, and case-insensitive substring filtering.
OpenAPI Specification
src/pages/api/openapi.json.ts
Added OpenAPI path entries for /{version}/tokens, /{version}/tokens/{category}, and /{version}/tokens/all with parameters, response schemas, and examples for 200/404 responses.
Test Suites
src/__tests__/pages/api/__tests__/[version]/tokens.test.ts, src/__tests__/pages/api/__tests__/[version]/tokens/[category].test.ts, src/__tests__/pages/api/__tests__/[version]/tokens/all.test.ts, src/__tests__/utils/tokens.test.ts
New Jest tests mocking API index, token utilities, and global fetch. Cover 200 responses, filtering behavior (case-insensitive), empty results, 400/404 error cases, response headers, and caching; restore mocks after each test.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant APIRoute as API Route
    participant ApiIndex as fetchApiIndex
    participant TokenUtil as Token Utilities
    participant PatternFly as `@patternfly/react-tokens`

    Client->>APIRoute: GET /api/{version}/tokens[/all|/{category}]?filter=...
    APIRoute->>APIRoute: validate params (version, category)
    APIRoute->>ApiIndex: fetchApiIndex(url)
    ApiIndex-->>APIRoute: API index (versions)
    APIRoute->>TokenUtil: getTokenCategories() / getTokensForCategory() / getTokensByCategory()
    TokenUtil->>PatternFly: load token module
    PatternFly-->>TokenUtil: token exports
    TokenUtil->>TokenUtil: extract, categorize, cache
    TokenUtil-->>APIRoute: tokens or tokens-by-category
    APIRoute->>TokenUtil: filterTokens(...)? (if filter present)
    TokenUtil-->>APIRoute: filtered results
    APIRoute-->>Client: 200 JSON or 400/404/500 error
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • dlabaj
🚥 Pre-merge checks | ✅ 4 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
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.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding API support for design tokens, which aligns with all substantial code additions in the PR.
Linked Issues check ✅ Passed The PR implements all core requirements from #172: three API routes with proper token retrieval, filtering, sorting, error handling, token utilities with caching, comprehensive test coverage, and OpenAPI documentation updates.
Out of Scope Changes check ✅ Passed All changes directly support the core requirements of #172. Token utilities, API route handlers, tests, and OpenAPI spec updates are within scope; documentation updates like README are not included but are listed as separate items.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/utils/tokens.ts`:
- Around line 129-149: Update the function comment for filterTokensByCategory to
accurately describe its behavior: it filters tokens within each category by
token name (case-insensitive) using filterTokens and returns only categories
that still have matching tokens; replace the current misleading lines about
matching the category name and ensure the docstring references TokensByCategory
and the filter parameter semantics.
🧹 Nitpick comments (3)
src/pages/api/[version]/tokens.ts (1)

15-30: Serialize error details to avoid {} responses.
JSON.stringify(Error) drops message/stack. Consider normalizing to a string for consistent debug info.

♻️ Proposed adjustment
-  } catch (error) {
-    return createJsonResponse(
-      { error: 'Failed to load tokens', details: error },
-      500,
-    )
-  }
+  } catch (error) {
+    const details = error instanceof Error ? error.message : String(error)
+    return createJsonResponse(
+      { error: 'Failed to load tokens', details },
+      500,
+    )
+  }
src/pages/api/[version]/tokens/all.ts (1)

35-38: Avoid returning raw error objects in API responses.
details: error can leak internals or serialize unpredictably; return a sanitized message instead.

🔧 Suggested adjustment
-  } catch (error) {
-    return createJsonResponse(
-      { error: 'Failed to load tokens', details: error },
-      500,
-    )
-  }
+  } catch (error) {
+    const message = error instanceof Error ? error.message : String(error)
+    return createJsonResponse(
+      { error: 'Failed to load tokens', details: message },
+      500,
+    )
+  }
src/utils/tokens.ts (1)

85-103: Optional: sort tokens within each category for deterministic output.
This can make responses stable and easier to diff/consume.

♻️ Suggested refinement
   for (const token of tokens) {
     const category = getCategoryFromTokenName(token.name)
     if (!byCategory[category]) {
       byCategory[category] = []
     }
     byCategory[category].push(token)
   }
+
+  for (const categoryTokens of Object.values(byCategory)) {
+    categoryTokens.sort((a, b) => a.name.localeCompare(b.name))
+  }

Comment on lines 129 to 149
/**
* Filters tokens by category (case-insensitive)
* Matches against the category name
*/
export function filterTokensByCategory(
byCategory: TokensByCategory,
filter: string,
): TokensByCategory {
if (!filter) {
return byCategory
}

const filtered: TokensByCategory = {}
for (const [category, tokens] of Object.entries(byCategory)) {
const filteredTokens = filterTokens(tokens, filter)
if (filteredTokens.length > 0) {
filtered[category] = filteredTokens
}
}

return filtered
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix docstring: filtering is by token name, not category name.
The comment conflicts with the implementation and could mislead readers.

📝 Suggested doc fix
- * Filters tokens by category (case-insensitive)
- * Matches against the category name
+ * Filters tokens by name across categories (case-insensitive)
+ * Matches against the token name field
📝 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
/**
* Filters tokens by category (case-insensitive)
* Matches against the category name
*/
export function filterTokensByCategory(
byCategory: TokensByCategory,
filter: string,
): TokensByCategory {
if (!filter) {
return byCategory
}
const filtered: TokensByCategory = {}
for (const [category, tokens] of Object.entries(byCategory)) {
const filteredTokens = filterTokens(tokens, filter)
if (filteredTokens.length > 0) {
filtered[category] = filteredTokens
}
}
return filtered
/**
* Filters tokens by name across categories (case-insensitive)
* Matches against the token name field
*/
export function filterTokensByCategory(
byCategory: TokensByCategory,
filter: string,
): TokensByCategory {
if (!filter) {
return byCategory
}
const filtered: TokensByCategory = {}
for (const [category, tokens] of Object.entries(byCategory)) {
const filteredTokens = filterTokens(tokens, filter)
if (filteredTokens.length > 0) {
filtered[category] = filteredTokens
}
}
return filtered
}
🤖 Prompt for AI Agents
In `@src/utils/tokens.ts` around lines 129 - 149, Update the function comment for
filterTokensByCategory to accurately describe its behavior: it filters tokens
within each category by token name (case-insensitive) using filterTokens and
returns only categories that still have matching tokens; replace the current
misleading lines about matching the category name and ensure the docstring
references TokensByCategory and the filter parameter semantics.

Copy link

@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

🤖 Fix all issues with AI agents
In `@src/__tests__/utils/tokens.test.ts`:
- Around line 1-41: The mocked token object in the jest.mock call uses
non-camelcase keys (e.g., c_alert_BackgroundColor, c_alert_Color,
c_button_BackgroundColor, t_global_color_100, invalidToken) which triggers the
camelcase ESLint rule; add a scoped eslint-disable-next-line or eslint-disable
comment for camelcase just above the jest.mock invocation (or wrap the object
with /* eslint-disable `@typescript-eslint/camelcase` */ and re-enable after) so
the token keys remain unchanged and the linter does not fail.

In `@src/utils/tokens.ts`:
- Around line 17-36: In getCategoryFromTokenName, replace the mutable
declaration for the category variable with an immutable one: change the
declaration of category (currently declared with let after computing parts =
tokenName.split('-')) to use const since it is never reassigned; keep the
existing early-return for the 'chart' case and return category at the end as
before.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/__tests__/utils/tokens.test.ts`:
- Line 1: Replace the ineffective single-line directive with a block disable
using the base rule name (change the existing "// eslint-disable
`@typescript-eslint/camelcase`" to a block comment that disables "camelcase"
across the mock section) and then re-enable the rule after the mock block (add a
corresponding block enable for "camelcase" immediately after the mock block) so
the disable only spans the intended mock code; locate the directive at the top
of the tokens.test.ts file and the mock block that follows to apply these
changes.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add API support for design tokens

1 participant