@stll/folio-core 0.33.0 → 0.33.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-edits/apply.d.ts +15 -0
- package/dist/ai-edits/apply.js +135 -24
- package/dist/ai-edits/headless.d.ts +47 -3
- package/dist/ai-edits/headless.js +53 -3
- package/dist/ai-edits/index.d.ts +1 -1
- package/dist/ai-edits/snapshot.d.ts +19 -1
- package/dist/ai-edits/snapshot.js +25 -3
- package/dist/ai-edits/table-geometry.d.ts +56 -0
- package/dist/ai-edits/table-geometry.js +217 -0
- package/dist/ai-edits/table-row-column-mutations.d.ts +34 -16
- package/dist/ai-edits/table-row-column-mutations.js +12 -4
- package/dist/ai-edits/table-template.d.ts +60 -0
- package/dist/ai-edits/table-template.js +176 -0
- package/dist/ai-edits/types.d.ts +7 -0
- package/dist/compare/__fixtures__/body-sequence.d.ts +86 -4
- package/dist/compare/__fixtures__/body-sequence.js +169 -12
- package/dist/compare/compare.d.ts +15 -8
- package/dist/compare/compare.js +138 -34
- package/dist/compare/plan.d.ts +31 -1
- package/dist/compare/plan.js +277 -28
- package/dist/compare/reproducible-package.d.ts +7 -3
- package/dist/compare/reproducible-package.js +20 -3
- package/dist/compare/types.d.ts +20 -3
- package/dist/compare/types.js +13 -1
- package/dist/compare/verification.d.ts +49 -2
- package/dist/compare/verification.js +115 -1
- package/dist/compat/eigenpal.d.ts +5 -5
- package/dist/compat/eigenpal.js +3 -3
- package/dist/document-operations.d.ts +10 -1
- package/dist/document-operations.js +3 -2
- package/dist/docx/appVersionNormalization.d.ts +49 -0
- package/dist/docx/appVersionNormalization.js +74 -0
- package/dist/docx/blockContentParser.js +3 -2
- package/dist/docx/drawingUtils.js +4 -3
- package/dist/docx/hyperlinkParser.d.ts +9 -1
- package/dist/docx/hyperlinkParser.js +19 -13
- package/dist/docx/paraIdRangeNormalization.d.ts +40 -0
- package/dist/docx/paraIdRangeNormalization.js +64 -0
- package/dist/docx/paragraphParser.js +82 -6
- package/dist/docx/revisionIdNormalization.d.ts +15 -1
- package/dist/docx/revisionIdNormalization.js +22 -4
- package/dist/docx/rezip.d.ts +13 -1
- package/dist/docx/rezip.js +80 -21
- package/dist/docx/runParser.js +9 -8
- package/dist/docx/sdtProperties.js +4 -3
- package/dist/docx/selectiveSave.js +7 -6
- package/dist/docx/serializer/commentSerializer.d.ts +1 -1
- package/dist/docx/serializer/commentSerializer.js +43 -19
- package/dist/docx/serializer/documentSerializer.d.ts +3 -1
- package/dist/docx/serializer/documentSerializer.js +42 -78
- package/dist/docx/serializer/fontTableSerializer.js +8 -5
- package/dist/docx/serializer/headerFooterSerializer.d.ts +4 -1
- package/dist/docx/serializer/headerFooterSerializer.js +34 -29
- package/dist/docx/serializer/noteSerializer.js +34 -30
- package/dist/docx/serializer/numberingSerializer.js +8 -4
- package/dist/docx/serializer/paragraphSerializer.js +45 -21
- package/dist/docx/serializer/partNamespaces.d.ts +78 -0
- package/dist/docx/serializer/partNamespaces.js +324 -0
- package/dist/docx/serializer/runSerializer.js +1 -1
- package/dist/docx/serializer/settingsSerializer.js +8 -2
- package/dist/docx/serializer/stylesSerializer.js +8 -5
- package/dist/docx/serializer/tableSerializer.js +107 -27
- package/dist/docx/serializer/themeSerializer.js +10 -2
- package/dist/docx/server/build.d.ts +1 -1
- package/dist/docx/strictValueEncodings.gen.d.ts +15 -0
- package/dist/docx/strictValueEncodings.gen.js +275 -0
- package/dist/docx/tableParser.d.ts +0 -6
- package/dist/docx/tableParser.js +52 -7
- package/dist/docx/transitionalSpelling.d.ts +23 -0
- package/dist/docx/transitionalSpelling.js +36 -0
- package/dist/docx/universalMeasure.d.ts +20 -0
- package/dist/docx/universalMeasure.js +32 -0
- package/dist/docx/verbatimCapture.d.ts +20 -0
- package/dist/docx/verbatimCapture.js +131 -0
- package/dist/docx/vmlImageParser.js +4 -3
- package/dist/docx/watermarkParser.js +4 -3
- package/dist/docx/xmlParser.d.ts +23 -2
- package/dist/docx/xmlParser.js +43 -11
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -3
- package/dist/model.d.ts +3 -3
- package/dist/model.js +2 -2
- package/dist/prosemirror/commands/comments.js +8 -2
- package/dist/prosemirror/containerFinalParagraph.d.ts +47 -0
- package/dist/prosemirror/containerFinalParagraph.js +92 -0
- package/dist/prosemirror/conversion/fromProseDoc.d.ts +8 -1
- package/dist/prosemirror/conversion/fromProseDoc.js +15 -4
- package/dist/prosemirror/conversion/toProseDoc.js +12 -3
- package/dist/prosemirror/extensions/nodes/TableExtension.js +5 -0
- package/dist/prosemirror/schema/marks.d.ts +1 -1
- package/dist/prosemirror/schema/nodes.d.ts +22 -0
- package/dist/server.d.ts +1 -1
- package/dist/types/block-id.d.ts +12 -1
- package/dist/types/block-id.js +17 -1
- package/dist/utils/canonicalJson.d.ts +14 -0
- package/dist/utils/canonicalJson.js +19 -0
- package/dist/utils/formatToStyle.d.ts +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,19 @@
|
|
|
1
|
+
import { PARAGRAPH_MARK_CHANGE_KINDS } from "@stll/docx-core/model";
|
|
1
2
|
//#region src/compare/verification.ts
|
|
3
|
+
/**
|
|
4
|
+
* What the round-trip self-check found, and how to say it safely.
|
|
5
|
+
*
|
|
6
|
+
* The check compares two block projections: what accepting the generated
|
|
7
|
+
* revisions leaves against the target, and what rejecting them leaves against
|
|
8
|
+
* the base. A projection carries each block's container, style, list level and
|
|
9
|
+
* text, so WHICH field diverged names which part of the pipeline lost the
|
|
10
|
+
* difference — and that is worth reporting as a typed cause rather than as one
|
|
11
|
+
* opaque "did not reproduce".
|
|
12
|
+
*
|
|
13
|
+
* Every `detail` string here is structural: counts, offsets, container kinds.
|
|
14
|
+
* Never a phrase of either document, because a caller may log it, put it in a
|
|
15
|
+
* report, or quote it in a review.
|
|
16
|
+
*/
|
|
2
17
|
/** The two directions of the round trip, each an invariant of its own. */
|
|
3
18
|
const COMPARE_VERIFICATION_INVARIANTS = Object.freeze(["accept-reproduces-target", "reject-reproduces-base"]);
|
|
4
19
|
/**
|
|
@@ -10,6 +25,7 @@ const COMPARE_VERIFICATION_CAUSES = Object.freeze([
|
|
|
10
25
|
"invisible-structure",
|
|
11
26
|
"block-count",
|
|
12
27
|
"container",
|
|
28
|
+
"table-geometry",
|
|
13
29
|
"style",
|
|
14
30
|
"list-level",
|
|
15
31
|
"inline-formatting",
|
|
@@ -116,6 +132,21 @@ const firstDivergence = (actual, expected) => {
|
|
|
116
132
|
};
|
|
117
133
|
};
|
|
118
134
|
/**
|
|
135
|
+
* The failure two table-geometry projections describe, or `null` when they
|
|
136
|
+
* agree. One line per table, so the detail names which table diverged and
|
|
137
|
+
* whether the count itself did — never a property value, which could carry a
|
|
138
|
+
* style name either document chose.
|
|
139
|
+
*/
|
|
140
|
+
const classifyGeometryMismatch = ({ invariant, story, actual, expected }) => {
|
|
141
|
+
if (sameProjection(actual, expected)) return null;
|
|
142
|
+
return {
|
|
143
|
+
invariant,
|
|
144
|
+
cause: "table-geometry",
|
|
145
|
+
story,
|
|
146
|
+
detail: actual.length === expected.length ? `table ${String(actual.findIndex((entry, index) => entry !== expected[index]))} of ${String(actual.length)} carries different properties` : `${String(actual.length)} tables against ${String(expected.length)}`
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
119
150
|
* The failure two projections describe, or `null` when they agree.
|
|
120
151
|
*
|
|
121
152
|
* Total over the causes by construction: the last branch is unconditional, so
|
|
@@ -142,5 +173,88 @@ const classifyProjectionMismatch = ({ invariant, story, actual, expected }) => {
|
|
|
142
173
|
if (actual.length !== expected.length) return failure("block-count", `${counts}, first differing ${at}`);
|
|
143
174
|
return failure("text", `a ${containerKind(left.container)} block's text does not match ${at}, length ${String(left.text.length)} against ${String(right.text.length)} (${counts})`);
|
|
144
175
|
};
|
|
176
|
+
const isAParagraphMarkChangeKind = (value) => PARAGRAPH_MARK_CHANGE_KINDS.some((kind) => kind === value);
|
|
177
|
+
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
178
|
+
const isParagraph = (value) => isRecord(value) && value["type"] === "paragraph";
|
|
179
|
+
/**
|
|
180
|
+
* A row the package marks deleted, whose cells' marks go with it.
|
|
181
|
+
*
|
|
182
|
+
* A deleted table row is written as `w:trPr/w:del` PLUS a deletion on every
|
|
183
|
+
* mark the row's cells end with: accepting takes the whole row away, so those
|
|
184
|
+
* marks never have to join anything and are the shape the format asks for.
|
|
185
|
+
*/
|
|
186
|
+
const isADeletedTableRow = (value) => {
|
|
187
|
+
const change = value["structuralChange"];
|
|
188
|
+
return isRecord(change) && change["type"] === "tableRowDeletion";
|
|
189
|
+
};
|
|
190
|
+
/**
|
|
191
|
+
* Every container in a package whose final paragraph mark carries a revision.
|
|
192
|
+
*
|
|
193
|
+
* A deleted paragraph mark says "join this paragraph with the one after it",
|
|
194
|
+
* and an inserted one says that break was ADDED, so rejecting it closes the
|
|
195
|
+
* paragraph back over the next one. The last paragraph of a body, a table
|
|
196
|
+
* cell, a header or footer, a note or a text box has no paragraph after it, so
|
|
197
|
+
* neither direction states an edit that can be carried out: a consumer refuses
|
|
198
|
+
* the package, or opens it and leaves a revision standing that neither
|
|
199
|
+
* accepting nor rejecting everything can clear. The exception is a cell of a
|
|
200
|
+
* row the package is DELETING: there the mark leaves with its row.
|
|
201
|
+
*
|
|
202
|
+
* The walk is over the package model rather than over a list of the containers
|
|
203
|
+
* known today: a container is any sequence that ends in a paragraph, so a part
|
|
204
|
+
* the model grows later is covered the day it arrives instead of the day
|
|
205
|
+
* someone remembers this function.
|
|
206
|
+
*
|
|
207
|
+
* `since` scopes it to the revisions a comparison MINTED: a base may arrive
|
|
208
|
+
* carrying one of these on a paragraph in a part no story mounts, which folio
|
|
209
|
+
* preserves the way it preserves everything else it parses. What this proves
|
|
210
|
+
* is that the comparison writes none of its own.
|
|
211
|
+
*/
|
|
212
|
+
const revisedFinalParagraphMarks = (packageModel, { since = 0 } = {}) => {
|
|
213
|
+
const found = [];
|
|
214
|
+
const trail = ["package"];
|
|
215
|
+
const pathOf = () => {
|
|
216
|
+
let path = "";
|
|
217
|
+
for (const segment of trail) path += typeof segment === "number" ? `[${String(segment)}]` : `.${segment}`;
|
|
218
|
+
return path.slice(1);
|
|
219
|
+
};
|
|
220
|
+
const visit = (value, insideADeletedRow) => {
|
|
221
|
+
if (Array.isArray(value)) {
|
|
222
|
+
const last = value.at(-1);
|
|
223
|
+
const mark = isParagraph(last) ? last["pPrMark"] : void 0;
|
|
224
|
+
const kind = isRecord(mark) ? mark["kind"] : void 0;
|
|
225
|
+
const info = isRecord(mark) ? mark["info"] : void 0;
|
|
226
|
+
const revisionId = isRecord(info) ? info["id"] : void 0;
|
|
227
|
+
const isOurs = typeof revisionId === "number" ? revisionId >= since : true;
|
|
228
|
+
if (isAParagraphMarkChangeKind(kind) && isOurs && !insideADeletedRow) found.push({
|
|
229
|
+
container: pathOf(),
|
|
230
|
+
paragraphIndex: value.length - 1,
|
|
231
|
+
kind
|
|
232
|
+
});
|
|
233
|
+
for (const [index, item] of value.entries()) {
|
|
234
|
+
trail.push(index);
|
|
235
|
+
visit(item, insideADeletedRow);
|
|
236
|
+
trail.pop();
|
|
237
|
+
}
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (value instanceof Map) {
|
|
241
|
+
for (const [key, item] of value) {
|
|
242
|
+
trail.push(String(key));
|
|
243
|
+
visit(item, insideADeletedRow);
|
|
244
|
+
trail.pop();
|
|
245
|
+
}
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (!isRecord(value) || value instanceof Date || ArrayBuffer.isView(value)) return;
|
|
249
|
+
const inADeletedRow = insideADeletedRow || isADeletedTableRow(value);
|
|
250
|
+
for (const [key, item] of Object.entries(value)) {
|
|
251
|
+
trail.push(key);
|
|
252
|
+
visit(item, inADeletedRow);
|
|
253
|
+
trail.pop();
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
visit(packageModel, false);
|
|
257
|
+
return found;
|
|
258
|
+
};
|
|
145
259
|
//#endregion
|
|
146
|
-
export { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, classifyProjectionMismatch, projectSupportedInlineFormatting, sameProjection };
|
|
260
|
+
export { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, classifyGeometryMismatch, classifyProjectionMismatch, projectSupportedInlineFormatting, revisedFinalParagraphMarks, sameProjection };
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
+
import { document_d_exports } from "../types/document.js";
|
|
1
2
|
import { FolioAIBlock, FolioAIBlockAnchor, FolioAIBlockKind, FolioAIBlockPreviewRun, FolioAIBlockTableLocation, FolioAIComment, FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditApplyResult, FolioAIEditNormalization, FolioAIEditNormalizationCode, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditReviewMeta, FolioAIEditSeverity, FolioAIEditSkipReason, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAISignatureParty } from "../ai-edits/types.js";
|
|
2
3
|
import { WORD_DIFF_GRANULARITIES, WordDiffGranularity, WordDiffNormalization, WordDiffOptions, WordDiffSegment, diffWordSegments } from "../ai-edits/word-diff.js";
|
|
3
4
|
import { FolioAIEditApplyOutcome, FolioRevisionStamp, FolioWordDiffOptions, applyFolioAIEditOperations } from "../ai-edits/apply.js";
|
|
4
|
-
import { document_d_exports } from "../types/document.js";
|
|
5
5
|
import { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
|
|
6
6
|
import { createFolioAIEditSnapshot, hashFolioAIBlockText, isFolioAIContentBlock, normalizeFolioAIBlockText } from "../ai-edits/snapshot.js";
|
|
7
|
-
import { DeriveBlockIdInput, FolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
|
|
7
|
+
import { DeriveBlockIdInput, FolioBlockId, currentFolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
|
|
8
8
|
import { AIBarStatus, AIChatMode, AICitation, AICitationSource, AIGenerateInput, AISuggestion, AISuggestionApplyMode, AISuggestionPreset, AISuggestionSeverity, AISuggestionStatus, DEFAULT_AI_SUGGESTION_PRESETS } from "../ai-suggestions/types.js";
|
|
9
9
|
import { ApplyResult, applySuggestions } from "../ai-suggestions/apply.js";
|
|
10
10
|
import { ResolvedAnchor, isSuggestionStale, resolveSuggestionAnchor } from "../ai-suggestions/conflict.js";
|
|
11
11
|
import { PositionalText, buildPositionalText } from "../ai-suggestions/text-positions.js";
|
|
12
|
-
import { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareVerification, CompareVerificationCause, CompareVerificationFailure, CompareVerificationInvariant } from "../compare/verification.js";
|
|
13
|
-
import { COMPARE_UNSUPPORTED_REASONS, CompareChange, CompareChangeLocation, CompareDocxApplyError, CompareDocxError, CompareDocxOperationLimitError, CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, CompareFormatRange, CompareResult, CompareUnsupportedPart, CompareUnsupportedReason, InvalidCompareDocxOptionsError } from "../compare/types.js";
|
|
12
|
+
import { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareVerification, CompareVerificationCause, CompareVerificationFailure, CompareVerificationInvariant, FinalParagraphMarkRevision } from "../compare/verification.js";
|
|
13
|
+
import { COMPARE_UNSUPPORTED_REASONS, CompareChange, CompareChangeLocation, CompareDocxApplyError, CompareDocxError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, CompareFormatRange, CompareResult, CompareUnsupportedPart, CompareUnsupportedReason, InvalidCompareDocxOptionsError } from "../compare/types.js";
|
|
14
14
|
import { MAX_COMPARE_OPERATIONS, compareDocx } from "../compare/compare.js";
|
|
15
15
|
import { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DocumentPreset, DocumentStyleSet } from "../style-sets/types.js";
|
|
16
16
|
import { CreateEmptyDocumentOptions, createEmptyDocument } from "../utils/createDocument.js";
|
|
@@ -37,4 +37,4 @@ import { getGoogleFontsEnabled, setEmbeddedFontFamilyMap, setGoogleFontsEnabled
|
|
|
37
37
|
import { DOCX_CONFORMANCE_CLASSES } from "../index.js";
|
|
38
38
|
type Document = document_d_exports.Document;
|
|
39
39
|
type DocxConformanceClass = document_d_exports.DocxConformanceClass;
|
|
40
|
-
export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, type CompareChange, type CompareChangeLocation, CompareDocxApplyError, type CompareDocxError, CompareDocxOperationLimitError, type CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, type CompareFormatRange, type CompareResult, type CompareUnsupportedPart, type CompareUnsupportedReason, type CompareVerification, type CompareVerificationCause, type CompareVerificationFailure, type CompareVerificationInvariant, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type FolioRevisionStamp, type FolioWordDiffOptions, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidCompareDocxOptionsError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
|
40
|
+
export { type AIBarStatus, type AIChatMode, type AICitation, type AICitationRange, type AICitationSource, type AIGenerateInput, type AISuggestion, type AISuggestionApplyMode, type AISuggestionPreset, type AISuggestionSeverity, type AISuggestionStatus, type AcceptAutocompleteResult, type AnonymizationMatch, type AnonymizationTerm, type ApplyFolioDocumentOperationsOptions, type ApplyResult, type AutocompleteSuggestionPluginOptions, type AutocompleteSuggestionState, type AutocompleteSuggestionStatus, type AutocompleteTriggerCheck, type AutocompleteTriggerOptions, type AutocompleteTriggerSkipReason, type BlockRect, COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, type CompareChange, type CompareChangeLocation, CompareDocxApplyError, type CompareDocxError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, type CompareDocxOptions, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, type CompareFormatRange, type CompareResult, type CompareUnsupportedPart, type CompareUnsupportedReason, type CompareVerification, type CompareVerificationCause, type CompareVerificationFailure, type CompareVerificationInvariant, type CreateEmptyDocumentOptions, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, type DeriveBlockIdInput, type DirectiveKind, type DirectiveRange, type Document, type DocumentPreset, type DocumentStyleCatalog, type DocumentStyleCatalogEntry, type DocumentStyleSet, type DocxCompatibility, type DocxCompatibilityContext, type DocxCompatibilityIssue, type DocxCompatibilityLocation, type DocxCompatibilityPart, type DocxConformanceClass, type EmbeddedFont, type EmbeddedFontParts, type ExtractDocumentStyleSetOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, type FinalParagraphMarkRevision, type FolioAIBlock, type FolioAIBlockAnchor, type FolioAIBlockKind, type FolioAIBlockPreviewRun, type FolioAIBlockTableLocation, type FolioAIComment, type FolioAIEditAppliedOperation, type FolioAIEditApplyMode, type FolioAIEditApplyOutcome, type FolioAIEditApplyResult, type FolioAIEditNormalization, type FolioAIEditNormalizationCode, type FolioAIEditOperation, type FolioAIEditPrecondition, type FolioAIEditReviewMeta, type FolioAIEditSeverity, type FolioAIEditSkipReason, type FolioAIEditSkippedOperation, type FolioAIEditSnapshot, type FolioAISignatureParty, type FolioBlockId, type FolioDocumentOperation, type FolioDocumentOperationAffectedTarget, type FolioDocumentOperationBatch, type FolioDocumentOperationCapabilities, type FolioDocumentOperationIssue, type FolioDocumentOperationMode, type FolioDocumentOperationPrecondition, type FolioDocumentOperationReceipt, type FolioDocumentOperationRecovery, type FolioDocumentOperationResult, type FolioDocumentOperationResultBase, type FolioDocumentOperationStatus, type FolioDocumentOperationStory, type FolioDocumentOperationType, type FolioDocumentOperationUndoFailureReason, type FolioDocumentOperationUndoHandle, type FolioDocumentOperationUndoResult, type FolioDocxCompatibilityHost, type FolioDocxCompatibilityProfile, type FolioRevisionStamp, type FolioWordDiffOptions, type ImageMeta, type ImageRef, type InspectDocxCompatibilityOptions, InvalidCompareDocxOptionsError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, type MarkdownOptions, type MarkdownResult, type PositionalText, type ResolvedAnchor, STELLA_STYLE_SET_NAME, type TemplatePreviewSpan, type TemplatePreviewValue, type TemplatePreviewValues, type TemplateSlashMenuKeyAction, type TemplateSlashMenuState, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, type WordDiffGranularity, type WordDiffNormalization, type WordDiffOptions, type WordDiffSegment, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
package/dist/compat/eigenpal.js
CHANGED
|
@@ -6,7 +6,7 @@ import { isSuggestionStale, resolveSuggestionAnchor } from "../ai-suggestions/co
|
|
|
6
6
|
import { buildPositionalText } from "../ai-suggestions/text-positions.js";
|
|
7
7
|
import { DEFAULT_AI_SUGGESTION_PRESETS } from "../ai-suggestions/types.js";
|
|
8
8
|
import { MAX_COMPARE_OPERATIONS, compareDocx } from "../compare/compare.js";
|
|
9
|
-
import { COMPARE_UNSUPPORTED_REASONS, CompareDocxApplyError, CompareDocxOperationLimitError, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, InvalidCompareDocxOptionsError } from "../compare/types.js";
|
|
9
|
+
import { COMPARE_UNSUPPORTED_REASONS, CompareDocxApplyError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, InvalidCompareDocxOptionsError } from "../compare/types.js";
|
|
10
10
|
import { COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS } from "../compare/verification.js";
|
|
11
11
|
import { FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch } from "../document-operations.js";
|
|
12
12
|
import { inspectDocxCompatibility } from "../docx/compatibility.js";
|
|
@@ -27,8 +27,8 @@ import { clearTemplateSlashMenu, consumeTemplateSlashQuery, getTemplateSlashMenu
|
|
|
27
27
|
import { extractDocumentStyleSet, extractDocumentStyleSetFromDocx, inspectDocumentStyles, inspectDocumentStylesFromDocx } from "../style-sets/extract.js";
|
|
28
28
|
import { STELLA_STYLE_SET_NAME, createStellaStyleDocumentPreset, createStellaStyleSet } from "../style-sets/stellaStyle.js";
|
|
29
29
|
import { DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION } from "../style-sets/types.js";
|
|
30
|
-
import { deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
|
|
30
|
+
import { currentFolioBlockId, deriveBlockId, getFolioParaIdFromBlockId, isFolioBlockId, isSequentialFolioBlockId } from "../types/block-id.js";
|
|
31
31
|
import { createEmptyDocument } from "../utils/createDocument.js";
|
|
32
32
|
import { getGoogleFontsEnabled, setEmbeddedFontFamilyMap, setGoogleFontsEnabled } from "../utils/fontResolver.js";
|
|
33
33
|
import { mergeDocumentContent } from "../utils/mergeDocumentContent.js";
|
|
34
|
-
export { COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareDocxApplyError, CompareDocxOperationLimitError, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidCompareDocxOptionsError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
|
34
|
+
export { COMPARE_UNSUPPORTED_REASONS, COMPARE_VERIFICATION_CAUSES, COMPARE_VERIFICATION_INVARIANTS, CompareDocxApplyError, CompareDocxFinalParagraphMarkError, CompareDocxOperationLimitError, CompareDocxParseError, CompareDocxRoundTripError, CompareDocxSerializeError, DEFAULT_AI_SUGGESTION_PRESETS, DEFAULT_AUTOCOMPLETE_DEAD_ZONE_NODES, DOCUMENT_PRESET_VERSION, DOCUMENT_STYLE_SET_VERSION, DOCX_CONFORMANCE_CLASSES, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, InvalidCompareDocxOptionsError, InvalidFolioDocumentOperationBatchError, MAX_COMPARE_OPERATIONS, STELLA_STYLE_SET_NAME, UnsupportedFolioDocumentOperationVersionError, WORD_DIFF_GRANULARITIES, acceptAutocompleteSuggestion, acceptAutocompleteWord, anonymizationDecorationsKey, appendAutocompleteToken, applyFolioAIEditOperations, applyFolioDocumentOperations, applySuggestions, assertSupportedFolioDocumentOperationVersion, autocompleteSuggestionKey, autocompleteSuggestionPlugin, buildEmbeddedFontFamilyMap, buildPositionalText, clearAutocompleteSuggestion, clearTemplateSlashMenu, compareDocx, consumeTemplateSlashQuery, createAICitationDecorationsPlugin, createDocx, createEmptyDocument, createFolioAIEditSnapshot, createStellaStyleDocumentPreset, createStellaStyleSet, currentFolioBlockId, deriveBlockId, diffWordSegments, extractDocumentStyleSet, extractDocumentStyleSetFromDocx, extractEmbeddedFonts, finishAutocompleteSuggestion, fromMarkdown, getAnonymizationMatches, getAutocompleteSuggestion, getEmbeddedFontFaces, getFolioCaretViewportRect, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, getFolioParaIdFromBlockId, getFolioSelectionViewportRect, getGoogleFontsEnabled, getTemplateDirectives, getTemplateSlashMenu, hashFolioAIBlockText, inspectDocumentStyles, inspectDocumentStylesFromDocx, inspectDocxCompatibility, isFolioAIContentBlock, isFolioBlockId, isFolioDocumentOperationModeSupported, isSequentialFolioBlockId, isSuggestionStale, isSupportedFolioDocumentOperationVersion, mergeDocumentContent, normalizeFolioAIBlockText, parseFolioDocumentOperationBatch, resetTemplateSlashQuery, resolveSuggestionAnchor, scanDirectives, scopeEmbeddedFontFamily, scrollFolioPositionIntoView, setAICitationsMeta, setAISuggestionsMeta, setActiveCitationMeta, setAnonymizationTermsMeta, setEmbeddedFontFamilyMap, setFocusedSuggestionMeta, setGoogleFontsEnabled, setTemplatePreviewValues, shouldTriggerAutocomplete, startAutocompleteSuggestion, templateSlashMenuKey, toMarkdown, toMarkdownResult };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { FolioTableTemplates } from "./ai-edits/table-template.js";
|
|
1
2
|
import { FolioAIEditAppliedOperation, FolioAIEditApplyMode, FolioAIEditNormalization, FolioAIEditOperation, FolioAIEditPrecondition, FolioAIEditSkippedOperation, FolioAIEditSnapshot, FolioAITextRangeHandle } from "./ai-edits/types.js";
|
|
2
3
|
import { FolioAIEditView, FolioRevisionStamp, FolioWordDiffOptions } from "./ai-edits/apply.js";
|
|
3
4
|
//#region src/document-operations.d.ts
|
|
@@ -266,7 +267,15 @@ type ApplyFolioDocumentOperationsOptions = {
|
|
|
266
267
|
revisionStamp?: FolioRevisionStamp;
|
|
267
268
|
/** Token size a replacement's redline is cut at. Word-level by default. */
|
|
268
269
|
wordDiff?: FolioWordDiffOptions;
|
|
270
|
+
/**
|
|
271
|
+
* Tables and rows an `insertTable` / `insertTableRow` in the batch places
|
|
272
|
+
* verbatim, by operation id. Outside the serialized batch because a table
|
|
273
|
+
* node is not JSON: the contract still describes a table by its cell texts,
|
|
274
|
+
* and an in-process caller that already holds the table — a comparison
|
|
275
|
+
* copying the target document's — hands the whole thing over instead.
|
|
276
|
+
*/
|
|
277
|
+
tableTemplates?: FolioTableTemplates;
|
|
269
278
|
};
|
|
270
|
-
declare const applyFolioDocumentOperations: ({ view, snapshot, batch, story, author, createCommentId, createUndoHandle, revisionStamp, wordDiff }: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
|
|
279
|
+
declare const applyFolioDocumentOperations: ({ view, snapshot, batch, story, author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates }: ApplyFolioDocumentOperationsOptions) => FolioDocumentOperationResult;
|
|
271
280
|
//#endregion
|
|
272
281
|
export { ApplyFolioDocumentOperationsOptions, FOLIO_DOCUMENT_OPERATION_BATCH_MODES, FOLIO_DOCUMENT_OPERATION_BATCH_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_CONTRACT_VERSION, FOLIO_DOCUMENT_OPERATION_KEYS_BY_TYPE, FOLIO_DOCUMENT_OPERATION_MODES, FOLIO_DOCUMENT_OPERATION_MODES_BY_TYPE, FOLIO_DOCUMENT_OPERATION_PRECONDITIONS, FOLIO_DOCUMENT_OPERATION_STORIES, FOLIO_DOCUMENT_OPERATION_TYPES, FolioDocumentOperation, FolioDocumentOperationAffectedTarget, FolioDocumentOperationBatch, FolioDocumentOperationBatchPrecondition, FolioDocumentOperationCapabilities, FolioDocumentOperationIssue, FolioDocumentOperationMode, FolioDocumentOperationPrecondition, FolioDocumentOperationQueuedOperation, FolioDocumentOperationReceipt, FolioDocumentOperationRecovery, FolioDocumentOperationResult, FolioDocumentOperationResultBase, FolioDocumentOperationStatus, FolioDocumentOperationStory, FolioDocumentOperationType, FolioDocumentOperationUndoFailureReason, FolioDocumentOperationUndoHandle, FolioDocumentOperationUndoResult, InvalidFolioDocumentOperationBatchError, UnsupportedFolioDocumentOperationVersionError, applyFolioDocumentOperations, assertSupportedFolioDocumentOperationVersion, getFolioDocumentOperationCapabilities, getFolioDocumentOperationIssues, getFolioDocumentOperationReceipts, isFolioDocumentOperationModeSupported, isSupportedFolioDocumentOperationVersion, parseFolioDocumentOperationBatch };
|
|
@@ -879,7 +879,7 @@ const getFolioDocumentOperationReceiptsForStory = ({ operations, applied, story
|
|
|
879
879
|
});
|
|
880
880
|
return receipts;
|
|
881
881
|
};
|
|
882
|
-
const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle, revisionStamp, wordDiff }) => {
|
|
882
|
+
const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", author, createCommentId, createUndoHandle, revisionStamp, wordDiff, tableTemplates }) => {
|
|
883
883
|
const parsedBatch = parseFolioDocumentOperationBatch(batch);
|
|
884
884
|
const apply = ({ targetView, targetCreateCommentId = createCommentId, preview = false }) => {
|
|
885
885
|
return (preview ? previewFolioAIEditOperations : applyFolioAIEditOperations)({
|
|
@@ -890,7 +890,8 @@ const applyFolioDocumentOperations = ({ view, snapshot, batch, story = "main", a
|
|
|
890
890
|
...author !== void 0 && { author },
|
|
891
891
|
...targetCreateCommentId !== void 0 && { createCommentId: targetCreateCommentId },
|
|
892
892
|
...revisionStamp !== void 0 && { revisionStamp },
|
|
893
|
-
...wordDiff !== void 0 && { wordDiff }
|
|
893
|
+
...wordDiff !== void 0 && { wordDiff },
|
|
894
|
+
...tableTemplates !== void 0 && { tableTemplates }
|
|
894
895
|
});
|
|
895
896
|
};
|
|
896
897
|
const preview = () => apply({
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
//#region src/docx/appVersionNormalization.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Keep the application version a package states about itself in the form the
|
|
4
|
+
* schema gives it.
|
|
5
|
+
*
|
|
6
|
+
* `AppVersion` in the extended-properties part is `XX.YYYY`: a one- or
|
|
7
|
+
* two-digit integer, a dot, and four digits. Producers exist that write a
|
|
8
|
+
* three-part version there instead, and folio copies `docProps/app.xml`
|
|
9
|
+
* through verbatim when it saves a document it did not create — so a package
|
|
10
|
+
* can carry a value with two dots in, and a save that copies it out hands a
|
|
11
|
+
* consumer a package it refuses to open at all.
|
|
12
|
+
*
|
|
13
|
+
* {@link appVersionInSchemaForm} is the one mapping, and it is a pure function
|
|
14
|
+
* of the value alone: it keeps the leading integer where the value opens with
|
|
15
|
+
* one the form allows, and writes the build digits the form requires. Nothing
|
|
16
|
+
* else in the part is touched, and a package that carries no extended
|
|
17
|
+
* properties keeps carrying none — synthesizing metadata a document never
|
|
18
|
+
* stated is a different decision.
|
|
19
|
+
*/
|
|
20
|
+
declare const AppVersionSchemaError_base: import("better-result").TaggedErrorClass<"AppVersionSchemaError">;
|
|
21
|
+
/**
|
|
22
|
+
* A value reached the package that the schema form does not accept.
|
|
23
|
+
*
|
|
24
|
+
* The normalization hands every value it writes to one choke point, which
|
|
25
|
+
* throws this rather than letting the package go out carrying a version a
|
|
26
|
+
* consumer refuses.
|
|
27
|
+
*/
|
|
28
|
+
declare class AppVersionSchemaError extends AppVersionSchemaError_base<{
|
|
29
|
+
message: string;
|
|
30
|
+
appVersion: string;
|
|
31
|
+
}> {}
|
|
32
|
+
/**
|
|
33
|
+
* `value` when it already fits, and a value derived from it when it does not.
|
|
34
|
+
*
|
|
35
|
+
* The derivation reads the value and nothing else — not the package, not the
|
|
36
|
+
* clock, not folio's own version — so two saves of one document state the same
|
|
37
|
+
* application version.
|
|
38
|
+
*/
|
|
39
|
+
declare const appVersionInSchemaForm: (value: string) => string;
|
|
40
|
+
/**
|
|
41
|
+
* Rewrite the application version an extended-properties part states.
|
|
42
|
+
*
|
|
43
|
+
* Returns the part unchanged when the value already fits and when the part
|
|
44
|
+
* states no version at all, so a save of a document that never carried a
|
|
45
|
+
* malformed one is byte-identical.
|
|
46
|
+
*/
|
|
47
|
+
declare const normalizeAppVersionInExtendedProperties: (xml: string) => string;
|
|
48
|
+
//#endregion
|
|
49
|
+
export { AppVersionSchemaError, appVersionInSchemaForm, normalizeAppVersionInExtendedProperties };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { TaggedError } from "better-result";
|
|
2
|
+
//#region src/docx/appVersionNormalization.ts
|
|
3
|
+
/**
|
|
4
|
+
* Keep the application version a package states about itself in the form the
|
|
5
|
+
* schema gives it.
|
|
6
|
+
*
|
|
7
|
+
* `AppVersion` in the extended-properties part is `XX.YYYY`: a one- or
|
|
8
|
+
* two-digit integer, a dot, and four digits. Producers exist that write a
|
|
9
|
+
* three-part version there instead, and folio copies `docProps/app.xml`
|
|
10
|
+
* through verbatim when it saves a document it did not create — so a package
|
|
11
|
+
* can carry a value with two dots in, and a save that copies it out hands a
|
|
12
|
+
* consumer a package it refuses to open at all.
|
|
13
|
+
*
|
|
14
|
+
* {@link appVersionInSchemaForm} is the one mapping, and it is a pure function
|
|
15
|
+
* of the value alone: it keeps the leading integer where the value opens with
|
|
16
|
+
* one the form allows, and writes the build digits the form requires. Nothing
|
|
17
|
+
* else in the part is touched, and a package that carries no extended
|
|
18
|
+
* properties keeps carrying none — synthesizing metadata a document never
|
|
19
|
+
* stated is a different decision.
|
|
20
|
+
*/
|
|
21
|
+
/** `XX.YYYY`: the only form the extended-properties `AppVersion` may take. */
|
|
22
|
+
const SCHEMA_FORM = /^\d{1,2}\.\d{4}$/u;
|
|
23
|
+
/** The leading integer, when the value opens with one the form allows. */
|
|
24
|
+
const LEADING_MAJOR = /^\d{1,2}(?!\d)/u;
|
|
25
|
+
/** Major version for a value that does not open with one. */
|
|
26
|
+
const DEFAULT_MAJOR = "1";
|
|
27
|
+
/**
|
|
28
|
+
* The build digits a rewritten value gets. A value the form rejects states no
|
|
29
|
+
* build this pass could carry over, so every rewrite lands on the same one.
|
|
30
|
+
*/
|
|
31
|
+
const CANONICAL_BUILD = "0000";
|
|
32
|
+
/**
|
|
33
|
+
* A value reached the package that the schema form does not accept.
|
|
34
|
+
*
|
|
35
|
+
* The normalization hands every value it writes to one choke point, which
|
|
36
|
+
* throws this rather than letting the package go out carrying a version a
|
|
37
|
+
* consumer refuses.
|
|
38
|
+
*/
|
|
39
|
+
var AppVersionSchemaError = class extends TaggedError("AppVersionSchemaError") {};
|
|
40
|
+
/**
|
|
41
|
+
* `value` when it already fits, and a value derived from it when it does not.
|
|
42
|
+
*
|
|
43
|
+
* The derivation reads the value and nothing else — not the package, not the
|
|
44
|
+
* clock, not folio's own version — so two saves of one document state the same
|
|
45
|
+
* application version.
|
|
46
|
+
*/
|
|
47
|
+
const appVersionInSchemaForm = (value) => {
|
|
48
|
+
if (SCHEMA_FORM.test(value)) return value;
|
|
49
|
+
const normalized = `${LEADING_MAJOR.exec(value.trim())?.[0] ?? DEFAULT_MAJOR}.${CANONICAL_BUILD}`;
|
|
50
|
+
if (!SCHEMA_FORM.test(normalized)) throw new AppVersionSchemaError({
|
|
51
|
+
message: `Derived application version ${normalized} is not of the form XX.YYYY`,
|
|
52
|
+
appVersion: value
|
|
53
|
+
});
|
|
54
|
+
return normalized;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The element and its content, with the prefix and attributes it was written
|
|
58
|
+
* with preserved: the replacement rewrites the value between the tags and
|
|
59
|
+
* leaves the rest of the part byte-identical.
|
|
60
|
+
*/
|
|
61
|
+
const APP_VERSION_ELEMENT = /(<(?:[^\s<>/:]+:)?AppVersion(?:\s[^<>]*)?>)([^<]*)(<\/(?:[^\s<>/:]+:)?AppVersion>)/u;
|
|
62
|
+
/**
|
|
63
|
+
* Rewrite the application version an extended-properties part states.
|
|
64
|
+
*
|
|
65
|
+
* Returns the part unchanged when the value already fits and when the part
|
|
66
|
+
* states no version at all, so a save of a document that never carried a
|
|
67
|
+
* malformed one is byte-identical.
|
|
68
|
+
*/
|
|
69
|
+
const normalizeAppVersionInExtendedProperties = (xml) => xml.replace(APP_VERSION_ELEMENT, (whole, open, value, close) => {
|
|
70
|
+
const replacement = appVersionInSchemaForm(value);
|
|
71
|
+
return replacement === value ? whole : `${open}${replacement}${close}`;
|
|
72
|
+
});
|
|
73
|
+
//#endregion
|
|
74
|
+
export { AppVersionSchemaError, appVersionInSchemaForm, normalizeAppVersionInExtendedProperties };
|
|
@@ -6,7 +6,8 @@ import { parseParagraph } from "./paragraphParser.js";
|
|
|
6
6
|
import { enrichParagraphTextBoxes } from "./paragraphTextBoxEnrichment.js";
|
|
7
7
|
import { parseSdtProperties } from "./sdtProperties.js";
|
|
8
8
|
import { parseTable } from "./tableParser.js";
|
|
9
|
-
import {
|
|
9
|
+
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
10
|
+
import { findChild, getChildElements, getLocalName, mergeXmlnsDeclarations } from "./xmlParser.js";
|
|
10
11
|
//#region src/docx/blockContentParser.ts
|
|
11
12
|
const computeListMarker = (paragraph, { numbering, listCounters, abstractCounters, restartedNumIds, previousList, siblingNumIdsByAbstractNumId }) => {
|
|
12
13
|
const listRendering = paragraph.listRendering;
|
|
@@ -192,7 +193,7 @@ const captureSdtSiblingMarkers = (sdt) => {
|
|
|
192
193
|
sawContent = true;
|
|
193
194
|
continue;
|
|
194
195
|
}
|
|
195
|
-
const xml =
|
|
196
|
+
const xml = captureVerbatimXml(ch);
|
|
196
197
|
if (sawContent) afterParts.push(xml);
|
|
197
198
|
else beforeParts.push(xml);
|
|
198
199
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ImageHorizontalAlignmentSchema, ImageHorizontalRelativeToSchema, ImageVerticalAlignmentSchema, ImageVerticalRelativeToSchema, ImageWrapTextSchema, ShapeOutlineStyleSchema, narrowEnum } from "./parserEnums.js";
|
|
2
|
-
import {
|
|
2
|
+
import { captureVerbatimXml } from "./verbatimCapture.js";
|
|
3
|
+
import { findByFullName, findChildByLocalName, findChildrenByLocalName, getAttribute, getChildElements, getTextContent, parseNumericAttribute } from "./xmlParser.js";
|
|
3
4
|
//#region src/docx/drawingUtils.ts
|
|
4
5
|
/**
|
|
5
6
|
* Map OOXML scheme names to standard theme color slots.
|
|
@@ -162,7 +163,7 @@ function parseGradientFill(gradientFill) {
|
|
|
162
163
|
}
|
|
163
164
|
return {
|
|
164
165
|
type: "gradient",
|
|
165
|
-
rawXml:
|
|
166
|
+
rawXml: captureVerbatimXml(gradientFill),
|
|
166
167
|
gradient: {
|
|
167
168
|
type,
|
|
168
169
|
...angle !== void 0 ? { angle } : {},
|
|
@@ -177,7 +178,7 @@ function parseOutline(spPr) {
|
|
|
177
178
|
const ln = spPr ? findChildByLocalName(spPr, "ln") : null;
|
|
178
179
|
if (!ln) return;
|
|
179
180
|
if (findChildByLocalName(ln, "noFill")) return;
|
|
180
|
-
const outline = { rawXml:
|
|
181
|
+
const outline = { rawXml: captureVerbatimXml(ln) };
|
|
181
182
|
const w = getAttribute(ln, null, "w");
|
|
182
183
|
if (w) {
|
|
183
184
|
const parsed = Number.parseInt(w, 10);
|
|
@@ -16,6 +16,14 @@ import { XmlElement } from "./xmlParser.js";
|
|
|
16
16
|
* @returns Parsed Hyperlink object
|
|
17
17
|
*/
|
|
18
18
|
declare function parseHyperlink(node: XmlElement, rels: document_d_exports.RelationshipMap | null, styles?: StyleMap | null, theme?: document_d_exports.Theme | null, media?: Map<string, document_d_exports.MediaFile> | null, rootXmlns?: Record<string, string>): document_d_exports.Hyperlink;
|
|
19
|
+
/**
|
|
20
|
+
* One `w:hyperlink` child, or `null` for markup the model does not carry.
|
|
21
|
+
*
|
|
22
|
+
* Exposed so a caller that has to segment a hyperlink — one holding revision
|
|
23
|
+
* wrappers, which the model nests the other way round — parses its plain
|
|
24
|
+
* children exactly as {@link parseHyperlink} does.
|
|
25
|
+
*/
|
|
26
|
+
declare function parseHyperlinkChild(node: XmlElement, styles: StyleMap | null, theme: document_d_exports.Theme | null, rels: document_d_exports.RelationshipMap | null, media: Map<string, document_d_exports.MediaFile> | null, inScopeXmlns: Record<string, string>): document_d_exports.Hyperlink["children"][number] | null;
|
|
19
27
|
/**
|
|
20
28
|
* Get the display text of a hyperlink
|
|
21
29
|
*
|
|
@@ -104,4 +112,4 @@ declare function createExternalHyperlink(url: string, children: document_d_expor
|
|
|
104
112
|
target?: string;
|
|
105
113
|
}): document_d_exports.Hyperlink;
|
|
106
114
|
//#endregion
|
|
107
|
-
export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, resolveHyperlinkUrl };
|
|
115
|
+
export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, parseHyperlinkChild, resolveHyperlinkUrl };
|
|
@@ -71,22 +71,28 @@ function parseHyperlink(node, rels, styles = null, theme = null, media = null, r
|
|
|
71
71
|
const docLocation = getAttribute(node, "w", "docLocation");
|
|
72
72
|
if (docLocation) hyperlink.docLocation = docLocation;
|
|
73
73
|
const inScopeXmlns = mergeXmlnsDeclarations(rootXmlns, node);
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
hyperlink.children.push(parseRun(child, styles, theme, rels, media, inScopeXmlns));
|
|
78
|
-
break;
|
|
79
|
-
case "bookmarkStart":
|
|
80
|
-
hyperlink.children.push(parseBookmarkStart(child));
|
|
81
|
-
break;
|
|
82
|
-
case "bookmarkEnd":
|
|
83
|
-
hyperlink.children.push(parseBookmarkEnd(child));
|
|
84
|
-
break;
|
|
85
|
-
default: break;
|
|
74
|
+
for (const child of getChildElements(node)) {
|
|
75
|
+
const parsed = parseHyperlinkChild(child, styles, theme, rels, media, inScopeXmlns);
|
|
76
|
+
if (parsed) hyperlink.children.push(parsed);
|
|
86
77
|
}
|
|
87
78
|
return hyperlink;
|
|
88
79
|
}
|
|
89
80
|
/**
|
|
81
|
+
* One `w:hyperlink` child, or `null` for markup the model does not carry.
|
|
82
|
+
*
|
|
83
|
+
* Exposed so a caller that has to segment a hyperlink — one holding revision
|
|
84
|
+
* wrappers, which the model nests the other way round — parses its plain
|
|
85
|
+
* children exactly as {@link parseHyperlink} does.
|
|
86
|
+
*/
|
|
87
|
+
function parseHyperlinkChild(node, styles, theme, rels, media, inScopeXmlns) {
|
|
88
|
+
switch (getLocalName(node.name)) {
|
|
89
|
+
case "r": return parseRun(node, styles, theme, rels, media, inScopeXmlns);
|
|
90
|
+
case "bookmarkStart": return parseBookmarkStart(node);
|
|
91
|
+
case "bookmarkEnd": return parseBookmarkEnd(node);
|
|
92
|
+
default: return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
90
96
|
* Get the display text of a hyperlink
|
|
91
97
|
*
|
|
92
98
|
* Concatenates text from all child runs.
|
|
@@ -219,4 +225,4 @@ function createExternalHyperlink(url, children, options) {
|
|
|
219
225
|
};
|
|
220
226
|
}
|
|
221
227
|
//#endregion
|
|
222
|
-
export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, resolveHyperlinkUrl };
|
|
228
|
+
export { createExternalHyperlink, createInternalHyperlink, getHyperlinkRuns, getHyperlinkText, getHyperlinkUrl, hasContent, isExternalLink, isInternalLink, parseHyperlink, parseHyperlinkChild, resolveHyperlinkUrl };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
//#region src/docx/paraIdRangeNormalization.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Keep every paragraph id a package carries inside the range the schema gives
|
|
4
|
+
* it.
|
|
5
|
+
*
|
|
6
|
+
* `w14:paraId`, `w14:textId` and the comment-part ids that reference a
|
|
7
|
+
* paragraph are `ST_LongHexNumber` with a maximum: the value has to be below
|
|
8
|
+
* `0x80000000`, so the ids are 31-bit. Producers exist that write eight hex
|
|
9
|
+
* digits without that bound, and folio preserves the ids a document arrives
|
|
10
|
+
* with — so a package can carry an out-of-range id in, and a save that copies
|
|
11
|
+
* it through hands a consumer a package it will refuse.
|
|
12
|
+
*
|
|
13
|
+
* {@link paraIdInRange} is the one mapping, and it is a pure function of the
|
|
14
|
+
* value alone. That is what lets the parser and the save agree without
|
|
15
|
+
* consulting each other: a paragraph's id in the model is the id the file gets,
|
|
16
|
+
* so bringing an id into range does not make a document's own identity move
|
|
17
|
+
* under it between reading and writing. The package pass below is the same
|
|
18
|
+
* mapping applied to every attribute that carries such an id, so a paragraph
|
|
19
|
+
* and every reference to it move together.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* `value` when it already fits, and a value derived from it when it does not.
|
|
23
|
+
*
|
|
24
|
+
* The replacement is derived from the id being replaced and from nothing else.
|
|
25
|
+
* A package-aware search for a free id would read better here and would be
|
|
26
|
+
* wrong: the parser has no package to search, and an id that means one
|
|
27
|
+
* paragraph while reading and another while writing is worse than the
|
|
28
|
+
* vanishing chance of two rewritten ids landing on one value, which is a
|
|
29
|
+
* duplicate rather than a package a consumer refuses.
|
|
30
|
+
*/
|
|
31
|
+
declare const paraIdInRange: (value: string) => string;
|
|
32
|
+
/**
|
|
33
|
+
* Rewrite out-of-range paragraph ids across a whole package.
|
|
34
|
+
*
|
|
35
|
+
* Returns the parts unchanged when every id already fits, so a save of a
|
|
36
|
+
* document that never carried one is byte-identical.
|
|
37
|
+
*/
|
|
38
|
+
declare const normalizeParaIdRangeInXmlParts: (parts: ReadonlyMap<string, string>) => Map<string, string>;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { normalizeParaIdRangeInXmlParts, paraIdInRange };
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { deterministicHexId } from "../utils/hexId.js";
|
|
2
|
+
//#region src/docx/paraIdRangeNormalization.ts
|
|
3
|
+
/**
|
|
4
|
+
* Keep every paragraph id a package carries inside the range the schema gives
|
|
5
|
+
* it.
|
|
6
|
+
*
|
|
7
|
+
* `w14:paraId`, `w14:textId` and the comment-part ids that reference a
|
|
8
|
+
* paragraph are `ST_LongHexNumber` with a maximum: the value has to be below
|
|
9
|
+
* `0x80000000`, so the ids are 31-bit. Producers exist that write eight hex
|
|
10
|
+
* digits without that bound, and folio preserves the ids a document arrives
|
|
11
|
+
* with — so a package can carry an out-of-range id in, and a save that copies
|
|
12
|
+
* it through hands a consumer a package it will refuse.
|
|
13
|
+
*
|
|
14
|
+
* {@link paraIdInRange} is the one mapping, and it is a pure function of the
|
|
15
|
+
* value alone. That is what lets the parser and the save agree without
|
|
16
|
+
* consulting each other: a paragraph's id in the model is the id the file gets,
|
|
17
|
+
* so bringing an id into range does not make a document's own identity move
|
|
18
|
+
* under it between reading and writing. The package pass below is the same
|
|
19
|
+
* mapping applied to every attribute that carries such an id, so a paragraph
|
|
20
|
+
* and every reference to it move together.
|
|
21
|
+
*/
|
|
22
|
+
/** Exclusive upper bound on a paragraph id: the values are 31-bit. */
|
|
23
|
+
const MAX_PARA_ID_EXCLUSIVE = 2147483648;
|
|
24
|
+
/**
|
|
25
|
+
* Every attribute that carries a paragraph id or the text-revision marker
|
|
26
|
+
* written beside one: the paragraph's own `w14:paraId` / `w14:textId` (the
|
|
27
|
+
* parser accepts a `w:` prefix too), the comment part's `w15:paraId` and the
|
|
28
|
+
* `w15:paraIdParent` that links a reply to its thread, and the durable-comment
|
|
29
|
+
* part's `w16cid:paraId`.
|
|
30
|
+
*/
|
|
31
|
+
const PARA_ID_ATTRIBUTE = /\b(w|w14|w15|w16cid):(paraId|paraIdParent|textId)=(?<quote>["'])([0-9A-Fa-f]{8})\k<quote>/gu;
|
|
32
|
+
/** A candidate part is one that mentions any of those attributes at all. */
|
|
33
|
+
const PARA_ID_CANDIDATE = /\b(?:w|w14|w15|w16cid):(?:paraId|paraIdParent|textId)=/u;
|
|
34
|
+
/**
|
|
35
|
+
* `value` when it already fits, and a value derived from it when it does not.
|
|
36
|
+
*
|
|
37
|
+
* The replacement is derived from the id being replaced and from nothing else.
|
|
38
|
+
* A package-aware search for a free id would read better here and would be
|
|
39
|
+
* wrong: the parser has no package to search, and an id that means one
|
|
40
|
+
* paragraph while reading and another while writing is worse than the
|
|
41
|
+
* vanishing chance of two rewritten ids landing on one value, which is a
|
|
42
|
+
* duplicate rather than a package a consumer refuses.
|
|
43
|
+
*/
|
|
44
|
+
const paraIdInRange = (value) => Number.parseInt(value, 16) < MAX_PARA_ID_EXCLUSIVE ? value : deterministicHexId(value);
|
|
45
|
+
/**
|
|
46
|
+
* Rewrite out-of-range paragraph ids across a whole package.
|
|
47
|
+
*
|
|
48
|
+
* Returns the parts unchanged when every id already fits, so a save of a
|
|
49
|
+
* document that never carried one is byte-identical.
|
|
50
|
+
*/
|
|
51
|
+
const normalizeParaIdRangeInXmlParts = (parts) => {
|
|
52
|
+
const normalized = new Map(parts);
|
|
53
|
+
for (const [path, xml] of parts) {
|
|
54
|
+
if (!PARA_ID_CANDIDATE.test(xml)) continue;
|
|
55
|
+
const rewritten = xml.replaceAll(PARA_ID_ATTRIBUTE, (whole, prefix, name, quote, value) => {
|
|
56
|
+
const replacement = paraIdInRange(value);
|
|
57
|
+
return replacement === value ? whole : `${prefix}:${name}=${quote}${replacement}${quote}`;
|
|
58
|
+
});
|
|
59
|
+
if (rewritten !== xml) normalized.set(path, rewritten);
|
|
60
|
+
}
|
|
61
|
+
return normalized;
|
|
62
|
+
};
|
|
63
|
+
//#endregion
|
|
64
|
+
export { normalizeParaIdRangeInXmlParts, paraIdInRange };
|