mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-08-29 19:01:41 +00:00
Co-authored-by: Douglas Lai <115660088+Douglasymlai@users.noreply.github.com> Co-authored-by: Douglas <douglas.ym.lai@gmail.com>
138 lines
4.8 KiB
JavaScript
138 lines
4.8 KiB
JavaScript
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import { spawnSync } from 'node:child_process';
|
|
import fs from 'node:fs';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
const repositoryRoot = path.resolve(scriptDirectory, '..');
|
|
const fixturePath = path.join(
|
|
repositoryRoot,
|
|
'src',
|
|
'style',
|
|
`.tailwind4-verify-${process.pid}.css`
|
|
);
|
|
const outputPath = path.join(
|
|
os.tmpdir(),
|
|
`eigent-tailwind4-verify-${process.pid}.css`
|
|
);
|
|
const tailwindBinary = path.join(
|
|
repositoryRoot,
|
|
'node_modules',
|
|
'.bin',
|
|
'tailwindcss'
|
|
);
|
|
|
|
const fixture = `@import './index.css';
|
|
@source inline('short:block max-lg:block smooth-shadow-md smooth-shadow-ring-md bg-ds-accent-strong-default bg-ds-neutral-default-default bg-ds-bg-neutral-default-default text-ds-text-base text-body-sm text-ds-ink-default-default border-ds-hairline-default-default ring-ds-ring-focus shadow-ds-elevation-control h-ds-control-md');
|
|
`;
|
|
|
|
const requiredOutput = [
|
|
['public Neutral fill utility', '.bg-ds-neutral-default-default'],
|
|
['compatibility Neutral fill utility', '.bg-ds-bg-neutral-default-default'],
|
|
['compatibility typography alias', '.text-body-sm'],
|
|
['legacy custom shadow utility', '.shadow-button-shadow'],
|
|
['Tailwind 4 replacement utility', '.shrink-0'],
|
|
['shadow-plugin utility', '.smooth-shadow-md'],
|
|
['shadow-plugin ring utility', '.smooth-shadow-ring-md'],
|
|
['custom short-screen media query', '@media (max-height: 800px)'],
|
|
['custom max-lg responsive utility', '.max-lg\\:block'],
|
|
['public accent fill utility', '.bg-ds-accent-strong-default'],
|
|
['public Ink utility', '.text-ds-ink-default-default'],
|
|
['public Hairline utility', '.border-ds-hairline-default-default'],
|
|
['public focus ring utility', '.ring-ds-ring-focus'],
|
|
['generated type role utility', '.text-ds-text-base'],
|
|
['semantic elevation utility', '.shadow-ds-elevation-control'],
|
|
['control height utility', '.h-ds-control-md'],
|
|
];
|
|
|
|
const forbiddenOutput = [
|
|
['unprocessed Tailwind theme directive', '@theme'],
|
|
['unprocessed Tailwind utility directive', '@utility'],
|
|
['unprocessed config directive', '@config'],
|
|
['unprocessed source directive', '@source'],
|
|
['invalid empty selector', ':where()'],
|
|
['invalid layer media query', '@media layer(utilities)'],
|
|
];
|
|
|
|
function fail(message) {
|
|
process.stderr.write(`FAIL ${message}\n`);
|
|
process.exitCode = 1;
|
|
}
|
|
|
|
try {
|
|
const tailwindVersion = JSON.parse(
|
|
fs.readFileSync(
|
|
path.join(repositoryRoot, 'node_modules', 'tailwindcss', 'package.json'),
|
|
'utf8'
|
|
)
|
|
).version;
|
|
const shadowPluginVersion = JSON.parse(
|
|
fs.readFileSync(
|
|
path.join(
|
|
repositoryRoot,
|
|
'node_modules',
|
|
'shadow-plugin',
|
|
'package.json'
|
|
),
|
|
'utf8'
|
|
)
|
|
).version;
|
|
|
|
if (!tailwindVersion.startsWith('4.')) {
|
|
fail(`Expected Tailwind 4, found ${tailwindVersion}`);
|
|
}
|
|
if (!shadowPluginVersion.startsWith('2.')) {
|
|
fail(`Expected shadow-plugin 2, found ${shadowPluginVersion}`);
|
|
}
|
|
|
|
fs.writeFileSync(fixturePath, fixture, 'utf8');
|
|
const result = spawnSync(
|
|
tailwindBinary,
|
|
['-i', fixturePath, '-o', outputPath],
|
|
{
|
|
cwd: repositoryRoot,
|
|
encoding: 'utf8',
|
|
}
|
|
);
|
|
|
|
if (result.status !== 0) {
|
|
process.stderr.write(result.stdout);
|
|
process.stderr.write(result.stderr);
|
|
fail(`Tailwind compilation exited with status ${result.status}`);
|
|
} else {
|
|
if (/\b(?:warning|unexpected)\b/i.test(result.stderr)) {
|
|
process.stderr.write(result.stderr);
|
|
fail('Tailwind compilation emitted a CSS warning');
|
|
}
|
|
const css = fs.readFileSync(outputPath, 'utf8');
|
|
for (const [label, sentinel] of requiredOutput) {
|
|
if (!css.includes(sentinel)) fail(`Missing ${label}: ${sentinel}`);
|
|
}
|
|
for (const [label, sentinel] of forbiddenOutput) {
|
|
if (css.includes(sentinel)) fail(`Found ${label}: ${sentinel}`);
|
|
}
|
|
}
|
|
|
|
if (!process.exitCode) {
|
|
process.stdout.write(
|
|
`PASS Tailwind ${tailwindVersion}, shadow-plugin ${shadowPluginVersion}, and Eigent config sentinels compiled correctly.\n`
|
|
);
|
|
}
|
|
} finally {
|
|
fs.rmSync(fixturePath, { force: true });
|
|
fs.rmSync(outputPath, { force: true });
|
|
}
|