import { CommentAnalyzer } from "../analyzer/CommentAnalyzer";
import { FileEndAnalyzer } from "../analyzer/FileEndAnalyzer";
import { SCIPAnalyzer } from "../analyzer/SCIPAnalyzer";
import { TSHighLighter } from "../analyzer/TSHighlighter";
import { HTMLGenerator } from "../generator/HTMLGenerator";
import { MarkdownGenerator } from "../generator/MarkdownGenerator";
import {
CommentMergePass,
FillPlaintextPass,
MergeTokenPass,
SortTokenPass,
SplitByLinePass,
} from "../passes";
import type { CireConfig, DocGenerator, FileIR, TokenInfo } from "../types";
export class WorkflowManager {
private tsHighlighter: TSHighLighter;
private scipAnalyzer: SCIPAnalyzer | null = null;
private eofAnalyzer: FileEndAnalyzer | null = null;
private commentAnalyzer: CommentAnalyzer;
private generator: DocGenerator;
private config: CireConfig;
constructor(config: CireConfig) {
this.config = config;
// Initialize components
this.tsHighlighter = new TSHighLighter(config.input.language);
this.commentAnalyzer = new CommentAnalyzer();
// Initialize generator based on output format
const backend = config.outputFormat?.backend || "html";
if (backend === "markdown") {
this.generator = new MarkdownGenerator(config);
this.eofAnalyzer = new FileEndAnalyzer();
} else {
this.generator = new HTMLGenerator(config);
}
// Initialize SCIP analyzer if SCIP index path is provided
// Note: SCIPAnalyzer provides both hover documentation AND definition jumping functionality
if (config.lsp?.indexPath) {
this.scipAnalyzer = new SCIPAnalyzer(config.lsp.indexPath);
}
}
Process a file through the complete workflow
processFile(fileIR: FileIR, projectRoot: string): string {
console.log(`Processing file: `);
// Step 1: Extract syntax highlighting tokens
const allTokens: TokenInfo[] = [];
if (this.config.features?.syntaxHighlighting ?? true) {
console.log(" → Extracting syntax highlighting tokens...");
const highlightTokens = this.tsHighlighter.analyze(
fileIR,
projectRoot,
);
allTokens.push(...highlightTokens);
console.log(` Found syntax tokens`);
}
// Step 2: Extract comment tokens
if (this.config.features?.commentMarkdown ?? true) {
console.log(" → Extracting comment tokens...");
const commentTokens = this.commentAnalyzer.analyze(
fileIR,
projectRoot,
);
allTokens.push(...commentTokens);
console.log(` Found comment tokens`);
}
// Step 3: Extract definition and hover documentation tokens from SCIP
if (
((this.config.features?.hoverDocumentation ?? false) ||
(this.config.features?.definitionJumping ?? false)) &&
this.scipAnalyzer
) {
const scipTokens = this.scipAnalyzer.analyze(fileIR, projectRoot);
allTokens.push(...scipTokens);
}
if (this.eofAnalyzer) {
allTokens.push(...this.eofAnalyzer.analyze(fileIR, projectRoot));
}
// Step 4: Merge and deduplicate tokens
console.log(" → Merging and deduplicating tokens...");
const mergedTokens = this.mergeTokens(allTokens);
console.log(` Final count: unique tokens`);
// Step 5: Generate output
const backend = this.config.outputFormat?.backend || "html";
console.log(` → Generating ...`);
const output = this.generator.generate(
fileIR,
mergedTokens,
projectRoot,
);
console.log(` → generation complete!`);
return output;
}
Merge tokens from multiple analyzers and resolve overlaps
private mergeTokens(tokens: TokenInfo[]): TokenInfo[] {
if (tokens.length === 0) {
return [];
}
// Use professional passes instead of manual implementation
const sortPass = new SortTokenPass();
const mergePass = new MergeTokenPass();
const commentMergePass = new CommentMergePass();
const fillPlaintextPass = new FillPlaintextPass();
const splitByLinePass = new SplitByLinePass();
// Process tokens through the pipeline: sort → merge → comment merge → fill plaintext
const sortedTokens = sortPass.process(tokens);
const mergedTokens = mergePass.process(sortedTokens);
const commentMergedTokens = commentMergePass.process(mergedTokens);
const filledTokens = fillPlaintextPass.process(commentMergedTokens);
// Apply SplitByLinePass only for Markdown output to ensure tokens don't span multiple lines
const backend = this.config.outputFormat?.backend || "html";
const finalTokens =
backend === "markdown"
? splitByLinePass.process(filledTokens)
: filledTokens;
return finalTokens;
}
Get workflow statistics
getStats(): { syntaxHighlighter: boolean; scipAnalyzer: boolean } {
return {
syntaxHighlighter: !!(
this.config.features?.syntaxHighlighting ?? true
),
scipAnalyzer: !!this.scipAnalyzer,
};
}
}