feat: deliver first finance preview with setup wizard
Release / release (push) Failing after 18s

This commit is contained in:
Qiufeng
2026-08-17 14:08:40 +08:00
parent 47403fd337
commit c8b0151769
558 changed files with 140774 additions and 3 deletions
@@ -0,0 +1,132 @@
import { readdir, readFile, stat } from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const scanDist = process.argv.includes('--dist');
const forbiddenPaths = [
'src/pages/dashboard',
'src/pages/detail',
'src/pages/form',
'src/pages/list',
'src/pages/user',
'src/components/common-table',
'src/components/product-card',
'src/components/trend',
'src/api/finance.ts',
'src/api/list.ts',
'src/api/detail.ts',
'src/api/permission.ts',
'src/api/model/listModel.ts',
'src/api/model/detailModel.ts',
'src/api/model/permissionModel.ts',
'src/utils/route/index.ts',
'src/assets/assets-empty.svg',
'src/assets/assets-logo-full.svg',
'src/assets/assets-t-logo.svg',
'src/assets/assets-tencent-logo.png',
'src/assets/assets-product-1.svg',
'src/assets/assets-product-2.svg',
'src/assets/assets-product-3.svg',
'src/assets/assets-product-4.svg',
'src/assets/assets-setting-auto.svg',
'src/assets/assets-setting-dark.svg',
'src/assets/assets-setting-light.svg',
];
const sourceFragments = [
"import.meta.glob('../../pages/**/*.vue')",
'/dashboard/base',
'/detail/base',
'/list/base',
'demo-select-base',
'assets-tencent-logo',
'assets-product-',
'TDesign Vue Next Starter',
'tdesign.gtimg.com/starter/brand-logo',
];
const distFragments = [
'dashboardBase',
'dashboardDetail',
'detailBase',
'formBase',
'listBase',
'demo-select-base',
'assets-tencent-logo',
'TDesign Vue Next Starter',
'tdesign.gtimg.com/starter/brand-logo',
];
async function exists(relativePath) {
try {
await stat(path.join(root, relativePath));
return true;
} catch (error) {
if (error?.code === 'ENOENT') return false;
throw error;
}
}
async function filesUnder(relativePath) {
const absolutePath = path.join(root, relativePath);
if (!(await exists(relativePath))) return [];
const entries = await readdir(absolutePath, { withFileTypes: true });
const files = [];
for (const entry of entries) {
const child = path.join(relativePath, entry.name);
if (entry.isDirectory()) files.push(...(await filesUnder(child)));
else if (entry.isFile()) files.push(child);
}
return files;
}
async function findFragments(relativeFiles, fragments) {
const violations = [];
for (const relativeFile of relativeFiles) {
const content = (await readFile(path.join(root, relativeFile))).toString('utf8');
for (const fragment of fragments) {
if (content.includes(fragment)) violations.push(`${relativeFile}: ${fragment}`);
}
}
return violations;
}
const violations = [];
for (const relativePath of forbiddenPaths) {
if (await exists(relativePath)) violations.push(`${relativePath}: forbidden production path`);
}
const mockFiles = await filesUnder('mock');
for (const file of mockFiles) violations.push(`${file}: Mock fixture is forbidden in production frontend`);
const sourceFiles = (await filesUnder('src')).filter((file) =>
/\.(?:css|html|js|json|jsx|less|ts|tsx|vue)$/.test(file),
);
violations.push(...(await findFragments(sourceFiles, sourceFragments)));
let distFiles = [];
if (scanDist) {
if (!(await exists('dist'))) {
violations.push('dist: production build output is missing');
} else {
distFiles = await filesUnder('dist');
for (const file of distFiles) {
if (/assets-(?:empty|logo-full|product-|setting-|t-logo|tencent-logo)/.test(path.basename(file))) {
violations.push(`${file}: forbidden Starter asset`);
}
}
violations.push(...(await findFragments(distFiles, distFragments)));
}
}
if (violations.length > 0) {
console.error(`Production hygiene check failed with ${violations.length} violation(s):`);
for (const violation of violations) console.error(`- ${violation}`);
process.exit(1);
}
console.log(
`Production hygiene passed: ${sourceFiles.length} source files${scanDist ? ` and ${distFiles.length} dist files` : ''} scanned.`,
);