Skip to content

Commit

Permalink
Add hyphenation support (#2678)
Browse files Browse the repository at this point in the history
* Add hyphenation support

* Remove unneeded linebreaks

* Add documentation and fix eslint

* Add tests

---------

Co-authored-by: Dolan Miu <[email protected]>
  • Loading branch information
merewif and dolanmiu authored Nov 21, 2024
1 parent 05a3cf5 commit c6bb255
Show file tree
Hide file tree
Showing 8 changed files with 206 additions and 16 deletions.
37 changes: 24 additions & 13 deletions docs/usage/document.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,30 @@ const doc = new docx.Document({

### Full list of options:

- creator
- description
- title
- subject
- keywords
- lastModifiedBy
- revision
- externalStyles
- styles
- numbering
- footnotes
- hyperlinks
- background
| Property | Type | Notes |
| -------------------------- | -------------------------------------------------------- | -------- |
| sections | `ISectionOptions[]` | Optional |
| title | `string` | Optional |
| subject | `string` | Optional |
| creator | `string` | Optional |
| keywords | `string` | Optional |
| description | `string` | Optional |
| lastModifiedBy | `string` | Optional |
| revision | `number` | Optional |
| externalStyles | `string` | Optional |
| styles | `IStylesOptions` | Optional |
| numbering | `INumberingOptions` | Optional |
| comments | `ICommentsOptions` | Optional |
| footnotes | `Record<string, { children: Paragraph[] }>` | Optional |
| background | `IDocumentBackgroundOptions` | Optional |
| features | `{ trackRevisions?: boolean; updateFields?: boolean; }` | Optional |
| compatabilityModeVersion | `number` | Optional |
| compatibility | `ICompatibilityOptions` | Optional |
| customProperties | ` ICustomPropertyOptions`[] | Optional |
| evenAndOddHeaderAndFooters | `boolean` | Optional |
| defaultTabStop | `number` | Optional |
| fonts | ` FontOptions[]` | Optional |
| hyphenation | `IHyphenationOptions` | Optional |

### Change background color of Document

Expand Down
2 changes: 2 additions & 0 deletions src/file/core-properties/properties.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FontOptions } from "@file/fonts/font-table";
import { ICommentsOptions } from "@file/paragraph/run/comment-run";
import { IHyphenationOptions } from "@file/settings";
import { ICompatibilityOptions } from "@file/settings/compatibility";
import { StringContainer, XmlComponent } from "@file/xml-components";
import { dateTimeValue } from "@util/values";
Expand Down Expand Up @@ -44,6 +45,7 @@ export type IPropertiesOptions = {
readonly evenAndOddHeaderAndFooters?: boolean;
readonly defaultTabStop?: number;
readonly fonts?: readonly FontOptions[];
readonly hyphenation?: IHyphenationOptions;
};

// <xs:element name="coreProperties" type="CT_CoreProperties"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { describe, expect, it } from "vitest";

import { Formatter } from "@export/formatter";

import { createLineNumberType } from "./line-number";

describe("createLineNumberType", () => {
it("should work", () => {
const textDirection = createLineNumberType({ countBy: 0, start: 0, restart: "newPage", distance: 10 });

const tree = new Formatter().format(textDirection);
expect(tree).to.deep.equal({
"w:lnNumType": { _attr: { "w:countBy": 0, "w:start": 0, "w:restart": "newPage", "w:distance": 10 } },
});
});

it("should work with string measures for distance", () => {
const textDirection = createLineNumberType({ countBy: 0, start: 0, restart: "newPage", distance: "10mm" });

const tree = new Formatter().format(textDirection);
expect(tree).to.deep.equal({
"w:lnNumType": { _attr: { "w:countBy": 0, "w:start": 0, "w:restart": "newPage", "w:distance": "10mm" } },
});
});

it("should work with blank entries", () => {
const textDirection = createLineNumberType({});

const tree = new Formatter().format(textDirection);
expect(tree).to.deep.equal({
"w:lnNumType": { _attr: {} },
});
});
});
37 changes: 37 additions & 0 deletions src/file/file.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,4 +479,41 @@ describe("File", () => {
expect(doc.Styles).to.not.be.undefined;
});
});

describe("#features", () => {
it("should work with updateFields", () => {
const doc = new File({
sections: [],
features: {
updateFields: true,
},
});

expect(doc.Styles).to.not.be.undefined;
});

it("should work with trackRevisions", () => {
const doc = new File({
sections: [],
features: {
trackRevisions: true,
},
});

expect(doc.Styles).to.not.be.undefined;
});
});

describe("#hyphenation", () => {
it("should work with autoHyphenation", () => {
const doc = new File({
sections: [],
hyphenation: {
autoHyphenation: true,
},
});

expect(doc.Styles).to.not.be.undefined;
});
});
});
6 changes: 6 additions & 0 deletions src/file/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ export class File {
trackRevisions: options.features?.trackRevisions,
updateFields: options.features?.updateFields,
defaultTabStop: options.defaultTabStop,
hyphenation: {
autoHyphenation: options.hyphenation?.autoHyphenation,
hyphenationZone: options.hyphenation?.hyphenationZone,
consecutiveHyphenLimit: options.hyphenation?.consecutiveHyphenLimit,
doNotHyphenateCaps: options.hyphenation?.doNotHyphenateCaps,
},
});

