Skip to content

feat(docs): add machine-readable api-index.json for all tokens and classes - #271

Merged
jackgranatowski merged 2 commits into
mainfrom
feat/api-index-json
Jun 8, 2026
Merged

feat(docs): add machine-readable api-index.json for all tokens and classes#271
jackgranatowski merged 2 commits into
mainfrom
feat/api-index-json

Conversation

@jackgranatowski

@jackgranatowski jackgranatowski commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

This pull request was created by @kiro-agent on behalf of @jackgranatowski 👻

Comment with /kiro fix to address specific feedback or /kiro all to address everything.
Learn about Kiro Web


What

Adds docs/api-index.json — a single, auto-generated, machine-readable catalogue of every public framework element (design tokens and classes), built for editor integrations, autocomplete/IntelliSense, tooltip hints, and docs tooling.

Think of it as a spreadsheet: one row per element, many metadata columns.

Each entry (row) carries

  • Common: name, type (token|class), tier (PUBLIC/PUBLIC-ADVANCED/INTERNAL), category, area, group, description, sourceFiles, layer, bundles (which tiers ship it), optional
  • Token-only: namespace (color/space/font/…), value, aliasOf, registered, animatable, syntax, inherits, hasFallback, fallbackOnly
  • Class-only: selector, prefix (sf/is/``), kind, `isVariant`, `baseClass`

A self-describing _meta block includes generated_by, source lists, the full bundle list, counts (by type / tier / category) and a schema documenting every column — so consumers can introspect the format.

Where descriptions/categories come from

No new annotation syntax was introduced. group + description are derived from the existing section-banner comments in the source CSS; category/layer/bundles come from the file + bundle.config.json; token tiers come from the existing contract.

How it's wired in

  • scripts/gen-api-index.js — new generator. Reuses the canonical comment/string-masking parse contract used by the other generators. Output is deterministic (verified byte-identical across runs).
  • scripts/token-tiers.js — extracted the INTERNAL/ADVANCED tier sets into a shared module; gen-token-index.js now imports them (token-index output is byte-identical, verified).
  • Build pipeline: appended to the npm run docs chain + added a docs:api script; registered the output in scripts/artifacts.json so CI's freshness check enforces it; shipped via package.json exports/files; and copied next to the bundles on the published dist branch (CDN), e.g. …/SLASHED@dist/api-index.json.

Counts (cross-checked against registry.json)

1024 elements: 802 tokens (incl. 33 legacy HSL fallback-only channels, flagged) + 222 classes (173 .sf-, 40 .is-, 9 unprefixed). The 769 core tokens / 173 / 40 / 9 all match registry.json.

Testing

  • node scripts/check-artifacts.js --check (the CI freshness job) passes — full bundle + docs build clean.
  • Regenerating twice is byte-identical (deterministic).
  • gen-token-index.js refactor produces no diff in docs/token-index.{json,md}.

Note: the repo's full Playwright/fast-check test suite was not run here because dev dependencies aren't installed in this environment; the Node-based generators and the artifact freshness check were validated directly.

Summary by CodeRabbit

  • New Features
    • A machine-readable API index is now published alongside CSS bundles, providing programmatic access to token and class metadata including descriptions, groups, and stability information.

…asses

Generate docs/api-index.json — a single, spreadsheet-style catalogue of
every public framework element (design tokens AND classes) for editor
integrations, autocomplete, tooltip hints and docs tooling.

Each row carries rich metadata columns: type, stability tier
(PUBLIC/PUBLIC-ADVANCED/INTERNAL), category, group + description (derived
from the existing section-banner comments — no new annotation syntax),
source files, @layer, bundle membership, and per-type facets (token
namespace/value/aliasOf/registered/animatable/syntax/inherits/fallback;
class selector/prefix/kind/variant/baseClass). A self-describing _meta
block with counts and a column schema is included for consumers.

- scripts/gen-api-index.js: new generator, reuses the canonical
  comment/string-masking parse contract; token/class counts line up with
  registry.json (769 tokens, 173 .sf-, 40 .is-, 9 unprefixed).
- scripts/token-tiers.js: extract the INTERNAL/ADVANCED tier sets into a
  shared module; gen-token-index.js now imports them (byte-identical
  output, verified).
