@portone/docx-editor 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/DocxEditor.js +1 -0
  3. package/dist/core.d.ts +1 -1
  4. package/dist/docx/comments/writing.js +14 -8
  5. package/dist/docx/exportDocx.js +20 -4
  6. package/dist/docx/formatting/attrs.d.ts +20 -2
  7. package/dist/docx/formatting/attrs.js +57 -2
  8. package/dist/docx/formatting/context.d.ts +10 -2
  9. package/dist/docx/formatting/context.js +23 -5
  10. package/dist/docx/formatting/resolve.d.ts +10 -4
  11. package/dist/docx/formatting/resolve.js +31 -11
  12. package/dist/docx/formatting/styles.d.ts +25 -2
  13. package/dist/docx/formatting/styles.js +84 -3
  14. package/dist/docx/hyperlink.d.ts +14 -4
  15. package/dist/docx/hyperlink.js +4 -1
  16. package/dist/docx/importDocx.js +46 -37
  17. package/dist/docx/importTable.d.ts +2 -2
  18. package/dist/docx/importTable.js +52 -55
  19. package/dist/docx/invariants.js +26 -13
  20. package/dist/docx/newLists.d.ts +30 -0
  21. package/dist/docx/newLists.js +24 -1
  22. package/dist/docx/numberingPlanner.d.ts +6 -3
  23. package/dist/docx/numberingPlanner.js +38 -7
  24. package/dist/docx/session.d.ts +1 -1
  25. package/dist/docx/session.js +11 -1
  26. package/dist/docx/tableFormatting/conditions.d.ts +76 -0
  27. package/dist/docx/tableFormatting/conditions.js +196 -0
  28. package/dist/docx/tableFormatting/editing.d.ts +7 -3
  29. package/dist/docx/tableFormatting/editing.js +4 -5
  30. package/dist/docx/tableFormatting/reading.d.ts +49 -19
  31. package/dist/docx/tableFormatting/reading.js +109 -35
  32. package/dist/docx/tableFormatting.d.ts +1 -0
  33. package/dist/docx/tableFormatting.js +1 -0
  34. package/dist/docx/tableTemplate.js +12 -12
  35. package/dist/editor/commands/formatting/propertyCommands.js +6 -1
  36. package/dist/editor/commands/listCommands.d.ts +6 -3
  37. package/dist/editor/commands/listCommands.js +73 -28
  38. package/dist/editor/commands/paragraphCommands.js +6 -1
  39. package/dist/editor/createEditor.js +1 -1
  40. package/dist/editor/editorDocument.d.ts +7 -6
  41. package/dist/editor/editorDocument.js +18 -6
  42. package/dist/editor/externalClipboard.d.ts +13 -2
  43. package/dist/editor/externalClipboard.js +64 -34
  44. package/dist/editor/paragraphEdits.d.ts +16 -1
  45. package/dist/editor/paragraphEdits.js +13 -5
  46. package/dist/editor/paragraphPlacement.d.ts +11 -0
  47. package/dist/editor/paragraphPlacement.js +18 -0
  48. package/dist/editor/plugins/imagePaste.js +7 -4
  49. package/dist/editor/plugins/numberingDecorations.d.ts +10 -4
  50. package/dist/editor/plugins/numberingDecorations.js +43 -2
  51. package/dist/editor/plugins/paragraphDisplay.js +9 -3
  52. package/dist/editor/plugins/tableDisplay.js +19 -5
  53. package/dist/model/format.d.ts +50 -0
  54. package/dist/model/format.js +65 -0
  55. package/dist/numbering/listRegistry.d.ts +37 -0
  56. package/dist/numbering/listRegistry.js +112 -0
  57. package/dist/numbering/listTemplate.d.ts +26 -17
  58. package/dist/numbering/listTemplate.js +66 -20
  59. package/dist/numbering/markers.d.ts +15 -6
  60. package/dist/numbering/markers.js +26 -59
  61. package/dist/numbering/parseNumbering.d.ts +70 -5
  62. package/dist/numbering/parseNumbering.js +100 -26
  63. package/dist/numbering/spellers.d.ts +15 -0
  64. package/dist/numbering/spellers.js +96 -0
  65. package/dist/numbering/writeNumbering.d.ts +5 -3
  66. package/dist/numbering/writeNumbering.js +15 -15
  67. package/dist/ooxml/conformance.d.ts +28 -0
  68. package/dist/ooxml/conformance.js +20 -0
  69. package/dist/ooxml/errors.d.ts +5 -5
  70. package/dist/ooxml/names.d.ts +9 -0
  71. package/dist/ooxml/names.js +8 -1
  72. package/dist/ooxml/partSplice.d.ts +1 -1
  73. package/dist/ooxml/partSplice.js +10 -3
  74. package/dist/ooxml/xml.d.ts +8 -9
  75. package/dist/ooxml/xml.js +6 -6
  76. package/dist/page/PageGuides.d.ts +1 -1
  77. package/dist/page/PageGuides.js +0 -13
  78. package/dist/page/pageLayout.d.ts +0 -10
  79. package/dist/page/pageLayout.js +3 -10
  80. package/dist/page/usePageLayout.d.ts +0 -7
  81. package/dist/page/usePageLayout.js +2 -9
  82. package/dist/schema/attrRoles.js +8 -1
  83. package/dist/schema/docxSchema.js +32 -3
  84. package/dist/styles/classNames.d.ts +13 -2
  85. package/dist/styles/classNames.js +13 -2
  86. package/dist/styles.css +16 -18
  87. package/dist/table/cellFormatting.js +1 -2
  88. package/dist/table/gridBorders.d.ts +11 -15
  89. package/dist/table/gridBorders.js +32 -18
  90. package/package.json +1 -1
