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:
co-authored by
Claude Opus 5
parent
6147221b89
commit
c047fefd8b
@@ -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.
|
`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:
|
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:
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ use Symfony\Component\Finder\Finder;
|
|||||||
* height, letter spacing, easing or duration, and a media query at a width other than
|
* 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
|
* 600/840/1200/1600px — each with its token or breakpoint. A value inside
|
||||||
* `var(--md-sys-…)` or `calc()` is never flagged, whatever it contains.
|
* `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
|
* (iv) Tailwind palette colours, icon names that are not Material Symbols, and Blade
|
||||||
* not Material Symbols, and Blade directives written inside a component tag (where they
|
* directives written inside a component tag (where they do not compile) — plus whatever
|
||||||
* do not compile) — plus whatever an application bans on top with `forbidColours()`,
|
* an application bans on top with `forbidColours()`, `forbidAbsolutes()`,
|
||||||
* `forbidAbsolutes()`, `forbidOpacityInk()` and `forbid()`. These, and the breakpoint,
|
* `forbidOpacityInk()` and `forbid()`. These, and the breakpoint,
|
||||||
* scale and colour-value checks, read a line at a time, so a class assembled at runtime
|
* 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
|
* (`'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
|
* 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 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. */
|
/** 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"\']*\]?/';
|
protected const string ARBITRARY_COLOUR = '/(?<![\w-])'.self::UTILITY.'-\[(?:#|rgb|hsl|oklch|color-mix)[^\]\s"\']*\]?/';
|
||||||
|
|
||||||
@@ -337,12 +326,6 @@ class DesignGuard
|
|||||||
$contents = $this->withoutBladeComments($contents);
|
$contents = $this->withoutBladeComments($contents);
|
||||||
|
|
||||||
foreach ($this->literalClasses($contents) as [$line, $class]) {
|
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) {
|
if (($hint = $this->tailwindFamilyHint($class)) !== null) {
|
||||||
$violations[] = "{$where}:{$line} {$hint}";
|
$violations[] = "{$where}:{$line} {$hint}";
|
||||||
}
|
}
|
||||||
@@ -366,12 +349,6 @@ class DesignGuard
|
|||||||
foreach (explode("\n", $contents) as $index => $text) {
|
foreach (explode("\n", $contents) as $index => $text) {
|
||||||
$line = $index + 1;
|
$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)) {
|
if (preg_match_all($this->colourPattern(), $text, $matches)) {
|
||||||
foreach ($matches[0] as $class) {
|
foreach ($matches[0] as $class) {
|
||||||
$violations[] = "{$where}:{$line} colour the theme does not declare `{$class}`";
|
$violations[] = "{$where}:{$line} colour the theme does not declare `{$class}`";
|
||||||
@@ -413,7 +390,7 @@ class DesignGuard
|
|||||||
|
|
||||||
protected function colourPattern(): string
|
protected function colourPattern(): string
|
||||||
{
|
{
|
||||||
$names = [self::PALETTE, self::DAISY_COLOURS];
|
$names = [self::PALETTE];
|
||||||
|
|
||||||
foreach ($this->forbiddenColours as $role) {
|
foreach ($this->forbiddenColours as $role) {
|
||||||
$role = preg_quote($role, '/');
|
$role = preg_quote($role, '/');
|
||||||
@@ -548,17 +525,6 @@ class DesignGuard
|
|||||||
return $found;
|
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
|
* 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
|
* 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
|
* Every class written out literally: in `class="…"`, and in the string keys and values of
|
||||||
* `:class`/`x-bind:class`, `@class([...])`, `->class([...])` and `Arr::toCssClasses([...])`.
|
* `:class`/`x-bind:class`, `@class([...])`, `->class([...])` and `Arr::toCssClasses([...])`.
|
||||||
* Echoes inside a list are skipped. A token is returned exactly as written, variant prefix
|
* 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
|
* (`sm:`, `hover:`) and all, since `tailwindFamilyHint()` reports the prefix itself.
|
||||||
* needs to see through it; `tailwindFamilyHint()` needs to see it.
|
|
||||||
*
|
*
|
||||||
* @return list<array{0: int, 1: string}>
|
* @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
|
* 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
|
* `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
|
* 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
|
* prefixed tag always reaches the package). `<x-slot:…>` is not a component tag.
|
||||||
* `<x-mary-…>` is the maryUI check's concern.
|
|
||||||
*
|
*
|
||||||
* @return list<array{0: int, 1: string, 2: string}>
|
* @return list<array{0: int, 1: string, 2: string}>
|
||||||
*/
|
*/
|
||||||
@@ -981,7 +945,7 @@ class DesignGuard
|
|||||||
$found = [];
|
$found = [];
|
||||||
|
|
||||||
foreach ($tags[1] as [$tag, $offset]) {
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,16 +23,12 @@ it('finds what compiles to nothing', function () {
|
|||||||
|
|
||||||
expect(fixtureRelative($violations))->toBe([
|
expect(fixtureRelative($violations))->toBe([
|
||||||
'app/Status.php:14 colour the theme does not declare `text-red-500`',
|
'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: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: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: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:6 daisyUI class `btn-primary`',
|
'views/page.blade.php:3 unknown Material Symbol `o-home`',
|
||||||
'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 `not_a_symbol`',
|
||||||
'views/page.blade.php:4 unknown Material Symbol `o-home`',
|
'views/page.blade.php:8 Blade directive `@class` inside a component tag, where it does not compile',
|
||||||
'views/page.blade.php:5 unknown Material Symbol `not_a_symbol`',
|
'views/page.blade.php:5 colour the theme does not declare `text-red-600`',
|
||||||
'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`',
|
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -299,7 +295,7 @@ it('bans the roles an application leaves out', function () {
|
|||||||
->forbidColours(['tertiary'])
|
->forbidColours(['tertiary'])
|
||||||
->violations());
|
->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 () {
|
it('bans any further pattern', function () {
|
||||||
@@ -307,7 +303,7 @@ it('bans any further pattern', function () {
|
|||||||
->forbid('/\bfocus-ring\b/', 'a retired utility')
|
->forbid('/\bfocus-ring\b/', 'a retired utility')
|
||||||
->violations());
|
->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 () {
|
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 --}}
|
{{-- text-red-600 and <x-icon name="o-home" /> in a comment are not violations --}}
|
||||||
<x-mary-button label="Old" />
|
<div class="p-4">
|
||||||
<div class="card bg-base-200 p-4">
|
|
||||||
<x-icon name="o-home" />
|
<x-icon name="o-home" />
|
||||||
<x-button icon="calendar_month" icon-right="not_a_symbol" label="Fine" />
|
<x-button icon="calendar_month" icon-right="not_a_symbol" label="Fine" />
|
||||||
<span @class(['btn-primary' => $active, 'select-none'])>text-red-600</span>
|
<span>text-red-600</span>
|
||||||
<p class="text-tertiary table collapse link focus-ring">Tailwind's and ours</p>
|
<p class="text-tertiary focus-ring">Tailwind's and ours</p>
|
||||||
<x-icon :name="$dynamic" />
|
<x-icon :name="$dynamic" />
|
||||||
<x-icon name="home" @class(['size-4']) />
|
<x-icon name="home" @class(['size-4']) />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user