feat(bricks): REST validation, stale detection, and class hints - #157
Conversation
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
|
Warning Review limit reached
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 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThis 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. ChangesClass Hints and Framework Updates
Sequence DiagramssequenceDiagram
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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 winImport/export doesn't round-trip
show_class_hints.
export_tokens()now serializes the full plugin settings, but import only restorescss_bundleandhtml_font_size. Importing a settings export will silently resetshow_class_hintsback 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 winConsider 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
⛔ Files ignored due to path filters (1)
dist/slashed-bricks.zipis excluded by!**/dist/**,!**/*.zip
📒 Files selected for processing (9)
data/classes-hints.jsonintegrations/bricks/admin-app/src/components/BundleTab.svelteintegrations/bricks/includes/class-admin-page-svelte.phpintegrations/bricks/includes/class-rebemer-enqueue.phpintegrations/bricks/includes/class-rest-controller.phpintegrations/bricks/includes/class-token-store.phpintegrations/bricks/slashed-bricks.phppackage.jsonscripts/gen-class-hints.js
| // 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 }; | ||
| } |
There was a problem hiding this comment.
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
Summary
POST /slashed-bricks/v1/tokens/validaterunsToken_Sanitizeron submitted values without saving; returns{ section, sanitized, changed }for inline admin SPA feedback before savescripts/gen-class-hints.jsparses CSS section comments →data/classes-hints.json(169 hints);show_class_hintstoggle in BundleTab; hints passed to both admin SPA and editor app viawp_localize_scriptWhat changed
scripts/gen-class-hints.js/* -- Section --- */comments, manual hints foris-*statesdata/classes-hints.json{ description, category }entriespackage.jsonbricks:class-hintsscript; wires intonpm run builddocs pipelineclass-rest-controller.php/tokens/validateroute + handler;save_settingsacceptsshow_class_hintsclass-token-store.phpPLUGIN_SETTING_DEFAULTSconstant;get_plugin_settings()merges defaultsclass-admin-page-svelte.phpclassHintsto admin SPA; addsget_class_hints()static helperclass-rebemer-enqueue.phpshowClassHints+classHintsto editor app aswindow.slashedBricksEditorBundleTab.svelteshow_class_hintscheckbox wired tosaveSettingsslashed-bricks.phpTest plan
POST /slashed-bricks/v1/tokens/validatewith a valid section returns sanitized values,changedmap is populated for normalised fields, nothing is persistedPOST /slashed-bricks/v1/tokens/validatewith an unknown section returns 400window.slashedBricksEditor.classHintsis present in the Bricks editor when the toggle is onnpm run buildregeneratesdata/classes-hints.jsondo_action('slashed_bricks_version_check')populates the transientSLASHED_BRICKS_CSS_REFhttps://claude.ai/code/session_018u9uVFxgL7K6EpPjZPggKR
Generated by Claude Code
Summary by CodeRabbit
New Features
Chores