Skip to content

Commit 22dc447

Browse files
authored
refactor: remove unused tokens from components (#1159)
1 parent 059121e commit 22dc447

File tree

22 files changed

+223
-95
lines changed

22 files changed

+223
-95
lines changed

.phpunit.result.cache

Lines changed: 0 additions & 1 deletion
This file was deleted.

build.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/bin/php
22
<?php
3+
34
// Only allow run from cli.
45
if (php_sapi_name() !== 'cli') {
56
exit(0);
@@ -9,7 +10,7 @@
910
$buildCommands = [
1011
'npm ci --no-progress --no-audit',
1112
'npm run build',
12-
'composer install --prefer-dist --no-progress'
13+
'composer install --prefer-dist --no-progress',
1314
];
1415

1516
// Files and directories not suitable for prod to be removed.
@@ -34,6 +35,7 @@
3435
'postcss.config.js',
3536
'setup.sh',
3637
'webpack.config.js',
38+
'source/components/Tests',
3739
];
3840

3941
$dirName = basename(dirname(__FILE__));
@@ -69,14 +71,14 @@ function executeCommand($command)
6971
{
7072
$proc = popen("$command 2>&1 ; echo Exit status : $?", 'r');
7173

72-
$liveOutput = '';
74+
$liveOutput = '';
7375
$completeOutput = '';
7476

7577
while (!feof($proc)) {
76-
$liveOutput = fread($proc, 4096);
78+
$liveOutput = fread($proc, 4096);
7779
$completeOutput = $completeOutput . $liveOutput;
7880
print $liveOutput;
79-
@ flush();
81+
@flush();
8082
}
8183

8284
pclose($proc);

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
}
5454
},
5555
"scripts": {
56-
"test": "vendor/bin/phpunit",
56+
"test": "vendor/bin/phpunit --testdox",
5757
"test:filter": "vendor/bin/phpunit --filter",
5858
"lint": "vendor/bin/mago lint",
5959
"fix": "vendor/bin/mago lint --format-after-fix --fix",

phpunit.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,8 @@
1212
<testsuite name="validators">
1313
<directory suffix="Test.php">source/validators/Tests</directory>
1414
</testsuite>
15+
<testsuite name="components">
16+
<directory suffix="Test.php">source/components/Tests</directory>
17+
</testsuite>
1518
</testsuites>
1619
</phpunit>
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<?php
2+
3+
namespace MunicipioStyleGuide\Components\Tests;
4+
5+
use PHPUnit\Framework\TestCase;
6+
7+
class UnusedTokensTest extends TestCase
8+
{
9+
private const SHADOW_TOKEN = 'shadow';
10+
private const SHADOW_REQUIRED_TOKENS = ['shadow-amount', 'shadow-color'];
11+
private const TOKEN_EXCEPTIONS = self::SHADOW_REQUIRED_TOKENS;
12+
13+
/**
14+
* @testdox component utilizes all tokens declared in component.json
15+
* @dataProvider componentFilesProvider
16+
*/
17+
public function testComponentUtilizeAllTokens(string $component, string $tokenFile, string $styleFile): void
18+
{
19+
$tokens = self::extractTokensFromTokenFile($tokenFile);
20+
$styleFileContents = (string) file_get_contents($styleFile);
21+
22+
self::assertShadowDependenciesAreDeclared($tokens, $styleFileContents, $component);
23+
$unusedTokens = self::findUnusedTokens($tokens, $styleFileContents, self::TOKEN_EXCEPTIONS);
24+
25+
$errorMessage = sprintf("Component '%s' has declared but unused tokens in %s:%s- %s", $component, $styleFile, PHP_EOL, implode(PHP_EOL . '- ', $unusedTokens));
26+
$this->assertEmpty($unusedTokens, $errorMessage);
27+
}
28+
29+
private static function assertShadowDependenciesAreDeclared(
30+
array $tokens,
31+
string $styleFileContents,
32+
string $component,
33+
): void {
34+
if (!self::styleFileUsesToken($styleFileContents, self::SHADOW_TOKEN)) {
35+
return;
36+
}
37+
38+
$missingTokens = array_values(array_diff(self::SHADOW_REQUIRED_TOKENS, $tokens));
39+
40+
self::assertEmpty(
41+
$missingTokens,
42+
sprintf(
43+
"Component '%s' is missing required shadow tokens: %s",
44+
$component,
45+
implode(', ', $missingTokens),
46+
),
47+
);
48+
}
49+
50+
private static function findUnusedTokens(array $tokens, string $styleFileContents, array $excludedTokens): array
51+
{
52+
$unusedTokens = [];
53+
54+
foreach ($tokens as $token) {
55+
if (in_array($token, $excludedTokens, true)) {
56+
continue;
57+
}
58+
59+
if (!self::styleFileUsesToken($styleFileContents, $token)) {
60+
$unusedTokens[] = $token;
61+
}
62+
}
63+
64+
return $unusedTokens;
65+
}
66+
67+
private static function styleFileUsesToken(string $styleFileContents, string $token): bool
68+
{
69+
// Match tokens.use/get(<anything>, '<token>'[, <optional args>])
70+
$pattern = '/tokens\.(use|get)\s*\([^,]+,\s*[\'\"]' . preg_quote($token, '/') . '[\'\"](?:\s*,[^)]*)?\s*\)/m';
71+
72+
return preg_match($pattern, $styleFileContents) === 1;
73+
}
74+
75+
private static function extractTokensFromTokenFile(string $tokenFile): array
76+
{
77+
$content = (string) file_get_contents($tokenFile);
78+
$data = json_decode($content, true);
79+
80+
if (!is_array($data)) {
81+
return [];
82+
}
83+
84+
return $data['tokens'] ?? [];
85+
}
86+
87+
public static function componentFilesProvider(): \Generator
88+
{
89+
$componentsDir = __DIR__ . '/../';
90+
$componentExceptions = ['Tests']; // Exclude test directory itself
91+
$components = array_filter(scandir($componentsDir), function ($item) use ($componentsDir, $componentExceptions) {
92+
return is_dir($componentsDir . $item) && !in_array($item, ['.', '..', ...$componentExceptions], true);
93+
});
94+
95+
foreach ($components as $component) {
96+
$tokenFile = $componentsDir . $component . '/component.json';
97+
$styleFile = $componentsDir . $component . '/style.scss';
98+
99+
yield $component => [$component, $tokenFile, $styleFile];
100+
}
101+
102+
return;
103+
}
104+
}

source/components/acceptance/style.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ $_: "c-acceptance";
4646
}
4747

