diff --git a/.gitignore b/.gitignore index 35ae2af..c1d6137 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,7 @@ node_modules *.docx !fixtures/**/*.docx output/*.docx -output/*.json +output/**/*.json output/*.xml vrt/screenshot/actual vrt/screenshot/diff @@ -16,5 +16,4 @@ vrt/report.html reg.json docx-core/tests/output/*.docx docx-wasm/*.tgz - -docx-core/tests/output/*.json \ No newline at end of file +docx-core/tests/output/*.json diff --git a/docx-core/src/documents/elements/table_cell_property.rs b/docx-core/src/documents/elements/table_cell_property.rs index 4426442..ffbd8ae 100644 --- a/docx-core/src/documents/elements/table_cell_property.rs +++ b/docx-core/src/documents/elements/table_cell_property.rs @@ -1,3 +1,4 @@ +use wasm_bindgen::prelude::*; use serde::Serialize; use super::*; @@ -5,6 +6,7 @@ use crate::documents::BuildXML; use crate::types::*; use crate::xml_builder::*; +#[wasm_bindgen] #[derive(Serialize, Debug, Clone, PartialEq)] #[serde(rename_all = "camelCase")] pub struct TableCellProperty { diff --git a/docx-core/src/documents/elements/table_of_contents.rs b/docx-core/src/documents/elements/table_of_contents.rs index 85d0b60..00e8eed 100644 --- a/docx-core/src/documents/elements/table_of_contents.rs +++ b/docx-core/src/documents/elements/table_of_contents.rs @@ -10,9 +10,10 @@ use crate::xml_builder::*; pub struct TableOfContents { pub instr: InstrToC, pub items: Vec, - // pub disable_auto_items: bool, + pub auto: bool, pub dirty: bool, pub alias: Option, + pub page_ref_placeholder: Option, } impl TableOfContents { @@ -45,10 +46,10 @@ impl TableOfContents { self } - // pub fn disable_auto_items(mut self) -> Self { - // self.disable_auto_items = true; - // self - // } + pub fn auto(mut self) -> Self { + self.auto = true; + self + } pub fn dirty(mut self) -> Self { self.dirty = true; @@ -88,6 +89,9 @@ impl BuildXML for TableOfContents { let mut item = item.clone(); item.instr = self.instr.clone(); item.dirty = self.dirty; + if item.page_ref.is_none() { + item.page_ref = self.page_ref_placeholder.clone(); + } item }) .collect(); diff --git a/docx-core/src/documents/elements/table_property.rs b/docx-core/src/documents/elements/table_property.rs index 9a74a33..fadbfd4 100644 --- a/docx-core/src/documents/elements/table_property.rs +++ b/docx-core/src/documents/elements/table_property.rs @@ -1,3 +1,4 @@ +use wasm_bindgen::prelude::*; use serde::Serialize; use super::*; @@ -5,6 +6,7 @@ use crate::documents::BuildXML; use crate::types::*; use crate::xml_builder::*; +#[wasm_bindgen] #[derive(Debug, Clone, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct TableProperty { diff --git a/docx-core/src/documents/mod.rs b/docx-core/src/documents/mod.rs index 0a9419d..feebc68 100644 --- a/docx-core/src/documents/mod.rs +++ b/docx-core/src/documents/mod.rs @@ -445,7 +445,7 @@ impl Docx { } for (i, toc) in tocs { - if toc.items.is_empty() { + if toc.items.is_empty() && toc.auto { let children = update_document_by_toc(self.document.children, &self.styles, toc, i); self.document.children = children; } @@ -894,6 +894,16 @@ fn update_document_by_toc( paragraph = paragraph.wrap_by_bookmark(generate_bookmark_id(), &toc_key); } + } else { + // If no heading range is specified, all heading levels used in the document are listed. + let toc_key = TocKey::generate(); + items.push( + TableOfContentsItem::new() + .text(paragraph.raw_text()) + .toc_key(&toc_key) + .level(*heading_level), + ); + paragraph = paragraph.wrap_by_bookmark(generate_bookmark_id(), &toc_key); } if let Some((_min, _max)) = toc.instr.tc_field_level_range { diff --git a/docx-wasm/js/index.ts b/docx-wasm/js/index.ts index 2df59a4..dc3fb50 100644 --- a/docx-wasm/js/index.ts +++ b/docx-wasm/js/index.ts @@ -4,6 +4,7 @@ import { Delete } from "./delete"; import { Hyperlink } from "./hyperlink"; import { DeleteText } from "./delete-text"; import { Table } from "./table"; +import { TableOfContents } from "./table-of-contents"; import { TableCell, toTextDirectionWasmType } from "./table-cell"; import { BorderType } from "./border"; import { Run, RunFonts } from "./run"; @@ -18,6 +19,7 @@ import { BookmarkStart } from "./bookmark-start"; import { BookmarkEnd } from "./bookmark-end"; import { Settings } from "./settings"; import { DocProps } from "./doc-props"; +import { Style } from "./style"; import { Styles } from "./styles"; import { WebExtension } from "./webextension"; import { Footer } from "./footer"; @@ -75,7 +77,13 @@ const convertWidthType = (t: WidthType) => { }; export class Docx { - children: (Paragraph | Table | BookmarkStart | BookmarkEnd)[] = []; + children: ( + | Paragraph + | Table + | BookmarkStart + | BookmarkEnd + | TableOfContents + )[] = []; hasNumberings = false; abstractNumberings: AbstractNumbering[] = []; numberings: Numbering[] = []; @@ -87,6 +95,16 @@ export class Docx { customItems: { id: string; xml: string }[] = []; styles = new Styles(); + addTableOfContents(t: TableOfContents) { + this.children.push(t); + return this; + } + + addStyle(s: Style) { + this.styles.styles.push(s); + return this; + } + addParagraph(p: Paragraph) { if (p.hasNumberings) { this.hasNumberings = true; @@ -876,6 +894,8 @@ export class Docx { docx = docx.add_bookmark_start(child.id, child.name); } else if (child instanceof BookmarkEnd) { docx = docx.add_bookmark_end(child.id); + } else if (child instanceof TableOfContents) { + docx = docx.add_table_of_contents(child.buildWasmObject()); } }); @@ -1039,6 +1059,10 @@ export class Docx { docx = docx.doc_grid(type, linePitch, charSpace); } + for (const s of this.styles?.styles) { + docx = docx.add_style(s.buildWasmObject()); + } + if (this.styles?.docDefaults) { if (this.styles.docDefaults.runProperty?.fonts) { const fonts = this.buildRunFonts( @@ -1126,6 +1150,8 @@ export * from "./table"; export * from "./table-cell"; export * from "./table-cell-border"; export * from "./table-cell-borders"; +export * from "./table-of-contents"; +export * from "./table-of-contents-item"; export * from "./table-row"; export * from "./run"; export * from "./text"; diff --git a/docx-wasm/js/style.ts b/docx-wasm/js/style.ts index faa7bec..5d77428 100644 --- a/docx-wasm/js/style.ts +++ b/docx-wasm/js/style.ts @@ -1,3 +1,5 @@ +import * as wasm from "./pkg"; + import { createDefaultTableCellMargins, TableProperty } from "./table"; import { RunProperty, createDefaultRunProperty } from "./run"; import { createDefaultParagraphProperty, ParagraphProperty } from "./paragraph"; @@ -31,5 +33,33 @@ export class Style { this._basedOn = null; } - // TODO: Add setter + name = (n: string) => { + this._name = n; + return this; + }; + + buildStyleType = () => { + switch (this._styleType) { + case "character": + return wasm.StyleType.Character; + case "numbering": + return wasm.StyleType.Numbering; + case "paragraph": + return wasm.StyleType.Paragraph; + case "table": + return wasm.StyleType.Table; + } + return wasm.StyleType.Paragraph; + }; + + buildWasmObject = () => { + const styleType = this.buildStyleType(); + let s = wasm.createStyle(this._styleId, styleType); + + if (this._name) { + s = s.name(this._name); + } + + return s; + }; } diff --git a/docx-wasm/js/styles.ts b/docx-wasm/js/styles.ts index 170a0b0..f439ba6 100644 --- a/docx-wasm/js/styles.ts +++ b/docx-wasm/js/styles.ts @@ -3,7 +3,7 @@ import { DocDefaults } from "./doc-defaults"; import { RunFonts } from "./run"; export class Styles { - styles: Style[]; + styles: Style[] = []; docDefaults = new DocDefaults(); defaultSize(size: number) { diff --git a/docx-wasm/js/table-of-contents-item.ts b/docx-wasm/js/table-of-contents-item.ts new file mode 100644 index 0000000..aeedff0 --- /dev/null +++ b/docx-wasm/js/table-of-contents-item.ts @@ -0,0 +1,49 @@ +import * as wasm from "./pkg/docx_wasm"; + +export class TableOfContentsItem { + _text = ""; + _tocKey = ""; + _level = 1; + _pageRef = ""; + + text = (text: string) => { + this._text = text; + return this; + }; + + tocKey = (key: string) => { + this._tocKey = key; + return this; + }; + + level = (l: number) => { + this._level = l; + return this; + }; + + pageRef = (r: string) => { + this._pageRef = r; + return this; + }; + + buildWasmObject = () => { + let item = wasm.createTableOfContentsItem(); + if (this._text) { + item = item.text(this._text); + } + + if (this._tocKey) { + item = item.toc_key(this._tocKey); + } + + if (this._level) { + item = item.level(this._level); + } + + if (this._pageRef) { + item = item.page_ref(this._pageRef); + } + + return item; + }; +} diff --git a/docx-wasm/js/table-of-contents.ts b/docx-wasm/js/table-of-contents.ts new file mode 100644 index 0000000..704b2e8 --- /dev/null +++ b/docx-wasm/js/table-of-contents.ts @@ -0,0 +1,84 @@ +import * as wasm from "./pkg"; + +import { TableOfContentsItem } from "./table-of-contents-item"; + +export class TableOfContents { + _headingStylesRange: [number, number] | null = null; + _hyperlink = false; + _alias = ""; + _auto = false; + _dirty = false; + _items: TableOfContentsItem[] = []; + _pageRefPlaceholder = ""; + + headingStylesRange = (r: [number, number]) => { + this._headingStylesRange = r; + return this; + }; + + hyperlink = () => { + this._hyperlink = true; + return this; + }; + + alias = (alias: string) => { + this._alias = alias; + return this; + }; + + pageRefPlaceholder = (placeholder: string) => { + this._pageRefPlaceholder = placeholder; + return this; + }; + + auto = () => { + this._auto = true; + return this; + }; + + dirty = () => { + this._dirty = true; + return this; + }; + + addItem = (item: TableOfContentsItem) => { + this._items.push(item); + return this; + }; + + buildWasmObject = () => { + let toc = wasm.createTableOfContents(); + if (this._headingStylesRange) { + toc = toc.heading_styles_range( + this._headingStylesRange[0], + this._headingStylesRange[1] + ); + } + + if (this._hyperlink) { + toc = toc.hyperlink(); + } + + if (this._alias) { + toc = toc.alias(this._alias); + } + + if (this._auto) { + toc = toc.auto(); + } + + if (this._dirty) { + toc = toc.dirty(); + } + + if (this._pageRefPlaceholder) { + toc = toc.page_ref_placeholder(this._pageRefPlaceholder); + } + + for (const item of this._items) { + toc = toc.add_item(item.buildWasmObject()); + } + + return toc; + }; +} diff --git a/docx-wasm/src/doc.rs b/docx-wasm/src/doc.rs index c85799b..0a9fadc 100644 --- a/docx-wasm/src/doc.rs +++ b/docx-wasm/src/doc.rs @@ -18,6 +18,11 @@ impl Docx { self } + pub fn add_table_of_contents(mut self, t: TableOfContents) -> Self { + self.0 = self.0.add_table_of_contents(t.take()); + self + } + pub fn add_bookmark_start(mut self, id: usize, name: &str) -> Self { self.0 = self.0.add_bookmark_start(id, name); self @@ -118,6 +123,11 @@ impl Docx { self } + pub fn add_style(mut self, s: Style) -> Self { + self.0.styles = self.0.styles.add_style(s.take()); + self + } + pub fn default_size(mut self, size: usize) -> Self { self.0.styles = self.0.styles.default_size(size); self diff --git a/docx-wasm/src/lib.rs b/docx-wasm/src/lib.rs index 42bc7ed..f87beb2 100644 --- a/docx-wasm/src/lib.rs +++ b/docx-wasm/src/lib.rs @@ -16,9 +16,12 @@ mod paragraph; mod reader; mod run; mod run_fonts; +mod style; mod table; mod table_cell; mod table_cell_border; +mod table_of_contents; +mod table_of_contents_item; mod table_row; mod web_extension; @@ -40,8 +43,11 @@ pub use paragraph::*; pub use reader::*; pub use run::*; pub use run_fonts::*; +pub use style::*; pub use table::*; pub use table_cell::*; pub use table_cell_border::*; +pub use table_of_contents::*; +pub use table_of_contents_item::*; pub use table_row::*; pub use web_extension::*; diff --git a/docx-wasm/src/style.rs b/docx-wasm/src/style.rs new file mode 100644 index 0000000..820e6ef --- /dev/null +++ b/docx-wasm/src/style.rs @@ -0,0 +1,99 @@ +use super::*; +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +#[derive(Debug)] +pub struct Style(docx_rs::Style); + +#[wasm_bindgen(js_name = createStyle)] +pub fn create_style(style_id: &str, style_type: docx_rs::StyleType) -> Style { + Style(docx_rs::Style::new(style_id, style_type)) +} + +#[wasm_bindgen] +impl Style { + pub fn name(mut self, name: &str) -> Self { + self.0.name = docx_rs::Name::new(name); + self + } + + pub fn based_on(mut self, base: &str) -> Self { + self.0.based_on = Some(docx_rs::BasedOn::new(base)); + self + } + + pub fn size(mut self, size: usize) -> Self { + self.0.run_property = self.0.run_property.size(size); + self + } + + pub fn color(mut self, color: &str) -> Self { + self.0.run_property = self.0.run_property.color(color); + self + } + + pub fn highlight(mut self, color: &str) -> Self { + self.0.run_property = self.0.run_property.highlight(color); + self + } + + pub fn bold(mut self) -> Self { + self.0.run_property = self.0.run_property.bold(); + self + } + + pub fn italic(mut self) -> Self { + self.0.run_property = self.0.run_property.italic(); + self + } + + pub fn underline(mut self, line_type: &str) -> Self { + self.0.run_property = self.0.run_property.underline(line_type); + self + } + + pub fn vanish(mut self) -> Self { + self.0.run_property = self.0.run_property.vanish(); + self + } + + pub fn align(mut self, alignment_type: docx_rs::AlignmentType) -> Self { + self.0.paragraph_property = self.0.paragraph_property.align(alignment_type); + self + } + + pub fn indent( + mut self, + left: i32, + special_indent_kind: Option, + special_indent_size: Option, + ) -> Self { + let special_indent = create_special_indent(special_indent_kind, special_indent_size); + self.0.paragraph_property = + self.0 + .paragraph_property + .indent(Some(left), special_indent, None, None); + self + } + + pub fn outline_lvl(mut self, l: usize) -> Self { + self.0.paragraph_property = self.0.paragraph_property.outline_lvl(l); + self + } + + pub fn table_property(mut self, p: docx_rs::TableProperty) -> Self { + self.0.table_property = p; + self + } + + pub fn table_cell_property(mut self, p: docx_rs::TableCellProperty) -> Self { + self.0.table_cell_property = p; + self + } +} + +impl Style { + pub fn take(self) -> docx_rs::Style { + self.0 + } +} diff --git a/docx-wasm/src/table_of_contents.rs b/docx-wasm/src/table_of_contents.rs new file mode 100644 index 0000000..409febe --- /dev/null +++ b/docx-wasm/src/table_of_contents.rs @@ -0,0 +1,56 @@ +use wasm_bindgen::prelude::*; + +use super::*; + +#[wasm_bindgen] +#[derive(Debug)] +pub struct TableOfContents(docx_rs::TableOfContents); + +#[wasm_bindgen(js_name = createTableOfContents)] +pub fn create_table_of_contents() -> TableOfContents { + TableOfContents(docx_rs::TableOfContents::new()) +} + +impl TableOfContents { + pub fn take(self) -> docx_rs::TableOfContents { + self.0 + } +} + +#[wasm_bindgen] +impl TableOfContents { + pub fn heading_styles_range(mut self, start: usize, end: usize) -> Self { + self.0.instr = self.0.instr.heading_styles_range(start, end); + self + } + + pub fn hyperlink(mut self) -> Self { + self.0.instr = self.0.instr.hyperlink(); + self + } + + pub fn alias(mut self, a: &str) -> Self { + self.0.alias = Some(a.into()); + self + } + + pub fn page_ref_placeholder(mut self, a: &str) -> Self { + self.0.page_ref_placeholder = Some(a.into()); + self + } + + pub fn add_item(mut self, t: TableOfContentsItem) -> Self { + self.0.items.push(t.take()); + self + } + + pub fn auto(mut self) -> Self { + self.0.auto = true; + self + } + + pub fn dirty(mut self) -> Self { + self.0.dirty = true; + self + } +} diff --git a/docx-wasm/src/table_of_contents_item.rs b/docx-wasm/src/table_of_contents_item.rs new file mode 100644 index 0000000..cadebaa --- /dev/null +++ b/docx-wasm/src/table_of_contents_item.rs @@ -0,0 +1,39 @@ +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +#[derive(Debug)] +pub struct TableOfContentsItem(docx_rs::TableOfContentsItem); + +#[wasm_bindgen(js_name = createTableOfContentsItem)] +pub fn create_table_of_contents_item() -> TableOfContentsItem { + TableOfContentsItem(docx_rs::TableOfContentsItem::new()) +} + +impl TableOfContentsItem { + pub fn take(self) -> docx_rs::TableOfContentsItem { + self.0 + } +} + +#[wasm_bindgen] +impl TableOfContentsItem { + pub fn text(mut self, a: &str) -> Self { + self.0.text = a.into(); + self + } + + pub fn toc_key(mut self, a: &str) -> Self { + self.0.toc_key = a.into(); + self + } + + pub fn level(mut self, l: usize) -> Self { + self.0.level = l; + self + } + + pub fn page_ref(mut self, a: &str) -> Self { + self.0.page_ref = Some(a.into()); + self + } +} diff --git a/docx-wasm/test/__snapshots__/index.test.js.snap b/docx-wasm/test/__snapshots__/index.test.js.snap index 99b12b2..cfb38aa 100644 --- a/docx-wasm/test/__snapshots__/index.test.js.snap +++ b/docx-wasm/test/__snapshots__/index.test.js.snap @@ -23628,6 +23628,66 @@ Object { } `; +exports[`writer should write ToC with items 1`] = ` +" + + + + + +" +`; + +exports[`writer should write ToC with items 2`] = ` +" + + + + + + + +TOCHello!!PAGEREF _Toc00000000 \\\\h2 + + +WorldPAGEREF _Toc00000001 \\\\h3 + + +Hello!! +World +" +`; + +exports[`writer should write auto items ToC 1`] = ` +" + + + + + +" +`; + +exports[`writer should write auto items ToC 2`] = ` +" + + + + + + + +TOCHello!!PAGEREF _Toc00000000 \\\\h1 + + +WorldPAGEREF _Toc00000001 \\\\h1 + + +Hello!! +World +" +`; + exports[`writer should write cell shading 1`] = ` " @@ -23753,6 +23813,27 @@ exports[`writer should write default font 3`] = ` " `; +exports[`writer should write dirty and disable auto items ToC 1`] = ` +" + + + + + +" +`; + +exports[`writer should write dirty and disable auto items ToC 2`] = ` +" + + +TOC + +Hello!! +World +" +`; + exports[`writer should write doc grid 1`] = ` " diff --git a/docx-wasm/test/index.test.js b/docx-wasm/test/index.test.js index 6e244ec..8a3ca8d 100644 --- a/docx-wasm/test/index.test.js +++ b/docx-wasm/test/index.test.js @@ -18,14 +18,14 @@ describe("reader", () => { test("should read tr2bl docx", () => { const buffer = readFileSync("../fixtures/tr2bl/tr2bl.docx"); const json = w.readDocx(buffer); - writeFileSync("../output/tr2bl.json", JSON.stringify(json, null, 2)); + writeFileSync("../output/js/tr2bl.json", JSON.stringify(json, null, 2)); expect(json).toMatchSnapshot(); }); test("should read custom docx", () => { const buffer = readFileSync("../fixtures/custom/custom.docx"); const json = w.readDocx(buffer); - writeFileSync("../output/custom.json", JSON.stringify(json, null, 2)); + writeFileSync("../output/js/custom.json", JSON.stringify(json, null, 2)); expect(json).toMatchSnapshot(); }); @@ -123,7 +123,7 @@ describe("writer", () => { expect(z.readAsText(e)).toMatchSnapshot(); } } - writeFileSync("../output/strike.docx", buffer); + writeFileSync("../output/js/strike.docx", buffer); }); test("should write lvlOverride with level", () => { @@ -176,7 +176,7 @@ describe("writer", () => { expect(z.readAsText(e)).toMatchSnapshot(); } } - writeFileSync("../output/nested_table.docx", buffer); + writeFileSync("../output/js/nested_table.docx", buffer); }); test("should write tl2br and tr2bl cells", () => { @@ -207,7 +207,7 @@ describe("writer", () => { expect(z.readAsText(e)).toMatchSnapshot(); } } - writeFileSync("../output/cell_borders.docx", buffer); + writeFileSync("../output/js/cell_borders.docx", buffer); }); test("should write cell shading", () => { @@ -224,7 +224,7 @@ describe("writer", () => { expect(z.readAsText(e)).toMatchSnapshot(); } } - writeFileSync("../output/cell_shading.docx", buffer); + writeFileSync("../output/js/cell_shading.docx", buffer); }); test("should write page margin", () => { @@ -252,7 +252,7 @@ describe("writer", () => { .defaultSize(40) .defaultFonts(fonts) .build(); - writeFileSync("../output/default_font.docx", buffer); + writeFileSync("../output/js/default_font.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|numbering.xml/)) { @@ -264,7 +264,7 @@ describe("writer", () => { test("should write doc vars", () => { const p = new w.Paragraph().addRun(new w.Run().addText("Hello world!!!!")); const buffer = new w.Docx().addParagraph(p).addDocVar("foo", "bar").build(); - writeFileSync("../output/doc_vars.docx", buffer); + writeFileSync("../output/js/doc_vars.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|numbering.xml/)) { @@ -276,7 +276,7 @@ describe("writer", () => { test("should write doc grid", () => { const p = new w.Paragraph().addRun(new w.Run().addText("Hello world!!!!")); const buffer = new w.Docx().addParagraph(p).docGrid("default", 360).build(); - writeFileSync("../output/doc_grid.docx", buffer); + writeFileSync("../output/js/doc_grid.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|numbering.xml/)) { @@ -297,7 +297,7 @@ describe("writer", () => { expect(z.readAsText(e)).toMatchSnapshot(); } } - writeFileSync("../output/table_layout.docx", buffer); + writeFileSync("../output/js/table_layout.docx", buffer); }); test("should write text border", () => { @@ -305,7 +305,7 @@ describe("writer", () => { .addRun(new w.Run().addText("Hello ")) .addRun(new w.Run().addText("World!").textBorder("single", 4, 0, "auto")); const buffer = new w.Docx().addParagraph(p).build(); - writeFileSync("../output/text_border.docx", buffer); + writeFileSync("../output/js/text_border.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|numbering.xml/)) { @@ -321,7 +321,7 @@ describe("writer", () => { .pageSize(16838, 11906) .pageOrientation("landscape") .build(); - writeFileSync("../output/page_orientation.docx", buffer); + writeFileSync("../output/js/page_orientation.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|numbering.xml/)) { @@ -336,7 +336,7 @@ describe("writer", () => { .addParagraph(p) .customProperty("hello", '{"world": 0}') .build(); - writeFileSync("../output/custom.docx", buffer); + writeFileSync("../output/js/custom.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|numbering.xml|custom.xml/)) { @@ -360,7 +360,7 @@ describe("writer", () => { ).property("hello", JSON.stringify({ hello: "world" })) ) .build(); - writeFileSync("../output/webextension.docx", buffer); + writeFileSync("../output/js/webextension.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/webextension1.xml|_rels|taskpanes.xml.rel/)) { @@ -378,7 +378,7 @@ describe("writer", () => { '' ) .build(); - writeFileSync("../output/custom-item.docx", buffer); + writeFileSync("../output/js/custom-item.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/item1.xml|_rels|item1Props/)) { @@ -394,7 +394,7 @@ describe("writer", () => { new w.LineSpacing().before(100).after(0).line(100).afterLines(400) ); const buffer = new w.Docx().addParagraph(p).build(); - writeFileSync("../output/line_spacing.docx", buffer); + writeFileSync("../output/js/line_spacing.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|numbering.xml/)) { @@ -408,7 +408,7 @@ describe("writer", () => { const p2 = new w.Paragraph().addRun(new w.Run().addText("World ")); const footer = new w.Footer().addParagraph(p1); const buffer = new w.Docx().footer(footer).addParagraph(p2).build(); - writeFileSync("../output/footer.docx", buffer); + writeFileSync("../output/js/footer.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|footer1.xml/)) { @@ -422,7 +422,7 @@ describe("writer", () => { const p2 = new w.Paragraph().addRun(new w.Run().addText("World ")); const header = new w.Header().addParagraph(p1); const buffer = new w.Docx().header(header).addParagraph(p2).build(); - writeFileSync("../output/header.docx", buffer); + writeFileSync("../output/js/header.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|footer1.xml/)) { @@ -438,7 +438,7 @@ describe("writer", () => { ); const header = new w.Header().addTable(table); const buffer = new w.Docx().firstHeader(header).build(); - writeFileSync("../output/first_header_with_table.docx", buffer); + writeFileSync("../output/js/first_header_with_table.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|header[1-9].xml/)) { @@ -454,7 +454,7 @@ describe("writer", () => { ); const footer = new w.Footer().addTable(table); const buffer = new w.Docx().evenFooter(footer).build(); - writeFileSync("../output/even_footer_with_table.docx", buffer); + writeFileSync("../output/js/even_footer_with_table.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml|footer[1-9].xml/)) { @@ -474,7 +474,113 @@ describe("writer", () => { .addBookmarkEnd(1); const buffer = new w.Docx().addParagraph(p1).addParagraph(p2).build(); - writeFileSync("../output/hyperlink.docx", buffer); + writeFileSync("../output/js/hyperlink.docx", buffer); + const z = new Zip(Buffer.from(buffer)); + for (const e of z.getEntries()) { + if (e.entryName.match(/document.xml/)) { + expect(z.readAsText(e)).toMatchSnapshot(); + } + } + }); + + test("should write dirty and disable auto items ToC", () => { + const p1 = new w.Paragraph() + .addRun(new w.Run().addText("Hello!!")) + .pageBreakBefore(true) + .style("Heading1"); + const style1 = new w.Style("Heading1", "paragraph").name("Heading 1"); + const p2 = new w.Paragraph() + .addRun(new w.Run().addText("World")) + .pageBreakBefore(true) + .style("Heading2"); + const style2 = new w.Style("Heading2", "paragraph").name("Heading 2"); + const buffer = new w.Docx() + .addTableOfContents( + new w.TableOfContents().alias("Table of contents").dirty() + ) + .addParagraph(p1) + .addParagraph(p2) + .addStyle(style1) + .addStyle(style2) + .build(); + writeFileSync("../output/js/toc_dirty_and_disable_auto_items.docx", buffer); + const z = new Zip(Buffer.from(buffer)); + for (const e of z.getEntries()) { + if (e.entryName.match(/document.xml/)) { + expect(z.readAsText(e)).toMatchSnapshot(); + } + } + }); + + test("should write auto items ToC", () => { + const p1 = new w.Paragraph() + .addRun(new w.Run().addText("Hello!!")) + .pageBreakBefore(true) + .style("Heading1"); + const style1 = new w.Style("Heading1", "paragraph").name("Heading 1"); + const p2 = new w.Paragraph() + .addRun(new w.Run().addText("World")) + .pageBreakBefore(true) + .style("Heading2"); + const style2 = new w.Style("Heading2", "paragraph").name("Heading 2"); + const buffer = new w.Docx() + .addTableOfContents( + new w.TableOfContents().alias("Table of contents").auto() + ) + .addParagraph(p1) + .addParagraph(p2) + .addStyle(style1) + .addStyle(style2) + .build(); + writeFileSync("../output/js/toc_auto_items.docx", buffer); + const z = new Zip(Buffer.from(buffer)); + for (const e of z.getEntries()) { + if (e.entryName.match(/document.xml/)) { + expect(z.readAsText(e)).toMatchSnapshot(); + } + } + }); + + test("should write ToC with items", () => { + const p1 = new w.Paragraph() + .addBookmarkStart(1, "_Toc00000000") + .addRun(new w.Run().addText("Hello!!")) + .addBookmarkEnd(1) + .pageBreakBefore(true) + .style("Heading1"); + const style1 = new w.Style("Heading1", "paragraph").name("Heading 1"); + const p2 = new w.Paragraph() + .addBookmarkStart(2, "_Toc00000001") + .addRun(new w.Run().addText("World")) + .addBookmarkEnd(2) + .pageBreakBefore(true) + .style("Heading2"); + const style2 = new w.Style("Heading2", "paragraph").name("Heading 2"); + const buffer = new w.Docx() + .addTableOfContents( + new w.TableOfContents() + .alias("Table of contents") + .addItem( + new w.TableOfContentsItem() + .text("Hello!!") + .level(1) + .pageRef("2") + .tocKey("_Toc00000000") + ) + .addItem( + new w.TableOfContentsItem() + .text("World") + .level(2) + .pageRef("3") + .tocKey("_Toc00000001") + ) + ) + .addParagraph(p1) + .addParagraph(p2) + .addStyle(style1) + .addStyle(style2) + .build(); + writeFileSync("../output/js/toc_with_items.docx", buffer); const z = new Zip(Buffer.from(buffer)); for (const e of z.getEntries()) { if (e.entryName.match(/document.xml/)) { diff --git a/output/docProps/custom.xml b/output/docProps/custom.xml deleted file mode 100755 index 935fad9..0000000 --- a/output/docProps/custom.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/output/js/.keep b/output/js/.keep new file mode 100644 index 0000000..e69de29