Skip to content

feat(bricks): REST validation, stale detection, and class hints - #157

Merged
jackgranatowski merged 2 commits into
mainfrom
claude/gifted-cray-HWDVq
May 30, 2026
Merged

feat(bricks): REST validation, stale detection, and class hints#157
jackgranatowski merged 2 commits into
mainfrom
claude/gifted-cray-HWDVq

Conversation

@jackgranatowski

@jackgranatowski jackgranatowski commented May 30, 2026

Copy link
Copy Markdown
Contributor

Summary

  • REST validation endpointPOST /slashed-bricks/v1/tokens/validate runs Token_Sanitizer on submitted values without saving; returns { section, sanitized, changed } for inline admin SPA feedback before save
  • Stale version detection — daily WP cron queries jsDelivr metadata API for newest framework tag; shows a dashboard widget when behind, silent when up to date; 2-day transient cache
  • Class hints pipelinescripts/gen-class-hints.js parses CSS section comments → data/classes-hints.json (169 hints); show_class_hints toggle in BundleTab; hints passed to both admin SPA and editor app via wp_localize_script

What changed

File Change
scripts/gen-class-hints.js New build script — parses /* -- Section --- */ comments, manual hints for is-* states
data/classes-hints.json Generated output, 169 class → { description, category } entries
package.json Adds bricks:class-hints script; wires into npm run build docs pipeline
class-rest-controller.php Adds /tokens/validate route + handler; save_settings accepts show_class_hints
class-token-store.php Adds PLUGIN_SETTING_DEFAULTS constant; get_plugin_settings() merges defaults
class-admin-page-svelte.php Passes classHints to admin SPA; adds get_class_hints() static helper
class-rebemer-enqueue.php Passes showClassHints + classHints to editor app as window.slashedBricksEditor
BundleTab.svelte Adds show_class_hints checkbox wired to saveSettings
slashed-bricks.php Registers cron, version-check callback, and dashboard widget

Test plan

  • POST /slashed-bricks/v1/tokens/validate with a valid section returns sanitized values, changed map is populated for normalised fields, nothing is persisted
  • POST /slashed-bricks/v1/tokens/validate with an unknown section returns 400
  • BundleTab "Show class hints" checkbox saves and persists across page reloads
  • window.slashedBricksEditor.classHints is present in the Bricks editor when the toggle is on
  • npm run build regenerates data/classes-hints.json
  • Manually triggering do_action('slashed_bricks_version_check') populates the transient
  • Dashboard widget appears when transient holds a version newer than SLASHED_BRICKS_CSS_REF

https://claude.ai/code/session_018u9uVFxgL7K6EpPjZPggKR


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Class hints setting enables display of utility class descriptions in the Bricks editor.
    • Dashboard widget notifies administrators when new framework versions are available.
    • Token validation endpoint added to REST API.
  • Chores

    • Class hints generation script added to build process.

Review Change Stack

REST validation endpoint
  - POST /slashed-bricks/v1/tokens/validate — runs Token_Sanitizer on
    submitted values without saving; returns { section, sanitized, changed }
    so the admin SPA can surface normalisation feedback inline before save

Stale inventory / version detection
  - Daily WP cron (slashed_bricks_version_check) queries jsDelivr package
    metadata for the latest codeslash-dev/SLASHED GitHub tag
  - Newest tag cached in a 2-day transient
  - wp_dashboard_setup adds a SLASHED widget when a newer release is found;
    shown only to manage_options users; no widget when up to date

