UNPKG

@cantoo/pdf-lib

Version:

Create and modify PDF files with JavaScript

731 lines 30.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const PDFDocument_1 = tslib_1.__importDefault(require("../PDFDocument")); const PDFButton_1 = tslib_1.__importDefault(require("./PDFButton")); const PDFCheckBox_1 = tslib_1.__importDefault(require("./PDFCheckBox")); const PDFDropdown_1 = tslib_1.__importDefault(require("./PDFDropdown")); const PDFOptionList_1 = tslib_1.__importDefault(require("./PDFOptionList")); const PDFRadioGroup_1 = tslib_1.__importDefault(require("./PDFRadioGroup")); const PDFSignature_1 = tslib_1.__importDefault(require("./PDFSignature")); const PDFTextField_1 = tslib_1.__importDefault(require("./PDFTextField")); const errors_1 = require("../errors"); const PDFFont_1 = tslib_1.__importDefault(require("../PDFFont")); const StandardFonts_1 = require("../StandardFonts"); const operations_1 = require("../operations"); const operators_1 = require("../operators"); const core_1 = require("../../core"); const utils_1 = require("../../utils"); /** * Represents the interactive form of a [[PDFDocument]]. * * Interactive forms (sometimes called _AcroForms_) are collections of fields * designed to gather information from a user. A PDF document may contains any * number of fields that appear on various pages, all of which make up a single, * global interactive form spanning the entire document. This means that * instances of [[PDFDocument]] shall contain at most one [[PDFForm]]. * * The fields of an interactive form are represented by [[PDFField]] instances. */ class PDFForm { constructor(acroForm, doc) { this.embedDefaultFont = () => this.doc.embedStandardFont(StandardFonts_1.StandardFonts.Helvetica); (0, utils_1.assertIs)(acroForm, 'acroForm', [[core_1.PDFAcroForm, 'PDFAcroForm']]); (0, utils_1.assertIs)(doc, 'doc', [[PDFDocument_1.default, 'PDFDocument']]); this.acroForm = acroForm; this.doc = doc; this.dirtyFields = new Set(); this.defaultFontCache = utils_1.Cache.populatedBy(this.embedDefaultFont); } /** * Returns `true` if this [[PDFForm]] has XFA data. Most PDFs with form * fields do not use XFA as it is not widely supported by PDF readers. * * > `pdf-lib` does not support creation, modification, or reading of XFA * > fields. * * For example: * ```js * const form = pdfDoc.getForm() * if (form.hasXFA()) console.log('PDF has XFA data') * ``` * @returns Whether or not this form has XFA data. */ hasXFA() { return this.acroForm.dict.has(core_1.PDFName.of('XFA')); } /** * Disconnect the XFA data from this [[PDFForm]] (if any exists). This will * force readers to fallback to standard fields if the [[PDFDocument]] * contains any. For example: * * For example: * ```js * const form = pdfDoc.getForm() * form.deleteXFA() * ``` */ deleteXFA() { this.acroForm.dict.delete(core_1.PDFName.of('XFA')); } /** * Get all fields contained in this [[PDFForm]]. For example: * ```js * const form = pdfDoc.getForm() * const fields = form.getFields() * fields.forEach(field => { * const type = field.constructor.name * const name = field.getName() * console.log(`${type}: ${name}`) * }) * ``` * @returns An array of all fields in this form. */ getFields() { const allFields = this.acroForm.getAllFields(); const fields = []; for (let idx = 0, len = allFields.length; idx < len; idx++) { const [acroField, ref] = allFields[idx]; const field = convertToPDFField(acroField, ref, this.doc); if (field) fields.push(field); } return fields; } /** * Get the field in this [[PDFForm]] with the given name. For example: * ```js * const form = pdfDoc.getForm() * const field = form.getFieldMaybe('Page1.Foo.Bar[0]') * if (field) console.log('Field exists!') * ``` * @param name A fully qualified field name. * @returns The field with the specified name, if one exists. */ getFieldMaybe(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const fields = this.getFields(); for (let idx = 0, len = fields.length; idx < len; idx++) { const field = fields[idx]; if (field.getName() === name) return field; } return undefined; } /** * Get the field in this [[PDFForm]] with the given name. For example: * ```js * const form = pdfDoc.getForm() * const field = form.getField('Page1.Foo.Bar[0]') * ``` * If no field exists with the provided name, an error will be thrown. * @param name A fully qualified field name. * @returns The field with the specified name. */ getField(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const field = this.getFieldMaybe(name); if (field) return field; throw new errors_1.NoSuchFieldError(name); } /** * Get the button field in this [[PDFForm]] with the given name. For example: * ```js * const form = pdfDoc.getForm() * const button = form.getButton('Page1.Foo.Button[0]') * ``` * An error will be thrown if no field exists with the provided name, or if * the field exists but is not a button. * @param name A fully qualified button name. * @returns The button with the specified name. */ getButton(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const field = this.getField(name); if (field instanceof PDFButton_1.default) return field; throw new errors_1.UnexpectedFieldTypeError(name, PDFButton_1.default, field); } /** * Get the check box field in this [[PDFForm]] with the given name. * For example: * ```js * const form = pdfDoc.getForm() * const checkBox = form.getCheckBox('Page1.Foo.CheckBox[0]') * checkBox.check() * ``` * An error will be thrown if no field exists with the provided name, or if * the field exists but is not a check box. * @param name A fully qualified check box name. * @returns The check box with the specified name. */ getCheckBox(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const field = this.getField(name); if (field instanceof PDFCheckBox_1.default) return field; throw new errors_1.UnexpectedFieldTypeError(name, PDFCheckBox_1.default, field); } /** * Get the dropdown field in this [[PDFForm]] with the given name. * For example: * ```js * const form = pdfDoc.getForm() * const dropdown = form.getDropdown('Page1.Foo.Dropdown[0]') * const options = dropdown.getOptions() * dropdown.select(options[0]) * ``` * An error will be thrown if no field exists with the provided name, or if * the field exists but is not a dropdown. * @param name A fully qualified dropdown name. * @returns The dropdown with the specified name. */ getDropdown(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const field = this.getField(name); if (field instanceof PDFDropdown_1.default) return field; throw new errors_1.UnexpectedFieldTypeError(name, PDFDropdown_1.default, field); } /** * Get the option list field in this [[PDFForm]] with the given name. * For example: * ```js * const form = pdfDoc.getForm() * const optionList = form.getOptionList('Page1.Foo.OptionList[0]') * const options = optionList.getOptions() * optionList.select(options[0]) * ``` * An error will be thrown if no field exists with the provided name, or if * the field exists but is not an option list. * @param name A fully qualified option list name. * @returns The option list with the specified name. */ getOptionList(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const field = this.getField(name); if (field instanceof PDFOptionList_1.default) return field; throw new errors_1.UnexpectedFieldTypeError(name, PDFOptionList_1.default, field); } /** * Get the radio group field in this [[PDFForm]] with the given name. * For example: * ```js * const form = pdfDoc.getForm() * const radioGroup = form.getRadioGroup('Page1.Foo.RadioGroup[0]') * const options = radioGroup.getOptions() * radioGroup.select(options[0]) * ``` * An error will be thrown if no field exists with the provided name, or if * the field exists but is not a radio group. * @param name A fully qualified radio group name. * @returns The radio group with the specified name. */ getRadioGroup(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const field = this.getField(name); if (field instanceof PDFRadioGroup_1.default) return field; throw new errors_1.UnexpectedFieldTypeError(name, PDFRadioGroup_1.default, field); } /** * Get the signature field in this [[PDFForm]] with the given name. * For example: * ```js * const form = pdfDoc.getForm() * const signature = form.getSignature('Page1.Foo.Signature[0]') * ``` * An error will be thrown if no field exists with the provided name, or if * the field exists but is not a signature. * @param name A fully qualified signature name. * @returns The signature with the specified name. */ getSignature(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const field = this.getField(name); if (field instanceof PDFSignature_1.default) return field; throw new errors_1.UnexpectedFieldTypeError(name, PDFSignature_1.default, field); } /** * Get the text field in this [[PDFForm]] with the given name. * For example: * ```js * const form = pdfDoc.getForm() * const textField = form.getTextField('Page1.Foo.TextField[0]') * textField.setText('Are you designed to act or to be acted upon?') * ``` * An error will be thrown if no field exists with the provided name, or if * the field exists but is not a text field. * @param name A fully qualified text field name. * @returns The text field with the specified name. */ getTextField(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const field = this.getField(name); if (field instanceof PDFTextField_1.default) return field; throw new errors_1.UnexpectedFieldTypeError(name, PDFTextField_1.default, field); } /** * Create a new button field in this [[PDFForm]] with the given name. * For example: * ```js * const font = await pdfDoc.embedFont(StandardFonts.Helvetica) * const page = pdfDoc.addPage() * * const form = pdfDoc.getForm() * const button = form.createButton('cool.new.button') * * button.addToPage('Do Stuff', font, page) * ``` * An error will be thrown if a field already exists with the provided name. * @param name The fully qualified name for the new button. * @returns The new button field. */ createButton(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const nameParts = splitFieldName(name); const parent = this.findOrCreateNonTerminals(nameParts.nonTerminal); const button = core_1.PDFAcroPushButton.create(this.doc.context); button.setPartialName(nameParts.terminal); addFieldToParent(parent, [button, button.ref], nameParts.terminal); return PDFButton_1.default.of(button, button.ref, this.doc); } /** * Create a new check box field in this [[PDFForm]] with the given name. * For example: * ```js * const font = await pdfDoc.embedFont(StandardFonts.Helvetica) * const page = pdfDoc.addPage() * * const form = pdfDoc.getForm() * const checkBox = form.createCheckBox('cool.new.checkBox') * * checkBox.addToPage(page) * ``` * An error will be thrown if a field already exists with the provided name. * @param name The fully qualified name for the new check box. * @returns The new check box field. */ createCheckBox(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const nameParts = splitFieldName(name); const parent = this.findOrCreateNonTerminals(nameParts.nonTerminal); const checkBox = core_1.PDFAcroCheckBox.create(this.doc.context); checkBox.setPartialName(nameParts.terminal); addFieldToParent(parent, [checkBox, checkBox.ref], nameParts.terminal); return PDFCheckBox_1.default.of(checkBox, checkBox.ref, this.doc); } /** * Create a new dropdown field in this [[PDFForm]] with the given name. * For example: * ```js * const font = await pdfDoc.embedFont(StandardFonts.Helvetica) * const page = pdfDoc.addPage() * * const form = pdfDoc.getForm() * const dropdown = form.createDropdown('cool.new.dropdown') * * dropdown.addToPage(font, page) * ``` * An error will be thrown if a field already exists with the provided name. * @param name The fully qualified name for the new dropdown. * @returns The new dropdown field. */ createDropdown(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const nameParts = splitFieldName(name); const parent = this.findOrCreateNonTerminals(nameParts.nonTerminal); const comboBox = core_1.PDFAcroComboBox.create(this.doc.context); comboBox.setPartialName(nameParts.terminal); addFieldToParent(parent, [comboBox, comboBox.ref], nameParts.terminal); return PDFDropdown_1.default.of(comboBox, comboBox.ref, this.doc); } /** * Create a new option list field in this [[PDFForm]] with the given name. * For example: * ```js * const font = await pdfDoc.embedFont(StandardFonts.Helvetica) * const page = pdfDoc.addPage() * * const form = pdfDoc.getForm() * const optionList = form.createOptionList('cool.new.optionList') * * optionList.addToPage(font, page) * ``` * An error will be thrown if a field already exists with the provided name. * @param name The fully qualified name for the new option list. * @returns The new option list field. */ createOptionList(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const nameParts = splitFieldName(name); const parent = this.findOrCreateNonTerminals(nameParts.nonTerminal); const listBox = core_1.PDFAcroListBox.create(this.doc.context); listBox.setPartialName(nameParts.terminal); addFieldToParent(parent, [listBox, listBox.ref], nameParts.terminal); return PDFOptionList_1.default.of(listBox, listBox.ref, this.doc); } /** * Create a new radio group field in this [[PDFForm]] with the given name. * For example: * ```js * const font = await pdfDoc.embedFont(StandardFonts.Helvetica) * const page = pdfDoc.addPage() * * const form = pdfDoc.getForm() * const radioGroup = form.createRadioGroup('cool.new.radioGroup') * * radioGroup.addOptionToPage('is-dog', page, { y: 0 }) * radioGroup.addOptionToPage('is-cat', page, { y: 75 }) * ``` * An error will be thrown if a field already exists with the provided name. * @param name The fully qualified name for the new radio group. * @returns The new radio group field. */ createRadioGroup(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const nameParts = splitFieldName(name); const parent = this.findOrCreateNonTerminals(nameParts.nonTerminal); const radioButton = core_1.PDFAcroRadioButton.create(this.doc.context); radioButton.setPartialName(nameParts.terminal); addFieldToParent(parent, [radioButton, radioButton.ref], nameParts.terminal); return PDFRadioGroup_1.default.of(radioButton, radioButton.ref, this.doc); } /** * Create a new text field in this [[PDFForm]] with the given name. * For example: * ```js * const font = await pdfDoc.embedFont(StandardFonts.Helvetica) * const page = pdfDoc.addPage() * * const form = pdfDoc.getForm() * const textField = form.createTextField('cool.new.textField') * * textField.addToPage(font, page) * ``` * An error will be thrown if a field already exists with the provided name. * @param name The fully qualified name for the new radio group. * @returns The new radio group field. */ createTextField(name) { (0, utils_1.assertIs)(name, 'name', ['string']); const nameParts = splitFieldName(name); const parent = this.findOrCreateNonTerminals(nameParts.nonTerminal); const text = core_1.PDFAcroText.create(this.doc.context); text.setPartialName(nameParts.terminal); addFieldToParent(parent, [text, text.ref], nameParts.terminal); return PDFTextField_1.default.of(text, text.ref, this.doc); } /** * Flatten all fields in this [[PDFForm]]. * * Flattening a form field will take the current appearance for each of that * field's widgets and make them part of their page's content stream. All form * fields and annotations associated are then removed. Note that once a form * has been flattened its fields can no longer be accessed or edited. * * This operation is often used after filling form fields to ensure a * consistent appearance across different PDF readers and/or printers. * Another common use case is to copy a template document with form fields * into another document. In this scenario you would load the template * document, fill its fields, flatten it, and then copy its pages into the * recipient document - the filled fields will be copied over. * * For example: * ```js * const form = pdfDoc.getForm(); * form.flatten(); * ``` */ flatten(options = { updateFieldAppearances: true }) { if (options.updateFieldAppearances) { this.updateFieldAppearances(); } const fields = this.getFields(); for (let i = 0, lenFields = fields.length; i < lenFields; i++) { const field = fields[i]; const widgets = field.acroField.getWidgets(); for (let j = 0, lenWidgets = widgets.length; j < lenWidgets; j++) { try { const widget = widgets[j]; const page = this.findWidgetPage(widget); const widgetRef = this.findWidgetAppearanceRef(field, widget); const xObjectKey = page.node.newXObject('FlatWidget', widgetRef); const rectangle = widget.getRectangle(); const operators = [ (0, operators_1.pushGraphicsState)(), (0, operators_1.translate)(rectangle.x, rectangle.y), ...(0, operations_1.rotateInPlace)(Object.assign(Object.assign({}, rectangle), { rotation: 0 })), (0, operators_1.drawObject)(xObjectKey), (0, operators_1.popGraphicsState)(), ].filter(Boolean); page.pushOperators(...operators); } catch (err) { console.error(err); } } this.removeField(field); } } /** * Remove a field from this [[PDFForm]]. * * For example: * ```js * const form = pdfDoc.getForm(); * const ageField = form.getFields().find(x => x.getName() === 'Age'); * form.removeField(ageField); * ``` */ removeField(field) { const widgets = field.acroField.getWidgets(); const pages = new Set(); for (let i = 0, len = widgets.length; i < len; i++) { try { const widget = widgets[i]; const widgetRef = this.findWidgetAppearanceRef(field, widget); const page = this.findWidgetPage(widget); pages.add(page); page.node.removeAnnot(widgetRef); } catch (err) { console.error(err); } } pages.forEach((page) => page.node.removeAnnot(field.ref)); this.acroForm.removeField(field.acroField); const fieldKids = field.acroField.normalizedEntries().Kids; const kidsCount = fieldKids.size(); for (let childIndex = 0; childIndex < kidsCount; childIndex++) { const child = fieldKids.get(childIndex); if (child instanceof core_1.PDFRef) { this.doc.context.delete(child); } } this.doc.context.delete(field.ref); } /** * Update the appearance streams for all widgets of all fields in this * [[PDFForm]]. Appearance streams will only be created for a widget if it * does not have any existing appearance streams, or the field's value has * changed (e.g. by calling [[PDFTextField.setText]] or * [[PDFDropdown.select]]). * * For example: * ```js * const courier = await pdfDoc.embedFont(StandardFonts.Courier) * const form = pdfDoc.getForm() * form.updateFieldAppearances(courier) * ``` * * **IMPORTANT:** The default value for the `font` parameter is * [[StandardFonts.Helvetica]]. Note that this is a WinAnsi font. This means * that encoding errors will be thrown if any fields contain text with * characters outside the WinAnsi character set (the latin alphabet). * * Embedding a custom font and passing that as the `font` * parameter allows you to generate appearance streams with non WinAnsi * characters (assuming your custom font supports them). * * > **NOTE:** The [[PDFDocument.save]] method will call this method to * > update appearances automatically if a form was accessed via the * > [[PDFDocument.getForm]] method prior to saving. * * @param font Optionally, the font to use when creating new appearances. */ updateFieldAppearances(font) { (0, utils_1.assertOrUndefined)(font, 'font', [[PDFFont_1.default, 'PDFFont']]); font = font !== null && font !== void 0 ? font : this.getDefaultFont(); const fields = this.getFields(); for (let idx = 0, len = fields.length; idx < len; idx++) { const field = fields[idx]; if (field.needsAppearancesUpdate()) { field.defaultUpdateAppearances(font); } } } /** * Mark a field as dirty. This will cause its appearance streams to be * updated by [[PDFForm.updateFieldAppearances]]. * ```js * const form = pdfDoc.getForm() * const field = form.getField('foo.bar') * form.markFieldAsDirty(field.ref) * ``` * @param fieldRef The reference to the field that should be marked. */ markFieldAsDirty(fieldRef) { (0, utils_1.assertOrUndefined)(fieldRef, 'fieldRef', [[core_1.PDFRef, 'PDFRef']]); this.dirtyFields.add(fieldRef); } /** * Mark a field as dirty. This will cause its appearance streams to not be * updated by [[PDFForm.updateFieldAppearances]]. * ```js * const form = pdfDoc.getForm() * const field = form.getField('foo.bar') * form.markFieldAsClean(field.ref) * ``` * @param fieldRef The reference to the field that should be marked. */ markFieldAsClean(fieldRef) { (0, utils_1.assertOrUndefined)(fieldRef, 'fieldRef', [[core_1.PDFRef, 'PDFRef']]); this.dirtyFields.delete(fieldRef); } /** * Returns `true` is the specified field has been marked as dirty. * ```js * const form = pdfDoc.getForm() * const field = form.getField('foo.bar') * if (form.fieldIsDirty(field.ref)) console.log('Field is dirty') * ``` * @param fieldRef The reference to the field that should be checked. * @returns Whether or not the specified field is dirty. */ fieldIsDirty(fieldRef) { (0, utils_1.assertOrUndefined)(fieldRef, 'fieldRef', [[core_1.PDFRef, 'PDFRef']]); return this.dirtyFields.has(fieldRef); } getDefaultFont() { return this.defaultFontCache.access(); } findWidgetPage(widget) { const pageRef = widget.P(); let page = this.doc.getPages().find((x) => x.ref === pageRef); if (page === undefined) { const widgetRef = this.doc.context.getObjectRef(widget.dict); if (widgetRef === undefined) { throw new Error('Could not find PDFRef for PDFObject'); } page = this.doc.findPageForAnnotationRef(widgetRef); if (page === undefined) { throw new Error(`Could not find page for PDFRef ${widgetRef}`); } } return page; } findWidgetAppearanceRef(field, widget) { var _a; let refOrDict = widget.getNormalAppearance(); if (field instanceof PDFCheckBox_1.default || field instanceof PDFRadioGroup_1.default) { if (refOrDict instanceof core_1.PDFRef) { refOrDict = this.doc.context.lookup(refOrDict, core_1.PDFDict); } if (refOrDict instanceof core_1.PDFDict) { const value = field.acroField.getValue(); const ref = (_a = refOrDict.get(value)) !== null && _a !== void 0 ? _a : refOrDict.get(core_1.PDFName.of('Off')); if (ref instanceof core_1.PDFRef) { refOrDict = ref; } } } if (!(refOrDict instanceof core_1.PDFRef)) { const name = field.getName(); throw new Error(`Failed to extract appearance ref for: ${name}`); } return refOrDict; } findOrCreateNonTerminals(partialNames) { let nonTerminal = [ this.acroForm, ]; for (let idx = 0, len = partialNames.length; idx < len; idx++) { const namePart = partialNames[idx]; if (!namePart) throw new errors_1.InvalidFieldNamePartError(namePart); const [parent, parentRef] = nonTerminal; const res = this.findNonTerminal(namePart, parent); if (res) { nonTerminal = res; } else { const node = core_1.PDFAcroNonTerminal.create(this.doc.context); node.setPartialName(namePart); node.setParent(parentRef); const nodeRef = this.doc.context.register(node.dict); parent.addField(nodeRef); nonTerminal = [node, nodeRef]; } } return nonTerminal; } findNonTerminal(partialName, parent) { const fields = parent instanceof core_1.PDFAcroForm ? this.acroForm.getFields() : (0, core_1.createPDFAcroFields)(parent.Kids()); for (let idx = 0, len = fields.length; idx < len; idx++) { const [field, ref] = fields[idx]; if (field.getPartialName() === partialName) { if (field instanceof core_1.PDFAcroNonTerminal) return [field, ref]; throw new errors_1.FieldAlreadyExistsError(partialName); } } return undefined; } } exports.default = PDFForm; /** * > **NOTE:** You probably don't want to call this method directly. Instead, * > consider using the [[PDFDocument.getForm]] method, which will create an * > instance of [[PDFForm]] for you. * * Create an instance of [[PDFForm]] from an existing acroForm and embedder * * @param acroForm The underlying `PDFAcroForm` for this form. * @param doc The document to which the form will belong. */ PDFForm.of = (acroForm, doc) => new PDFForm(acroForm, doc); const convertToPDFField = (field, ref, doc) => { if (field instanceof core_1.PDFAcroPushButton) return PDFButton_1.default.of(field, ref, doc); if (field instanceof core_1.PDFAcroCheckBox) return PDFCheckBox_1.default.of(field, ref, doc); if (field instanceof core_1.PDFAcroComboBox) return PDFDropdown_1.default.of(field, ref, doc); if (field instanceof core_1.PDFAcroListBox) return PDFOptionList_1.default.of(field, ref, doc); if (field instanceof core_1.PDFAcroText) return PDFTextField_1.default.of(field, ref, doc); if (field instanceof core_1.PDFAcroRadioButton) { return PDFRadioGroup_1.default.of(field, ref, doc); } if (field instanceof core_1.PDFAcroSignature) { return PDFSignature_1.default.of(field, ref, doc); } return undefined; }; const splitFieldName = (fullyQualifiedName) => { if (fullyQualifiedName.length === 0) { throw new Error('PDF field names must not be empty strings'); } const parts = fullyQualifiedName.split('.'); for (let idx = 0, len = parts.length; idx < len; idx++) { if (parts[idx] === '') { throw new Error(`Periods in PDF field names must be separated by at least one character: "${fullyQualifiedName}"`); } } if (parts.length === 1) return { nonTerminal: [], terminal: parts[0] }; return { nonTerminal: parts.slice(0, parts.length - 1), terminal: parts[parts.length - 1], }; }; const addFieldToParent = ([parent, parentRef], [field, fieldRef], partialName) => { const entries = parent.normalizedEntries(); const fields = (0, core_1.createPDFAcroFields)('Kids' in entries ? entries.Kids : entries.Fields); for (let idx = 0, len = fields.length; idx < len; idx++) { if (fields[idx][0].getPartialName() === partialName) { throw new errors_1.FieldAlreadyExistsError(partialName); } } parent.addField(fieldRef); field.setParent(parentRef); }; //# sourceMappingURL=PDFForm.js.map