208 lines
6.2 KiB
TypeScript
208 lines
6.2 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import type { CsoundReference } from './types';
|
|
|
|
export class TypeScriptGenerator {
|
|
private outputDir: string;
|
|
|
|
constructor(outputDir: string) {
|
|
this.outputDir = outputDir;
|
|
}
|
|
|
|
sanitizeCategoryName(category: string): string {
|
|
return category
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/^-+|-+$/g, '');
|
|
}
|
|
|
|
sanitizeVariableName(category: string): string {
|
|
return category
|
|
.replace(/[^a-zA-Z0-9]+/g, ' ')
|
|
.split(' ')
|
|
.map((word, index) =>
|
|
index === 0
|
|
? word.toLowerCase()
|
|
: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()
|
|
)
|
|
.join('')
|
|
.replace(/^[0-9]/, '_$&');
|
|
}
|
|
|
|
escapeString(str: string): string {
|
|
return str
|
|
.replace(/\\/g, '\\\\')
|
|
.replace(/'/g, "\\'")
|
|
.replace(/\n/g, '\\n')
|
|
.replace(/\r/g, '\\r')
|
|
.replace(/\t/g, '\\t');
|
|
}
|
|
|
|
generateReferenceObject(ref: CsoundReference, indent: string = ' '): string {
|
|
const lines: string[] = [];
|
|
lines.push(`{`);
|
|
lines.push(`${indent}name: '${this.escapeString(ref.name)}',`);
|
|
lines.push(`${indent}type: '${ref.type}',`);
|
|
lines.push(`${indent}category: '${this.escapeString(ref.category)}',`);
|
|
lines.push(`${indent}description: '${this.escapeString(ref.description)}',`);
|
|
|
|
if (ref.syntax) {
|
|
lines.push(`${indent}syntax: '${this.escapeString(ref.syntax)}',`);
|
|
}
|
|
|
|
if (ref.example) {
|
|
const escapedExample = this.escapeString(ref.example);
|
|
lines.push(`${indent}example: '${escapedExample}',`);
|
|
}
|
|
|
|
if (ref.rates && ref.rates.length > 0) {
|
|
lines.push(`${indent}rates: [${ref.rates.map(r => `'${r}'`).join(', ')}],`);
|
|
}
|
|
|
|
if (ref.parameters && ref.parameters.length > 0) {
|
|
lines.push(`${indent}parameters: [`);
|
|
for (const param of ref.parameters) {
|
|
lines.push(`${indent} {`);
|
|
lines.push(`${indent} name: '${this.escapeString(param.name)}',`);
|
|
lines.push(`${indent} description: '${this.escapeString(param.description)}',`);
|
|
lines.push(`${indent} type: '${param.type}'`);
|
|
lines.push(`${indent} },`);
|
|
}
|
|
lines.push(`${indent}],`);
|
|
}
|
|
|
|
if (ref.seeAlso && ref.seeAlso.length > 0) {
|
|
lines.push(`${indent}seeAlso: [${ref.seeAlso.map(s => `'${this.escapeString(s)}'`).join(', ')}]`);
|
|
}
|
|
|
|
lines.push(`}`);
|
|
return lines.join('\n');
|
|
}
|
|
|
|
generateCategoryFile(
|
|
category: string,
|
|
references: CsoundReference[],
|
|
fileName: string
|
|
): string {
|
|
const varName = this.sanitizeVariableName(category);
|
|
|
|
const lines: string[] = [];
|
|
lines.push(`import type { CsoundReference } from './types'`);
|
|
lines.push(``);
|
|
lines.push(`// ${category}`);
|
|
lines.push(`export const ${varName}: CsoundReference[] = [`);
|
|
|
|
for (const ref of references) {
|
|
const refLines = this.generateReferenceObject(ref, ' ');
|
|
lines.push(refLines + ',');
|
|
}
|
|
|
|
lines.push(`]`);
|
|
lines.push(``);
|
|
|
|
return lines.join('\n');
|
|
}
|
|
|
|
generateMainFile(categories: Map<string, CsoundReference[]>): string {
|
|
const lines: string[] = [];
|
|
|
|
lines.push(`import type { CsoundReference } from './types'`);
|
|
|
|
const imports: string[] = [];
|
|
const varNames: string[] = [];
|
|
|
|
for (const [category] of categories) {
|
|
const fileName = this.sanitizeCategoryName(category);
|
|
const varName = this.sanitizeVariableName(category);
|
|
imports.push(`import { ${varName} } from './${fileName}'`);
|
|
varNames.push(varName);
|
|
}
|
|
|
|
lines.push(...imports);
|
|
lines.push(``);
|
|
lines.push(`export type { CsoundReference }`);
|
|
lines.push(``);
|
|
lines.push(`export const allCsoundReferences: CsoundReference[] = [`);
|
|
for (const varName of varNames) {
|
|
lines.push(` ...${varName},`);
|
|
}
|
|
lines.push(`]`);
|
|
lines.push(``);
|
|
|
|
lines.push(`export const csoundReferenceMap = new Map<string, CsoundReference>()`);
|
|
lines.push(`allCsoundReferences.forEach(ref => {`);
|
|
lines.push(` csoundReferenceMap.set(ref.name, ref)`);
|
|
lines.push(`})`);
|
|
lines.push(``);
|
|
|
|
lines.push(`export function getCsoundReference(name: string): CsoundReference | undefined {`);
|
|
lines.push(` return csoundReferenceMap.get(name)`);
|
|
lines.push(`}`);
|
|
lines.push(``);
|
|
|
|
lines.push(`export function getCsoundReferencesByCategory(category: string): CsoundReference[] {`);
|
|
lines.push(` return allCsoundReferences.filter(ref => ref.category === category)`);
|
|
lines.push(`}`);
|
|
lines.push(``);
|
|
|
|
lines.push(`export {`);
|
|
for (const varName of varNames) {
|
|
lines.push(` ${varName},`);
|
|
}
|
|
lines.push(`}`);
|
|
lines.push(``);
|
|
|
|
return lines.join('\n');
|
|
}
|
|
|
|
writeCategoryFiles(categories: Map<string, CsoundReference[]>): void {
|
|
if (!fs.existsSync(this.outputDir)) {
|
|
fs.mkdirSync(this.outputDir, { recursive: true });
|
|
}
|
|
|
|
let fileCount = 0;
|
|
|
|
for (const [category, references] of categories) {
|
|
const fileName = this.sanitizeCategoryName(category);
|
|
const filePath = path.join(this.outputDir, `${fileName}.ts`);
|
|
const content = this.generateCategoryFile(category, references, fileName);
|
|
|
|
fs.writeFileSync(filePath, content, 'utf-8');
|
|
fileCount++;
|
|
console.log(`Generated: ${fileName}.ts (${references.length} opcodes)`);
|
|
}
|
|
|
|
console.log(`\nGenerated ${fileCount} category files`);
|
|
}
|
|
|
|
writeMainFile(categories: Map<string, CsoundReference[]>): void {
|
|
const filePath = path.join(this.outputDir, 'csoundReference.ts');
|
|
const content = this.generateMainFile(categories);
|
|
|
|
fs.writeFileSync(filePath, content, 'utf-8');
|
|
console.log(`Generated: csoundReference.ts`);
|
|
}
|
|
|
|
copyTypes(): void {
|
|
if (!fs.existsSync(this.outputDir)) {
|
|
fs.mkdirSync(this.outputDir, { recursive: true });
|
|
}
|
|
|
|
const sourceTypes = path.join(__dirname, 'types.ts');
|
|
const destTypes = path.join(this.outputDir, 'types.ts');
|
|
|
|
if (fs.existsSync(sourceTypes)) {
|
|
fs.copyFileSync(sourceTypes, destTypes);
|
|
console.log(`Copied: types.ts`);
|
|
}
|
|
}
|
|
|
|
generateAll(categories: Map<string, CsoundReference[]>): void {
|
|
console.log(`\nGenerating TypeScript files...`);
|
|
this.copyTypes();
|
|
this.writeCategoryFiles(categories);
|
|
this.writeMainFile(categories);
|
|
console.log(`\nDone!`);
|
|
}
|
|
}
|