Class hints (show_class_hints)
  - scripts/gen-class-hints.js: parses /* -- Section --- */ comments from
    CSS source files to map each .sf-* / .is-* class to a description and
    category; manual hints fill gaps for states (different comment format)
  - data/classes-hints.json: generated output (169 class hints)
  - package.json: adds bricks:class-hints script; includes gen-class-hints
    in the docs pipeline so it rebuilds with npm run build
  - class-token-store.php: adds PLUGIN_SETTING_DEFAULTS constant with
    show_class_hints: false default; get_plugin_settings() now merges
    defaults so new keys are always present
  - class-rest-controller.php: save_settings accepts show_class_hints
    boolean; register_routes adds the /tokens/validate route
  - class-admin-page-svelte.php: passes classHints to admin SPA via
    wp_localize_script; adds get_class_hints() static helper
  - class-rebemer-enqueue.php: passes showClassHints + classHints to
    editor app via wp_localize_script into slashedBricksEditor global
  - BundleTab.svelte: adds show_class_hints checkbox wired to saveSettings

https://claude.ai/code/session_018u9uVFxgL7K6EpPjZPggKR
@coderabbitai

coderabbitai Bot commented May 30, 2026

Copy link
Copy Markdown

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 50 minutes and 9 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: 63c763ef-58c4-4c0b-9c1e-23a849d4c4fe

📥 Commits

Reviewing files that changed from the base of the PR and between d1c8529 and c2c5876.

📒 Files selected for processing (5)
  • data/classes-hints.json
  • integrations/bricks/includes/class-admin-page-svelte.php
  • integrations/bricks/includes/class-rest-controller.php
  • integrations/bricks/slashed-bricks.php
  • scripts/gen-class-hints.js
📝 Walkthrough

Walkthrough

This PR introduces a class hints feature for the SLASHED Bricks editor that generates, stores, and displays descriptions for utility classes. It parses CSS source files to extract section comments and class selectors, generates a JSON hints file, and exposes it through the admin settings and editor UI. Additionally, the PR adds framework version detection that caches the latest SLASHED tag and displays a dashboard notification for admins when updates are available.

Changes

Class Hints and Framework Updates

Layer / File(s) Summary
Class hints generation script
scripts/gen-class-hints.js, package.json
Node.js CLI script parses CSS source files, extracts section comments and class selectors grouped by category, and generates hints JSON. Output can be validated with --check flag. New npm scripts docs and bricks:class-hints trigger generation.
Generated class hints data
data/classes-hints.json
JSON dictionary mapping 200+ utility class names to descriptions and categories across Layout (grid, stack, container), Macros (prose, flow, gradients, shadows), and States (visibility, interactivity, validation, positioning).
Plugin settings defaults and retrieval
integrations/bricks/includes/class-token-store.php
New PLUGIN_SETTING_DEFAULTS constant defines default values for html_font_size, css_bundle, and show_class_hints. Updated get_plugin_settings() merges stored settings with defaults to ensure all expected keys are always present.
REST API for settings and token validation
integrations/bricks/includes/class-rest-controller.php
Extended plugin settings POST route to accept and persist boolean show_class_hints parameter. Added new POST /tokens/validate endpoint that sanitizes token values inline (without persistence) and returns a changed map indicating which fields were normalized.
Admin page and editor script binding
integrations/bricks/includes/class-admin-page-svelte.php, integrations/bricks/includes/class-rebemer-enqueue.php
Admin page loads classes-hints.json via new get_class_hints() method and localizes it for the Svelte app. Editor script enqueue injects slashedBricksEditor object containing both classHints data and showClassHints setting flag.
Frontend settings UI and display
integrations/bricks/admin-app/src/components/BundleTab.svelte
Adds reactive showClassHints state bound to plugin settings and new checkbox UI labeled "Show class hints in Bricks editor" that toggles display of class descriptions in the editor. Setting is persisted through REST API.
Framework version checking and notifications
integrations/bricks/slashed-bricks.php
Registers daily cron job that fetches latest SLASHED package tag from jsDelivr, caches it in a transient, and conditionally displays a dashboard widget for admins when the cached version is newer than the pinned SLASHED_BRICKS_CSS_REF.

Sequence Diagrams

sequenceDiagram
  participant Admin as Admin UI
  participant REST as REST API
  participant Store as Token Store
  participant Settings as Settings Storage
  Admin->>REST: POST /settings {show_class_hints: true}
  REST->>Store: get_plugin_settings()
  Store->>Settings: read slashed_bricks_settings
  Store-->>REST: merged with defaults
  REST->>Settings: update show_class_hints
  REST-->>Admin: return updated settings