- wire into the build: npm run docs chain + docs:api script, register the
  output in scripts/artifacts.json (CI freshness), ship via package.json
  exports/files, and publish alongside the bundles on the dist branch.

Co-authored-by: Jack Granatowski <contact@codeslash.net>
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jackgranatowski, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 32 minutes and 38 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c6a911f8-aa7b-4c61-9eae-4d5eab090812

📥 Commits

Reviewing files that changed from the base of the PR and between cd487c4 and 9e44472.

📒 Files selected for processing (5)
  • docs/api-index.md
  • package.json
  • scripts/artifacts.json
  • scripts/gen-api-index.js
  • tests/api-index-sync.test.js
📝 Walkthrough

Walkthrough

This PR establishes a shared token tier contract, extracts it into an authoritative module, refactors the existing token index generator to use it, implements a new API index generator that catalogs tokens and CSS classes with metadata and tier information, and integrates the generated index into package exports and CI publishing.

Changes

API Index Generation & Token Tier Extraction

Layer / File(s) Summary
Token Stability Tier Contract
scripts/token-tiers.js
Introduces INTERNAL and ADVANCED sets defining stability tiers for tokens, plus a tierOf() function returning 'INTERNAL', 'PUBLIC-ADVANCED', or default 'PUBLIC' classification.
Token Index Refactor
scripts/gen-token-index.js
Imports tier definitions and functions from token-tiers.js and explicitly re-exports them, replacing the previous local tier implementation.
API Index Generator
scripts/gen-api-index.js
Implements a 620-line CLI script that extracts tokens from @property and custom-property declarations with banner metadata, detects aliases and fallback-only entries, extracts both prefixed and unprefixed CSS classes with variant/modifier relationships, and assembles a unified sorted JSON output with tier/bundle/source/layer annotations.
Package & Publishing Integration
package.json, scripts/artifacts.json, .github/workflows/publish-dist.yml
Adds ./api-index.json export pointing to docs/api-index.json, includes the index in published files, registers it as an output artifact, adds docs:api script, and extends the dist-publishing workflow to copy the index into the orphan dist branch.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • codeslash-dev/SLASHED#211: Modifies scripts/artifacts.json manifest which this PR extends to register docs/api-index.json as a generated output tracked by artifact verification infrastructure.
  • codeslash-dev/SLASHED#66: Establishes the publish-dist.yml workflow for publishing to the orphan dist branch, which this PR extends to include the newly generated API index.
  • codeslash-dev/SLASHED#265: Modifies scripts/gen-token-index.js and its tier logic, which this PR refactors to import from the new shared token-tiers.js module.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.69% 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 accurately describes the main change: adding a machine-readable api-index.json file that catalogs all tokens and classes, which is the primary objective across all modified files.
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 feat/api-index-json

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.

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

🧹 Nitpick comments (1)
scripts/gen-api-index.js (1)

344-345: ⚡ Quick win

Fail fast when a source file is missing FILE_META mapping.

Line 344 and Line 438 assume FILE_META[rel] exists. If TOKEN_FILES/CLASS_FILES gains a new source without metadata, the script throws a generic property-access error instead of a clear contract failure.