@@ -1,5 +1,6 @@
1
1
  // src/docx/formatting/styles.ts
2
2
  import {
3
+ TABLE_STYLE_CONDITIONS,
3
4
  toParagraphFormat,
4
5
  toRunFormat,
5
6
  toTableFormat
@@ -9,11 +10,16 @@ import { ST_OnOff } from "../../ooxml/simpleTypes.js";
9
10
  import { childValue, isOn, wAttr } from "../../ooxml/units.js";
10
11
  import { childByLocalName, elementChildren } from "../../ooxml/xml.js";
11
12
  import {
13
+ layerBandSizes,
12
14
  layerCellMargins,
15
+ layerCellStyleFormat,
13
16
  layerInsideBorders,
17
+ NO_BAND_SIZES,
14
18
  NO_CELL_MARGINS,
15
19
  NO_INSIDE_BORDERS,
20
+ readBandSizes,
16
21
  readCellMarginsOf,
22
+ readCellStyleFormat,
17
23
  readInsideBorders,
18
24
  readTableFormat
19
25
  } from "../tableFormatting.js";
@@ -35,23 +41,51 @@ function styleChain(id, sources) {
35
41
  return chain;
36
42
  }
37
43
  var EMPTY_STYLE_FORMAT = {
44
+ type: "paragraph",
38
45
  paragraph: {},
39
46
  run: {},
40
47
  table: {},
41
48
  tableInside: NO_INSIDE_BORDERS,
42
- tableCellMargins: NO_CELL_MARGINS
49
+ tableCellMargins: NO_CELL_MARGINS,
50
+ tableBands: NO_BAND_SIZES,
51
+ tableConditions: {}
43
52
  };
53
+ function conditionOf(el) {
54
+ const type = wAttr(el, "type");
55
+ return TABLE_STYLE_CONDITIONS.find((known) => known === type) ?? null;
56
+ }
57
+ function readConditionalFormat(el, themeFonts) {
58
+ const tblPr = childByLocalName(el, "tblPr");
59
+ return {
60
+ paragraph: readParagraphFormat(childByLocalName(el, "pPr")) ?? {},
61
+ run: readRunFormat(childByLocalName(el, "rPr"), themeFonts) ?? {},
62
+ table: readTableFormat(tblPr) ?? {},
63
+ cell: readCellStyleFormat(childByLocalName(el, "tcPr"), tblPr)
64
+ };
65
+ }
66
+ function readConditions(source, themeFonts) {
67
+ const conditions = {};
68
+ for (const el of source.tblStylePr) {
69
+ const type = conditionOf(el);
70
+ if (type !== null) conditions[type] = readConditionalFormat(el, themeFonts);
71
+ }
72
+ return conditions;
73
+ }
44
74
  function readStyleFormat(source, themeFonts) {
45
75
  return {
76
+ type: source.type,
46
77
  paragraph: readParagraphFormat(source.pPr) ?? {},
47
78
  run: readRunFormat(source.rPr, themeFonts) ?? {},
48
79
  table: readTableFormat(source.tblPr) ?? {},
49
80
  tableInside: readInsideBorders(source.tblPr),
50
- tableCellMargins: readCellMarginsOf(source.tblPr, "tblCellMar")
81
+ tableCellMargins: readCellMarginsOf(source.tblPr, "tblCellMar"),
82
+ tableBands: readBandSizes(source.tblPr),
83
+ tableConditions: readConditions(source, themeFonts)
51
84
  };
52
85
  }
53
86
  function layerStyleFormat(base, over) {
54
87
  return {
88
+ type: over.type,
55
89
  paragraph: layerParagraphValues(base.paragraph, over.paragraph),
56
90
  run: { ...base.run, ...over.run },
57
91
  table: { ...base.table, ...over.table },
@@ -59,12 +93,45 @@ function layerStyleFormat(base, over) {
59
93
  tableCellMargins: layerCellMargins(
60
94
  base.tableCellMargins,
61
95
  over.tableCellMargins
96
+ ),
97
+ tableBands: layerBandSizes(base.tableBands, over.tableBands),
98
+ tableConditions: layerConditions(
99
+ base.tableConditions,
100
+ over.tableConditions
62
101
  )
63
102
  };
64
103
  }
104
+ function layerConditionalFormat(base, over) {
105
+ return {
106
+ paragraph: layerParagraphValues(base.paragraph, over.paragraph),
107
+ run: { ...base.run, ...over.run },
108
+ table: { ...base.table, ...over.table },
109
+ cell: layerCellStyleFormat(base.cell, over.cell)
110
+ };
111
+ }
112
+ function layerConditions(base, over) {
113
+ const conditions = {};
114
+ for (const type of TABLE_STYLE_CONDITIONS) {
115
+ const under = base[type];
116
+ const above = over[type];
117
+ const format = under && above ? layerConditionalFormat(under, above) : above ?? under;
118
+ if (format) conditions[type] = format;
119
+ }
120
+ return conditions;
121
+ }
65
122
  function foldChain(chain, themeFonts) {
66
123
  return chain.map((source) => readStyleFormat(source, themeFonts)).reduce(layerStyleFormat, EMPTY_STYLE_FORMAT);
67
124
  }
125
+ var STYLE_TYPES = [
126
+ "paragraph",
127
+ "character",
128
+ "table",
129
+ "numbering"
130
+ ];
131
+ function styleTypeOf(el) {
132
+ const type = wAttr(el, "type");
133
+ return STYLE_TYPES.find((known) => known === type) ?? "paragraph";
134
+ }
68
135
  function readStyles(styles, themeFonts = NO_THEME_FONTS) {
69
136
  const sources = /* @__PURE__ */ new Map();
70
137
  for (const el of elementChildren(styles.documentElement)) {
@@ -72,10 +139,14 @@ function readStyles(styles, themeFonts = NO_THEME_FONTS) {
72
139
  const id = wAttr(el, "styleId");
73
140
  if (id === null || id.length === 0) continue;
74
141
  sources.set(id, {
142
+ type: styleTypeOf(el),
75
143
  basedOn: childValue(el, "basedOn"),
76
144
  pPr: childByLocalName(el, "pPr"),
77
145
  rPr: childByLocalName(el, "rPr"),
78
- tblPr: childByLocalName(el, "tblPr")
146
+ tblPr: childByLocalName(el, "tblPr"),
147
+ tblStylePr: elementChildren(el).filter(
148
+ (child) => child.localName === "tblStylePr"
149
+ )
79
150
  });
80
151
  }
81
152
  const table = /* @__PURE__ */ new Map();
@@ -84,6 +155,15 @@ function readStyles(styles, themeFonts = NO_THEME_FONTS) {
84
155
  }
85
156
  return table;
86
157
  }
158
+ function numberingStyleLinks(styles) {
159
+ const links = /* @__PURE__ */ new Map();
160
+ for (const [id, format] of styles) {
161
+ if (format.type !== "numbering") continue;
162
+ const numId = format.paragraph.numbering?.numId;
163
+ if (numId !== void 0) links.set(id, numId);
164
+ }
165
+ return links;
166
+ }
87
167
  function isDefaultStyle(el) {
88
168
  return ST_OnOff.parse(wAttr(el, "default")) === true;
89
169
  }
@@ -158,6 +238,7 @@ export {
158
238
  layerParagraphFormat,
159
239
  layerRunFormat,
160
240
  layerTableFormat,
241
+ numberingStyleLinks,
161
242
  paragraphStyleFormat,
162
243
  readParagraphStyles,
163
244
  readStyles,
@@ -45,9 +45,8 @@ export declare function relIdIn(prefix: string): string | null;
45
45
  *
46
46
  * A tag that already names one has only that value rewritten, so a link nobody retargeted comes
47
47
  * out as the very string it went in as. A tag that named none is given the attribute, which the
48
- * specification has supersede any `w:anchor` beside it, along with the namespace it lives in: the
49
- * body we write into is not always one that declares it, and declaring it again where it is
50
- * already bound to the same namespace changes nothing.
48
+ * specification has supersede any `w:anchor` beside it. The namespace it lives in is the part
49
+ * root's to bind, which `hyperlinkRefs` reports and `docx/exportDocx` sees to.
51
50
  */
52
51
  export declare function withRelId(prefix: string, relId: string): string;
53
52
  /** Which relationship each address goes out on while the body is being written */
@@ -62,6 +61,17 @@ export interface LinkRefs {
62
61
  }
63
62
  /** What a serializer called on its own, outside an export, has to work with */
64
63
  export declare const NO_LINK_REFS: LinkRefs;
64
+ /**
65
+ * The refs a body is written through, and what the part it went into has to declare afterwards.
66
+ *
67
+ * `withRelId` puts the attribute on exactly the tag that arrived without one, and that is the tag
68
+ * `relIdOf` is handed a null `was` for, so what is recorded here and what is written cannot come
69
+ * apart.
70
+ */
71
+ export interface LinkWriting extends LinkRefs {
72
+ /** Whether a link went out under an `r:id` its own opening tag did not arrive carrying */
73
+ addedRelId(): boolean;
74
+ }
65
75
  /**
66
76
  * Hands out the relationship for every address the body points at, adding one where the package
67
77
  * has none.
@@ -72,4 +82,4 @@ export declare const NO_LINK_REFS: LinkRefs;
72
82
  * relationship a link arrived on is kept wherever it still leads where the link now goes, so
73
83
  * retargeting one link in a document leaves every other link's XML alone.
74
84
  */
75
- export declare function hyperlinkRefs(relationships: RelationshipWriter): LinkRefs;
85
+ export declare function hyperlinkRefs(relationships: RelationshipWriter): LinkWriting;
@@ -34,7 +34,7 @@ function withRelId(prefix, relId) {
34
34
  return prefix.replace(REL_ID_VALUE, ` ${REL_ID_ATTR}="${relId}"`);
35
35
  }
36
36
  const name = "<w:hyperlink";
37
- return `${name} xmlns:r="${R_NS}" ${REL_ID_ATTR}="${relId}"${prefix.slice(name.length)}`;
37
+ return `${name} ${REL_ID_ATTR}="${relId}"${prefix.slice(name.length)}`;
38
38
  }
39
39
  var NO_LINK_REFS = { relIdOf: () => void 0 };
40
40
  function hyperlinkRefs(relationships) {
@@ -42,8 +42,11 @@ function hyperlinkRefs(relationships) {
42
42
  (rel) => rel.type === HYPERLINK_REL_TYPE && rel.external
43
43
  );
44
44
  const added = /* @__PURE__ */ new Map();
45
+ let attributeAdded = false;
45
46
  return {
47
+ addedRelId: () => attributeAdded,
46
48
  relIdOf: (href, was) => {
49
+ if (was === null) attributeAdded = true;
47
50
  const kept = external.find((rel) => rel.id === was);
48
51
  if (kept?.target === href) return was ?? void 0;
49
52
  const found = external.find((rel) => rel.target === href);
@@ -1,6 +1,10 @@
1
1
  // src/docx/importDocx.ts
2
2
  import { Fragment } from "prosemirror-model";
3
- import { parseNumbering } from "../numbering/parseNumbering.js";
3
+ import {
4
+ bindsWritingPrefix,
5
+ conformanceOf,
6
+ STRICT_OFFICE_DOCUMENT_REL
7
+ } from "../ooxml/conformance.js";
4
8
  import { DocxImportError } from "../ooxml/errors.js";
5
9
  import {
6
10
  childByLocalName,
@@ -23,17 +27,16 @@ import { fidelityNotesOf } from "./fidelity.js";
23
27
  import {
24
28
  formattingContextOf,
25
29
  NO_DOCUMENT_DEFAULTS,
26
- paragraphAttrsOf,
27
30
  readDocumentDefaults,
28
31
  readParagraphStyles,
29
- resolveParagraph,
30
- runMarkUnder
32
+ styledParagraph
31
33
  } from "./formatting.js";
32
34
  import { readHeadersFooters } from "./headersFooters.js";
33
35
  import { readLinkTargets } from "./hyperlink.js";
34
36
  import { buildParagraph } from "./importParagraph.js";
35
37
  import { buildTable } from "./importTable.js";
36
38
  import { readImageSources } from "./media.js";
39
+ import { NUMBERING_REL_TYPE } from "./newLists.js";
37
40
  import { readNotes } from "./notes.js";
38
41
  import { readPart, relatedPartPath } from "./packageParts.js";
39
42
  import { readBodyGeometry } from "./pageGeometry.js";
@@ -48,14 +51,20 @@ import {
48
51
  import { NO_THEME_FONTS, readThemeFonts } from "./theme.js";
49
52
  var OFFICE_DOCUMENT_REL = `${R_NS}/officeDocument`;
50
53
  var STYLES_REL = `${R_NS}/styles`;
51
- var NUMBERING_REL = `${R_NS}/numbering`;
52
54
  var THEME_REL = `${R_NS}/theme`;
53
55
  var SETTINGS_REL = `${R_NS}/settings`;
54
56
  function findMainPartPath(parts) {
55
- const target = readRelationships(parts, "_rels/.rels").find(
57
+ const relationships = readRelationships(parts, "_rels/.rels");
58
+ const target = relationships.find(
56
59
  (rel) => rel.type === OFFICE_DOCUMENT_REL
57
60
  )?.target;
58
61
  if (!target) {
62
+ if (relationships.some((rel) => rel.type === STRICT_OFFICE_DOCUMENT_REL)) {
63
+ throw new DocxImportError(
64
+ "unsupported-conformance",
65
+ "the package relates its main document part as an ECMA-376 Strict one"
66
+ );
67
+ }
59
68
  throw new DocxImportError(
60
69
  "missing-part",
61
70
  "no relationship pointing at the main document part"
@@ -63,6 +72,26 @@ function findMainPartPath(parts) {
63
72
  }
64
73
  return target.replace(/^\//, "");
65
74
  }
75
+ function assertWritableMainPart(root) {
76
+ if (conformanceOf(root) === "strict") {
77
+ throw new DocxImportError(
78
+ "unsupported-conformance",
79
+ "the main document part is written in the ECMA-376 Strict vocabulary"
80
+ );
81
+ }
82
+ if (conformanceOf(root) !== "transitional" || root.localName !== "document") {
83
+ throw new DocxImportError(
84
+ "unsupported-content",
85
+ "the main part is not a Transitional WordprocessingML document"
86
+ );
87
+ }
88
+ if (!bindsWritingPrefix(root)) {
89
+ throw new DocxImportError(
90
+ "unsupported-content",
91
+ "the main document part binds WordprocessingML to a prefix other than w"
92
+ );
93
+ }
94
+ }
66
95
  function buildBlock(el, srcId, sources, context) {
67
96
  if (el.localName === "bookmarkStart" || el.localName === "bookmarkEnd") {
68
97
  return docxSchema.nodes.bookmarkBlock.create({
@@ -75,43 +104,18 @@ function buildBlock(el, srcId, sources, context) {
75
104
  if (paragraph) return paragraph;
76
105
  }
77
106
  if (el.localName === "tbl") {
78
- const table = buildTable(
79
- el,
80
- srcId,
81
- sources,
82
- context.styles,
83
- context.defaultTableStyleId
84
- );
107
+ const table = buildTable(el, srcId, sources, context);
85
108
  if (table) return table;
86
109
  }
87
110
  return docxSchema.nodes.docxRaw.create({ srcId, name: el.nodeName });
88
111
  }
89
- function styledParagraph(node, context) {
90
- const pPr = node.attrs.pPr;
91
- const paragraph = resolveParagraph(
92
- typeof pPr === "string" ? pPr : null,
93
- context
94
- );
95
- const inline = node.children.map((child) => {
96
- const mark = runMarkUnder(
97
- child.marks.find((entry) => entry.type === docxSchema.marks.run) ?? null,
98
- child.isText,
99
- paragraph,
100
- context
101
- );
102
- return mark ? child.mark(mark.addToSet(child.marks)) : child;
103
- });
104
- return node.type.create(
105
- { ...node.attrs, ...paragraphAttrsOf(paragraph) },
106
- Fragment.fromArray(inline),
107
- node.marks
108
- );
109
- }
110
112
  function withStyleFormats(node, context) {
111
113
  if (node.type === docxSchema.nodes.paragraph) {
112
114
  return styledParagraph(node, context);
113
115
  }
114
- if (node.childCount === 0) return node;
116
+ if (node.childCount === 0 || node.type === docxSchema.nodes.table) {
117
+ return node;
118
+ }
115
119
  const children = node.children.map(
116
120
  (child) => withStyleFormats(child, context)
117
121
  );
@@ -158,6 +162,7 @@ function readDocx(input) {
158
162
  const { text: source, hadBom } = decodeUtf8(mainPart);
159
163
  const scanned = scanBody(source);
160
164
  const dom = parseXml(source);
165
+ assertWritableMainPart(dom.documentElement);
161
166
  const body = childByLocalName(dom.documentElement, "body");
162
167
  if (!body) {
163
168
  throw new DocxImportError("missing-body", "document has no w:body");
@@ -178,7 +183,11 @@ function readDocx(input) {
178
183
  );
179
184
  const settingsDom = settingsXml === null ? null : parseXml(settingsXml);
180
185
  const defaultTabStopPt = readDefaultTabStop(settingsDom) ?? DEFAULT_TAB_STOP_PT;
181
- const numberingPartPath = relatedPartPath(parts, mainPartPath, NUMBERING_REL);
186
+ const numberingPartPath = relatedPartPath(
187
+ parts,
188
+ mainPartPath,
189
+ NUMBERING_REL_TYPE
190
+ );
182
191
  const themeXml = readPart(
183
192
  parts,
184
193
  relatedPartPath(parts, mainPartPath, THEME_REL)
@@ -187,7 +196,7 @@ function readDocx(input) {
187
196
  const numberingXml = readPart(parts, numberingPartPath);
188
197
  const formatting = formattingContextOf(
189
198
  stylesDom,
190
- parseNumbering(numberingXml),
199
+ numberingXml,
191
200
  themeFonts,
192
201
  readCompatSettings(settingsDom)
193
202
  );
@@ -3,7 +3,7 @@
3
3
  * values for display. Unsupported grids return null so the caller can preserve their source XML.
4
4
  */
5
5
  import type { Node as PMNode } from "prosemirror-model";
6
- import { type StyleTable } from "./formatting";
6
+ import { type FormattingContext } from "./formatting";
7
7
  import { type ImportSources } from "./importParagraph";
8
8
  /** Moves a `<w:tbl>` into a table node. null if it cannot be modelled */
9
- export declare function buildTable(el: Element, srcId: string | null, sources?: ImportSources, styles?: StyleTable, defaultTableStyleId?: string | null): PMNode | null;
9
+ export declare function buildTable(el: Element, srcId: string | null, sources?: ImportSources, context?: FormattingContext): PMNode | null;
@@ -1,8 +1,4 @@
1
1
  // src/docx/importTable.ts
2
- import {
3
- toCellMargins,
4
- toInsideBorders
5
- } from "../model/format.js";
6
2
  import { childValue, wAttr } from "../ooxml/units.js";
7
3
  import {
8
4
  attrString,
@@ -13,7 +9,10 @@ import {
13
9
  import { docxSchema } from "../schema/index.js";
14
10
  import {
15
11
  layerTableFormat,
16
- NO_STYLES
12
+ NO_FORMATTING,
13
+ styledParagraph,
14
+ tableStyleAttrs,
15
+ tableStyleFor
17
16
  } from "./formatting.js";
18
17
  import {
19
18
  buildParagraph,
@@ -21,18 +20,22 @@ import {
21
20
  } from "./importParagraph.js";
22
21
  import { readSdtWrapper } from "./sdt.js";
23
22
  import {
24
- cellBorderDefaults,
25
- gridEdgesOf,
23
+ cellConditionsOf,
24
+ cellDefaultsFor,
25
+ layerBandSizes,
26
26
  layerCellMargins,
27
27
  layerInsideBorders,
28
+ NO_BAND_SIZES,
28
29
  NO_CELL_MARGINS,
29
30
  NO_INSIDE_BORDERS,
31
+ readBandSizes,
30
32
  readCellFormat,
31
33
  readCellMarginsOf,
32
34
  readGridCols,
33
35
  readInsideBorders,
34
36
  readRowFormat,
35
37
  readTableFormat,
38
+ readTableLook,
36
39
  readTableWidth,
37
40
  tblStyleIdOf
38
41
  } from "./tableFormatting.js";
@@ -162,37 +165,31 @@ function gridWidthOf(rows) {
162
165
  const first = widths[0];
163
166
  return widths.every((width) => width === first) ? first : null;
164
167
  }
165
- function buildCellBlock(el, sources) {
168
+ function buildCellBlock(el, sources, context, placement) {
166
169
  if (el.localName === "p") {
167
170
  const paragraph = buildParagraph(el, null, sources);
168
- if (paragraph) return paragraph;
171
+ if (paragraph) return styledParagraph(paragraph, context, placement);
169
172
  }
170
173
  return docxSchema.nodes.rawBlock.create({
171
174
  xml: serializeXml(el),
172
175
  name: el.nodeName
173
176
  });
174
177
  }
175
- function cellBorderDefaultsFor(draft, lines) {
176
- return cellBorderDefaults(
177
- gridEdgesOf(
178
- {
179
- top: draft.row,
180
- bottom: draft.row + draft.rowspan,
181
- left: draft.col,
182
- right: draft.col + draft.colspan
183
- },
184
- lines
185
- ),
186
- lines.outer,
187
- lines.inside
188
- );
178
+ function cellRect(draft) {
179
+ return {
180
+ top: draft.row,
181
+ bottom: draft.row + draft.rowspan,
182
+ left: draft.col,
183
+ right: draft.col + draft.colspan
184
+ };
189
185
  }
190
- function buildCell(draft, lines, sources) {
186
+ function buildCell(draft, table, sources, context) {
191
187
  const tcPr = childByLocalName(draft.el, "tcPr");
188
+ const defaults = cellDefaultsFor(cellRect(draft), table.grid, table.sources);
192
189
  const blocks = [];
193
190
  for (const child of elementChildren(draft.el)) {
194
191
  if (child.localName === "tcPr") continue;
195
- blocks.push(buildCellBlock(child, sources));
192
+ blocks.push(buildCellBlock(child, sources, context, defaults.placement));
196
193
  }
197
194
  if (blocks.length === 0) return null;
198
195
  return docxSchema.nodes.tableCell.create(
@@ -203,11 +200,7 @@ function buildCell(draft, lines, sources) {
203
200
  tcAttrs: attrString(draft.el),
204
201
  tcPr: tcPr ? serializeXml(tcPr) : null,
205
202
  tcW: readTableWidth(tcPr, "tcW"),
206
- format: readCellFormat(
207
- tcPr,
208
- cellBorderDefaultsFor(draft, lines),
209
- lines.margins
210
- ),
203
+ format: readCellFormat(tcPr, defaults),
211
204
  sdtPrefix: draft.control?.prefix ?? null,
212
205
  sdtContentsLocked: draft.control?.contentsLocked ?? false,
213
206
  sdtDeletionLocked: draft.control?.deletionLocked ?? false
@@ -215,10 +208,10 @@ function buildCell(draft, lines, sources) {
215
208
  blocks
216
209
  );
217
210
  }
218
- function buildRow(row, drafts, lines, sources) {
211
+ function buildRow(row, drafts, table, sources, context) {
219
212
  const cells = [];
220
213
  for (const draft of drafts) {
221
- const cell = buildCell(draft, lines, sources);
214
+ const cell = buildCell(draft, table, sources, context);
222
215
  if (!cell) return null;
223
216
  cells.push(cell);
224
217
  }
@@ -233,11 +226,7 @@ function buildRow(row, drafts, lines, sources) {
233
226
  cells
234
227
  );
235
228
  }
236
- function tableStyleOf(tblPr, styles, defaultTableStyleId) {
237
- const styleId = tblStyleIdOf(tblPr);
238
- return (styleId !== null ? styles.get(styleId) : void 0) ?? (defaultTableStyleId !== null ? styles.get(defaultTableStyleId) : void 0);
239
- }
240
- function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, styles = NO_STYLES, defaultTableStyleId = null) {
229
+ function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, context = NO_FORMATTING) {
241
230
  const parts = readTableParts(el);
242
231
  if (!parts) return null;
243
232
  const gridCols = readGridCols(parts.tblGrid);
@@ -246,27 +235,38 @@ function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, styles = NO_STYLES,
246
235
  if (gridCols.length > 0 && gridCols.length !== width) return null;
247
236
  const drafts = resolveVerticalMerges(parts.rows, width);
248
237
  if (!drafts) return null;
249
- const style = tableStyleOf(parts.tblPr, styles, defaultTableStyleId);
238
+ const styleId = tblStyleIdOf(parts.tblPr);
239
+ const style = tableStyleFor(styleId, context);
250
240
  const tableFormat = layerTableFormat(
251
241
  style?.table ?? {},
252
242
  readTableFormat(parts.tblPr)
253
243
  );
254
- const lines = {
255
- rows: parts.rows.length,
256
- cols: width,
257
- outer: tableFormat,
258
- inside: layerInsideBorders(
259
- style?.tableInside ?? NO_INSIDE_BORDERS,
260
- readInsideBorders(parts.tblPr)
261
- ),
262
- margins: layerCellMargins(
263
- style?.tableCellMargins ?? NO_CELL_MARGINS,
264
- readCellMarginsOf(parts.tblPr, "tblCellMar")
265
- )
244
+ const bands = layerBandSizes(
245
+ style?.tableBands ?? NO_BAND_SIZES,
246
+ readBandSizes(parts.tblPr)
247
+ );
248
+ const conditions = cellConditionsOf(style?.tableConditions ?? {});
249
+ const table = {
250
+ grid: { rows: parts.rows.length, cols: width },
251
+ sources: {
252
+ outer: tableFormat,
253
+ inside: layerInsideBorders(
254
+ style?.tableInside ?? NO_INSIDE_BORDERS,
255
+ readInsideBorders(parts.tblPr)
256
+ ),
257
+ margins: layerCellMargins(
258
+ style?.tableCellMargins ?? NO_CELL_MARGINS,
259
+ readCellMarginsOf(parts.tblPr, "tblCellMar")
260
+ ),
261
+ look: readTableLook(parts.tblPr),
262
+ bands,
263
+ conditions,
264
+ styleId
265
+ }
266
266
  };
267
267
  const rows = [];
268
268
  for (const [index, row] of parts.rows.entries()) {
269
- const built = buildRow(row, drafts[index], lines, sources);
269
+ const built = buildRow(row, drafts[index], table, sources, context);
270
270
  if (!built) return null;
271
271
  rows.push(built);
272
272
  }
@@ -278,10 +278,7 @@ function buildTable(el, srcId, sources = NO_IMPORT_SOURCES, styles = NO_STYLES,
278
278
  tblW: readTableWidth(parts.tblPr, "tblW"),
279
279
  gridCols,
280
280
  gridChange: parts.gridChange,
281
- format: tableFormat,
282
- // The cells need these again whenever an edit derives their display values afresh
283
- styleInside: toInsideBorders(style?.tableInside),
284
- styleCellMargins: toCellMargins(style?.tableCellMargins)
281
+ ...tableStyleAttrs(parts.tblPr, context)
285
282
  },
286
283
  rows
287
284
  );
@@ -1,5 +1,5 @@
1
1
  // src/docx/invariants.ts
2
- import { spanCount } from "../model/format.js";
2
+ import { spanCount, toParagraphFormat } from "../model/format.js";
3
3
  import {
4
4
  attributeByLocalName,
5
5
  parseXml,
@@ -22,7 +22,7 @@ import { unrecordedAuthors } from "./comments/people.js";
22
22
  import { currentCommentBodies } from "./comments/writing.js";
23
23
  import { identityProblems } from "./identities.js";
24
24
  import { insertedImageSrcs } from "./media.js";
25
- import { newNumIds, numberingPartOf } from "./newLists.js";
25
+ import { canDefineNewList, newNumIds, startedLists } from "./newLists.js";
26
26
  import { CONTENT_TYPES_PATH } from "./packageParts.js";
27
27
  import { lostOriginal } from "./serializeBlock.js";
28
28
  import {
@@ -160,17 +160,24 @@ var uniqueIdentities = {
160
160
  return identityProblems(doc);
161
161
  }
162
162
  };
163
- var numberingPart = {
164
- name: "numberingPart",
163
+ var listDefinitions = {
164
+ name: "listDefinitions",
165
165
  check(doc, session) {
166
- if (numberingPartOf(session) !== null) return [];
167
- if (newNumIds(doc, session).length === 0) return [];
168
- return [
169
- {
170
- code: "missing-numbering-part",
171
- message: "cannot add a new list to a document that has no numbering.xml"
172
- }
173
- ];
166
+ const undefinedIds = new Set(startedLists(doc, session).unregistered);
167
+ if (undefinedIds.size === 0) return [];
168
+ const problems = [];
169
+ doc.descendants((node, pos) => {
170
+ if (node.type.name !== "paragraph") return true;
171
+ const numId = toParagraphFormat(node.attrs.format)?.numbering?.numId;
172
+ if (numId === void 0 || !undefinedIds.delete(numId)) return false;
173
+ problems.push({
174
+ code: "unsupported-content",
175
+ message: `the list numbered ${numId} has no definition to be written`,
176
+ pos
177
+ });
178
+ return false;
179
+ });
180
+ return problems;
174
181
  }
175
182
  };
176
183
  function addsCommentsPart(doc, session) {
@@ -198,6 +205,12 @@ var mediaContentTypes = {
198
205
  message: `cannot add an image to a package that has no ${CONTENT_TYPES_PATH}`
199
206
  });
200
207
  }
208
+ if (!canDefineNewList(session) && newNumIds(doc, session).length > 0) {
209
+ problems.push({
210
+ code: "missing-content-types",
211
+ message: `cannot add a part to a package that has no ${CONTENT_TYPES_PATH}`
212
+ });
213
+ }
201
214
  if (addsCommentsPart(doc, session)) {
202
215
  problems.push({
203
216
  code: "missing-content-types",
@@ -230,7 +243,7 @@ var EXPORT_INVARIANTS = [
230
243
  tableGrids,
231
244
  preservedOriginals,
232
245
  uniqueIdentities,
233
- numberingPart,
246
+ listDefinitions,
234
247
  mediaContentTypes,
235
248
  commentPartRoots
236
249
  ];