Loading
sequenceDiagram
  participant SVG as Svelte Component
  participant Admin as Admin Page
  participant JSON as JSON File
  participant Enqueue as Editor Enqueue
  Admin->>JSON: get_class_hints()
  JSON-->>Admin: parsed hints object
  Admin->>SVG: localize classHints
  Enqueue->>Store: get_plugin_settings()
  Store-->>Enqueue: showClassHints flag
  Enqueue->>SVG: inject slashedBricksEditor
  SVG-->>SVG: render hints in editor
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.82% 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 pull request title accurately captures the three main features: REST validation endpoint, stale version detection (via cron), and class hints pipeline functionality.
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 claude/gifted-cray-HWDVq

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

Caution

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

⚠️ Outside diff range comments (1)
integrations/bricks/includes/class-rest-controller.php (1)

448-470: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Import/export doesn't round-trip show_class_hints.

export_tokens() now serializes the full plugin settings, but import only restores css_bundle and html_font_size. Importing a settings export will silently reset show_class_hints back to the default on the target site.

Suggested fix
 			if ( isset( $raw['html_font_size'] )
 				&& in_array( (string) $raw['html_font_size'], array( '', '100', '62.5' ), true )
 			) {
 				$existing['html_font_size'] = (string) $raw['html_font_size'];
 				$settings_imported = true;
 			}
+
+			if ( array_key_exists( 'show_class_hints', $raw ) ) {
+				$existing['show_class_hints'] = (bool) $raw['show_class_hints'];
+				$settings_imported = true;
+			}
 
 			if ( $settings_imported ) {
 				Slashed_Bricks_Token_Store::update_plugin_settings( $existing );
 			}
🤖 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 `@integrations/bricks/includes/class-rest-controller.php` around lines 448 -
470, The import code in the plugin settings block only restores css_bundle and
html_font_size, so exported show_class_hints is lost; update the block that
reads $body['plugin_settings'] (using
Slashed_Bricks_Token_Store::get_plugin_settings() / update_plugin_settings()) to
also detect and validate a submitted show_class_hints value and copy it into
$existing before calling update_plugin_settings; ensure you accept the same
canonical forms used elsewhere (e.g., boolean true/false or '1'/'0' strings) and
coerce to the stored type so show_class_hints round-trips correctly.
🧹 Nitpick comments (1)
integrations/bricks/slashed-bricks.php (1)

288-293: ⚡ Quick win

Consider adding a deactivation hook to clean up the scheduled cron event.

