Publication IA: - 4 templates (magazine, brief, essay, simple) avec CSS riche - Rewrite IA (article/exercises/tutorial/reference/mixed) - Modération avec timeout 12s + fallback safe - Quotas publish_enhance par tier (basic=2, pro=15, business=100) - Détection contenu stale (hash) - Migration DB publishedContent/publishedTemplate/publishedSourceHash Fixes: - cheerio v1.2: Element -> AnyNode (domhandler), decodeEntities cast - _isShared ajouté au type Note (champ virtuel serveur) - callout colors PDF export: extraction fonction pure testable - admin/published: guard note.userId null - Cmd+S fonctionne en mode dialog (pas seulement fullPage) i18n: - 23 clés publish* traduites dans les 15 locales - Extension Web Clipper: 13 locales mise à jour Tests: - callout-colors.test.ts (6 tests) - note-visible-in-view.test.ts (5 tests) - entitlements.test.ts + byok-entitlements.test.ts: mock usageLog + unstubAllEnvs - 199/199 tests passent Tracker: user-stories.md sync avec sprint-status.yaml
161 lines
5.0 KiB
JavaScript
161 lines
5.0 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* Script de diagnostic pour l'extension Memento
|
||
* Vérifie tous les fichiers et identifie les problèmes potentiels
|
||
*/
|
||
|
||
import fs from 'fs'
|
||
import path from 'path'
|
||
import { fileURLToPath } from 'url'
|
||
|
||
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
||
const extDir = __dirname
|
||
|
||
console.log('🔍 Diagnostic Extension Memento\n')
|
||
|
||
const issues = []
|
||
const warnings = []
|
||
|
||
// Vérifier la syntaxe des fichiers JS
|
||
function checkSyntax(filePath) {
|
||
try {
|
||
const content = fs.readFileSync(filePath, 'utf8')
|
||
// Pas de vérification syntaxique simple en Node.js sans eval
|
||
// On vérifie juste que le fichier est lisible
|
||
return true
|
||
} catch (error) {
|
||
issues.push(`Fichier illisible: ${filePath} - ${error.message}`)
|
||
return false
|
||
}
|
||
}
|
||
|
||
// Vérifier les event handlers inline dans le HTML
|
||
function checkInlineHandlers(htmlPath) {
|
||
try {
|
||
const content = fs.readFileSync(htmlPath, 'utf8')
|
||
const inlineHandlers = []
|
||
|
||
if (content.match(/onerror=/i)) inlineHandlers.push('onerror')
|
||
if (content.match(/onclick=/i)) inlineHandlers.push('onclick')
|
||
if (content.match(/onload=/i)) inlineHandlers.push('onload')
|
||
|
||
if (inlineHandlers.length > 0) {
|
||
issues.push(`Event handlers inline trouvés dans ${htmlPath}: ${inlineHandlers.join(', ')}`)
|
||
} else {
|
||
console.log('✓ Pas d\'event handlers inline dans le HTML')
|
||
}
|
||
} catch (error) {
|
||
issues.push(`Impossible de lire ${htmlPath}: ${error.message}`)
|
||
}
|
||
}
|
||
|
||
// Vérifier les fixes CSP dans sidepanel.js
|
||
function checkCSPFixes(jsPath) {
|
||
try {
|
||
const content = fs.readFileSync(jsPath, 'utf8')
|
||
|
||
// Vérifier l'absence de onerror inline
|
||
if (content.match(/onerror=/)) {
|
||
issues.push('Event handler onerror trouvé dans sidepanel.js')
|
||
} else {
|
||
console.log('✓ Pas de onerror inline dans sidepanel.js')
|
||
}
|
||
|
||
// Vérifier la présence du fix avec data-fallback
|
||
if (content.includes('data-fallback')) {
|
||
console.log('✓ Fix CSP data-favicon présent')
|
||
} else {
|
||
warnings.push('Fix CSP data-favicon可能缺失')
|
||
}
|
||
|
||
// Vérifier le handler de favicon
|
||
if (content.includes("querySelector('.page-favicon')")) {
|
||
console.log('✓ Handler error pour favicon présent')
|
||
} else {
|
||
warnings.push('Handler error pour favicon可能缺失')
|
||
}
|
||
|
||
} catch (error) {
|
||
issues.push(`Impossible de lire ${jsPath}: ${error.message}`)
|
||
}
|
||
}
|
||
|
||
// Vérifier le fix pick mode
|
||
function checkPickModeFix(jsPath) {
|
||
try {
|
||
const content = fs.readFileSync(jsPath, 'utf8')
|
||
|
||
// Vérifier le handler visibilitychange
|
||
if (content.includes('visibilityState === \'hidden\'')) {
|
||
console.log('✓ Handler visibilitychange pour hidden présent')
|
||
} else {
|
||
issues.push('Handler visibilitychange pour hidden manquant')
|
||
}
|
||
|
||
// Vérifier l'appel à setPickModeOnTab(false)
|
||
if (content.match(/visibilityState === 'hidden'.*setPickModeOnTab\(false\)/s)) {
|
||
console.log('✓ Appel setPickModeOnTab(false) dans visibilitychange présent')
|
||
} else {
|
||
issues.push('Appel setPickModeOnTab(false) dans visibilitychange可能缺失')
|
||
}
|
||
|
||
} catch (error) {
|
||
issues.push(`Impossible de lire ${jsPath}: ${error.message}`)
|
||
}
|
||
}
|
||
|
||
// Vérifier le manifest
|
||
function checkManifest(manifestPath) {
|
||
try {
|
||
const content = fs.readFileSync(manifestPath, 'utf8')
|
||
const manifest = JSON.parse(content)
|
||
|
||
console.log('✓ Manifest.json valide')
|
||
console.log(` Version: ${manifest.version}`)
|
||
console.log(` Permissions: ${manifest.permissions.join(', ')}`)
|
||
console.log(` Host permissions: ${manifest.host_permissions.length}`)
|
||
|
||
} catch (error) {
|
||
issues.push(`Manifest.json invalide: ${error.message}`)
|
||
}
|
||
}
|
||
|
||
// Exécuter les tests
|
||
console.log('📋 Vérification des fichiers...\n')
|
||
|
||
checkSyntax(path.join(extDir, 'sidepanel.js'))
|
||
checkSyntax(path.join(extDir, 'content.js'))
|
||
checkSyntax(path.join(extDir, 'background.js'))
|
||
|
||
console.log('\n🔒 Vérification CSP...\n')
|
||
checkInlineHandlers(path.join(extDir, 'sidepanel.html'))
|
||
checkCSPFixes(path.join(extDir, 'sidepanel.js'))
|
||
|
||
console.log('\n🎯 Vérification fix pick mode...\n')
|
||
checkPickModeFix(path.join(extDir, 'sidepanel.js'))
|
||
|
||
console.log('\n📦 Vérification manifest...\n')
|
||
checkManifest(path.join(extDir, 'manifest.json'))
|
||
|
||
// Résumé
|
||
console.log('\n' + '='.repeat(50))
|
||
if (issues.length === 0 && warnings.length === 0) {
|
||
console.log('✅ Aucun problème détecté !')
|
||
} else {
|
||
if (issues.length > 0) {
|
||
console.log('\n❌ Problèmes détectés:')
|
||
issues.forEach(issue => console.log(` • ${issue}`))
|
||
}
|
||
if (warnings.length > 0) {
|
||
console.log('\n⚠️ Warnings:')
|
||
warnings.forEach(warning => console.log(` • ${warning}`))
|
||
}
|
||
}
|
||
|
||
console.log('\n📝 Instructions:')
|
||
console.log('1. Rechargez l\'extension dans chrome://extensions (bouton 🔄)')
|
||
console.log('2. Ouvrez une page web normale')
|
||
console.log('3. Cliquez sur l\'icône Memento')
|
||
console.log('4. Fermez le sidepanel - la bannière doit disparaître')
|
||
console.log('5. Ouvrez la console (F12) - pas d\'erreur CSP')
|