Files
TechradarDev/scripts/extract-technologies.js
syoul 055e4a9281 refactor: réorganiser la documentation en séparant app et data
- Création de docs/app/ pour la documentation de l'application
- Création de docs/data/ pour les données utilisées par l'application
- Déplacement de la documentation technique vers docs/app/
- Déplacement des données métier vers docs/data/
- Mise à jour de tous les liens et références dans les fichiers
- Mise à jour des scripts (extract-technologies.js, analyze-business-metrics.js)
- Mise à jour des fichiers JavaScript (custom.js, strategie-link.js)
- Création de README.md dans docs/, docs/app/ et docs/data/
- Mise à jour du Readme.md principal avec les nouveaux chemins
2025-12-03 14:35:36 +01:00

262 lines
11 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Script pour extraire les technologies de technologies-duniter.md
* et générer les blips pour le radar business
*/
const fs = require('fs');
const path = require('path');
// Mapping des compétences de l'équipe
const teamSkills = {
'poka': ['Flutter', 'Dart', 'ProxMox', 'bash', 'Python', 'infrastructure'],
'ManUtopiK': ['VueJS', 'Nuxt.js', 'JavaScript', 'TypeScript', 'CMS', 'web'],
'aya': ['Linux', 'glusterfs', 'cephfs', 'ipfs', 'infrastructure', 'systèmes distribués', 'ThreeFold'],
'Eloïs': ['Rust', 'blockchain', 'Substrate', 'migration'],
'Fred': ['IPFS', 'Secure ScuttleButt', 'Nostr', 'TiddlyWiki', 'développement', 'ThreeFold'],
'Vivien': ['Cesium', 'Godot'],
'1000i100': ['Serverless', 'GitLab', 'CI/CD', 'Docker', 'web'],
'tuxmain': ['cryptographie', 'chiffrage', 'math', 'électronique'],
'boris': ['UX', 'UI', 'Figma', 'LLM', 'JavaScript', 'TypeScript', 'APIs', 'Vis.js'],
'Syoul': ['bidouille', 'résilience', 'domotique', 'infrastructure décentralisée'],
'Hugo': ['financement', 'rédaction', 'gestion'],
'Yvv': ['gestion', 'médiathèque', 'wiki']
};
// Mapping technologies -> compétences de l'équipe
function findTeamCoverage(techName, techKeywords) {
const coverage = new Set();
const techLower = techName.toLowerCase();
const keywords = techKeywords.map(k => k.toLowerCase());
for (const [member, skills] of Object.entries(teamSkills)) {
const memberSkills = skills.map(s => s.toLowerCase());
// Vérifier si le nom de la technologie correspond
if (memberSkills.some(skill => techLower.includes(skill) || skill.includes(techLower))) {
coverage.add(member);
}
// Vérifier les mots-clés
for (const keyword of keywords) {
if (memberSkills.some(skill => keyword.includes(skill) || skill.includes(keyword))) {
coverage.add(member);
}
}
}
return {
count: coverage.size,
members: Array.from(coverage),
level: coverage.size >= 3 ? 'expert' : coverage.size >= 2 ? 'intermediate' : 'beginner',
gap: coverage.size === 0 ? 'high' : coverage.size === 1 ? 'high' : coverage.size === 2 ? 'medium' : 'low'
};
}
// Classification par quadrant et ring (à affiner manuellement)
function classifyTechnology(techName, category) {
const name = techName.toLowerCase();
// Technologies différenciantes (core/strategic)
if (name.includes('rust') || name.includes('substrate') || name.includes('blockchain')) {
return {
quadrant: 'technologies-differentiantes',
ring: 'core',
businessImpact: 'high',
differentiation: 'high',
riskLevel: 'medium'
};
}
// Technologies de commodité (support)
if (name.includes('docker') || name.includes('postgresql') || name.includes('linux')) {
return {
quadrant: 'technologies-commodite',
ring: 'support',
businessImpact: 'medium',
differentiation: 'low',
riskLevel: 'low'
};
}
// Technologies émergentes (strategic/assess)
if (name.includes('ipfs') || name.includes('nostr') || name.includes('serverless') ||
name.includes('threefold') || name.includes('zero os') || name.includes('mycelium') ||
name.includes('aibox') || name.includes('3node') || name.includes('d3.js') ||
name.includes('echarts') || name.includes('grafana') || name.includes('leaflet') ||
name.includes('cytoscape')) {
return {
quadrant: 'technologies-emergentes',
ring: 'strategic',
businessImpact: 'high',
differentiation: 'high',
riskLevel: 'medium'
};
}
// Par défaut
return {
quadrant: 'technologies-commodite',
ring: 'support',
businessImpact: 'medium',
differentiation: 'medium',
riskLevel: 'medium'
};
}
// Générer un blip
function generateBlip(tech, category, description) {
const classification = classifyTechnology(tech.name, category);
const coverage = findTeamCoverage(tech.name, tech.keywords || []);
const blip = `---
title: "${tech.name}"
ring: ${classification.ring}
quadrant: ${classification.quadrant}
tags: [${(tech.tags || []).join(', ')}]
businessImpact: ${classification.businessImpact}
costToReplace: ${tech.costToReplace || 0}
revenueImpact: ${tech.revenueImpact || 'indirect'}
riskLevel: ${classification.riskLevel}
competencyLevel: ${coverage.level}
maintenanceCost: ${tech.maintenanceCost || 0}
differentiation: ${classification.differentiation}
teamCoverage: ${coverage.count}
skillGap: ${coverage.gap}
---
${description || tech.description || `Description de ${tech.name}.`}
## Impact Business
${tech.businessImpact || 'À compléter'}
## Coûts
- Coût de remplacement : ${tech.costToReplace || 0}
- Coût de maintenance annuel : ${tech.maintenanceCost || 0}
## Compétences
- Nombre de personnes maîtrisant : ${coverage.count}
- Membres de l'équipe : ${coverage.members.join(', ') || 'Aucun'}
- Niveau moyen : ${coverage.level}
- Risque de compétence manquante : ${coverage.gap}
## Recommandations
${tech.recommendations || 'À compléter avec des recommandations stratégiques.'}
`;
return blip;
}
// Parser le fichier technologies-duniter.md
function parseTechnologiesFile(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const technologies = [];
// Liste des technologies principales à extraire
const techList = [
{ name: 'Rust', keywords: ['Rust', 'blockchain', 'Substrate'], category: 'Langages' },
{ name: 'Python', keywords: ['Python', 'CLI'], category: 'Langages' },
{ name: 'JavaScript/TypeScript', keywords: ['JavaScript', 'TypeScript', 'web'], category: 'Langages' },
{ name: 'Dart', keywords: ['Dart', 'Flutter'], category: 'Langages' },
{ name: 'Substrate Framework', keywords: ['Substrate', 'Rust', 'blockchain'], category: 'Frameworks' },
{ name: 'Nuxt.js', keywords: ['Nuxt', 'Vue', 'SSR'], category: 'Frameworks' },
{ name: 'Vue.js', keywords: ['Vue', 'JavaScript'], category: 'Frameworks' },
{ name: 'Flutter', keywords: ['Flutter', 'Dart'], category: 'Frameworks' },
{ name: 'NetlifyCMS', keywords: ['CMS', 'Git'], category: 'CMS' },
{ name: 'WordUp CMS', keywords: ['CMS'], category: 'CMS' },
{ name: 'Docker', keywords: ['Docker', 'conteneurisation'], category: 'Infrastructure' },
{ name: 'Kubernetes', keywords: ['Kubernetes', 'orchestration'], category: 'Infrastructure' },
{ name: 'PostgreSQL', keywords: ['PostgreSQL', 'base de données'], category: 'Infrastructure' },
{ name: 'ProxMox', keywords: ['ProxMox', 'virtualisation'], category: 'Infrastructure' },
{ name: 'Linux', keywords: ['Linux', 'système'], category: 'Infrastructure' },
{ name: 'IPFS', keywords: ['IPFS', 'distribué'], category: 'Technologies distribuées' },
{ name: 'Nostr', keywords: ['Nostr', 'protocole'], category: 'Technologies distribuées' },
{ name: 'GitLab CI/CD', keywords: ['GitLab', 'CI/CD'], category: 'DevOps' },
{ name: 'Serverless', keywords: ['Serverless'], category: 'Architecture' },
{ name: 'Squid', keywords: ['Squid', 'indexer', 'GraphQL'], category: 'Outils' },
{ name: 'Cryptographie', keywords: ['cryptographie', 'chiffrage'], category: 'Sécurité' },
{ name: 'Bash', keywords: ['bash', 'scripting'], category: 'Outils' },
// Technologies ThreeFold
{ name: 'Zero OS', keywords: ['Zero OS', 'bare metal', 'cloud décentralisé'], category: 'Infrastructure décentralisée' },
{ name: 'ThreeFold Grid', keywords: ['ThreeFold', 'Grid', 'infrastructure décentralisée'], category: 'Infrastructure décentralisée' },
{ name: '3Node', keywords: ['3Node', 'nœuds', 'serveurs'], category: 'Infrastructure décentralisée' },
{ name: 'ThreeFold Compute', keywords: ['ThreeFold', 'Compute', 'edge computing'], category: 'Infrastructure décentralisée' },
{ name: 'ThreeFold Data Storage', keywords: ['ThreeFold', 'Storage', 'stockage distribué'], category: 'Infrastructure décentralisée' },
{ name: 'Mycelium Network', keywords: ['Mycelium', 'Network', 'réseau overlay'], category: 'Infrastructure décentralisée' },
{ name: 'ThreeFold Blockchain', keywords: ['ThreeFold', 'Blockchain'], category: 'Blockchain' },
{ name: 'ThreeFold Cloud', keywords: ['ThreeFold', 'Cloud', 'Kubernetes'], category: 'Cloud décentralisé' },
{ name: 'AIBox', keywords: ['AIBox', 'IA', 'machine learning'], category: 'IA' },
// Technologies DataViz
{ name: 'D3.js', keywords: ['D3.js', 'DataViz', 'JavaScript'], category: 'Data Visualization' },
{ name: 'ECharts', keywords: ['ECharts', 'DataViz', 'Apache'], category: 'Data Visualization' },
{ name: 'Grafana', keywords: ['Grafana', 'Monitoring', 'Dashboard'], category: 'Data Visualization' },
{ name: 'Leaflet', keywords: ['Leaflet', 'Cartographie', 'Map'], category: 'Data Visualization' },
{ name: 'Cytoscape.js', keywords: ['Cytoscape', 'Graphes', 'Réseaux'], category: 'Data Visualization' }
];
// Pour chaque technologie, créer un blip
for (const tech of techList) {
// Extraire la description depuis le fichier si disponible
let description = '';
const techRegex = new RegExp(`#### ${tech.name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}[\\s\\S]*?(?=#### |## |$)`, 'i');
const match = content.match(techRegex);
if (match) {
description = match[0].split('\n').slice(1).join('\n').trim();
// Limiter à 10 lignes
description = description.split('\n').slice(0, 10).join('\n');
} else {
description = `Technologie ${tech.name} utilisée dans l'écosystème Duniter/Ğ1.`;
}
technologies.push({
name: tech.name,
category: tech.category,
description: description,
keywords: tech.keywords,
tags: tech.keywords.slice(0, 3)
});
}
return technologies;
}
// Main
function main() {
const techFile = path.join(__dirname, '../docs/data/technologies-duniter.md');
const outputDir = path.join(__dirname, '../radar-business/2025-01-15');
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
console.log('Extraction des technologies...');
const technologies = parseTechnologiesFile(techFile);
console.log(`Trouvé ${technologies.length} technologies`);
for (const tech of technologies) {
const blip = generateBlip(tech, tech.category, tech.description);
const filename = tech.name.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '') + '.md';
const filePath = path.join(outputDir, filename);
fs.writeFileSync(filePath, blip, 'utf-8');
console.log(`Généré: ${filename}`);
}
console.log(`\n${technologies.length} blips générés dans ${outputDir}`);
}
if (require.main === module) {
main();
}
module.exports = { parseTechnologiesFile, generateBlip, findTeamCoverage };