Skip to content

Commit b2a136d

Browse files
committed
feat(cli): wire omniscript-converters for PDF/DOCX/PPTX/XLSX rendering
- Import PDFConverter, DOCXConverter, PPTXConverter, XLSXConverter - Implement renderPdf/Docx/Pptx/Xlsx using converter classes - Add theme support from command-line flags - Write binary buffers to output files properly - Update CLI tests to expect successful rendering instead of errors - Add omniscript-converters to workspace for development - Fix vitest config to exclude all node_modules subdirectories Fixes P0-3: CLI now actually renders to all advertised formats
1 parent a626bea commit b2a136d

File tree

5 files changed

+91
-63
lines changed

5 files changed

+91
-63
lines changed

cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
"dependencies": {
4040
"ajv": "^8.12.0",
4141
"omniscript-parser": "workspace:*",
42-
"omniscript-converters": "^1.0.0"
42+
"omniscript-converters": "workspace:*"
4343
},
4444
"devDependencies": {
4545
"@types/node": "^22.15.33",

cli/src/osf.ts

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
OSFValue,
1414
TextRun,
1515
} from 'omniscript-parser';
16+
import { PDFConverter, DOCXConverter, PPTXConverter, XLSXConverter } from 'omniscript-converters';
1617

1718
// Type definitions for formula handling
1819
interface FormulaDefinition {
@@ -591,20 +592,28 @@ function renderHtml(doc: OSFDocument): string {
591592
}
592593

593594
// Advanced format renderers using omniscript-converters
594-
async function renderPdf(): Promise<Buffer> {
595-
throw new Error('PDF rendering not implemented');
595+
async function renderPdf(doc: OSFDocument, options?: any): Promise<Buffer> {
596+
const converter = new PDFConverter();
597+
const result = await converter.convert(doc, options || {});
598+
return result.buffer;
596599
}
597600

598-
async function renderDocx(): Promise<Buffer> {
599-
throw new Error('DOCX rendering not implemented');
601+
async function renderDocx(doc: OSFDocument, options?: any): Promise<Buffer> {
602+
const converter = new DOCXConverter();
603+
const result = await converter.convert(doc, options || {});
604+
return result.buffer;
600605
}
601606

602-
async function renderPptx(): Promise<Buffer> {
603-
throw new Error('PPTX rendering not implemented');
607+
async function renderPptx(doc: OSFDocument, options?: any): Promise<Buffer> {
608+
const converter = new PPTXConverter();
609+
const result = await converter.convert(doc, options || {});
610+
return result.buffer;
604611
}
605612

606-
async function renderXlsx(): Promise<Buffer> {
607-
throw new Error('XLSX rendering not implemented');
613+
async function renderXlsx(doc: OSFDocument, options?: any): Promise<Buffer> {
614+
const converter = new XLSXConverter();
615+
const result = await converter.convert(doc, options || {});
616+
return result.buffer;
608617
}
609618

610619
// Helper to convert TextRun to Markdown
@@ -995,6 +1004,9 @@ async function main(): Promise<void> {
9951004

9961005
const doc = parse(loadFile(file));
9971006

1007+
const themeFlag = commandArgs.indexOf('--theme');
1008+
const theme = themeFlag >= 0 ? commandArgs[themeFlag + 1] : 'default';
1009+
9981010
switch (format) {
9991011
case 'html': {
10001012
const htmlOutput = renderHtml(doc);
@@ -1006,19 +1018,43 @@ async function main(): Promise<void> {
10061018
break;
10071019
}
10081020
case 'pdf': {
1009-
await renderPdf();
1021+
const pdfBuffer = await renderPdf(doc, { theme });
1022+
if (outputFile) {
1023+
writeFileSync(outputFile, pdfBuffer);
1024+
console.log(`PDF written to ${outputFile}`);
1025+
} else {
1026+
process.stdout.write(pdfBuffer);
1027+
}
10101028
break;
10111029
}
10121030
case 'docx': {
1013-
await renderDocx();
1031+
const docxBuffer = await renderDocx(doc, { theme });
1032+
if (outputFile) {
1033+
writeFileSync(outputFile, docxBuffer);
1034+
console.log(`DOCX written to ${outputFile}`);
1035+
} else {
1036+
process.stdout.write(docxBuffer);
1037+
}
10141038
break;
10151039
}
10161040
case 'pptx': {
1017-
await renderPptx();
1041+
const pptxBuffer = await renderPptx(doc, { theme });
1042+
if (outputFile) {
1043+
writeFileSync(outputFile, pptxBuffer);
1044+
console.log(`PPTX written to ${outputFile}`);
1045+
} else {
1046+
process.stdout.write(pptxBuffer);
1047+
}
10181048
break;
10191049
}
10201050
case 'xlsx': {
1021-
await renderXlsx();
1051+
const xlsxBuffer = await renderXlsx(doc, { theme });
1052+
if (outputFile) {
1053+
writeFileSync(outputFile, xlsxBuffer);
1054+
console.log(`XLSX written to ${outputFile}`);
1055+
} else {
1056+
process.stdout.write(xlsxBuffer);
1057+
}
10221058
break;
10231059
}
10241060
default:

cli/tests/cli.test.ts

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -227,51 +227,59 @@ describe('OSF CLI', () => {
227227
}
228228
});
229229

230-
it('should fail to render OSF to PDF', () => {
230+
it('should render OSF to PDF', () => {
231+
const pdfFile = join(TEST_FIXTURES_DIR, 'test.pdf');
231232
try {
232-
const result = execSync(`node "${CLI_PATH}" render "${testFile}" --format pdf`, {
233+
execSync(`node "${CLI_PATH}" render "${testFile}" --format pdf --output "${pdfFile}"`, {
233234
encoding: 'utf8',
234235
});
235-
expect.fail(`Expected render command to fail but succeeded with output: ${result}`);
236-
} catch (err: any) {
237-
const output = (err.stderr || err.stdout) as string;
238-
expect(output).toContain('PDF rendering not implemented');
236+
expect(existsSync(pdfFile)).toBe(true);
237+
} finally {
238+
if (existsSync(pdfFile)) {
239+
unlinkSync(pdfFile);
240+
}
239241
}
240242
});
241243

242-
it('should fail to render OSF to DOCX', () => {
244+
it('should render OSF to DOCX', () => {
245+
const docxFile = join(TEST_FIXTURES_DIR, 'test.docx');
243246
try {
244-
const result = execSync(`node "${CLI_PATH}" render "${testFile}" --format docx`, {
247+
execSync(`node "${CLI_PATH}" render "${testFile}" --format docx --output "${docxFile}"`, {
245248
encoding: 'utf8',
246249
});
247-
expect.fail(`Expected render command to fail but succeeded with output: ${result}`);
248-
} catch (err: any) {
249-
const output = (err.stderr || err.stdout) as string;
250-
expect(output).toContain('DOCX rendering not implemented');
250+
expect(existsSync(docxFile)).toBe(true);
251+
} finally {
252+
if (existsSync(docxFile)) {
253+
unlinkSync(docxFile);
254+
}
251255
}
252256
});
253257

254-
it('should fail to render OSF to PPTX', () => {
258+
it('should render OSF to PPTX', () => {
259+
const pptxFile = join(TEST_FIXTURES_DIR, 'test.pptx');
255260
try {
256-
const result = execSync(`node "${CLI_PATH}" render "${testFile}" --format pptx`, {
261+
execSync(`node "${CLI_PATH}" render "${testFile}" --format pptx --output "${pptxFile}"`, {
257262
encoding: 'utf8',
258263
});
259-
expect.fail(`Expected render command to fail but succeeded with output: ${result}`);
260-
} catch (err: any) {
261-
const output = (err.stderr || err.stdout) as string;
262-
expect(output).toContain('PPTX rendering not implemented');
264+
expect(existsSync(pptxFile)).toBe(true);
265+
} finally {
266+
if (existsSync(pptxFile)) {
267+
unlinkSync(pptxFile);
268+
}
263269
}
264270
});
265271

266-
it('should fail to render OSF to XLSX', () => {
272+
it('should render OSF to XLSX', () => {
273+
const xlsxFile = join(TEST_FIXTURES_DIR, 'test.xlsx');
267274
try {
268-
const result = execSync(`node "${CLI_PATH}" render "${testFile}" --format xlsx`, {
275+
execSync(`node "${CLI_PATH}" render "${testFile}" --format xlsx --output "${xlsxFile}"`, {
269276
encoding: 'utf8',
270277
});
271-
expect.fail(`Expected render command to fail but succeeded with output: ${result}`);
272-
} catch (err: any) {
273-
const output = (err.stderr || err.stdout) as string;
274-
expect(output).toContain('XLSX rendering not implemented');
278+
expect(existsSync(xlsxFile)).toBe(true);
279+
} finally {
280+
if (existsSync(xlsxFile)) {
281+
unlinkSync(xlsxFile);
282+
}
275283
}
276284
});
277285

pnpm-lock.yaml

Lines changed: 2 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vitest.config.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,14 @@ export default defineConfig({
55
globals: true,
66
environment: 'node',
77
include: ['**/*.{test,spec}.{js,ts}'],
8-
exclude: ['node_modules', 'dist', '.git'],
8+
exclude: [
9+
'node_modules',
10+
'dist',
11+
'.git',
12+
'**/node_modules/**',
13+
'cli/node_modules',
14+
'parser/node_modules',
15+
],
916
coverage: {
1017
provider: 'v8',
1118
reporter: ['text', 'json', 'html'],

0 commit comments

Comments
 (0)