@intentic/fileq 1.317.0 → 1.318.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 (111) hide show
  1. package/NOTICE +208 -0
  2. package/README.md +24 -3
  3. package/dist/app.d.ts.map +1 -1
  4. package/dist/app.js +15 -1
  5. package/dist/app.js.map +1 -1
  6. package/dist/commands/check.command.d.ts +3 -0
  7. package/dist/commands/check.command.d.ts.map +1 -0
  8. package/dist/commands/check.command.js +80 -0
  9. package/dist/commands/check.command.js.map +1 -0
  10. package/dist/commands/render.command.d.ts +3 -0
  11. package/dist/commands/render.command.d.ts.map +1 -0
  12. package/dist/commands/render.command.js +67 -0
  13. package/dist/commands/render.command.js.map +1 -0
  14. package/dist/lib/check/check.d.ts +15 -0
  15. package/dist/lib/check/check.d.ts.map +1 -0
  16. package/dist/lib/check/check.js +35 -0
  17. package/dist/lib/check/check.js.map +1 -0
  18. package/dist/lib/check/docx.d.ts +3 -0
  19. package/dist/lib/check/docx.d.ts.map +1 -0
  20. package/dist/lib/check/docx.js +329 -0
  21. package/dist/lib/check/docx.js.map +1 -0
  22. package/dist/lib/check/finding.d.ts +20 -0
  23. package/dist/lib/check/finding.d.ts.map +1 -0
  24. package/dist/lib/check/finding.js +27 -0
  25. package/dist/lib/check/finding.js.map +1 -0
  26. package/dist/lib/check/package.d.ts +25 -0
  27. package/dist/lib/check/package.d.ts.map +1 -0
  28. package/dist/lib/check/package.js +139 -0
  29. package/dist/lib/check/package.js.map +1 -0
  30. package/dist/lib/check/pdf.d.ts +3 -0
  31. package/dist/lib/check/pdf.d.ts.map +1 -0
  32. package/dist/lib/check/pdf.js +160 -0
  33. package/dist/lib/check/pdf.js.map +1 -0
  34. package/dist/lib/check/pptx.d.ts +3 -0
  35. package/dist/lib/check/pptx.d.ts.map +1 -0
  36. package/dist/lib/check/pptx.js +497 -0
  37. package/dist/lib/check/pptx.js.map +1 -0
  38. package/dist/lib/check/text-fit.d.ts +18 -0
  39. package/dist/lib/check/text-fit.d.ts.map +1 -0
  40. package/dist/lib/check/text-fit.js +69 -0
  41. package/dist/lib/check/text-fit.js.map +1 -0
  42. package/dist/lib/check/xlsx.d.ts +3 -0
  43. package/dist/lib/check/xlsx.d.ts.map +1 -0
  44. package/dist/lib/check/xlsx.js +131 -0
  45. package/dist/lib/check/xlsx.js.map +1 -0
  46. package/dist/lib/check/xml-tree.d.ts +15 -0
  47. package/dist/lib/check/xml-tree.d.ts.map +1 -0
  48. package/dist/lib/check/xml-tree.js +131 -0
  49. package/dist/lib/check/xml-tree.js.map +1 -0
  50. package/dist/lib/derivers/image.d.ts.map +1 -1
  51. package/dist/lib/derivers/image.js.map +1 -1
  52. package/dist/lib/formats.d.ts +1 -0
  53. package/dist/lib/formats.d.ts.map +1 -1
  54. package/dist/lib/formats.js +1 -0
  55. package/dist/lib/formats.js.map +1 -1
  56. package/dist/lib/render/convert.d.ts +11 -0
  57. package/dist/lib/render/convert.d.ts.map +1 -0
  58. package/dist/lib/render/convert.js +107 -0
  59. package/dist/lib/render/convert.js.map +1 -0
  60. package/dist/lib/render/pages.d.ts +11 -0
  61. package/dist/lib/render/pages.d.ts.map +1 -0
  62. package/dist/lib/render/pages.js +43 -0
  63. package/dist/lib/render/pages.js.map +1 -0
  64. package/dist/lib/render/render.d.ts +29 -0
  65. package/dist/lib/render/render.d.ts.map +1 -0
  66. package/dist/lib/render/render.js +142 -0
  67. package/dist/lib/render/render.js.map +1 -0
  68. package/dist/skill-authoring.d.ts +2 -0
  69. package/dist/skill-authoring.d.ts.map +1 -0
  70. package/dist/skill-authoring.js +20 -0
  71. package/dist/skill-authoring.js.map +1 -0
  72. package/dist/skill.d.ts.map +1 -1
  73. package/dist/skill.js +24 -1
  74. package/dist/skill.js.map +1 -1
  75. package/dist/testing.d.ts +67 -0
  76. package/dist/testing.d.ts.map +1 -1
  77. package/dist/testing.js +151 -0
  78. package/dist/testing.js.map +1 -1
  79. package/package.json +20 -7
  80. package/src/app.ts +15 -1
  81. package/src/cli.integration.test.ts +63 -1
  82. package/src/commands/check.command.ts +97 -0
  83. package/src/commands/render.command.ts +80 -0
  84. package/src/lib/check/check.test.ts +446 -0
  85. package/src/lib/check/check.ts +49 -0
  86. package/src/lib/check/docx.ts +434 -0
  87. package/src/lib/check/finding.ts +63 -0
  88. package/src/lib/check/package.ts +199 -0
  89. package/src/lib/check/pdf.ts +228 -0
  90. package/src/lib/check/pptx.ts +641 -0
  91. package/src/lib/check/text-fit.ts +105 -0
  92. package/src/lib/check/xlsx.ts +163 -0
  93. package/src/lib/check/xml-tree.ts +186 -0
  94. package/src/lib/derivers/image.ts +2 -1
  95. package/src/lib/formats.ts +6 -0
  96. package/src/lib/render/convert.ts +133 -0
  97. package/src/lib/render/pages.test.ts +38 -0
  98. package/src/lib/render/pages.ts +58 -0
  99. package/src/lib/render/render.ts +198 -0
  100. package/src/render.integration.test.ts +217 -0
  101. package/src/skill-authoring.ts +27 -0
  102. package/src/skill.ts +28 -1
  103. package/src/testing.ts +287 -0
  104. package/dist/lib/flags.d.ts +0 -2
  105. package/dist/lib/flags.d.ts.map +0 -1
  106. package/dist/lib/flags.js +0 -8
  107. package/dist/lib/flags.js.map +0 -1
  108. package/dist/version.d.ts +0 -2
  109. package/dist/version.d.ts.map +0 -1
  110. package/dist/version.js +0 -3
  111. package/dist/version.js.map +0 -1
