Compare commits

...

107 Commits

Author SHA1 Message Date
89135fa9c2 build(deps-dev): bump eslint-plugin-functional from 7.1.0 to 9.0.2
Bumps [eslint-plugin-functional](https://github.com/eslint-functional/eslint-plugin-functional) from 7.1.0 to 9.0.2.
- [Release notes](https://github.com/eslint-functional/eslint-plugin-functional/releases)
- [Changelog](https://github.com/eslint-functional/eslint-plugin-functional/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint-functional/eslint-plugin-functional/compare/v7.1.0...v9.0.2)

---
updated-dependencies:
- dependency-name: eslint-plugin-functional
  dependency-version: 9.0.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 11:48:32 +00:00
88ddfa79be build(deps): bump @types/node from 22.15.3 to 22.15.27 (#3127)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.15.3 to 22.15.27.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 22.15.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-31 14:32:01 +01:00
f6ee55a947 build(deps-dev): bump typescript-eslint from 8.30.1 to 8.33.0 (#3122)
Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.30.1 to 8.33.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.33.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.33.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-31 14:31:38 +01:00
b8cc44a31b build(deps-dev): bump @vitest/coverage-v8 from 3.1.2 to 3.1.4 (#3116)
Bumps [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) from 3.1.2 to 3.1.4.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v3.1.4/packages/coverage-v8)

---
updated-dependencies:
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 3.1.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-31 14:31:31 +01:00
e1a478cd72 build(deps-dev): bump eslint-plugin-unicorn from 59.0.0 to 59.0.1 (#3095)
Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 59.0.0 to 59.0.1.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v59.0.0...v59.0.1)

---
updated-dependencies:
- dependency-name: eslint-plugin-unicorn
  dependency-version: 59.0.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-31 14:31:24 +01:00
e39bed6032 build(deps-dev): bump @types/inquirer from 9.0.7 to 9.0.8 (#3094)
Bumps [@types/inquirer](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/inquirer) from 9.0.7 to 9.0.8.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/inquirer)

---
updated-dependencies:
- dependency-name: "@types/inquirer"
  dependency-version: 9.0.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-31 14:31:16 +01:00
495f2e4888 Version bump 2025-05-05 23:44:24 +01:00
ba292d07f7 build(deps-dev): bump eslint-plugin-unicorn from 58.0.0 to 59.0.0 (#3089)
Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 58.0.0 to 59.0.0.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v58.0.0...v59.0.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-unicorn
  dependency-version: 59.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 23:43:37 +01:00
db8a5be998 build(deps-dev): bump cspell from 8.19.2 to 9.0.0 (#3093)
Bumps [cspell](https://github.com/streetsidesoftware/cspell/tree/HEAD/packages/cspell) from 8.19.2 to 9.0.0.
- [Release notes](https://github.com/streetsidesoftware/cspell/releases)
- [Changelog](https://github.com/streetsidesoftware/cspell/blob/main/packages/cspell/CHANGELOG.md)
- [Commits](https://github.com/streetsidesoftware/cspell/commits/v9.0.0/packages/cspell)

---
updated-dependencies:
- dependency-name: cspell
  dependency-version: 9.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 23:42:36 +01:00
a7a6b69004 build(deps-dev): bump vite from 6.3.4 to 6.3.5 (#3092)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.4 to 6.3.5.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.3.5/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.3.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 23:39:00 +01:00
b60f940994 build(deps-dev): bump tsx from 4.19.3 to 4.19.4 (#3091)
Bumps [tsx](https://github.com/privatenumber/tsx) from 4.19.3 to 4.19.4.
- [Release notes](https://github.com/privatenumber/tsx/releases)
- [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs)
- [Commits](https://github.com/privatenumber/tsx/compare/v4.19.3...v4.19.4)

---
updated-dependencies:
- dependency-name: tsx
  dependency-version: 4.19.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 23:38:52 +01:00
afa3374376 build(deps-dev): bump typedoc from 0.28.3 to 0.28.4 (#3090)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.28.3 to 0.28.4.
- [Release notes](https://github.com/TypeStrong/TypeDoc/releases)
- [Changelog](https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/TypeDoc/compare/v0.28.3...v0.28.4)

---
updated-dependencies:
- dependency-name: typedoc
  dependency-version: 0.28.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 23:38:31 +01:00
45795bf43d build(deps-dev): bump eslint from 9.25.1 to 9.26.0 (#3088)
Bumps [eslint](https://github.com/eslint/eslint) from 9.25.1 to 9.26.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.25.1...v9.26.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 9.26.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 23:38:07 +01:00
bd7321d221 build(deps-dev): bump @typescript-eslint/eslint-plugin (#3084)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 8.30.1 to 8.31.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.31.1/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-version: 8.31.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-05 23:37:52 +01:00
aa2d72507c build(deps-dev): bump vite from 6.3.2 to 6.3.4 (#3086)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.2 to 6.3.4.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.3.4/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-03 23:56:03 +01:00
a2755f57f4 build(deps-dev): bump @typescript-eslint/parser from 8.30.1 to 8.31.1 (#3083)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.30.1 to 8.31.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.31.1/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.31.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-03 23:55:37 +01:00
a604677a37 build(deps): bump @types/node from 22.14.1 to 22.15.3 (#3082)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.14.1 to 22.15.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 22.15.3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-03 23:55:29 +01:00
e3436de693 build(deps-dev): bump eslint-plugin-jsdoc from 50.6.9 to 50.6.11 (#3081)
Bumps [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from 50.6.9 to 50.6.11.
- [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases)
- [Changelog](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/.releaserc)
- [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v50.6.9...v50.6.11)

---
updated-dependencies:
- dependency-name: eslint-plugin-jsdoc
  dependency-version: 50.6.11
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-03 23:55:17 +01:00
e2f4556ac3 build(deps-dev): bump glob from 11.0.1 to 11.0.2 (#3077)
Bumps [glob](https://github.com/isaacs/node-glob) from 11.0.1 to 11.0.2.
- [Changelog](https://github.com/isaacs/node-glob/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/node-glob/compare/v11.0.1...v11.0.2)

---
updated-dependencies:
- dependency-name: glob
  dependency-version: 11.0.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-02 20:08:16 +01:00
42151c1534 build(deps-dev): bump inquirer from 12.5.2 to 12.6.0 (#3075)
Bumps [inquirer](https://github.com/SBoudrias/Inquirer.js) from 12.5.2 to 12.6.0.
- [Release notes](https://github.com/SBoudrias/Inquirer.js/releases)
- [Commits](https://github.com/SBoudrias/Inquirer.js/compare/inquirer@12.5.2...inquirer@12.6.0)

---
updated-dependencies:
- dependency-name: inquirer
  dependency-version: 12.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-02 20:08:08 +01:00
7d1129900f Fix: separate vertical alignment enums for ITableCellOptions and ISectionPropertiesOptions (#3079)
* fix: separate vertical alignment enums for table and section properties

- Introduced `VerticalAlignTable` for table-cell vertical alignment with valid values: `top`, `center`, and `bottom`.
- Added `VerticalAlignSection` for section properties, extending `VerticalAlignTable` with an additional value `both`.
- Marked the original `VerticalAlign` as deprecated for backward compatibility, directing users to the new enums.
- Updated type definitions for better clarity on valid vertical alignments.

* refactor: update vertical alignment imports and types for section and table properties

- Renamed `VerticalAlign` to `VerticalAlignSection` in section properties and `VerticalAlignTable` in table-cell properties for clarity.
- Updated type definitions to reflect the new enum names, ensuring better organization and understanding of vertical alignment options.
- Adjusted related test cases to utilize the new imports and types.

* refactor: update demos to use new enums for table and section properties for vertical alignment
2025-05-02 19:58:10 +01:00
1e6c9e1772 fix: omit empty descr/title in <wp:docPr> for Word 2007 compatibility (#3073) 2025-05-02 19:55:22 +01:00
c38d0a253e build(deps-dev): bump eslint from 9.24.0 to 9.25.1 (#3068)
Bumps [eslint](https://github.com/eslint/eslint) from 9.24.0 to 9.25.1.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.24.0...v9.25.1)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 9.25.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 22:18:00 +01:00
89464ea7fc build(deps-dev): bump eslint-import-resolver-typescript (#3067)
Bumps [eslint-import-resolver-typescript](https://github.com/import-js/eslint-import-resolver-typescript) from 4.3.2 to 4.3.4.
- [Release notes](https://github.com/import-js/eslint-import-resolver-typescript/releases)
- [Changelog](https://github.com/import-js/eslint-import-resolver-typescript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-import-resolver-typescript/compare/v4.3.2...v4.3.4)

---
updated-dependencies:
- dependency-name: eslint-import-resolver-typescript
  dependency-version: 4.3.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 22:17:52 +01:00
61ed317f24 build(deps-dev): bump typedoc from 0.28.2 to 0.28.3 (#3065)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.28.2 to 0.28.3.
- [Release notes](https://github.com/TypeStrong/TypeDoc/releases)
- [Changelog](https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/TypeDoc/compare/v0.28.2...v0.28.3)

---
updated-dependencies:
- dependency-name: typedoc
  dependency-version: 0.28.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 22:17:40 +01:00
b1bb95df79 build(deps-dev): bump cspell from 8.19.0 to 8.19.2 (#3064)
Bumps [cspell](https://github.com/streetsidesoftware/cspell/tree/HEAD/packages/cspell) from 8.19.0 to 8.19.2.
- [Release notes](https://github.com/streetsidesoftware/cspell/releases)
- [Changelog](https://github.com/streetsidesoftware/cspell/blob/main/packages/cspell/CHANGELOG.md)
- [Commits](https://github.com/streetsidesoftware/cspell/commits/v8.19.2/packages/cspell)

---
updated-dependencies:
- dependency-name: cspell
  dependency-version: 8.19.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 22:17:31 +01:00
2b73c243f3 build(deps-dev): bump @vitest/coverage-v8 from 3.1.1 to 3.1.2 (#3059)
Bumps [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) from 3.1.1 to 3.1.2.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v3.1.2/packages/coverage-v8)

---
updated-dependencies:
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 3.1.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 22:17:17 +01:00
f29c2687dd build(deps-dev): bump vite from 6.3.1 to 6.3.2 (#3058)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.1 to 6.3.2.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.3.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.3.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-22 22:17:09 +01:00
44ed2d6943 Fix: Use browser compatable Buffer (#3057)
* Fix: Use browser compatable Buffer

* Update src/patcher/from-docx.ts

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-18 00:02:21 +01:00
fe7a75b754 build(deps-dev): bump cspell from 8.18.1 to 8.19.0 (#3055)
Bumps [cspell](https://github.com/streetsidesoftware/cspell/tree/HEAD/packages/cspell) from 8.18.1 to 8.19.0.
- [Release notes](https://github.com/streetsidesoftware/cspell/releases)
- [Changelog](https://github.com/streetsidesoftware/cspell/blob/main/packages/cspell/CHANGELOG.md)
- [Commits](https://github.com/streetsidesoftware/cspell/commits/v8.19.0/packages/cspell)

---
updated-dependencies:
- dependency-name: cspell
  dependency-version: 8.19.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 23:53:40 +01:00
d30cd546ab build(deps-dev): bump vite from 6.3.0 to 6.3.1 (#3054)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.3.0 to 6.3.1.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@6.3.1/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.3.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-17 23:53:30 +01:00
03d47658d6 Fix guidelines 2025-04-17 00:41:04 +01:00
1403ac664b Update contribution guidelines (#3053) 2025-04-16 23:51:30 +01:00
ba0a502d27 build(deps-dev): bump eslint-plugin-jsdoc from 50.6.6 to 50.6.9 (#3049)
Bumps [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from 50.6.6 to 50.6.9.
- [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases)
- [Changelog](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/.releaserc)
- [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v50.6.6...v50.6.9)

---
updated-dependencies:
- dependency-name: eslint-plugin-jsdoc
  dependency-version: 50.6.9
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dolan <dolan_miu@hotmail.com>
2025-04-16 23:23:53 +01:00
44d4b93d06 feat: Added TableCellSpacing (#3052)
* feat: Added TableCellSpacingElement

* feat: Added cellSpacing (Table-constructor, TableProperties-constructor and ITableOptions)

* feat: Added cellSpacing (ITablePropertiesOptions and constructor implementation)

* feat: Added cellSpacing (ITableRowPropertiesOptions and constructor implementation)

* feat: Added cellSpacing (Implementation Test)

---------

Co-authored-by: Philip <1760073-philip.asx@users.noreply.gitlab.com>
2025-04-16 22:38:28 +01:00
72abd4b7ac build(deps-dev): bump jsdom from 26.0.0 to 26.1.0 (#3050)
Bumps [jsdom](https://github.com/jsdom/jsdom) from 26.0.0 to 26.1.0.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/main/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/compare/26.0.0...26.1.0)

---
updated-dependencies:
- dependency-name: jsdom
  dependency-version: 26.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 22:35:54 +01:00
a473a98f17 build(deps-dev): bump typescript-eslint from 8.19.1 to 8.30.1 (#3051)
Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.19.1 to 8.30.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.30.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.30.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 22:35:46 +01:00
f649dac62c build(deps-dev): bump @vitest/coverage-v8 from 3.0.8 to 3.1.1 (#3048)
Bumps [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) from 3.0.8 to 3.1.1.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v3.1.1/packages/coverage-v8)

---
updated-dependencies:
- dependency-name: "@vitest/coverage-v8"
  dependency-version: 3.1.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 22:35:31 +01:00
ba7f937a7a build(deps-dev): bump cspell from 8.17.5 to 8.18.1 (#3047)
Bumps [cspell](https://github.com/streetsidesoftware/cspell/tree/HEAD/packages/cspell) from 8.17.5 to 8.18.1.
- [Release notes](https://github.com/streetsidesoftware/cspell/releases)
- [Changelog](https://github.com/streetsidesoftware/cspell/blob/main/packages/cspell/CHANGELOG.md)
- [Commits](https://github.com/streetsidesoftware/cspell/commits/v8.18.1/packages/cspell)

---
updated-dependencies:
- dependency-name: cspell
  dependency-version: 8.18.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 22:35:20 +01:00
1c8e6ae1db build(deps-dev): bump eslint from 9.22.0 to 9.24.0 (#3046)
Bumps [eslint](https://github.com/eslint/eslint) from 9.22.0 to 9.24.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.22.0...v9.24.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-version: 9.24.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 22:35:12 +01:00
e09e201c45 build(deps-dev): bump eslint-import-resolver-typescript (#3044)
Bumps [eslint-import-resolver-typescript](https://github.com/import-js/eslint-import-resolver-typescript) from 3.7.0 to 4.3.2.
- [Release notes](https://github.com/import-js/eslint-import-resolver-typescript/releases)
- [Changelog](https://github.com/import-js/eslint-import-resolver-typescript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-import-resolver-typescript/compare/v3.7.0...v4.3.2)

---
updated-dependencies:
- dependency-name: eslint-import-resolver-typescript
  dependency-version: 4.3.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 22:35:05 +01:00
409ea028cb Version bump 2025-04-16 10:15:02 +01:00
fc86e1842d fix: patchDocument, looks for namspaces more carefully over whole doc… (#2943)
* fix: patchDocument, looks for namspaces more carefully over whole document

added support of different placeholder brackets, default `{{`: `}}`

extended inputDataType to accept JSZip

* fix: Attribute value string not converted to HTML esc char by js2xml

original: https://github.com/nashwaan/xml-js/issues/142

* fix: skip processing utf-16 encoded files

* fix: patching goes on the second circle over patched document

added parameter `recursive`(= true by default) to be able to disable
this behavior

* Fix linting

* Simplify code

* write tests to skip UTF-16 types

---------

Co-authored-by: Vladimir Bulyga <vladimir.bulyga@legatics.com>
Co-authored-by: Dolan Miu <dolan_miu@hotmail.com>
2025-04-16 10:03:49 +01:00
b614b74a2a build(deps): bump @types/node from 22.10.1 to 22.14.1 (#3039)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.10.1 to 22.14.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 22.14.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Dolan <dolan_miu@hotmail.com>
2025-04-16 09:57:24 +01:00
e7eb415376 build(deps-dev): bump vite from 6.2.3 to 6.3.0 in the npm_and_yarn group (#3043)
Bumps the npm_and_yarn group with 1 update: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 6.2.3 to 6.3.0
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@6.3.0/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.3.0
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 09:08:19 +01:00
77c5a736dd build(deps-dev): bump vite from 6.2.2 to 6.2.6 (#3034)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.2.2 to 6.2.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.6/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 6.2.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 09:08:04 +01:00
a241a51cfd build(deps-dev): bump @typescript-eslint/parser from 8.19.1 to 8.30.1 (#3040)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 8.19.1 to 8.30.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.30.1/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-version: 8.30.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 08:56:06 +01:00
4e0468d978 build(deps-dev): bump typedoc from 0.27.6 to 0.28.2 (#3029)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.27.6 to 0.28.2.
- [Release notes](https://github.com/TypeStrong/TypeDoc/releases)
- [Changelog](https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/TypeDoc/compare/v0.27.6...v0.28.2)

---
updated-dependencies:
- dependency-name: typedoc
  dependency-version: 0.28.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 08:55:47 +01:00
cfe5970e54 build(deps-dev): bump inquirer from 12.4.3 to 12.5.2 (#3027)
Bumps [inquirer](https://github.com/SBoudrias/Inquirer.js) from 12.4.3 to 12.5.2.
- [Release notes](https://github.com/SBoudrias/Inquirer.js/releases)
- [Commits](https://github.com/SBoudrias/Inquirer.js/compare/inquirer@12.4.3...inquirer@12.5.2)

---
updated-dependencies:
- dependency-name: inquirer
  dependency-version: 12.5.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 08:55:40 +01:00
27977edf82 build(deps-dev): bump vite from 6.2.2 to 6.2.3 in the npm_and_yarn group (#3014)
Bumps the npm_and_yarn group with 1 update: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 6.2.2 to 6.2.3
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v6.2.3/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.3/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 08:55:33 +01:00
7405a19ae8 build(deps-dev): bump eslint-plugin-unicorn from 56.0.1 to 58.0.0 (#3012)
Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 56.0.1 to 58.0.0.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v56.0.1...v58.0.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-unicorn
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 08:55:26 +01:00
ce32375d47 build(deps): bump nanoid from 5.1.3 to 5.1.5 (#3003)
Bumps [nanoid](https://github.com/ai/nanoid) from 5.1.3 to 5.1.5.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.1.3...5.1.5)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 08:55:18 +01:00
b33b7d2ebd build(deps-dev): bump @types/unzipper from 0.10.10 to 0.10.11 (#3001)
Bumps [@types/unzipper](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/unzipper) from 0.10.10 to 0.10.11.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/unzipper)

---
updated-dependencies:
- dependency-name: "@types/unzipper"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 08:55:11 +01:00
b2b23bdc1c build(deps-dev): bump prettier from 3.4.2 to 3.5.3 (#2999)
Bumps [prettier](https://github.com/prettier/prettier) from 3.4.2 to 3.5.3.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.4.2...3.5.3)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-16 08:55:03 +01:00
7f26badbc9 feat: Added NumberedItemReference (#3042)
* feat: Added NumberedItemReference

* Fix linting

* ts-ignore until TypeScript upgrade

---------

Co-authored-by: Alexander Nortung <alexander.nortung@oakdigital.dk>
2025-04-16 08:54:50 +01:00
b19025881b feat(comments): Support comment pictures (#3032)
* feat(comments): Support comment pictures

* fix(demo): Fix the image path to load the image correctly

* fix(test): Update the number of files asserted in the compiler test case

* feat(comments): Support comment pictures

* fix(demo): Fix the image path to load the image correctly

* fix(test): Update the number of files asserted in the compiler test case

* style(src): Format the code and remove extra blank lines

---------

Co-authored-by: Dolan <dolan_miu@hotmail.com>
2025-04-16 08:45:36 +01:00
5af1045a59 feat: add support for custom patch delimiters in PatchDocumentOptions (#3036)
* feat: add support for custom patch delimiters in PatchDocumentOptions

* chore: add validation for placeholder delimiters
2025-04-16 08:18:55 +01:00
4d1a351649 Documentation and Refactoring (#3028)
* Documentation and Refactoring

* Documentation and Refactoring

* Fix lint issues

* Convert components to Builder style

---------

Co-authored-by: Dolan Miu <dmiu@bloomberg.net>
2025-04-14 16:43:15 +05:30
8ba9a448d3 Version bump 2025-03-15 03:19:53 +00:00
a708475539 export IPropertiesOptions for use by other libraries or code using docx library (#2979)
* export IPropertiesOptions for use by other libraries or code using docx library

* fixes #2978: export OutputTypes

* Export file in main index file

* Move type export to inside

---------

Co-authored-by: Dolan Miu <dolan_miu@hotmail.com>
2025-03-15 03:18:43 +00:00
9c60cfcbc7 build(deps): bump the npm_and_yarn group with 12 updates (#2992)
Bumps the npm_and_yarn group with 15 updates:

| Package | From | To |
| --- | --- | --- |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `2.1.8` | `2.1.9` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `2.1.8` | `2.1.9` |
| [@vitest/ui](https://github.com/vitest-dev/vitest/tree/HEAD/packages/ui) | `2.1.8` | `2.1.9` |
| [dompurify](https://github.com/cure53/DOMPurify) | `2.5.7` | `removed` |
| [docsify](https://github.com/docsifyjs/docsify) | `4.12.2` | `4.13.1` |
| [docsify-server-renderer](https://github.com/docsifyjs/docsify) | `4.12.2` | `4.13.1` |
| [elliptic](https://github.com/indutny/elliptic) | `6.6.0` | `6.6.1` |
| [esbuild](https://github.com/evanw/esbuild) | `0.21.5` | `0.25.1` |
| [@vitest/coverage-v8](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-v8) | `2.1.9` | `3.0.8` |
| [@vitest/ui](https://github.com/vitest-dev/vitest/tree/HEAD/packages/ui) | `2.1.9` | `3.0.8` |
| [tsx](https://github.com/privatenumber/tsx) | `4.19.2` | `4.19.3` |
| [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) | `6.0.9` | `6.2.2` |
| [vite-plugin-node-polyfills](https://github.com/davidmyersdev/vite-plugin-node-polyfills) | `0.22.0` | `0.23.0` |
| [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) | `2.1.9` | `3.0.8` |
| [prismjs](https://github.com/PrismJS/prism) | `1.27.0` | `1.30.0` |


Updates `vitest` from 2.1.8 to 2.1.9
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v2.1.9/packages/vitest)

Updates `@vitest/coverage-v8` from 2.1.8 to 2.1.9
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v2.1.9/packages/coverage-v8)

Updates `@vitest/ui` from 2.1.8 to 2.1.9
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v2.1.9/packages/ui)

Removes `dompurify`

Updates `docsify` from 4.12.2 to 4.13.1
- [Release notes](https://github.com/docsifyjs/docsify/releases)
- [Changelog](https://github.com/docsifyjs/docsify/blob/v4.13.1/CHANGELOG.md)
- [Commits](https://github.com/docsifyjs/docsify/compare/v4.12.2...v4.13.1)

Updates `docsify-server-renderer` from 4.12.2 to 4.13.1
- [Release notes](https://github.com/docsifyjs/docsify/releases)
- [Changelog](https://github.com/docsifyjs/docsify/blob/v4.13.1/CHANGELOG.md)
- [Commits](https://github.com/docsifyjs/docsify/compare/v4.12.2...v4.13.1)

Updates `elliptic` from 6.6.0 to 6.6.1
- [Commits](https://github.com/indutny/elliptic/compare/v6.6.0...v6.6.1)

Updates `esbuild` from 0.21.5 to 0.25.1
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2024.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.21.5...v0.25.1)

Updates `@vitest/coverage-v8` from 2.1.9 to 3.0.8
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v2.1.9/packages/coverage-v8)

Updates `@vitest/ui` from 2.1.9 to 3.0.8
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v2.1.9/packages/ui)

Updates `tsx` from 4.19.2 to 4.19.3
- [Release notes](https://github.com/privatenumber/tsx/releases)
- [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs)
- [Commits](https://github.com/privatenumber/tsx/compare/v4.19.2...v4.19.3)

Updates `vite` from 6.0.9 to 6.2.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.2.2/packages/vite)

Updates `vite-plugin-node-polyfills` from 0.22.0 to 0.23.0
- [Release notes](https://github.com/davidmyersdev/vite-plugin-node-polyfills/releases)
- [Commits](https://github.com/davidmyersdev/vite-plugin-node-polyfills/compare/v0.22.0...v0.23.0)

Updates `vitest` from 2.1.9 to 3.0.8
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v2.1.9/packages/vitest)

Updates `prismjs` from 1.27.0 to 1.30.0
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.27.0...v1.30.0)

---
updated-dependencies:
- dependency-name: vitest
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: "@vitest/coverage-v8"
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: "@vitest/ui"
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: dompurify
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: docsify
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: docsify-server-renderer
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: elliptic
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: esbuild
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: "@vitest/coverage-v8"
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: "@vitest/ui"
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: tsx
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: vite
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: vite-plugin-node-polyfills
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: vitest
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: prismjs
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-15 03:05:07 +00:00
a5454edc61 Feature/math improve (#2976)
* add new feature

* add test file

* update test file

* update test file

* Fix linting

---------

Co-authored-by: Dolan Miu <dolan_miu@hotmail.com>
2025-03-15 03:04:01 +00:00
7152abfe48 build(deps-dev): bump eslint-plugin-jsdoc from 50.6.0 to 50.6.6 (#2987)
Bumps [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from 50.6.0 to 50.6.6.
- [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases)
- [Changelog](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/.releaserc)
- [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v50.6.0...v50.6.6)

---
updated-dependencies:
- dependency-name: eslint-plugin-jsdoc
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 23:44:41 +00:00
075eeb7e3c build(deps-dev): bump eslint from 9.16.0 to 9.22.0 (#2983)
Bumps [eslint](https://github.com/eslint/eslint) from 9.16.0 to 9.22.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.16.0...v9.22.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 23:44:33 +00:00
f0acb3f3fb build(deps-dev): bump inquirer from 12.3.0 to 12.4.3 (#2982)
Bumps [inquirer](https://github.com/SBoudrias/Inquirer.js) from 12.3.0 to 12.4.3.
- [Release notes](https://github.com/SBoudrias/Inquirer.js/releases)
- [Commits](https://github.com/SBoudrias/Inquirer.js/compare/inquirer@12.3.0...inquirer@12.4.3)

---
updated-dependencies:
- dependency-name: inquirer
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 23:44:26 +00:00
ae048833a1 build(deps-dev): bump vite-plugin-dts from 4.3.0 to 4.5.3 (#2973)
Bumps [vite-plugin-dts](https://github.com/qmhc/vite-plugin-dts) from 4.3.0 to 4.5.3.
- [Release notes](https://github.com/qmhc/vite-plugin-dts/releases)
- [Changelog](https://github.com/qmhc/vite-plugin-dts/blob/main/CHANGELOG.md)
- [Commits](https://github.com/qmhc/vite-plugin-dts/compare/v4.3.0...v4.5.3)

---
updated-dependencies:
- dependency-name: vite-plugin-dts
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 23:44:17 +00:00
ebae72004c Fix support for after auto-spacing. (#2975) 2025-03-14 23:44:09 +00:00
13744abff5 build(deps-dev): bump cspell from 8.16.1 to 8.17.5 (#2969)
Bumps [cspell](https://github.com/streetsidesoftware/cspell/tree/HEAD/packages/cspell) from 8.16.1 to 8.17.5.
- [Release notes](https://github.com/streetsidesoftware/cspell/releases)
- [Changelog](https://github.com/streetsidesoftware/cspell/blob/main/packages/cspell/CHANGELOG.md)
- [Commits](https://github.com/streetsidesoftware/cspell/commits/v8.17.5/packages/cspell)

---
updated-dependencies:
- dependency-name: cspell
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 23:43:46 +00:00
492ef29d7f build(deps-dev): bump vite from 6.0.7 to 6.0.9 in the npm_and_yarn group (#2940)
Bumps the npm_and_yarn group with 1 update: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 6.0.7 to 6.0.9
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.0.9/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 23:43:39 +00:00
a6e6463a36 build(deps-dev): bump jiti from 2.4.1 to 2.4.2 (#2932)
Bumps [jiti](https://github.com/unjs/jiti) from 2.4.1 to 2.4.2.
- [Release notes](https://github.com/unjs/jiti/releases)
- [Changelog](https://github.com/unjs/jiti/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unjs/jiti/compare/v2.4.1...v2.4.2)

---
updated-dependencies:
- dependency-name: jiti
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 23:43:32 +00:00
2ef596543b build(deps-dev): bump glob from 11.0.0 to 11.0.1 (#2930)
Bumps [glob](https://github.com/isaacs/node-glob) from 11.0.0 to 11.0.1.
- [Changelog](https://github.com/isaacs/node-glob/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/node-glob/compare/v11.0.0...v11.0.1)

---
updated-dependencies:
- dependency-name: glob
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 23:43:25 +00:00
85005c3c07 build(deps-dev): bump jsdom from 25.0.1 to 26.0.0 (#2928)
Bumps [jsdom](https://github.com/jsdom/jsdom) from 25.0.1 to 26.0.0.
- [Release notes](https://github.com/jsdom/jsdom/releases)
- [Changelog](https://github.com/jsdom/jsdom/blob/main/Changelog.md)
- [Commits](https://github.com/jsdom/jsdom/compare/25.0.1...26.0.0)

---
updated-dependencies:
- dependency-name: jsdom
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-14 23:43:17 +00:00
0d2b433446 Chore: bump nanoid to fix security issue (#2991) 2025-03-14 23:43:08 +00:00
b1f67652e9 docs: add Playground (Docx.js Editor) url to README.md (#2965) 2025-02-23 20:36:33 +01:00
4e2befb7ef Update docs for new Packer methods (#2961)
To cover #2920
2025-02-17 21:22:07 +00:00
a887927968 Version bump 2025-02-16 18:35:16 +00:00
ee6db1429a Add shading and border settings to paragraph style options. (#2955)
* Add shading and border settings to paragraph style options.

* Fix prettier

---------

Co-authored-by: Dolan Miu <dolan_miu@hotmail.com>
2025-02-16 18:33:21 +00:00
170309a7ed Add Packer.pack and Packer.toArrayBuffer (#2959)
* Add Packer.pack and Packer.toArrayBuffer

To mirror patchDocument's outputType parameter.

See https://github.com/dolanmiu/docx/discussions/2920

* Ignore coverage

---------

Co-authored-by: Dolan Miu <dolan_miu@hotmail.com>
2025-02-16 18:24:15 +00:00
05fcf6edd4 Feat: subfile overrides (#2941)
* Adds overrides parameter to Packer methods and compiler

* Adds tests for overrides parameter

* Update Packer usage examples
2025-01-27 10:39:23 +00:00
eb2174e566 Version bump 2025-01-10 12:31:16 +00:00
2a56360875 build(deps-dev): bump typescript-eslint from 8.16.0 to 8.19.1 (#2921)
Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.16.0 to 8.19.1.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.19.1/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 11:22:37 +00:00
ba862766a6 build(deps-dev): bump vite from 6.0.1 to 6.0.7 (#2919)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 6.0.1 to 6.0.7.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v6.0.7/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 11:22:29 +00:00
71291dab8f build(deps-dev): bump typedoc from 0.27.3 to 0.27.6 (#2913)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.27.3 to 0.27.6.
- [Release notes](https://github.com/TypeStrong/TypeDoc/releases)
- [Changelog](https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/TypeDoc/compare/v0.27.3...v0.27.6)

---
updated-dependencies:
- dependency-name: typedoc
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 11:22:21 +00:00
974ba7b450 build(deps-dev): bump inquirer from 12.1.0 to 12.3.0 (#2908)
Bumps [inquirer](https://github.com/SBoudrias/Inquirer.js) from 12.1.0 to 12.3.0.
- [Release notes](https://github.com/SBoudrias/Inquirer.js/releases)
- [Commits](https://github.com/SBoudrias/Inquirer.js/compare/inquirer@12.1.0...inquirer@12.3.0)

---
updated-dependencies:
- dependency-name: inquirer
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 11:22:13 +00:00
8f7df39c07 build(deps-dev): bump execa from 9.5.1 to 9.5.2 (#2892)
Bumps [execa](https://github.com/sindresorhus/execa) from 9.5.1 to 9.5.2.
- [Release notes](https://github.com/sindresorhus/execa/releases)
- [Commits](https://github.com/sindresorhus/execa/compare/v9.5.1...v9.5.2)

---
updated-dependencies:
- dependency-name: execa
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 11:22:03 +00:00
ca3d8f0121 build(deps-dev): bump vite-tsconfig-paths from 5.1.3 to 5.1.4 (#2890)
Bumps [vite-tsconfig-paths](https://github.com/aleclarson/vite-tsconfig-paths) from 5.1.3 to 5.1.4.
- [Release notes](https://github.com/aleclarson/vite-tsconfig-paths/releases)
- [Commits](https://github.com/aleclarson/vite-tsconfig-paths/compare/v5.1.3...v5.1.4)

---
updated-dependencies:
- dependency-name: vite-tsconfig-paths
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 11:21:55 +00:00
46c517d195 build(deps-dev): bump eslint-import-resolver-typescript (#2887)
Bumps [eslint-import-resolver-typescript](https://github.com/import-js/eslint-import-resolver-typescript) from 3.6.3 to 3.7.0.
- [Release notes](https://github.com/import-js/eslint-import-resolver-typescript/releases)
- [Changelog](https://github.com/import-js/eslint-import-resolver-typescript/blob/master/CHANGELOG.md)
- [Commits](https://github.com/import-js/eslint-import-resolver-typescript/compare/v3.6.3...v3.7.0)

---
updated-dependencies:
- dependency-name: eslint-import-resolver-typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-01-10 11:21:43 +00:00
ff37f3b460 fix: Ensure necessary namespaces are in patched doc (#2698)
* refactor: Extract timestamp properties

In preparation for reworking DocumentAttributes.

* refactor: Consolidate namespaces

* fix: Ensure necessary namespaces are in patched doc

Fixes #2697

* Fix tsc and ESLint errors

* Fix CSpell

* Add a test to fix code coverage failure
2025-01-06 22:19:00 +00:00
7b9b474484 Fix: custom fonts support on the Browser (#2898) 2024-12-19 02:08:52 +00:00
e80a50d36c #2846 Type error when importing docx in CJS file with TypeScript modu… (#2883)
* #2846 Type error when importing docx in CJS file with TypeScript moduleResolution set to node16

* Adhere to publint
2024-12-06 13:44:42 +00:00
df99f96469 Chore: Update vitest (#2882)
* Chore: Update vitest

* Fix test
2024-12-05 15:43:30 +00:00
f87ad6a43c build(deps-dev): bump typedoc from 0.26.11 to 0.27.3 (#2879)
Bumps [typedoc](https://github.com/TypeStrong/TypeDoc) from 0.26.11 to 0.27.3.
- [Release notes](https://github.com/TypeStrong/TypeDoc/releases)
- [Changelog](https://github.com/TypeStrong/typedoc/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TypeStrong/TypeDoc/compare/v0.26.11...v0.27.3)

---
updated-dependencies:
- dependency-name: typedoc
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 14:04:43 +00:00
8bf5220e31 build(deps-dev): bump prettier from 3.3.3 to 3.4.2 (#2878)
Bumps [prettier](https://github.com/prettier/prettier) from 3.3.3 to 3.4.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.3.3...3.4.2)

---
updated-dependencies:
- dependency-name: prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 14:04:24 +00:00
da8148251a build(deps-dev): bump eslint from 9.14.0 to 9.16.0 (#2874)
Bumps [eslint](https://github.com/eslint/eslint) from 9.14.0 to 9.16.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v9.14.0...v9.16.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 14:04:06 +00:00
01183ac34d build(deps-dev): bump jiti from 2.4.0 to 2.4.1 (#2871)
Bumps [jiti](https://github.com/unjs/jiti) from 2.4.0 to 2.4.1.
- [Release notes](https://github.com/unjs/jiti/releases)
- [Changelog](https://github.com/unjs/jiti/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unjs/jiti/compare/v2.4.0...v2.4.1)

---
updated-dependencies:
- dependency-name: jiti
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 14:03:46 +00:00
d553e4763a build(deps): bump @types/node from 22.9.0 to 22.10.1 (#2868)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.9.0 to 22.10.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 14:03:36 +00:00
213c3d29f3 build(deps-dev): bump eslint-plugin-unicorn from 56.0.0 to 56.0.1 (#2867)
Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 56.0.0 to 56.0.1.
- [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases)
- [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v56.0.0...v56.0.1)

---
updated-dependencies:
- dependency-name: eslint-plugin-unicorn
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 14:03:28 +00:00
697c1d91c6 build(deps): bump nanoid from 5.0.8 to 5.0.9 (#2866)
Bumps [nanoid](https://github.com/ai/nanoid) from 5.0.8 to 5.0.9.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/5.0.8...5.0.9)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 14:03:07 +00:00
b22de4ac4f build(deps-dev): bump cspell from 8.16.0 to 8.16.1 (#2865)
Bumps [cspell](https://github.com/streetsidesoftware/cspell/tree/HEAD/packages/cspell) from 8.16.0 to 8.16.1.
- [Release notes](https://github.com/streetsidesoftware/cspell/releases)
- [Changelog](https://github.com/streetsidesoftware/cspell/blob/main/packages/cspell/CHANGELOG.md)
- [Commits](https://github.com/streetsidesoftware/cspell/commits/v8.16.1/packages/cspell)

---
updated-dependencies:
- dependency-name: cspell
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-05 14:02:53 +00:00
0af9d27dcc Chore: Remove @eslint/compat (#2881) 2024-12-05 13:54:43 +00:00
b89b571c4e Fix replacer error on patches with empty Runs (#2875)
* Add test to demonstrate empty strings not creating runs

* Fix Run not creating Text child for empty strings

* Simplify TextRun constructor

Since `Run` already has a option for instantiating a `Text` element, we don't need to push children here.

* Add replacer test for empty runs

* Add replacer test for empty runs

* replacer: handle patches with empty runs

* Fix incorrect test name
2024-12-03 11:25:22 +00:00
64505a295f build(deps-dev): bump eslint-plugin-jsdoc from 50.4.3 to 50.6.0 (#2863)
Bumps [eslint-plugin-jsdoc](https://github.com/gajus/eslint-plugin-jsdoc) from 50.4.3 to 50.6.0.
- [Release notes](https://github.com/gajus/eslint-plugin-jsdoc/releases)
- [Changelog](https://github.com/gajus/eslint-plugin-jsdoc/blob/main/.releaserc)
- [Commits](https://github.com/gajus/eslint-plugin-jsdoc/compare/v50.4.3...v50.6.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-jsdoc
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 10:47:45 +00:00
c247bbf409 build(deps-dev): bump @vitest/ui from 2.1.4 to 2.1.6 (#2862)
Bumps [@vitest/ui](https://github.com/vitest-dev/vitest/tree/HEAD/packages/ui) from 2.1.4 to 2.1.6.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v2.1.6/packages/ui)

---
updated-dependencies:
- dependency-name: "@vitest/ui"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 10:47:22 +00:00
4c60e6a0c0 build(deps-dev): bump vite from 5.4.10 to 6.0.1 (#2861)
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.4.10 to 6.0.1.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/create-vite@6.0.1/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 10:47:13 +00:00
086e5ef184 build(deps-dev): bump typescript-eslint from 8.13.0 to 8.16.0 (#2857)
Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.13.0 to 8.16.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.16.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 10:46:36 +00:00
7e81f7b368 build(deps-dev): bump vite-tsconfig-paths from 5.1.0 to 5.1.3 (#2850)
Bumps [vite-tsconfig-paths](https://github.com/aleclarson/vite-tsconfig-paths) from 5.1.0 to 5.1.3.
- [Release notes](https://github.com/aleclarson/vite-tsconfig-paths/releases)
- [Commits](https://github.com/aleclarson/vite-tsconfig-paths/compare/v5.1.0...v5.1.3)

---
updated-dependencies:
- dependency-name: vite-tsconfig-paths
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 10:46:26 +00:00
defa431aa9 build(deps-dev): bump inquirer from 12.0.1 to 12.1.0 (#2838)
Bumps [inquirer](https://github.com/SBoudrias/Inquirer.js) from 12.0.1 to 12.1.0.
- [Release notes](https://github.com/SBoudrias/Inquirer.js/releases)
- [Commits](https://github.com/SBoudrias/Inquirer.js/compare/inquirer@12.0.1...inquirer@12.1.0)

---
updated-dependencies:
- dependency-name: inquirer
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-28 10:44:33 +00:00
144 changed files with 8981 additions and 7216 deletions

View File

@ -8,11 +8,14 @@
// words - list of words to be always considered correct
"words": [
"Abjad",
"aink",
"aiueo",
"ATLEAST",
"chosung",
"clippy",
"datas",
"dcmitype",
"dcterms",
"docsify",
"dolan",
"execa",
@ -32,6 +35,7 @@
"panose",
"rels",
"rsid",
"sdtdh",
"twip",
"twips",
"Xmlable",

View File

@ -1,243 +0,0 @@
extends: eslint:recommended
env:
browser: true
es6: true
node: true
parser: "@typescript-eslint/parser"
parserOptions:
project:
- tsconfig.json
sourceType: module
plugins:
- eslint-plugin-import
- eslint-plugin-no-null
- eslint-plugin-unicorn
- eslint-plugin-jsdoc
- eslint-plugin-prefer-arrow
- "@typescript-eslint"
- eslint-plugin-functional
root: true
rules:
no-undef: "off"
no-extra-boolean-cast: "off"
no-alert: error
no-self-compare: error
no-unreachable-loop: error
no-template-curly-in-string: error
no-unused-private-class-members: error
no-extend-native: error
no-floating-decimal: error
no-implied-eval: error
no-iterator: error
no-lone-blocks: error
no-loop-func: error
no-new-object: error
no-proto: error
no-useless-catch: error
one-var-declaration-per-line: error
prefer-arrow-callback: error
prefer-destructuring: error
prefer-exponentiation-operator: error
prefer-promise-reject-errors: error
prefer-regex-literals: error
prefer-spread: error
prefer-template: error
require-await: error
"@typescript-eslint/adjacent-overload-signatures": error
"@typescript-eslint/array-type":
- error
- default: array
"@typescript-eslint/no-restricted-types":
- error
- types:
Object:
message: Avoid using the `Object` type. Did you mean `object`?
fixWith: object
Function:
message: >-
Avoid using the `Function` type. Prefer a specific function type,
like `() => void`.
Boolean:
message: Avoid using the `Boolean` type. Did you mean `boolean`?
fixWith: boolean
Number:
message: Avoid using the `Number` type. Did you mean `number`?
fixWith: number
String:
message: Avoid using the `String` type. Did you mean `string`?
fixWith: string
Symbol:
message: Avoid using the `Symbol` type. Did you mean `symbol`?
fixWith: symbol
"@typescript-eslint/consistent-type-assertions": error
"@typescript-eslint/dot-notation": error
"@typescript-eslint/explicit-function-return-type":
- error
- allowExpressions: true
allowTypedFunctionExpressions: true
allowHigherOrderFunctions: false
allowDirectConstAssertionInArrowFunctions: true
allowConciseArrowFunctionExpressionsStartingWithVoid: true
"@typescript-eslint/explicit-member-accessibility":
- error
- accessibility: explicit
overrides:
accessors: explicit
"@typescript-eslint/explicit-module-boundary-types":
- error
- allowArgumentsExplicitlyTypedAsAny: true
allowDirectConstAssertionInArrowFunctions: true
allowHigherOrderFunctions: false
allowTypedFunctionExpressions: false
"@typescript-eslint/naming-convention":
- error
- selector:
- objectLiteralProperty
leadingUnderscore: allow
format:
- camelCase
- PascalCase
- UPPER_CASE # for constants
filter:
regex: (^[a-z]+:.+)|_attr|[0-9]
match: false
"@typescript-eslint/no-empty-function": error
"@typescript-eslint/no-empty-interface": error
"@typescript-eslint/no-explicit-any": error
"@typescript-eslint/no-misused-new": error
"@typescript-eslint/no-namespace": error
"@typescript-eslint/no-parameter-properties": "off"
"@typescript-eslint/no-require-imports": error
"@typescript-eslint/no-shadow":
- error
- hoist: all
"@typescript-eslint/no-this-alias": error
"@typescript-eslint/no-unused-expressions": error
"@typescript-eslint/no-use-before-define": "off"
"@typescript-eslint/no-var-requires": error
"@typescript-eslint/prefer-for-of": error
"@typescript-eslint/prefer-function-type": error
"@typescript-eslint/prefer-namespace-keyword": error
"@typescript-eslint/prefer-readonly": error
"@typescript-eslint/triple-slash-reference":
- error
- path: always
types: prefer-import
lib: always
"@typescript-eslint/typedef":
- error
- parameter: true
propertyDeclaration: true
"@typescript-eslint/unified-signatures": error
arrow-body-style: error
complexity: "off"
consistent-return: error
constructor-super: error
curly: error
dot-notation: "off"
eqeqeq:
- error
- smart
guard-for-in: error
id-denylist:
- error
- any
- Number
- number
- String
- string
- Boolean
- boolean
- Undefined
- undefined
id-match: error
import/no-default-export: error
import/no-extraneous-dependencies: "off"
import/no-internal-modules: "off"
import/order: error
indent: "off"
jsdoc/check-alignment: error
jsdoc/check-indentation: "off"
max-classes-per-file: "off"
max-len: "off"
new-parens: error
no-bitwise: error
no-caller: error
no-cond-assign: error
no-console: error
no-debugger: error
no-duplicate-case: error
no-duplicate-imports: error
no-empty: error
no-empty-function: "off"
no-eval: error
no-extra-bind: error
no-fallthrough: "off"
no-invalid-this: "off"
no-multiple-empty-lines: error
no-new-func: error
no-new-wrappers: error
no-null/no-null: error
no-param-reassign: error
no-redeclare: error
no-return-await: error
no-sequences: error
no-shadow: "off"
no-sparse-arrays: error
no-throw-literal: error
no-trailing-spaces: error
no-undef-init: error
no-underscore-dangle:
- error
- allow:
- _attr
no-unsafe-finally: error
no-unused-expressions: "off"
no-unused-labels: error
no-use-before-define: "off"
no-useless-constructor: error
no-var: error
object-shorthand: "off"
one-var:
- error
- never
prefer-arrow/prefer-arrow-functions: error
prefer-const: error
prefer-object-spread: error
radix: error
space-in-parens:
- error
- never
spaced-comment:
- error
- always
- markers:
- /
unicorn/filename-case: error
unicorn/prefer-ternary: error
use-isnan: error
valid-typeof: "off"
functional/immutable-data:
- error
- ignoreImmediateMutation: true
ignoreAccessorPattern:
- "**.root*"
- "**.numberingReferences*"
- "**.sections*"
- "**.properties*"
functional/prefer-property-signatures: error
functional/no-mixed-types: error
functional/prefer-readonly-type: error
no-unused-vars:
- error
- argsIgnorePattern: ^[_]+$
ignorePatterns:
- vite.config.ts
overrides:
- files:
- "*.spec.ts"
rules:
"@typescript-eslint/no-unused-expressions": "off"
"@typescript-eslint/dot-notation": "off"
prefer-destructuring: "off"
"@typescript-eslint/explicit-function-return-type": "off"

View File

@ -65,5 +65,5 @@ jobs:
uses: actions/checkout@v4
- name: Install Dependencies
run: npm ci --force
- name: Prettier
- name: CSpell
run: npm run cspell

3
.gitignore vendored
View File

@ -33,8 +33,7 @@ node_modules
.node_repl_history
# build
build
build-tests
dist
# Documentation
docs/api/

View File

@ -14,6 +14,7 @@
[![Known Vulnerabilities][snky-image]][snky-url]
[![PRs Welcome][pr-image]][pr-url]
[![codecov][codecov-image]][codecov-url]
[![Docx.js Editor][docxjs-editor-image]][docxjs-editor-url]
<p align="center">
<img src="https://i.imgur.com/QeL1HuU.png" alt="drawing"/>
@ -64,6 +65,10 @@ More [here](https://github.com/dolanmiu/docx/tree/master/demo)
Please refer to the [documentation at https://docx.js.org/](https://docx.js.org/) for details on how to use this library, examples and much more!
# Playground
Experience `docx` in action through [Docx.js Editor][docxjs-editor-url], an interactive playground where you can code and preview the results in real-time.
# Examples
Check the [demo folder](https://github.com/dolanmiu/docx/tree/master/demo) for examples.
@ -115,3 +120,5 @@ Made with 💖
[patreon-url]: https://www.patreon.com/dolanmiu
[browserstack-image]: https://user-images.githubusercontent.com/2917613/54233552-128e9d00-4505-11e9-88fb-025a4e04007c.png
[browserstack-url]: https://www.browserstack.com
[docxjs-editor-image]: https://img.shields.io/badge/Docx.js%20Editor-2b579a.svg?style=flat&amp;logo=javascript&amp;logoColor=white
[docxjs-editor-url]: https://docxjs-editor.vercel.app/

View File

@ -1,7 +1,7 @@
// Example of how you would create a table and add data to it
import * as fs from "fs";
import { Document, HeadingLevel, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign, TextDirection } from "docx";
import { Document, HeadingLevel, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlignTable, TextDirection } from "docx";
const doc = new Document({
sections: [
@ -13,11 +13,11 @@ const doc = new Document({
children: [
new TableCell({
children: [new Paragraph({}), new Paragraph({})],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [new Paragraph({}), new Paragraph({})],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [new Paragraph({ text: "bottom to top" }), new Paragraph({})],
@ -45,7 +45,7 @@ const doc = new Document({
text: "This text should be in the middle of the cell",
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [
@ -53,7 +53,7 @@ const doc = new Document({
text: "Text above should be vertical from bottom to top",
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [
@ -61,7 +61,7 @@ const doc = new Document({
text: "Text above should be vertical from top to bottom",
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
],
}),

View File

@ -1,13 +1,13 @@
// Example of making content of section vertically aligned
import * as fs from "fs";
import { Document, Packer, Paragraph, VerticalAlign, TextRun, Tab } from "docx";
import { Document, Packer, Paragraph, VerticalAlignSection, TextRun, Tab } from "docx";
const doc = new Document({
sections: [
{
properties: {
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignSection.CENTER,
},
children: [
new Paragraph({

View File

@ -12,7 +12,7 @@ import {
TableCell,
TableRow,
TextDirection,
VerticalAlign,
VerticalAlignTable,
} from "docx";
const table = new Table({
@ -102,11 +102,11 @@ const noBorderTable = new Table({
children: [
new TableCell({
children: [new Paragraph({}), new Paragraph({})],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [new Paragraph({}), new Paragraph({})],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [new Paragraph({ text: "bottom to top" }), new Paragraph({})],
@ -134,7 +134,7 @@ const noBorderTable = new Table({
text: "This text should be in the middle of the cell",
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [
@ -142,7 +142,7 @@ const noBorderTable = new Table({
text: "Text above should be vertical from bottom to top",
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [
@ -150,7 +150,7 @@ const noBorderTable = new Table({
text: "Text above should be vertical from top to bottom",
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
],
}),

View File

@ -1,7 +1,7 @@
// The demo on the README.md
import * as fs from "fs";
import { Document, HeadingLevel, ImageRun, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign } from "docx";
import { Document, HeadingLevel, ImageRun, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlignTable } from "docx";
const table = new Table({
rows: [
@ -13,6 +13,7 @@ const table = new Table({
children: [
new ImageRun({
data: fs.readFileSync("./demo/images/image1.jpeg"),
type: "jpg",
transformation: {
width: 100,
height: 100,
@ -21,7 +22,7 @@ const table = new Table({
],
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [
@ -30,7 +31,7 @@ const table = new Table({
heading: HeadingLevel.HEADING_1,
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
],
}),
@ -50,6 +51,7 @@ const table = new Table({
children: [
new ImageRun({
data: fs.readFileSync("./demo/images/image1.jpeg"),
type: "jpg",
transformation: {
width: 100,
height: 100,
@ -77,6 +79,7 @@ const doc = new Document({
children: [
new ImageRun({
data: fs.readFileSync("./demo/images/pizza.gif"),
type: "gif",
transformation: {
width: 100,
height: 100,

View File

@ -1,7 +1,7 @@
// Example demonstrating page borders with style, colors and size
import { BorderStyle, Document, Packer, PageBorderDisplay, PageBorderOffsetFrom, PageBorderZOrder, Paragraph, TextRun } from "docx";
import * as fs from "fs";
import { Document, Packer, TextRun, Paragraph, BorderStyle, PageBorderDisplay, PageBorderOffsetFrom, PageBorderZOrder } from "docx";
const doc = new Document({
sections: [

View File

@ -1,7 +1,7 @@
// Simple example to add comments to a document
import * as fs from "fs";
import { Document, Packer, Paragraph, TextRun, CommentRangeStart, CommentRangeEnd, CommentReference } from "docx";
import { Document, Packer, Paragraph, TextRun, CommentRangeStart, CommentRangeEnd, CommentReference, ImageRun } from "docx";
const doc = new Document({
comments: {
@ -20,6 +20,14 @@ const doc = new Document({
}),
new Paragraph({
children: [
new ImageRun({
type: "jpg",
data: fs.readFileSync("./demo/images/cat.jpg"),
transformation: {
width: 100,
height: 100,
},
}),
new TextRun({
text: "comment text content",
}),

View File

@ -9,7 +9,7 @@ import {
Table,
TableCell,
TableRow,
VerticalAlign,
VerticalAlignTable,
TextDirection,
TextRun,
WidthType,
@ -101,17 +101,17 @@ const generateRows = (prices: StockPrice[]): TableRow[] =>
children: [
new TableCell({
children: [new Paragraph(date.toString())],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
textDirection: TextDirection.LEFT_TO_RIGHT_TOP_TO_BOTTOM,
}),
new TableCell({
children: [new Paragraph(ticker)],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
textDirection: TextDirection.LEFT_TO_RIGHT_TOP_TO_BOTTOM,
}),
new TableCell({
children: [new Paragraph(price.toString())],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
textDirection: TextDirection.TOP_TO_BOTTOM_RIGHT_TO_LEFT,
}),
],
@ -143,7 +143,7 @@ const doc = new Document({
],
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
textDirection: TextDirection.LEFT_TO_RIGHT_TOP_TO_BOTTOM,
}),
new TableCell({
@ -159,7 +159,7 @@ const doc = new Document({
],
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
textDirection: TextDirection.LEFT_TO_RIGHT_TOP_TO_BOTTOM,
}),
new TableCell({
@ -175,7 +175,7 @@ const doc = new Document({
],
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
textDirection: TextDirection.TOP_TO_BOTTOM_RIGHT_TO_LEFT,
}),
],

View File

@ -13,7 +13,7 @@ import {
TableRow,
TextDirection,
TextRun,
VerticalAlign,
VerticalAlignTable,
} from "docx";
patchDocument({
@ -105,11 +105,11 @@ patchDocument({
children: [
new TableCell({
children: [new Paragraph({}), new Paragraph({})],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [new Paragraph({}), new Paragraph({})],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [new Paragraph({ text: "bottom to top" }), new Paragraph({})],
@ -137,7 +137,7 @@ patchDocument({
text: "This text should be in the middle of the cell",
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [
@ -145,7 +145,7 @@ patchDocument({
text: "Text above should be vertical from bottom to top",
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [
@ -153,7 +153,7 @@ patchDocument({
text: "Text above should be vertical from top to bottom",
}),
],
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
}),
],
}),

View File

@ -0,0 +1,60 @@
import * as fs from "fs";
import { BorderStyle, Document, Packer, Paragraph, TextRun } from "docx";
const doc = new Document({
styles: {
paragraphStyles: [
{
id: "withSingleBlackBordersAndYellowShading",
name: "Paragraph Style with Black Borders and Yellow Shading",
basedOn: "Normal",
paragraph: {
shading: {
color: "#fff000",
type: "solid",
},
border: {
top: {
style: BorderStyle.SINGLE,
color: "#000000",
size: 4,
},
bottom: {
style: BorderStyle.SINGLE,
color: "#000000",
size: 4,
},
left: {
style: BorderStyle.SINGLE,
color: "#000000",
size: 4,
},
right: {
style: BorderStyle.SINGLE,
color: "#000000",
size: 4,
},
},
},
},
],
},
sections: [
{
children: [
new Paragraph({
style: "withSingleBlackBordersAndYellowShading",
children: [
new TextRun({
text: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
}),
],
}),
],
},
],
});
Packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -0,0 +1,168 @@
// Patch a document with patches
import * as fs from "fs";
import {
ExternalHyperlink,
HeadingLevel,
ImageRun,
Paragraph,
patchDocument,
PatchType,
Table,
TableCell,
TableRow,
TextDirection,
TextRun,
VerticalAlignTable,
} from "docx";
patchDocument({
outputType: "nodebuffer",
data: fs.readFileSync("demo/assets/simple-template-4.docx"),
patches: {
name: {
type: PatchType.PARAGRAPH,
children: [new TextRun("Sir. "), new TextRun("John Doe"), new TextRun("(The Conqueror)")],
},
table_heading_1: {
type: PatchType.PARAGRAPH,
children: [new TextRun("Heading wow!")],
},
item_1: {
type: PatchType.PARAGRAPH,
children: [
new TextRun("#657"),
new ExternalHyperlink({
children: [
new TextRun({
text: "BBC News Link",
}),
],
link: "https://www.bbc.co.uk/news",
}),
],
},
paragraph_replace: {
type: PatchType.DOCUMENT,
children: [
new Paragraph("Lorem ipsum paragraph"),
new Paragraph("Another paragraph"),
new Paragraph({
children: [
new TextRun("This is a "),
new ExternalHyperlink({
children: [
new TextRun({
text: "Google Link",
}),
],
link: "https://www.google.co.uk",
}),
new ImageRun({
type: "png",
data: fs.readFileSync("./demo/images/dog.png"),
transformation: { width: 100, height: 100 },
}),
],
}),
],
},
header_adjective: {
type: PatchType.PARAGRAPH,
children: [new TextRun("Delightful Header")],
},
footer_text: {
type: PatchType.PARAGRAPH,
children: [
new TextRun("replaced just as"),
new TextRun(" well"),
new ExternalHyperlink({
children: [
new TextRun({
text: "BBC News Link",
}),
],
link: "https://www.bbc.co.uk/news",
}),
],
},
image_test: {
type: PatchType.PARAGRAPH,
children: [
new ImageRun({
type: "jpg",
data: fs.readFileSync("./demo/images/image1.jpeg"),
transformation: { width: 100, height: 100 },
}),
],
},
table: {
type: PatchType.DOCUMENT,
children: [
new Table({
rows: [
new TableRow({
children: [
new TableCell({
children: [new Paragraph({}), new Paragraph({})],
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [new Paragraph({}), new Paragraph({})],
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [new Paragraph({ text: "bottom to top" }), new Paragraph({})],
textDirection: TextDirection.BOTTOM_TO_TOP_LEFT_TO_RIGHT,
}),
new TableCell({
children: [new Paragraph({ text: "top to bottom" }), new Paragraph({})],
textDirection: TextDirection.TOP_TO_BOTTOM_RIGHT_TO_LEFT,
}),
],
}),
new TableRow({
children: [
new TableCell({
children: [
new Paragraph({
text: "Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah Blah",
heading: HeadingLevel.HEADING_1,
}),
],
}),
new TableCell({
children: [
new Paragraph({
text: "This text should be in the middle of the cell",
}),
],
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [
new Paragraph({
text: "Text above should be vertical from bottom to top",
}),
],
verticalAlign: VerticalAlignTable.CENTER,
}),
new TableCell({
children: [
new Paragraph({
text: "Text above should be vertical from top to bottom",
}),
],
verticalAlign: VerticalAlignTable.CENTER,
}),
],
}),
],
}),
],
},
},
placeholderDelimiters: { start: "<<", end: ">>" },
}).then((doc) => {
fs.writeFileSync("My Document.docx", doc);
});

Binary file not shown.

View File

@ -1,24 +1,25 @@
# Contribution Guidelines
- Include documentation reference(s) at the top of each file as a comment. For example:
- Include documentation reference(s) at the top of each file as a comment. For example:
```ts
// http://officeopenxml.com/WPdocument.php
```
<!-- cSpell:ignore datypic -->
It can be a link to `officeopenxml.com` or `datypic.com` etc.
It could also be a reference to the official ECMA-376 standard: https://www.ecma-international.org/publications-and-standards/standards/ecma-376/
- Include a portion of the schema as a comment for cross reference. For example:
- Include a portion of the schema as a comment for cross reference. For example:
```ts
// <xsd:element name="tbl" type="CT_Tbl" minOccurs="0" maxOccurs="1"/>
```
- Follow Prettier standards, and consider using the [Prettier VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) plugin.
- Follow Prettier standards, and consider using the [Prettier VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) plugin.
- Follow the `ESLint` rules
- Follow the `ESLint` rules
## Always think about the user
@ -37,6 +38,7 @@ Please write good commit messages when making a commit: https://chris.beams.io/p
**Do not:**
<!-- cspell:disable -->
```
c // What?
rtl // Adding acronyms without explaining anything else is not helpful
@ -44,6 +46,7 @@ works! // Glad its working, but the message is not helpful
demo updated // Getting better, but capitalize the first letter
Unesesary coment removed // Make sure to use correct spelling
```
<!-- cspell:enable -->
**Do**
@ -104,25 +107,28 @@ private get _level: string;
private get level: string;
```
## Interfaces over type alias
## Types over interfaces
Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it.
Using `type` aliases in TypeScript offers several advantages over `interfaces`:
> "In general, use what you want ( type alias / interface ) just be consistent"
> "always use interface for public API's definition when authoring a library or 3rd party ambient type definitions"
>
> - https://medium.com/@martin_hotell/interface-vs-type-alias-in-typescript-2-7-2a8f1777af4c
- **Flexibility with Complex Types**: `type` supports defining unions, intersections, and other complex type constructs that `interfaces` cannot handle. For example:
`Interface` is generally preferred over `type`: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
```typescript
type StringOrNumber = string | number;
type Combined = TypeA & TypeB;
```
- **Support for Primitive Types**: `type` can alias primitive types (e.g., `type ID = string`), while `interfaces` are limited to object shapes.
- **Tuple and Array Types**: `type` allows defining tuples and specific array types easily (e.g., `type Point = [number, number]`), which `interfaces` cannot represent.
- **Utility Types Compatibility**: `type` works seamlessly with TypeScript's utility types (e.g., `Partial<T>`, `Pick<T, K>`), enabling more expressive type transformations.
- **Functional Programming**: `type` is ideal for functional programming patterns, such as defining function signatures or mapped types, due to its versatility.
- **No Declaration Merging**: Unlike `interfaces`, type does not support declaration merging, which can prevent accidental type extensions and ensure predictable type definitions.
- **Consistent Pattern**: This project uses `type` for all type definitions, so using `type` for all type definitions maintains consistency and readability across the codebase.
Detailed discussion: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
**Do not:**
```ts
type RelationshipFileInfo = { id: number; target: string };
```
**Do:**
```ts
interface IRelationshipFileInfo {
id: number;
@ -130,6 +136,12 @@ interface IRelationshipFileInfo {
}
```
**Do:**
```ts
type RelationshipFileInfo = { id: number; target: string };
```
## String enums vs type
To take full advantage of TypeScript's typing system, its best to use `string enums`:

View File

@ -16,12 +16,10 @@ const chapter1 = new Paragraph({
children: [
new Bookmark({
id: "anchorForChapter1",
children: [
new TextRun("Chapter 1"),
],
children: [new TextRun("Chapter 1")],
}),
],
})
});
```
Then you can create an hyperlink pointing to that bookmark with an `InternalHyperLink`:
@ -35,20 +33,32 @@ const link = new InternalHyperlink({
}),
],
anchor: "anchorForChapter1",
})
});
```
### Page reference
You can also get the page number of the bookmark by creating a page reference to it:
```ts
const paragraph = new Paragraph({
children: [
new TextRun("Chapter 1 can be seen on page "),
new PageReference("anchorForChapter1"),
],
children: [new TextRun("Chapter 1 can be seen on page "), new PageReference("anchorForChapter1")],
});
```
### Numbered item reference
You can also create cross references for numbered items with `NumberedItemReference`.
```ts
const paragraph = new Paragraph({
children: [new TextRun("See Paragraph "), new NumberedItemReference("anchorForParagraph1", "1.1")],
});
```
> [!NOTE]
> The `NumberedItemReference` currently needs a cached value (in this case `1.1`)
## External
To create an external hyperlink you just need to specify the url and the text of the link, then add it to a paragraph:
@ -69,7 +79,6 @@ const paragraph = new Paragraph({
});
```
## Styling hyperlinks
It is possible to set the style of the text of both internal and external hyperlinks. This can be done applying run formatting on any of the `TextRun` children of the hyperlink. Use the `style: "Hyperlink"` property to show the default link styles, which can be combined with any other style.

View File

@ -2,7 +2,7 @@
> Packers are the way in which `docx` turns your code into `.docx` format. It is completely decoupled from the `docx.Document`.
Packers works in both a node and browser environment (Angular etc). Now, the packer returns a `Buffer`, `Blob` or `base64 string`. It is up to you to take that and persist it with node's `fs`, send it down as a downloadable file, or anything else you wish. As of `version 4+`, this library will not have options to export to PDF.
Packers works in both a node and browser environment (Angular etc). Now, the packer returns a `Buffer`, `Blob`, `string`, `base64 string`, `ArrayBuffer`, or `Stream`. It is up to you to take that and persist it with node's `fs`, send it down as a downloadable file, or anything else you wish. As of `version 4+`, this library will not have options to export to PDF.
### Export as Buffer
@ -14,6 +14,14 @@ Packer.toBuffer(doc).then((buffer) => {
});
```
### Export as string
```ts
Packer.toString(doc).then((string) => {
console.log(string);
});
```
### Export as a `base64` string
```ts
@ -32,3 +40,46 @@ Packer.toBlob(doc).then((blob) => {
saveAs(blob, "example.docx");
});
```
### Export as ArrayBuffer
This may be useful when working in a Node.js worker.
```ts
Packer.toArrayBuffer(doc).then((arrayBuffer) => {
port.postMessage(arrayBuffer, [arrayBuffer]);
});
```
### Export as a Stream
```ts
Packer.toStream(doc).then((stream) => {
// read from stream
});
```
### Export using optional arguments
The `Packer` methods support 2 optional arguments.
The first is for controlling the indentation of the xml and should be a `boolean` or `keyof typeof PrettifyType`.
The second is an array of subfile overrides (`{path: string, data: string}[]`). These overrides can be used to write additional subfiles to the result or even override default subfiles in the case that the default handling of these subfiles does not meet your needs.
```ts
const overrides = [{ path: "word/commentsExtended.xml", data: "string_data" }];
Packer.toString(doc, true, overrides).then((string) => {
console.log(string);
});
```
### Export to arbitrary formats
You can also use the lower-level `Packer.pack` method to export to any specified type.
```ts
Packer.pack(doc, 'string').then((string) => {
console.log(string);
});
```

View File

@ -159,7 +159,7 @@ const tableRow = new TableRow({
| children | `Array<Paragraph or Table>` | Required. You can nest tables by adding a table into a cell |
| shading | `IShadingAttributesProperties` | Optional |
| margins | `ITableCellMarginOptions` | Optional |
| verticalAlign | `VerticalAlign` | Optional |
| verticalAlign | `VerticalAlignTable` | Optional |
| columnSpan | `number` | Optional |
| rowSpan | `number` | Optional |
| borders | `BorderOptions` | Optional |
@ -266,7 +266,7 @@ Sets the vertical alignment of the contents of the cell
```ts
const cell = new TableCell({
...,
verticalAlign: VerticalAlign,
verticalAlign: VerticalAlignTable,
});
```
@ -282,7 +282,7 @@ For example, to center align a cell:
```ts
const cell = new TableCell({
verticalAlign: VerticalAlign.CENTER,
verticalAlign: VerticalAlignTable.CENTER,
});
```

View File

@ -10,7 +10,7 @@ import tsEslint from "typescript-eslint";
const config: Linter.Config<Linter.RulesRecord>[] = [
{
ignores: ["**/vite.config.ts", "**/build/**", "**/coverage/**", "**/*.js", "eslint.config.ts", "**/demo/**", "**/scripts/**"],
ignores: ["**/vite.config.ts", "**/dist/**", "**/coverage/**", "**/*.js", "eslint.config.ts", "**/demo/**", "**/scripts/**"],
},
eslint.configs.recommended,
importPlugin.flatConfigs.recommended,

12280
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,25 @@
{
"name": "docx",
"version": "9.1.0",
"version": "9.5.0",
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
"type": "module",
"main": "build/index.umd.js",
"module": "./build/index.mjs",
"types": "./build/index.d.ts",
"main": "dist/index.umd.cjs",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"require": "./build/index.cjs",
"types": "./build/index.d.ts",
"import": "./build/index.mjs",
"default": "./build/index.mjs"
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.mjs"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"files": [
"build"
"dist"
],
"scripts": {
"build": "tsc && vite build",
@ -57,7 +61,7 @@
"@types/node": "^22.7.5",
"hash.js": "^1.1.7",
"jszip": "^3.10.1",
"nanoid": "^5.0.4",
"nanoid": "^5.1.3",
"xml": "^1.0.1",
"xml-js": "^1.6.8"
},
@ -68,7 +72,6 @@
},
"homepage": "https://docx.js.org",
"devDependencies": {
"@eslint/compat": "^1.2.1",
"@types/eslint__js": "^8.42.3",
"@types/inquirer": "^9.0.3",
"@types/prompt": "^1.1.1",
@ -76,36 +79,36 @@
"@types/xml": "^1.0.8",
"@typescript-eslint/eslint-plugin": "^8.8.1",
"@typescript-eslint/parser": "^8.8.1",
"@vitest/coverage-v8": "^1.1.0",
"@vitest/ui": "^2.1.2",
"cspell": "^8.2.3",
"@vitest/coverage-v8": "^3.0.8",
"@vitest/ui": "^3.0.8",
"cspell": "^9.0.0",
"docsify-cli": "^4.3.0",
"eslint": "^9.13.0",
"eslint-import-resolver-typescript": "^3.6.3",
"eslint-plugin-functional": "^7.0.2",
"eslint-import-resolver-typescript": "^4.3.2",
"eslint-plugin-functional": "^9.0.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^50.3.1",
"eslint-plugin-no-null": "^1.0.2",
"eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-unicorn": "^56.0.0",
"eslint-plugin-unicorn": "^59.0.0",
"execa": "^9.4.0",
"glob": "^11.0.0",
"inquirer": "^12.0.0",
"jiti": "^2.3.3",
"jsdom": "^25.0.1",
"jsdom": "^26.0.0",
"pre-commit": "^1.2.2",
"prettier": "^3.1.1",
"tsconfig-paths": "^4.0.0",
"tsx": "^4.7.0",
"typedoc": "^0.26.9",
"typedoc": "^0.28.2",
"typescript": "5.3.3",
"typescript-eslint": "^8.10.0",
"unzipper": "^0.12.3",
"vite": "^5.0.10",
"vite": "^6.0.1",
"vite-plugin-dts": "^4.2.4",
"vite-plugin-node-polyfills": "^0.22.0",
"vite-plugin-node-polyfills": "^0.23.0",
"vite-tsconfig-paths": "^5.0.1",
"vitest": "^1.1.0"
"vitest": "^3.0.8"
},
"engines": {
"node": ">=10"

View File

@ -36,7 +36,7 @@ describe("Compiler", () => {
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(19);
expect(fileNames).has.length(20);
expect(fileNames).to.include("word/document.xml");
expect(fileNames).to.include("word/styles.xml");
expect(fileNames).to.include("docProps/core.xml");
@ -96,7 +96,7 @@ describe("Compiler", () => {
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(27);
expect(fileNames).has.length(28);
expect(fileNames).to.include("word/header1.xml");
expect(fileNames).to.include("word/_rels/header1.xml.rels");
@ -112,6 +112,41 @@ describe("Compiler", () => {
},
);
it(
"should pack subfile overrides",
async () => {
const file = new File({
sections: [],
comments: {
children: [],
},
});
const subfileData1 = "comments";
const subfileData2 = "commentsExtended";
const overrides = [
{ path: "word/comments.xml", data: subfileData1 },
{ path: "word/commentsExtended.xml", data: subfileData2 },
];
const zipFile = compiler.compile(file, "", overrides);
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(21);
expect(fileNames).to.include("word/comments.xml");
expect(fileNames).to.include("word/commentsExtended.xml");
const commentsText = await zipFile.file("word/comments.xml")?.async("text");
const commentsExtendedText = await zipFile.file("word/commentsExtended.xml")?.async("text");
expect(commentsText).toBe(subfileData1);
expect(commentsExtendedText).toBe(subfileData2);
},
{
timeout: 99999999,
},
);
it("should call the format method X times equalling X files to be formatted", () => {
// This test is required because before, there was a case where Document was formatted twice, which was inefficient
// This also caused issues such as running prepForXml multiple times as format() was ran multiple times.
@ -128,7 +163,7 @@ describe("Compiler", () => {
const spy = vi.spyOn(compiler["formatter"], "format");
compiler.compile(file);
expect(spy).toBeCalledTimes(15);
expect(spy).toBeCalledTimes(16);
});
it("should work with media datas", () => {

View File

@ -9,7 +9,7 @@ import { ImageReplacer } from "./image-replacer";
import { NumberingReplacer } from "./numbering-replacer";
import { PrettifyType } from "./packer";
type IXmlifyedFile = {
export type IXmlifyedFile = {
readonly data: string;
readonly path: string;
};
@ -32,6 +32,7 @@ type IXmlifyedFileMapping = {
readonly FootNotesRelationships: IXmlifyedFile;
readonly Settings: IXmlifyedFile;
readonly Comments?: IXmlifyedFile;
readonly CommentsRelationships?: IXmlifyedFile;
readonly FontTable?: IXmlifyedFile;
readonly FontTableRelationships?: IXmlifyedFile;
};
@ -47,7 +48,11 @@ export class Compiler {
this.numberingReplacer = new NumberingReplacer();
}
public compile(file: File, prettifyXml?: (typeof PrettifyType)[keyof typeof PrettifyType]): JSZip {
public compile(
file: File,
prettifyXml?: (typeof PrettifyType)[keyof typeof PrettifyType],
overrides: readonly IXmlifyedFile[] = [],
): JSZip {
const zip = new JSZip();
const xmlifiedFileMapping = this.xmlifyFile(file, prettifyXml);
const map = new Map<string, IXmlifyedFile | readonly IXmlifyedFile[]>(Object.entries(xmlifiedFileMapping));
@ -62,6 +67,10 @@ export class Compiler {
}
}
for (const subFile of overrides) {
zip.file(subFile.path, subFile.data);
}
for (const data of file.Media.Array) {
if (data.type !== "svg") {
zip.file(`word/media/${data.fileName}`, data.data);
@ -96,7 +105,28 @@ export class Compiler {
},
},
);
const commentRelationshipCount = file.Comments.Relationships.RelationshipCount + 1;
const commentXmlData = xml(
this.formatter.format(file.Comments, {
viewWrapper: {
View: file.Comments,
Relationships: file.Comments.Relationships,
},
file,
stack: [],
}),
{
indent: prettify,
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
},
);
const documentMediaDatas = this.imageReplacer.getMediaData(documentXmlData, file.Media);
const commentMediaDatas = this.imageReplacer.getMediaData(commentXmlData, file.Media);
return {
Relationships: {
@ -442,22 +472,41 @@ export class Compiler {
path: "word/settings.xml",
},
Comments: {
data: xml(
this.formatter.format(file.Comments, {
viewWrapper: file.Document,
file,
stack: [],
}),
{
indent: prettify,
declaration: {
standalone: "yes",
encoding: "UTF-8",
},
},
),
data: (() => {
const xmlData = this.imageReplacer.replace(commentXmlData, commentMediaDatas, commentRelationshipCount);
const referenedXmlData = this.numberingReplacer.replace(xmlData, file.Numbering.ConcreteNumbering);
return referenedXmlData;
})(),
path: "word/comments.xml",
},
CommentsRelationships: {
data: (() => {
commentMediaDatas.forEach((mediaData, i) => {
file.Comments.Relationships.createRelationship(
commentRelationshipCount + i,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
`media/${mediaData.fileName}`,
);
});
return xml(
this.formatter.format(file.Comments.Relationships, {
viewWrapper: {
View: file.Comments,
Relationships: file.Comments.Relationships,
},
file,
stack: [],
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
);
})(),
path: "word/_rels/comments.xml.rels",
},
FontTable: {
data: xml(
this.formatter.format(file.FontTable.View, {

View File

@ -46,7 +46,7 @@ describe("Packer", () => {
await Packer.toString(file, true);
expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_2_BLANKS);
expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_2_BLANKS, expect.anything());
});
it("should use a prettify value", async () => {
@ -55,7 +55,7 @@ describe("Packer", () => {
await Packer.toString(file, PrettifyType.WITH_4_BLANKS);
expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_4_BLANKS);
expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_4_BLANKS, expect.anything());
});
it("should use an undefined prettify value", async () => {
@ -64,7 +64,32 @@ describe("Packer", () => {
await Packer.toString(file, false);
expect(spy).toBeCalledWith(expect.anything(), undefined);
expect(spy).toBeCalledWith(expect.anything(), undefined, expect.anything());
});
});
describe("overrides", () => {
afterEach(() => {
vi.restoreAllMocks();
});
it("should use an overrides value", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const spy = vi.spyOn((Packer as any).compiler, "compile");
const overrides = [{ path: "word/comments.xml", data: "comments" }];
await Packer.toString(file, true, overrides);
expect(spy).toBeCalledWith(expect.anything(), expect.anything(), overrides);
});
it("should use a default overrides value", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const spy = vi.spyOn((Packer as any).compiler, "compile");
await Packer.toString(file);
expect(spy).toBeCalledWith(expect.anything(), undefined, []);
});
});
@ -162,6 +187,33 @@ describe("Packer", () => {
});
});
describe("#toArrayBuffer()", () => {
it("should create a standard docx file", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
vi.spyOn((Packer as any).compiler, "compile").mockReturnValue({
generateAsync: () => vi.fn(),
});
const str = await Packer.toArrayBuffer(file);
assert.isDefined(str);
});
it("should handle exception if it throws any", () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
vi.spyOn((Packer as any).compiler, "compile").mockImplementation(() => {
throw new Error();
});
return Packer.toArrayBuffer(file).catch((error) => {
assert.isDefined(error);
});
});
afterEach(() => {
vi.resetAllMocks();
});
});
describe("#toStream()", () => {
it("should create a standard docx file", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@ -1,8 +1,9 @@
import { Stream } from "stream";
import { File } from "@file/file";
import { OutputByType, OutputType } from "@util/output-type";
import { Compiler } from "./next-compiler";
import { Compiler, IXmlifyedFile } from "./next-compiler";
/**
* Use blanks to prettify
@ -21,53 +22,68 @@ const convertPrettifyType = (
prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify;
export class Packer {
public static async toString(file: File, prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType]): Promise<string> {
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
const zipData = await zip.generateAsync({
type: "string",
// eslint-disable-next-line require-await
public static async pack<T extends OutputType>(
file: File,
type: T,
prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType],
overrides: readonly IXmlifyedFile[] = [],
): Promise<OutputByType[T]> {
const zip = this.compiler.compile(file, convertPrettifyType(prettify), overrides);
return zip.generateAsync({
type,
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
});
return zipData;
}
public static async toBuffer(file: File, prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType]): Promise<Buffer> {
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
const zipData = await zip.generateAsync({
type: "nodebuffer",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
});
return zipData;
public static toString(
file: File,
prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType],
overrides: readonly IXmlifyedFile[] = [],
): Promise<string> {
return Packer.pack(file, "string", prettify, overrides);
}
public static async toBase64String(file: File, prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType]): Promise<string> {
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
const zipData = await zip.generateAsync({
type: "base64",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
});
return zipData;
public static toBuffer(
file: File,
prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType],
overrides: readonly IXmlifyedFile[] = [],
): Promise<Buffer> {
return Packer.pack(file, "nodebuffer", prettify, overrides);
}
public static async toBlob(file: File, prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType]): Promise<Blob> {
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
const zipData = await zip.generateAsync({
type: "blob",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
});
return zipData;
public static toBase64String(
file: File,
prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType],
overrides: readonly IXmlifyedFile[] = [],
): Promise<string> {
return Packer.pack(file, "base64", prettify, overrides);
}
public static toStream(file: File, prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType]): Stream {
public static toBlob(
file: File,
prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType],
overrides: readonly IXmlifyedFile[] = [],
): Promise<Blob> {
return Packer.pack(file, "blob", prettify, overrides);
}
public static toArrayBuffer(
file: File,
prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType],
overrides: readonly IXmlifyedFile[] = [],
): Promise<ArrayBuffer> {
return Packer.pack(file, "arraybuffer", prettify, overrides);
}
public static toStream(
file: File,
prettify?: boolean | (typeof PrettifyType)[keyof typeof PrettifyType],
overrides: readonly IXmlifyedFile[] = [],
): Stream {
const stream = new Stream();
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
const zip = this.compiler.compile(file, convertPrettifyType(prettify), overrides);
zip.generateAsync({
type: "nodebuffer",

View File

@ -55,32 +55,101 @@ class BordersAttributes extends XmlAttributeComponent<IBorderOptions> {
};
}
/**
* Table borders are defined with the <w:tblBorders> element. Child elements of this element specify the kinds of `border`:
*
* `bottom`, `end` (`right` in the previous version of the standard), `insideH`, `insideV`, `start` (`left` in the previous version of the standard), and `top`.
*
* Reference: http://officeopenxml.com/WPtableBorders.php
*
* ## XSD Schema
* ```xml
* <xsd:simpleType name="ST_Border">
* <xsd:restriction base="xsd:string">
* <xsd:enumeration value="single"/>
* <xsd:enumeration value="dashDotStroked"/>
* <xsd:enumeration value="dashed"/>
* <xsd:enumeration value="dashSmallGap"/>
* <xsd:enumeration value="dotDash"/>
* <xsd:enumeration value="dotDotDash"/>
* <xsd:enumeration value="dotted"/>
* <xsd:enumeration value="double"/>
* <xsd:enumeration value="doubleWave"/>
* <xsd:enumeration value="inset"/>
* <xsd:enumeration value="nil"/>
* <xsd:enumeration value="none"/>
* <xsd:enumeration value="outset"/>
* <xsd:enumeration value="thick"/>
* <xsd:enumeration value="thickThinLargeGap"/>
* <xsd:enumeration value="thickThinMediumGap"/>
* <xsd:enumeration value="thickThinSmallGap"/>
* <xsd:enumeration value="thinThickLargeGap"/>
* <xsd:enumeration value="thinThickMediumGap"/>
* <xsd:enumeration value="thinThickSmallGap"/>
* <xsd:enumeration value="thinThickThinLargeGap"/>
* <xsd:enumeration value="thinThickThinMediumGap"/>
* <xsd:enumeration value="thinThickThinSmallGap"/>
* <xsd:enumeration value="threeDEmboss"/>
* <xsd:enumeration value="threeDEngrave"/>
* <xsd:enumeration value="triple"/>
* <xsd:enumeration value="wave"/>
* </xsd:restriction>
* </xsd:simpleType>
* ```
*/
export const BorderStyle = {
/** a single line */
SINGLE: "single",
/** a line with a series of alternating thin and thick strokes */
DASH_DOT_STROKED: "dashDotStroked",
/** a dashed line */
DASHED: "dashed",
/** a dashed line with small gaps */
DASH_SMALL_GAP: "dashSmallGap",
/** a line with alternating dots and dashes */
DOT_DASH: "dotDash",
/** a line with a repeating dot - dot - dash sequence */
DOT_DOT_DASH: "dotDotDash",
/** a dotted line */
DOTTED: "dotted",
/** a double line */
DOUBLE: "double",
/** a double wavy line */
DOUBLE_WAVE: "doubleWave",
/** an inset set of lines */
INSET: "inset",
/** no border */
NIL: "nil",
/** no border */
NONE: "none",
/** an outset set of lines */
OUTSET: "outset",
/** a single line */
THICK: "thick",
/** a thick line contained within a thin line with a large-sized intermediate gap */
THICK_THIN_LARGE_GAP: "thickThinLargeGap",
/** a thick line contained within a thin line with a medium-sized intermediate gap */
THICK_THIN_MEDIUM_GAP: "thickThinMediumGap",
/** a thick line contained within a thin line with a small intermediate gap */
THICK_THIN_SMALL_GAP: "thickThinSmallGap",
/** a thin line contained within a thick line with a large-sized intermediate gap */
THIN_THICK_LARGE_GAP: "thinThickLargeGap",
/** a thick line contained within a thin line with a medium-sized intermediate gap */
THIN_THICK_MEDIUM_GAP: "thinThickMediumGap",
/** a thick line contained within a thin line with a small intermediate gap */
THIN_THICK_SMALL_GAP: "thinThickSmallGap",
/** a thin-thick-thin line with a large gap */
THIN_THICK_THIN_LARGE_GAP: "thinThickThinLargeGap",
/** a thin-thick-thin line with a medium gap */
THIN_THICK_THIN_MEDIUM_GAP: "thinThickThinMediumGap",
/** a thin-thick-thin line with a small gap */
THIN_THICK_THIN_SMALL_GAP: "thinThickThinSmallGap",
/** a three-staged gradient line, getting darker towards the paragraph */
THREE_D_EMBOSS: "threeDEmboss",
/** a three-staged gradient like, getting darker away from the paragraph */
THREE_D_ENGRAVE: "threeDEngrave",
/** a triple line */
TRIPLE: "triple",
/** a wavy line */
WAVE: "wave",
} as const;

View File

@ -2,7 +2,7 @@ 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 { StringContainer, XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { dateTimeValue } from "@util/values";
import { ICustomPropertyOptions } from "../custom-properties";
@ -75,15 +75,7 @@ export type IPropertiesOptions = {
export class CoreProperties extends XmlComponent {
public constructor(options: Omit<IPropertiesOptions, "sections">) {
super("cp:coreProperties");
this.root.push(
new DocumentAttributes({
cp: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
dc: "http://purl.org/dc/elements/1.1/",
dcterms: "http://purl.org/dc/terms/",
dcmitype: "http://purl.org/dc/dcmitype/",
xsi: "http://www.w3.org/2001/XMLSchema-instance",
}),
);
this.root.push(new DocumentAttributes(["cp", "dc", "dcterms", "dcmitype", "xsi"]));
if (options.title) {
this.root.push(new StringContainer("dc:title", options.title));
}
@ -110,11 +102,15 @@ export class CoreProperties extends XmlComponent {
}
}
class TimestampElementProperties extends XmlAttributeComponent<{ readonly type: string }> {
protected readonly xmlKeys = { type: "xsi:type" };
}
class TimestampElement extends XmlComponent {
public constructor(name: string) {
super(name);
this.root.push(
new DocumentAttributes({
new TimestampElementProperties({
type: "dcterms:W3CDTF",
}),
);

View File

@ -2,26 +2,26 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { DocumentGrid, DocumentGridType } from ".";
import { DocumentGridType, createDocumentGrid } from ".";
describe("DocumentGrid", () => {
describe("createDocumentGrid", () => {
describe("#constructor()", () => {
it("should create documentGrid with specified linePitch", () => {
const docGrid = new DocumentGrid(360);
const docGrid = createDocumentGrid({ linePitch: 360 });
const tree = new Formatter().format(docGrid);
expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 360 } });
});
it("should create documentGrid with specified linePitch and type", () => {
const docGrid = new DocumentGrid(360, undefined, DocumentGridType.LINES);
const docGrid = createDocumentGrid({ linePitch: 360, type: DocumentGridType.LINES });
const tree = new Formatter().format(docGrid);
expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 360, "w:type": "lines" } });
});
it("should create documentGrid with specified linePitch,charSpace and type", () => {
const docGrid = new DocumentGrid(346, -1541, DocumentGridType.LINES_AND_CHARS);
const docGrid = createDocumentGrid({ linePitch: 346, charSpace: -1541, type: DocumentGridType.LINES_AND_CHARS });
const tree = new Formatter().format(docGrid);
expect(tree["w:docGrid"]).to.deep.equal({ _attr: { "w:linePitch": 346, "w:charSpace": -1541, "w:type": "linesAndChars" } });

View File

@ -1,53 +1,113 @@
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { decimalNumber } from "@util/values";
// not implemented
// <xsd:simpleType name="ST_DocGrid">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="default"/>
// <xsd:enumeration value="lines"/>
// <xsd:enumeration value="linesAndChars"/>
// <xsd:enumeration value="snapToChars"/>
// </xsd:restriction>
// </xsd:simpleType>
// <xsd:complexType name="CT_DocGrid">
// <xsd:attribute name="type" type="ST_DocGrid"/>
// <xsd:attribute name="linePitch" type="ST_DecimalNumber"/>
// <xsd:attribute name="charSpace" type="ST_DecimalNumber"/>
// </xsd:complexType>
/**
* Specifies the type of the current document grid, which defines the grid behavior.
*
* The grid can define a grid which snaps all East Asian characters to grid positions, but leaves Latin text with its default spacing; a grid which adds the specified character pitch to all characters on each row; or a grid which affects only the line pitch for the current section.
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_DocGrid_topic_ID0ELYP2.html
*
* ## XSD Schema
* ```xml
* <xsd:simpleType name="ST_DocGrid">
* <xsd:restriction base="xsd:string">
* <xsd:enumeration value="default"/>
* <xsd:enumeration value="lines"/>
* <xsd:enumeration value="linesAndChars"/>
* <xsd:enumeration value="snapToChars"/>
* </xsd:restriction>
* </xsd:simpleType>
* ```
*/
export const DocumentGridType = {
/**
* Specifies that no document grid shall be applied to the contents of the current section in the document.
*/
DEFAULT: "default",
/**
* Specifies that the parent section shall have additional line pitch added to each line within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain the specified number of lines per page.
*/
LINES: "lines",
/**
* Specifies that the parent section shall have both the additional line pitch and character pitch added to each line and character within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain a specific number of lines per page and characters per line.
*
* When this value is set, the input specified via the user interface may be allowed in exact number of line/character pitch units. */
LINES_AND_CHARS: "linesAndChars",
/**
* Specifies that the parent section shall have both the additional line pitch and character pitch added to each line and character within it (as specified on the <docGrid> element (§2.6.5)) in order to maintain a specific number of lines per page and characters per line.
*
* When this value is set, the input specified via the user interface may be restricted to the number of lines per page and characters per line, with the consumer or producer translating this information based on the current font data to get the resulting line and character pitch values
*/
SNAP_TO_CHARS: "snapToChars",
} as const;
export type IDocGridAttributesProperties = {
/**
* Specifies the type of the current document grid, which defines the grid behavior.
*
* The grid can define a grid which snaps all East Asian characters to grid positions, but leaves Latin text with its default spacing; a grid which adds the specified character pitch to each character on each row; or a grid which affects only the line pitch for the current section.
*/
readonly type?: (typeof DocumentGridType)[keyof typeof DocumentGridType];
readonly linePitch?: number;
/**
* Specifies the number of lines to be allowed on the document grid for the current page assuming all lines have equal line pitch applied to them. This line pitch shall not be added to any line which appears within a table cell unless the <adjustLineHeightInTable> element (§2.15.3.1) is present in the document's compatibility settings.
*
* This attribute is specified in twentieths of a point, and defines the pitch for each line of text on this page such that the desired number of single spaced lines of text fits on the current page.
*
* ```xml
* <w:docGrid w:linePitch="684" …/>
* ```
*
* The `linePitch` attribute specifies that 34.2 points is to the amount of pitch allowed for each line on this page in order to maintain the specific document grid. ]
*
* Individual paragraphs can override the line pitch information specified for the document grid by either:
*
* Specifying an exact line spacing value using the `lineRule` attribute of value exact on the <spacing> element (§2.3.1.33).
*
* Specifying that the paragraph text shall not snap to the document grid via the <snapToGrid> element (§2.3.1.32).
*
* The possible values for this attribute are defined by the ST_DecimalNumber simple type (§2.18.16).
*/
readonly linePitch: number;
/**
* Specifies the number of characters to be allowed on the document grid for each line in this section.
*
* This attribute's value shall be specified by multiplying the difference between the desired character pitch and the character pitch for that character in the font size of the Normal font by 4096.
*
* This value shall then be used to add the character pitch for the specified point size to each character in the section [: This results in text in the Normal style having a specific number of characters per line. ]
*
* ```xml
* <w:docGrid w:charSize="40960" …/>
* ```
* The `charSpace` attribute specifies a value of 40960, which means that the delta between the character pitch of each character in the grid and the Normal font is 10 points, resulting in a character pitch of 11+10 = 21 points for all characters in this section. ]
*
* Individual runs of text can override the line pitch information specified for the document grid by specifying that the run text shall not snap to the document grid via the <snapToGrid> element (§2.3.2.32).
*
* The possible values for this attribute are defined by the `ST_DecimalNumber` simple type (§2.18.16).
*/
readonly charSpace?: number;
};
export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
protected readonly xmlKeys = {
type: "w:type",
linePitch: "w:linePitch",
charSpace: "w:charSpace",
};
}
export class DocumentGrid extends XmlComponent {
public constructor(linePitch: number, charSpace?: number, type?: (typeof DocumentGridType)[keyof typeof DocumentGridType]) {
super("w:docGrid");
this.root.push(
new DocGridAttributes({
type: type,
linePitch: decimalNumber(linePitch),
charSpace: charSpace ? decimalNumber(charSpace) : undefined,
}),
);
}
}
/**
* This element specifies the settings for the document grid, which enables precise layout of full-width East Asian language characters within a document by specifying the desired number of characters per line and lines per page for all East Asian text content in this section.
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_docGrid_topic_ID0EHU5S.html
*
* ```xml
* <xsd:complexType name="CT_DocGrid">
* <xsd:attribute name="type" type="ST_DocGrid"/>
* <xsd:attribute name="linePitch" type="ST_DecimalNumber"/>
* <xsd:attribute name="charSpace" type="ST_DecimalNumber"/>
* </xsd:complexType>
* ```
* @returns
*/
export const createDocumentGrid = ({ type, linePitch, charSpace }: IDocGridAttributesProperties): XmlComponent =>
new BuilderElement<IDocGridAttributesProperties>({
name: "w:docGrid",
attributes: {
type: { key: "w:type", value: type },
linePitch: { key: "w:linePitch", value: decimalNumber(linePitch) },
charSpace: { key: "w:charSpace", value: charSpace ? decimalNumber(charSpace) : undefined },
},
});

View File

@ -1,19 +1,30 @@
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
// <xsd:simpleType name="ST_HdrFtr">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="even"/>
// <xsd:enumeration value="default"/>
// <xsd:enumeration value="first"/>
// </xsd:restriction>
// </xsd:simpleType>
/**
* This simple type specifies the possible types of headers and footers which may be specified for a given header or footer reference in a document. This value determines the page(s) on which the current header or footer shall be displayed.
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_HdrFtr_topic_ID0E2UW2.html
*
* ## XSD Schema
* ```xml
* <xsd:simpleType name="ST_HdrFtr">
* <xsd:restriction base="xsd:string">
* <xsd:enumeration value="even"/>
* <xsd:enumeration value="default"/>
* <xsd:enumeration value="first"/>
* </xsd:restriction>
* </xsd:simpleType>
* ```
*/
export const HeaderFooterReferenceType = {
/** Specifies that this header or footer shall appear on every page in this section which is not overridden with a specific `even` or `first` page header/footer. In a section with all three types specified, this type shall be used on all odd numbered pages (counting from the `first` page in the section, not the section numbering). */
DEFAULT: "default",
/** Specifies that this header or footer shall appear on the first page in this section. The appearance of this header or footer is contingent on the setting of the `titlePg` element (§2.10.6). */
FIRST: "first",
/** Specifies that this header or footer shall appear on all even numbered pages in this section (counting from the first page in the section, not the section numbering). The appearance of this header or footer is contingent on the setting of the `evenAndOddHeaders` element (§2.10.1). */
EVEN: "even",
} as const;
// </xsd:complexType>
// <xsd:group name="EG_HdrFtrReferences">
// <xsd:choice>
// <xsd:element name="headerReference" type="CT_HdrFtrRef" minOccurs="0"/>

View File

@ -1,35 +1,128 @@
// http://officeopenxml.com/WPsectionLineNumbering.php
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { PositiveUniversalMeasure, decimalNumber, twipsMeasureValue } from "@util/values";
// <xsd:simpleType name="ST_LineNumberRestart">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="newPage"/>
// <xsd:enumeration value="newSection"/>
// <xsd:enumeration value="continuous"/>
// </xsd:restriction>
// </xsd:simpleType>
/**
* This simple type specifies when the line numbering in the parent section shall be reset to its restart value. The line numbering increments for each line (even if the line number itself is not displayed) until it reaches the restart point specified by this element.
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_LineNumberRestart_topic_ID0EUS42.html
*
* ## XSD Schema
*
* ```xml
* <xsd:simpleType name="ST_LineNumberRestart">
* <xsd:restriction base="xsd:string">
* <xsd:enumeration value="newPage"/>
* <xsd:enumeration value="newSection"/>
* <xsd:enumeration value="continuous"/>
* </xsd:restriction>
* </xsd:simpleType>
* ```
*/
export const LineNumberRestartFormat = {
/**
* ## Restart Line Numbering on Each Page
*
* Specifies that line numbering for the parent section shall restart to the starting value whenever a new page is displayed.
*/
NEW_PAGE: "newPage",
/**
* ## Restart Line Numbering for Each Section
*
* Specifies that line numbering for the parent section shall restart to the starting value whenever the parent begins.
*/
NEW_SECTION: "newSection",
/**
* ## Continue Line Numbering From Previous Section
*
* Specifies that line numbering for the parent section shall continue from the line numbering from the end of the previous section, if any.
*/
CONTINUOUS: "continuous",
} as const;
// <xsd:complexType name="CT_LineNumber">
// <xsd:attribute name="countBy" type="ST_DecimalNumber" use="optional"/>
// <xsd:attribute name="start" type="ST_DecimalNumber" use="optional" default="1"/>
// <xsd:attribute name="distance" type="s:ST_TwipsMeasure" use="optional"/>
// <xsd:attribute name="restart" type="ST_LineNumberRestart" use="optional" default="newPage"/>
// </xsd:complexType>
export type ILineNumberAttributes = {
/**
* Specifies the line number increments to be displayed in the current document.
*
* Although each line has an associated line number, only lines which are an even multiple of this value shall be displayed.
*
* ### Example
*
* ```xml
* <w:lnNumType … w:countBy="5"/>
* ```
*
* This setting ensures that only lines whose number is a multiple of (e.g. 5, 10, and 15) will have a line number displayed. ]
*
* The possible values for this attribute are defined by the ST_DecimalNumber simple type (§2.18.16).
*/
readonly countBy?: number;
/**
* ## Line Numbering Starting Value
*
* Specifies the starting value used for the first line whenever the line numbering is restarted by use of the `restart` attribute.
*
* ### Example
*
* ```xml
* <w:lnNumType w:start="3" w:countBy="5"/>
* ```
*
* The `start` attribute specifies that line numbers shall be counted starting from the number 3.
*
* The possible values for this attribute are defined by the ST_DecimalNumber simple type (§2.18.16).
*/
readonly start?: number;
/**
* ## Line Numbering Restart Setting
*
* Specifies when the line numbering in this section shall be reset to the line number specified by the `start` attribute's value.
*
* The line numbering increments for each line (even if it is not displayed) until it reaches the restart point specified by this element.
*
* ### Example
*
* ```xml
* <w:sectPr>
* ...
* <w:lnNumType w:restart="newPage" ... />
* </w:sectPr>
* ```
*
* The value of `newPage` specifies that the line numbers shall restart at the top of each page to the value specified by the `start` attribute. In this case, `newPage` is the default, so this value could have been omitted entirely.
*
* The possible values for this attribute are defined by the ST_LineNumberRestart simple type (§2.18.54).
*/
readonly restart?: (typeof LineNumberRestartFormat)[keyof typeof LineNumberRestartFormat];
/**
* Specifies the distance between the text margin and the edge of any line numbers appearing in that section.
*
* ```.xml
* <w:lnNumType ... w:distance="720"/>
* ```
*
* The possible values for this attribute are defined by the ST_TwipsMeasure simple type (§2.18.105).
*/
readonly distance?: number | PositiveUniversalMeasure;
};
/**
* This element specifies the settings for line numbering to be displayed before each column of text in this section in the document.
*
* References:
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_lnNumType_topic_ID0EVRAT.html
* - http://officeopenxml.com/WPsectionLineNumbering.php
*
* ## XSD Schema
*
* ```xml
* <xsd:complexType name="CT_LineNumber">
* <xsd:attribute name="countBy" type="ST_DecimalNumber" use="optional"/>
* <xsd:attribute name="start" type="ST_DecimalNumber" use="optional" default="1"/>
* <xsd:attribute name="distance" type="s:ST_TwipsMeasure" use="optional"/>
* <xsd:attribute name="restart" type="ST_LineNumberRestart" use="optional" default="newPage"/>
* </xsd:complexType>
* ```
*/
export const createLineNumberType = ({ countBy, start, restart, distance }: ILineNumberAttributes): XmlComponent =>
new BuilderElement<ILineNumberAttributes>({
name: "w:lnNumType",

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { PageOrientation, PageSize } from "./page-size";
import { PageOrientation, createPageSize } from "./page-size";
describe("PageSize", () => {
describe("#constructor()", () => {
it("should create page size with portrait", () => {
const properties = new PageSize(100, 200, PageOrientation.PORTRAIT);
const properties = createPageSize({ width: 100, height: 200, orientation: PageOrientation.PORTRAIT });
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);
@ -15,7 +15,7 @@ describe("PageSize", () => {
});
it("should create page size with horizontal and invert the lengths", () => {
const properties = new PageSize(100, 200, PageOrientation.LANDSCAPE);
const properties = createPageSize({ width: 100, height: 200, orientation: PageOrientation.LANDSCAPE });
const tree = new Formatter().format(properties);
expect(Object.keys(tree)).to.deep.equal(["w:pgSz"]);

View File

@ -1,48 +1,132 @@
import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
// <xsd:simpleType name="ST_PageOrientation">
// <xsd:restriction base="xsd:string">
// <xsd:enumeration value="portrait"/>
// <xsd:enumeration value="landscape"/>
// </xsd:restriction>
// </xsd:simpleType>
/**
* This simple type specifies the orientation of all pages in the parent section. This information is used to determine the actual paper size to use when printing the file.
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_PageOrientation_topic_ID0EKBK3.html
*
* ## XSD Schema
*
* ```xml
* <xsd:simpleType name="ST_PageOrientation">
* <xsd:restriction base="xsd:string">
* <xsd:enumeration value="portrait"/>
* <xsd:enumeration value="landscape"/>
* </xsd:restriction>
* </xsd:simpleType>
* ```
*/
export const PageOrientation = {
/**
* ## Portrait Mode
*
* Specifies that pages in this section shall be printed in portrait mode.
*/
PORTRAIT: "portrait",
/**
* ## Landscape Mode
*
* Specifies that pages in this section shall be printed in landscape mode, which prints the page contents with a 90 degree rotation with respect to the normal page orientation.
*/
LANDSCAPE: "landscape",
} as const;
// <xsd:complexType name="CT_PageSz">
// <xsd:attribute name="w" type="s:ST_TwipsMeasure"/>
// <xsd:attribute name="h" type="s:ST_TwipsMeasure"/>
// <xsd:attribute name="orient" type="ST_PageOrientation" use="optional"/>
// <xsd:attribute name="code" type="ST_DecimalNumber" use="optional"/>
// </xsd:complexType>
export type IPageSizeAttributes = {
readonly width?: number | PositiveUniversalMeasure;
readonly height?: number | PositiveUniversalMeasure;
/**
* ## Page Width
*
* This attribute indicates the width (in twentieths of a point) for all pages in the current section.
*
* ### Example
*
* ```xml
* <w:pgSz w:w="15840" w:h="12240" />
* ```
*
* All pages in this section are displayed on a page that is 15840 twentieths of a point (11") wide.
*
* The possible values for this attribute are defined by the ST_TwipsMeasure simple type (§2.18.105).
*/
readonly width: number | PositiveUniversalMeasure;
/**
* ## Page Height
*
* Specifies the height (in twentieths of a point) for all pages in the current section.
*
* ### Example
*
* ```xml
* <w:pgSz w:w="15840" w:h="12240" />
* ```
*
* All pages in this section are displayed on a page that is `12240` twentieths of a point (`8.5"`) tall.
*
* The possible values for this attribute are defined by the `ST_TwipsMeasure` simple type (§2.18.105).
*/
readonly height: number | PositiveUniversalMeasure;
/**
* ## Page Orientation
*
* Specifies the orientation of all pages in this section.
*
* This information is used to determine the actual paper size to use on the printer.
*
* This implies that the actual paper size width and height are reversed for pages in this section. If this attribute is omitted, then portrait shall be implied.
*
* ### Example
*
* ```xml
* <w:pgSz w:w="15840" w:h="12240" w:orient="landscape" />
* ```
*
* Although the page width is 11", and page height is 8.5", according to the `w` and `h` attributes, because the `orient` attribute is set to landscape, pages in this section are printed on 8.5x11" paper in landscape mode.
*
* The possible values for this attribute are defined by the `ST_PageOrientation` simple type (§2.18.71).
*/
readonly orientation?: (typeof PageOrientation)[keyof typeof PageOrientation];
/**
* ## Printer Paper Code
*
* Specifies a printer-specific paper code for the paper type, which shall be used by the printer for pages in this section.
*
* This code is stored to ensure the proper paper type is chosen if the specified paper size matches the sizes of multiple paper types supported by the current printer.
*
* It will be sent to the printer and used by the printer to determine the appropriate paper type to use when printing.
*
* This value is not interpreted or modified other than storing it as specified by the printer.
*
* The possible values for this attribute are defined by the `ST_DecimalNumber` simple type (§2.18.16).
*/
readonly code?: number;
};
export class PageSize extends XmlComponent {
public constructor(
width: number | PositiveUniversalMeasure,
height: number | PositiveUniversalMeasure,
orientation: (typeof PageOrientation)[keyof typeof PageOrientation],
) {
super("w:pgSz");
const flip = orientation === PageOrientation.LANDSCAPE;
const widthTwips = twipsMeasureValue(width);
const heightTwips = twipsMeasureValue(height);
this.root.push(
new NextAttributeComponent<IPageSizeAttributes>({
width: { key: "w:w", value: flip ? heightTwips : widthTwips },
height: { key: "w:h", value: flip ? widthTwips : heightTwips },
orientation: { key: "w:orient", value: orientation },
}),
);
}
}
/**
* This element specifies the properties (size and orientation) for all pages in the current section.
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_pgSz_topic_ID0ENEDT.html?hl=pgsz%2Cpage%2Csize
*
* ## XSD Schema
*
* ```xml
* <xsd:complexType name="CT_PageSz">
* <xsd:attribute name="w" type="s:ST_TwipsMeasure"/>
* <xsd:attribute name="h" type="s:ST_TwipsMeasure"/>
* <xsd:attribute name="orient" type="ST_PageOrientation" use="optional"/>
* <xsd:attribute name="code" type="ST_DecimalNumber" use="optional"/>
* </xsd:complexType>
* ```
*/
export const createPageSize = ({ width, height, orientation, code }: IPageSizeAttributes): XmlComponent => {
const widthTwips = twipsMeasureValue(width);
const heightTwips = twipsMeasureValue(height);
return new BuilderElement<IPageSizeAttributes>({
name: "w:pgSz",
attributes: {
width: { key: "w:w", value: orientation === PageOrientation.LANDSCAPE ? heightTwips : widthTwips },
height: { key: "w:h", value: orientation === PageOrientation.LANDSCAPE ? widthTwips : heightTwips },
orientation: { key: "w:orient", value: orientation },
code: { key: "w:code", value: code },
},
});
};

View File

@ -6,7 +6,7 @@ import { FooterWrapper } from "@file/footer-wrapper";
import { HeaderWrapper } from "@file/header-wrapper";
import { Media } from "@file/media";
import { NumberFormat } from "@file/shared/number-format";
import { VerticalAlign } from "@file/vertical-align";
import { VerticalAlignSection } from "@file/vertical-align";
import { convertInchesToTwip } from "@util/convenience-functions";
import { PageOrientation } from "./properties";
@ -75,7 +75,7 @@ describe("SectionProperties", () => {
even: new FooterWrapper(media, 200),
},
titlePage: true,
verticalAlign: VerticalAlign.TOP,
verticalAlign: VerticalAlignSection.TOP,
});
const tree = new Formatter().format(properties);

View File

@ -2,17 +2,17 @@
import { FooterWrapper } from "@file/footer-wrapper";
import { HeaderWrapper } from "@file/header-wrapper";
import { VerticalAlign, VerticalAlignElement } from "@file/vertical-align";
import { SectionVerticalAlign, VerticalAlignElement } from "@file/vertical-align";
import { OnOffElement, XmlComponent } from "@file/xml-components";
import { Columns, IColumnsAttributes } from "./properties/columns";
import { DocumentGrid, IDocGridAttributesProperties } from "./properties/doc-grid";
import { IDocGridAttributesProperties, createDocumentGrid } from "./properties/doc-grid";
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./properties/header-footer-reference";
import { ILineNumberAttributes, createLineNumberType } from "./properties/line-number";
import { IPageBordersOptions, PageBorders } from "./properties/page-borders";
import { IPageMarginAttributes, PageMargin } from "./properties/page-margin";
import { IPageNumberTypeAttributes, PageNumberType } from "./properties/page-number";
import { IPageSizeAttributes, PageOrientation, PageSize } from "./properties/page-size";
import { IPageSizeAttributes, PageOrientation, createPageSize } from "./properties/page-size";
import { PageTextDirection, PageTextDirectionType } from "./properties/page-text-direction";
import { SectionType, Type } from "./properties/section-type";
@ -24,18 +24,18 @@ export type IHeaderFooterGroup<T> = {
export type ISectionPropertiesOptions = {
readonly page?: {
readonly size?: IPageSizeAttributes;
readonly size?: Partial<IPageSizeAttributes>;
readonly margin?: IPageMarginAttributes;
readonly pageNumbers?: IPageNumberTypeAttributes;
readonly borders?: IPageBordersOptions;
readonly textDirection?: (typeof PageTextDirectionType)[keyof typeof PageTextDirectionType];
};
readonly grid?: IDocGridAttributesProperties;
readonly grid?: Partial<IDocGridAttributesProperties>;
readonly headerWrapperGroup?: IHeaderFooterGroup<HeaderWrapper>;
readonly footerWrapperGroup?: IHeaderFooterGroup<FooterWrapper>;
readonly lineNumbers?: ILineNumberAttributes;
readonly titlePage?: boolean;
readonly verticalAlign?: (typeof VerticalAlign)[keyof typeof VerticalAlign];
readonly verticalAlign?: SectionVerticalAlign;
readonly column?: IColumnsAttributes;
readonly type?: (typeof SectionType)[keyof typeof SectionType];
};
@ -128,7 +128,7 @@ export class SectionProperties extends XmlComponent {
this.root.push(new Type(type));
}
this.root.push(new PageSize(width, height, orientation));
this.root.push(createPageSize({ width, height, orientation }));
this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter));
if (borders) {
@ -157,7 +157,7 @@ export class SectionProperties extends XmlComponent {
this.root.push(new PageTextDirection(textDirection));
}
this.root.push(new DocumentGrid(linePitch, charSpace, gridType));
this.root.push(createDocumentGrid({ linePitch, charSpace, type: gridType }));
}
private addHeaderFooterGroup(

View File

@ -1,89 +1,60 @@
import { XmlAttributeComponent } from "@file/xml-components";
import { AttributeMap, XmlAttributeComponent } from "@file/xml-components";
/* cSpell:disable */
export type IDocumentAttributesProperties = {
readonly wpc?: string;
readonly mc?: string;
readonly o?: string;
readonly r?: string;
readonly m?: string;
readonly v?: string;
readonly wp14?: string;
readonly wp?: string;
readonly w10?: string;
readonly w?: string;
readonly w14?: string;
readonly w15?: string;
readonly wpg?: string;
readonly wpi?: string;
readonly wne?: string;
readonly wps?: string;
readonly Ignorable?: string;
readonly cp?: string;
readonly dc?: string;
readonly dcterms?: string;
readonly dcmitype?: string;
readonly xsi?: string;
readonly type?: string;
readonly cx?: string;
readonly cx1?: string;
readonly cx2?: string;
readonly cx3?: string;
readonly cx4?: string;
readonly cx5?: string;
readonly cx6?: string;
readonly cx7?: string;
readonly cx8?: string;
readonly aink?: string;
readonly am3d?: string;
readonly w16cex?: string;
readonly w16cid?: string;
readonly w16?: string;
readonly w16sdtdh?: string;
readonly w16se?: string;
export const DocumentAttributeNamespaces = {
wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
o: "urn:schemas-microsoft-com:office:office",
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
m: "http://schemas.openxmlformats.org/officeDocument/2006/math",
v: "urn:schemas-microsoft-com:vml",
wp14: "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
wp: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
w10: "urn:schemas-microsoft-com:office:word",
w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
w14: "http://schemas.microsoft.com/office/word/2010/wordml",
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
wpg: "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
wne: "http://schemas.microsoft.com/office/word/2006/wordml",
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
cp: "http://schemas.openxmlformats.org/package/2006/metadata/core-properties",
dc: "http://purl.org/dc/elements/1.1/",
dcterms: "http://purl.org/dc/terms/",
dcmitype: "http://purl.org/dc/dcmitype/",
xsi: "http://www.w3.org/2001/XMLSchema-instance",
cx: "http://schemas.microsoft.com/office/drawing/2014/chartex",
cx1: "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex",
cx2: "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex",
cx3: "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex",
cx4: "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex",
cx5: "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex",
cx6: "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex",
cx7: "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex",
cx8: "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex",
aink: "http://schemas.microsoft.com/office/drawing/2016/ink",
am3d: "http://schemas.microsoft.com/office/drawing/2017/model3d",
w16cex: "http://schemas.microsoft.com/office/word/2018/wordml/cex",
w16cid: "http://schemas.microsoft.com/office/word/2016/wordml/cid",
w16: "http://schemas.microsoft.com/office/word/2018/wordml",
w16sdtdh: "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash",
w16se: "http://schemas.microsoft.com/office/word/2015/wordml/symex",
};
/* cSpell:enable */
export type DocumentAttributeNamespace = keyof typeof DocumentAttributeNamespaces;
export type IDocumentAttributesProperties = Partial<Record<DocumentAttributeNamespace, string>> & {
readonly Ignorable?: string;
};
export class DocumentAttributes extends XmlAttributeComponent<IDocumentAttributesProperties> {
protected readonly xmlKeys = {
wpc: "xmlns:wpc",
mc: "xmlns:mc",
o: "xmlns:o",
r: "xmlns:r",
m: "xmlns:m",
v: "xmlns:v",
wp14: "xmlns:wp14",
wp: "xmlns:wp",
w10: "xmlns:w10",
w: "xmlns:w",
w14: "xmlns:w14",
w15: "xmlns:w15",
wpg: "xmlns:wpg",
wpi: "xmlns:wpi",
wne: "xmlns:wne",
wps: "xmlns:wps",
Ignorable: "mc:Ignorable",
cp: "xmlns:cp",
dc: "xmlns:dc",
dcterms: "xmlns:dcterms",
dcmitype: "xmlns:dcmitype",
xsi: "xmlns:xsi",
type: "xsi:type",
cx: "xmlns:cx",
cx1: "xmlns:cx1",
cx2: "xmlns:cx2",
cx3: "xmlns:cx3",
cx4: "xmlns:cx4",
cx5: "xmlns:cx5",
cx6: "xmlns:cx6",
cx7: "xmlns:cx7",
cx8: "xmlns:cx8",
aink: "xmlns:aink",
am3d: "xmlns:am3d",
w16cex: "xmlns:w16cex",
w16cid: "xmlns:w16cid",
w16: "xmlns:w16",
w16sdtdh: "xmlns:w16sdtdh",
w16se: "xmlns:w16se",
};
...Object.fromEntries(Object.keys(DocumentAttributeNamespaces).map((key) => [key, `xmlns:${key}`])),
} as AttributeMap<IDocumentAttributesProperties>;
public constructor(ns: readonly DocumentAttributeNamespace[], Ignorable?: string) {
super({ Ignorable, ...Object.fromEntries(ns.map((n) => [n, DocumentAttributeNamespaces[n]])) });
}
}

View File

@ -37,41 +37,43 @@ export class Document extends XmlComponent {
public constructor(options: IDocumentOptions) {
super("w:document");
this.root.push(
new DocumentAttributes({
wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
o: "urn:schemas-microsoft-com:office:office",
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
m: "http://schemas.openxmlformats.org/officeDocument/2006/math",
v: "urn:schemas-microsoft-com:vml",
wp14: "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
wp: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
w10: "urn:schemas-microsoft-com:office:word",
w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
w14: "http://schemas.microsoft.com/office/word/2010/wordml",
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
wpg: "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
wne: "http://schemas.microsoft.com/office/word/2006/wordml",
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
cx: "http://schemas.microsoft.com/office/drawing/2014/chartex",
cx1: "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex",
cx2: "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex",
cx3: "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex",
cx4: "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex",
cx5: "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex",
cx6: "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex",
cx7: "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex",
cx8: "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex",
aink: "http://schemas.microsoft.com/office/drawing/2016/ink",
am3d: "http://schemas.microsoft.com/office/drawing/2017/model3d",
w16cex: "http://schemas.microsoft.com/office/word/2018/wordml/cex",
w16cid: "http://schemas.microsoft.com/office/word/2016/wordml/cid",
w16: "http://schemas.microsoft.com/office/word/2018/wordml",
w16sdtdh: "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash",
w16se: "http://schemas.microsoft.com/office/word/2015/wordml/symex",
Ignorable: "w14 w15 wp14",
}),
new DocumentAttributes(
[
"wpc",
"mc",
"o",
"r",
"m",
"v",
"wp14",
"wp",
"w10",
"w",
"w14",
"w15",
"wpg",
"wpi",
"wne",
"wps",
"cx",
"cx1",
"cx2",
"cx3",
"cx4",
"cx5",
"cx6",
"cx7",
"cx8",
"aink",
"am3d",
"w16cex",
"w16cid",
"w16",
"w16sdtdh",
"w16se",
],
"w14 w15 wp14",
),
);
this.body = new Body();
if (options.background) {

View File

@ -91,28 +91,20 @@ describe("Anchor", () => {
// 2: horizontal position
const horizontalPosition = newJson.root[2];
assert.equal(horizontalPosition.rootKey, "wp:positionH");
assert.include(horizontalPosition.root[0].root, {
relativeFrom: "page",
});
assert.equal(horizontalPosition.root[1].rootKey, "wp:posOffset");
assert.include(horizontalPosition.root[1].root[0], 0);
// 3: vertical position
const verticalPosition = newJson.root[3];
assert.equal(verticalPosition.rootKey, "wp:positionV");
assert.include(verticalPosition.root[0].root, {
relativeFrom: "page",
});
assert.equal(verticalPosition.root[1].rootKey, "wp:posOffset");
assert.include(verticalPosition.root[1].root[0], 0);
// 4: extent
const extent = newJson.root[4];
assert.equal(extent.rootKey, "wp:extent");
assert.include(extent.root[0].root, {
cx: 952500,
cy: 952500,
});
// 5: effect extent
const effectExtent = newJson.root[5];

View File

@ -3,13 +3,13 @@ import { IMediaData, IMediaDataTransformation } from "@file/media";
import { XmlComponent } from "@file/xml-components";
import { IDrawingOptions } from "../drawing";
import { HorizontalPosition, IFloating, SimplePos, VerticalPosition } from "../floating";
import { IFloating, createHorizontalPosition, createSimplePos, createVerticalPosition } from "../floating";
import { Graphic } from "../inline/graphic";
import { TextWrappingType, WrapNone, WrapSquare, WrapTight, WrapTopAndBottom } from "../text-wrap";
import { DocProperties } from "./../doc-properties/doc-properties";
import { createEffectExtent } from "./../effect-extent/effect-extent";
import { Extent } from "./../extent/extent";
import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
import { createExtent } from "./../extent/extent";
import { createGraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
import { AnchorAttributes } from "./anchor-attributes";
// <xsd:complexType name="CT_Anchor">
@ -74,10 +74,10 @@ export class Anchor extends XmlComponent {
}),
);
this.root.push(new SimplePos());
this.root.push(new HorizontalPosition(floating.horizontalPosition));
this.root.push(new VerticalPosition(floating.verticalPosition));
this.root.push(new Extent(transform.emus.x, transform.emus.y));
this.root.push(createSimplePos());
this.root.push(createHorizontalPosition(floating.horizontalPosition));
this.root.push(createVerticalPosition(floating.verticalPosition));
this.root.push(createExtent({ x: transform.emus.x, y: transform.emus.y }));
this.root.push(createEffectExtent({ top: 0, right: 0, bottom: 0, left: 0 }));
if (drawingOptions.floating !== undefined && drawingOptions.floating.wrap !== undefined) {
@ -100,7 +100,7 @@ export class Anchor extends XmlComponent {
}
this.root.push(new DocProperties(drawingOptions.docProperties));
this.root.push(new GraphicFrameProperties());
this.root.push(createGraphicFrameProperties());
this.root.push(new Graphic({ mediaData, transform, outline: drawingOptions.outline }));
}
}

View File

@ -19,8 +19,8 @@ import { createHyperlinkClick } from "./doc-properties-children";
export type DocPropertiesOptions = {
readonly name: string;
readonly description: string;
readonly title: string;
readonly description?: string;
readonly title?: string;
};
export class DocProperties extends XmlComponent {
@ -29,26 +29,32 @@ export class DocProperties extends XmlComponent {
public constructor({ name, description, title }: DocPropertiesOptions = { name: "", description: "", title: "" }) {
super("wp:docPr");
this.root.push(
new NextAttributeComponent({
id: {
key: "id",
value: this.docPropertiesUniqueNumericId(),
},
name: {
key: "name",
value: name,
},
description: {
key: "descr",
value: description,
},
title: {
key: "title",
value: title,
},
}),
);
const attributes: Record<string, { readonly key: string; readonly value: string | number }> = {
id: {
key: "id",
value: this.docPropertiesUniqueNumericId(),
},
name: {
key: "name",
value: name,
},
};
if (description !== null && description !== undefined) {
attributes.description = {
key: "descr",
value: description,
};
}
if (title !== null && title !== undefined) {
attributes.title = {
key: "title",
value: title,
};
}
this.root.push(new NextAttributeComponent(attributes));
}
public prepForXml(context: IContext): IXmlableObject | undefined {
@ -59,7 +65,6 @@ export class DocProperties extends XmlComponent {
}
this.root.push(createHyperlinkClick(element.linkId, true));
break;
}

View File

@ -1,18 +1,50 @@
import { BuilderElement, XmlComponent } from "@file/xml-components";
export type EffectExtentAttributes = {
/**
* ## Additional Extent on Top Edge
*
* Specifies the additional length, in EMUs, which shall be added to the top edge of the DrawingML object to determine its actual top edge including effects.
*/
readonly top: number;
/**
* ## Additional Extent on Right Edge
*
* Specifies the additional length, in EMUs, which shall be added to the right edge of the DrawingML object to determine its actual right edge including effects.
*/
readonly right: number;
/**
* ## Additional Extent on Bottom Edge
*
* Specifies the additional length, in EMUs, which shall be added to the bottom edge of the DrawingML object to determine its actual bottom edge including effects.
*/
readonly bottom: number;
/**
* ## Additional Extent on Left Edge
*
* Specifies the additional length, in EMUs, which shall be added to the left edge of the DrawingML object to determine its actual left edge including effects.
*/
readonly left: number;
};
// <xsd:complexType name="CT_EffectExtent">
// <xsd:attribute name="l" type="a:ST_Coordinate" use="required"/>
// <xsd:attribute name="t" type="a:ST_Coordinate" use="required"/>
// <xsd:attribute name="r" type="a:ST_Coordinate" use="required"/>
// <xsd:attribute name="b" type="a:ST_Coordinate" use="required"/>
// </xsd:complexType>
/**
* This element specifies the additional extent which shall be added to each edge of the image (top, bottom, left, right) in order to compensate for any drawing effects applied to the DrawingML object.
*
* The `<extent>` element (§5.5.2.7) specifies the size of the actual DrawingML object; however, an object may have effects applied which change its overall size
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_effectExtent_topic_ID0E5O3OB.html
*
* ## XSD Schema
*
* ```xml
* <xsd:complexType name="CT_EffectExtent">
* <xsd:attribute name="l" type="a:ST_Coordinate" use="required"/>
* <xsd:attribute name="t" type="a:ST_Coordinate" use="required"/>
* <xsd:attribute name="r" type="a:ST_Coordinate" use="required"/>
* <xsd:attribute name="b" type="a:ST_Coordinate" use="required"/>
* </xsd:complexType>
* ```
*/
export const createEffectExtent = ({ top, right, bottom, left }: EffectExtentAttributes): XmlComponent =>
new BuilderElement<EffectExtentAttributes>({
name: "wp:effectExtent",

View File

@ -1,11 +0,0 @@
import { XmlAttributeComponent } from "@file/xml-components";
export class ExtentAttributes extends XmlAttributeComponent<{
readonly cx?: number;
readonly cy?: number;
}> {
protected readonly xmlKeys = {
cx: "cx",
cy: "cy",
};
}

View File

@ -1,18 +1,60 @@
import { XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { ExtentAttributes } from "./extent-attributes";
type ExtentAttributes = {
/**
* ## Extent Length
*
* Specifies the length of the extents rectangle in EMUs. This rectangle shall dictate the size of the object as displayed (the result of any scaling to the original object).
*
*
* ### Example
*
* ```xml
* <... cx="1828800" cy="200000"/>
* ```
*
* The `cx` attributes specifies that this object has a height of `1828800` EMUs (English Metric Units).
*
* The possible values for this attribute are defined by the `ST_PositiveCoordinate` simple type (§5.1.12.42).
*/
readonly x?: number;
/**
* ## Extent Width
*
* Specifies the width of the extents rectangle in EMUs. This rectangle shall dictate the size of the object as displayed (the result of any scaling to the original object).
*
* ### Example
*
* ```xml
* <... cx="1828800" cy="200000"/>
* ```
*
* The `cy` attribute specifies that this object has a width of `200000` EMUs (English Metric Units).
*
* The possible values for this attribute are defined by the `ST_PositiveCoordinate` simple type (§5.1.12.42).
*/
readonly y?: number;
};
export class Extent extends XmlComponent {
private readonly attributes: ExtentAttributes;
public constructor(x: number, y: number) {
super("wp:extent");
this.attributes = new ExtentAttributes({
cx: x,
cy: y,
});
this.root.push(this.attributes);
}
}
/**
* This element specifies the extents of the parent `DrawingML` object within the document (i.e. its final height and width).
*
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_extent_topic_ID0EQB4OB.html
*
* ## XSD Schema
*
* ```xml
* <complexType name="CT_PositiveSize2D">
* <attribute name="cx" type="ST_PositiveCoordinate" use="required"/>
* <attribute name="cy" type="ST_PositiveCoordinate" use="required"/>
* </complexType>
* ```
*/
export const createExtent = ({ x, y }: ExtentAttributes): XmlComponent =>
new BuilderElement<ExtentAttributes>({
name: "wp:extent",
attributes: {
x: { key: "cx", value: x },
y: { key: "cy", value: y },
},
});

View File

@ -3,12 +3,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { VerticalPositionAlign } from "@file/shared/alignment";
import { Align } from "./align";
import { createAlign } from "./align";
describe("Align", () => {
describe("#constructor()", () => {
it("should create a element with correct root key", () => {
const tree = new Formatter().format(new Align(VerticalPositionAlign.CENTER));
const tree = new Formatter().format(createAlign(VerticalPositionAlign.CENTER));
expect(tree).to.deep.equal({
"wp:align": ["center"],
});

View File

@ -1,14 +1,23 @@
// http://officeopenxml.com/drwPicFloating-position.php
import { HorizontalPositionAlign, VerticalPositionAlign } from "@file/shared/alignment";
import { XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
export class Align extends XmlComponent {
public constructor(
value:
| (typeof HorizontalPositionAlign)[keyof typeof HorizontalPositionAlign]
| (typeof VerticalPositionAlign)[keyof typeof VerticalPositionAlign],
) {
super("wp:align");
this.root.push(value);
}
}
/**
* # Relative Horizontal/Vertical Alignment
*
* This element specifies how a DrawingML object shall be horizontally/vertically aligned relative to the horizontal/vertical alignment base defined by the parent element. Once an alignment base is defined, this element shall determine how the DrawingML object shall be aligned relative to that location.
*
* References:
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_align_topic_ID0EYZZOB.html
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_align_topic_ID0ET4ZOB.html
* - http://officeopenxml.com/drwPicFloating-position.php
*/
export const createAlign = (
value:
| (typeof HorizontalPositionAlign)[keyof typeof HorizontalPositionAlign]
| (typeof VerticalPositionAlign)[keyof typeof VerticalPositionAlign],
): XmlComponent =>
new BuilderElement({
name: "wp:align",
// eslint-disable-next-line @typescript-eslint/no-explicit-any
children: [value as any],
});

View File

@ -4,25 +4,115 @@ import { HorizontalPositionAlign, VerticalPositionAlign } from "@file/shared/ali
import { ITextWrapping } from "../text-wrap";
/**
* Horizontal Relative Positioning
*
* Reference: https://www.datypic.com/sc/ooxml/t-wp_ST_RelFromH.html
*/
export const HorizontalPositionRelativeFrom = {
/**
* ## Character
*
* Specifies that the horizontal positioning shall be relative to the position of the anchor within its run content.
*/
CHARACTER: "character",
/**
* ## Column
*
* Specifies that the horizontal positioning shall be relative to the extents of the column which contains its anchor.
*/
COLUMN: "column",
/**
* ## Inside Margin
*
* Specifies that the horizontal positioning shall be relative to the inside margin of the current page (the left margin on odd pages, right on even pages).
*/
INSIDE_MARGIN: "insideMargin",
/**
* ## Left Margin
*
* Specifies that the horizontal positioning shall be relative to the left margin of the page.
*/
LEFT_MARGIN: "leftMargin",
/**
* ## Page Margin
*
* Specifies that the horizontal positioning shall be relative to the page margins.
*/
MARGIN: "margin",
/**
* ## Outside Margin
*
* Specifies that the horizontal positioning shall be relative to the outside margin of the current page (the right margin on odd pages, left on even pages).
*/
OUTSIDE_MARGIN: "outsideMargin",
/**
* ## Page Edge
*
* Specifies that the horizontal positioning shall be relative to the edge of the page.
*/
PAGE: "page",
/**
* ## Right Margin
*
* Specifies that the horizontal positioning shall be relative to the right margin of the page.
*/
RIGHT_MARGIN: "rightMargin",
} as const;
/**
* Vertical Relative Positioning
*
* Reference: https://www.datypic.com/sc/ooxml/t-wp_ST_RelFromV.html
*/
export const VerticalPositionRelativeFrom = {
/**
* ## Bottom Margin
*
* Specifies that the vertical positioning shall be relative to the bottom margin of the current page.
*/
BOTTOM_MARGIN: "bottomMargin",
/**
* ## Inside Margin
*
* Specifies that the vertical positioning shall be relative to the inside margin of the current page.
*/
INSIDE_MARGIN: "insideMargin",
/**
* ## Line
*
* Specifies that the vertical positioning shall be relative to the line containing the anchor character.
*/
LINE: "line",
/**
* ## Page Margin
*
* Specifies that the vertical positioning shall be relative to the page margins.
*/
MARGIN: "margin",
/**
* ## Outside Margin
*
* Specifies that the vertical positioning shall be relative to the outside margin of the current page.
*/
OUTSIDE_MARGIN: "outsideMargin",
/**
* ## Page Edge
*
* Specifies that the vertical positioning shall be relative to the edge of the page.
*/
PAGE: "page",
/**
* ## Paragraph
*
* Specifies that the vertical positioning shall be relative to the paragraph which contains the drawing anchor.
*/
PARAGRAPH: "paragraph",
/**
* ## Top Margin
*
* Specifies that the vertical positioning shall be relative to the top margin of the current page.
*/
TOP_MARGIN: "topMargin",
} as const;

View File

@ -4,13 +4,13 @@ import { Formatter } from "@export/formatter";
import { HorizontalPositionAlign } from "@file/shared/alignment";
import { HorizontalPositionRelativeFrom } from "./floating-position";
import { HorizontalPosition } from "./horizontal-position";
import { createHorizontalPosition } from "./horizontal-position";
describe("HorizontalPosition", () => {
describe("#constructor()", () => {
it("should create a element with position align", () => {
const tree = new Formatter().format(
new HorizontalPosition({
createHorizontalPosition({
relative: HorizontalPositionRelativeFrom.MARGIN,
align: HorizontalPositionAlign.CENTER,
}),
@ -31,7 +31,7 @@ describe("HorizontalPosition", () => {
it("should create a element with offset", () => {
const tree = new Formatter().format(
new HorizontalPosition({
createHorizontalPosition({
relative: HorizontalPositionRelativeFrom.MARGIN,
offset: 40,
}),
@ -51,7 +51,7 @@ describe("HorizontalPosition", () => {
});
it("should require one of align or offset", () => {
expect(() => new HorizontalPosition({})).to.throw();
expect(() => createHorizontalPosition({})).to.throw();
});
});
});

View File

@ -1,34 +1,33 @@
// http://officeopenxml.com/drwPicFloating-position.php
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { Align } from "./align";
import { createAlign } from "./align";
import { HorizontalPositionRelativeFrom, IHorizontalPositionOptions } from "./floating-position";
import { PositionOffset } from "./position-offset";
import { createPositionOffset } from "./position-offset";
class HorizontalPositionAttributes extends XmlAttributeComponent<{
readonly relativeFrom: (typeof HorizontalPositionRelativeFrom)[keyof typeof HorizontalPositionRelativeFrom];
}> {
protected readonly xmlKeys = {
relativeFrom: "relativeFrom",
};
}
export class HorizontalPosition extends XmlComponent {
public constructor(horizontalPosition: IHorizontalPositionOptions) {
super("wp:positionH");
this.root.push(
new HorizontalPositionAttributes({
relativeFrom: horizontalPosition.relative || HorizontalPositionRelativeFrom.PAGE,
}),
);
if (horizontalPosition.align) {
this.root.push(new Align(horizontalPosition.align));
} else if (horizontalPosition.offset !== undefined) {
this.root.push(new PositionOffset(horizontalPosition.offset));
} else {
throw new Error("There is no configuration provided for floating position (Align or offset)");
}
}
}
/**
* Horizontal Positioning
*
* Reference: https://www.datypic.com/sc/ooxml/e-wp_positionH-1.html
*/
export const createHorizontalPosition = ({ relative, align, offset }: IHorizontalPositionOptions): XmlComponent =>
new BuilderElement<{
/** Horizontal Position Relative Base */
readonly relativeFrom: (typeof HorizontalPositionRelativeFrom)[keyof typeof HorizontalPositionRelativeFrom];
}>({
name: "wp:positionH",
attributes: {
relativeFrom: { key: "relativeFrom", value: relative ?? HorizontalPositionRelativeFrom.PAGE },
},
children: [
(() => {
if (align) {
return createAlign(align);
} else if (offset !== undefined) {
return createPositionOffset(offset);
} else {
throw new Error("There is no configuration provided for floating position (Align or offset)");
}
})(),
],
});

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { PositionOffset } from "./position-offset";
import { createPositionOffset } from "./position-offset";
describe("PositionOffset", () => {
describe("createPositionOffset", () => {
describe("#constructor()", () => {
it("should create a element with correct root key", () => {
const tree = new Formatter().format(new PositionOffset(50));
const tree = new Formatter().format(createPositionOffset(50));
expect(tree).to.deep.equal({
"wp:posOffset": ["50"],
});

View File

@ -1,9 +1,17 @@
// http://officeopenxml.com/drwPicFloating-position.php
import { XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
export class PositionOffset extends XmlComponent {
public constructor(offsetValue: number) {
super("wp:posOffset");
this.root.push(offsetValue.toString());
}
}
/**
* # Absolute Position Offset
*
* This element specifies an absolute measurement for the positioning of a floating DrawingML object within a WordprocessingML document. This measurement shall be calculated relative to the top left edge of the positioning base specified by the parent element's `relativeFrom` attribute.
*
* References:
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_posOffset_topic_ID0EMG6OB.html
* - http://officeopenxml.com/drwPicFloating-position.php
*/
export const createPositionOffset = (offsetValue: number): XmlComponent =>
new BuilderElement({
name: "wp:posOffset",
// eslint-disable-next-line @typescript-eslint/no-explicit-any
children: [offsetValue.toString() as any],
});

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { SimplePos } from "./simple-pos";
import { createSimplePos } from "./simple-pos";
describe("SimplePos", () => {
describe("createSimplePos", () => {
describe("#constructor()", () => {
it("should create a element with correct root key", () => {
const tree = new Formatter().format(new SimplePos());
const tree = new Formatter().format(createSimplePos());
expect(tree).to.deep.equal({
"wp:simplePos": {
_attr: {

View File

@ -1,26 +1,62 @@
// http://officeopenxml.com/drwPicFloating-position.php
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
class SimplePosAttributes extends XmlAttributeComponent<{
readonly x: number;
readonly y: number;
}> {
protected readonly xmlKeys = {
x: "x",
y: "y",
};
}
export class SimplePos extends XmlComponent {
public constructor() {
super("wp:simplePos");
import { BuilderElement, XmlComponent } from "@file/xml-components";
/**
* # Simple Positioning Coordinates
*
* This element specifies the coordinates at which a DrawingML object shall be positioned relative to the top-left edge of its page, when the `simplePos` attribute is specified on the <anchor> element (§5.5.2.3).
*
* References:
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_simplePos_topic_ID0E5K6OB.html
* - http://officeopenxml.com/drwPicFloating-position.php
*
* ## XSD Schema
*
* ```xml
* <xsd:complexType name="CT_Point2D">
* <xsd:attribute name="x" type="ST_Coordinate" use="required"/>
* <xsd:attribute name="y" type="ST_Coordinate" use="required"/>
* </xsd:complexType>
* ```
*/
export const createSimplePos = (): XmlComponent =>
new BuilderElement<{
/**
* ## X-Axis Coordinate
*
* Specifies a coordinate on the x-axis. The origin point for this coordinate shall be specified by the parent XML element.
*
* ### Example
*
* ```xml
* <wp:... x="0" y="100" />
* ```
*
* The `x` attribute defines an x-coordinate of 0.
*
* The possible values for this attribute are defined by the `ST_Coordinate` simple type (§5.1.12.16).
*/
readonly x: number;
/**
* ## Y-Axis Coordinate
*
* Specifies a coordinate on the x-axis. The origin point for this coordinate shall be specified by the parent XML element.
*
* ### Example
* ```xml
* <wp:... x="0" y="100" />
* ```
*
* The `y` attribute defines a y-coordinate of 100.
*
* The possible values for this attribute are defined by the `ST_Coordinate` simple type (§5.1.12.16).
*/
readonly y: number;
}>({
name: "wp:simplePos",
// NOTE: It's not fully supported in Microsoft Word, but this element is needed anyway
this.root.push(
new SimplePosAttributes({
x: 0,
y: 0,
}),
);
}
}
attributes: {
x: { key: "x", value: 0 },
y: { key: "y", value: 0 },
},
});

View File

@ -4,13 +4,13 @@ import { Formatter } from "@export/formatter";
import { VerticalPositionAlign } from "@file/shared/alignment";
import { VerticalPositionRelativeFrom } from "./floating-position";
import { VerticalPosition } from "./vertical-position";
import { createVerticalPosition } from "./vertical-position";
describe("VerticalPosition", () => {
describe("#constructor()", () => {
it("should create a element with position align", () => {
const tree = new Formatter().format(
new VerticalPosition({
createVerticalPosition({
relative: VerticalPositionRelativeFrom.MARGIN,
align: VerticalPositionAlign.INSIDE,
}),
@ -31,7 +31,7 @@ describe("VerticalPosition", () => {
it("should create a element with offset", () => {
const tree = new Formatter().format(
new VerticalPosition({
createVerticalPosition({
relative: VerticalPositionRelativeFrom.MARGIN,
offset: 40,
}),
@ -51,7 +51,7 @@ describe("VerticalPosition", () => {
});
it("should require one of align or offset", () => {
expect(() => new VerticalPosition({})).to.throw();
expect(() => createVerticalPosition({})).to.throw();
});
});
});

View File

@ -1,34 +1,35 @@
// http://officeopenxml.com/drwPicFloating-position.php
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { Align } from "./align";
import { createAlign } from "./align";
import { IVerticalPositionOptions, VerticalPositionRelativeFrom } from "./floating-position";
import { PositionOffset } from "./position-offset";
import { createPositionOffset } from "./position-offset";
class VerticalPositionAttributes extends XmlAttributeComponent<{
readonly relativeFrom: (typeof VerticalPositionRelativeFrom)[keyof typeof VerticalPositionRelativeFrom];
}> {
protected readonly xmlKeys = {
relativeFrom: "relativeFrom",
};
}
export class VerticalPosition extends XmlComponent {
public constructor(verticalPosition: IVerticalPositionOptions) {
super("wp:positionV");
this.root.push(
new VerticalPositionAttributes({
relativeFrom: verticalPosition.relative || VerticalPositionRelativeFrom.PAGE,
}),
);
if (verticalPosition.align) {
this.root.push(new Align(verticalPosition.align));
} else if (verticalPosition.offset !== undefined) {
this.root.push(new PositionOffset(verticalPosition.offset));
} else {
throw new Error("There is no configuration provided for floating position (Align or offset)");
}
}
}
/**
* Vertical Positioning
*
* This simple type specifies the possible values for the base from which the relative vertical positioning of an object shall be calculated.
*
* Reference: https://www.datypic.com/sc/ooxml/e-wp_positionV-1.html
*/
export const createVerticalPosition = ({ relative, align, offset }: IVerticalPositionOptions): XmlComponent =>
new BuilderElement<{
/** Vertical Position Relative Base */
readonly relativeFrom: (typeof VerticalPositionRelativeFrom)[keyof typeof VerticalPositionRelativeFrom];
}>({
name: "wp:positionV",
attributes: {
relativeFrom: { key: "relativeFrom", value: relative ?? VerticalPositionRelativeFrom.PAGE },
},
children: [
(() => {
if (align) {
return createAlign(align);
} else if (offset !== undefined) {
return createPositionOffset(offset);
} else {
throw new Error("There is no configuration provided for floating position (Align or offset)");
}
})(),
],
});

View File

@ -1,11 +1,28 @@
import { XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { GraphicFrameLocks } from "./graphic-frame-locks/graphic-frame-locks";
export class GraphicFrameProperties extends XmlComponent {
public constructor() {
super("wp:cNvGraphicFramePr");
this.root.push(new GraphicFrameLocks());
}
}
/**
* # Common DrawingML Non-Visual Properties
*
* This element specifies common non-visual DrawingML object properties for the parent DrawingML object. These properties are specified as child elements of this element.
*
* References:
* - https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_cNvGraphicFramePr_topic_ID0E6U2OB.html
*
* ## XSD Schema
*
* ```xml
* <xsd:complexType name="CT_NonVisualGraphicFrameProperties">
* <xsd:sequence>
* <xsd:element name="graphicFrameLocks" type="CT_GraphicalObjectFrameLocking" minOccurs="0" maxOccurs="1"/>
* <xsd:element name="extLst" type="CT_OfficeArtExtensionList" minOccurs="0" maxOccurs="1"/>
* </xsd:sequence>
* </xsd:complexType>
* ```
*/
export const createGraphicFrameProperties = (): XmlComponent =>
new BuilderElement({
name: "wp:cNvGraphicFramePr",
children: [new GraphicFrameLocks()],
});

View File

@ -4,8 +4,8 @@ import { BuilderElement, XmlComponent } from "@file/xml-components";
import { DocProperties, DocPropertiesOptions } from "./../doc-properties/doc-properties";
import { createEffectExtent } from "./../effect-extent/effect-extent";
import { Extent } from "./../extent/extent";
import { GraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
import { createExtent } from "./../extent/extent";
import { createGraphicFrameProperties } from "./../graphic-frame/graphic-frame-properties";
import { Graphic } from "./../inline/graphic";
import { OutlineOptions } from "./graphic/graphic-data/pic/shape-properties/outline/outline";
@ -52,7 +52,7 @@ export const createInline = ({ mediaData, transform, docProperties, outline }: I
},
},
children: [
new Extent(transform.emus.x, transform.emus.y),
createExtent({ x: transform.emus.x, y: transform.emus.y }),
createEffectExtent(
outline
? {
@ -64,7 +64,7 @@ export const createInline = ({ mediaData, transform, docProperties, outline }: I
: { top: 0, right: 0, bottom: 0, left: 0 },
),
new DocProperties(docProperties),
new GraphicFrameProperties(),
createGraphicFrameProperties(),
new Graphic({ mediaData, transform, outline }),
],
});

View File

@ -2,7 +2,7 @@ const obfuscatedStartOffset = 0;
const obfuscatedEndOffset = 32;
const guidSize = 32;
export const obfuscate = (buf: Buffer, fontKey: string): Buffer => {
export const obfuscate = (buf: Uint8Array, fontKey: string): Uint8Array => {
const guid = fontKey.replace(/-/g, "");
if (guid.length !== guidSize) {
throw new Error(`Error: Cannot extract GUID from font filename: ${fontKey}`);
@ -17,6 +17,9 @@ export const obfuscate = (buf: Buffer, fontKey: string): Buffer => {
// eslint-disable-next-line no-bitwise
const obfuscatedBytes = bytesToObfuscate.map((byte, i) => byte ^ hexNumbers[i % hexNumbers.length]);
const out = Buffer.concat([buf.slice(0, obfuscatedStartOffset), obfuscatedBytes, buf.slice(obfuscatedEndOffset)]);
const out = new Uint8Array(obfuscatedStartOffset + obfuscatedBytes.length + Math.max(0, buf.length - obfuscatedEndOffset));
out.set(buf.slice(0, obfuscatedStartOffset));
out.set(obfuscatedBytes, obfuscatedStartOffset);
out.set(buf.slice(obfuscatedEndOffset), obfuscatedStartOffset + obfuscatedBytes.length);
return out;
};

View File

@ -21,3 +21,4 @@ export * from "./vertical-align";
export * from "./checkbox";
export * from "./fonts";
export * from "./textbox";
export { type IPropertiesOptions } from "./core-properties";

View File

@ -37,25 +37,10 @@ export class Numbering extends XmlComponent {
public constructor(options: INumberingOptions) {
super("w:numbering");
this.root.push(
new DocumentAttributes({
wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
o: "urn:schemas-microsoft-com:office:office",
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
m: "http://schemas.openxmlformats.org/officeDocument/2006/math",
v: "urn:schemas-microsoft-com:vml",
wp14: "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
wp: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
w10: "urn:schemas-microsoft-com:office:word",
w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
w14: "http://schemas.microsoft.com/office/word/2010/wordml",
w15: "http://schemas.microsoft.com/office/word/2012/wordml",
wpg: "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
wne: "http://schemas.microsoft.com/office/word/2006/wordml",
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
Ignorable: "w14 w15 wp14",
}),
new DocumentAttributes(
["wpc", "mc", "o", "r", "m", "v", "wp14", "wp", "w10", "w", "w14", "w15", "wpg", "wpi", "wne", "wps"],
"w14 w15 wp14",
),
);
const abstractNumbering = new AbstractNumbering(this.abstractNumUniqueNumericId(), [

View File

@ -24,7 +24,7 @@ class SpacingAttributes extends XmlAttributeComponent<ISpacingProperties> {
line: "w:line",
lineRule: "w:lineRule",
beforeAutoSpacing: "w:beforeAutospacing",
afterAutoSpacing: "w:afterAutoSpacing",
afterAutoSpacing: "w:afterAutospacing",
};
}

View File

@ -0,0 +1,133 @@
import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { NumberedItemReference, NumberedItemReferenceFormat } from "./numbered-item-ref";
describe("NumberedItemReference", () => {
describe("#constructor()", () => {
it("should create a numbered item ref without options", () => {
const ref = new NumberedItemReference("some_bookmark");
const tree = new Formatter().format(ref);
expect(tree).to.deep.equal({
"w:fldSimple": {
_attr: {
"w:instr": "REF some_bookmark \\h \\w",
},
},
});
});
it("should create a numbered item ref with hyperlink option disabled", () => {
const ref = new NumberedItemReference("some_bookmark", "1", { hyperlink: false });
const tree = new Formatter().format(ref);
expect(tree).to.deep.equal({
"w:fldSimple": [
{
_attr: {
"w:instr": "REF some_bookmark \\w",
},
},
{
"w:r": [
{
"w:t": [
{
_attr: {
"xml:space": "preserve",
},
},
"1",
],
},
],
},
],
});
});
it("should create a numbered item ref with referenceFormat option", () => {
const ref = new NumberedItemReference("some_bookmark", "1", { referenceFormat: NumberedItemReferenceFormat.RELATIVE });
const tree = new Formatter().format(ref);
expect(tree).to.deep.equal({
"w:fldSimple": [
{
_attr: {
"w:instr": "REF some_bookmark \\h \\r",
},
},
{
"w:r": [
{
"w:t": [
{
_attr: {
"xml:space": "preserve",
},
},
"1",
],
},
],
},
],
});
});
it("should be possible to use the none referenceFormat option", () => {
const ref = new NumberedItemReference("some_bookmark", "1", { referenceFormat: NumberedItemReferenceFormat.NONE });
const tree = new Formatter().format(ref);
expect(tree).to.deep.equal({
"w:fldSimple": [
{
_attr: {
"w:instr": "REF some_bookmark \\h",
},
},
{
"w:r": [
{
"w:t": [
{
_attr: {
"xml:space": "preserve",
},
},
"1",
],
},
],
},
],
});
});
it("should be possible to use the NO_CONTEXT referenceFormat option", () => {
const ref = new NumberedItemReference("some_bookmark", "1", { referenceFormat: NumberedItemReferenceFormat.NO_CONTEXT });
const tree = new Formatter().format(ref);
expect(tree).to.deep.equal({
"w:fldSimple": [
{
_attr: {
"w:instr": "REF some_bookmark \\h \\n",
},
},
{
"w:r": [
{
"w:t": [
{
_attr: {
"xml:space": "preserve",
},
},
"1",
],
},
],
},
],
});
});
});
});

View File

@ -0,0 +1,66 @@
import { SimpleField } from "../run";
// https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oi29500/7088a8ce-e784-49d4-94b8-cba6ef8fce78
export enum NumberedItemReferenceFormat {
NONE = "none",
/**
* \r option - inserts the paragraph number of the bookmarked paragraph in relative context, or relative to its position in the numbering scheme
*/
RELATIVE = "relative",
/**
* \n option - causes the field result to be the paragraph number without trailing periods. No information about prior numbered levels is displayed unless it is included as part of the current level.
*/
NO_CONTEXT = "no_context",
/**
* \w option - causes the field result to be the entire paragraph number without trailing periods, regardless of the location of the REF field.
*/
FULL_CONTEXT = "full_context",
}
export type INumberedItemReferenceOptions = {
/**
* \h option - Creates a hyperlink to the bookmarked paragraph.
* @default true
*/
readonly hyperlink?: boolean;
/**
* which switch to use for the reference format
* @default NumberedItemReferenceFormat.FULL_CONTEXT
*/
readonly referenceFormat?: NumberedItemReferenceFormat;
};
type Switch = "\\h" | "\\r" | "\\n" | "\\w";
const SWITCH_MAP: Record<NumberedItemReferenceFormat, Switch | undefined> = {
[NumberedItemReferenceFormat.RELATIVE]: "\\r",
[NumberedItemReferenceFormat.NO_CONTEXT]: "\\n",
[NumberedItemReferenceFormat.FULL_CONTEXT]: "\\w",
[NumberedItemReferenceFormat.NONE]: undefined,
};
/**
* Creates a field/cross reference to a numbered item in the document.
*/
export class NumberedItemReference extends SimpleField {
public constructor(
bookmarkId: string,
// TODO: It would be nice if the cached value could be automatically generated
/**
* The cached value of the field. This is used to display the field result in the document.
*/
cachedValue?: string,
options: INumberedItemReferenceOptions = {},
) {
const { hyperlink = true, referenceFormat = NumberedItemReferenceFormat.FULL_CONTEXT } = options;
const baseInstruction = `REF ${bookmarkId}`;
// TODO: Requires TypeScript 5.5 update for it to understand `filter`
// @ts-expect-error TS2322
const switches: readonly Switch[] = [...(hyperlink ? (["\\h"] as const) : []), ...[SWITCH_MAP[referenceFormat]].filter((a) => !!a)];
const instruction = `${baseInstruction} ${switches.join(" ")}`;
super(instruction, cachedValue);
}
}

View File

@ -0,0 +1,2 @@
export * from "./math-bar";
export * from "./math-bar-properties";

View File

@ -0,0 +1,12 @@
// https://www.datypic.com/sc/ooxml/e-m_pos-1.html
import { BuilderElement, XmlComponent } from "@file/xml-components";
type MathBarPosOptions = { readonly val: string };
export const createMathBarPos = ({ val }: MathBarPosOptions): XmlComponent =>
new BuilderElement<MathBarPosOptions>({
name: "m:pos",
attributes: {
val: { key: "w:val", value: val },
},
});

View File

@ -0,0 +1,44 @@
import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { createMathBarProperties } from "./math-bar-properties";
describe("MathBarProperties", () => {
describe("#constructor()", () => {
it("should create a MathBarProperties with top key", () => {
const mathBarProperties = createMathBarProperties({ type: "top" });
const tree = new Formatter().format(mathBarProperties);
expect(tree).to.deep.equal({
"m:barPr": [
{
"m:pos": {
_attr: {
"w:val": "top",
},
},
},
],
});
});
it("should create a MathBarProperties with bottom key", () => {
const mathBarProperties = createMathBarProperties({ type: "bot" });
const tree = new Formatter().format(mathBarProperties);
expect(tree).to.deep.equal({
"m:barPr": [
{
"m:pos": {
_attr: {
"w:val": "bot",
},
},
},
],
});
});
});
});

View File

@ -0,0 +1,10 @@
// https://www.datypic.com/sc/ooxml/e-m_barPr-1.html
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { createMathBarPos } from "./math-bar-pos";
export const createMathBarProperties = ({ type }: { readonly type: string }): XmlComponent =>
new BuilderElement({
name: "m:barPr",
children: [createMathBarPos({ val: type })],
});

View File

@ -0,0 +1,38 @@
import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathRun } from "../math-run";
import { createMathBar } from "./math-bar";
describe("MathBar", () => {
describe("#constructor()", () => {
it("should create a MathBar with correct root key", () => {
const mathBar = createMathBar({ type: "top", children: [new MathRun("text")] });
const tree = new Formatter().format(mathBar);
expect(tree).to.deep.equal({
"m:bar": [
{
"m:barPr": [
{
"m:pos": {
_attr: {
"w:val": "top",
},
},
},
],
},
{
"m:e": [
{
"m:r": [{ "m:t": ["text"] }],
},
],
},
],
});
});
});
});

View File

@ -0,0 +1,17 @@
// https://www.datypic.com/sc/ooxml/e-m_bar-1.html
import { BuilderElement, XmlComponent } from "@file/xml-components";
import type { MathComponent } from "../math-component";
import { createMathBase } from "../n-ary";
import { createMathBarProperties } from "./math-bar-properties";
type MathBarOptions = {
readonly type: "top" | "bot";
readonly children: readonly MathComponent[];
};
export const createMathBar = ({ type, children }: MathBarOptions): XmlComponent =>
new BuilderElement({
name: "m:bar",
children: [createMathBarProperties({ type }), createMathBase({ children })],
});

View File

@ -2,19 +2,23 @@
import { XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
import { MathBase } from "../n-ary";
import { MathBracketProperties } from "./math-bracket-properties";
import { createMathBase } from "../n-ary";
import { createMathBracketProperties } from "./math-bracket-properties";
type MathAngledBracketsOptions = { readonly children: readonly MathComponent[] };
export class MathAngledBrackets extends XmlComponent {
public constructor(options: { readonly children: readonly MathComponent[] }) {
public constructor(options: MathAngledBracketsOptions) {
super("m:d");
this.root.push(
new MathBracketProperties({
beginningCharacter: "〈",
endingCharacter: "",
createMathBracketProperties({
characters: {
beginningCharacter: "",
endingCharacter: "〉",
},
}),
);
this.root.push(new MathBase(options.children));
this.root.push(createMathBase({ children: options.children }));
}
}

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathBeginningCharacter } from "./math-beginning-character";
import { createMathBeginningCharacter } from "./math-beginning-character";
describe("MathBeginningCharacter", () => {
describe("createMathBeginningCharacter", () => {
describe("#constructor()", () => {
it("should create a MathBeginningCharacter with correct root key", () => {
const mathBeginningCharacter = new MathBeginningCharacter("[");
const mathBeginningCharacter = createMathBeginningCharacter({ character: "[" });
const tree = new Formatter().format(mathBeginningCharacter);
expect(tree).to.deep.equal({

View File

@ -1,14 +1,12 @@
// http://www.datypic.com/sc/ooxml/e-m_begChr-1.html
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
class MathBeginningCharacterAttributes extends XmlAttributeComponent<{ readonly character: string }> {
protected readonly xmlKeys = { character: "m:val" };
}
type MathBeginningCharacterOptions = { readonly character: string };
export class MathBeginningCharacter extends XmlComponent {
public constructor(character: string) {
super("m:begChr");
this.root.push(new MathBeginningCharacterAttributes({ character }));
}
}
export const createMathBeginningCharacter = ({ character }: MathBeginningCharacterOptions): XmlComponent =>
new BuilderElement<MathBeginningCharacterOptions>({
name: "m:begChr",
attributes: {
character: { key: "m:val", value: character },
},
});

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathBracketProperties } from "./math-bracket-properties";
import { createMathBracketProperties } from "./math-bracket-properties";
describe("MathBracketProperties", () => {
describe("createMathBracketProperties", () => {
describe("#constructor()", () => {
it("should create a MathBracketProperties with correct root key", () => {
const mathBracketProperties = new MathBracketProperties();
const mathBracketProperties = createMathBracketProperties({});
const tree = new Formatter().format(mathBracketProperties);
expect(tree).to.deep.equal({
@ -16,9 +16,11 @@ describe("MathBracketProperties", () => {
});
it("should create a MathBracketProperties with correct root key and add brackets", () => {
const mathBracketProperties = new MathBracketProperties({
beginningCharacter: "[",
endingCharacter: "]",
const mathBracketProperties = createMathBracketProperties({
characters: {
beginningCharacter: "[",
endingCharacter: "]",
},
});
const tree = new Formatter().format(mathBracketProperties);

View File

@ -1,16 +1,18 @@
// http://www.datypic.com/sc/ooxml/e-m_dPr-1.html
import { XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { MathBeginningCharacter } from "./math-beginning-character";
import { MathEndingCharacter } from "./math-ending-char";
import { createMathBeginningCharacter } from "./math-beginning-character";
import { createMathEndingCharacter } from "./math-ending-char";
export class MathBracketProperties extends XmlComponent {
public constructor(options?: { readonly beginningCharacter: string; readonly endingCharacter: string }) {
super("m:dPr");
type MathBracketPropertiesOptions = { readonly characters?: { readonly beginningCharacter: string; readonly endingCharacter: string } };
if (!!options) {
this.root.push(new MathBeginningCharacter(options.beginningCharacter));
this.root.push(new MathEndingCharacter(options.endingCharacter));
}
}
}
export const createMathBracketProperties = ({ characters }: MathBracketPropertiesOptions): XmlComponent =>
new BuilderElement({
name: "m:dPr",
children: !!characters
? [
createMathBeginningCharacter({ character: characters.beginningCharacter }),
createMathEndingCharacter({ character: characters.endingCharacter }),
]
: [],
});

View File

@ -2,19 +2,21 @@
import { XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
import { MathBase } from "../n-ary";
import { MathBracketProperties } from "./math-bracket-properties";
import { createMathBase } from "../n-ary";
import { createMathBracketProperties } from "./math-bracket-properties";
export class MathCurlyBrackets extends XmlComponent {
public constructor(options: { readonly children: readonly MathComponent[] }) {
super("m:d");
this.root.push(
new MathBracketProperties({
beginningCharacter: "{",
endingCharacter: "}",
createMathBracketProperties({
characters: {
beginningCharacter: "{",
endingCharacter: "}",
},
}),
);
this.root.push(new MathBase(options.children));
this.root.push(createMathBase({ children: options.children }));
}
}

View File

@ -1,14 +1,12 @@
// http://www.datypic.com/sc/ooxml/e-m_endChr-1.html
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
class MathEndingCharacterAttributes extends XmlAttributeComponent<{ readonly character: string }> {
protected readonly xmlKeys = { character: "m:val" };
}
type MathEndingCharacterOptions = { readonly character: string };
export class MathEndingCharacter extends XmlComponent {
public constructor(character: string) {
super("m:endChr");
this.root.push(new MathEndingCharacterAttributes({ character }));
}
}
export const createMathEndingCharacter = ({ character }: MathEndingCharacterOptions): XmlComponent =>
new BuilderElement<MathEndingCharacterOptions>({
name: "m:endChr",
attributes: {
character: { key: "m:val", value: character },
},
});

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathEndingCharacter } from "./math-ending-char";
import { createMathEndingCharacter } from "./math-ending-char";
describe("MathEndingCharacter", () => {
describe("createMathEndingCharacter", () => {
describe("#constructor()", () => {
it("should create a MathEndingCharacter with correct root key", () => {
const mathEndingCharacter = new MathEndingCharacter("]");
const mathEndingCharacter = createMathEndingCharacter({ character: "]" });
const tree = new Formatter().format(mathEndingCharacter);
expect(tree).to.deep.equal({

View File

@ -2,14 +2,14 @@
import { XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
import { MathBase } from "../n-ary";
import { MathBracketProperties } from "./math-bracket-properties";
import { createMathBase } from "../n-ary";
import { createMathBracketProperties } from "./math-bracket-properties";
export class MathRoundBrackets extends XmlComponent {
public constructor(options: { readonly children: readonly MathComponent[] }) {
super("m:d");
this.root.push(new MathBracketProperties());
this.root.push(new MathBase(options.children));
this.root.push(createMathBracketProperties({}));
this.root.push(createMathBase({ children: options.children }));
}
}

View File

@ -2,19 +2,21 @@
import { XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
import { MathBase } from "../n-ary";
import { MathBracketProperties } from "./math-bracket-properties";
import { createMathBase } from "../n-ary";
import { createMathBracketProperties } from "./math-bracket-properties";
export class MathSquareBrackets extends XmlComponent {
public constructor(options: { readonly children: readonly MathComponent[] }) {
super("m:d");
this.root.push(
new MathBracketProperties({
beginningCharacter: "[",
endingCharacter: "]",
createMathBracketProperties({
characters: {
beginningCharacter: "[",
endingCharacter: "]",
},
}),
);
this.root.push(new MathBase(options.children));
this.root.push(createMathBase({ children: options.children }));
}
}

View File

@ -2,7 +2,7 @@
import { XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
import { MathBase } from "../n-ary";
import { createMathBase } from "../n-ary";
import { MathFunctionName } from "./math-function-name";
import { MathFunctionProperties } from "./math-function-properties";
@ -17,6 +17,6 @@ export class MathFunction extends XmlComponent {
this.root.push(new MathFunctionProperties());
this.root.push(new MathFunctionName(options.name));
this.root.push(new MathBase(options.children));
this.root.push(createMathBase({ children: options.children }));
}
}

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathAccentCharacter } from "./math-accent-character";
import { createMathAccentCharacter } from "./math-accent-character";
describe("MathAccentCharacter", () => {
describe("#constructor()", () => {
it("should create a MathAccentCharacter with correct root key", () => {
const mathAccentCharacter = new MathAccentCharacter("∑");
const mathAccentCharacter = createMathAccentCharacter({ accent: "∑" });
const tree = new Formatter().format(mathAccentCharacter);
expect(tree).to.deep.equal({

View File

@ -1,14 +1,12 @@
// http://www.datypic.com/sc/ooxml/e-m_chr-1.html
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
class MathAccentCharacterAttributes extends XmlAttributeComponent<{ readonly accent: string }> {
protected readonly xmlKeys = { accent: "m:val" };
}
type MathAccentCharacterOptions = { readonly accent: string };
export class MathAccentCharacter extends XmlComponent {
public constructor(accent: string) {
super("m:chr");
this.root.push(new MathAccentCharacterAttributes({ accent }));
}
}
export const createMathAccentCharacter = ({ accent }: MathAccentCharacterOptions): XmlComponent =>
new BuilderElement<MathAccentCharacterOptions>({
name: "m:chr",
attributes: {
accent: { key: "m:val", value: accent },
},
});

View File

@ -3,12 +3,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathRun } from "../math-run";
import { MathBase } from "./math-base";
import { createMathBase } from "./math-base";
describe("MathBase", () => {
describe("createMathBase", () => {
describe("#constructor()", () => {
it("should create a MathBase with correct root key", () => {
const mathBase = new MathBase([new MathRun("2+2")]);
const mathBase = createMathBase({ children: [new MathRun("2+2")] });
const tree = new Formatter().format(mathBase);
expect(tree).to.deep.equal({

View File

@ -1,14 +1,14 @@
// http://www.datypic.com/sc/ooxml/e-m_e-1.html
import { XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
export class MathBase extends XmlComponent {
public constructor(children: readonly MathComponent[]) {
super("m:e");
type MathBaseOptions = {
readonly children: readonly MathComponent[];
};
for (const child of children) {
this.root.push(child);
}
}
}
export const createMathBase = ({ children }: MathBaseOptions): XmlComponent =>
new BuilderElement({
name: "m:e",
children,
});

View File

@ -1,10 +1,10 @@
import { XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
import { MathBase } from "./math-base";
import { MathNAryProperties } from "./math-n-ary-properties";
import { MathSubScriptElement } from "./math-sub-script";
import { MathSuperScriptElement } from "./math-super-script";
import { createMathBase } from "./math-base";
import { createMathNAryProperties } from "./math-n-ary-properties";
import { createMathSubScriptElement } from "./math-sub-script";
import { createMathSuperScriptElement } from "./math-super-script";
export type IMathIntegralOptions = {
readonly children: readonly MathComponent[];
@ -16,16 +16,23 @@ export class MathIntegral extends XmlComponent {
public constructor(options: IMathIntegralOptions) {
super("m:nary");
this.root.push(new MathNAryProperties("", !!options.superScript, !!options.subScript, "subSup"));
this.root.push(
createMathNAryProperties({
accent: "",
hasSuperScript: !!options.superScript,
hasSubScript: !!options.subScript,
limitLocationVal: "subSup",
}),
);
if (!!options.subScript) {
this.root.push(new MathSubScriptElement(options.subScript));
this.root.push(createMathSubScriptElement({ children: options.subScript }));
}
if (!!options.superScript) {
this.root.push(new MathSuperScriptElement(options.superScript));
this.root.push(createMathSuperScriptElement({ children: options.superScript }));
}
this.root.push(new MathBase(options.children));
this.root.push(createMathBase({ children: options.children }));
}
}

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathLimitLocation } from "./math-limit-location";
import { createMathLimitLocation } from "./math-limit-location";
describe("MathLimitLocation", () => {
describe("createMathLimitLocation", () => {
describe("#constructor()", () => {
it("should create a MathLimitLocation with correct root key", () => {
const mathLimitLocation = new MathLimitLocation();
const mathLimitLocation = createMathLimitLocation({});
const tree = new Formatter().format(mathLimitLocation);
expect(tree).to.deep.equal({

View File

@ -1,14 +1,12 @@
// http://www.datypic.com/sc/ooxml/e-m_limLoc-1.html
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
class MathLimitLocationAttributes extends XmlAttributeComponent<{ readonly value: string }> {
protected readonly xmlKeys = { value: "m:val" };
}
type MathLimitLocationOptions = { readonly value?: string };
export class MathLimitLocation extends XmlComponent {
public constructor(value?: string) {
super("m:limLoc");
this.root.push(new MathLimitLocationAttributes({ value: value || "undOvr" }));
}
}
export const createMathLimitLocation = ({ value }: MathLimitLocationOptions): XmlComponent =>
new BuilderElement<Required<MathLimitLocationOptions>>({
name: "m:limLoc",
attributes: {
value: { key: "m:val", value: value || "undOvr" },
},
});

View File

@ -2,7 +2,7 @@
import { XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
import { MathBase } from "./math-base";
import { createMathBase } from "./math-base";
import { MathLimit } from "./math-limit";
export type IMathLimitLowerOptions = {
@ -14,7 +14,7 @@ export class MathLimitLower extends XmlComponent {
public constructor(options: IMathLimitLowerOptions) {
super("m:limLow");
this.root.push(new MathBase(options.children));
this.root.push(createMathBase({ children: options.children }));
this.root.push(new MathLimit(options.limit));
}
}

View File

@ -2,7 +2,7 @@
import { XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
import { MathBase } from "./math-base";
import { createMathBase } from "./math-base";
import { MathLimit } from "./math-limit";
export type IMathLimitUpperOptions = {
@ -14,7 +14,7 @@ export class MathLimitUpper extends XmlComponent {
public constructor(options: IMathLimitUpperOptions) {
super("m:limUpp");
this.root.push(new MathBase(options.children));
this.root.push(createMathBase({ children: options.children }));
this.root.push(new MathLimit(options.limit));
}
}

View File

@ -2,12 +2,16 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathNAryProperties } from "./math-n-ary-properties";
import { createMathNAryProperties } from "./math-n-ary-properties";
describe("MathNAryProperties", () => {
describe("createMathNAryProperties", () => {
describe("#constructor()", () => {
it("should create a MathNAryProperties with correct root key", () => {
const mathNAryProperties = new MathNAryProperties("∑", true, true);
const mathNAryProperties = createMathNAryProperties({
accent: "∑",
hasSuperScript: true,
hasSubScript: true,
});
const tree = new Formatter().format(mathNAryProperties);
expect(tree).to.deep.equal({
@ -31,7 +35,11 @@ describe("MathNAryProperties", () => {
});
it("should add super-script hide attributes", () => {
const mathNAryProperties = new MathNAryProperties("∑", false, true);
const mathNAryProperties = createMathNAryProperties({
accent: "∑",
hasSuperScript: false,
hasSubScript: true,
});
const tree = new Formatter().format(mathNAryProperties);
expect(tree).to.deep.equal({
@ -62,7 +70,11 @@ describe("MathNAryProperties", () => {
});
it("should add sub-script hide attributes", () => {
const mathNAryProperties = new MathNAryProperties("∑", true, false);
const mathNAryProperties = createMathNAryProperties({
accent: "∑",
hasSuperScript: true,
hasSubScript: false,
});
const tree = new Formatter().format(mathNAryProperties);
expect(tree).to.deep.equal({
@ -93,7 +105,11 @@ describe("MathNAryProperties", () => {
});
it("should add both super-script and sub-script hide attributes", () => {
const mathNAryProperties = new MathNAryProperties("∑", false, false);
const mathNAryProperties = createMathNAryProperties({
accent: "∑",
hasSuperScript: false,
hasSubScript: false,
});
const tree = new Formatter().format(mathNAryProperties);
expect(tree).to.deep.equal({

View File

@ -1,26 +1,30 @@
// http://www.datypic.com/sc/ooxml/e-m_naryPr-1.html
import { XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { MathAccentCharacter } from "./math-accent-character";
import { MathLimitLocation } from "./math-limit-location";
import { MathSubScriptHide } from "./math-sub-script-hide";
import { MathSuperScriptHide } from "./math-super-script-hide";
import { createMathAccentCharacter } from "./math-accent-character";
import { createMathLimitLocation } from "./math-limit-location";
import { createMathSubScriptHide } from "./math-sub-script-hide";
import { createMathSuperScriptHide } from "./math-super-script-hide";
export class MathNAryProperties extends XmlComponent {
public constructor(accent: string, hasSuperScript: boolean, hasSubScript: boolean, limitLocationVal?: string) {
super("m:naryPr");
type MathNAryPropertiesOptions = {
readonly accent: string;
readonly hasSuperScript: boolean;
readonly hasSubScript: boolean;
readonly limitLocationVal?: string;
};
if (!!accent) {
this.root.push(new MathAccentCharacter(accent));
}
this.root.push(new MathLimitLocation(limitLocationVal));
if (!hasSuperScript) {
this.root.push(new MathSuperScriptHide());
}
if (!hasSubScript) {
this.root.push(new MathSubScriptHide());
}
}
}
export const createMathNAryProperties = ({
accent,
hasSuperScript,
hasSubScript,
limitLocationVal,
}: MathNAryPropertiesOptions): XmlComponent =>
new BuilderElement({
name: "m:naryPr",
children: [
...(!!accent ? [createMathAccentCharacter({ accent })] : []),
createMathLimitLocation({ value: limitLocationVal }),
...(!hasSuperScript ? [createMathSuperScriptHide()] : []),
...(!hasSubScript ? [createMathSubScriptHide()] : []),
],
});

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathSubScriptHide } from "./math-sub-script-hide";
import { createMathSubScriptHide } from "./math-sub-script-hide";
describe("MathSubScriptHide", () => {
describe("createMathSubScriptHide", () => {
describe("#constructor()", () => {
it("should create a MathSubScriptHide with correct root key", () => {
const mathSubScriptHide = new MathSubScriptHide();
const mathSubScriptHide = createMathSubScriptHide();
const tree = new Formatter().format(mathSubScriptHide);
expect(tree).to.deep.equal({

View File

@ -1,14 +1,10 @@
// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
class MathSubScriptHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> {
protected readonly xmlKeys = { hide: "m:val" };
}
export class MathSubScriptHide extends XmlComponent {
public constructor() {
super("m:subHide");
this.root.push(new MathSubScriptHideAttributes({ hide: 1 }));
}
}
export const createMathSubScriptHide = (): XmlComponent =>
new BuilderElement<{ readonly hide: number }>({
name: "m:subHide",
attributes: {
hide: { key: "m:val", value: 1 },
},
});

View File

@ -3,12 +3,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathRun } from "../math-run";
import { MathSubScriptElement } from "./math-sub-script";
import { createMathSubScriptElement } from "./math-sub-script";
describe("MathSubScriptElement", () => {
describe("createMathSubScriptElement", () => {
describe("#constructor()", () => {
it("should create a MathSubScriptElement with correct root key", () => {
const mathSubScriptElement = new MathSubScriptElement([new MathRun("2+2")]);
const mathSubScriptElement = createMathSubScriptElement({ children: [new MathRun("2+2")] });
const tree = new Formatter().format(mathSubScriptElement);
expect(tree).to.deep.equal({

View File

@ -1,14 +1,14 @@
// http://www.datypic.com/sc/ooxml/e-m_sub-3.html
import { XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
export class MathSubScriptElement extends XmlComponent {
public constructor(children: readonly MathComponent[]) {
super("m:sub");
type MathSubScriptElementOptions = {
readonly children: readonly MathComponent[];
};
for (const child of children) {
this.root.push(child);
}
}
}
export const createMathSubScriptElement = ({ children }: MathSubScriptElementOptions): XmlComponent =>
new BuilderElement({
name: "m:sub",
children,
});

View File

@ -2,10 +2,10 @@
import { XmlComponent } from "@file/xml-components";
import { MathComponent } from "../math-component";
import { MathBase } from "./math-base";
import { MathNAryProperties } from "./math-n-ary-properties";
import { MathSubScriptElement } from "./math-sub-script";
import { MathSuperScriptElement } from "./math-super-script";
import { createMathBase } from "./math-base";
import { createMathNAryProperties } from "./math-n-ary-properties";
import { createMathSubScriptElement } from "./math-sub-script";
import { createMathSuperScriptElement } from "./math-super-script";
export type IMathSumOptions = {
readonly children: readonly MathComponent[];
@ -17,16 +17,22 @@ export class MathSum extends XmlComponent {
public constructor(options: IMathSumOptions) {
super("m:nary");
this.root.push(new MathNAryProperties("∑", !!options.superScript, !!options.subScript));
this.root.push(
createMathNAryProperties({
accent: "∑",
hasSuperScript: !!options.superScript,
hasSubScript: !!options.subScript,
}),
);
if (!!options.subScript) {
this.root.push(new MathSubScriptElement(options.subScript));
this.root.push(createMathSubScriptElement({ children: options.subScript }));
}
if (!!options.superScript) {
this.root.push(new MathSuperScriptElement(options.superScript));
this.root.push(createMathSuperScriptElement({ children: options.superScript }));
}
this.root.push(new MathBase(options.children));
this.root.push(createMathBase({ children: options.children }));
}
}

View File

@ -2,12 +2,12 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { MathSuperScriptHide } from "./math-super-script-hide";
import { createMathSuperScriptHide } from "./math-super-script-hide";
describe("MathSuperScriptHide", () => {
describe("createMathSuperScriptHide", () => {
describe("#constructor()", () => {
it("should create a MathSuperScriptHide with correct root key", () => {
const mathSuperScriptHide = new MathSuperScriptHide();
const mathSuperScriptHide = createMathSuperScriptHide();
const tree = new Formatter().format(mathSuperScriptHide);
expect(tree).to.deep.equal({

View File

@ -1,14 +1,10 @@
// http://www.datypic.com/sc/ooxml/e-m_subHide-1.html
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { BuilderElement, XmlComponent } from "@file/xml-components";
class MathSuperScriptHideAttributes extends XmlAttributeComponent<{ readonly hide: number }> {
protected readonly xmlKeys = { hide: "m:val" };
}
export class MathSuperScriptHide extends XmlComponent {
public constructor() {
super("m:supHide");
this.root.push(new MathSuperScriptHideAttributes({ hide: 1 }));
}
}
export const createMathSuperScriptHide = (): XmlComponent =>
new BuilderElement<{ readonly hide: number }>({
name: "m:supHide",
attributes: {
hide: { key: "m:val", value: 1 },
},
});

Some files were not shown because too many files have changed in this diff Show More