towel-txt 0.1.0

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/LICENSE +21 -0
  3. package/README.md +334 -0
  4. package/dist/cli/args.d.ts +45 -0
  5. package/dist/cli/args.d.ts.map +1 -0
  6. package/dist/cli/args.js +208 -0
  7. package/dist/cli/assets.d.ts +15 -0
  8. package/dist/cli/assets.d.ts.map +1 -0
  9. package/dist/cli/assets.js +50 -0
  10. package/dist/cli/config.d.ts +29 -0
  11. package/dist/cli/config.d.ts.map +1 -0
  12. package/dist/cli/config.js +200 -0
  13. package/dist/cli/exit-codes.d.ts +8 -0
  14. package/dist/cli/exit-codes.d.ts.map +1 -0
  15. package/dist/cli/exit-codes.js +6 -0
  16. package/dist/cli/pdf.d.ts +9 -0
  17. package/dist/cli/pdf.d.ts.map +1 -0
  18. package/dist/cli/pdf.js +164 -0
  19. package/dist/cli/run.d.ts +16 -0
  20. package/dist/cli/run.d.ts.map +1 -0
  21. package/dist/cli/run.js +414 -0
  22. package/dist/cli/summary.d.ts +17 -0
  23. package/dist/cli/summary.d.ts.map +1 -0
  24. package/dist/cli/summary.js +20 -0
  25. package/dist/cli/watch.d.ts +8 -0
  26. package/dist/cli/watch.d.ts.map +1 -0
  27. package/dist/cli/watch.js +59 -0
  28. package/dist/cli.d.ts +3 -0
  29. package/dist/cli.d.ts.map +1 -0
  30. package/dist/cli.js +3 -0
  31. package/dist/index.d.ts +17 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +16 -0
  34. package/dist/meta.d.ts +3 -0
  35. package/dist/meta.d.ts.map +1 -0
  36. package/dist/meta.js +2 -0
  37. package/dist/parser/footnotes.d.ts +24 -0
  38. package/dist/parser/footnotes.d.ts.map +1 -0
  39. package/dist/parser/footnotes.js +159 -0
  40. package/dist/parser/headings.d.ts +8 -0
  41. package/dist/parser/headings.d.ts.map +1 -0
  42. package/dist/parser/headings.js +95 -0
  43. package/dist/parser/highlight.d.ts +2 -0
  44. package/dist/parser/highlight.d.ts.map +1 -0
  45. package/dist/parser/highlight.js +81 -0
  46. package/dist/parser/images.d.ts +8 -0
  47. package/dist/parser/images.d.ts.map +1 -0
  48. package/dist/parser/images.js +62 -0
  49. package/dist/parser/markdown.d.ts +12 -0
  50. package/dist/parser/markdown.d.ts.map +1 -0
  51. package/dist/parser/markdown.js +60 -0
  52. package/dist/parser/metadata.d.ts +18 -0
  53. package/dist/parser/metadata.d.ts.map +1 -0
  54. package/dist/parser/metadata.js +95 -0
  55. package/dist/parser/page-breaks.d.ts +3 -0
  56. package/dist/parser/page-breaks.d.ts.map +1 -0
  57. package/dist/parser/page-breaks.js +21 -0
  58. package/dist/render/document.d.ts +13 -0
  59. package/dist/render/document.d.ts.map +1 -0
  60. package/dist/render/document.js +103 -0
  61. package/dist/render/minify.d.ts +2 -0
  62. package/dist/render/minify.d.ts.map +1 -0
  63. package/dist/render/minify.js +21 -0
  64. package/dist/render/print-options.d.ts +6 -0
  65. package/dist/render/print-options.d.ts.map +1 -0
  66. package/dist/render/print-options.js +24 -0
  67. package/dist/render/toc.d.ts +8 -0
  68. package/dist/render/toc.d.ts.map +1 -0
  69. package/dist/render/toc.js +58 -0
  70. package/dist/theme/default.d.ts +2 -0
  71. package/dist/theme/default.d.ts.map +1 -0
  72. package/dist/theme/default.js +327 -0
  73. package/dist/theme/themes.d.ts +5 -0
  74. package/dist/theme/themes.d.ts.map +1 -0
  75. package/dist/theme/themes.js +97 -0
  76. package/dist/utils/ids.d.ts +3 -0
  77. package/dist/utils/ids.d.ts.map +1 -0
  78. package/dist/utils/ids.js +21 -0
  79. package/docs/cli-reference.md +222 -0
  80. package/docs/examples.md +63 -0
  81. package/docs/print-notes.md +11 -0
  82. package/docs/production-roadmap.md +159 -0
  83. package/docs/release.md +44 -0
  84. package/docs/security-and-limits.md +121 -0
  85. package/examples/brief.md +30 -0
  86. package/examples/image-workflow.md +26 -0
  87. package/examples/images/workflow.svg +43 -0
  88. package/examples/print.css +7 -0
  89. package/examples/report.css +22 -0
  90. package/examples/report.md +44 -0
  91. package/examples/sample.md +39 -0
  92. package/examples/technical-note.md +46 -0
  93. package/examples/towel-txt.config.yaml +7 -0
  94. package/package.json +85 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,66 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on Keep a Changelog, and this project uses Semantic