@@ -0,0 +1,29 @@
1
+ import { type Format } from "../formats.js";
2
+ import { type PageRange } from "./pages.js";
3
+ export declare const RENDERED_DIR = ".intentic/local/cache/rendered";
4
+ export declare const DEFAULT_PAGE_CAP = 20;
5
+ export declare const DEFAULT_SIZE = 1600;
6
+ export declare class NotRenderable extends Error {
7
+ }
8
+ export interface RenderRequest {
9
+ readonly absPath: string;
10
+ readonly pages: readonly PageRange[] | undefined;
11
+ readonly outDir: string | undefined;
12
+ readonly size: number;
13
+ }
14
+ export interface RenderedPage {
15
+ readonly page: number;
16
+ readonly path: string;
17
+ }
18
+ export interface RenderResult {
19
+ readonly format: Format;
20
+ readonly unit: "slide" | "page";
21
+ readonly total: number;
22
+ readonly images: RenderedPage[];
23
+ readonly outDir: string;
24
+ readonly reused: boolean;
25
+ readonly notes: string[];
26
+ }
27
+ export declare const defaultOutDir: (absPath: string, workspaceRoot: string | undefined) => string;
28
+ export declare const renderDocument: (request: RenderRequest, workspaceRoot: string | undefined) => Promise<RenderResult>;
29
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/lib/render/render.ts"],"names":[],"mappings":"AAQA,OAAO,EAAiB,KAAK,MAAM,EAAE,MAAM,eAAe,CAAC;AAG3D,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAQnE,eAAO,MAAM,YAAY,mCAAsC,CAAC;AAIhE,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,YAAY,OAAO,CAAC;AAKjC,qBAAa,aAAc,SAAQ,KAAK;CAAG;AAE3C,MAAM,WAAW,aAAa;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,QAAQ,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,CAAC;IAEjD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IAEpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;CAC5B;AAWD,eAAO,MAAM,aAAa,YAAa,MAAM,iBAAiB,MAAM,GAAG,SAAS,KAAG,MAOlF,CAAC;AAyEF,eAAO,MAAM,cAAc,YAAmB,aAAa,iBAAiB,MAAM,GAAG,SAAS,KAAG,OAAO,CAAC,YAAY,CAkDpH,CAAC"}
@@ -0,0 +1,142 @@
1
+ import { createHash } from "node:crypto";
2
+ import { copyFile, mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
3
+ import { tmpdir } from "node:os";
4
+ import { basename, join } from "node:path";
5
+ import { toolOutDir } from "@intentic/agent-cli/env";
6
+ import { STATE_DIR } from "@intentic/constants";
7
+ import { getDocumentProxy } from "unpdf";
8
+ import { relPathIn } from "../derive.js";
9
+ import { claimedFormat } from "../formats.js";
10
+ import { sha256OfFile } from "../sidecar.js";
11
+ import { ConvertFailed, listDir, office, rasterizer, toPdf, toPngs } from "./convert.js";
12
+ import { BadPages, pagesWithin } from "./pages.js";
13
+ export const RENDERED_DIR = `${STATE_DIR}/local/cache/rendered`;
14
+ export const DEFAULT_PAGE_CAP = 20;
15
+ export const DEFAULT_SIZE = 1600;
16
+ const VIA_OFFICE = new Set(["docx", "pptx", "xlsx", "odt", "ods", "odp", "rtf"]);
17
+ const SLIDES = new Set(["pptx", "odp"]);
18
+ export class NotRenderable extends Error {
19
+ }
20
+ const STAMP_FILE = ".fileq-render.json";
21
+ export const defaultOutDir = (absPath, workspaceRoot) => {
22
+ const relPath = workspaceRoot === undefined ? undefined : relPathIn(workspaceRoot, absPath);
23
+ if (workspaceRoot !== undefined && relPath !== undefined) {
24
+ return join(workspaceRoot, RENDERED_DIR, relPath);
25
+ }
26
+ const hash = createHash("sha256").update(absPath).digest("hex").slice(0, 8);
27
+ return join(toolOutDir("fileq"), "rendered", `${basename(absPath).toLowerCase().replaceAll(/[^a-z0-9.]+/g, "-")}-${hash}`);
28
+ };
29
+ const readStamp = async (dir) => {
30
+ try {
31
+ const parsed = JSON.parse(await readFile(join(dir, STAMP_FILE), "utf8"));
32
+ return parsed.sha256 === undefined || parsed.size === undefined || parsed.total === undefined ? undefined : { sha256: parsed.sha256, size: parsed.size, total: parsed.total };
33
+ }
34
+ catch {
35
+ return undefined;
36
+ }
37
+ };
38
+ const clearImages = async (dir) => {
39
+ const names = await listDir(dir);
40
+ await Promise.all(names.filter((name) => /^(?:slide|page)-\d+\.png$/.test(name)).map((name) => rm(join(dir, name), { force: true })));
41
+ };
42
+ const ignoreInGit = async (workspaceRoot, outDir) => {
43
+ if (workspaceRoot === undefined || !outDir.startsWith(join(workspaceRoot, RENDERED_DIR))) {
44
+ return;
45
+ }
46
+ try {
47
+ await writeFile(join(workspaceRoot, RENDERED_DIR, ".gitignore"), "# fileq's rendered pages; regenerated on demand.\n*\n", { flag: "wx" });
48
+ }
49
+ catch {
50
+ }
51
+ };
52
+ const pageCount = async (pdfPath) => {
53
+ try {
54
+ const pdf = await getDocumentProxy(new Uint8Array(await readFile(pdfPath)));
55
+ return pdf.numPages;
56
+ }
57
+ catch (cause) {
58
+ const locked = cause instanceof Error && cause.name === "PasswordException";
59
+ throw new ConvertFailed(locked ? "the PDF is password-protected" : "the PDF cannot be read");
60
+ }
61
+ };
62
+ const formatOf = async (absPath) => {
63
+ const format = await claimedFormat(absPath);
64
+ if (format === "pdf" || (format !== undefined && VIA_OFFICE.has(format))) {
65
+ return format;
66
+ }
67
+ if (format === "image") {
68
+ throw new NotRenderable("an image is already pixels: Read it directly");
69
+ }
70
+ throw new NotRenderable(`fileq render draws pdf, docx, pptx, xlsx, odt, odp, ods and rtf; this is ${format ?? "none of them"}`);
71
+ };
72
+ const choosePages = (request, total, unit, notes) => {
73
+ if (request.pages === undefined) {
74
+ const pages = pagesWithin([{ from: 1, to: DEFAULT_PAGE_CAP }], total);
75
+ if (total > DEFAULT_PAGE_CAP) {
76
+ notes.push(`drew the first ${DEFAULT_PAGE_CAP} of ${total} ${unit}s: pass --pages ${DEFAULT_PAGE_CAP + 1}-${total} for the rest`);
77
+ }
78
+ return pages;
79
+ }
80
+ const pages = pagesWithin(request.pages, total);
81
+ if (pages.length === 0) {
82
+ throw new BadPages(`the document has ${total} ${unit}${total === 1 ? "" : "s"}; --pages names none of them`);
83
+ }
84
+ const asked = request.pages.some((range) => (range.to ?? range.from) > total);
85
+ if (asked) {
86
+ notes.push(`the document has ${total} ${unit}${total === 1 ? "" : "s"}; drew the ones --pages named within that`);
87
+ }
88
+ return pages;
89
+ };
90
+ export const renderDocument = async (request, workspaceRoot) => {
91
+ const format = await formatOf(request.absPath);
92
+ const unit = SLIDES.has(format) ? "slide" : "page";
93
+ const tool = rasterizer();
94
+ const binary = format === "pdf" ? undefined : office(format);
95
+ const outDir = request.outDir ?? defaultOutDir(request.absPath, workspaceRoot);
96
+ const notes = [];
97
+ const sha256 = await sha256OfFile(request.absPath);
98
+ const cached = request.outDir === undefined ? await readStamp(outDir) : undefined;
99
+ const current = cached !== undefined && cached.sha256 === sha256 && cached.size === request.size;
100
+ if (current) {
101
+ const pages = choosePages(request, cached.total, unit, notes);
102
+ const existing = new Set(await listDir(outDir));
103
+ if (pages.every((page) => existing.has(`${unit}-${page}.png`))) {
104
+ return { format, unit, total: cached.total, images: pages.map((page) => ({ page, path: join(outDir, `${unit}-${page}.png`) })), outDir, reused: true, notes };
105
+ }
106
+ notes.length = 0;
107
+ }
108
+ const work = await mkdtemp(join(tmpdir(), "fileq-render-"));
109
+ try {
110
+ const pdf = binary === undefined ? request.absPath : await toPdf(binary, request.absPath, format, work);
111
+ const total = await pageCount(pdf);
112
+ const pages = choosePages(request, total, unit, notes);
113
+ const raster = join(work, "png");
114
+ await mkdir(raster, { recursive: true });
115
+ const drawn = await toPngs(tool, pdf, pages, request.size, raster);
116
+ await mkdir(outDir, { recursive: true });
117
+ await ignoreInGit(workspaceRoot, outDir);
118
+ if (request.outDir === undefined && !current) {
119
+ await clearImages(outDir);
120
+ }
121
+ const images = [];
122
+ for (const page of pages) {
123
+ const from = drawn.get(page);
124
+ if (from !== undefined) {
125
+ const path = join(outDir, `${unit}-${page}.png`);
126
+ await copyFile(from, path);
127
+ images.push({ page, path });
128
+ }
129
+ }
130
+ if (images.length < pages.length) {
131
+ notes.push(`${pages.length - images.length} of the ${unit}s asked for drew nothing`);
132
+ }
133
+ if (request.outDir === undefined) {
134
+ await writeFile(join(outDir, STAMP_FILE), `${JSON.stringify({ sha256, size: request.size, total })}\n`);
135
+ }
136
+ return { format, unit, total, images, outDir, reused: false, notes };
137
+ }
138
+ finally {
139
+ await rm(work, { recursive: true, force: true });
140
+ }
141
+ };
142
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/lib/render/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const AUTHORING_RULES = "## Making a document someone will open\nRules that decide whether a generated file looks right (adapted from SurfSense's document skills, Apache-2.0):\n- **Decks**: one purpose per slide, at most about six short bullets; titles 32\u201340 pt, body at least 18 pt;\n 0.5 in outer margins, and every shape on the slide (no parking shapes off-canvas, no hidden spare slides).\n Fill every placeholder you keep or delete it; no prompt text, TODOs or design notes on a slide. Size each\n box to its text instead of relying on autofit, which PowerPoint and LibreOffice resolve differently: shorten\n or split the slide. Keep an image's proportions: set one side and derive the other, crop rather than stretch.\n- **Word documents**: built-in heading styles, real list numbering (never a typed \"\u2022\"), a page break as its\n own paragraph, margins of at least 18 mm, one page size and orientation. A table of contents only when asked,\n and say its page numbers fill in when Word updates fields. No image wider than the text column.\n- **Spreadsheets**: save every formula with its computed value (XlsxWriter's `write_formula(cell, formula,\n format, value)`; openpyxl saves none, so recalculate its output with LibreOffice). Leave no error value\n (#REF!, #DIV/0!, #N/A) in a cell. Name sheets for the reader, set column widths, freeze header rows.\n- **PDFs**: embed the fonts (register a TTF in ReportLab; WeasyPrint embeds on its own); A4 or US Letter by\n locale, margins of at least 18 mm. To turn an office file into a PDF:\n `soffice --headless -env:UserInstallation=file:///tmp/lo-$$ --convert-to pdf --outdir <dir> <file>`\n (its own profile per run; the output is named after the source).\n- Fonts: prefer Arial, Times New Roman or Courier New where the layout is tight: LibreOffice substitutes their\n metric-compatible Liberation fonts, so lines break the same. Any other font gets about 10% spare room.";
2
+ //# sourceMappingURL=skill-authoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-authoring.d.ts","sourceRoot":"","sources":["../src/skill-authoring.ts"],"names":[],"mappings":"AAQA,eAAO,MAAM,eAAe,04DAkB6E,CAAC"}
@@ -0,0 +1,20 @@
1
+ export const AUTHORING_RULES = `## Making a document someone will open
2
+ Rules that decide whether a generated file looks right (adapted from SurfSense's document skills, Apache-2.0):
3
+ - **Decks**: one purpose per slide, at most about six short bullets; titles 32–40 pt, body at least 18 pt;
4
+ 0.5 in outer margins, and every shape on the slide (no parking shapes off-canvas, no hidden spare slides).
5
+ Fill every placeholder you keep or delete it; no prompt text, TODOs or design notes on a slide. Size each
6
+ box to its text instead of relying on autofit, which PowerPoint and LibreOffice resolve differently: shorten
7
+ or split the slide. Keep an image's proportions: set one side and derive the other, crop rather than stretch.
8
+ - **Word documents**: built-in heading styles, real list numbering (never a typed "•"), a page break as its
9
+ own paragraph, margins of at least 18 mm, one page size and orientation. A table of contents only when asked,
10
+ and say its page numbers fill in when Word updates fields. No image wider than the text column.
11
+ - **Spreadsheets**: save every formula with its computed value (XlsxWriter's \`write_formula(cell, formula,
12
+ format, value)\`; openpyxl saves none, so recalculate its output with LibreOffice). Leave no error value
13
+ (#REF!, #DIV/0!, #N/A) in a cell. Name sheets for the reader, set column widths, freeze header rows.
14
+ - **PDFs**: embed the fonts (register a TTF in ReportLab; WeasyPrint embeds on its own); A4 or US Letter by
15
+ locale, margins of at least 18 mm. To turn an office file into a PDF:
16
+ \`soffice --headless -env:UserInstallation=file:///tmp/lo-$$ --convert-to pdf --outdir <dir> <file>\`
17
+ (its own profile per run; the output is named after the source).
18
+ - Fonts: prefer Arial, Times New Roman or Courier New where the layout is tight: LibreOffice substitutes their
19
+ metric-compatible Liberation fonts, so lines break the same. Any other font gets about 10% spare room.`;
20
+ //# sourceMappingURL=skill-authoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-authoring.js","sourceRoot":"","sources":["../src/skill-authoring.ts"],"names":[],"mappings":"AAQA,MAAM,CAAC,MAAM,eAAe,GAAG;;;;;;;;;;;;;;;;;;yGAkB0E,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,cAAc;IAE3B,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;CAC3C;AAwBD,eAAO,MAAM,UAAU,aAAc,cAAc,KAAG,MAsDrD,CAAC"}
1
+ {"version":3,"file":"skill.d.ts","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,cAAc;IAE3B,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,CAAC;CAC3C;AAmCD,eAAO,MAAM,UAAU,aAAc,cAAc,KAAG,MAqErD,CAAC"}
package/dist/skill.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { DERIVED_DIR } from "./lib/sidecar.js";
2
+ import { AUTHORING_RULES } from "./skill-authoring.js";
2
3
  const OCR_FORMAT = {
3
4
  sandbox: "a scan is OCR'd when the image carries tesseract",
4
5
  standalone: "a scan is OCR'd when `tesseract` is on PATH",
@@ -11,6 +12,13 @@ const OCR_REFUSAL = {
11
12
  rather than an empty page; images say "no visual description". Treat those notes as "not generated",
12
13
  never as "nothing there". Installing tesseract turns the first into OCR.`,
13
14
  };
15
+ const RENDER_TOOLS = {
16
+ sandbox: `It needs LibreOffice (\`soffice\`) for office formats and \`pdftoppm\` for every format, both in the opt-in
17
+ \`office\` image pack. If it exits 2 naming one, run the \`environment propose office --pack\` it prints (the owner
18
+ approves, a rebuild brings it), say the document was checked but not seen, and do not claim it looks right.`,
19
+ standalone: `It needs LibreOffice (\`soffice\`) for office formats and \`pdftoppm\` (poppler-utils) or \`mutool\` for
20
+ every format. If it exits 2 naming one, install it or tell the user the document was checked but not seen.`,
21
+ };
14
22
  const TEXTCONV = `## What changed in a document
15
23
  \`git diff\`, \`git show\` and \`git log -p\` on a .docx, .xlsx, .pptx, .pdf or .ipynb print the change to its
16
24
  text, not "Binary files differ": every derivable extension is routed through fileq as git's textconv. Read the
@@ -19,7 +27,7 @@ diff; do not convert both versions by hand.
19
27
  `;
20
28
  export const fileqSkill = ({ host }) => `---
21
29
  name: fileq
22
- description: Read binary workspace files (docx, odt, xlsx, pptx, pdf, epub, ipynb, images, audio, zip and tar archives, V8 CPU and heap profiles) as clean budgeted markdown with the \`fileq\` CLI, and read big text-shaped files (csv, json, logs) without flooding your context. Use whenever a task needs the contents of a document, the text layer of a PDF, the metadata of an image or recording, what is inside an archive, or a look inside a file too large to cat — instead of guessing from the filename or shelling out to ad-hoc converters.
30
+ description: Read binary files (docx, xlsx, pptx, pdf, odt, epub, ipynb, images, audio, archives, V8 profiles) as budgeted markdown with \`fileq\`, size up csv, json or logs too big to cat, and check and render a docx, pptx, xlsx or pdf you made. Use instead of guessing from a filename, ad-hoc converters, or delivering it unseen.
23
31
  ---
24
32
 
25
33
  # fileq: binary files as markdown
@@ -53,6 +61,21 @@ ${OCR_REFUSAL[host]}
53
61
 
54
62
  ${host === "sandbox" ? TEXTCONV : ""}Exit codes: 0 content, 1 nothing derivable, 2 broken invocation or install.
55
63
 
64
+ ## After you produce a document
65
+ A deck, report, spreadsheet or PDF made for someone is not finished until you have checked it and looked at it.
66
+ 1. \`fileq check <file>\` (docx, pptx, xlsx, pdf) lists what a reader would meet, each with where it is:
67
+ \`slide 3 · "Title 1"\`, \`'Q3 plan'!C4\`, \`page 7\`, \`paragraph 12 · "…"\`. Exit 1 means an error (a missing
68
+ image, a #REF!, a broken link, leftover "Click to add title"): fix every one and check again. Warnings are
69
+ judgement calls (a TODO, a hidden slide) or estimates (text overflowing its box): settle those by looking.
70
+ 2. \`fileq render <file> [--pages 1-3]\` draws the pages or slides as PNGs (the first 20 unless you say) and
71
+ prints one path per line; Read them. An unchanged file answers from its last render. Office formats are laid
72
+ out by LibreOffice, so a font the machine lacks is substituted: judge overflow and spacing, not the typeface.
73
+ ${RENDER_TOOLS[host].replaceAll("\n", "\n ")}
74
+ Fix what you find in whatever generated the file, regenerate, and check again; after two rounds, stop and tell
75
+ the user what is left rather than looping.
76
+
77
+ ${AUTHORING_RULES}
78
+
56
79
  ## Text-shaped files that are too big to cat
57
80
  The commonest way to lose a context window is \`cat\` on a file you have not sized. Stat first, then read
58
81
  the shape, then only what the question needs:
package/dist/skill.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"skill.js","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAa/C,MAAM,UAAU,GAA2C;IACvD,OAAO,EAAE,kDAAkD;IAC3D,UAAU,EAAE,6CAA6C;CAC5D,CAAC;AAEF,MAAM,WAAW,GAA2C;IACxD,OAAO,EAAE;;iGAEoF;IAC7F,UAAU,EAAE;;2EAE2D;CAC1E,CAAC;AAGF,MAAM,QAAQ,GAAG;;;;;CAKhB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EAAE,IAAI,EAAkB,EAAU,EAAE,CAAC;;;;;;;;;;;;;;;qBAe3C,UAAU,CAAC,IAAI,CAAC;;;;;;;;;;wCAUG,WAAW;;;;;EAKjD,WAAW,CAAC,IAAI,CAAC;;;;EAIjB,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;CAoBnC,CAAC"}
1
+ {"version":3,"file":"skill.js","sourceRoot":"","sources":["../src/skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAavD,MAAM,UAAU,GAA2C;IACvD,OAAO,EAAE,kDAAkD;IAC3D,UAAU,EAAE,6CAA6C;CAC5D,CAAC;AAEF,MAAM,WAAW,GAA2C;IACxD,OAAO,EAAE;;iGAEoF;IAC7F,UAAU,EAAE;;2EAE2D;CAC1E,CAAC;AAKF,MAAM,YAAY,GAAG;IACjB,OAAO,EAAE;;4GAE+F;IACxG,UAAU,EAAE;2GAC2F;CACzD,CAAC;AAGnD,MAAM,QAAQ,GAAG;;;;;CAKhB,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,EAAE,IAAI,EAAkB,EAAU,EAAE,CAAC;;;;;;;;;;;;;;;qBAe3C,UAAU,CAAC,IAAI,CAAC;;;;;;;;;;wCAUG,WAAW;;;;;EAKjD,WAAW,CAAC,IAAI,CAAC;;;;EAIjB,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;KAW/B,YAAY,CAAC,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC;;;;EAI/C,eAAe;;;;;;;;;;;;;;;;;;;;CAoBhB,CAAC"}
package/dist/testing.d.ts CHANGED
@@ -22,4 +22,71 @@ export declare const zipBytes: (files: Readonly<Record<string, string>>) => Uint
22
22
  export declare const tarBytes: (files: Readonly<Record<string, string>>) => Uint8Array;
23
23
  export declare const gzipBytes: (name: string, content: Uint8Array | string) => Uint8Array;
24
24
  export declare const pngBytes: () => Uint8Array;
25
+ export interface FixtureRel {
26
+ readonly type: string;
27
+ readonly target: string;
28
+ readonly external?: boolean;
29
+ }
30
+ export interface Frame {
31
+ readonly x: number;
32
+ readonly y: number;
33
+ readonly w: number;
34
+ readonly h: number;
35
+ }
36
+ export interface TextBoxOptions {
37
+ readonly size?: number;
38
+ readonly ph?: {
39
+ readonly type?: string;
40
+ readonly idx?: number;
41
+ };
42
+ readonly autofit?: "shrink" | "grow";
43
+ }
44
+ export declare const textBox: (name: string, frame: Frame | undefined, lines: readonly string[], options?: TextBoxOptions) => string;
45
+ export declare const pictureFrame: (name: string, frame: Frame, rId: string, crop?: {
46
+ readonly l?: number;
47
+ readonly r?: number;
48
+ readonly t?: number;
49
+ readonly b?: number;
50
+ }) => string;
51
+ export declare const tableFrame: (name: string, frame: Frame, rows: readonly (readonly string[])[], height: number, size?: number) => string;
52
+ export interface DeckSlide {
53
+ readonly drawings: readonly string[];
54
+ readonly rels?: Readonly<Record<string, FixtureRel>>;
55
+ readonly hidden?: boolean;
56
+ readonly partNumber?: number;
57
+ }
58
+ export interface DeckOptions {
59
+ readonly slides: readonly DeckSlide[];
60
+ readonly media?: Readonly<Record<string, Uint8Array>>;
61
+ readonly width?: number;
62
+ readonly height?: number;
63
+ readonly untypedMedia?: boolean;
64
+ }
65
+ export declare const deckBytes: (options: DeckOptions) => Uint8Array;
66
+ export declare const pngOfSize: (width: number, height: number) => Uint8Array;
67
+ export declare const para: (text: string, style?: string) => string;
68
+ export declare const inlinePicture: (rId: string, width: number, height: number) => string;
69
+ export declare const field: (instruction: string, result: string | undefined) => string;
70
+ export interface WordOptions {
71
+ readonly body: readonly string[];
72
+ readonly rels?: Readonly<Record<string, FixtureRel>>;
73
+ readonly media?: Readonly<Record<string, Uint8Array>>;
74
+ readonly comments?: readonly string[];
75
+ }
76
+ export declare const wordBytes: (options: WordOptions) => Uint8Array;
77
+ export interface SheetFixture {
78
+ readonly name: string;
79
+ readonly rows: string;
80
+ }
81
+ export declare const workbookBytes: (sheets: readonly SheetFixture[], options?: {
82
+ readonly definedNames?: string;
83
+ readonly calcPr?: string;
84
+ }) => Uint8Array;
85
+ export interface PdfPageFixture {
86
+ readonly content: string;
87
+ readonly font?: string;
88
+ readonly extra?: string;
89
+ readonly size?: readonly [number, number];
90
+ }
91
+ export declare const pdfPagesBytes: (pages: readonly PdfPageFixture[]) => Uint8Array;
25
92
  //# sourceMappingURL=testing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,SAAS,YAAa,MAAM,cAAc,SAAS,MAAM,EAAE,KAAG,UAiB1E,CAAC;AASF,eAAO,MAAM,SAAS,WAAY,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,KAAG,UAgBlE,CAAC;AAMF,eAAO,MAAM,QAAQ,SAAU,MAAM,KAAG,UAwBvC,CAAC;AAGF,eAAO,MAAM,QAAQ,QAAO,UA0B3B,CAAC;AAMF,eAAO,MAAM,QAAQ,YAAa,MAAM,cAAc,SAAS,MAAM,EAAE,KAAG,UA0BpE,CAAC;AAoBP,eAAO,MAAM,QAAQ,WAAY,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAA;CAAE,EAAE,KAAG,UAgBlH,CAAC;AAGN,eAAO,MAAM,QAAQ,WAAY,SAAS;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,KAAG,UAc9H,CAAC;AAGN,eAAO,MAAM,QAAQ,eAAgB,SAAS,MAAM,EAAE,KAAG,UAKpD,CAAC;AAGN,eAAO,MAAM,SAAS,UAAW,MAAM,YAAY,SAAS;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,KAAG,UAyBjH,CAAC;AAGF,eAAO,MAAM,SAAS,UAAW,MAAM,QAAQ,MAAM,eAAe,SAAS,MAAM,EAAE,KAAG,MAkBlF,CAAC;AAGP,eAAO,MAAM,QAAQ,UAAW,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAG,UACgC,CAAC;AAkCpG,eAAO,MAAM,QAAQ,UAAW,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,KAAG,UAkBlE,CAAC;AAGF,eAAO,MAAM,SAAS,SAAU,MAAM,WAAW,UAAU,GAAG,MAAM,KAAG,UACmB,CAAC;AAG3F,eAAO,MAAM,QAAQ,QAAO,UACkH,CAAC"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"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"}
package/dist/testing.js CHANGED
@@ -217,4 +217,155 @@ export const tarBytes = (files) => {
217
217
  };
218
218
  export const gzipBytes = (name, content) => gzipSync(typeof content === "string" ? strToU8(content) : content, { filename: name });
219
219
  export const pngBytes = () => Uint8Array.from(Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", "base64"));
220
+ const EMU = 914_400;
221
+ const NS_P = 'xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"';
222
+ const REL_TYPE = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
223
+ const relsXml = (rels) => `<?xml version="1.0" encoding="UTF-8"?>
224
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">${Object.entries(rels)
225
+ .map(([id, rel]) => `<Relationship Id="${id}" Type="${REL_TYPE}/${rel.type}" Target="${xmlEscape(rel.target)}"${rel.external === true ? ' TargetMode="External"' : ""}/>`)
226
+ .join("")}</Relationships>`;
227
+ const xfrm = (frame, tag = "a:xfrm") => `<${tag}><a:off x="${Math.round(frame.x * EMU)}" y="${Math.round(frame.y * EMU)}"/><a:ext cx="${Math.round(frame.w * EMU)}" cy="${Math.round(frame.h * EMU)}"/></${tag}>`;
228
+ let drawingId = 10;
229
+ export const textBox = (name, frame, lines, options = {}) => {
230
+ drawingId += 1;
231
+ const ph = options.ph === undefined ? "" : `<p:ph${options.ph.type === undefined ? "" : ` type="${options.ph.type}"`}${options.ph.idx === undefined ? "" : ` idx="${options.ph.idx}"`}/>`;
232
+ const fit = options.autofit === "shrink" ? "<a:normAutofit/>" : options.autofit === "grow" ? "<a:spAutoFit/>" : "";
233
+ const size = options.size === undefined ? "" : ` sz="${options.size * 100}"`;
234
+ const paragraphs = lines.length === 0 ? "<a:p/>" : lines.map((line) => `<a:p><a:r><a:rPr lang="en-US"${size}/><a:t>${xmlEscape(line)}</a:t></a:r></a:p>`).join("");
235
+ return `<p:sp><p:nvSpPr><p:cNvPr id="${drawingId}" name="${xmlEscape(name)}"/><p:cNvSpPr/><p:nvPr>${ph}</p:nvPr></p:nvSpPr><p:spPr>${frame === undefined ? "" : xfrm(frame)}</p:spPr><p:txBody><a:bodyPr wrap="square">${fit}</a:bodyPr><a:lstStyle/>${paragraphs}</p:txBody></p:sp>`;
236
+ };
237
+ export const pictureFrame = (name, frame, rId, crop) => {
238
+ drawingId += 1;
239
+ const src = crop === undefined ? "" : `<a:srcRect l="${crop.l ?? 0}" r="${crop.r ?? 0}" t="${crop.t ?? 0}" b="${crop.b ?? 0}"/>`;
240
+ return `<p:pic><p:nvPicPr><p:cNvPr id="${drawingId}" name="${xmlEscape(name)}"/><p:cNvPicPr/><p:nvPr/></p:nvPicPr><p:blipFill><a:blip r:embed="${rId}"/>${src}<a:stretch><a:fillRect/></a:stretch></p:blipFill><p:spPr>${xfrm(frame)}<a:prstGeom prst="rect"><a:avLst/></a:prstGeom></p:spPr></p:pic>`;
241
+ };
242
+ export const tableFrame = (name, frame, rows, height, size = 18) => {
243
+ drawingId += 1;
244
+ const columns = Math.max(1, ...rows.map((row) => row.length));
245
+ const columnWidth = Math.round((frame.w * EMU) / columns);
246
+ const cells = (row) => row.map((cell) => `<a:tc><a:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:rPr lang="en-US" sz="${size * 100}"/><a:t>${xmlEscape(cell)}</a:t></a:r></a:p></a:txBody><a:tcPr/></a:tc>`).join("");
247
+ return `<p:graphicFrame><p:nvGraphicFramePr><p:cNvPr id="${drawingId}" name="${xmlEscape(name)}"/><p:cNvGraphicFramePr/><p:nvPr/></p:nvGraphicFramePr>${xfrm(frame, "p:xfrm")}<a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/table"><a:tbl><a:tblGrid>${Array.from({ length: columns }, () => `<a:gridCol w="${columnWidth}"/>`).join("")}</a:tblGrid>${rows.map((row) => `<a:tr h="${Math.round(height * EMU)}">${cells(row)}</a:tr>`).join("")}</a:tbl></a:graphicData></a:graphic></p:graphicFrame>`;
248
+ };
249
+ const MASTER = `<?xml version="1.0" encoding="UTF-8"?>
250
+ <p:sldMaster ${NS_P}><p:cSld><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr/>
251
+ <p:sp><p:nvSpPr><p:cNvPr id="2" name="Title Placeholder 1"/><p:cNvSpPr/><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr>${xfrm({ x: 0.92, y: 0.4, w: 11.5, h: 1.45 })}</p:spPr><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:t>Click to edit Master title style</a:t></a:r></a:p></p:txBody></p:sp>
252
+ <p:sp><p:nvSpPr><p:cNvPr id="3" name="Text Placeholder 2"/><p:cNvSpPr/><p:nvPr><p:ph type="body" idx="1"/></p:nvPr></p:nvSpPr><p:spPr>${xfrm({ x: 0.92, y: 2, w: 11.5, h: 4.75 })}</p:spPr><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:t>Click to edit Master text styles</a:t></a:r></a:p></p:txBody></p:sp>
253
+ </p:spTree></p:cSld><p:clrMap bg1="lt1" tx1="dk1" bg2="lt2" tx2="dk2" accent1="accent1" accent2="accent2" accent3="accent3" accent4="accent4" accent5="accent5" accent6="accent6" hlink="hlink" folHlink="folHlink"/><p:sldLayoutIdLst><p:sldLayoutId id="2147483649" r:id="rId1"/></p:sldLayoutIdLst>
254
+ <p:txStyles><p:titleStyle><a:lvl1pPr><a:defRPr sz="4400"/></a:lvl1pPr></p:titleStyle><p:bodyStyle><a:lvl1pPr><a:defRPr sz="2800"/></a:lvl1pPr><a:lvl2pPr><a:defRPr sz="2400"/></a:lvl2pPr></p:bodyStyle><p:otherStyle/></p:txStyles></p:sldMaster>`;
255
+ const LAYOUT = `<?xml version="1.0" encoding="UTF-8"?>
256
+ <p:sldLayout ${NS_P} type="obj"><p:cSld name="Title and Content"><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr/>
257
+ <p:sp><p:nvSpPr><p:cNvPr id="2" name="Title 1"/><p:cNvSpPr/><p:nvPr><p:ph type="title"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:t>Click to edit Master title style</a:t></a:r></a:p></p:txBody></p:sp>
258
+ <p:sp><p:nvSpPr><p:cNvPr id="3" name="Content Placeholder 2"/><p:cNvSpPr/><p:nvPr><p:ph idx="1"/></p:nvPr></p:nvSpPr><p:spPr/><p:txBody><a:bodyPr/><a:lstStyle/><a:p><a:r><a:t>Click to edit Master text styles</a:t></a:r></a:p></p:txBody></p:sp>
259
+ </p:spTree></p:cSld></p:sldLayout>`;
260
+ export const deckBytes = (options) => {
261
+ const width = Math.round((options.width ?? 13.333) * EMU);
262
+ const height = Math.round((options.height ?? 7.5) * EMU);
263
+ const numbers = options.slides.map((slide, index) => slide.partNumber ?? index + 1);
264
+ const types = [
265
+ '<Override PartName="/ppt/presentation.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.presentation.main+xml"/>',
266
+ '<Override PartName="/ppt/slideMasters/slideMaster1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideMaster+xml"/>',
267
+ '<Override PartName="/ppt/slideLayouts/slideLayout1.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slideLayout+xml"/>',
268
+ ...numbers.map((number) => `<Override PartName="/ppt/slides/slide${number}.xml" ContentType="application/vnd.openxmlformats-officedocument.presentationml.slide+xml"/>`),
269
+ options.untypedMedia === true ? "" : '<Default Extension="png" ContentType="image/png"/>',
270
+ ].join("");
271
+ const files = new Map([
272
+ ["[Content_Types].xml", strToU8(CONTENT_TYPES(types))],
273
+ ["_rels/.rels", strToU8(RELS("ppt/presentation.xml"))],
274
+ ["ppt/presentation.xml", strToU8(`<?xml version="1.0" encoding="UTF-8"?>
275
+ <p:presentation ${NS_P}><p:sldMasterIdLst><p:sldMasterId id="2147483648" r:id="rId1"/></p:sldMasterIdLst><p:sldIdLst>${numbers.map((number, index) => `<p:sldId id="${256 + index}" r:id="rId${number + 1}"/>`).join("")}</p:sldIdLst><p:sldSz cx="${width}" cy="${height}"/><p:notesSz cx="6858000" cy="9144000"/></p:presentation>`)],
276
+ ["ppt/_rels/presentation.xml.rels", strToU8(relsXml({
277
+ rId1: { type: "slideMaster", target: "slideMasters/slideMaster1.xml" },
278
+ ...Object.fromEntries(numbers.map((number) => [`rId${number + 1}`, { type: "slide", target: `slides/slide${number}.xml` }])),
279
+ }))],
280
+ ["ppt/slideMasters/slideMaster1.xml", strToU8(MASTER)],
281
+ ["ppt/slideMasters/_rels/slideMaster1.xml.rels", strToU8(relsXml({ rId1: { type: "slideLayout", target: "../slideLayouts/slideLayout1.xml" } }))],
282
+ ["ppt/slideLayouts/slideLayout1.xml", strToU8(LAYOUT)],
283
+ ["ppt/slideLayouts/_rels/slideLayout1.xml.rels", strToU8(relsXml({ rId1: { type: "slideMaster", target: "../slideMasters/slideMaster1.xml" } }))],
284
+ ]);
285
+ options.slides.forEach((slide, index) => {
286
+ const number = numbers[index] ?? index + 1;
287
+ files.set(`ppt/slides/slide${number}.xml`, strToU8(`<?xml version="1.0" encoding="UTF-8"?>
288
+ <p:sld ${NS_P}${slide.hidden === true ? ' show="0"' : ""}><p:cSld><p:spTree><p:nvGrpSpPr><p:cNvPr id="1" name=""/><p:cNvGrpSpPr/><p:nvPr/></p:nvGrpSpPr><p:grpSpPr/>${slide.drawings.join("")}</p:spTree></p:cSld></p:sld>`));
289
+ files.set(`ppt/slides/_rels/slide${number}.xml.rels`, strToU8(relsXml({ rId1: { type: "slideLayout", target: "../slideLayouts/slideLayout1.xml" }, ...slide.rels })));
290
+ });
291
+ for (const [name, bytes] of Object.entries(options.media ?? {})) {
292
+ files.set(`ppt/media/${name}`, bytes);
293
+ }
294
+ return zipSync(Object.fromEntries(files));
295
+ };
296
+ export const pngOfSize = (width, height) => {
297
+ const png = pngBytes().slice();
298
+ const view = new DataView(png.buffer, png.byteOffset, png.byteLength);
299
+ view.setUint32(16, width);
300
+ view.setUint32(20, height);
301
+ return png;
302
+ };
303
+ const NS_W = 'xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"';
304
+ export const para = (text, style) => `<w:p>${style === undefined ? "" : `<w:pPr><w:pStyle w:val="${style}"/></w:pPr>`}${text === "" ? "" : `<w:r><w:t xml:space="preserve">${xmlEscape(text)}</w:t></w:r>`}</w:p>`;
305
+ export const inlinePicture = (rId, width, height) => `<w:p><w:r><w:drawing><wp:inline><wp:extent cx="${Math.round(width * EMU)}" cy="${Math.round(height * EMU)}"/><wp:docPr id="1" name="Picture 1"/><a:graphic><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic><pic:blipFill><a:blip r:embed="${rId}"/></pic:blipFill></pic:pic></a:graphicData></a:graphic></wp:inline></w:drawing></w:r></w:p>`;
306
+ export const field = (instruction, result) => `<w:p><w:r><w:fldChar w:fldCharType="begin"/></w:r><w:r><w:instrText xml:space="preserve"> ${xmlEscape(instruction)} </w:instrText></w:r>${result === undefined ? "" : `<w:r><w:fldChar w:fldCharType="separate"/></w:r><w:r><w:t>${xmlEscape(result)}</w:t></w:r>`}<w:r><w:fldChar w:fldCharType="end"/></w:r></w:p>`;
307
+ const STYLES = `<?xml version="1.0" encoding="UTF-8"?>
308
+ <w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:style w:type="paragraph" w:default="1" w:styleId="Normal"><w:name w:val="Normal"/></w:style><w:style w:type="paragraph" w:styleId="berschrift1"><w:name w:val="heading 1"/><w:basedOn w:val="Normal"/></w:style><w:style w:type="paragraph" w:styleId="berschrift2"><w:name w:val="heading 2"/><w:basedOn w:val="Normal"/></w:style><w:style w:type="paragraph" w:styleId="Callout"><w:name w:val="Callout"/><w:basedOn w:val="berschrift2"/></w:style></w:styles>`;
309
+ export const wordBytes = (options) => {
310
+ const commentRels = options.comments === undefined ? {} : { rIdComments: { type: "comments", target: "comments.xml" } };
311
+ const files = new Map([
312
+ ["[Content_Types].xml", strToU8(CONTENT_TYPES([
313
+ '<Default Extension="png" ContentType="image/png"/>',
314
+ '<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>',
315
+ '<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>',
316
+ options.comments === undefined ? "" : '<Override PartName="/word/comments.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml"/>',
317
+ ].join("")))],
318
+ ["_rels/.rels", strToU8(RELS("word/document.xml"))],
319
+ ["word/styles.xml", strToU8(STYLES)],
320
+ ["word/document.xml", strToU8(`<?xml version="1.0" encoding="UTF-8"?>
321
+ <w:document ${NS_W}><w:body>${options.body.join("")}<w:sectPr><w:pgSz w:w="12240" w:h="15840"/><w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:gutter="0"/></w:sectPr></w:body></w:document>`)],
322
+ ]);
323
+ if (options.comments !== undefined) {
324
+ files.set("word/comments.xml", strToU8(`<?xml version="1.0" encoding="UTF-8"?>
325
+ <w:comments xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">${options.comments.map((text, index) => `<w:comment w:id="${index}" w:author="Reviewer"><w:p><w:r><w:t>${xmlEscape(text)}</w:t></w:r></w:p></w:comment>`).join("")}</w:comments>`));
326
+ }
327
+ files.set("word/_rels/document.xml.rels", strToU8(relsXml({ rIdStyles: { type: "styles", target: "styles.xml" }, ...options.rels, ...commentRels })));
328
+ for (const [name, bytes] of Object.entries(options.media ?? {})) {
329
+ files.set(`word/media/${name}`, bytes);
330
+ }
331
+ return zipSync(Object.fromEntries(files));
332
+ };
333
+ export const workbookBytes = (sheets, options = {}) => {
334
+ const files = new Map([
335
+ ["[Content_Types].xml", strToU8(CONTENT_TYPES([
336
+ '<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>',
337
+ ...sheets.map((_, index) => `<Override PartName="/xl/worksheets/sheet${index + 1}.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>`),
338
+ ].join("")))],
339
+ ["_rels/.rels", strToU8(RELS("xl/workbook.xml"))],
340
+ ["xl/workbook.xml", strToU8(`<?xml version="1.0" encoding="UTF-8"?>
341
+ <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets>${sheets.map((sheet, index) => `<sheet name="${xmlEscape(sheet.name)}" sheetId="${index + 1}" r:id="rId${index + 1}"/>`).join("")}</sheets>${options.definedNames === undefined ? "" : `<definedNames>${options.definedNames}</definedNames>`}${options.calcPr ?? ""}</workbook>`)],
342
+ ["xl/_rels/workbook.xml.rels", strToU8(relsXml(Object.fromEntries(sheets.map((_, index) => [`rId${index + 1}`, { type: "worksheet", target: `worksheets/sheet${index + 1}.xml` }]))))],
343
+ ]);
344
+ sheets.forEach((sheet, index) => {
345
+ files.set(`xl/worksheets/sheet${index + 1}.xml`, strToU8(`<?xml version="1.0" encoding="UTF-8"?>
346
+ <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData>${sheet.rows}</sheetData></worksheet>`));
347
+ });
348
+ return zipSync(Object.fromEntries(files));
349
+ };
350
+ export const pdfPagesBytes = (pages) => {
351
+ const objects = ["", ""];
352
+ const add = (body) => objects.push(body);
353
+ const kids = pages.map((page) => {
354
+ const font = add(`<< /Type /Font /Subtype /${page.font === undefined ? "Type1" : "TrueType"} /BaseFont /${page.font ?? "Helvetica"} >>`);
355
+ const content = add(`<< /Length ${page.content.length} >>\nstream\n${page.content}\nendstream`);
356
+ const [width, height] = page.size ?? [612, 792];
357
+ return add(`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${width} ${height}] /Contents ${content} 0 R /Resources << /Font << /F1 ${font} 0 R >> >> ${page.extra ?? ""} >>`);
358
+ });
359
+ objects[0] = "<< /Type /Catalog /Pages 2 0 R >>";
360
+ objects[1] = `<< /Type /Pages /Kids [${kids.map((kid) => `${kid} 0 R`).join(" ")}] /Count ${kids.length} >>`;
361
+ let out = "%PDF-1.4\n";
362
+ const offsets = objects.map((body, index) => {
363
+ const offset = out.length;
364
+ out += `${index + 1} 0 obj\n${body}\nendobj\n`;
365
+ return offset;
366
+ });
367
+ const xref = out.length;
368
+ out += `xref\n0 ${objects.length + 1}\n0000000000 65535 f \n${offsets.map((offset) => `${String(offset).padStart(10, "0")} 00000 n `).join("\n")}\ntrailer\n<< /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xref}\n%%EOF\n`;
369
+ return strToU8(out);
370
+ };
220
371
  //# sourceMappingURL=testing.js.map