The cron event is scheduled but never unscheduled when the plugin is deactivated, leaving an orphaned scheduled task. While harmless (the callback won't exist), cleaning up scheduled events on deactivation is a best practice.

🧹 Proposed deactivation hook

Add this function and registration:

/**
 * Cleanup: unschedule version check cron on plugin deactivation.
 */
function slashed_bricks_deactivation_cleanup() {
	$timestamp = wp_next_scheduled( 'slashed_bricks_version_check' );
	if ( $timestamp ) {
		wp_unschedule_event( $timestamp, 'slashed_bricks_version_check' );
	}
}
register_deactivation_hook( __FILE__, 'slashed_bricks_deactivation_cleanup' );
🤖 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 `@integrations/bricks/slashed-bricks.php` around lines 288 - 293, The scheduled
daily cron event created by slashed_bricks_schedule_version_check for
'slashed_bricks_version_check' is never removed on plugin deactivation; add a
deactivation cleanup function named slashed_bricks_deactivation_cleanup that
calls wp_next_scheduled('slashed_bricks_version_check') and, if a timestamp
exists, wp_unschedule_event($timestamp, 'slashed_bricks_version_check'), then
register it with register_deactivation_hook(__FILE__,
'slashed_bricks_deactivation_cleanup') so the cron is unscheduled when the
plugin is deactivated.
🤖 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 `@integrations/bricks/includes/class-admin-page-svelte.php`:
- Around line 154-155: In get_class_hints(), guard the file_get_contents() call
so you never pass false into json_decode: call $json = file_get_contents($path),
check if $json === false and if so set $data = [] (or skip json_decode)
otherwise set $data = json_decode($json, true); keep the existing is_array()
fallback afterwards to ensure $data is an array; this prevents a TypeError when
file_get_contents fails for $path.

In `@integrations/bricks/includes/class-rest-controller.php`:
- Around line 276-286: The current loop only iterates $sanitized so fields
dropped by the sanitizer never appear in $changed; update the computation in the
method that builds $changed (using $sanitized and $values variables in
class-rest-controller.php) to iterate the union of keys from both $values and
$sanitized (e.g. array_keys(array_merge($values, $sanitized)) or
array_unique(array_merge(array_keys($values), array_keys($sanitized)))), compute
$raw = isset($values[$key]) ? (string)$values[$key] : '' and $clean =
isset($sanitized[$key]) ? $sanitized[$key] : null, then add $changed[$key] =
['original'=>$raw,'sanitized'=>$clean] and optionally a flag like 'removed' =>
true when $clean === null so the SPA can display rejected inputs.

In `@integrations/bricks/slashed-bricks.php`:
- Around line 299-333: slashed_bricks_run_version_check currently looks for
body['tags'][*]['name'] but jsDelivr returns body['versions'] with items
containing a 'version' field; update the parsing to iterate body['versions'],
check each item's 'version' against a semver regex (allow optional leading "v"),
pick the newest matching semver, normalize it to the "vX.Y.Z" form if necessary,
and then call set_transient('slashed_bricks_latest_version', $latest,
DAY_IN_SECONDS * 2) as before; ensure the code still handles non-array or empty
responses and preserves the existing failure early-returns.

In `@scripts/gen-class-hints.js`:
- Around line 114-134: The loop is reusing the section-level currentDesc for
every selector match causing incorrect hints; instead, for each classRe match
inside the code slice (where classRe.exec(code) returns cm) retrieve a
selector-specific comment/description (e.g., look backwards from cm.index in
code to find a preceding block or line comment nearest the selector, or use a
regex that captures an optional comment immediately before the selector) and
assign that as the description for that specific name in hints; keep falling
back to currentDesc only when no selector-level comment is found, and preserve
the existing parentClass logic so modifiers still inherit their root when
appropriate (update references to tokens/currentDesc/parentClass/classRe/hints
accordingly).

---

Outside diff comments:
In `@integrations/bricks/includes/class-rest-controller.php`:
- Around line 448-470: The import code in the plugin settings block only
restores css_bundle and html_font_size, so exported show_class_hints is lost;
update the block that reads $body['plugin_settings'] (using
Slashed_Bricks_Token_Store::get_plugin_settings() / update_plugin_settings()) to
also detect and validate a submitted show_class_hints value and copy it into
$existing before calling update_plugin_settings; ensure you accept the same
canonical forms used elsewhere (e.g., boolean true/false or '1'/'0' strings) and
coerce to the stored type so show_class_hints round-trips correctly.

---

Nitpick comments:
In `@integrations/bricks/slashed-bricks.php`:
- Around line 288-293: The scheduled daily cron event created by
slashed_bricks_schedule_version_check for 'slashed_bricks_version_check' is
never removed on plugin deactivation; add a deactivation cleanup function named
slashed_bricks_deactivation_cleanup that calls
wp_next_scheduled('slashed_bricks_version_check') and, if a timestamp exists,
wp_unschedule_event($timestamp, 'slashed_bricks_version_check'), then register
it with register_deactivation_hook(__FILE__,
'slashed_bricks_deactivation_cleanup') so the cron is unscheduled when the
plugin is deactivated.
🪄 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: baabc7c8-50b8-4e21-8f02-aaebc4ab0b68

📥 Commits

Reviewing files that changed from the base of the PR and between 2410b41 and d1c8529.

⛔ Files ignored due to path filters (1)
  • dist/slashed-bricks.zip is excluded by !**/dist/**, !**/*.zip
📒 Files selected for processing (9)
  • data/classes-hints.json
  • integrations/bricks/admin-app/src/components/BundleTab.svelte
  • integrations/bricks/includes/class-admin-page-svelte.php
  • integrations/bricks/includes/class-rebemer-enqueue.php
  • integrations/bricks/includes/class-rest-controller.php
  • integrations/bricks/includes/class-token-store.php
  • integrations/bricks/slashed-bricks.php
  • package.json
  • scripts/gen-class-hints.js

Comment thread integrations/bricks/includes/class-admin-page-svelte.php
Comment thread integrations/bricks/includes/class-rest-controller.php Outdated
Comment thread integrations/bricks/slashed-bricks.php
Comment on lines +114 to +134
// Walk the file in order: between section markers, extract class names.
for (let i = 0; i < tokens.length; i++) {
const section = tokens[i];
currentDesc = section.desc;
parentClass = '';

const codeStart = section.end;
const codeEnd = i + 1 < tokens.length ? tokens[i + 1].offset : src.length;
const code = src.slice(codeStart, codeEnd)
// strip remaining block comments
.replace(/\/\*[\s\S]*?\*\//g, '');

classRe.lastIndex = 0;
let cm;
while ((cm = classRe.exec(code)) !== null) {
const name = cm[1]; // e.g. "sf-stack" or "sf-stack--xl"
// Track the first (root) class in this section as the parent.
if (!parentClass) parentClass = name;
// Modifier classes inherit the parent description; root classes get the section desc.
hints[name] = { description: currentDesc, category };
}

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 | 🏗️ Heavy lift

Don't reuse one section description for every selector in the block.

This loop assigns the same currentDesc to every .sf-*/.is-* match until the next heading, and the generated JSON already shows incorrect hints as a result (sf-truncate/sf-line-clamp-* get the sf-flow text, sf-alternate gets sf-imposter's text, etc.). That means the editor will ship misleading tooltips for a large slice of classes unless the generator binds descriptions to the specific selector/comment pair rather than the whole section.

🧰 Tools
🪛 OpenGrep (1.22.0)

[ERROR] 128-128: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-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 `@scripts/gen-class-hints.js` around lines 114 - 134, The loop is reusing the
section-level currentDesc for every selector match causing incorrect hints;
instead, for each classRe match inside the code slice (where classRe.exec(code)
returns cm) retrieve a selector-specific comment/description (e.g., look
backwards from cm.index in code to find a preceding block or line comment
nearest the selector, or use a regex that captures an optional comment
immediately before the selector) and assign that as the description for that
specific name in hints; keep falling back to currentDesc only when no
selector-level comment is found, and preserve the existing parentClass logic so
modifiers still inherit their root when appropriate (update references to
tokens/currentDesc/parentClass/classRe/hints accordingly).

- class-admin-page-svelte.php: guard file_get_contents() against false
  before passing to json_decode() (prevents TypeError on PHP 8+)
- class-rest-controller.php: fix validate_section() $changed loop to
  also report fields dropped entirely by the sanitizer (not only
  normalised survivors)
- class-rest-controller.php: round-trip show_class_hints through
  import_tokens() so it isn't silently reset on target sites
- slashed-bricks.php: fix jsDelivr API parsing — endpoint returns
  body['versions'][*]['version'], not body['tags'][*]['name']
- slashed-bricks.php: add deactivation hook to unschedule cron event
- scripts/gen-class-hints.js: fix sectionRe to allow hyphens in
  section titles (e.g. "Truncate / line-clamp", "media-object") so
  those classes no longer inherit the preceding section's description
- data/classes-hints.json: regenerated with corrected descriptions

https://claude.ai/code/session_018u9uVFxgL7K6EpPjZPggKR
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