230 lines
6.5 KiB
JavaScript
Executable File
230 lines
6.5 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
/**
|
|
* 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);
|
|
}
|