One day I'll figure this shit out

This commit is contained in:
Emmaline Autumn 2025-05-28 09:09:41 -06:00
parent 0f9c377853
commit 65743d8562
6 changed files with 512 additions and 139 deletions

View File

@ -1,5 +1,4 @@
import { Cursor } from "./cursor.ts"; import { Cursor } from "./cursor.ts";
import { InputManager } from "./InputManager.ts";
export class TerminalLayout { export class TerminalLayout {
private static ALT_BUFFER_ENABLE = "\x1b[?1049h"; private static ALT_BUFFER_ENABLE = "\x1b[?1049h";

View File

@ -1,5 +1,6 @@
import type { callback } from "../types.ts"; import type { callback } from "../types.ts";
import { type CLICharEvent, InputManager } from "./InputManager.ts"; import { type CLICharEvent, InputManager } from "./InputManager.ts";
import { cliLog } from "./prompts.ts";
import { colorize } from "./style.ts"; import { colorize } from "./style.ts";
import { TerminalBlock, TerminalLayout } from "./TerminalLayout.ts"; import { TerminalBlock, TerminalLayout } from "./TerminalLayout.ts";
@ -299,7 +300,7 @@ if (import.meta.main) {
"yuzu", "yuzu",
"zucchini", "zucchini",
], { terminalBlock: block }); ], { terminalBlock: block });
// console.log(val); cliLog(val || "No value");
// Deno.stdout.writeSync(new TextEncoder().encode("\x07")); // Deno.stdout.writeSync(new TextEncoder().encode("\x07"));
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@bearmetal/pdf-tools", "name": "@bearmetal/pdf-tools",
"version": "1.0.8-h", "version": "1.0.8-l",
"license": "GPL 3.0", "license": "GPL 3.0",
"tasks": { "tasks": {
"dev": "deno run -A --env-file=.env main.ts", "dev": "deno run -A --env-file=.env main.ts",

Binary file not shown.

View File

@ -1,13 +1,18 @@
import { import {
type PDFAcroField, PDFAcroField,
PDFAcroTerminal,
PDFArray, PDFArray,
PDFCheckBox, PDFCheckBox,
PDFContext,
PDFDict,
type PDFDocument, type PDFDocument,
type PDFField, type PDFField,
PDFHexString,
PDFName, PDFName,
PDFNumber, PDFNumber,
type PDFObject,
PDFRadioGroup, PDFRadioGroup,
type PDFRef, PDFRef,
PDFString, PDFString,
PDFTextField, PDFTextField,
type PDFWidgetAnnotation, type PDFWidgetAnnotation,
@ -20,63 +25,458 @@ import { cliAlert, cliLog, cliPrompt } from "../cli/prompts.ts";
import { multiSelectMenuInteractive } from "../cli/selectMenu.ts"; import { multiSelectMenuInteractive } from "../cli/selectMenu.ts";
import type { callback, ITool } from "../types.ts"; import type { callback, ITool } from "../types.ts";
import { toCase } from "util/caseManagement.ts"; import { toCase } from "util/caseManagement.ts";
import { log } from "util/logfile.ts";
function applyRename( function removeWidgetFromOldField(
doc: PDFDocument,
field: PDFField, field: PDFField,
name: string, widget: PDFWidgetAnnotation,
pattern: RegExp,
change: string,
) { ) {
const segments = name.split("."); const maybeKids = field.acroField.dict.get(PDFName.of("Kids"));
const matchingSegments = segments.filter((s) => pattern.test(s)); if (!maybeKids || !(maybeKids instanceof PDFArray)) return;
let cField: PDFAcroField | undefined = field.acroField; const kids = maybeKids;
while (cField) { if (!kids) return;
if (
cField.getPartialName() && const widgetRef = getWidgetRef(widget, doc);
matchingSegments.includes(cField.getPartialName()!) if (!widgetRef) return;
) {
const mName = cField.getPartialName()?.replace(pattern, change); const updatedKids = kids.asArray().filter((ref) => {
if (mName) { const dict = doc.context.lookup(ref);
cField.dict.set(PDFName.of("T"), PDFString.of(mName)); return dict !== widget.dict;
// console.log(cField.getPartialName()) });
}
} if (updatedKids.length === 0) {
cField = cField.getParent(); // Field is now empty, remove it from the AcroForm
// console.log(cField?.getPartialName()) const acroForm = doc.catalog.lookup(PDFName.of("AcroForm"), PDFDict);
const fields = acroForm.lookup(PDFName.of("Fields"), PDFArray);
const fieldRef = field.acroField.ref;
const newFields = fields.asArray().filter((ref) => ref !== fieldRef);
acroForm.set(PDFName.of("Fields"), doc.context.obj(newFields));
} else {
field.acroField.dict.set(PDFName.of("Kids"), doc.context.obj(updatedKids));
} }
} }
// function applyWidgetRename( function moveWidgetToFlatField(
// doc: PDFDocument, doc: PDFDocument,
// field: PDFField, field: PDFField,
// widget: PDFWidgetAnnotation, widget: PDFWidgetAnnotation,
// name: string, newName: string,
// pattern: RegExp, ) {
// change: string, const form = doc.getForm();
// ) { const page = findPageForWidget(doc, widget);
// if (field.acroField.getWidgets().length > 1) { if (!page) throw new Error("Widget's page not found");
// const widgets = field.acroField.getWidgets();
// const widgetIndex = widgets.indexOf(widget);
// widgets.splice(widgetIndex, 1);
// const pdfDocContext = doc.context; const rect = widget.getRectangle();
if (!rect) throw new Error("Widget has no rectangle");
// const originalRef = field.acroField.ref; const fieldType = detectFieldType(field);
// const originalFieldDict = pdfDocContext.lookup(originalRef); const widgetRef = getWidgetRef(widget, doc);
// if (!originalFieldDict) return; if (!widgetRef) throw new Error("Widget ref not found");
// const newFieldDict = pdfDocContext.obj({ // 🔒 Extract value + style before any destructive ops
// ...originalFieldDict, let value: string | undefined;
// T: PDFString.of(name.replace(pattern, change)), try {
// Kids: [getWidgetRef(widget, doc.getPages())], if (fieldType === "/Tx" && field instanceof PDFTextField) {
// }); value = field.getText();
// const newField = pdfDocContext.register(newFieldDict); }
} catch (_) {
log("Failed to extract value from field");
}
const sourceFieldDict = field.acroField.dict;
const sourceWidgetDict = widget.dict;
// 🔥 Remove widget from page + field
removeWidgetFromPage(widget, doc);
removeWidgetCompletely(doc, widget, field);
// 🔥 Carefully remove field + parents
try {
fullyDeleteFieldHierarchy(doc, field);
} catch (_) {
// fallback
log("Failed to remove field hierarchy");
removeFieldIfEmpty(doc, field);
}
sanitizeFieldsTree(doc);
removeDanglingParents(doc);
removeEmptyAncestors(doc, field);
// 🔁 Create replacement field
let newField: PDFField;
switch (fieldType) {
case "/Tx": {
const tf = form.createTextField(newName);
if (value) tf.setText(value);
tf.addToPage(page, rect);
newField = tf;
break;
}
case "/Btn": {
const isRadio = getFlag(field, 15);
if (isRadio) {
const rg = form.createRadioGroup(newName);
rg.addOptionToPage(newName, page, rect);
return;
} else {
const cb = form.createCheckBox(newName);
cb.addToPage(page, rect);
if (field instanceof PDFCheckBox && field.isChecked()) {
cb.check();
}
return;
}
}
case "/Ch": {
const ff = sourceFieldDict.get(PDFName.of("Ff"));
const isCombo = ff instanceof PDFNumber &&
((ff.asNumber() & (1 << 17)) !== 0);
const opts = sourceFieldDict.lookupMaybe(PDFName.of("Opt"), PDFArray);
const values =
opts?.asArray().map((opt) =>
opt instanceof PDFString || opt instanceof PDFHexString
? opt.decodeText()
: ""
) ?? [];
if (isCombo) {
const dd = form.createDropdown(newName);
dd.addOptions(values);
dd.addToPage(page, rect);
newField = dd;
} else {
const ol = form.createOptionList(newName);
ol.addOptions(values);
ol.addToPage(page, rect);
newField = ol;
}
break;
}
default:
throw new Error(`Unsupported field type: ${fieldType}`);
}
// 🔧 Apply styles *after creation*
const targetWidgetDict = newField.acroField.getWidgets()[0].dict;
copyFieldAndWidgetStyles(
sourceFieldDict,
sourceWidgetDict,
newField.acroField.dict,
targetWidgetDict,
);
}
function removeDanglingParents(doc: PDFDocument) {
const context = doc.context;
const acroForm = doc.catalog.lookup(PDFName.of("AcroForm"), PDFDict);
const fields = acroForm.lookupMaybe(PDFName.of("Fields"), PDFArray);
if (!(fields instanceof PDFArray)) return;
function fixFieldDict(dict: PDFDict) {
const parentRef = dict.get(PDFName.of("Parent"));
if (!parentRef || !(parentRef instanceof PDFRef)) return;
try {
const parentDict = context.lookup(parentRef, PDFDict);
if (!parentDict) throw new Error("Missing parent");
} catch {
// Parent is broken — remove reference
dict.delete(PDFName.of("Parent"));
log("Broken parent reference removed");
}
}
const visited = new Set<string>();
function recurseKids(dict: PDFDict) {
const kids = dict.lookupMaybe(PDFName.of("Kids"), PDFArray);
if (!(kids instanceof PDFArray)) return;
for (const kidRef of kids.asArray()) {
if (!(kidRef instanceof PDFRef)) continue;
const key = kidRef.toString();
if (visited.has(key)) continue;
visited.add(key);
try {
const kidDict = context.lookup(kidRef, PDFDict);
fixFieldDict(kidDict);
recurseKids(kidDict);
} catch (e) {
context.delete(kidRef); // nuke broken reference
log("Broken kid reference removed");
log(e);
}
}
}
for (const ref of fields.asArray()) {
if (!(ref instanceof PDFRef)) continue;
try {
const dict = context.lookup(ref, PDFDict);
fixFieldDict(dict);
recurseKids(dict);
} catch {
context.delete(ref); // broken root
log("Broken root reference removed");
}
}
}
function removeFieldByName(doc: PDFDocument, fieldName: string) {
const form = doc.getForm();
const acroForm = doc.catalog.lookup(PDFName.of("AcroForm"), PDFDict);
const fields = acroForm.lookup(PDFName.of("Fields"), PDFArray);
const context = doc.context;
const remainingFields = fields.asArray().filter((ref) => {
const dict = context.lookup(ref, PDFDict);
const name = dict?.get(PDFName.of("T"));
if (name && (name.decodeText?.() === fieldName)) {
context.delete(ref as PDFRef);
return false;
}
return true;
});
acroForm.set(PDFName.of("Fields"), context.obj(remainingFields));
}
function sanitizeFieldsTree(doc: PDFDocument) {
const context = doc.context;
const acroForm = doc.catalog.lookup(PDFName.of("AcroForm"), PDFDict);
const fields = acroForm.lookupMaybe(PDFName.of("Fields"), PDFArray);
if (!(fields instanceof PDFArray)) return;
function pruneInvalidKids(dict: PDFDict, context: PDFContext) {
const kids = dict.lookupMaybe(PDFName.of("Kids"), PDFArray);
if (!(kids instanceof PDFArray)) return;
const validKids: PDFRef[] = [];
for (const ref of kids.asArray()) {
// 💥 Defensive: skip anything that's not a real PDFRef
if (!ref || !(ref instanceof PDFRef)) continue;
let child: PDFDict | undefined;
try {
child = context.lookup(ref, PDFDict);
} catch (e) {
context.delete(ref);
log("Broken kid reference removed");
log(e);
continue;
}
if (!child) {
context.delete(ref);
continue;
}
const t = child.get(PDFName.of("T"));
if (!(t instanceof PDFString || t instanceof PDFHexString)) {
context.delete(ref);
continue;
}
// Recurse, but protect inner layers too
pruneInvalidKids(child, context);
validKids.push(ref);
}
if (validKids.length > 0) {
dict.set(PDFName.of("Kids"), context.obj(validKids));
} else {
dict.delete(PDFName.of("Kids"));
}
}
const validFields: PDFRef[] = [];
for (const ref of fields.asArray()) {
if (!ref || !(ref instanceof PDFRef)) continue;
let dict: PDFDict | undefined;
try {
dict = context.lookup(ref, PDFDict);
} catch {
context.delete(ref);
log("Broken field reference removed");
continue;
}
if (!dict) {
context.delete(ref);
continue;
}
const t = dict.get(PDFName.of("T"));
if (!(t instanceof PDFString || t instanceof PDFHexString)) {
context.delete(ref);
continue;
}
pruneInvalidKids(dict, context);
validFields.push(ref);
}
acroForm.set(PDFName.of("Fields"), context.obj(validFields));
}
function fullyDeleteFieldHierarchy(doc: PDFDocument, rootField: PDFField) {
const context = doc.context;
const acroForm = doc.catalog.lookup(PDFName.of("AcroForm"), PDFDict);
const fields = acroForm.lookup(PDFName.of("Fields"), PDFArray);
function recurseDelete(dict: PDFDict, ref: PDFRef) {
const kids = dict.lookupMaybe(PDFName.of("Kids"), PDFArray);
if (kids instanceof PDFArray) {
for (const kidRef of kids.asArray()) {
const kidDict = context.lookup(kidRef, PDFDict);
if (kidDict) {
recurseDelete(kidDict, kidRef as PDFRef);
}
}
}
context.delete(ref);
}
recurseDelete(rootField.acroField.dict, rootField.acroField.ref);
// Remove root from AcroForm.Fields
const newFields = fields
.asArray()
.filter((ref) => ref !== rootField.acroField.ref);
acroForm.set(PDFName.of("Fields"), context.obj(newFields));
}
function removeEmptyAncestors(doc: PDFDocument, field: PDFField) {
let current: PDFAcroField | undefined = field.acroField;
const context = doc.context;
while (current) {
const parent = current.getParent();
const kids = parent?.dict.lookupMaybe(PDFName.of("Kids"), PDFArray);
if (kids instanceof PDFArray) {
const remaining = kids.asArray().filter((ref) => {
try {
const kidDict = context.lookup(ref, PDFDict);
return kidDict !== current?.dict;
} catch (e) {
log("Broken kid reference removed");
log(e);
return false;
}
});
if (remaining.length > 0) {
parent.dict.set(PDFName.of("Kids"), context.obj(remaining));
break;
} else {
parent.dict.delete(PDFName.of("Kids"));
}
}
context.delete(current.ref);
current = parent;
}
}
function removeWidgetCompletely(
doc: PDFDocument,
widget: PDFWidgetAnnotation,
field: PDFField,
) {
const widgetRef = getWidgetRef(widget, doc);
if (!widgetRef) return;
// 1. Remove from field's /Kids array
const kidsRaw = field.acroField.dict.get(PDFName.of("Kids"));
if (kidsRaw instanceof PDFArray) {
const updatedKids = kidsRaw.asArray().filter((ref) => {
const dict = doc.context.lookup(ref);
return dict !== widget.dict;
});
if (updatedKids.length > 0) {
field.acroField.dict.set(
PDFName.of("Kids"),
doc.context.obj(updatedKids),
);
} else {
field.acroField.dict.delete(PDFName.of("Kids"));
}
}
// 2. Remove from page /Annots
for (const page of doc.getPages()) {
const annotsRaw = page.node.Annots()?.asArray();
if (!annotsRaw) continue;
const remainingAnnots = annotsRaw.filter((ref) => {
const dict = doc.context.lookup(ref);
return dict !== widget.dict;
});
page.node.set(PDFName.of("Annots"), doc.context.obj(remainingAnnots));
}
// Optional: delete the widget from the context
doc.context.delete(widgetRef);
}
function removeFieldIfEmpty(doc: PDFDocument, field: PDFField) {
const kids = field.acroField.getWidgets();
if (kids.length > 0) return;
const acroForm = doc.catalog.lookup(PDFName.of("AcroForm"), PDFDict);
const fieldsArray = acroForm.lookup(PDFName.of("Fields"), PDFArray);
const ref = field.acroField.ref;
const updatedFields = fieldsArray.asArray().filter((f) => f !== ref);
acroForm.set(PDFName.of("Fields"), doc.context.obj(updatedFields));
// Optional: remove field object entirely
doc.context.delete(ref);
}
function copyFieldAndWidgetStyles(
sourceFieldDict: PDFDict,
sourceWidgetDict: PDFDict,
targetFieldDict: PDFDict,
targetWidgetDict: PDFDict,
) {
const fieldKeys = ["DA", "DR", "Q"];
const widgetKeys = ["MK", "BS", "Border"];
// Copy from field dict → field dict
for (const key of fieldKeys) {
const val = sourceFieldDict.get(PDFName.of(key));
if (val) {
targetFieldDict.set(PDFName.of(key), val);
}
}
// Copy from widget dict → widget dict
for (const key of widgetKeys) {
const val = sourceWidgetDict.get(PDFName.of(key));
if (val) {
targetWidgetDict.set(PDFName.of(key), val);
}
}
}
// const acroForm = doc.catalog.lookup(PDFName.of("AcroForm"), PDFDict);
// const fields = acroForm.lookup(PDFName.of("Fields"), PDFArray);
// fields.push(newField);
// }
// }
function findPageForWidget( function findPageForWidget(
doc: PDFDocument, doc: PDFDocument,
widget: PDFWidgetAnnotation, widget: PDFWidgetAnnotation,
@ -134,19 +534,22 @@ function applyWidgetRename(
try { try {
const form = doc.getForm(); const form = doc.getForm();
const widgets = field.acroField.getWidgets(); const widgets = field.acroField.getWidgets();
if (widgets.length <= 1) return;
const widgetDict = widget.dict; const widgetDict = widget.dict;
const widgetIndex = widgets.findIndex((w) => w.dict === widgetDict); const widgetIndex = widgets.findIndex((w) => w.dict === widgetDict);
if (widgetIndex === -1) return; if (widgetIndex === -1) return;
const widgetRef = getWidgetRef(widget, doc);
if (!widgetRef) return;
// Remove widget from internal widgets list
widgets.splice(widgetIndex, 1); widgets.splice(widgetIndex, 1);
const kids = field.acroField.dict.lookup(PDFName.of("Kids"), PDFArray); // Remove from /Kids
if (kids) { const maybeKids = field.acroField.dict.get(PDFName.of("Kids"));
const updatedKids = kids.asArray().filter((ref) => { if (maybeKids instanceof PDFArray) {
const updatedKids = maybeKids.asArray().filter((ref) => {
const maybeDict = doc.context.lookup(ref); const maybeDict = doc.context.lookup(ref);
return maybeDict !== widget.dict; return maybeDict !== widgetDict;
}); });
field.acroField.dict.set( field.acroField.dict.set(
PDFName.of("Kids"), PDFName.of("Kids"),
@ -155,48 +558,41 @@ function applyWidgetRename(
} }
const page = findPageForWidget(doc, widget); const page = findPageForWidget(doc, widget);
if (!page) throw new Error("Widget page not found"); if (!page) throw new Error("Widget's page not found");
const rect = widget.getRectangle(); const rect = widget.getRectangle();
if (!rect) throw new Error("Widget has no rectangle"); if (!rect) throw new Error("Widget has no rectangle");
const finalName = newName.replace(pattern, change); const finalName = newName.replace(pattern, change);
const fieldType = detectFieldType(field);
// Try to get existing field with the new name // Attempt to find an existing field with the new name
let targetField: PDFField | undefined; let targetField: PDFField | undefined;
try { try {
targetField = form.getField(finalName); targetField = form.getField(finalName);
} catch { } catch {
// Field doesn't exist — that's fine //
log("Failed to find existing field");
} }
// Compare field types if field exists
if (targetField) { if (targetField) {
const sourceType = detectFieldType(field); const sourceType = detectFieldType(field);
const targetType = detectFieldType(targetField); const targetType = detectFieldType(targetField);
if (sourceType !== targetType) { if (sourceType !== targetType) {
throw new Error( throw new Error(
`Field "${finalName}" already exists with a different type (${targetType} vs ${sourceType})`, `Field "${finalName}" already exists with a different type (${targetType} vs ${sourceType})`,
); );
} }
// ✅ Same type — attach widget to the existing field // Add widget to existing field
// const targetFieldWidgets = targetField.acroField.getWidgets(); widget.dict.set(PDFName.of("Parent"), targetField.acroField.ref);
const targetKidsArray = targetField.acroField.dict.lookup(
const kids = targetField.acroField.dict.lookup(
PDFName.of("Kids"), PDFName.of("Kids"),
PDFArray, PDFArray,
); );
if (kids) {
// Set /Parent on the widget to point to the existing field kids.push(widgetRef);
widget.dict.set(PDFName.of("Parent"), targetField.acroField.ref);
// Add the widget to the field's /Kids array
const widgetRef = getWidgetRef(widget, doc);
if (!widgetRef) throw new Error("Widget ref not found");
if (targetKidsArray) {
targetKidsArray.push(widgetRef);
} else { } else {
targetField.acroField.dict.set( targetField.acroField.dict.set(
PDFName.of("Kids"), PDFName.of("Kids"),
@ -204,22 +600,23 @@ function applyWidgetRename(
); );
} }
// Also ensure widget is attached to a page const annots = page.node.Annots()?.asArray() ?? [];
const page = findPageForWidget(doc, widget); if (!annots.includes(widgetRef)) {
if (!page) throw new Error("Widget's page not found"); annots.push(widgetRef);
page.node.set(PDFName.of("Annots"), doc.context.obj(annots));
const pageAnnots = page.node.Annots();
const refs = pageAnnots?.asArray() ?? [];
if (!refs.includes(widgetRef)) {
refs.push(widgetRef);
page.node.set(PDFName.of("Annots"), doc.context.obj(refs));
} }
return; // Done
}
removeWidgetFromPage(widget, doc); removeWidgetFromPage(widget, doc);
removeWidgetCompletely(doc, widget, field);
removeFieldIfEmpty(doc, field);
const fieldType = detectFieldType(field); return;
}
// No existing field — create new one and move widget
removeWidgetFromPage(widget, doc);
removeWidgetCompletely(doc, widget, field);
removeFieldIfEmpty(doc, field);
let newField: PDFField; let newField: PDFField;
@ -230,6 +627,12 @@ function applyWidgetRename(
const val = field.getText(); const val = field.getText();
if (val) tf.setText(val); if (val) tf.setText(val);
} }
tf.addToPage(page, {
x: rect.x,
y: rect.y,
width: rect.width,
height: rect.height,
});
newField = tf; newField = tf;
break; break;
} }
@ -237,8 +640,8 @@ function applyWidgetRename(
case "/Btn": { case "/Btn": {
const isRadio = getFlag(field, 15); const isRadio = getFlag(field, 15);
if (isRadio) { if (isRadio) {
const rf = form.createRadioGroup(finalName); const radio = form.createRadioGroup(finalName);
rf.addOptionToPage(finalName, page, { radio.addOptionToPage(finalName, page, {
x: rect.x, x: rect.x,
y: rect.y, y: rect.y,
width: rect.width, width: rect.width,
@ -246,7 +649,7 @@ function applyWidgetRename(
}); });
if (field instanceof PDFRadioGroup) { if (field instanceof PDFRadioGroup) {
const selected = field.getSelected(); const selected = field.getSelected();
if (selected) rf.select(selected); if (selected) radio.select(selected);
} }
return; return;
} else { } else {
@ -268,20 +671,15 @@ function applyWidgetRename(
throw new Error(`Unsupported field type: ${fieldType}`); throw new Error(`Unsupported field type: ${fieldType}`);
} }
// Attach the new field to the page if necessary // Apply styles from old field/widget after creation
if ( copyFieldAndWidgetStyles(
newField instanceof PDFTextField || field.acroField.dict,
newField instanceof PDFCheckBox widget.dict,
) { newField.acroField.dict,
newField.addToPage(page, { newField.acroField.getWidgets()[0].dict,
x: rect.x, );
y: rect.y, } catch (e) {
width: rect.width, log("applyWidgetRename error:", e);
height: rect.height,
});
}
} catch {
// log(e);
} }
} }
@ -304,36 +702,6 @@ function removeWidgetFromPage(widget: PDFWidgetAnnotation, doc: PDFDocument) {
} }
} }
// function getWidgetRef(
// widget: PDFWidgetAnnotation,
// pages: PDFPage[],
// ): PDFRef | undefined {
// const widgetRect = (widget?.dict?.get(PDFName.of("Rect")) as PDFArray)
// ?.asArray();
// const widgetFT = (widget?.dict?.get(PDFName.of("FT")) as PDFString)
// ?.["value"];
// for (const page of pages) {
// const annotsArray = page.node.Annots()?.asArray();
// if (!annotsArray) continue;
// for (const annotRef of annotsArray) {
// const annotDict = page.doc.context.lookup(annotRef);
// if (!annotDict) continue;
// if (!(annotDict instanceof PDFDict)) continue;
// const rect = (annotDict.get(PDFName.of("Rect")) as PDFArray)?.asArray();
// const ft = (annotDict.get(PDFName.of("FT")) as PDFString)?.["value"];
// // rudimentary match (you can add more checks like /T, /Subtype, etc.)
// if (rect?.toString() === widgetRect?.toString() && ft === widgetFT) {
// return annotRef as PDFRef;
// }
// }
// }
// return undefined;
// }
/*** /***
* Evaluates the change string with the match array * Evaluates the change string with the match array
* *
@ -501,7 +869,12 @@ class RenameFields implements ITool {
new RegExp(patternRegex), new RegExp(patternRegex),
toChange, toChange,
) )
: applyRename(field, name, patternRegex, toChange); : moveWidgetToFlatField(
pdf,
field,
field.acroField.getWidgets()[0],
preview,
);
changesMade = true; changesMade = true;
}, },
]; ];
@ -527,7 +900,7 @@ class RenameFields implements ITool {
try { try {
await savePdf(pdf, path || pdfPath); await savePdf(pdf, path || pdfPath);
} catch { } catch {
// log(e); log(e);
} }
} else { } else {
cliLog("No changes made, skipping", this.block); cliLog("No changes made, skipping", this.block);

View File

@ -7,7 +7,7 @@ const logFile = Deno.openSync("./log.txt", {
logFile.truncateSync(0); logFile.truncateSync(0);
export function log(message: any) { export function log(...message: any) {
if (typeof message === "object") { if (typeof message === "object") {
message = Deno.inspect(message); message = Deno.inspect(message);
} }