this.media = new Media();
Expand Down
68 changes: 68 additions & 0 deletions src/file/settings/settings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,74 @@ describe("Settings", () => {
});
});

it("should add autoHyphenation setting", () => {
const options = {
hyphenation: {
autoHyphenation: true,
},
};

const tree = new Formatter().format(new Settings(options));
expect(Object.keys(tree)).has.length(1);
expect(tree["w:settings"]).to.be.an("array");
expect(tree["w:settings"]).to.deep.include({
"w:autoHyphenation": {},
});
});

it("should add doNotHyphenateCaps setting", () => {
const options = {
hyphenation: {
doNotHyphenateCaps: true,
},
};

const tree = new Formatter().format(new Settings(options));
expect(Object.keys(tree)).has.length(1);
expect(tree["w:settings"]).to.be.an("array");
expect(tree["w:settings"]).to.deep.include({
"w:doNotHyphenateCaps": {},
});
});

it("should add hyphenationZone setting", () => {
const options = {
hyphenation: {
hyphenationZone: 200,
},
};

const tree = new Formatter().format(new Settings(options));
expect(Object.keys(tree)).has.length(1);
expect(tree["w:settings"]).to.be.an("array");
expect(tree["w:settings"]).to.deep.include({
"w:hyphenationZone": {
_attr: {
"w:val": 200,
},
},
});
});

it("should add consecutiveHyphenLimit setting", () => {
const options = {
hyphenation: {
consecutiveHyphenLimit: 3,
},
};

const tree = new Formatter().format(new Settings(options));
expect(Object.keys(tree)).has.length(1);
expect(tree["w:settings"]).to.be.an("array");
expect(tree["w:settings"]).to.deep.include({
"w:consecutiveHyphenLimit": {
_attr: {
"w:val": 3,
},
},
});
});

// TODO: Remove when deprecating compatibilityModeVersion
it("should add compatibility setting with legacy version", () => {
const settings = new Settings({
Expand Down
32 changes: 32 additions & 0 deletions src/file/settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,18 @@ export type ISettingsOptions = {
readonly updateFields?: boolean;
readonly compatibility?: ICompatibilityOptions;
readonly defaultTabStop?: number;
readonly hyphenation?: IHyphenationOptions;
};

export type IHyphenationOptions = {
/** Specifies whether the application automatically hyphenates words as they are typed in the document. */
readonly autoHyphenation?: boolean;
/** Specifies the minimum number of characters at the beginning of a word before a hyphen can be inserted. */
readonly hyphenationZone?: number;
/** Specifies the maximum number of consecutive lines that can end with a hyphenated word. */
readonly consecutiveHyphenLimit?: number;
/** Specifies whether to hyphenate words in all capital letters. */
readonly doNotHyphenateCaps?: boolean;
};

export class Settings extends XmlComponent {
Expand Down Expand Up @@ -204,6 +216,26 @@ export class Settings extends XmlComponent {
this.root.push(new NumberValueElement("w:defaultTabStop", options.defaultTabStop));
}

// https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_autoHyphenation_topic_ID0EFUMX.html
if (options.hyphenation?.autoHyphenation !== undefined) {
this.root.push(new OnOffElement("w:autoHyphenation", options.hyphenation.autoHyphenation));
}

// https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_hyphenationZone_topic_ID0ERI3X.html
if (options.hyphenation?.hyphenationZone !== undefined) {
this.root.push(new NumberValueElement("w:hyphenationZone", options.hyphenation.hyphenationZone));
}

// https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_consecutiveHyphenLim_topic_ID0EQ6RX.html
if (options.hyphenation?.consecutiveHyphenLimit !== undefined) {
this.root.push(new NumberValueElement("w:consecutiveHyphenLimit", options.hyphenation.consecutiveHyphenLimit));
}

// https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_doNotHyphenateCaps_topic_ID0EW4XX.html
if (options.hyphenation?.doNotHyphenateCaps !== undefined) {
this.root.push(new OnOffElement("w:doNotHyphenateCaps", options.hyphenation.doNotHyphenateCaps));
}

this.root.push(
new Compatibility({
...(options.compatibility ?? {}),
Expand Down
6 changes: 3 additions & 3 deletions vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { configDefaults, defineConfig } from "vitest/config";
import { resolve } from "path";
import tsconfigPaths from "vite-tsconfig-paths";
import dts from "vite-plugin-dts";
import { nodePolyfills } from "vite-plugin-node-polyfills";
import tsconfigPaths from "vite-tsconfig-paths";
import { configDefaults, defineConfig } from "vitest/config";

export default defineConfig({
plugins: [
Expand Down Expand Up @@ -65,7 +65,7 @@ export default defineConfig({
reporter: ["text", "json", "html"],
thresholds: {
statements: 100,
branches: 99.35,
branches: 99.68,
functions: 100,
lines: 100,
},
Expand Down

0 comments on commit c6bb255

Please sign in to comment.