convert-md-to-json.js•4.97 kB
#!/usr/bin/env node
import { readFileSync, writeFileSync, readdirSync, statSync, mkdirSync } from 'fs';
import { join, dirname, basename, relative } from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const dataDir = join(__dirname, '..', 'data');
const docsDir = join(__dirname, '..', 'docs');
function parseMdToJson(mdContent, filePath, metadata = null) {
const lines = mdContent.split('\n');
const categories = [];
let currentCategory = null;
// Use provided metadata or extract from file path
let os, desktop, application, fileName;
if (metadata) {
os = metadata.os;
desktop = metadata.desktop || null;
application = metadata.application || null;
fileName = metadata.file;
} else {
// Extract from file path
const relativePath = relative(dataDir, filePath);
const parts = relativePath.split('/');
os = parts[0]; // ubuntu
const type = parts[1]; // desktops, apps, tools
desktop = null;
application = null;
if (type === 'desktops') {
desktop = parts[2]; // gnome
} else if (type === 'apps') {
application = basename(filePath, '.md');
} else if (type === 'tools') {
application = basename(filePath, '.md');
}
fileName = basename(filePath, '.md');
}
for (const line of lines) {
// Skip title lines and TOC
if (line.startsWith('# ') || line.startsWith('- [')) continue;
if (line.trim() === '---') continue; // Skip dividers
// Main category header (##)
if (line.startsWith('## ')) {
if (currentCategory && currentCategory.shortcuts.length > 0) {
categories.push(currentCategory);
}
currentCategory = {
name: line.replace('## ', '').trim(),
shortcuts: []
};
continue;
}
// Sub-category header (###) - append to current category name
if (line.startsWith('### ')) {
if (currentCategory && currentCategory.shortcuts.length > 0) {
categories.push(currentCategory);
}
const subName = line.replace('### ', '').trim();
// Keep parent category context if exists
const parentName = currentCategory ? currentCategory.name.split(' - ')[0] : '';
currentCategory = {
name: parentName ? `${parentName} - ${subName}` : subName,
shortcuts: []
};
continue;
}
// Shortcut patterns:
// - `keys` - description
// - **keys** - description (bold format)
const match1 = line.match(/^-\s+`([^`]+)`\s+-\s+(.+)$/);
const match2 = line.match(/^-\s+\*\*([^*]+)\*\*\s+-\s+(.+)$/);
const match = match1 || match2;
if (match && currentCategory) {
currentCategory.shortcuts.push({
keys: match[1].trim(),
description: match[2].trim()
});
}
}
// Add last category
if (currentCategory && currentCategory.shortcuts.length > 0) {
categories.push(currentCategory);
}
return {
os,
desktop,
application,
file: fileName,
categories
};
}
function convertFile(mdPath) {
try {
const mdContent = readFileSync(mdPath, 'utf-8');
const jsonData = parseMdToJson(mdContent, mdPath);
const jsonPath = mdPath.replace('.md', '.json');
writeFileSync(jsonPath, JSON.stringify(jsonData, null, 2));
console.log(`✓ Converted: ${relative(dataDir, mdPath)}`);
} catch (error) {
console.error(`✗ Failed: ${relative(dataDir, mdPath)}`, error.message);
}
}
function findMdFiles(dir) {
const files = [];
const entries = readdirSync(dir);
for (const entry of entries) {
const fullPath = join(dir, entry);
const stat = statSync(fullPath);
if (stat.isDirectory()) {
files.push(...findMdFiles(fullPath));
} else if (entry.endsWith('.md')) {
files.push(fullPath);
}
}
return files;
}
// Convert docs/ files with manual metadata
function convertDocsFile(mdFileName, metadata) {
const mdPath = join(docsDir, mdFileName);
const outputDir = join(dataDir, metadata.os, 'desktops', metadata.desktop);
try {
mkdirSync(outputDir, { recursive: true });
const mdContent = readFileSync(mdPath, 'utf-8');
const jsonData = parseMdToJson(mdContent, mdPath, metadata);
const jsonPath = join(outputDir, `${metadata.file}.json`);
writeFileSync(jsonPath, JSON.stringify(jsonData, null, 2));
console.log(`✓ Converted: docs/${mdFileName} → ${relative(dataDir, jsonPath)}`);
} catch (error) {
console.error(`✗ Failed: docs/${mdFileName}`, error.message);
}
}
// Main execution
const mdFiles = findMdFiles(dataDir);
console.log(`Found ${mdFiles.length} markdown files in data/ to convert\n`);
for (const mdFile of mdFiles) {
convertFile(mdFile);
}
// Convert KDE shortcuts for Ubuntu
console.log('\nConverting docs/ files...\n');
convertDocsFile('kde.md', {
os: 'ubuntu',
desktop: 'kde',
file: 'kde-shortcuts'
});
console.log(`\n✓ Conversion complete!`);