node-osc
Version:
pyOSC inspired library for sending and receiving OSC messages
230 lines (191 loc) • 6.66 kB
JavaScript
/**
* Converts JSDoc JSON output to Markdown documentation.
* This script reads JSDoc JSON data and generates a formatted Markdown file.
*/
import { writeFileSync } from 'node:fs';
import { execSync } from 'node:child_process';
// Generate JSDoc JSON
let jsdocJson;
try {
jsdocJson = execSync('npx jsdoc -X -c jsdoc.json', {
encoding: 'utf8',
maxBuffer: 10 * 1024 * 1024
});
} catch (error) {
console.error('❌ Failed to run JSDoc:');
console.error(error.message);
process.exit(1);
}
let docs;
try {
docs = JSON.parse(jsdocJson);
} catch (error) {
console.error('❌ Failed to parse JSDoc JSON output:');
console.error(error.message);
process.exit(1);
}
// Filter and organize documentation
const classes = {};
const functions = {};
docs.forEach(item => {
if (item.undocumented || item.ignore) return;
if (item.kind === 'class' && item.classdesc) {
if (!classes[item.name]) {
classes[item.name] = {
desc: item.classdesc,
constructor: null,
methods: [],
examples: item.examples || [],
augments: item.augments || []
};
}
// Look for constructor params
if (item.params) {
classes[item.name].constructor = {
params: item.params,
examples: item.examples || []
};
}
} else if (item.kind === 'function' && item.memberof) {
// Method of a class
const className = item.memberof;
if (!classes[className]) {
classes[className] = {
desc: '',
constructor: null,
methods: [],
examples: []
};
}
classes[className].methods.push(item);
} else if (item.kind === 'function' && !item.memberof && item.scope === 'global') {
// Top-level function
functions[item.name] = item;
}
});
// Generate Markdown
let markdown = `<!-- Generated by JSDoc. Update this documentation by updating the source code. -->
# API Reference
> **⚠️ This file is auto-generated from JSDoc comments in the source code.**
> To update this documentation, edit the JSDoc comments in the source files and run \`npm run docs\`.
This document provides detailed API reference for all classes, methods, and functions in node-osc.
For usage guides, best practices, and troubleshooting, see the **[Guide](./GUIDE.md)**.
## Table of Contents
`;
// Define order: Server → Client → Message → Bundle → Low Level
const classOrder = ['Server', 'Client', 'Message', 'Bundle'];
const functionOrder = ['encode', 'decode'];
// Add classes to TOC
classOrder.forEach(name => {
if (classes[name]) {
markdown += `- [${name}](#${name.toLowerCase()})\n`;
if (classes[name].constructor) {
markdown += ` - [Constructor](#${name.toLowerCase()}-constructor)\n`;
}
classes[name].methods.forEach(method => {
markdown += ` - [${method.name}()](#${name.toLowerCase()}-${method.name.toLowerCase()})\n`;
});
}
});
// Add functions to TOC
markdown += `- [Low Level Functions](#low-level-functions)\n`;
functionOrder.forEach(name => {
if (functions[name]) {
markdown += ` - [${name}()](#${name.toLowerCase()})\n`;
}
});
markdown += `\n---\n\n`;
// Helper function to format parameters
function formatParams(params) {
if (!params || params.length === 0) return '';
let result = '\n**Parameters:**\n\n';
params.forEach(param => {
const optional = param.optional ? ' (optional)' : '';
const defaultVal = param.defaultvalue ? ` - Default: \`${param.defaultvalue}\`` : '';
const types = param.type ? param.type.names.join(' | ') : 'any';
result += `- \`${param.name}\` *{${types}}*${optional}${defaultVal} - ${param.description || ''}\n`;
});
return result;
}
// Helper function to format examples
function formatExamples(examples) {
if (!examples || examples.length === 0) return '';
let result = '\n**Examples:**\n\n';
examples.forEach(example => {
result += '```javascript\n' + example + '\n```\n\n';
});
return result;
}
// Helper function to format returns
function formatReturns(returns) {
if (!returns || returns.length === 0) return '';
const ret = returns[0];
const types = ret.type ? ret.type.names.join(' | ') : 'any';
return `\n**Returns:** *{${types}}* - ${ret.description || ''}\n`;
}
// Helper function to format throws
function formatThrows(exceptions) {
if (!exceptions || exceptions.length === 0) return '';
let result = '\n**Throws:**\n\n';
exceptions.forEach(ex => {
const types = ex.type ? ex.type.names.join(' | ') : 'Error';
result += `- *{${types}}* - ${ex.description || ''}\n`;
});
return result;
}
// Generate class documentation
classOrder.forEach(className => {
const classInfo = classes[className];
if (!classInfo) return;
markdown += `## ${className}\n\n`;
// Add extends info
if (classInfo.augments && classInfo.augments.length > 0) {
markdown += `**Extends:** ${classInfo.augments.join(', ')}\n\n`;
}
markdown += `${classInfo.desc}\n`;
// Class-level examples
if (classInfo.examples.length > 0 && !classInfo.constructor) {
markdown += formatExamples(classInfo.examples);
}
// Constructor
if (classInfo.constructor) {
markdown += `\n### ${className} Constructor\n\n`;
markdown += `Creates a new ${className} instance.\n`;
markdown += formatParams(classInfo.constructor.params);
markdown += formatExamples(classInfo.constructor.examples);
}
// Methods
classInfo.methods.forEach(method => {
markdown += `\n### ${className}.${method.name}()\n\n`;
markdown += `${method.description || ''}\n`;
markdown += formatParams(method.params);
markdown += formatReturns(method.returns);
markdown += formatThrows(method.exceptions);
markdown += formatExamples(method.examples);
});
markdown += `\n---\n\n`;
});
// Generate function documentation
markdown += `## Low Level Functions\n\n`;
markdown += `These functions provide low-level access to OSC encoding and decoding for advanced use cases.\n\n`;
functionOrder.forEach(funcName => {
const func = functions[funcName];
if (!func) return;
markdown += `### ${funcName}()\n\n`;
markdown += `${func.description || ''}\n`;
markdown += formatParams(func.params);
markdown += formatReturns(func.returns);
markdown += formatThrows(func.exceptions);
markdown += formatExamples(func.examples);
markdown += `\n`;
});
// Write output
try {
writeFileSync('docs/API.md', markdown, 'utf8');
console.log('✅ API documentation generated: docs/API.md');
} catch (error) {
console.error('❌ Failed to write API.md:');
console.error(error.message);
process.exit(1);
}