@bendyline/squisq-cli 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/dist/__tests__/convert.test.d.ts +7 -0
- package/dist/__tests__/convert.test.d.ts.map +1 -0
- package/dist/__tests__/convert.test.js +127 -0
- package/dist/__tests__/convert.test.js.map +1 -0
- package/dist/__tests__/readInput.test.d.ts +5 -0
- package/dist/__tests__/readInput.test.d.ts.map +1 -0
- package/dist/__tests__/readInput.test.js +83 -0
- package/dist/__tests__/readInput.test.js.map +1 -0
- package/dist/commands/convert.d.ts +15 -0
- package/dist/commands/convert.d.ts.map +1 -0
- package/dist/commands/convert.js +182 -0
- package/dist/commands/convert.js.map +1 -0
- package/dist/commands/video.d.ts +15 -0
- package/dist/commands/video.d.ts.map +1 -0
- package/dist/commands/video.js +253 -0
- package/dist/commands/video.js.map +1 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -425
- package/dist/index.js.map +1 -1
- package/dist/nativeEncoder-EXDP2O5B.js +0 -0
- package/dist/util/detectFfmpeg.d.ts +15 -0
- package/dist/util/detectFfmpeg.d.ts.map +1 -0
- package/dist/util/detectFfmpeg.js +29 -0
- package/dist/util/detectFfmpeg.js.map +1 -0
- package/dist/util/nativeEncoder.d.ts +27 -0
- package/dist/util/nativeEncoder.d.ts.map +1 -0
- package/dist/util/nativeEncoder.js +106 -0
- package/dist/util/nativeEncoder.js.map +1 -0
- package/dist/util/readInput.d.ts +19 -0
- package/dist/util/readInput.d.ts.map +1 -0
- package/dist/util/readInput.js +98 -0
- package/dist/util/readInput.js.map +1 -0
- package/package.json +5 -5
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @bendyline/squisq-cli
|
|
2
|
+
|
|
3
|
+
Command-line tool for converting Squisq documents to multiple formats and rendering them to video. Reads Markdown files, ZIP/DBK containers, or folders as input.
|
|
4
|
+
|
|
5
|
+
Part of the [Squisq](https://github.com/bendyline/squisq) monorepo.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@bendyline/squisq-cli)
|
|
8
|
+
[](https://github.com/bendyline/squisq/blob/main/LICENSE)
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install -g @bendyline/squisq-cli
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
17
|
+
|
|
18
|
+
### `squisq convert`
|
|
19
|
+
|
|
20
|
+
Convert a Squisq document to DOCX, PPTX, PDF, HTML, or DBK (container ZIP):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
squisq convert input.md --formats docx,pptx,pdf
|
|
24
|
+
squisq convert project.dbk --output-dir ./out --formats html,docx
|
|
25
|
+
squisq convert ./my-folder --formats pdf --theme documentary
|
|
26
|
+
squisq convert input.md --theme cinematic --transform magazine --formats pptx
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Option | Description | Default |
|
|
30
|
+
| -------------- | ------------------------------------------------ | ----------- |
|
|
31
|
+
| `--output-dir` | Output directory | current dir |
|
|
32
|
+
| `--formats` | Comma-separated list: docx, pptx, pdf, html, dbk | all |
|
|
33
|
+
| `--theme` | Squisq theme ID (e.g., documentary, cinematic) | none |
|
|
34
|
+
| `--transform` | Transform style (e.g., documentary, magazine) | none |
|
|
35
|
+
|
|
36
|
+
### `squisq video`
|
|
37
|
+
|
|
38
|
+
Render a Squisq document to MP4 video using Playwright for frame capture and native ffmpeg for encoding:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
squisq video input.md output.mp4
|
|
42
|
+
squisq video project.dbk --quality high --fps 30
|
|
43
|
+
squisq video ./my-folder --orientation portrait --captions social
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
| Option | Description | Default |
|
|
47
|
+
| --------------- | ------------------------- | --------- |
|
|
48
|
+
| `--fps` | Frames per second (1–120) | 30 |
|
|
49
|
+
| `--quality` | draft, normal, or high | normal |
|
|
50
|
+
| `--orientation` | landscape or portrait | landscape |
|
|
51
|
+
| `--captions` | off, standard, or social | off |
|
|
52
|
+
| `--width` | Override width in pixels | auto |
|
|
53
|
+
| `--height` | Override height in pixels | auto |
|
|
54
|
+
|
|
55
|
+
**Requires:** [ffmpeg](https://ffmpeg.org/) installed and available on your PATH.
|
|
56
|
+
|
|
57
|
+
## Input Formats
|
|
58
|
+
|
|
59
|
+
The CLI accepts three types of input:
|
|
60
|
+
|
|
61
|
+
| Input | Description |
|
|
62
|
+
| ------------- | --------------------------------------------------------- |
|
|
63
|
+
| `.md` file | Plain Markdown file |
|
|
64
|
+
| `.zip`/`.dbk` | Container archive with document + embedded media |
|
|
65
|
+
| Folder | Directory with a Markdown file and associated media files |
|
|
66
|
+
|
|
67
|
+
## Related Packages
|
|
68
|
+
|
|
69
|
+
| Package | Description |
|
|
70
|
+
| ------------------------------------------------------------------------------------ | ----------------------------------------------- |
|
|
71
|
+
| [@bendyline/squisq](https://www.npmjs.com/package/@bendyline/squisq) | Headless core — schemas, templates, markdown |
|
|
72
|
+
| [@bendyline/squisq-formats](https://www.npmjs.com/package/@bendyline/squisq-formats) | DOCX, PDF, HTML import/export (used by convert) |
|
|
73
|
+
| [@bendyline/squisq-video](https://www.npmjs.com/package/@bendyline/squisq-video) | Headless video rendering (used by video) |
|
|
74
|
+
| [@bendyline/squisq-react](https://www.npmjs.com/package/@bendyline/squisq-react) | React components for rendering docs |
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
[MIT](https://github.com/bendyline/squisq/blob/main/LICENSE)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/convert.test.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* convert command integration tests
|
|
3
|
+
*
|
|
4
|
+
* Exercises the full convert pipeline: input → all formats → output validation.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, before, after, beforeEach, afterEach } from 'mocha';
|
|
7
|
+
import { expect } from 'chai';
|
|
8
|
+
import { execFile } from 'node:child_process';
|
|
9
|
+
import { promisify } from 'node:util';
|
|
10
|
+
import { readFile, mkdir, rm, stat, writeFile as fsWriteFile } from 'node:fs/promises';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { tmpdir } from 'node:os';
|
|
13
|
+
import { containerToZip } from '@bendyline/squisq-formats/container';
|
|
14
|
+
import { MemoryContentContainer } from '@bendyline/squisq/storage';
|
|
15
|
+
import { zipToContainer } from '@bendyline/squisq-formats/container';
|
|
16
|
+
const exec = promisify(execFile);
|
|
17
|
+
const CLI_PATH = join(import.meta.dirname, '..', '..', 'dist', 'index.js');
|
|
18
|
+
const FIXTURE_MD = join(import.meta.dirname, 'fixtures', 'test.md');
|
|
19
|
+
/**
|
|
20
|
+
* Run the CLI with the given args and return stdout/stderr.
|
|
21
|
+
*/
|
|
22
|
+
async function runCli(...args) {
|
|
23
|
+
return exec('node', [CLI_PATH, ...args], { timeout: 30000 });
|
|
24
|
+
}
|
|
25
|
+
describe('convert command', () => {
|
|
26
|
+
let tempDir;
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
tempDir = join(tmpdir(), `squisq-convert-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
29
|
+
await mkdir(tempDir, { recursive: true });
|
|
30
|
+
});
|
|
31
|
+
afterEach(async () => {
|
|
32
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
33
|
+
});
|
|
34
|
+
it('converts a .md file to all formats', async () => {
|
|
35
|
+
const { stderr } = await runCli('convert', FIXTURE_MD, '-o', tempDir);
|
|
36
|
+
expect(stderr).to.include('Done.');
|
|
37
|
+
// Verify all four output files exist and are non-empty
|
|
38
|
+
for (const ext of ['docx', 'pdf', 'html', 'dbk']) {
|
|
39
|
+
const outPath = join(tempDir, `test.${ext}`);
|
|
40
|
+
const info = await stat(outPath);
|
|
41
|
+
expect(info.size).to.be.greaterThan(0);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
it('respects --formats to produce only selected formats', async () => {
|
|
45
|
+
await runCli('convert', FIXTURE_MD, '-o', tempDir, '-f', 'docx,pdf');
|
|
46
|
+
// These should exist
|
|
47
|
+
const docxStat = await stat(join(tempDir, 'test.docx'));
|
|
48
|
+
expect(docxStat.size).to.be.greaterThan(0);
|
|
49
|
+
const pdfStat = await stat(join(tempDir, 'test.pdf'));
|
|
50
|
+
expect(pdfStat.size).to.be.greaterThan(0);
|
|
51
|
+
// These should NOT exist
|
|
52
|
+
for (const ext of ['html', 'dbk']) {
|
|
53
|
+
try {
|
|
54
|
+
await stat(join(tempDir, `test.${ext}`));
|
|
55
|
+
expect.fail(`test.${ext} should not exist`);
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
expect(err.code).to.equal('ENOENT');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
it('converts a .dbk container to all formats', async () => {
|
|
63
|
+
// Create a minimal .dbk container
|
|
64
|
+
const container = new MemoryContentContainer();
|
|
65
|
+
await container.writeDocument('# Container Doc\n\nSome content here.');
|
|
66
|
+
const blob = await containerToZip(container);
|
|
67
|
+
const buf = Buffer.from(await blob.arrayBuffer());
|
|
68
|
+
const dbkPath = join(tempDir, 'input.dbk');
|
|
69
|
+
await fsWriteFile(dbkPath, buf);
|
|
70
|
+
// Convert to a separate output dir to avoid overwriting the input .dbk
|
|
71
|
+
const outDir = join(tempDir, 'out');
|
|
72
|
+
const { stderr } = await runCli('convert', dbkPath, '-o', outDir);
|
|
73
|
+
expect(stderr).to.include('Done.');
|
|
74
|
+
for (const ext of ['docx', 'pdf', 'html', 'dbk']) {
|
|
75
|
+
const info = await stat(join(outDir, `input.${ext}`));
|
|
76
|
+
expect(info.size).to.be.greaterThan(0);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
it('exits with error for nonexistent input', async () => {
|
|
80
|
+
try {
|
|
81
|
+
await runCli('convert', '/nonexistent/file.md', '-o', tempDir);
|
|
82
|
+
expect.fail('Expected a non-zero exit');
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
// execFile rejects on non-zero exit
|
|
86
|
+
expect(err.stderr).to.include('Error');
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
describe('output validation', () => {
|
|
90
|
+
let validationDir;
|
|
91
|
+
before(async () => {
|
|
92
|
+
validationDir = join(tmpdir(), `squisq-validate-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
93
|
+
await mkdir(validationDir, { recursive: true });
|
|
94
|
+
await runCli('convert', FIXTURE_MD, '-o', validationDir);
|
|
95
|
+
});
|
|
96
|
+
after(async () => {
|
|
97
|
+
await rm(validationDir, { recursive: true, force: true });
|
|
98
|
+
});
|
|
99
|
+
it('DOCX is a valid ZIP with WordprocessingML content', async () => {
|
|
100
|
+
const data = await readFile(join(validationDir, 'test.docx'));
|
|
101
|
+
// ZIP files start with PK (0x50 0x4B)
|
|
102
|
+
expect(data[0]).to.equal(0x50);
|
|
103
|
+
expect(data[1]).to.equal(0x4b);
|
|
104
|
+
// Should contain Content_Types and document.xml inside
|
|
105
|
+
const asString = data.toString('latin1');
|
|
106
|
+
expect(asString).to.include('[Content_Types].xml');
|
|
107
|
+
expect(asString).to.include('word/document.xml');
|
|
108
|
+
});
|
|
109
|
+
it('PDF starts with %PDF- magic bytes', async () => {
|
|
110
|
+
const data = await readFile(join(validationDir, 'test.pdf'));
|
|
111
|
+
const header = data.subarray(0, 5).toString('ascii');
|
|
112
|
+
expect(header).to.equal('%PDF-');
|
|
113
|
+
});
|
|
114
|
+
it('HTML contains SquisqPlayer and root element', async () => {
|
|
115
|
+
const html = await readFile(join(validationDir, 'test.html'), 'utf-8');
|
|
116
|
+
expect(html).to.include('SquisqPlayer');
|
|
117
|
+
expect(html).to.include('squisq-root');
|
|
118
|
+
});
|
|
119
|
+
it('DBK container round-trips through zipToContainer', async () => {
|
|
120
|
+
const data = await readFile(join(validationDir, 'test.dbk'));
|
|
121
|
+
const container = await zipToContainer(data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength));
|
|
122
|
+
const md = await container.readDocument();
|
|
123
|
+
expect(md).to.be.a('string').that.includes('# Test Document');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=convert.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.test.js","sourceRoot":"","sources":["../../src/__tests__/convert.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readInput.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/readInput.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* readInput unit tests
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, beforeEach, afterEach } from 'mocha';
|
|
5
|
+
import { expect } from 'chai';
|
|
6
|
+
import { readInput } from '../util/readInput.js';
|
|
7
|
+
import { writeFile, mkdir, rm } from 'node:fs/promises';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { tmpdir } from 'node:os';
|
|
10
|
+
import { containerToZip } from '@bendyline/squisq-formats/container';
|
|
11
|
+
import { MemoryContentContainer } from '@bendyline/squisq/storage';
|
|
12
|
+
const FIXTURE_MD = join(import.meta.dirname, 'fixtures', 'test.md');
|
|
13
|
+
describe('readInput', () => {
|
|
14
|
+
let tempDir;
|
|
15
|
+
beforeEach(async () => {
|
|
16
|
+
tempDir = join(tmpdir(), `squisq-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
17
|
+
await mkdir(tempDir, { recursive: true });
|
|
18
|
+
});
|
|
19
|
+
afterEach(async () => {
|
|
20
|
+
await rm(tempDir, { recursive: true, force: true });
|
|
21
|
+
});
|
|
22
|
+
it('reads a .md file into a container and MarkdownDocument', async () => {
|
|
23
|
+
const result = await readInput(FIXTURE_MD);
|
|
24
|
+
expect(result.markdownDoc).to.have.property('type', 'document');
|
|
25
|
+
expect(result.markdownDoc.children).to.be.an('array');
|
|
26
|
+
expect(result.markdownDoc.children.length).to.be.greaterThan(0);
|
|
27
|
+
const docContent = await result.container.readDocument();
|
|
28
|
+
expect(docContent).to.be.a('string').that.includes('# Test Document');
|
|
29
|
+
});
|
|
30
|
+
it('reads a .zip container', async () => {
|
|
31
|
+
// Build a minimal container ZIP
|
|
32
|
+
const container = new MemoryContentContainer();
|
|
33
|
+
await container.writeDocument('# From ZIP\n\nHello from a ZIP container.');
|
|
34
|
+
const blob = await containerToZip(container);
|
|
35
|
+
const buf = Buffer.from(await blob.arrayBuffer());
|
|
36
|
+
const zipPath = join(tempDir, 'test.zip');
|
|
37
|
+
await writeFile(zipPath, buf);
|
|
38
|
+
const result = await readInput(zipPath);
|
|
39
|
+
expect(result.markdownDoc.type).to.equal('document');
|
|
40
|
+
const doc = await result.container.readDocument();
|
|
41
|
+
expect(doc).to.include('# From ZIP');
|
|
42
|
+
});
|
|
43
|
+
it('reads a .dbk container (same as .zip)', async () => {
|
|
44
|
+
const container = new MemoryContentContainer();
|
|
45
|
+
await container.writeDocument('# From DBK\n\nHello from a DBK container.');
|
|
46
|
+
const blob = await containerToZip(container);
|
|
47
|
+
const buf = Buffer.from(await blob.arrayBuffer());
|
|
48
|
+
const dbkPath = join(tempDir, 'test.dbk');
|
|
49
|
+
await writeFile(dbkPath, buf);
|
|
50
|
+
const result = await readInput(dbkPath);
|
|
51
|
+
expect(result.markdownDoc.type).to.equal('document');
|
|
52
|
+
const doc = await result.container.readDocument();
|
|
53
|
+
expect(doc).to.include('# From DBK');
|
|
54
|
+
});
|
|
55
|
+
it('reads a folder with markdown and media', async () => {
|
|
56
|
+
const folderPath = join(tempDir, 'mydoc');
|
|
57
|
+
await mkdir(folderPath, { recursive: true });
|
|
58
|
+
await writeFile(join(folderPath, 'index.md'), '# Folder Doc\n\nContent here.');
|
|
59
|
+
await writeFile(join(folderPath, 'image.txt'), 'placeholder');
|
|
60
|
+
const result = await readInput(folderPath);
|
|
61
|
+
expect(result.markdownDoc.type).to.equal('document');
|
|
62
|
+
const doc = await result.container.readDocument();
|
|
63
|
+
expect(doc).to.include('# Folder Doc');
|
|
64
|
+
// Media files are also in the container
|
|
65
|
+
const files = await result.container.listFiles();
|
|
66
|
+
const paths = files.map((f) => f.path);
|
|
67
|
+
expect(paths).to.include('image.txt');
|
|
68
|
+
});
|
|
69
|
+
it('throws on folder with no markdown file', async () => {
|
|
70
|
+
const folderPath = join(tempDir, 'empty');
|
|
71
|
+
await mkdir(folderPath, { recursive: true });
|
|
72
|
+
await writeFile(join(folderPath, 'image.png'), Buffer.from([0x89, 0x50]));
|
|
73
|
+
try {
|
|
74
|
+
await readInput(folderPath);
|
|
75
|
+
expect.fail('Expected an error');
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
expect(err).to.be.instanceOf(Error);
|
|
79
|
+
expect(err.message).to.include('No markdown document found');
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
//# sourceMappingURL=readInput.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readInput.test.js","sourceRoot":"","sources":["../../src/__tests__/readInput.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* convert command
|
|
3
|
+
*
|
|
4
|
+
* Reads a markdown file, ZIP/DBK container, or folder and exports to
|
|
5
|
+
* all supported formats: DOCX, PPTX, PDF, HTML, and container ZIP (.dbk).
|
|
6
|
+
*
|
|
7
|
+
* Supports optional --theme and --transform flags to apply a squisq theme
|
|
8
|
+
* and/or transform style before exporting.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* squisq convert <input> [--output-dir <dir>] [--formats <list>] [--theme <id>] [--transform <style>]
|
|
12
|
+
*/
|
|
13
|
+
import type { Command } from 'commander';
|
|
14
|
+
export declare function registerConvertCommand(program: Command): void;
|
|
15
|
+
//# sourceMappingURL=convert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/commands/convert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+BzC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAwB7D"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* convert command
|
|
3
|
+
*
|
|
4
|
+
* Reads a markdown file, ZIP/DBK container, or folder and exports to
|
|
5
|
+
* all supported formats: DOCX, PPTX, PDF, HTML, and container ZIP (.dbk).
|
|
6
|
+
*
|
|
7
|
+
* Supports optional --theme and --transform flags to apply a squisq theme
|
|
8
|
+
* and/or transform style before exporting.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* squisq convert <input> [--output-dir <dir>] [--formats <list>] [--theme <id>] [--transform <style>]
|
|
12
|
+
*/
|
|
13
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
14
|
+
import { dirname, basename, extname, join, resolve } from 'node:path';
|
|
15
|
+
import { readInput } from '../util/readInput.js';
|
|
16
|
+
const ALL_FORMATS = ['docx', 'pptx', 'pdf', 'html', 'dbk'];
|
|
17
|
+
function parseFormats(value) {
|
|
18
|
+
const requested = value.split(',').map((s) => s.trim().toLowerCase());
|
|
19
|
+
const valid = [];
|
|
20
|
+
for (const r of requested) {
|
|
21
|
+
if (ALL_FORMATS.includes(r)) {
|
|
22
|
+
valid.push(r);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
console.warn(`Unknown format "${r}" — skipping. Valid: ${ALL_FORMATS.join(', ')}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (valid.length === 0) {
|
|
29
|
+
throw new Error(`No valid formats specified. Valid: ${ALL_FORMATS.join(', ')}`);
|
|
30
|
+
}
|
|
31
|
+
return valid;
|
|
32
|
+
}
|
|
33
|
+
export function registerConvertCommand(program) {
|
|
34
|
+
program
|
|
35
|
+
.command('convert')
|
|
36
|
+
.description('Convert a markdown document to DOCX, PPTX, PDF, HTML, and DBK container formats')
|
|
37
|
+
.argument('<input>', 'Path to .md file, .zip/.dbk container, or folder')
|
|
38
|
+
.option('-o, --output-dir <dir>', 'Output directory (default: same as input)')
|
|
39
|
+
.option('-f, --formats <list>', `Comma-separated formats to produce (default: all). Valid: ${ALL_FORMATS.join(', ')}`)
|
|
40
|
+
.option('-t, --theme <id>', 'Squisq theme ID to apply (e.g., documentary, cinematic, bold)')
|
|
41
|
+
.option('--transform <style>', 'Transform style to apply before export (e.g., documentary, magazine, minimal)')
|
|
42
|
+
.action(async (inputPath, opts) => {
|
|
43
|
+
try {
|
|
44
|
+
await runConvert(inputPath, opts);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
48
|
+
console.error(`Error: ${message}`);
|
|
49
|
+
process.exitCode = 1;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async function runConvert(inputPath, opts) {
|
|
54
|
+
const resolvedInput = resolve(inputPath);
|
|
55
|
+
// Determine which formats to produce
|
|
56
|
+
const formats = opts.formats ? parseFormats(opts.formats) : [...ALL_FORMATS];
|
|
57
|
+
// Determine output directory and base filename
|
|
58
|
+
const outputDir = opts.outputDir ? resolve(opts.outputDir) : dirname(resolvedInput);
|
|
59
|
+
const inputBasename = basename(resolvedInput);
|
|
60
|
+
const inputExt = extname(inputBasename);
|
|
61
|
+
const baseName = inputExt ? inputBasename.slice(0, -inputExt.length) : inputBasename;
|
|
62
|
+
// Ensure output directory exists
|
|
63
|
+
await mkdir(outputDir, { recursive: true });
|
|
64
|
+
// Validate theme and transform IDs
|
|
65
|
+
if (opts.theme) {
|
|
66
|
+
const { getAvailableThemes } = await import('@bendyline/squisq/schemas');
|
|
67
|
+
const themes = getAvailableThemes();
|
|
68
|
+
if (!themes.includes(opts.theme)) {
|
|
69
|
+
throw new Error(`Unknown theme "${opts.theme}". Available: ${themes.join(', ')}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (opts.transform) {
|
|
73
|
+
const { getTransformStyleIds } = await import('@bendyline/squisq/transform');
|
|
74
|
+
const styles = getTransformStyleIds();
|
|
75
|
+
if (!styles.includes(opts.transform)) {
|
|
76
|
+
throw new Error(`Unknown transform style "${opts.transform}". Available: ${styles.join(', ')}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
console.error(`Reading: ${resolvedInput}`);
|
|
80
|
+
const { container, markdownDoc } = await readInput(resolvedInput);
|
|
81
|
+
// Apply transform if requested
|
|
82
|
+
let exportMarkdownDoc = markdownDoc;
|
|
83
|
+
if (opts.transform) {
|
|
84
|
+
exportMarkdownDoc = await applyTransformToMarkdown(markdownDoc, container, opts.transform, opts.theme);
|
|
85
|
+
console.error(` Applied transform: ${opts.transform}`);
|
|
86
|
+
}
|
|
87
|
+
const themeId = opts.theme;
|
|
88
|
+
for (const format of formats) {
|
|
89
|
+
const outPath = join(outputDir, `${baseName}.${format}`);
|
|
90
|
+
switch (format) {
|
|
91
|
+
case 'docx': {
|
|
92
|
+
const { markdownDocToDocx } = await import('@bendyline/squisq-formats/docx');
|
|
93
|
+
const buf = await markdownDocToDocx(exportMarkdownDoc, { themeId });
|
|
94
|
+
await writeFile(outPath, Buffer.from(buf));
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
case 'pptx': {
|
|
98
|
+
const { markdownDocToPptx } = await import('@bendyline/squisq-formats/pptx');
|
|
99
|
+
// Collect images from container for PPTX embedding
|
|
100
|
+
const images = await collectContainerImages(container);
|
|
101
|
+
const buf = await markdownDocToPptx(exportMarkdownDoc, { themeId, images });
|
|
102
|
+
await writeFile(outPath, Buffer.from(buf));
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
case 'pdf': {
|
|
106
|
+
const { markdownDocToPdf } = await import('@bendyline/squisq-formats/pdf');
|
|
107
|
+
const buf = await markdownDocToPdf(exportMarkdownDoc, { themeId });
|
|
108
|
+
await writeFile(outPath, Buffer.from(buf));
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
case 'html': {
|
|
112
|
+
const { markdownToDoc } = await import('@bendyline/squisq/doc');
|
|
113
|
+
const { docToHtml, collectImagePaths } = await import('@bendyline/squisq-formats/html');
|
|
114
|
+
const { PLAYER_BUNDLE } = await import('@bendyline/squisq-react/standalone-source');
|
|
115
|
+
const doc = markdownToDoc(exportMarkdownDoc);
|
|
116
|
+
// Gather images referenced by the doc from the container
|
|
117
|
+
const imagePaths = collectImagePaths(doc);
|
|
118
|
+
const images = new Map();
|
|
119
|
+
for (const imgPath of imagePaths) {
|
|
120
|
+
const data = await container.readFile(imgPath);
|
|
121
|
+
if (data) {
|
|
122
|
+
images.set(imgPath, data);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const html = docToHtml(doc, {
|
|
126
|
+
playerScript: PLAYER_BUNDLE,
|
|
127
|
+
images,
|
|
128
|
+
title: baseName,
|
|
129
|
+
mode: 'static',
|
|
130
|
+
themeId,
|
|
131
|
+
});
|
|
132
|
+
await writeFile(outPath, html, 'utf-8');
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case 'dbk': {
|
|
136
|
+
const { containerToZip } = await import('@bendyline/squisq-formats/container');
|
|
137
|
+
const blob = await containerToZip(container);
|
|
138
|
+
const buf = await blob.arrayBuffer();
|
|
139
|
+
await writeFile(outPath, Buffer.from(buf));
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
console.error(` ✓ ${outPath}`);
|
|
144
|
+
}
|
|
145
|
+
console.error('Done.');
|
|
146
|
+
}
|
|
147
|
+
// ============================================
|
|
148
|
+
// Transform Pipeline
|
|
149
|
+
// ============================================
|
|
150
|
+
/**
|
|
151
|
+
* Apply a transform style to a MarkdownDocument.
|
|
152
|
+
* Pipeline: MarkdownDocument → Doc → applyTransform → docToMarkdown → MarkdownDocument
|
|
153
|
+
*/
|
|
154
|
+
async function applyTransformToMarkdown(markdownDoc, container, transformStyle, themeId) {
|
|
155
|
+
const { markdownToDoc, docToMarkdown } = await import('@bendyline/squisq/doc');
|
|
156
|
+
const { applyTransform, extractDocImages } = await import('@bendyline/squisq/transform');
|
|
157
|
+
const doc = markdownToDoc(markdownDoc);
|
|
158
|
+
// Extract image metadata from the doc for transform interleaving
|
|
159
|
+
const images = extractDocImages(doc.blocks);
|
|
160
|
+
const result = applyTransform(doc, transformStyle, {
|
|
161
|
+
themeId,
|
|
162
|
+
images,
|
|
163
|
+
});
|
|
164
|
+
return docToMarkdown(result.doc);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Collect all image files from a container as a Map<path, ArrayBuffer>.
|
|
168
|
+
*/
|
|
169
|
+
async function collectContainerImages(container) {
|
|
170
|
+
const images = new Map();
|
|
171
|
+
const files = await container.listFiles();
|
|
172
|
+
for (const file of files) {
|
|
173
|
+
if (/\.(jpg|jpeg|png|gif|webp|svg|bmp|avif)$/i.test(file.path)) {
|
|
174
|
+
const data = await container.readFile(file.path);
|
|
175
|
+
if (data) {
|
|
176
|
+
images.set(file.path, data);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return images;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=convert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.js","sourceRoot":"","sources":["../../src/commands/convert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* video command
|
|
3
|
+
*
|
|
4
|
+
* Renders a squisq document to MP4 video by:
|
|
5
|
+
* 1. Parsing the input (markdown, container, or folder)
|
|
6
|
+
* 2. Generating a self-contained render HTML
|
|
7
|
+
* 3. Capturing frames via Playwright headless browser
|
|
8
|
+
* 4. Encoding to MP4 using native ffmpeg (fast) or ffmpeg.wasm (fallback)
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* squisq video <input> [-o output.mp4] [--fps 30] [--quality normal] [--orientation landscape]
|
|
12
|
+
*/
|
|
13
|
+
import type { Command } from 'commander';
|
|
14
|
+
export declare function registerVideoCommand(program: Command): void;
|
|
15
|
+
//# sourceMappingURL=video.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../src/commands/video.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuBzC,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAsC3D"}
|