docs-v2/scripts/docs-cli.js

237 lines
6.5 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Main CLI entry point for docs tools
* Supports subcommands: create, edit, placeholders
*
* Usage:
* docs create <draft-path> [options]
* docs edit <url> [options]
* docs placeholders <file.md> [options]
*/
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { spawn } from 'child_process';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Get subcommand and remaining arguments
const subcommand = process.argv[2];
const args = process.argv.slice(3);
// Map subcommands to script files
const subcommands = {
create: 'docs-create.js',
edit: 'docs-edit.js',
placeholders: 'add-placeholders.js',
};
/**
* Print usage information
*/
function printUsage() {
console.log(`
Usage: docs <command> [options]
Commands:
create <draft-path> Create new documentation from draft
edit <url> Edit existing documentation
placeholders <file.md> Add placeholder syntax to code blocks
test Run test suite to verify CLI functionality
Examples:
docs create drafts/new-feature.md --products influxdb3_core
docs edit https://docs.influxdata.com/influxdb3/core/admin/
docs placeholders content/influxdb3/core/admin/upgrade.md
docs test
For command-specific help:
docs create --help
docs edit --help
docs placeholders --help
`);
}
// Handle test command (async, so don't continue)
if (subcommand === 'test') {
runTests();
} else if (!subcommand || subcommand === '--help' || subcommand === '-h') {
// Handle no subcommand or help
printUsage();
process.exit(subcommand ? 0 : 1);
} else if (!subcommands[subcommand]) {
// Validate subcommand
console.error(`Error: Unknown command '${subcommand}'`);
console.error(`Run 'docs --help' for usage information`);
process.exit(1);
} else {
// Execute the appropriate script
const scriptPath = join(__dirname, subcommands[subcommand]);
const child = spawn('node', [scriptPath, ...args], {
stdio: 'inherit',
env: process.env,
});
child.on('exit', (code) => {
process.exit(code || 0);
});
child.on('error', (err) => {
console.error(`Failed to execute ${subcommand}:`, err.message);
process.exit(1);
});
}
/**
* Test function to verify docs CLI functionality
* Run with: npx docs test
*/
function runTests() {
import('child_process').then(({ execSync }) => {
const tests = [];
const testResults = [];
console.log('\n🧪 Testing docs CLI functionality...\n');
// Test 1: docs --help
tests.push({
name: 'docs --help',
command: 'npx docs --help',
expectedInOutput: [
'create <draft-path>',
'edit <url>',
'placeholders <file.md>',
],
});
// Test 2: docs create --help
tests.push({
name: 'docs create --help',
command: 'npx docs create --help',
expectedInOutput: [
'Documentation Content Scaffolding',
'--products',
'Pipe to external agent',
],
});
// Test 3: docs edit --help
tests.push({
name: 'docs edit --help',
command: 'npx docs edit --help',
expectedInOutput: ['Documentation File Opener', '--list'],
});
// Test 4: docs placeholders --help
tests.push({
name: 'docs placeholders --help',
command: 'npx docs placeholders --help',
expectedInOutput: [
'Add placeholder syntax',
'--dry',
'code-placeholder-key',
],
});
// Test 5: docs placeholders with missing args shows error
tests.push({
name: 'docs placeholders (no args)',
command: 'npx docs placeholders 2>&1',
expectedInOutput: ['Error: Missing file path'],
expectFailure: true,
});
// Test 6: Verify symlink exists
tests.push({
name: 'symlink exists',
command: 'ls -la node_modules/.bin/docs',
expectedInOutput: ['scripts/docs-cli.js'],
});
// Test 7: Unknown command shows error
tests.push({
name: 'unknown command',
command: 'npx docs invalid-command 2>&1',
expectedInOutput: ['Error: Unknown command'],
expectFailure: true,
});
// Run tests
for (const test of tests) {
try {
const output = execSync(test.command, {
encoding: 'utf8',
stdio: 'pipe',
});
const passed = test.expectedInOutput.every((expected) =>
output.includes(expected)
);
if (passed) {
console.log(`${test.name}`);
testResults.push({ name: test.name, passed: true });
} else {
console.log(`${test.name} - Expected output not found`);
console.log(` Expected: ${test.expectedInOutput.join(', ')}`);
testResults.push({
name: test.name,
passed: false,
reason: 'Expected output not found',
});
}
} catch (error) {
if (test.expectFailure) {
// Expected to fail - check if error output contains expected strings
const errorOutput =
error.stderr?.toString() || error.stdout?.toString() || '';
const passed = test.expectedInOutput.every((expected) =>
errorOutput.includes(expected)
);
if (passed) {
console.log(`${test.name} (expected failure)`);
testResults.push({ name: test.name, passed: true });
} else {
console.log(`${test.name} - Expected error message not found`);
console.log(` Expected: ${test.expectedInOutput.join(', ')}`);
testResults.push({
name: test.name,
passed: false,
reason: 'Expected error message not found',
});
}
} else {
console.log(`${test.name} - Command failed unexpectedly`);
console.log(` Error: ${error.message}`);
testResults.push({
name: test.name,
passed: false,
reason: error.message,
});
}
}
}
const passed = testResults.filter((r) => r.passed).length;
const failed = testResults.filter((r) => !r.passed).length;
console.log(`\n📊 Test Results: ${passed}/${tests.length} passed`);
if (failed > 0) {
console.log(`\n❌ Failed tests:`);
testResults
.filter((r) => !r.passed)
.forEach((r) => {
console.log(` - ${r.name}: ${r.reason}`);
});
process.exit(1);
} else {
console.log(`\n✅ All tests passed!\n`);
process.exit(0);
}
});
}