mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 15:33:22 +00:00
198 lines
5.4 KiB
JavaScript
198 lines
5.4 KiB
JavaScript
// scripts/check-hardcoded-strings.js
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const babel = require('@babel/parser');
|
|
const traverse = require('@babel/traverse').default;
|
|
|
|
// Patterns pour les classes Tailwind
|
|
const TAILWIND_PATTERNS = [
|
|
// Layout
|
|
/^(container|flex|grid|block|inline|hidden)/,
|
|
// Spacing
|
|
/^(m|p|mt|mb|ml|mr|mx|my|pt|pb|pl|pr|px|py)-[0-9]+/,
|
|
// Sizing
|
|
/^(w|h|min-w|min-h|max-w|max-h)-[0-9]+/,
|
|
// Typography
|
|
/^(text|font|leading)-/,
|
|
// Backgrounds
|
|
/^bg-/,
|
|
// Borders
|
|
/^(border|rounded|divide)-/,
|
|
// Effects
|
|
/^(shadow|opacity|transition)-/,
|
|
// Interactivity
|
|
/^(cursor|pointer-events|select|resize)-/,
|
|
// Layout
|
|
/^(z|top|right|bottom|left|float|clear)-/,
|
|
// Flexbox & Grid
|
|
/^(justify|items|content|self|place|gap)-/,
|
|
// États
|
|
/^(hover|focus|active|disabled|group|dark):/,
|
|
// Couleurs
|
|
/-(?:slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)-[0-9]+$/,
|
|
];
|
|
|
|
// Nouveaux patterns pour ignorer les logs et imports
|
|
const CODE_PATTERNS = [
|
|
// Console et debug avec contenu
|
|
/console\.(log|error|warn|info|debug)\(['"].*['"]/,
|
|
/^console\.(log|error|warn|info|debug)\(/,
|
|
/^debugger/,
|
|
|
|
// Imports et requires avec leurs chaînes
|
|
/^import\s+.*\s+from\s+['"].*['"]/,
|
|
/^import\s+['"].*['"]/,
|
|
/^require\(['"].*['"]\)/,
|
|
/^from\s+['"].*['"]/,
|
|
/^@/,
|
|
|
|
// Autres cas courants
|
|
/^process\.env\./,
|
|
/^module\.exports/,
|
|
/^export\s+/,
|
|
];
|
|
|
|
function isHardcodedString(str) {
|
|
// Ignorer les chaînes vides ou trop courtes
|
|
if (!str || str.length <= 1) return false;
|
|
|
|
// Vérifier si la chaîne fait partie d'un console.log ou d'un import
|
|
const context = str.trim();
|
|
if (CODE_PATTERNS.some((pattern) => pattern.test(context))) {
|
|
return false;
|
|
}
|
|
|
|
// Vérifier si c'est une chaîne dans un console.log
|
|
if (context.includes('console.log(')) {
|
|
return false;
|
|
}
|
|
|
|
// Vérifier si c'est une chaîne dans un import
|
|
if (context.includes("from '") || context.includes('from "')) {
|
|
return false;
|
|
}
|
|
|
|
// Vérifier si c'est une classe Tailwind
|
|
const classes = str.split(' ');
|
|
if (
|
|
classes.some((cls) =>
|
|
TAILWIND_PATTERNS.some((pattern) => pattern.test(cls))
|
|
)
|
|
) {
|
|
return false;
|
|
}
|
|
|
|
// Autres patterns à ignorer
|
|
const IGNORE_PATTERNS = [
|
|
/^[A-Z][A-Za-z]+$/, // Noms de composants
|
|
/^@/, // Imports
|
|
/^[./]/, // Chemins de fichiers
|
|
/^[0-9]+$/, // Nombres
|
|
/^style=/, // Props style
|
|
/^id=/, // Props id
|
|
/^data-/, // Data attributes
|
|
/^aria-/, // Aria attributes
|
|
/^role=/, // Role attributes
|
|
/^className=/, // className attributes
|
|
];
|
|
|
|
return !IGNORE_PATTERNS.some((pattern) => pattern.test(str));
|
|
}
|
|
|
|
async function scanFile(filePath) {
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
const hardcodedStrings = new Map(); // Utiliser Map pour stocker string -> ligne
|
|
|
|
try {
|
|
const ast = babel.parse(content, {
|
|
sourceType: 'module',
|
|
plugins: ['jsx', 'typescript'],
|
|
locations: true, // Active le tracking des positions
|
|
});
|
|
|
|
traverse(ast, {
|
|
StringLiteral(path) {
|
|
const value = path.node.value;
|
|
const line = path.node.loc.start.line;
|
|
if (isHardcodedString(value)) {
|
|
hardcodedStrings.set(value, line);
|
|
}
|
|
},
|
|
JSXText(path) {
|
|
const value = path.node.value.trim();
|
|
const line = path.node.loc.start.line;
|
|
if (isHardcodedString(value)) {
|
|
hardcodedStrings.set(value, line);
|
|
}
|
|
},
|
|
});
|
|
} catch (error) {
|
|
console.error(`Erreur dans le fichier ${filePath}:`, error);
|
|
}
|
|
|
|
return Array.from(hardcodedStrings.entries());
|
|
}
|
|
|
|
async function scanDirectory(dir) {
|
|
const results = {};
|
|
const files = fs.readdirSync(dir);
|
|
|
|
for (const file of files) {
|
|
const filePath = path.join(dir, file);
|
|
const stat = fs.statSync(filePath);
|
|
|
|
if (
|
|
stat.isDirectory() &&
|
|
!file.startsWith('.') &&
|
|
file !== 'node_modules'
|
|
) {
|
|
Object.assign(results, await scanDirectory(filePath));
|
|
} else if (
|
|
stat.isFile() &&
|
|
(file.endsWith('.js') || file.endsWith('.jsx') || file.endsWith('.tsx'))
|
|
) {
|
|
const strings = await scanFile(filePath);
|
|
if (strings.length > 0) {
|
|
results[filePath] = strings;
|
|
}
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
async function logStringsToFile(results) {
|
|
const outputPath = path.join(process.cwd(), 'hardcoded-strings-report.md');
|
|
let content = '# Rapport des chaînes en dur\n\n';
|
|
let totalStrings = 0;
|
|
|
|
for (const [file, strings] of Object.entries(results)) {
|
|
if (strings.length > 0) {
|
|
const relativePath = path.relative(process.cwd(), file);
|
|
content += `\n## ${relativePath}\n\n`;
|
|
|
|
strings.forEach(([str, line]) => {
|
|
totalStrings++;
|
|
content += `- Ligne ${line}: \`${str}\`\n`;
|
|
content += ` → [Voir dans le code](${relativePath}:${line}:1)\n\n`;
|
|
});
|
|
}
|
|
}
|
|
|
|
content += `\n## Résumé\n`;
|
|
content += `- Total des chaînes trouvées: ${totalStrings}\n`;
|
|
content += `- Date du scan: ${new Date().toLocaleString('fr-FR')}\n`;
|
|
|
|
fs.writeFileSync(outputPath, content, 'utf8');
|
|
console.log(`\nRapport généré: ${outputPath}`);
|
|
}
|
|
|
|
// Modifier la fonction main existante
|
|
async function main() {
|
|
const rootDir = process.cwd();
|
|
const results = await scanDirectory(path.join(rootDir, 'src'));
|
|
await logStringsToFile(results);
|
|
}
|
|
|
|
main().catch(console.error);
|