Remove the design guard's maryUI and daisyUI checks

Plan step 41 review (the user, 2026-09-15): SealShare and ReStride have
both left maryUI and daisyUI, and no application of 2.0.0 carries either,
so the <x-mary-*> tag check, the daisyUI class and colour lists and the
Tailwind look-alike exclusions they needed go, with their fixture lines
and the mentions in the header, README and development skill.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
This commit is contained in:
Andreas Reinhold / reini
2026-09-15 08:28:35 +02:00
co-authored by Claude Opus 5
parent 6147221b89
commit c047fefd8b
5 changed files with 22 additions and 63 deletions
+1 -1
View File
@@ -150,7 +150,7 @@ it('uses only what compiles', function () {
});
```
The guard fails on maryUI tags, daisyUI classes, colours the theme does not declare, unknown Material Symbol names and Blade directives written inside component tags. It also fails on every Tailwind utility or variant still sitting in a view, PHP or JS file — a breakpoint prefix, a radius, shadow, type size/weight/leading/tracking, easing or duration, a flex/grid/spacing/sizing/display utility, a text-layout utility, an M3 role utility (`text-on-surface-variant`, `bg-primary`), a pseudo-class variant, or an arbitrary `[…]` value — none of which compile any more, since the application carries no Tailwind: every line names its 2.0.0 replacement, a layout component and prop (`flex gap-4``<x-row gap="space200">`), an `md-*` class (`truncate``md-truncate`), or a token for the application's own CSS (`rounded-lg``var(--md-sys-shape-corner-lg)`). A class the application's own stylesheets declare is exempt, and so is every `md-*` class.
The guard fails on Tailwind palette colours, unknown Material Symbol names and Blade directives written inside component tags. It also fails on every Tailwind utility or variant still sitting in a view, PHP or JS file — a breakpoint prefix, a radius, shadow, type size/weight/leading/tracking, easing or duration, a flex/grid/spacing/sizing/display utility, a text-layout utility, an M3 role utility (`text-on-surface-variant`, `bg-primary`), a pseudo-class variant, or an arbitrary `[…]` value — none of which compile any more, since the application carries no Tailwind: every line names its 2.0.0 replacement, a layout component and prop (`flex gap-4``<x-row gap="space200">`), an `md-*` class (`truncate``md-truncate`), or a token for the application's own CSS (`rounded-lg``var(--md-sys-shape-corner-lg)`). A class the application's own stylesheets declare is exempt, and so is every `md-*` class.
`missingStylesheets($cssEntry)` checks the CSS entry's `@import` graph (followed through every package file's own imports) against the package tags a view actually renders — unprefixed, under the configured prefix, or `<x-livewire-material::…>` — and `->links()`; each missing one names the exact `@import` line to add, and a tag the application shadows with its own component of the same name is reported instead. It also turns on a check of the application's own CSS (the entry and what it imports outside the package, plus any `.css` file among the scanned paths), which reports a literal colour, radius, shadow, font size, weight, line height, letter spacing, easing, duration or off-scale media query with its token or breakpoint — a value inside `var(--md-sys-…)` or `calc()` is always fine, and the generated `material-scheme.css` is skipped.
@@ -1119,7 +1119,7 @@ it('uses only what compiles', function () {
});
```
It fails on maryUI tags, daisyUI classes, colours the theme does not declare, unknown symbol names and Blade directives written inside a component tag (where they do not compile), with `path:line` for each.
It fails on Tailwind palette colours, unknown symbol names and Blade directives written inside a component tag (where they do not compile), with `path:line` for each.
It also fails on every Tailwind utility or variant, which compile to nothing in a Tailwind-free application, each with its 2.0.0 replacement — a layout component and prop, an `md-*` class, or a token for the application's own CSS. A class the application's own stylesheets declare is exempt, and so is every `md-*` class:
+8 -44
View File
@@ -33,10 +33,10 @@ use Symfony\Component\Finder\Finder;
* height, letter spacing, easing or duration, and a media query at a width other than
* 600/840/1200/1600px each with its token or breakpoint. A value inside
* `var(--md-sys-…)` or `calc()` is never flagged, whatever it contains.
* (iv) maryUI tags, daisyUI classes, colours the theme does not declare, icon names that are
* not Material Symbols, and Blade directives written inside a component tag (where they
* do not compile) plus whatever an application bans on top with `forbidColours()`,
* `forbidAbsolutes()`, `forbidOpacityInk()` and `forbid()`. These, and the breakpoint,
* (iv) Tailwind palette colours, icon names that are not Material Symbols, and Blade
* directives written inside a component tag (where they do not compile) plus whatever
* an application bans on top with `forbidColours()`, `forbidAbsolutes()`,
* `forbidOpacityInk()` and `forbid()`. These, and the breakpoint,
* scale and colour-value checks, read a line at a time, so a class assembled at runtime
* (`'text-'.$tone`) or hidden in a comment stays invisible the same reason to write
* class names out whole. `forbidAbsolutes()` and `forbidOpacityInk()` matter mainly to an
@@ -66,17 +66,6 @@ class DesignGuard
protected const string PALETTE = '(?:red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose|slate|gray|zinc|neutral|stone)-(?:50|[1-9]00|950)';
protected const string DAISY_COLOURS = '(?:base-(?:100|200|300|content)|(?:primary|secondary|accent|neutral|info|success|warning|error)-content|accent|neutral)';
/**
* daisyUI's component classes. Tailwind utilities that share a name `collapse`, `table`,
* `select-none`, `tab-4` and the package's own `link` are not on it.
*/
protected const string DAISY_CLASSES = '/^(?:btn|badge|card|alert|modal|drawer|dropdown|menu|navbar|footer|hero|stats?|tabs?|tooltip|toast|toggle|checkbox|radio|range|rating|input|select|textarea|file-input|fieldset|label|join|kbd|loading|progress|radial-progress|skeleton|steps?|timeline|swap|indicator|avatar|divider|dock|fab|status|validator|breadcrumbs|carousel|chat|countdown|diff|stack|theme-controller)(?:-[a-z0-9-]+)?$'
.'|^(?:table-(?:zebra|xs|sm|md|lg|xl|pin-rows|pin-cols)|collapse-(?:arrow|plus|title|content|open|close)|list-row|link-(?:primary|secondary|accent|neutral|info|success|warning|error))$/';
protected const string TAILWIND_LOOKALIKES = '/^(?:select-(?:none|text|all|auto)|tab-\d+)$/';
/** A colour written as a value: an arbitrary hex, function or mix instead of a role. */
protected const string ARBITRARY_COLOUR = '/(?<![\w-])'.self::UTILITY.'-\[(?:#|rgb|hsl|oklch|color-mix)[^\]\s"\']*\]?/';
@@ -337,12 +326,6 @@ class DesignGuard
$contents = $this->withoutBladeComments($contents);
foreach ($this->literalClasses($contents) as [$line, $class]) {
$bare = $this->withoutVariantPrefix($class);
if (preg_match(self::DAISY_CLASSES, $bare) === 1 && preg_match(self::TAILWIND_LOOKALIKES, $bare) !== 1) {
$violations[] = "{$where}:{$line} daisyUI class `{$bare}`";
}
if (($hint = $this->tailwindFamilyHint($class)) !== null) {
$violations[] = "{$where}:{$line} {$hint}";
}
@@ -366,12 +349,6 @@ class DesignGuard
foreach (explode("\n", $contents) as $index => $text) {
$line = $index + 1;
if ($isBlade && preg_match_all('/<x-mary-[\w.:-]+/', $text, $matches)) {
foreach ($matches[0] as $tag) {
$violations[] = "{$where}:{$line} maryUI component `{$tag}`";
}
}
if (preg_match_all($this->colourPattern(), $text, $matches)) {
foreach ($matches[0] as $class) {
$violations[] = "{$where}:{$line} colour the theme does not declare `{$class}`";
@@ -413,7 +390,7 @@ class DesignGuard
protected function colourPattern(): string
{
$names = [self::PALETTE, self::DAISY_COLOURS];
$names = [self::PALETTE];
foreach ($this->forbiddenColours as $role) {
$role = preg_quote($role, '/');
@@ -548,17 +525,6 @@ class DesignGuard
return $found;
}
/**
* `$token` with a variant prefix a breakpoint, a stacked pseudo-class chain and a leading
* `!` dropped, so the daisyUI check can still recognise a variant-prefixed daisy class for
* what it is underneath. `tailwindFamilyHint()` reports the prefix itself (see the variant
* family below), so it works from the token `literalClasses()` returns, unstripped.
*/
protected function withoutVariantPrefix(string $token): string
{
return ltrim((string) preg_replace('/^.*:/', '', $token), '!');
}
/**
* A Tailwind-shaped class token's 2.0.0 replacement, or null when the token is not this
* guard's to report: it is not Tailwind-shaped at all (an application's own class, an ARIA or
@@ -859,8 +825,7 @@ class DesignGuard
* Every class written out literally: in `class="…"`, and in the string keys and values of
* `:class`/`x-bind:class`, `@class([...])`, `->class([...])` and `Arr::toCssClasses([...])`.
* Echoes inside a list are skipped. A token is returned exactly as written, variant prefix
* (`sm:`, `hover:`) and all `withoutVariantPrefix()` strips one for the daisyUI check, which
* needs to see through it; `tailwindFamilyHint()` needs to see it.
* (`sm:`, `hover:`) and all, since `tailwindFamilyHint()` reports the prefix itself.
*
* @return list<array{0: int, 1: string}>
*/
@@ -967,8 +932,7 @@ class DesignGuard
* application component of the same name (Blade tries the application's own
* `resources/views/components/<name>.blade.php` and a class-based one before this
* package's registered anonymous path, whatever the configured prefix; a namespaced or
* prefixed tag always reaches the package). `<x-slot:…>` is not a component tag, and
* `<x-mary-…>` is the maryUI check's concern.
* prefixed tag always reaches the package). `<x-slot:…>` is not a component tag.
*
* @return list<array{0: int, 1: string, 2: string}>
*/
@@ -981,7 +945,7 @@ class DesignGuard
$found = [];
foreach ($tags[1] as [$tag, $offset]) {
if (str_starts_with($tag, 'x-slot') || str_starts_with($tag, 'x-mary-')) {
if (str_starts_with($tag, 'x-slot')) {
continue;
}
+8 -12
View File
@@ -23,16 +23,12 @@ it('finds what compiles to nothing', function () {
expect(fixtureRelative($violations))->toBe([
'app/Status.php:14 colour the theme does not declare `text-red-500`',
'views/page.blade.php:3 daisyUI class `card`',
"views/page.blade.php:3 Tailwind spacing utility `p-4` compiles to nothing — use a layout component's `gap`/`padding` prop (`<x-stack gap>`, `<x-surface padding>`), or `var(--md-sys-measurement-space*)` in your own CSS",
'views/page.blade.php:6 daisyUI class `btn-primary`',
'views/page.blade.php:9 Tailwind sizing utility `size-4` compiles to nothing — M3 keeps no size scale; write the literal length in your own CSS, or use `<x-pane width>`/`<x-grid min-item>` where it fits',
'views/page.blade.php:4 unknown Material Symbol `o-home`',
'views/page.blade.php:5 unknown Material Symbol `not_a_symbol`',
'views/page.blade.php:9 Blade directive `@class` inside a component tag, where it does not compile',
'views/page.blade.php:2 maryUI component `<x-mary-button`',
'views/page.blade.php:3 colour the theme does not declare `bg-base-200`',
'views/page.blade.php:6 colour the theme does not declare `text-red-600`',
"views/page.blade.php:2 Tailwind spacing utility `p-4` compiles to nothing — use a layout component's `gap`/`padding` prop (`<x-stack gap>`, `<x-surface padding>`), or `var(--md-sys-measurement-space*)` in your own CSS",
'views/page.blade.php:8 Tailwind sizing utility `size-4` compiles to nothing — M3 keeps no size scale; write the literal length in your own CSS, or use `<x-pane width>`/`<x-grid min-item>` where it fits',
'views/page.blade.php:3 unknown Material Symbol `o-home`',
'views/page.blade.php:4 unknown Material Symbol `not_a_symbol`',
'views/page.blade.php:8 Blade directive `@class` inside a component tag, where it does not compile',
'views/page.blade.php:5 colour the theme does not declare `text-red-600`',
]);
});
@@ -299,7 +295,7 @@ it('bans the roles an application leaves out', function () {
->forbidColours(['tertiary'])
->violations());
expect($violations)->toContain('views/page.blade.php:7 colour the theme does not declare `text-tertiary`');
expect($violations)->toContain('views/page.blade.php:6 colour the theme does not declare `text-tertiary`');
});
it('bans any further pattern', function () {
@@ -307,7 +303,7 @@ it('bans any further pattern', function () {
->forbid('/\bfocus-ring\b/', 'a retired utility')
->violations());
expect($violations)->toContain('views/page.blade.php:7 a retired utility');
expect($violations)->toContain('views/page.blade.php:6 a retired utility');
});
it('names the missing package stylesheet and the exact @import line to add', function () {
@@ -1,10 +1,9 @@
{{-- <x-mary-button> and btn-primary in a comment are not violations --}}
<x-mary-button label="Old" />
<div class="card bg-base-200 p-4">
{{-- text-red-600 and <x-icon name="o-home" /> in a comment are not violations --}}
<div class="p-4">
<x-icon name="o-home" />
<x-button icon="calendar_month" icon-right="not_a_symbol" label="Fine" />
<span @class(['btn-primary' => $active, 'select-none'])>text-red-600</span>
<p class="text-tertiary table collapse link focus-ring">Tailwind's and ours</p>
<span>text-red-600</span>
<p class="text-tertiary focus-ring">Tailwind's and ours</p>
<x-icon :name="$dynamic" />
<x-icon name="home" @class(['size-4']) />
</div>