mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
fix(ui): declare Material system tokens and migrate dead --mdc overrides (#1775)
This commit is contained in:
1 parent
e4cf48fdc2
commit
572034f3be
28 files changed
+581
-88
No files matched your search
@@ -0,0 +1,86 @@
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
/**
|
||||
* Angular Material 19 renamed every `--mdc-*` component token to `--mat-*`,
|
||||
* and Material 22 reads none of the old names. An `--mdc-*` declaration
|
||||
* therefore compiles, looks intentional, and silently does nothing; a
|
||||
* `var(--mdc-*)` read always resolves to its fallback. Component tokens must
|
||||
* be set through the `mat.*-overrides()` mixins, which reject unknown names at
|
||||
* build time.
|
||||
*/
|
||||
const DEAD_MATERIAL_TOKEN = /--mdc-[a-z0-9-]+/g;
|
||||
|
||||
/** Source files whose styles or templates can carry component tokens. */
|
||||
const SCANNED_PATHSPECS = [
|
||||
'apps/*.scss',
|
||||
'apps/*.css',
|
||||
'apps/*.ts',
|
||||
'apps/*.html',
|
||||
'libs/*.scss',
|
||||
'libs/*.css',
|
||||
'libs/*.ts',
|
||||
'libs/*.html',
|
||||
];
|
||||
|
||||
/** Tests and this guard's own fixtures may name the retired prefix. */
|
||||
function isScanned(file) {
|
||||
return !/\.(spec|test)\.[cm]?[jt]s$/.test(file);
|
||||
}
|
||||
|
||||
export function findDeadMaterialTokens(file, source) {
|
||||
const findings = [];
|
||||
source.split('\n').forEach((line, index) => {
|
||||
for (const match of line.matchAll(DEAD_MATERIAL_TOKEN)) {
|
||||
findings.push({ file, line: index + 1, token: match[0] });
|
||||
}
|
||||
});
|
||||
return findings;
|
||||
}
|
||||
|
||||
/** Tracked files under `rootDir` that the guard reads, at any depth. */
|
||||
export function listScannedFiles(rootDir) {
|
||||
// No shell: `cmd.exe` treats single quotes as literal characters, so a
|
||||
// POSIX-quoted pathspec reaches git intact on Windows and matches nothing.
|
||||
return execFileSync('git', ['ls-files', ...SCANNED_PATHSPECS], {
|
||||
cwd: rootDir,
|
||||
encoding: 'utf8',
|
||||
maxBuffer: 32 * 1024 * 1024,
|
||||
})
|
||||
.trim()
|
||||
.split('\n')
|
||||
.filter(Boolean)
|
||||
.filter(isScanned);
|
||||
}
|
||||
|
||||
const isMain =
|
||||
process.argv[1] &&
|
||||
path.resolve(process.argv[1]) ===
|
||||
path.resolve(fileURLToPath(import.meta.url));
|
||||
|
||||
if (isMain) {
|
||||
const rootDir = process.cwd();
|
||||
const files = listScannedFiles(rootDir);
|
||||
|
||||
const findings = [];
|
||||
for (const file of files) {
|
||||
const source = await readFile(path.join(rootDir, file), 'utf8');
|
||||
findings.push(...findDeadMaterialTokens(file, source));
|
||||
}
|
||||
|
||||
if (findings.length > 0) {
|
||||
console.error(
|
||||
'Retired Angular Material --mdc-* tokens found. Material 22 ignores them; use the matching mat.*-overrides() mixin instead:'
|
||||
);
|
||||
for (const { file, line, token } of findings) {
|
||||
console.error(`- ${file}:${line} ${token}`);
|
||||
}
|
||||
process.exitCode = 1;
|
||||
} else {
|
||||
console.log(
|
||||
`Checked ${files.length} source files; no retired --mdc-* Material tokens remain.`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { test } from 'node:test';
|
||||
|
||||
import {
|
||||
findDeadMaterialTokens,
|
||||
listScannedFiles,
|
||||
} from './check-material-token-overrides.mjs';
|
||||
|
||||
test('reports retired --mdc-* declarations and reads with their location', () => {
|
||||
const source = [
|
||||
'.field {',
|
||||
' --mdc-outlined-text-field-container-shape: 10px;',
|
||||
' color: var(--mdc-theme-primary, #6366f1);',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
assert.deepEqual(findDeadMaterialTokens('a.scss', source), [
|
||||
{
|
||||
file: 'a.scss',
|
||||
line: 2,
|
||||
token: '--mdc-outlined-text-field-container-shape',
|
||||
},
|
||||
{ file: 'a.scss', line: 3, token: '--mdc-theme-primary' },
|
||||
]);
|
||||
});
|
||||
|
||||
test('accepts current --mat-* tokens and override mixins', () => {
|
||||
const source = [
|
||||
'.field {',
|
||||
' @include mat.form-field-overrides((outlined-container-shape: 10px));',
|
||||
' --mat-icon-button-state-layer-size: 32px;',
|
||||
' color: var(--mat-sys-error);',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
assert.deepEqual(findDeadMaterialTokens('b.scss', source), []);
|
||||
});
|
||||
|
||||
test('selects tracked app and lib sources at any depth, but not specs', async () => {
|
||||
const rootDir = await mkdtemp(path.join(os.tmpdir(), 'mat-token-guard-'));
|
||||
const git = (...args) =>
|
||||
execFileSync('git', args, { cwd: rootDir, stdio: 'pipe' });
|
||||
try {
|
||||
git('init', '-q');
|
||||
const files = {
|
||||
'libs/ui/feature/src/lib/deep/panel.component.scss': '',
|
||||
'libs/ui/feature/src/lib/deep/panel.component.html': '',
|
||||
'libs/ui/feature/src/lib/deep/panel.component.ts': '',
|
||||
'libs/ui/feature/src/lib/deep/panel.component.spec.ts': '',
|
||||
'apps/web/src/styles.scss': '',
|
||||
'apps/web/src/vendor.css': '',
|
||||
'tools/outside.scss': '',
|
||||
};
|
||||
for (const [file, content] of Object.entries(files)) {
|
||||
await mkdir(path.dirname(path.join(rootDir, file)), {
|
||||
recursive: true,
|
||||
});
|
||||
await writeFile(path.join(rootDir, file), content);
|
||||
}
|
||||
git('add', '.');
|
||||
// Untracked files are not part of the checkout CI sees.
|
||||
await writeFile(path.join(rootDir, 'apps/web/src/untracked.scss'), '');
|
||||
|
||||
assert.deepEqual(listScannedFiles(rootDir).sort(), [
|
||||
'apps/web/src/styles.scss',
|
||||
'apps/web/src/vendor.css',
|
||||
'libs/ui/feature/src/lib/deep/panel.component.html',
|
||||
'libs/ui/feature/src/lib/deep/panel.component.scss',
|
||||
'libs/ui/feature/src/lib/deep/panel.component.ts',
|
||||
]);
|
||||
} finally {
|
||||
await rm(rootDir, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
@@ -3,11 +3,11 @@
|
||||
"journeys": {
|
||||
"launch": {
|
||||
"renderer.initialBytes": {
|
||||
"value": 1598232,
|
||||
"value": 1605046,
|
||||
"unit": "bytes",
|
||||
"slack": 4096,
|
||||
"updatedAt": "2026-09-27",
|
||||
"evidencePr": 1734,
|
||||
"updatedAt": "2026-10-01",
|
||||
"evidencePr": 1775,
|
||||
"measuredWith": "pnpm nx build web && pnpm run perf:initial-bytes"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user