Proposed refactor
+function metaFor(rel) {
+  const meta = FILE_META[rel];
+  if (!meta) {
+    throw new Error(`[docs:api] Missing FILE_META entry for source file: ${rel}`);
+  }
+  return meta;
+}
+
 function buildTokenEntries(bundlesFor) {
   const fb = fallbackNames();
   const merged = new Map(); // name -> entry

   for (const rel of TOKEN_FILES) {
     const rows = extractTokensFromFile(rel);
-    const meta = FILE_META[rel];
+    const meta = metaFor(rel);
@@
 function extractClassesFromFile(rel) {
@@
-  const meta     = FILE_META[rel];
+  const meta     = metaFor(rel);

Also applies to: 438-439

🤖 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 `@scripts/gen-api-index.js` around lines 344 - 345, The code assumes
FILE_META[rel] exists and will throw an opaque error if it doesn't; add an
explicit check after computing const meta = FILE_META[rel] (and the analogous
spot for the second usage) and if meta is undefined throw a clear Error that
includes the offending rel (and whether it came from TOKEN_FILES or CLASS_FILES)
and instructs to add the required metadata to FILE_META; update the blocks
around rows iteration to validate meta before accessing its properties so the
script fails fast with a helpful message.
🤖 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 `@scripts/gen-api-index.js`:
- Around line 348-368: The token objects created in merged.set(...) (see the
constructor setting name, type, tier, ... bundles) omit the fallbackOnly
property for regular tokens, making the column sparse; add fallbackOnly: false
to the object literal in the merged.set call that initializes normal token
entries (the block that sets value, aliasOf, registered, animatable, etc.) so
every row has a boolean, and ensure the later legacy-only branch (the other
merged.set around the legacy handling) continues to set fallbackOnly: true;
update both spots referenced in this diff (the regular token creation and the
legacy branch around lines 405-422) to keep the property consistent.

---

Nitpick comments:
In `@scripts/gen-api-index.js`:
- Around line 344-345: The code assumes FILE_META[rel] exists and will throw an
opaque error if it doesn't; add an explicit check after computing const meta =
FILE_META[rel] (and the analogous spot for the second usage) and if meta is
undefined throw a clear Error that includes the offending rel (and whether it
came from TOKEN_FILES or CLASS_FILES) and instructs to add the required metadata
to FILE_META; update the blocks around rows iteration to validate meta before
accessing its properties so the script fails fast with a helpful message.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: caa403d8-f067-464f-8be0-328c579a2bfc

📥 Commits

Reviewing files that changed from the base of the PR and between 6e20467 and cd487c4.

📒 Files selected for processing (7)
  • .github/workflows/publish-dist.yml
  • docs/api-index.json
  • package.json
  • scripts/artifacts.json
  • scripts/gen-api-index.js
  • scripts/gen-token-index.js
  • scripts/token-tiers.js

Comment thread scripts/gen-api-index.js
Comment on lines +348 to +368
merged.set(name, {
name,
type: 'token',
tier: tierOf(name),
namespace: namespaceOf(name),
category: meta.category,
area: meta.area,
group: data.group || '',
description: data.description || '',
value: data.value ?? null,
aliasOf: aliasTarget(data.value),
registered: !!data.registered,
animatable: !!data.registered,
syntax: data.syntax ?? null,
inherits: data.inherits ?? null,
hasFallback: fb.has(name),
optional: rel.startsWith('optional/'),
layer: data.layer || null,
sourceFiles: [rel],
bundles: new Set(bundlesFor(rel)),
});

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

Emit fallbackOnly: false for non-legacy token rows.

Line 348 initializes regular token entries without fallbackOnly, while Line 421 sets it to true for legacy-only rows. This makes the token column sparse and can break consumers expecting a boolean token field in every row.

Proposed fix
         merged.set(name, {
           name,
           type: 'token',
           tier: tierOf(name),
           namespace: namespaceOf(name),
@@
           syntax: data.syntax ?? null,
           inherits: data.inherits ?? null,
           hasFallback: fb.has(name),
+          fallbackOnly: false,
           optional: rel.startsWith('optional/'),
           layer: data.layer || null,
           sourceFiles: [rel],
           bundles: new Set(bundlesFor(rel)),
         });

Also applies to: 405-422

🤖 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 `@scripts/gen-api-index.js` around lines 348 - 368, The token objects created
in merged.set(...) (see the constructor setting name, type, tier, ... bundles)
omit the fallbackOnly property for regular tokens, making the column sparse; add
fallbackOnly: false to the object literal in the merged.set call that
initializes normal token entries (the block that sets value, aliasOf,
registered, animatable, etc.) so every row has a boolean, and ensure the later
legacy-only branch (the other merged.set around the legacy handling) continues
to set fallbackOnly: true; update both spots referenced in this diff (the
regular token creation and the legacy branch around lines 405-422) to keep the
property consistent.

- gen-api-index.js now also emits docs/api-index.md, a browseable
  companion generated from the SAME data as the JSON (tokens and classes
  split into per-category tables) so the two can never drift. Registered
  in scripts/artifacts.json for CI freshness.
- tests/api-index-sync.test.js: node:test regression asserting
  api-index.json stays in sync with the authoritative registry.json
  (token/class name parity, fallback-only isolation, _meta count
  consistency, and per-row column/enum well-formedness). Wired into the
  pretest chain. No fast-check dependency.
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.

2 participants