6
+ Versioning.
7
+
8
+ ## Unreleased
9
+
10
+ ### Added
11
+
12
+ - Release workflow serialization and timeout guardrails for safer publishing.
13
+ - Maintainer release preflight check for repository metadata, branch protection,
14
+ workflow health, npm package state, and publish credentials.
15
+ - Automated coverage for release preflight success and failure scenarios.
16
+
17
+ ## 0.1.0 - 2026-05-30
18
+
19
+ ### Added
20
+
21
+ - Initial open-source project scaffold.
22
+ - CLI file rendering from Markdown input to printable HTML output.
23
+ - Complete CLI reference for options, config fields, and common workflows.
24
+ - Custom CSS support for generated HTML documents.
25
+ - Dependabot update groups for npm dependencies and GitHub Actions.
26
+ - Documented the production readiness roadmap.
27
+ - Explicit page break markers and print break helper classes.
28
+ - Example Markdown document and generated printable HTML output.
29
+ - Example custom print CSS file.
30
+ - Front matter metadata parsing for document title, subtitle, author, date, and cover fields.
31
+ - GitHub Actions workflow dependencies updated to Node 24-compatible majors.
32
+ - Local relative image asset copying with copied, skipped, and missing diagnostics.
33
+ - Local image paths with Windows separators are handled consistently across platforms.
34
+ - Local image asset output directories with generated image path rewriting.
35
+ - Minor and patch Dependabot grouping with manual handling for major npm updates.
36
+ - Markdown heading extraction with stable heading IDs.
37
+ - Markdown body HTML rendering with safe raw HTML escaping.
38
+ - Named document themes: `default`, `compact`, and `report`.
39
+ - Optional cover pages from metadata, config, or CLI flags.
40
+ - Optional minified HTML output with `--minify` or config defaults.
41
+ - Optional table of contents suppression with `--no-toc`.
42
+ - Output overwrite protection with `--force`.
43
+ - Package metadata, exports, and publishable file list readiness checks.
44
+ - CodeQL code scanning for JavaScript and TypeScript security analysis.
45
+ - Package smoke testing for packed CLI installs.
46
+ - PDF export through a local Chrome, Edge, or Chromium browser.
47
+ - Production examples for reports, briefs, technical notes, images, and custom CSS.
48
+ - Print page size and margin options for generated HTML documents.
49
+ - Printable HTML document rendering with default screen and print styles.
50
+ - Project config files with `--config` and `--no-config`.
51
+ - Release checks for changelog, package metadata, and version consistency.
52
+ - Release workflow for verified package dry-runs and optional publishing.
53
+ - Release workflow publish prerequisite validation for npm credentials.
54
+ - Security audit and performance smoke gates in CI and release verification.
55
+ - Vitest upgraded to a patched 4.x release for GHSA-5xrq-8626-4rwp.
56
+ - Windows CI coverage for cross-platform CLI verification.
57
+ - Print-friendly footnotes with backlinks.
58
+ - Render summary JSON files for CI and script workflows.
59
+ - Security and limits documentation for rendering, image copying, CSS, and PDF export.
60
+ - Stable CLI exit codes for usage errors, render errors, and strict warning failures.
61
+ - Strict mode for failing renders when warnings are detected.
62
+ - Stdin Markdown input with `--stdin`.
63
+ - Stdout HTML output with `--stdout`.
64
+ - Syntax highlighting for JavaScript, TypeScript, JSON, and shell code fences.
65
+ - Table of contents tree building and HTML rendering.
66
+ - Watch mode with `--watch` for local Markdown and CSS rebuilds.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Towel.txt contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,334 @@
1
+ # Towel.txt
2
+
3
+ Towel.txt is a small command-line tool for turning Markdown into clean,
4
+ printable HTML and PDF documents.
5
+
6
+ It is designed for notes, reports, project writeups, briefs, and other
7
+ documents that start as plain Markdown but need a polished browser-printable
8
+ output.
9
+
10
+ ## Status
11
+
12
+ Towel.txt can currently generate self-contained printable HTML and PDF files
13
+ from Markdown. PDF export uses a local Chrome, Edge, or Chromium browser.
14
+ The first public package release is prepared as `0.1.0`; publishing requires
15
+ the maintainer release workflow and npm credentials.
16
+
17
+ ## Goals
18
+
19
+ - Convert Markdown files into readable HTML documents.
20
+ - Generate a table of contents from document headings.
21
+ - Include print-friendly CSS by default.
22
+ - Highlight common code fences with print-friendly colors.
23
+ - Render footnotes with backlinks for longer documents.
24
+ - Add an optional cover page from document metadata.
25
+ - Insert explicit print page breaks when a document needs fixed pagination.
26
+ - Keep output simple enough to inspect, customize, and share.
27
+ - Provide a focused CLI that works well in scripts and local workflows.
28
+
29
+ ## Install From Source
30
+
31
+ ```bash
32
+ git clone https://github.com/kaleab-kali/towel.txt.git
33
+ cd towel.txt
34
+ pnpm install
35
+ pnpm build
36
+ ```
37
+
38
+ ## Usage
39
+
40
+ ```bash
41
+ towel-txt document.md -o document.html
42
+ ```
43
+
44
+ For every command option, config field, conflict rule, and common workflow, see
45
+ [docs/cli-reference.md](docs/cli-reference.md).
46
+
47
+ Append a custom CSS file to the built-in print styles:
48
+
49
+ ```bash
50
+ towel-txt document.md -o document.html --css examples/print.css
51
+ ```
52
+
53
+ Place copied local image assets under a specific output folder:
54
+
55
+ ```bash
56
+ towel-txt document.md -o dist/document.html --asset-dir assets
57
+ ```
58
+
59
+ Generate compact HTML with layout whitespace removed:
60
+
61
+ ```bash
62
+ towel-txt document.md -o document.html --minify
63
+ ```
64
+
65
+ Write a JSON summary for CI or scripts:
66
+
67
+ ```bash
68
+ towel-txt document.md -o document.html --summary-json summary.json
69
+ ```
70
+
71
+ Fail the render when warnings are detected:
72
+
73
+ ```bash
74
+ towel-txt document.md -o document.html --strict
75
+ ```
76
+
77
+ Set print page size and margins:
78
+
79
+ ```bash
80
+ towel-txt document.md -o document.html --page-size "A4 landscape" --margin 18mm
81
+ ```
82
+
83
+ Generate a PDF:
84
+
85
+ ```bash
86
+ towel-txt document.md --format pdf -o document.pdf
87
+ ```
88
+
89
+ The CLI also infers PDF output from a `.pdf` output path:
90
+
91
+ ```bash
92
+ towel-txt document.md -o document.pdf
93
+ ```
94
+
95
+ Use a specific browser executable for PDF export:
96
+
97
+ ```bash
98
+ towel-txt document.md --format pdf -o document.pdf --browser /path/to/chrome
99
+ ```
100
+
101
+ Select a built-in theme:
102
+
103
+ ```bash
104
+ towel-txt document.md -o document.html --theme report
105
+ ```
106
+
107
+ Add a cover page for a rendered document:
108
+
109
+ ```bash
110
+ towel-txt document.md -o document.html --cover --subtitle "Quarterly planning notes"
111
+ ```
112
+
113
+ Insert a print page break by placing a marker on its own line:
114
+
115
+ ```md
116
+ First section.
117
+
118
+ [[page-break]]
119
+
120
+ Second section.
121
+ ```
122
+
123
+ Rebuild output when the Markdown or custom CSS file changes:
124
+
125
+ ```bash
126
+ towel-txt document.md -o document.html --watch
127
+ ```
128
+
129
+ Load defaults from a config file:
130
+
131
+ ```bash
132
+ towel-txt document.md --config towel-txt.config.yaml
133
+ ```
134
+
135
+ Overwrite an existing output file intentionally:
136
+
137
+ ```bash
138
+ towel-txt document.md -o document.html --force
139
+ ```
140
+
141
+ Disable the automatic table of contents:
142
+
143
+ ```bash
144
+ towel-txt document.md -o document.html --no-toc
145
+ ```
146
+
147
+ Write generated HTML to stdout for piping:
148
+
149
+ ```bash
150
+ towel-txt document.md --stdout
151
+ ```
152
+
153
+ Read Markdown from stdin:
154
+
155
+ ```bash
156
+ cat document.md | towel-txt --stdin --stdout
157
+ ```
158
+
159
+ During local development, run the CLI through pnpm:
160
+
161
+ ```bash
162
+ pnpm dev examples/sample.md --output examples/sample.html
163
+ ```
164
+
165
+ The CLI supports:
166
+
167
+ - Markdown input files.
168
+ - HTML output files.
169
+ - PDF output files through Chrome, Edge, or Chromium.
170
+ - Configurable copied asset output directories with `--asset-dir`.
171
+ - Syntax highlighting for JavaScript, TypeScript, JSON, and shell code fences.
172
+ - Footnotes using `[^label]` references and matching definitions.
173
+ - Optional cover pages from metadata, config, or `--cover`.
174
+ - Explicit page break markers: `[[page-break]]`, `\pagebreak`, and `\newpage`.
175
+ - Document title configuration.
176
+ - Front matter metadata for title, subtitle, author, date, and cover pages.
177
+ - Custom CSS appended to the default document styles.
178
+ - Heading anchors.
179
+ - Named themes: `default`, `compact`, and `report`.
180
+ - Output overwrite protection with an explicit `--force` option.
181
+ - Optional minified HTML output with `--minify`.
182
+ - Print page size and margin configuration.
183
+ - Relative local image asset copying with copied, skipped, and missing diagnostics.
184
+ - Table of contents generation.
185
+ - Optional table of contents suppression.
186
+ - Project config files for shared defaults.
187
+ - Render summary JSON files for CI and scripts.
188
+ - Watch mode for rebuilding file output during local editing.
189
+ - Stdout output for shell pipelines.
190
+ - Stdin input for shell pipelines.
191
+ - Strict mode for CI workflows that should fail on warnings.
192
+ - Stable CLI exit codes for scripts.
193
+ - Default screen and print styles.
194
+
195
+ ## Metadata
196
+
197
+ Documents can include YAML front matter at the top of the Markdown file:
198
+
199
+ ```md
200
+ ---
201
+ title: Project Brief
202
+ subtitle: Quarterly planning notes
203
+ author: Kaleab
204
+ date: 2026-05-27
205
+ cover: true
206
+ ---
207
+
208
+ # Project Brief
209
+ ```
210
+
211
+ The `title` field controls the generated HTML document title unless `--title` is
212
+ provided on the CLI. Set `cover: true` to render a cover page before the table of
213
+ contents and document body. Use `--no-cover` to disable a metadata or config
214
+ cover page for one command.
215
+
216
+ ## Footnotes
217
+
218
+ Use `[^label]` references in the document body and matching definitions later in
219
+ the Markdown file:
220
+
221
+ ```md
222
+ Detailed context can live in a note.[^context]
223
+
224
+ [^context]: Footnotes support Markdown such as **strong text** and links.
225
+ ```
226
+
227
+ Generated footnotes are rendered at the end of the document with backlinks to
228
+ their references.
229
+
230
+ ## Page Breaks
231
+
232
+ Use `[[page-break]]`, `\pagebreak`, or `\newpage` on its own line to insert an
233
+ explicit print break. The generated CSS also includes `.break-before-page`,
234
+ `.break-after-page`, and `.avoid-page-break` helpers for custom styles.
235
+
236
+ ## Configuration
237
+
238
+ Towel.txt automatically looks for `towel-txt.config.yaml`,
239
+ `towel-txt.config.yml`, or `towel-txt.config.json` in the current working
240
+ directory. Use `--config <path>` to load a specific config file, or
241
+ `--no-config` to disable discovery.
242
+
243
+ ```yaml
244
+ output: dist/document.html
245
+ assetDir: assets
246
+ css: examples/print.css
247
+ format: html
248
+ theme: report
249
+ title: Project Brief
250
+ subtitle: Quarterly planning notes
251
+ cover: true
252
+ pageSize: A4
253
+ margin: 18mm
254
+ minify: false
255
+ strict: false
256
+ summaryJson: dist/summary.json
257
+ tableOfContents: true
258
+ ```
259
+
260
+ CLI flags override config defaults. Use `--toc` when a config file disables the
261
+ table of contents and one command needs it enabled.
262
+
263
+ Supported config fields are `output`, `assetDir`, `css`, `format`, `theme`,
264
+ `title`, `subtitle`, `cover`, `pageSize`, `margin`, `minify`,
265
+ `strict`, `summaryJson`, `tableOfContents`, and `browser`.
266
+
267
+ ## Strict Mode
268
+
269
+ Use `--strict` to fail the command when warnings are detected. Strict mode
270
+ currently fails on missing or skipped image assets and front matter metadata
271
+ that would otherwise be ignored, such as unsupported fields or invalid value
272
+ types. Use `--no-strict` to disable a config default for one command.
273
+
274
+ ## JSON Summary
275
+
276
+ Use `--summary-json <path>` to write a machine-readable summary file after a
277
+ successful render. The summary includes the output format, absolute input and
278
+ output paths, bytes written, minify status, copied image results, and warning
279
+ messages.
280
+
281
+ ## Example
282
+
283
+ See [examples/sample.md](examples/sample.md) and the generated
284
+ [examples/sample.html](examples/sample.html).
285
+
286
+ See [examples/print.css](examples/print.css) for a small custom CSS example.
287
+ See [examples/towel-txt.config.yaml](examples/towel-txt.config.yaml) for a
288
+ small config example.
289
+ See [docs/examples.md](docs/examples.md) for report, brief, technical note,
290
+ image, and custom CSS workflows.
291
+ See [docs/security-and-limits.md](docs/security-and-limits.md) for renderer
292
+ security behavior and operational limits.
293
+
294
+ The generated HTML is self-contained, so it can be opened directly in a browser
295
+ and printed from the browser print dialog.
296
+
297
+ When output is written to a different directory, safe relative Markdown image
298
+ paths such as `images/diagram.png` are copied beside the generated HTML output.
299
+ The CLI reports copied images, skipped remote or unsafe sources, and missing
300
+ local files. Use `--asset-dir <dir>` or config `assetDir` to place copied assets
301
+ under a dedicated output folder and rewrite the generated image paths.
302
+
303
+ PDF output uses browser print automation. Install Chrome, Edge, or Chromium, or
304
+ pass `--browser <path>` if the executable is not on the default search path.
305
+
306
+ ## Development
307
+
308
+ This repository uses Node.js, TypeScript, and pnpm.
309
+
310
+ ```bash
311
+ pnpm install
312
+ pnpm release:check
313
+ pnpm lint
314
+ pnpm security:audit
315
+ pnpm typecheck
316
+ pnpm test
317
+ pnpm build
318
+ pnpm perf:smoke
319
+ pnpm smoke:package
320
+ ```
321
+
322
+ ## Roadmap
323
+
324
+ See [docs/production-roadmap.md](docs/production-roadmap.md) for the production
325
+ readiness backlog.
326
+
327
+ ## Contributing
328
+
329
+ Contributions should be small, focused, and easy to review. See
330
+ [CONTRIBUTING.md](CONTRIBUTING.md) for local setup and pull request standards.
331
+
332
+ ## License
333
+
334
+ MIT
@@ -0,0 +1,45 @@
1
+ import { type ThemeName } from "../theme/themes.js";
2
+ import { type CliExitCode } from "./exit-codes.js";
3
+ export type OutputFormat = "html" | "pdf";
4
+ export type CliCommand = {
5
+ kind: "help";
6
+ } | {
7
+ browserPath?: string;
8
+ assetDirectory?: string;
9
+ configPath?: string;
10
+ cover: boolean;
11
+ coverSpecified: boolean;
12
+ cssPath?: string;
13
+ force: boolean;
14
+ format?: OutputFormat;
15
+ inputPath?: string;
16
+ kind: "render";
17
+ margin?: string;
18
+ minify: boolean;
19
+ minifySpecified: boolean;
20
+ noConfig: boolean;
21
+ outputPath?: string;
22
+ pageSize?: string;
23
+ stdout: boolean;
24
+ stdin: boolean;
25
+ strict: boolean;
26
+ strictSpecified: boolean;
27
+ subtitle?: string;
28
+ summaryJsonPath?: string;
29
+ tableOfContents: boolean;
30
+ tableOfContentsSpecified: boolean;
31
+ theme?: ThemeName;
32
+ title?: string;
33
+ watch: boolean;
34
+ } | {
35
+ kind: "version";
36
+ };
37
+ export declare class CliUsageError extends Error {
38
+ readonly exitCode: CliExitCode;
39
+ constructor(message: string, exitCode?: CliExitCode);
40
+ }
41
+ export declare class CliStrictModeError extends CliUsageError {
42
+ constructor(message: string);
43
+ }
44
+ export declare function parseCliArgs(argv: string[]): CliCommand;
45
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAgB,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEjE,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,KAAK,CAAC;AAE1C,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IACE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,OAAO,CAAC;IACzB,wBAAwB,EAAE,OAAO,CAAC;IAClC,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB,GACD;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC;AAExB,qBAAa,aAAc,SAAQ,KAAK;IACtC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,WAAqC;CAK7E;AAED,qBAAa,kBAAmB,SAAQ,aAAa;gBACvC,OAAO,EAAE,MAAM;CAI5B;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA+JvD"}
@@ -0,0 +1,208 @@
1
+ import { parseArgs } from "node:util";
2
+ import { isThemeName } from "../theme/themes.js";
3
+ import { cliExitCodes } from "./exit-codes.js";
4
+ export class CliUsageError extends Error {
5
+ exitCode;
6
+ constructor(message, exitCode = cliExitCodes.usageError) {
7
+ super(message);
8
+ this.name = "CliUsageError";
9
+ this.exitCode = exitCode;
10
+ }
11
+ }
12
+ export class CliStrictModeError extends CliUsageError {
13
+ constructor(message) {
14
+ super(message, cliExitCodes.strictWarnings);
15
+ this.name = "CliStrictModeError";
16
+ }
17
+ }
18
+ export function parseCliArgs(argv) {
19
+ let parsed;
20
+ try {
21
+ parsed = parseArgs({
22
+ allowPositionals: true,
23
+ args: argv,
24
+ options: {
25
+ browser: {
26
+ type: "string"
27
+ },
28
+ "asset-dir": {
29
+ type: "string"
30
+ },
31
+ config: {
32
+ type: "string"
33
+ },
34
+ cover: {
35
+ type: "boolean"
36
+ },
37
+ help: {
38
+ short: "h",
39
+ type: "boolean"
40
+ },
41
+ css: {
42
+ type: "string"
43
+ },
44
+ force: {
45
+ type: "boolean"
46
+ },
47
+ format: {
48
+ type: "string"
49
+ },
50
+ output: {
51
+ short: "o",
52
+ type: "string"
53
+ },
54
+ margin: {
55
+ type: "string"
56
+ },
57
+ minify: {
58
+ type: "boolean"
59
+ },
60
+ "page-size": {
61
+ type: "string"
62
+ },
63
+ "no-toc": {
64
+ type: "boolean"
65
+ },
66
+ "no-config": {
67
+ type: "boolean"
68
+ },
69
+ "no-cover": {
70
+ type: "boolean"
71
+ },
72
+ "no-minify": {
73
+ type: "boolean"
74
+ },
75
+ "no-strict": {
76
+ type: "boolean"
77
+ },
78
+ stdout: {
79
+ type: "boolean"
80
+ },
81
+ stdin: {
82
+ type: "boolean"
83
+ },
84
+ strict: {
85
+ type: "boolean"
86
+ },
87
+ subtitle: {
88
+ type: "string"
89
+ },
90
+ "summary-json": {
91
+ type: "string"
92
+ },
93
+ title: {
94
+ type: "string"
95
+ },
96
+ theme: {
97
+ type: "string"
98
+ },
99
+ toc: {
100
+ type: "boolean"
101
+ },
102
+ version: {
103
+ type: "boolean"
104
+ },
105
+ watch: {
106
+ type: "boolean"
107
+ }
108
+ },
109
+ strict: true
110
+ });
111
+ }
112
+ catch (error) {
113
+ throw new CliUsageError(error instanceof Error ? error.message : "Invalid arguments.");
114
+ }
115
+ if (parsed.values.help) {
116
+ return { kind: "help" };
117
+ }
118
+ if (parsed.values.version) {
119
+ return { kind: "version" };
120
+ }
121
+ if (parsed.values.toc === true && parsed.values["no-toc"] === true) {
122
+ throw new CliUsageError("Do not pass --toc with --no-toc.");
123
+ }
124
+ if (parsed.values.cover === true && parsed.values["no-cover"] === true) {
125
+ throw new CliUsageError("Do not pass --cover with --no-cover.");
126
+ }
127
+ if (parsed.values.minify === true && parsed.values["no-minify"] === true) {
128
+ throw new CliUsageError("Do not pass --minify with --no-minify.");
129
+ }
130
+ if (parsed.values.strict === true && parsed.values["no-strict"] === true) {
131
+ throw new CliUsageError("Do not pass --strict with --no-strict.");
132
+ }
133
+ if (parsed.values.stdin === true && parsed.positionals.length > 0) {
134
+ throw new CliUsageError("Do not pass an input file when using --stdin.");
135
+ }
136
+ if (parsed.values.stdin !== true && parsed.positionals.length !== 1) {
137
+ throw new CliUsageError("Expected exactly one Markdown input file.");
138
+ }
139
+ return {
140
+ assetDirectory: getAssetDirectoryOption(parsed.values["asset-dir"], "--asset-dir"),
141
+ browserPath: getStringOption(parsed.values.browser),
142
+ configPath: getStringOption(parsed.values.config),
143
+ cover: parsed.values.cover === true && parsed.values["no-cover"] !== true,
144
+ coverSpecified: parsed.values.cover === true || parsed.values["no-cover"] === true,
145
+ cssPath: getStringOption(parsed.values.css),
146
+ force: parsed.values.force === true,
147
+ format: getOutputFormatOption(parsed.values.format),
148
+ ...(parsed.positionals[0] ? { inputPath: parsed.positionals[0] } : {}),
149
+ kind: "render",
150
+ margin: getStringOption(parsed.values.margin),
151
+ minify: parsed.values.minify === true && parsed.values["no-minify"] !== true,
152
+ minifySpecified: parsed.values.minify === true || parsed.values["no-minify"] === true,
153
+ noConfig: parsed.values["no-config"] === true,
154
+ outputPath: getStringOption(parsed.values.output),
155
+ pageSize: getStringOption(parsed.values["page-size"]),
156
+ stdin: parsed.values.stdin === true,
157
+ stdout: parsed.values.stdout === true,
158
+ strict: parsed.values.strict === true && parsed.values["no-strict"] !== true,
159
+ strictSpecified: parsed.values.strict === true || parsed.values["no-strict"] === true,
160
+ subtitle: getStringOption(parsed.values.subtitle),
161
+ summaryJsonPath: getStringOption(parsed.values["summary-json"]),
162
+ tableOfContents: parsed.values["no-toc"] !== true,
163
+ tableOfContentsSpecified: parsed.values["no-toc"] === true || parsed.values.toc === true,
164
+ theme: getThemeOption(parsed.values.theme),
165
+ title: getStringOption(parsed.values.title),
166
+ watch: parsed.values.watch === true
167
+ };
168
+ }
169
+ function getThemeOption(value) {
170
+ if (value === undefined) {
171
+ return undefined;
172
+ }
173
+ if (isThemeName(value)) {
174
+ return value;
175
+ }
176
+ throw new CliUsageError('Expected --theme to be "default", "compact", or "report".');
177
+ }
178
+ function getStringOption(value) {
179
+ return typeof value === "string" ? value : undefined;
180
+ }
181
+ function getAssetDirectoryOption(value, optionName) {
182
+ const directory = getStringOption(value)?.trim();
183
+ if (!directory) {
184
+ return undefined;
185
+ }
186
+ if (directory.includes("?") ||
187
+ directory.includes("#") ||
188
+ /^[a-z][a-z0-9+.-]*:/iu.test(directory) ||
189
+ directory.startsWith("/") ||
190
+ directory.startsWith("\\")) {
191
+ throw new CliUsageError(`Expected ${optionName} to be a safe relative directory.`);
192
+ }
193
+ const normalizedDirectory = directory.replace(/\\/g, "/");
194
+ const parts = normalizedDirectory.split("/");
195
+ if (parts.includes("..") || parts.includes("")) {
196
+ throw new CliUsageError(`Expected ${optionName} to be a safe relative directory.`);
197
+ }
198
+ return normalizedDirectory;
199
+ }
200
+ function getOutputFormatOption(value) {
201
+ if (value === undefined) {
202
+ return undefined;
203
+ }
204
+ if (value === "html" || value === "pdf") {
205
+ return value;
206
+ }
207
+ throw new CliUsageError('Expected --format to be "html" or "pdf".');
208
+ }
@@ -0,0 +1,15 @@
1
+ export interface CopyImageAssetsOptions {
2
+ assetDirectory?: string;
3
+ inputPath: string;
4
+ markdown: string;
5
+ outputPath: string;
6
+ }
7
+ export interface ImageAssetCopyResult {
8
+ error?: string;
9
+ reason?: string;
10
+ source: string;
11
+ status: "copied" | "missing" | "skipped";
12
+ targetSource?: string;
13
+ }
14
+ export declare function copyLocalImageAssets(options: CopyImageAssetsOptions): Promise<ImageAssetCopyResult[]>;
15
+ //# sourceMappingURL=assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../src/cli/assets.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,sBAAsB;IACrC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,oBAAoB,EAAE,CAAC,CA6CjC"}