4848
.#{$_}__modal-title {
49-
--inherit-font-size: var(--font-size-400);
49+
--inherit-font-size: tokens.get($_, "font-size-400");
5050
}
5151

5252
/* Map */

source/components/accordion/style.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ $_: "c-accordion";
149149

150150
.c-accordion__button .c-accordion__button-column,
151151
.c-accordion__button .c-accordion__button-wrapper {
152-
--inherit-font-size: var(--font-size-200);
152+
--inherit-font-size: tokens.get($_, "font-size-200");
153153
--inherit-margin-top: 0;
154154
--inherit-margin-bottom: 0;
155155
}

source/components/block/style.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ $_: "c-block";
3131
text-decoration: none;
3232

3333
.#{$_}__heading {
34-
--inherit-font-size: var(--font-size-400);
34+
--inherit-font-size: tokens.get($_, "font-size-400");
3535
}
3636

3737
.#{$_}__image {

source/components/box/style.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ $_: "c-box";
2525
transition: all 200ms ease-in;
2626

2727
.#{$_}__heading {
28-
--inherit-font-size: var(--font-size-400);
28+
--inherit-font-size: tokens.get($_, "font-size-400");
2929
}
3030

3131
.#{$_}__body {

source/components/card/style.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ $_: "c-card";
6868

6969
/** Tell child components to inherit font-size from card for better typography scaling */
7070
.#{$_}__heading {
71-
--inherit-font-size: var(--font-size-300);
71+
--inherit-font-size: tokens.get($_, "font-size-300");
7272
}
7373

7474
.#{$_}__header {

0 commit comments

Comments
 (0)