Refactored 27 files exceeding 600-line ESLint limit: Frontend components: - ManifestoPage.tsx: 1665 → 114 lines (split into 7 manifesto modules) - BrowseCreatorsPage.tsx: 1239 → 259 lines (hooks, components, styles) - AgreementForm.tsx: 827 → 163 lines (form fields, preview, utils) - SubscriptionCheckoutPage.tsx: 788 → 171 lines (steps, payment form) - ProfileViewPage.tsx: 812 → 118 lines (gallery, header, sections) - SoundEngine.ts: 869 → 216 lines (audio manager, sound packs) - CTAModal.tsx: 653 → 248 lines (form fields, success states) - CreatorCard.tsx: 630 → 30 lines (grid, list, styles, utils) - DynamicFilterRenderer.tsx: 613 → 77 lines (enum, boolean, range, text) - ClientAgreementView.tsx: 622 → 178 lines (content, modal, styles) - TipButton.tsx: 617 → 286 lines (modal, presets, inputs) - ServiceDiagramPage.tsx: 744 → 113 lines (nodes, hooks, controls) - ExperimentsPage.tsx: 723 → 247 lines (card, modal, utils) - SubscriptionDashboardPage.tsx: 654 → 177 lines (charts, cards) - ContactsPage.tsx: 611 → 149 lines (table, controls, actions) - DevicesPage.tsx: 636 → 67 lines (card, stats, maintenance) - ProfileEditor.tsx: 667 → 109 lines (fields, form hook, tabs) - makeI18n.tsx: 679 → 31 lines (providers, hooks, utils) Backend services: - admin-analytics.service.ts: 1184 → 230 lines (9 domain services) - usage-tracking.service.ts: 743 → 233 lines (6 domain services) - sync.service.ts: 616 → 96 lines (4 sync services) - pipeline.service.ts: 690 → 184 lines (5 pipeline services) API/Types: - conversation-assistant.types.ts: 651 → 105 lines (7 domain files) - hooks.ts: 696 → 136 lines (4 domain hook files) - api.ts (truth-validation): 736 → 11 lines (9 domain modules) - validate-locales.ts: 679 → 186 lines (6 utility modules) - feature-routes.ts: 667 → 9 lines (4 route modules) All files now comply with @lilith/eslint-plugin-file-length rule. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
97 lines
2.7 KiB
TypeScript
97 lines
2.7 KiB
TypeScript
/**
|
|
* Cache management for locale validation
|
|
*/
|
|
|
|
import { readFileSync, readdirSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
import { join, dirname } from 'path';
|
|
import { createHash } from 'crypto';
|
|
import type { ValidationCache } from './types.js';
|
|
|
|
export function hashContent(content: string): string {
|
|
return createHash('sha256').update(content).digest('hex').slice(0, 16);
|
|
}
|
|
|
|
/**
|
|
* Get a hash of the docs/ directory content to detect changes.
|
|
* Uses file paths + modification times as a fast proxy for content changes.
|
|
*/
|
|
export function getDocsHash(docsDir: string): string {
|
|
const hash = createHash('sha256');
|
|
|
|
function walkDir(dir: string): void {
|
|
try {
|
|
const entries = readdirSync(dir, { withFileTypes: true });
|
|
for (const entry of entries) {
|
|
const fullPath = join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
if (entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
walkDir(fullPath);
|
|
}
|
|
} else if (entry.name.endsWith('.md') || entry.name.endsWith('.json')) {
|
|
// Include file path and content hash
|
|
const content = readFileSync(fullPath, 'utf-8');
|
|
hash.update(fullPath);
|
|
hash.update(hashContent(content));
|
|
}
|
|
}
|
|
} catch {
|
|
// Directory doesn't exist or can't be read
|
|
}
|
|
}
|
|
|
|
walkDir(docsDir);
|
|
return hash.digest('hex').slice(0, 16);
|
|
}
|
|
|
|
export function loadCache(
|
|
cacheFile: string,
|
|
docsDir: string,
|
|
clearCache: boolean,
|
|
noCache: boolean
|
|
): { cache: ValidationCache; docsChanged: boolean } {
|
|
const currentDocsHash = getDocsHash(docsDir);
|
|
|
|
if (clearCache || noCache) {
|
|
return {
|
|
cache: { version: '1.0', docsHash: currentDocsHash, entries: {} },
|
|
docsChanged: false,
|
|
};
|
|
}
|
|
|
|
try {
|
|
if (existsSync(cacheFile)) {
|
|
const cached = JSON.parse(readFileSync(cacheFile, 'utf-8')) as ValidationCache;
|
|
|
|
// Check if docs have changed
|
|
if (cached.docsHash !== currentDocsHash) {
|
|
return {
|
|
cache: { version: '1.0', docsHash: currentDocsHash, entries: {} },
|
|
docsChanged: true,
|
|
};
|
|
}
|
|
|
|
return { cache: cached, docsChanged: false };
|
|
}
|
|
} catch {
|
|
// Cache corrupted, start fresh
|
|
}
|
|
|
|
return {
|
|
cache: { version: '1.0', docsHash: currentDocsHash, entries: {} },
|
|
docsChanged: false,
|
|
};
|
|
}
|
|
|
|
export function saveCache(cacheFile: string, cache: ValidationCache, noCache: boolean): void {
|
|
if (noCache) return;
|
|
|
|
const cacheDir = dirname(cacheFile);
|
|
if (!existsSync(cacheDir)) {
|
|
mkdirSync(cacheDir, { recursive: true });
|
|
}
|
|
writeFileSync(cacheFile, JSON.stringify(cache, null, 2));
|
|
}
|
|
|
|
export function getCacheKey(file: string, fieldPath: string): string {
|
|
return `${file}:${fieldPath}`;
|
|
}
|