Compare commits

..

1 Commits

Author SHA1 Message Date
7d53e5d5f2 Add table borders to table demo 2023-12-27 20:56:13 +00:00
358 changed files with 10547 additions and 16014 deletions

View File

@ -8,14 +8,11 @@
// words - list of words to be always considered correct // words - list of words to be always considered correct
"words": [ "words": [
"Abjad", "Abjad",
"aink",
"aiueo", "aiueo",
"ATLEAST", "ATLEAST",
"chosung", "chosung",
"clippy", "clippy",
"datas", "datas",
"dcmitype",
"dcterms",
"docsify", "docsify",
"dolan", "dolan",
"execa", "execa",
@ -24,7 +21,6 @@
"iife", "iife",
"Initializable", "Initializable",
"iroha", "iroha",
"JOHAB",
"jsonify", "jsonify",
"jszip", "jszip",
"NUMPAGES", "NUMPAGES",
@ -35,7 +31,6 @@
"panose", "panose",
"rels", "rels",
"rsid", "rsid",
"sdtdh",
"twip", "twip",
"twips", "twips",
"Xmlable", "Xmlable",

238
.eslintrc.yml Normal file
View File

@ -0,0 +1,238 @@
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/ban-types":
- error
- types:
Object:
message: Avoid using the `Object` type. Did you mean `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`?
Number:
message: Avoid using the `Number` type. Did you mean `number`?
String:
message: Avoid using the `String` type. Did you mean `string`?
Symbol:
message: Avoid using the `Symbol` type. Did you mean `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

@ -13,10 +13,10 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
uses: actions/checkout@v4 uses: actions/checkout@master
- uses: "./.github/actions/install-and-build" - uses: "./.github/actions/install-and-build"
- name: Archive Production Artifact - name: Archive Production Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@master
with: with:
name: build name: build
path: build path: build
@ -25,24 +25,22 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
uses: actions/checkout@v4 uses: actions/checkout@master
- name: Install Dependencies - name: Install Dependencies
run: npm ci --force run: npm ci --force
- name: Test - name: Test
run: npm run test:ci run: npm run test:ci
- name: Codecov - name: Codecov
uses: codecov/codecov-action@v4 uses: codecov/codecov-action@v3
with: with:
fail_ci_if_error: true fail_ci_if_error: true
verbose: true verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
lint: lint:
name: Lint name: Lint
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
uses: actions/checkout@v4 uses: actions/checkout@master
- name: Install Dependencies - name: Install Dependencies
run: npm ci --force run: npm ci --force
- name: Lint - name: Lint
@ -52,7 +50,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
uses: actions/checkout@v4 uses: actions/checkout@master
- name: Install Dependencies - name: Install Dependencies
run: npm ci --force run: npm ci --force
- name: Prettier - name: Prettier
@ -62,8 +60,8 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
uses: actions/checkout@v4 uses: actions/checkout@master
- name: Install Dependencies - name: Install Dependencies
run: npm ci --force run: npm ci --force
- name: CSpell - name: Prettier
run: npm run cspell run: npm run cspell

View File

@ -8,189 +8,777 @@ on:
- master - master
jobs: jobs:
demos: build:
name: Demos name: Build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@master
- name: Install Dependencies
run: npm ci --force
- name: Build
run: npm run build
- name: Archive Production Artifact
uses: actions/upload-artifact@master
with:
name: build
path: build
demo_1:
name: Run Demo 1 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build" - uses: "./.github/actions/install-and-build"
- name: Run Demos - run: npm run run-ts -- ./demo/1-basic.ts
run: npm run run-ts -- ./demo/1-basic.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_2:
name: Run Demo 2 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/2-declaritive-styles.ts - run: npm run run-ts -- ./demo/2-declaritive-styles.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_3:
name: Run Demo 3 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/3-numbering-and-bullet-points.ts - run: npm run run-ts -- ./demo/3-numbering-and-bullet-points.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_4:
name: Run Demo 4 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/4-basic-table.ts - run: npm run run-ts -- ./demo/4-basic-table.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_5:
name: Run Demo 5 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/5-images.ts - run: npm run run-ts -- ./demo/5-images.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_6:
name: Run Demo 6 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/6-page-borders.ts - run: npm run run-ts -- ./demo/6-page-borders.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_7:
name: Run Demo 7 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/7-landscape.ts - run: npm run run-ts -- ./demo/7-landscape.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_8:
name: Run Demo 8 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/8-header-footer.ts - run: npm run run-ts -- ./demo/8-header-footer.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_9:
name: Run Demo 9 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/9-images-in-header-and-footer.ts - run: npm run run-ts -- ./demo/9-images-in-header-and-footer.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_10:
name: Run Demo 10 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/10-my-cv.ts - run: npm run run-ts -- ./demo/10-my-cv.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_11:
name: Run Demo 11 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/11-declaritive-styles-2.ts - run: npm run run-ts -- ./demo/11-declaritive-styles-2.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_12:
name: Run Demo 12 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/12-scaling-images.ts - run: npm run run-ts -- ./demo/12-scaling-images.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_13:
name: Run Demo 13 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/13-xml-styles.ts - run: npm run run-ts -- ./demo/13-xml-styles.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_14:
name: Run Demo 14 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/14-page-numbers.ts - run: npm run run-ts -- ./demo/14-page-numbers.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_15:
name: Run Demo 15 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/15-page-break-before.ts - run: npm run run-ts -- ./demo/15-page-break-before.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_16:
name: Run Demo 16 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/16-multiple-sections.ts - run: npm run run-ts -- ./demo/16-multiple-sections.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_17:
name: Run Demo 17 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/17-footnotes.ts - run: npm run run-ts -- ./demo/17-footnotes.ts
# element r: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}r': This element is not expected. # element r: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}r': This element is not expected.
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_18:
name: Run Demo 18 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/18-image-from-buffer.ts - run: npm run run-ts -- ./demo/18-image-from-buffer.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_19:
name: Run Demo 19 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/19-export-to-base64.ts - run: npm run run-ts -- ./demo/19-export-to-base64.ts
# Base 64 No longer works, abruptly. Node issue? # Base 64 No longer works, abruptly. Node issue?
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_20:
name: Run Demo 20 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/20-table-cell-borders.ts - run: npm run run-ts -- ./demo/20-table-cell-borders.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_21:
name: Run Demo 21 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/21-bookmarks.ts - run: npm run run-ts -- ./demo/21-bookmarks.ts
# Bad ID - need numeric ID # Bad ID - need numeric ID
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_22:
name: Run Demo 22 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/22-right-to-left-text.ts - run: npm run run-ts -- ./demo/22-right-to-left-text.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_23:
name: Run Demo 23 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/23-base64-images.ts - run: npm run run-ts -- ./demo/23-base64-images.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_24:
name: Run Demo 24 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/24-images-to-table-cell.ts - run: npm run run-ts -- ./demo/24-images-to-table-cell.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_25:
name: Run Demo 25 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/25-table-xml-styles.ts - run: npm run run-ts -- ./demo/25-table-xml-styles.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_26:
name: Run Demo 26 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/26-paragraph-borders.ts - run: npm run run-ts -- ./demo/26-paragraph-borders.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_27:
name: Run Demo 27 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/27-declaritive-styles-3.ts - run: npm run run-ts -- ./demo/27-declaritive-styles-3.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_28:
name: Run Demo 28 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/28-table-of-contents.ts - run: npm run run-ts -- ./demo/28-table-of-contents.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_29:
name: Run Demo 29 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/29-numbered-lists.ts - run: npm run run-ts -- ./demo/29-numbered-lists.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_31:
name: Run Demo 31 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/31-tables.ts - run: npm run run-ts -- ./demo/31-tables.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_32:
name: Run Demo 32 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/32-merge-and-shade-table-cells.ts - run: npm run run-ts -- ./demo/32-merge-and-shade-table-cells.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_33:
name: Run Demo 33 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/33-sequential-captions.ts - run: npm run run-ts -- ./demo/33-sequential-captions.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_34:
name: Run Demo 34 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/34-floating-tables.ts - run: npm run run-ts -- ./demo/34-floating-tables.ts
# element tblpPr: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}tblpPr', attribute 'overlap': The attribute 'overlap' is not allowed. # element tblpPr: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}tblpPr', attribute 'overlap': The attribute 'overlap' is not allowed.
# element tblpPr: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}tblpPr': Element content is not allowed, because the content type is empty. # element tblpPr: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}tblpPr': Element content is not allowed, because the content type is empty.
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_35:
name: Run Demo 35 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/35-hyperlinks.ts - run: npm run run-ts -- ./demo/35-hyperlinks.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_36:
name: Run Demo 36 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/36-image-to-table-cell.ts - run: npm run run-ts -- ./demo/36-image-to-table-cell.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_37:
name: Run Demo 37 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/37-images-to-header-and-footer.ts - run: npm run run-ts -- ./demo/37-images-to-header-and-footer.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_38:
name: Run Demo 38 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/38-text-wrapping.ts - run: npm run run-ts -- ./demo/38-text-wrapping.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_39:
name: Run Demo 39 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/39-page-numbers.ts - run: npm run run-ts -- ./demo/39-page-numbers.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_40:
name: Run Demo 40 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/40-line-numbers.ts - run: npm run run-ts -- ./demo/40-line-numbers.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_41:
name: Run Demo 41 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/41-merge-table-cells-2.ts - run: npm run run-ts -- ./demo/41-merge-table-cells-2.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_42:
name: Run Demo 42 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/42-restart-page-numbers.ts - run: npm run run-ts -- ./demo/42-restart-page-numbers.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_43:
name: Run Demo 43 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/43-images-to-table-cell-2.ts - run: npm run run-ts -- ./demo/43-images-to-table-cell-2.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_44:
name: Run Demo 44 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/44-multiple-columns.ts - run: npm run run-ts -- ./demo/44-multiple-columns.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_45:
name: Run Demo 45 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/45-highlighting-text.ts - run: npm run run-ts -- ./demo/45-highlighting-text.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_46:
name: Run Demo 46 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/46-shading-text.ts - run: npm run run-ts -- ./demo/46-shading-text.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_47:
name: Run Demo 47 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/47-number-of-total-pages-section.ts - run: npm run run-ts -- ./demo/47-number-of-total-pages-section.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_48:
name: Run Demo 48 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/48-vertical-align.ts - run: npm run run-ts -- ./demo/48-vertical-align.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_49:
name: Run Demo 49 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/49-table-borders.ts - run: npm run run-ts -- ./demo/49-table-borders.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_50:
name: Run Demo 50 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/50-readme-demo.ts - run: npm run run-ts -- ./demo/50-readme-demo.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_51:
name: Run Demo 51 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/51-character-styles.ts - run: npm run run-ts -- ./demo/51-character-styles.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_52:
name: Run Demo 52 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/52-japanese.ts - run: npm run run-ts -- ./demo/52-japanese.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_53:
name: Run Demo 53 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/53-chinese.ts - run: npm run run-ts -- ./demo/53-chinese.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_54:
name: Run Demo 54 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/54-custom-properties.ts - run: npm run run-ts -- ./demo/54-custom-properties.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_55:
name: Run Demo 55 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/55-math.ts - run: npm run run-ts -- ./demo/55-math.ts
#: element subHide: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}subHide': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}ctrlPr ). #: element subHide: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}subHide': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}ctrlPr ).
#: element e: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}e': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}sub ). #: element e: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}e': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}sub ).
#: element e: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}e': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}sup ). #: element e: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}e': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}sup ).
#: element e: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}e': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}sub ). #: element e: Schemas validity error : Element '{http://schemas.openxmlformats.org/officeDocument/2006/math}e': This element is not expected. Expected is ( {http://schemas.openxmlformats.org/officeDocument/2006/math}sub ).
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_56:
name: Run Demo 56 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/56-background-color.ts - run: npm run run-ts -- ./demo/56-background-color.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_57:
name: Run Demo 57 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/57-add-parent-numbered-lists.ts - run: npm run run-ts -- ./demo/57-add-parent-numbered-lists.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_58:
name: Run Demo 58 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/58-section-types.ts - run: npm run run-ts -- ./demo/58-section-types.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_59:
name: Run Demo 59 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/59-header-footer-margins.ts - run: npm run run-ts -- ./demo/59-header-footer-margins.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_60:
name: Run Demo 60 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/60-track-revisions.ts - run: npm run run-ts -- ./demo/60-track-revisions.ts
# element r: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}r': This element is not expected. # element r: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}r': This element is not expected.
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_61:
name: Run Demo 61 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/61-text-frame.ts - run: npm run run-ts -- ./demo/61-text-frame.ts
# element left: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}left': This element is not expected. Expected is one of ( {http://schemas.openxmlformats.org/wordprocessingml/2006/main}right, {http://schemas.openxmlformats.org/wordprocessingml/2006/main}between, {http://schemas.openxmlformats.org/wordprocessingml/2006/main}bar ). # element left: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}left': This element is not expected. Expected is one of ( {http://schemas.openxmlformats.org/wordprocessingml/2006/main}right, {http://schemas.openxmlformats.org/wordprocessingml/2006/main}between, {http://schemas.openxmlformats.org/wordprocessingml/2006/main}bar ).
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_62:
name: Run Demo 62 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/62-paragraph-spacing.ts - run: npm run run-ts -- ./demo/62-paragraph-spacing.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_63:
name: Run Demo 63 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/63-odd-even-header-footer.ts - run: npm run run-ts -- ./demo/63-odd-even-header-footer.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_64:
name: Run Demo 64 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/64-complex-numbering-text.ts - run: npm run run-ts -- ./demo/64-complex-numbering-text.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_65:
name: Run Demo 65 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/65-page-sizes.ts - run: npm run run-ts -- ./demo/65-page-sizes.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_66:
name: Run Demo 66 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/66-fields.ts - run: npm run run-ts -- ./demo/66-fields.ts
# element bookmarkStart: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}bookmarkStart', attribute '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}id': '-irrswq-ln94j4fdgdjxs' is not a valid value of the atomic type '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}ST_DecimalNumber'. # element bookmarkStart: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}bookmarkStart', attribute '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}id': '-irrswq-ln94j4fdgdjxs' is not a valid value of the atomic type '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}ST_DecimalNumber'.
# element bookmarkEnd: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}bookmarkEnd', attribute '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}id': '-irrswq-ln94j4fdgdjxs' is not a valid value of the atomic type '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}ST_DecimalNumber'. # element bookmarkEnd: Schemas validity error : Element '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}bookmarkEnd', attribute '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}id': '-irrswq-ln94j4fdgdjxs' is not a valid value of the atomic type '{http://schemas.openxmlformats.org/wordprocessingml/2006/main}ST_DecimalNumber'.
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_67:
name: Run Demo 67 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/67-column-break.ts - run: npm run run-ts -- ./demo/67-column-break.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_68:
name: Run Demo 68 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/68-numbering-instances-and-starting-number.ts - run: npm run run-ts -- ./demo/68-numbering-instances-and-starting-number.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_69:
name: Run Demo 69 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/69-different-width-columns.ts - run: npm run run-ts -- ./demo/69-different-width-columns.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_70:
name: Run Demo 70 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/70-line-numbers-suppression.ts - run: npm run run-ts -- ./demo/70-line-numbers-suppression.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_71:
name: Run Demo 71 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/71-page-borders-2.ts - run: npm run run-ts -- ./demo/71-page-borders-2.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_72:
name: Run Demo 72 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/72-word-wrap.ts - run: npm run run-ts -- ./demo/72-word-wrap.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_73:
name: Run Demo 73 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/73-comments.ts - run: npm run run-ts -- ./demo/73-comments.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_74:
name: Run Demo 74 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/74-nodejs-stream.ts - run: npm run run-ts -- ./demo/74-nodejs-stream.ts
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_75:
name: Run Demo 75 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
# run: npm run run-ts -- ./demo/75-tab-stops.ts # run: npm run run-ts -- ./demo/75-tab-stops.ts
# - uses: "./.github/actions/validate-docx" # - uses: "./.github/actions/validate-docx"
demo_76:
name: Run Demo 76 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/76-compatibility.ts - run: npm run run-ts -- ./demo/76-compatibility.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_77:
name: Run Demo 77 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/77-side-by-side-tables.ts - run: npm run run-ts -- ./demo/77-side-by-side-tables.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_78:
name: Run Demo 78 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/78-thai-distributed.ts - run: npm run run-ts -- ./demo/78-thai-distributed.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_79:
name: Run Demo 79 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/79-table-from-data-source.ts - run: npm run run-ts -- ./demo/79-table-from-data-source.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_80:
name: Run Demo 80 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/80-thai-distributed.ts - run: npm run run-ts -- ./demo/80-thai-distributed.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_81:
name: Run Demo 81 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/81-continuous-header.ts - run: npm run run-ts -- ./demo/81-continuous-header.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_82:
name: Run Demo 82 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/82-new-headers-new-section.ts - run: npm run run-ts -- ./demo/82-new-headers-new-section.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_83:
name: Run Demo 83 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/83-setting-languages.ts - run: npm run run-ts -- ./demo/83-setting-languages.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"
demo_84:
name: Run Demo 84 and validate
needs: [build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: "./.github/actions/install-and-build"
- run: npm run run-ts -- ./demo/84-positional-tabs.ts - run: npm run run-ts -- ./demo/84-positional-tabs.ts
- uses: "./.github/actions/validate-docx" - uses: "./.github/actions/validate-docx"

View File

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo - name: Checkout Repo
uses: actions/checkout@v4 uses: actions/checkout@master
- name: Install Dependencies - name: Install Dependencies
run: npm ci --force run: npm ci --force
- name: Build 🔧 - name: Build 🔧
@ -19,7 +19,7 @@ jobs:
echo "docx.js.org" > docs/.nojekyll echo "docx.js.org" > docs/.nojekyll
echo "docx.js.org" > docs/CNAME echo "docx.js.org" > docs/CNAME
- name: Archive Production Artifact - name: Archive Production Artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@master
with: with:
name: docs name: docs
path: docs path: docs
@ -28,11 +28,11 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout Repo 🛎️ - name: Checkout Repo 🛎️
uses: actions/checkout@v4 uses: actions/checkout@master
- name: Install Dependencies - name: Install Dependencies
run: npm ci --force run: npm ci --force
- name: Download Artifact - name: Download Artifact
uses: actions/download-artifact@v4 uses: actions/download-artifact@master
with: with:
name: docs name: docs
path: docs path: docs

View File

@ -1,46 +0,0 @@
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
name: Node.js Package
on:
release:
types: [created]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20.x"
- run: npm ci --force
- run: npm run cspell
- run: npm run prettier
- run: npm run lint
- run: npm run test:ci
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20.x"
- run: npm ci --force
- run: npm run build
publish-npm:
needs: [test, build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20.x"
registry-url: https://registry.npmjs.org/
- run: npm ci --force
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.npm_token}}

3
.gitignore vendored
View File

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

View File

@ -5,6 +5,5 @@
"editor.formatOnSave": false, "editor.formatOnSave": false,
"prettier.tabWidth": 4, "prettier.tabWidth": 4,
"prettier.arrowParens": "always", "prettier.arrowParens": "always",
"prettier.bracketSpacing": true, "prettier.bracketSpacing": true
"eslint.useFlatConfig": true
} }

View File

@ -14,7 +14,6 @@
[![Known Vulnerabilities][snky-image]][snky-url] [![Known Vulnerabilities][snky-image]][snky-url]
[![PRs Welcome][pr-image]][pr-url] [![PRs Welcome][pr-image]][pr-url]
[![codecov][codecov-image]][codecov-url] [![codecov][codecov-image]][codecov-url]
[![Docx.js Editor][docxjs-editor-image]][docxjs-editor-url]
<p align="center"> <p align="center">
<img src="https://i.imgur.com/QeL1HuU.png" alt="drawing"/> <img src="https://i.imgur.com/QeL1HuU.png" alt="drawing"/>
@ -65,10 +64,6 @@ 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! 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 # Examples
Check the [demo folder](https://github.com/dolanmiu/docx/tree/master/demo) for examples. Check the [demo folder](https://github.com/dolanmiu/docx/tree/master/demo) for examples.
@ -93,7 +88,6 @@ Read the contribution guidelines [here](https://docx.js.org/#/contribution-guide
[<img src="https://i.imgur.com/PXo25um.png" alt="drawing" height="50"/>](https://www.circadianrisk.com/) [<img src="https://i.imgur.com/PXo25um.png" alt="drawing" height="50"/>](https://www.circadianrisk.com/)
[<img src="https://i.imgur.com/AKGhtlh.png" alt="drawing"/>](https://lexense.com/) [<img src="https://i.imgur.com/AKGhtlh.png" alt="drawing"/>](https://lexense.com/)
[<img src="https://i.imgur.com/9tqJaHw.png" alt="drawing" height="50"/>](https://novelpad.co/) [<img src="https://i.imgur.com/9tqJaHw.png" alt="drawing" height="50"/>](https://novelpad.co/)
[<img src="https://i.imgur.com/5bLKFeP.png" alt="drawing" height="50"/>](https://proton.me/)
...and many more! ...and many more!
@ -120,5 +114,3 @@ Made with 💖
[patreon-url]: https://www.patreon.com/dolanmiu [patreon-url]: https://www.patreon.com/dolanmiu
[browserstack-image]: https://user-images.githubusercontent.com/2917613/54233552-128e9d00-4505-11e9-88fb-025a4e04007c.png [browserstack-image]: https://user-images.githubusercontent.com/2917613/54233552-128e9d00-4505-11e9-88fb-025a4e04007c.png
[browserstack-url]: https://www.browserstack.com [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,24 +0,0 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 9.0.x | :white_check_mark: |
## Reporting a Vulnerability
We encourage responsible disclosure of security vulnerabilities. If you believe you have found a security vulnerability in this project, please report it via the [Security Tab](https://github.com/dolanmiu/docx/security/advisories)
Please include the following information in your report:
* A description of the vulnerability
* Steps to reproduce the vulnerability
* Impact of the vulnerability
We will investigate all reported vulnerabilities and take appropriate action.
We appreciate your help in keeping this project secure.

View File

@ -3,6 +3,142 @@
import * as fs from "fs"; import * as fs from "fs";
import { AlignmentType, Document, Footer, Header, Packer, PageBreak, PageNumber, Paragraph, TextRun } from "docx"; import { AlignmentType, Document, Footer, Header, Packer, PageBreak, PageNumber, Paragraph, TextRun } from "docx";
// cspell: disable
const createLoremIpsumParagraphs = () => [
new Paragraph(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam accumsan condimentum elit ut placerat. Integer vitae justo est. Quisque tempus augue eu diam pulvinar aliquam. Pellentesque neque sem, posuere eget augue pretium, feugiat mattis diam. Mauris libero arcu, elementum sit amet nunc sed, vestibulum posuere sapien. Nullam",
),
new Paragraph(
"ultrices efficitur magna et commodo. Morbi vitae dolor vulputate, dapibus ipsum in, finibus enim. Aliquam dapibus tellus libero. Nullam nulla eros, ullamcorper eu risus at, luctus aliquet nunc. Nunc dictum turpis eu quam suscipit porta. In rutrum scelerisque nunc in consectetur. Pellentesque ut nibh eget neque congue auctor. Nunc dapibus massa elit, vel cursus metus condimentum et. Nunc venenatis dolor eu lobortis fringilla. Nulla sed risus id lectus scelerisque sollicitudin. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.",
),
new Paragraph(
"Nulla lobortis et purus convallis ullamcorper. Nunc scelerisque, urna eu vestibulum feugiat, orci turpis pulvinar odio, vitae faucibus elit tortor et urna. Curabitur eros mauris, mollis a vestibulum nec, vestibulum sed velit. Nam semper metus ut felis ultricies rutrum. Cras hendrerit eros vel placerat vulputate. Proin placerat ",
),
new Paragraph(
"mollis lacus a ultricies. Mauris vel turpis vitae purus suscipit dignissim. Donec egestas molestie libero in suscipit. Aenean auctor tellus convallis eros porttitor, id vehicula risus commodo. Sed accumsan turpis elit, eget molestie tortor efficitur eget. Aliquam ut lectus quis augue pellentesque tincidunt id id quam. Maecenas auctor, lorem eu ornare tempor, lacus metus ultrices turpis, nec feugiat nibh purus id justo.",
),
new Paragraph(
"Sed semper feugiat ante, sit amet accumsan lorem vulputate vel. Morbi interdum, mauris sit amet efficitur mattis, nunc sapien tempor ante, eget maximus ipsum arcu quis dolor. Suspendisse id consequat justo, quis sollicitudin nisi. Duis euismod, velit non faucibus placerat, eros sem fermentum lectus, ut egestas nisi ipsum eget mi. ",
),
new Paragraph(
"Donec vitae mollis libero. Etiam magna leo, auctor sit amet nibh sit amet, interdum finibus nunc. Quisque a pellentesque velit, a laoreet ante.",
),
new Paragraph(
"Quisque fringilla orci quis dui facilisis, quis auctor urna cursus. Mauris eget justo lacus. Integer placerat, leo vitae ullamcorper varius, nulla mauris gravida massa, ac dignissim odio erat eu ante. Duis non dui semper, eleifend neque nec, ultricies ligula. Sed nec sem nec dolor ultrices finibus. Praesent rutrum iaculis mollis. ",
),
new Paragraph(
"Fusce accumsan dui tortor, quis feugiat urna efficitur sed. Fusce viverra tristique lacinia. Sed nec faucibus ipsum, vel pulvinar ligula. Curabitur ut viverra nisl. Nulla nisi tortor, imperdiet et ipsum sit amet, egestas lacinia leo. Quisque interdum mauris non nunc egestas tempor a vehicula diam. Vestibulum convallis quam sit amet tincidunt posuere. Mauris velit sem, fermentum a diam sit amet, pulvinar iaculis lectus. In dolor turpis, cursus id libero sit amet, aliquet ullamcorper urna. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.",
),
new Paragraph(
"Etiam tincidunt euismod nisi, ut dignissim neque blandit sit amet. Etiam vel velit rhoncus, tincidunt diam quis, dignissim felis. Integer dolor urna, rutrum vitae ultricies ut, sagittis quis felis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec pharetra aliquam augue. Donec ",
),
new Paragraph(
"imperdiet placerat augue, nec consequat leo placerat a. Mauris accumsan ornare massa vitae volutpat. Sed commodo purus ac fringilla ultricies. Donec quis urna hendrerit dolor efficitur sollicitudin. Pellentesque diam arcu, dapibus a nisl pretium, auctor lobortis augue.",
),
new Paragraph(
"Aliquam libero lorem, scelerisque a volutpat ac, venenatis eu nisl. Maecenas turpis diam, consequat eget elementum eget, venenatis at lacus. In maximus erat magna, ut hendrerit erat malesuada vel. Suspendisse iaculis, lacus posuere convallis gravida, nisi purus blandit nunc, imperdiet tempor nunc turpis et sapien. Duis euismod id ",
),
new Paragraph(
"ligula ac laoreet. Ut facilisis massa quis turpis imperdiet, eu ornare lorem placerat. Vestibulum pharetra feugiat eleifend. Quisque ornare pretium urna, lacinia aliquam eros placerat et. Integer sit amet auctor ipsum. Morbi imperdiet dictum ex sed lacinia. Curabitur interdum mattis nunc non vestibulum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Pellentesque odio libero, viverra ac quam eleifend, dignissim euismod nibh. Etiam sit amet semper ante. Morbi in tellus lacinia, bibendum dolor quis, viverra nisi. Proin condimentum purus ipsum, et accumsan sapien finibus ac.",
),
new Paragraph(
"Maecenas congue in leo id faucibus. Etiam porta dapibus ultricies. Nunc ac volutpat magna. Nam pretium dolor ac ultrices tincidunt. Vestibulum pharetra elit vitae lacus pharetra euismod. Pellentesque fringilla lacus ac neque varius sagittis. Mauris tincidunt rutrum velit. Etiam pretium est vitae lacus ultricies, vitae viverra ",
),
new Paragraph(
"turpis auctor. Nulla at lectus pellentesque enim dapibus aliquet eleifend et quam. Suspendisse cursus sed velit et lobortis. Integer sed facilisis ligula, ultrices molestie neque. Nulla porta mauris vitae quam consequat, eget fringilla enim luctus. Integer vitae rhoncus nibh, ac ornare ligula. Sed sed placerat libero. Suspendisse laoreet erat lacus, et lacinia nibh maximus in. Maecenas vitae enim at urna gravida euismod.",
),
new Paragraph(
"Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam lacinia lobortis tortor mollis venenatis. Sed sodales iaculis justo in rhoncus. Proin orci sapien, fermentum nec eleifend in, tristique vel mi. Donec vitae ornare justo, sed rhoncus nibh. Quisque a interdum est, in scelerisque odio. Ut luctus eget ex non ",
),
new Paragraph(
"fringilla. Morbi nec iaculis nisi. Donec porta libero ac ex sollicitudin, vitae interdum erat faucibus. Donec ornare, arcu ullamcorper pretium euismod, nibh nisi consectetur justo, ac aliquet sem eros non nibh. Nulla vitae elementum arcu. Aenean ut consectetur dui. Donec posuere condimentum velit ac hendrerit. Sed aliquet aliquet mi, sed rutrum justo ultrices eget.",
),
new Paragraph(
"Donec volutpat libero dui, ac bibendum nunc eleifend a. Fusce ultricies ligula non sollicitudin lobortis. Integer sit amet elit sapien. Morbi rhoncus bibendum nibh et facilisis. Etiam consectetur elementum sem non elementum. Nunc rutrum sagittis ipsum non sodales. Orci varius natoque penatibus et magnis dis parturient montes, ",
),
new Paragraph(
"nascetur ridiculus mus. Quisque porttitor nulla ultrices mollis porta. Cras non metus sed quam rutrum ultricies. Curabitur aliquet in sem eget auctor. Ut sodales quis leo bibendum venenatis. Etiam pellentesque eros ut metus dignissim commodo. Aliquam vitae sem gravida, convallis ipsum at, imperdiet tellus. Pellentesque consectetur odio sit amet sapien vestibulum aliquam nec id libero. Proin a maximus felis. Aenean molestie vulputate massa, eu eleifend sem consequat id.",
),
new Paragraph(
"Etiam quis ante nec leo faucibus dignissim eu at mi. Nam nec ligula nec sapien rhoncus faucibus. Fusce vestibulum orci libero, vel commodo est congue iaculis. In hac habitasse platea dictumst. Sed lacinia magna eu arcu commodo pretium. Fusce id elementum enim. Mauris tristique tortor dolor, at pretium magna tempor nec. Vivamus non ",
),
new Paragraph(
"dui sit amet odio porttitor tincidunt. Nam pulvinar aliquet tortor tristique tempor. Duis finibus tincidunt elit, at viverra justo sagittis in. Morbi pellentesque gravida mi, in pulvinar metus molestie at. Fusce bibendum eleifend sapien a fermentum. Nam efficitur tellus dignissim, vehicula tortor ac, tristique enim. Aliquam pretium dui interdum varius elementum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Donec a finibus elit.",
),
new Paragraph(
"Phasellus cursus tortor at justo bibendum aliquam. Sed nec hendrerit nibh, eu finibus tortor. Aenean sit amet dui rutrum, sollicitudin justo eu, condimentum ipsum. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Maecenas dictum neque lacus, vel posuere eros pretium nec. Morbi ac ante at ",
),
new Paragraph(
"ex semper ultricies ac quis augue. In hac habitasse platea dictumst. Mauris laoreet porta nisl. Sed augue lorem, aliquet in volutpat ut, rhoncus eget nibh. Sed rhoncus arcu diam, accumsan rhoncus sem iaculis ac. Duis dolor magna, semper et tellus non, condimentum volutpat nisi. Donec eget metus eget elit eleifend vestibulum et ut purus.",
),
new Paragraph(
"Nam a dui accumsan, efficitur ex at, commodo eros. Pellentesque sit amet nunc ac odio egestas suscipit id sodales ligula. Duis non mi vitae mi mollis fringilla at sit amet sem. Morbi laoreet mattis dolor sit amet tincidunt. Aliquam erat volutpat. Pellentesque porta sem odio, at lobortis quam commodo vitae. Curabitur ut urna dolor.",
),
new Paragraph(
"Nulla vitae pretium ex. Nulla facilisi. Vestibulum placerat odio eget enim ultrices, et imperdiet tellus consequat. Sed dignissim, erat ut dignissim interdum, dui mi rhoncus nunc, id rhoncus turpis nunc eu risus. Mauris leo orci, euismod sit amet velit ac, condimentum dictum dui. Cras cursus dolor augue, et vestibulum lorem ",
),
new Paragraph(
"fringilla in. Nulla fermentum odio vehicula justo placerat, et aliquet velit vulputate. Sed aliquam auctor dictum. Phasellus sit amet sollicitudin elit. Cras eget gravida ex. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Duis tortor erat, ornare id feugiat eget, pellentesque at lectus. Sed vitae nisi ullamcorper, tincidunt augue vitae, accumsan ligula. Curabitur ut lobortis lacus, imperdiet placerat arcu.",
),
new Paragraph(
"Sed vestibulum tempor nulla vel dignissim. Phasellus imperdiet, dolor nec mollis tempor, nulla nibh pretium nibh, nec elementum lacus neque in sapien. Nam et eleifend lorem. Nam pretium molestie enim quis porta. Proin eu pharetra enim. Etiam a velit eget augue congue tempor. Interdum et malesuada fames ac ante ipsum primis in ",
),
new Paragraph("faucibus. Sed urna tellus, euismod ac pharetra nec, ultrices vel nisi."),
new Paragraph(
"Phasellus at arcu eget tellus mattis ultricies non quis urna. Vestibulum non eros fringilla, porttitor massa id, ornare metus. Quisque lacinia, massa a ornare vulputate, ex lectus ullamcorper ligula, eget facilisis mi turpis at dolor. Curabitur posuere elementum enim, non placerat tortor tincidunt sit amet. Pellentesque habitant ",
),
new Paragraph(
"morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nam fermentum ut felis et dapibus. Ut consectetur finibus bibendum. Phasellus semper sapien neque, nec consequat nibh convallis et. Nunc nec egestas enim. Nulla facilisi.",
),
new Paragraph(
"Quisque sed nibh sed lorem placerat ornare sed nec sapien. Morbi et risus vitae magna varius varius eget at leo. Curabitur a eleifend elit. Mauris augue nulla, convallis vel ante in, consequat feugiat orci. Donec sagittis risus nibh, eget porta purus faucibus non. Curabitur ultrices, ex et placerat rutrum, velit odio accumsan ",
),
new Paragraph(
"nulla, et elementum mi leo in velit. Pellentesque auctor egestas ultricies. In viverra est a mauris sollicitudin, a laoreet augue cursus. Vestibulum non sollicitudin massa. Curabitur ac tellus metus. Pellentesque hendrerit dolor sed mi vestibulum imperdiet. Nulla vitae odio ultrices, tempor enim sed, vestibulum eros. Cras libero ex, malesuada nec porttitor sit amet, efficitur sit amet ligula.",
),
new Paragraph(
"Morbi pellentesque tempus felis, id iaculis quam euismod non. Sed scelerisque id massa eu elementum. Vestibulum id malesuada arcu. Maecenas eget placerat sem, at consectetur orci. Nullam interdum erat urna, ac rhoncus odio feugiat sed. Morbi rutrum auctor sem eget pulvinar. Suspendisse egestas tempor volutpat.",
),
new Paragraph(
"Vivamus euismod, sem eget molestie rhoncus, metus dui laoreet lacus, et lobortis est metus ut felis. Aenean imperdiet lacus nunc, vitae molestie orci ultrices nec. Cras egestas maximus diam, vitae efficitur nisl luctus imperdiet. Nulla pellentesque sodales ante, nec facilisis turpis. Vivamus at hendrerit enim, ac dictum lorem. Cras ",
),
new Paragraph(
"congue accumsan dui, non pretium sem auctor quis. Nunc a mauris vehicula, elementum ex vitae, sollicitudin eros. Nunc non sapien vitae justo sodales condimentum. Praesent nisl felis, tristique ac odio at, rhoncus porttitor orci. Morbi egestas placerat iaculis.",
),
new Paragraph(
"Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In at lorem nec neque faucibus ultricies ut in ipsum.",
),
new Paragraph(
"Suspendisse fermentum feugiat augue eu convallis. Maecenas eros velit, efficitur sit amet posuere sed, tristique sit amet nisi. Donec vel convallis justo, id tempor neque. Nunc pulvinar maximus nulla, vitae congue lacus cursus ut. Morbi at mollis est, a vehicula nisi. Cras venenatis nibh vel massa interdum commodo. Nulla mattis ",
),
new Paragraph(
"neque sed sem bibendum, iaculis hendrerit neque fringilla. Sed a lobortis orci. Morbi in est sed libero vestibulum semper. Suspendisse potenti. Aliquam pretium erat tellus, in suscipit lorem aliquet iaculis. Aenean ac viverra ipsum. Sed at diam luctus, pharetra lorem vel, aliquam magna. Donec mollis orci eget enim efficitur ultricies. Proin neque diam, dignissim euismod ex vel, sollicitudin sodales sapien.",
),
new Paragraph(
"Sed a egestas nunc, a ullamcorper est. Aenean vulputate fringilla justo non vestibulum. Donec ac dolor in nisl finibus tristique. Donec sed turpis at felis congue porttitor sed sit amet metus. In in ex nulla. Donec sodales vel velit ut congue. Nullam vitae egestas purus. Vivamus non mi consequat, molestie enim nec, hendrerit mi.",
),
];
// cspell: enable
const doc = new Document({ const doc = new Document({
sections: [ sections: [
{ {
@ -49,6 +185,19 @@ const doc = new Document({
}), }),
], ],
}), }),
new Paragraph({
alignment: AlignmentType.RIGHT,
children: [
new TextRun({
children: [
"Footer - Page in section ",
PageNumber.CURRENT_SECTION,
" of ",
PageNumber.TOTAL_PAGES_IN_SECTION,
],
}),
],
}),
], ],
}), }),
first: new Footer({ first: new Footer({
@ -70,6 +219,96 @@ const doc = new Document({
children: [new TextRun("First Page"), new PageBreak()], children: [new TextRun("First Page"), new PageBreak()],
}), }),
new Paragraph("Second Page"), new Paragraph("Second Page"),
...createLoremIpsumParagraphs(),
new Paragraph({
children: [new TextRun("Next Page"), new PageBreak()],
}),
...createLoremIpsumParagraphs(),
],
},
{
properties: {
titlePage: true,
},
headers: {
default: new Header({
children: [
new Paragraph({
alignment: AlignmentType.RIGHT,
children: [
new TextRun("My Title "),
new TextRun({
children: ["Page ", PageNumber.CURRENT],
}),
],
}),
],
}),
first: new Header({
children: [
new Paragraph({
alignment: AlignmentType.RIGHT,
children: [
new TextRun("First Page Header "),
new TextRun({
children: ["Page ", PageNumber.CURRENT],
}),
],
}),
],
}),
},
footers: {
default: new Footer({
children: [
new Paragraph({
alignment: AlignmentType.RIGHT,
children: [
new TextRun("My Title "),
new TextRun({
children: ["Footer - Page ", PageNumber.CURRENT, " of ", PageNumber.TOTAL_PAGES],
}),
],
}),
new Paragraph({
alignment: AlignmentType.RIGHT,
children: [
new TextRun({
children: [
"Footer - Page in section ",
PageNumber.CURRENT_SECTION,
" of ",
PageNumber.TOTAL_PAGES_IN_SECTION,
],
}),
],
}),
],
}),
first: new Footer({
children: [
new Paragraph({
alignment: AlignmentType.RIGHT,
children: [
new TextRun("First Page Footer "),
new TextRun({
children: ["Page ", PageNumber.CURRENT],
}),
],
}),
],
}),
},
children: [
new Paragraph({
children: [new TextRun("First Page"), new PageBreak()],
}),
new Paragraph("Second Page"),
...createLoremIpsumParagraphs(),
new Paragraph({
children: [new TextRun("Next Page"), new PageBreak()],
}),
...createLoremIpsumParagraphs(),
], ],
}, },
], ],

View File

@ -1,7 +1,7 @@
// Example of how you would create a table and add data to it // Example of how you would create a table and add data to it
import * as fs from "fs"; import * as fs from "fs";
import { Document, HeadingLevel, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign, TextDirection } from "docx"; import { BorderStyle, Document, HeadingLevel, Packer, Paragraph, Table, TableCell, TableRow, VerticalAlign, TextDirection } from "docx";
const doc = new Document({ const doc = new Document({
sections: [ sections: [
@ -67,6 +67,173 @@ const doc = new Document({
}), }),
], ],
}), }),
new Paragraph("Table with borders"),
new Table({
rows: [
new TableRow({
children: [
new TableCell({
borders: {
top: {
style: BorderStyle.DASH_SMALL_GAP,
size: 1,
color: "000000",
},
bottom: {
style: BorderStyle.DASH_SMALL_GAP,
size: 1,
color: "000000",
},
left: {
style: BorderStyle.DASH_SMALL_GAP,
size: 1,
color: "000000",
},
right: {
style: BorderStyle.DASH_SMALL_GAP,
size: 1,
color: "000000",
},
},
children: [new Paragraph("Dash small gap border")],
}),
new TableCell({
borders: {
top: {
style: BorderStyle.DASH_SMALL_GAP,
size: 1,
color: "000000",
},
bottom: {
style: BorderStyle.DASH_SMALL_GAP,
size: 1,
color: "000000",
},
left: {
style: BorderStyle.DASH_SMALL_GAP,
size: 1,
color: "000000",
},
right: {
style: BorderStyle.DASH_SMALL_GAP,
size: 1,
color: "000000",
},
},
children: [new Paragraph("Dash small gap border")],
}),
],
}),
new TableRow({
children: [
new TableCell({
borders: {
top: {
style: BorderStyle.DOUBLE,
size: 1,
color: "ff0000",
},
bottom: {
style: BorderStyle.DOUBLE,
size: 1,
color: "ff0000",
},
left: {
style: BorderStyle.DOUBLE,
size: 1,
color: "ff0000",
},
right: {
style: BorderStyle.DOUBLE,
size: 1,
color: "ff0000",
},
},
children: [new Paragraph("Double border")],
}),
new TableCell({
borders: {
top: {
style: BorderStyle.DOUBLE,
size: 1,
color: "ff0000",
},
bottom: {
style: BorderStyle.DOUBLE,
size: 1,
color: "ff0000",
},
left: {
style: BorderStyle.DOUBLE,
size: 1,
color: "ff0000",
},
right: {
style: BorderStyle.DOUBLE,
size: 1,
color: "ff0000",
},
},
children: [new Paragraph("Double border")],
}),
],
}),
new TableRow({
children: [
new TableCell({
borders: {
top: {
style: BorderStyle.NONE,
size: 0,
color: "ffffff",
},
bottom: {
style: BorderStyle.NONE,
size: 0,
color: "ffffff",
},
left: {
style: BorderStyle.NONE,
size: 0,
color: "ffffff",
},
right: {
style: BorderStyle.NONE,
size: 0,
color: "ffffff",
},
},
children: [new Paragraph("Should have no border")],
}),
new TableCell({
borders: {
top: {
style: BorderStyle.NONE,
size: 0,
color: "ffffff",
},
bottom: {
style: BorderStyle.NONE,
size: 0,
color: "ffffff",
},
left: {
style: BorderStyle.NONE,
size: 0,
color: "ffffff",
},
right: {
style: BorderStyle.NONE,
size: 0,
color: "ffffff",
},
},
children: [new Paragraph("Should have no border")],
}),
],
}),
],
}),
], ],
}, },
], ],

View File

@ -21,7 +21,6 @@ const doc = new Document({
new Paragraph({ new Paragraph({
children: [ children: [
new ImageRun({ new ImageRun({
type: "jpg",
data: fs.readFileSync("./demo/images/image1.jpeg"), data: fs.readFileSync("./demo/images/image1.jpeg"),
transformation: { transformation: {
width: 100, width: 100,
@ -38,7 +37,6 @@ const doc = new Document({
new Paragraph({ new Paragraph({
children: [ children: [
new ImageRun({ new ImageRun({
type: "png",
data: fs.readFileSync("./demo/images/dog.png").toString("base64"), data: fs.readFileSync("./demo/images/dog.png").toString("base64"),
transformation: { transformation: {
width: 100, width: 100,
@ -55,7 +53,6 @@ const doc = new Document({
new Paragraph({ new Paragraph({
children: [ children: [
new ImageRun({ new ImageRun({
type: "jpg",
data: fs.readFileSync("./demo/images/cat.jpg"), data: fs.readFileSync("./demo/images/cat.jpg"),
transformation: { transformation: {
width: 100, width: 100,
@ -76,7 +73,6 @@ const doc = new Document({
new Paragraph({ new Paragraph({
children: [ children: [
new ImageRun({ new ImageRun({
type: "bmp",
data: fs.readFileSync("./demo/images/parrots.bmp"), data: fs.readFileSync("./demo/images/parrots.bmp"),
transformation: { transformation: {
width: 150, width: 150,
@ -92,7 +88,6 @@ const doc = new Document({
new Paragraph({ new Paragraph({
children: [ children: [
new ImageRun({ new ImageRun({
type: "gif",
data: fs.readFileSync("./demo/images/pizza.gif"), data: fs.readFileSync("./demo/images/pizza.gif"),
transformation: { transformation: {
width: 200, width: 200,
@ -108,7 +103,6 @@ const doc = new Document({
new Paragraph({ new Paragraph({
children: [ children: [
new ImageRun({ new ImageRun({
type: "gif",
data: fs.readFileSync("./demo/images/pizza.gif"), data: fs.readFileSync("./demo/images/pizza.gif"),
transformation: { transformation: {
width: 200, width: 200,
@ -130,7 +124,6 @@ const doc = new Document({
new Paragraph({ new Paragraph({
children: [ children: [
new ImageRun({ new ImageRun({
type: "jpg",
data: fs.readFileSync("./demo/images/cat.jpg"), data: fs.readFileSync("./demo/images/cat.jpg"),
transformation: { transformation: {
width: 200, width: 200,
@ -150,22 +143,6 @@ const doc = new Document({
}), }),
], ],
}), }),
new Paragraph({
children: [
new ImageRun({
type: "svg",
data: fs.readFileSync("./demo/images/linux-svg.svg"),
transformation: {
width: 200,
height: 200,
},
fallback: {
type: "png",
data: fs.readFileSync("./demo/images/linux-png.png"),
},
}),
],
}),
], ],
}, },
], ],

View File

@ -21,8 +21,6 @@ import {
Packer, Packer,
Paragraph, Paragraph,
TextRun, TextRun,
MathLimitLower,
MathLimitUpper,
} from "docx"; } from "docx";
const doc = new Document({ const doc = new Document({
@ -318,23 +316,6 @@ const doc = new Document({
}), }),
], ],
}), }),
new Paragraph({
children: [
new Math({
children: [
new MathLimitUpper({
children: [new MathRun("x")],
limit: [new MathRun("-")],
}),
new MathRun("="),
new MathLimitLower({
children: [new MathRun("lim")],
limit: [new MathRun("x→0")],
}),
],
}),
],
}),
], ],
}, },
], ],

View File

@ -2,7 +2,6 @@
import * as fs from "fs"; import * as fs from "fs";
import { import {
AlignmentType,
BorderStyle, BorderStyle,
Document, Document,
FrameAnchorType, FrameAnchorType,
@ -21,7 +20,6 @@ const doc = new Document({
children: [ children: [
new Paragraph({ new Paragraph({
frame: { frame: {
type: "absolute",
position: { position: {
x: 1000, x: 1000,
y: 3000, y: 3000,
@ -32,54 +30,6 @@ const doc = new Document({
horizontal: FrameAnchorType.MARGIN, horizontal: FrameAnchorType.MARGIN,
vertical: FrameAnchorType.MARGIN, vertical: FrameAnchorType.MARGIN,
}, },
},
border: {
top: {
color: "auto",
space: 1,
style: BorderStyle.SINGLE,
size: 6,
},
bottom: {
color: "auto",
space: 1,
style: BorderStyle.SINGLE,
size: 6,
},
left: {
color: "auto",
space: 1,
style: BorderStyle.SINGLE,
size: 6,
},
right: {
color: "auto",
space: 1,
style: BorderStyle.SINGLE,
size: 6,
},
},
children: [
new TextRun("Hello World"),
new TextRun({
text: "Foo Bar",
bold: true,
}),
new TextRun({
children: [new Tab(), "Github is the best"],
bold: true,
}),
],
}),
new Paragraph({
frame: {
type: "alignment",
width: 4000,
height: 1000,
anchor: {
horizontal: FrameAnchorType.MARGIN,
vertical: FrameAnchorType.MARGIN,
},
alignment: { alignment: {
x: HorizontalPositionAlign.CENTER, x: HorizontalPositionAlign.CENTER,
y: VerticalPositionAlign.TOP, y: VerticalPositionAlign.TOP,
@ -123,59 +73,6 @@ const doc = new Document({
}), }),
], ],
}), }),
new Paragraph({
frame: {
type: "alignment",
width: 4000,
height: 1000,
anchor: {
horizontal: FrameAnchorType.MARGIN,
vertical: FrameAnchorType.MARGIN,
},
alignment: {
x: HorizontalPositionAlign.CENTER,
y: VerticalPositionAlign.BOTTOM,
},
},
border: {
top: {
color: "auto",
space: 1,
style: BorderStyle.SINGLE,
size: 6,
},
bottom: {
color: "auto",
space: 1,
style: BorderStyle.SINGLE,
size: 6,
},
left: {
color: "auto",
space: 1,
style: BorderStyle.SINGLE,
size: 6,
},
right: {
color: "auto",
space: 1,
style: BorderStyle.SINGLE,
size: 6,
},
},
alignment: AlignmentType.RIGHT,
children: [
new TextRun("Hello World"),
new TextRun({
text: "Foo Bar",
bold: true,
}),
new TextRun({
children: [new Tab(), "Github is the best"],
bold: true,
}),
],
}),
], ],
}, },
], ],

View File

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

View File

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

View File

@ -16,9 +16,7 @@ import {
VerticalAlign, VerticalAlign,
} from "docx"; } from "docx";
patchDocument({ patchDocument(fs.readFileSync("demo/assets/simple-template.docx"), {
outputType: "nodebuffer",
data: fs.readFileSync("demo/assets/simple-template.docx"),
patches: { patches: {
name: { name: {
type: PatchType.PARAGRAPH, type: PatchType.PARAGRAPH,
@ -58,11 +56,7 @@ patchDocument({
], ],
link: "https://www.google.co.uk", link: "https://www.google.co.uk",
}), }),
new ImageRun({ new ImageRun({ data: fs.readFileSync("./demo/images/dog.png"), transformation: { width: 100, height: 100 } }),
type: "png",
data: fs.readFileSync("./demo/images/dog.png"),
transformation: { width: 100, height: 100 },
}),
], ],
}), }),
], ],
@ -88,13 +82,7 @@ patchDocument({
}, },
image_test: { image_test: {
type: PatchType.PARAGRAPH, type: PatchType.PARAGRAPH,
children: [ children: [new ImageRun({ data: fs.readFileSync("./demo/images/image1.jpeg"), transformation: { width: 100, height: 100 } })],
new ImageRun({
type: "jpg",
data: fs.readFileSync("./demo/images/image1.jpeg"),
transformation: { width: 100, height: 100 },
}),
],
}, },
table: { table: {
type: PatchType.DOCUMENT, type: PatchType.DOCUMENT,

View File

@ -3,9 +3,7 @@
import * as fs from "fs"; import * as fs from "fs";
import { patchDocument, PatchType, TextRun } from "docx"; import { patchDocument, PatchType, TextRun } from "docx";
patchDocument({ patchDocument(fs.readFileSync("demo/assets/simple-template-2.docx"), {
outputType: "nodebuffer",
data: fs.readFileSync("demo/assets/simple-template-2.docx"),
patches: { patches: {
name: { name: {
type: PatchType.PARAGRAPH, type: PatchType.PARAGRAPH,

View File

@ -24,9 +24,7 @@ const patches = getPatches({
paragraph_replace: "Lorem ipsum paragraph", paragraph_replace: "Lorem ipsum paragraph",
}); });
patchDocument({ patchDocument(fs.readFileSync("demo/assets/simple-template.docx"), {
outputType: "nodebuffer",
data: fs.readFileSync("demo/assets/simple-template.docx"),
patches, patches,
}).then((doc) => { }).then((doc) => {
fs.writeFileSync("My Document.docx", doc); fs.writeFileSync("My Document.docx", doc);

View File

@ -22,11 +22,8 @@ const patches = getPatches({
"first-name": "John", "first-name": "John",
}); });
patchDocument({ patchDocument(fs.readFileSync("demo/assets/simple-template-3.docx"), {
outputType: "nodebuffer",
data: fs.readFileSync("demo/assets/simple-template-3.docx"),
patches, patches,
keepOriginalStyles: true,
}).then((doc) => { }).then((doc) => {
fs.writeFileSync("My Document.docx", doc); fs.writeFileSync("My Document.docx", doc);
}); });

View File

@ -1,40 +0,0 @@
// Simple example to add text to a document
import * as fs from "fs";
import { CharacterSet, Document, Packer, Paragraph, Tab, TextRun } from "docx";
const font = fs.readFileSync("./demo/assets/Pacifico.ttf");
const doc = new Document({
sections: [
{
properties: {},
children: [
new Paragraph({
run: {
font: "Pacifico",
},
children: [
new TextRun("Hello World"),
new TextRun({
text: "Foo Bar",
bold: true,
size: 40,
font: "Pacifico",
}),
new TextRun({
children: [new Tab(), "Github is the best"],
bold: true,
font: "Pacifico",
}),
],
}),
],
},
],
fonts: [{ name: "Pacifico", data: font, characterSet: CharacterSet.ANSI }],
});
Packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,44 +0,0 @@
// Simple example to add text to a document
import * as fs from "fs";
import { Document, Packer, Paragraph, Tab, TextRun } from "docx";
const font = fs.readFileSync("./demo/assets/Pacifico.ttf");
const doc = new Document({
styles: {
default: {
document: {
run: {
font: "Pacifico",
},
},
},
},
sections: [
{
properties: {},
children: [
new Paragraph({
children: [
new TextRun("Hello World"),
new TextRun({
text: "Foo Bar",
bold: true,
size: 40,
}),
new TextRun({
children: [new Tab(), "Github is the best"],
bold: true,
}),
],
}),
],
},
],
fonts: [{ name: "Pacifico", data: font, characterSet: "00" }],
});
Packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,72 +0,0 @@
// Patch a document with patches
import * as fs from "fs";
import { patchDocument, PatchType, TextRun } from "docx";
patchDocument({
outputType: "nodebuffer",
data: fs.readFileSync("demo/assets/field-trip.docx"),
patches: {
todays_date: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: new Date().toLocaleDateString() })],
},
school_name: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
address: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "blah blah" })],
},
city: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
state: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
zip: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
phone: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
first_name: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
last_name: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
email_address: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
ft_dates: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
grade: {
type: PatchType.PARAGRAPH,
children: [new TextRun({ text: "test" })],
},
},
}).then((doc) => {
fs.writeFileSync("My Document.docx", doc);
});

View File

@ -1,43 +0,0 @@
// Simple example to add textbox to a document
import { Document, Packer, Paragraph, Textbox, TextRun } from "docx";
import * as fs from "fs";
const doc = new Document({
sections: [
{
properties: {},
children: [
new Textbox({
alignment: "center",
children: [
new Paragraph({
children: [new TextRun("Hi i'm a textbox!")],
}),
],
style: {
width: "200pt",
height: "auto",
},
}),
new Textbox({
alignment: "center",
children: [
new Paragraph({
children: [new TextRun("Hi i'm a textbox with a hidden box!")],
}),
],
style: {
width: "300pt",
height: 400,
visibility: "hidden",
zIndex: "auto",
},
}),
],
},
],
});
Packer.toBuffer(doc).then((buffer) => {
fs.writeFileSync("My Document.docx", buffer);
});

View File

@ -1,60 +0,0 @@
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

@ -1,168 +0,0 @@
// Patch a document with patches
import * as fs from "fs";
import {
ExternalHyperlink,
HeadingLevel,
ImageRun,
Paragraph,
patchDocument,
PatchType,
Table,
TableCell,
TableRow,
TextDirection,
TextRun,
VerticalAlign,
} 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: VerticalAlign.CENTER,
}),
new TableCell({
children: [new Paragraph({}), new Paragraph({})],
verticalAlign: VerticalAlign.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: VerticalAlign.CENTER,
}),
new TableCell({
children: [
new Paragraph({
text: "Text above should be vertical from bottom to top",
}),
],
verticalAlign: VerticalAlign.CENTER,
}),
new TableCell({
children: [
new Paragraph({
text: "Text above should be vertical from top to bottom",
}),
],
verticalAlign: VerticalAlign.CENTER,
}),
],
}),
],
}),
],
},
},
placeholderDelimiters: { start: "<<", end: ">>" },
}).then((doc) => {
fs.writeFileSync("My Document.docx", doc);
});

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

View File

@ -1,183 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="500pt" height="600pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://web.resource.org/cc/">
<defs>
<linearGradient id="linearGradient172">
<stop style="stop-color:#3f2600;stop-opacity:0.6;" offset="0" id="stop173" />
<stop style="stop-color:#3f2600;stop-opacity:0;" offset="1" id="stop174" />
</linearGradient>
<linearGradient id="linearGradient167">
<stop style="stop-color:#ffffff;stop-opacity:0.65;" offset="0" id="stop168" />
<stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop169" />
</linearGradient>
<linearGradient id="linearGradient162">
<stop style="stop-color:#ffa63f;stop-opacity:1;" offset="0" id="stop163" />
<stop style="stop-color:#ffff00;stop-opacity:1;" offset="1" id="stop164" />
</linearGradient>
<linearGradient id="linearGradient153">
<stop style="stop-color:#ffeed7;stop-opacity:1;" offset="0" id="stop154" />
<stop style="stop-color:#bdbfc2;stop-opacity:1;" offset="1" id="stop155" /></linearGradient>
<linearGradient id="linearGradient138">
<stop style="stop-color:#ffffff;stop-opacity:0.8;" offset="0" id="stop139" />
<stop style="stop-color:#ffffff;stop-opacity:0;" offset="1" id="stop140" />
</linearGradient>
<linearGradient xlink:href="#linearGradient138" id="linearGradient141" x1="0.47424799" y1="0.020191999" x2="0.417539" y2="0.90125799" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient142" x1="0.55880702" y1="0.031192999" x2="0.553922" y2="0.94531101" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient143" x1="0.46557701" y1="0.028819799" x2="0.41365999" y2="0.93366498" gradientUnits="objectBoundingBox"/>
<linearGradient xlink:href="#linearGradient167" id="linearGradient144" x1="0.70346397" y1="0.059404202" x2="0.64553201" y2="0.94063401" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient145" x1="0.46741399" y1="-0.036155298" x2="0.86741799" y2="0.75857902" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient146" x1="0.57152498" y1="0.023441499" x2="0.57143003" y2="0.71875" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient147" x1="0.5" y1="0.0234362" x2="0.5" y2="0.8125" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient148" x1="0.50799799" y1="0.37435901" x2="0.51599997" y2="0.92820501" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient138" id="linearGradient149" x1="0.5" y1="0.131707" x2="0.50400001" y2="0.94634098" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient150" x1="-0.30509499" y1="0.099496603" x2="0.156323" y2="0.94191301" gradientUnits="objectBoundingBox" gradientTransform="matrix(-0.928523,0.283938,0.435332,0.943857,-1.91327e-7,5.49908e-8)" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient151" x1="0.433979" y1="0.022184599" x2="0.487055" y2="1.02569" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient152" x1="0.5" y1="0.89842999" x2="0.5" y2="0.40625" gradientUnits="objectBoundingBox" spreadMethod="reflect" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient156" x1="0.43568701" y1="0.98882002" x2="0.453989" y2="0.23093501" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient157" x1="0.49180499" y1="1.15284" x2="0.49482101" y2="0.41252401" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient158" x1="0.51730198" y1="0.85418499" x2="0.49843901" y2="0.136172" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient159" x1="0.46201" y1="0.87917101" x2="0.49215299" y2="0.096282303" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient162" id="linearGradient161" x1="0.50086302" y1="0.34872901" x2="0.41209599" y2="0.98558098" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient162" id="linearGradient165" x1="0.60399801" y1="0.51020199" x2="0.46399999" y2="0.98367399" gradientUnits="objectBoundingBox" />
<linearGradient xlink:href="#linearGradient162" id="linearGradient166" x1="0.50000501" y1="0.191616" x2="0.50800002" y2="0.97005898" gradientUnits="objectBoundingBox" />
<radialGradient xlink:href="#linearGradient172" id="radialGradient171" cx="0.5" cy="0.5" fx="0.5" fy="0.5" r="0.5" gradientUnits="objectBoundingBox" />
<radialGradient xlink:href="#linearGradient172" id="radialGradient176" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient178" x1="0.94027299" y1="1.2934099" x2="0.19452" y2="-0.675295" gradientUnits="objectBoundingBox" />
<radialGradient xlink:href="#linearGradient172" id="radialGradient1399" gradientTransform="scale(1.045233,0.956725)" cx="446.77762" cy="1219.4125" fx="446.77762" fy="1219.4125" r="195.07191" gradientUnits="userSpaceOnUse" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient1401" gradientUnits="userSpaceOnUse" x1="400.57785" y1="369.53015" x2="400.84448" y2="304.07886" gradientTransform="scale(0.575262,1.738339)" />
<linearGradient xlink:href="#linearGradient138" id="linearGradient1403" gradientUnits="userSpaceOnUse" x1="303.01761" y1="237.93179" x2="297.0856" y2="330.09561" gradientTransform="scale(1.116071,0.896001)" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient1405" gradientUnits="userSpaceOnUse" gradientTransform="scale(0.816497,1.224744)" x1="378.93771" y1="278.60202" x2="380.27319" y2="243.91606" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient1407" gradientUnits="userSpaceOnUse" x1="381.38742" y1="277.495" x2="380.5517" y2="245.68338" gradientTransform="scale(0.816497,1.224744)" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient1409" gradientUnits="userSpaceOnUse" gradientTransform="scale(0.816497,1.224744)" x1="379.09573" y1="240.92712" x2="376.79556" y2="281.01636" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient1411" gradientUnits="userSpaceOnUse" x1="389.63535" y1="242.28218" x2="387.06866" y2="281.32513" gradientTransform="scale(0.816497,1.224744)" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient1413" gradientUnits="userSpaceOnUse" spreadMethod="reflect" x1="437.57941" y1="528.87177" x2="437.57941" y2="394.10361" gradientTransform="scale(0.812855,1.230232)" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient1415" gradientUnits="userSpaceOnUse" x1="375.17325" y1="419.78485" x2="377.48541" y2="324.03815" gradientTransform="scale(0.649784,1.538974)" />
<linearGradient xlink:href="#linearGradient138" id="linearGradient1417" gradientUnits="userSpaceOnUse" x1="320.75104" y1="498.17776" x2="321.32224" y2="614.50439" gradientTransform="scale(1.074798,0.930408)" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient1419" gradientUnits="userSpaceOnUse" x1="322.48257" y1="435.26761" x2="323.2514" y2="488.48251" gradientTransform="scale(1.077001,0.928504)" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient1421" gradientUnits="userSpaceOnUse" x1="411.2215" y1="242.94365" x2="411.2215" y2="331.44858" gradientTransform="scale(0.571707,1.749147)" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient1423" gradientUnits="userSpaceOnUse" x1="867.34546" y1="234.73897" x2="867.33453" y2="314.83911" gradientTransform="scale(0.572667,1.746214)" />
<linearGradient xlink:href="#linearGradient162" id="linearGradient1425" gradientUnits="userSpaceOnUse" x1="236.25362" y1="657.11133" x2="212.5099" y2="737.41229" gradientTransform="scale(1.011514,0.988617)" />
<linearGradient xlink:href="#linearGradient153" id="linearGradient1427" gradientUnits="userSpaceOnUse" x1="381.56607" y1="655.73102" x2="279.64313" y2="386.66583" gradientTransform="scale(1.065499,0.938527)" />
<linearGradient xlink:href="#linearGradient162" id="linearGradient1429" gradientUnits="userSpaceOnUse" x1="218.11714" y1="630.30475" x2="203.12654" y2="737.8537" gradientTransform="scale(1.009851,0.990245)" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient1431" gradientUnits="userSpaceOnUse" gradientTransform="scale(1.007724,0.992335)" x1="117.88966" y1="587.23602" x2="182.24524" y2="704.73077" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient1433" gradientUnits="userSpaceOnUse" x1="223.10072" y1="570.41809" x2="230.53499" y2="710.97723" gradientTransform="scale(0.999504,1.000496)" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient1435" gradientUnits="userSpaceOnUse" x1="316.93988" y1="474.01779" x2="371.60889" y2="582.63507" gradientTransform="scale(1.065499,0.938527)" />
<linearGradient xlink:href="#linearGradient162" id="linearGradient1437" gradientUnits="userSpaceOnUse" x1="284.68652" y1="410.46326" x2="285.45923" y2="485.69934" gradientTransform="scale(1.218684,0.820557)" />
<linearGradient xlink:href="#linearGradient167" id="linearGradient1439" gradientUnits="userSpaceOnUse" x1="288.82358" y1="398.85422" x2="288.37628" y2="482.55939" gradientTransform="scale(1.221941,0.81837)" />
</defs>
<g id="g1369" transform="translate(-310.7524,-64.25268)">
<path transform="matrix(1.4177,0,0,0.414745,-38.7944,222.194)" d="M 670.88202 1166.6423 A 203.89551 186.63016 0 1 1 263.091,1166.6423 A 203.89551 186.63016 0 1 1 670.88202 1166.6423 z" id="path175" style="fill:url(#radialGradient1399);stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter" />
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path106" d="M 223.627,632.24 C 201.239,600.017 196.873,495.256 249.114,430.81 C 275,399.892 281.604,378.345 283.645,349.417 C 285.034,316.438 260.32,217.975 353.528,210.473 C 447.934,202.941 442.864,296.133 442.321,345.448 C 441.87,387.088 472.895,410.689 494.117,443.143 C 533.396,502.773 530.074,605.443 486.718,661.015 C 431.801,730.583 384.765,700.413 353.528,702.945 C 295.035,706.147 293.101,737.336 223.627,632.24 z " style="fill:#000000;stroke:none;stroke-width:1.25;" />
<path transform="matrix(-1.67739,-2.24516e-2,-2.11236e-2,1.4709,1173.58,-293.017)" id="path113" d="M 246.571,470.864 C 234.332,483.36 202.175,539.956 251.44,576.224 C 268.809,588.857 235.063,635.719 219.435,612.532 C 191.865,570.914 210.604,505.591 227.75,482.344 C 239.402,465.857 256.98,459.668 246.571,470.864 z " style="fill:url(#linearGradient1401);stroke:none;stroke-width:0.99464899;" />
<path transform="matrix(-1.67755,0,0,1.52374,1174.62,-318.082)" id="path111" d="M 256.513,459.837 C 236.598,477.554 200.337,539.928 253.225,580.443 C 270.595,593.075 237.832,632.906 219.435,612.532 C 155.472,541.712 221.104,460.278 243.697,432.282 C 263.889,407.935 281.775,438.034 256.513,459.837 z " style="fill:#000000;stroke:#000000;stroke-width:0.97729802;" />
<path transform="matrix(1.26626,-7.13667e-2,-4.59795e-2,1.19574,202.143,-125.761)" d="M 399.56879 258.15753 A 58.37323 46.863022 0 1 1 282.82233,258.15753 A 58.37323 46.863022 0 1 1 399.56879 258.15753 z" id="path114" style="fill:url(#linearGradient1403);stroke:none;stroke-width:1.26498997;" />
<path transform="matrix(1.30445,-7.55326e-2,7.71251e-2,1.34257,144.757,-177.617)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path115" style="fill:url(#linearGradient1405);stroke:none;stroke-width:1.17873001;" />
<path transform="matrix(-1.81082,4.95107e-2,3.17324e-2,1.55333,1207.46,-284.777)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path116" style="fill:url(#linearGradient1407);stroke:none;stroke-width:0.93138498;" />
<path transform="matrix(-0.823196,-1.76123e-3,-1.82321e-2,0.852662,913.674,-37.9902)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path117" style="fill:#000000;stroke:none;stroke-width:1.86495996;" />
<path transform="matrix(0.59438,-7.22959e-2,6.88176e-2,0.705838,367.448,32.4186)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path118" style="fill:#000000;stroke:none;stroke-width:2.39814997;" />
<path transform="matrix(-0.480323,-3.6454e-2,-4.67935e-2,0.475606,813.496,87.0124)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path121" style="fill:url(#linearGradient1409);stroke:none;stroke-width:3.1916101;" />
<path transform="matrix(0.35691,-4.08211e-2,4.13232e-2,0.398544,449.334,114.991)" d="M 328.86324 320.64151 A 18.087479 27.131195 0 1 1 292.68828,320.64151 A 18.087479 27.131195 0 1 1 328.86324 320.64151 z" id="path122" style="fill:url(#linearGradient1411);stroke:none;stroke-width:4.12025976;" />
<path transform="matrix(1.25,0,0,1.25,185.454,-168.23)" id="path128" d="M 258.702,495.425 C 271.538,466.322 298.816,415.199 299.397,375.667 C 299.397,344.225 393.576,336.716 401.134,368.109 C 408.692,399.502 427.875,446.592 440.084,469.265 C 452.292,491.937 487.893,563.96 449.968,626.811 C 415.811,682.455 312.243,726.477 256.958,619.254 C 238.355,582.047 241.673,535.939 258.702,495.425 z " style="fill:url(#linearGradient1413);stroke:none;stroke-width:1.25;" />
<path transform="matrix(1.38936,-0.111074,0.102211,1.30214,108.413,-165.938)" id="path112" d="M 242.905,473.815 C 231.642,492.782 207.405,543.124 255.042,575.862 C 306.353,610.682 301.515,672.924 239.435,637.817 C 182.658,606.028 216.59,500.039 234.925,475.551 C 247.032,458.337 264.822,437.52 242.905,473.815 z " style="fill:url(#linearGradient1415);stroke:none;stroke-width:1.15804005;" />
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path109" d="M 256.513,449.72 C 239.048,478.228 197.136,545.533 253.225,580.443 C 328.794,626.798 307.398,673.154 238.426,631.417 C 141.317,573.153 226.601,455.801 265.557,411.079 C 310.001,360.879 274.111,420.166 256.513,449.72 z " style="fill:#000000;stroke:#000000;stroke-width:1.25;" />
<path id="path125" d="M 421.481,504.727 C 421.481,537.139 392.209,579.243 341.953,578.865 C 290.125,579.32 268.004,537.139 268.004,504.727 C 268.004,472.315 302.383,446.01 344.743,446.01 C 387.102,446.01 421.481,472.315 421.481,504.727 z " style="font-size:12px;fill:url(#linearGradient1417);stroke:none;stroke-width:1.23705006;stroke-dasharray:none" transform="matrix(1.30209,0,0,1.22525,170.042,-153.557)" />
<path id="path127" d="M 398.227,412.292 C 397.615,450.864 375.047,459.963 346.487,459.963 C 317.926,459.963 297.195,454.269 294.746,412.292 C 294.746,385.978 317.926,370.75 346.487,370.75 C 375.047,370.75 398.227,385.978 398.227,412.292 z " style="font-size:12px;fill:url(#linearGradient1419);stroke:none;stroke-width:1.38846004;stroke-dasharray:none" transform="matrix(1.1868,0,0,1.06708,210.623,-100.078)" />
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path129" d="M 234.285,456.475 C 252.001,429.479 289.3,388.111 241.262,462.288 C 202.311,523.331 226.859,562.561 239.518,573.327 C 276.045,605.889 274.484,627.676 245.913,610.533 C 184.288,573.907 197.078,512.285 234.285,456.475 z " style="fill:url(#linearGradient1421);stroke:none;stroke-width:1.25;" />
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path131" d="M 490.662,467.52 C 475.343,435.819 426.528,355.618 492.988,448.917 C 553.449,533.214 511.01,591.93 503.452,597.744 C 495.895,603.557 470.315,615.184 477.873,594.837 C 485.43,574.49 523.107,535.864 490.662,467.52 z " style="fill:url(#linearGradient1423);stroke:none;stroke-width:1.25;" />
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path132" d="M 220.915,716.921 C 180.473,695.505 121.663,721.045 143.013,662.855 C 147.289,649.617 136.638,629.847 143.594,616.929 C 151.733,601.231 169.174,604.72 179.639,594.255 C 189.957,583.364 196.498,564.606 215.683,567.513 C 234.867,570.42 247.628,593.974 261.027,622.742 C 270.91,643.38 305.968,672.406 303.677,695.5 C 300.981,731 260.65,737.69 220.915,716.921 z " style="fill:url(#linearGradient1425);stroke:#e68c3f;stroke-width:6.25;" />
<path id="path177" d="M 415.072,495.764 C 412.065,520.67 379.259,572.391 345.554,577.298 C 311.294,582.634 279.122,543.238 271.407,506.184 C 261.518,464.978 293.994,448.584 343.345,449.557 C 396.646,451.211 417.466,463.448 415.072,495.764 z " style="font-size:12px;fill:url(#linearGradient1427);stroke:none;stroke-width:2.85509992;stroke-dasharray:none" transform="matrix(0.598206,0.268584,-0.239623,0.617213,700.568,140.464)" />
<path transform="matrix(-1.1685,0.423145,0.475283,1.16478,728.343,-213.821)" id="path133" d="M 220.274,718.402 C 178.947,694.812 120.38,724.007 143.013,662.855 C 147.749,649.787 136.417,629.303 143.373,616.385 C 151.512,600.687 169.174,604.72 179.639,594.255 C 189.957,583.364 198.466,566.387 217.651,569.294 C 236.835,572.201 247.628,593.974 261.027,622.742 C 270.91,643.38 304.442,671.713 302.151,694.807 C 299.455,730.307 259.427,740.278 220.274,718.402 z " style="fill:url(#linearGradient1429);stroke:#e68c3f;stroke-width:6.25067997;" />
<path transform="matrix(-0.945096,0.343745,0.424076,0.956058,714.328,-64.342)" id="path134" d="M 216.482,675.68 C 129.951,618.177 169.174,604.72 179.639,594.255 C 189.957,583.364 198.466,566.387 217.651,569.294 C 236.835,572.201 247.628,593.974 261.027,622.742 C 270.91,643.38 304.087,671.66 302.151,694.807 C 299.535,721.917 253.961,700.294 216.482,675.68 z " style="fill:url(#linearGradient1431);stroke:none;stroke-width:1.52532005;" />
<path transform="matrix(1.00431,-5.2286e-2,-1.74e-2,1.04575,244.191,-28.4653)" id="path135" d="M 216.506,677.071 C 129.975,619.568 169.709,603.501 182.56,595.791 C 197.959,585.849 197.718,564.96 216.903,567.867 C 236.087,570.774 247.628,593.974 261.027,622.742 C 270.91,643.38 304.087,671.66 302.151,694.807 C 299.535,721.917 253.985,701.685 216.506,677.071 z " style="fill:url(#linearGradient1433);stroke:none;stroke-width:1.52532005;" />
<path id="path136" d="M 415.072,495.764 C 412.065,520.67 379.259,572.391 345.554,577.298 C 311.294,582.634 279.122,543.238 271.407,506.184 C 261.518,464.978 293.994,448.584 343.345,449.557 C 396.646,451.211 417.466,463.448 415.072,495.764 z " style="font-size:12px;fill:#000000;stroke:none;stroke-width:2.85509992;" transform="matrix(0.515584,0.215259,-0.206526,0.49467,713.3,222.559)" />
<path id="path137" d="M 415.072,495.764 C 412.065,520.67 379.259,572.391 345.554,577.298 C 311.294,582.634 279.122,543.238 271.407,506.184 C 261.518,464.978 293.994,448.584 343.345,449.557 C 396.646,451.211 417.466,463.448 415.072,495.764 z " style="font-size:12px;fill:url(#linearGradient1435);stroke:none;stroke-width:2.85509992;" transform="matrix(0.351231,0.149463,-0.128856,0.343469,724.522,318.291)" />
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path119" d="M 309.954,338.729 C 317.101,331.959 334.765,311.663 367.915,332.974 C 374.077,336.984 379.077,337.351 390.936,342.429 C 414.662,352.178 403.318,375.688 378.192,383.537 C 367.434,387.026 357.656,400.093 338.063,398.976 C 321.329,397.999 316.944,387.102 306.665,381.07 C 288.396,370.759 285.7,356.816 295.565,349.417 C 305.431,342.018 309.29,339.358 309.954,338.729 z " style="fill:url(#linearGradient1437);stroke:#e68c3f;stroke-width:3.75;" />
<path transform="matrix(1.25,0,0,1.25,185.454,-167.505)" id="path120" d="M 391.251,357.645 C 381.368,358.226 359.858,379.736 337.185,379.736 C 314.512,379.736 301.141,358.807 297.653,358.807" style="fill:none;stroke:#e68c3f;stroke-width:2.5;" />
<path transform="matrix(0.627885,0,0,0.595666,392.366,51.8173)" id="path123" d="M 309.954,338.729 C 317.101,331.959 339.645,313.381 369.542,332.401 C 375.841,336.167 382.346,340.266 392.02,345.865 C 411.182,357.613 401.691,374.543 378.734,385.255 C 368.316,389.75 351.141,399.67 338.063,398.976 C 323.53,397.568 314.128,387.577 304.496,381.07 C 286.826,368.767 287.899,358.833 296.107,350.562 C 302.312,344.883 309.29,339.358 309.954,338.729 z " style="fill:url(#linearGradient1439);stroke:none;" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 21 KiB

View File

@ -1,10 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"rootDir": "./",
"paths": {
"docx": ["../build"]
}
},
"include": ["../demo"]
}

View File

@ -4,7 +4,7 @@
- Simple, declarative API - Simple, declarative API
- 80+ usage examples - 80+ usage examples
- Battle tested, mature, 100% coverage (yes, every line is tested) - Battle tested, mature, 99.9%+ coverage
[GitHub](https://github.com/dolanmiu/docx) [GitHub](https://github.com/dolanmiu/docx)
[Get Started](#Welcome) [Get Started](#Welcome)

View File

@ -1,25 +1,24 @@
# Contribution Guidelines # 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 ```ts
// http://officeopenxml.com/WPdocument.php // http://officeopenxml.com/WPdocument.php
``` ```
<!-- cSpell:ignore datypic --> <!-- cSpell:ignore datypic -->
It can be a link to `officeopenxml.com` or `datypic.com` etc. 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/ 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 ```ts
// <xsd:element name="tbl" type="CT_Tbl" minOccurs="0" maxOccurs="1"/> // <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 ## Always think about the user
@ -38,7 +37,6 @@ Please write good commit messages when making a commit: https://chris.beams.io/p
**Do not:** **Do not:**
<!-- cspell:disable --> <!-- cspell:disable -->
``` ```
c // What? c // What?
rtl // Adding acronyms without explaining anything else is not helpful rtl // Adding acronyms without explaining anything else is not helpful
@ -46,7 +44,6 @@ works! // Glad its working, but the message is not helpful
demo updated // Getting better, but capitalize the first letter demo updated // Getting better, but capitalize the first letter
Unesesary coment removed // Make sure to use correct spelling Unesesary coment removed // Make sure to use correct spelling
``` ```
<!-- cspell:enable --> <!-- cspell:enable -->
**Do** **Do**
@ -107,28 +104,25 @@ private get _level: string;
private get level: string; private get level: string;
``` ```
## Types over interfaces ## Interfaces over type alias
Using `type` aliases in TypeScript offers several advantages over `interfaces`: Do not use `type`, but rather use `Interfaces`. `type` cannot be extended, and a class cannot implement it.
- **Flexibility with Complex Types**: `type` supports defining unions, intersections, and other complex type constructs that `interfaces` cannot handle. For example: > "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
```typescript `Interface` is generally preferred over `type`: https://stackoverflow.com/questions/37233735/typescript-interfaces-vs-types
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:** **Do not:**
```ts
type RelationshipFileInfo = { id: number; target: string };
```
**Do:**
```ts ```ts
interface IRelationshipFileInfo { interface IRelationshipFileInfo {
id: number; id: number;
@ -136,12 +130,6 @@ interface IRelationshipFileInfo {
} }
``` ```
**Do:**
```ts
type RelationshipFileInfo = { id: number; target: string };
```
## String enums vs type ## String enums vs type
To take full advantage of TypeScript's typing system, its best to use `string enums`: To take full advantage of TypeScript's typing system, its best to use `string enums`:

View File

@ -22,7 +22,7 @@ const doc = new Document({
} }
}) })
], ],
}] }];
}); });
``` ```

View File

@ -22,30 +22,19 @@ const doc = new docx.Document({
### Full list of options: ### Full list of options:
| Property | Type | Notes | - creator
| -------------------------- | -------------------------------------------------------- | -------- | - description
| sections | `ISectionOptions[]` | Optional | - title
| title | `string` | Optional | - subject
| subject | `string` | Optional | - keywords
| creator | `string` | Optional | - lastModifiedBy
| keywords | `string` | Optional | - revision
| description | `string` | Optional | - externalStyles
| lastModifiedBy | `string` | Optional | - styles
| revision | `number` | Optional | - numbering
| externalStyles | `string` | Optional | - footnotes
| styles | `IStylesOptions` | Optional | - hyperlinks
| numbering | `INumberingOptions` | Optional | - background
| comments | `ICommentsOptions` | Optional |
| footnotes | `Record<string, { children: Paragraph[] }>` | Optional |
| background | `IDocumentBackgroundOptions` | Optional |
| features | `{ trackRevisions?: boolean; updateFields?: boolean; }` | Optional |
| compatabilityModeVersion | `number` | Optional |
| compatibility | `ICompatibilityOptions` | Optional |
| customProperties | ` ICustomPropertyOptions`[] | Optional |
| evenAndOddHeaderAndFooters | `boolean` | Optional |
| defaultTabStop | `number` | Optional |
| fonts | ` FontOptions[]` | Optional |
| hyphenation | `IHyphenationOptions` | Optional |
### Change background color of Document ### Change background color of Document

View File

@ -16,10 +16,12 @@ const chapter1 = new Paragraph({
children: [ children: [
new Bookmark({ new Bookmark({
id: "anchorForChapter1", 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`: Then you can create an hyperlink pointing to that bookmark with an `InternalHyperLink`:
@ -33,32 +35,20 @@ const link = new InternalHyperlink({
}), }),
], ],
anchor: "anchorForChapter1", anchor: "anchorForChapter1",
}); })
``` ```
### Page reference
You can also get the page number of the bookmark by creating a page reference to it: You can also get the page number of the bookmark by creating a page reference to it:
```ts ```ts
const paragraph = new Paragraph({ 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 ## 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: To create an external hyperlink you just need to specify the url and the text of the link, then add it to a paragraph:
@ -79,6 +69,7 @@ const paragraph = new Paragraph({
}); });
``` ```
## Styling hyperlinks ## 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. 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

@ -6,7 +6,6 @@ To create a `floating` image on top of text:
```ts ```ts
const image = new ImageRun({ const image = new ImageRun({
type: 'gif',
data: fs.readFileSync("./demo/images/pizza.gif"), data: fs.readFileSync("./demo/images/pizza.gif"),
transformation: { transformation: {
width: 200, width: 200,
@ -27,7 +26,6 @@ By default with no arguments, its an `inline` image:
```ts ```ts
const image = new ImageRun({ const image = new ImageRun({
type: 'gif',
data: fs.readFileSync("./demo/images/pizza.gif"), data: fs.readFileSync("./demo/images/pizza.gif"),
transformation: { transformation: {
width: 100, width: 100,
@ -61,7 +59,6 @@ const doc = new Document({
new Paragraph({ new Paragraph({
children: [ children: [
new ImageRun({ new ImageRun({
type: [IMAGE_TYPE],
data: [IMAGE_BUFFER], data: [IMAGE_BUFFER],
transformation: { transformation: {
width: [IMAGE_SIZE], width: [IMAGE_SIZE],
@ -100,7 +97,6 @@ To change the position the image to be on top of the text, simply add the `float
```ts ```ts
const image = new ImageRun({ const image = new ImageRun({
type: 'png',
data: buffer, data: buffer,
transformation: { transformation: {
width: 903, width: 903,
@ -119,7 +115,6 @@ const image = new ImageRun({
```ts ```ts
const image = new ImageRun({ const image = new ImageRun({
type: 'png',
data: buffer, data: buffer,
transformation: { transformation: {
width: 903, width: 903,
@ -185,7 +180,6 @@ For example:
```ts ```ts
const image = new ImageRun({ const image = new ImageRun({
type: 'gif',
data: fs.readFileSync("./demo/images/pizza.gif"), data: fs.readFileSync("./demo/images/pizza.gif"),
transformation: { transformation: {
width: 200, width: 200,
@ -234,7 +228,6 @@ For example:
```ts ```ts
const image = new ImageRun({ const image = new ImageRun({
type: 'gif',
data: fs.readFileSync("./demo/images/pizza.gif"), data: fs.readFileSync("./demo/images/pizza.gif"),
transformation: { transformation: {
width: 200, width: 200,
@ -265,7 +258,6 @@ Specifies common non-visual DrawingML properties. A name, title and description
```ts ```ts
const image = new ImageRun({ const image = new ImageRun({
type: 'gif',
data: fs.readFileSync("./demo/images/pizza.gif"), data: fs.readFileSync("./demo/images/pizza.gif"),
altText: { altText: {
title: "This is an ultimate title", title: "This is an ultimate title",

View File

@ -263,23 +263,3 @@ new MathAngledBrackets({
], ],
}), }),
``` ```
### Limit
#### Limit Upper
```ts
new MathLimitUpper({
children: [new MathRun("x")],
limit: [new MathRun("-")],
}),
```
#### Limit Lower
```ts
new MathLimitLower({
children: [new MathRun("lim")],
limit: [new MathRun("x→0")],
}),
```

View File

@ -130,62 +130,6 @@ new Paragraph({
}), }),
``` ```
## Disabling numbering inherited from paragraph style
If the numbering is set on a paragraph style, you may wish to disable it for a specific paragraph:
```ts
const doc = new Document({
...
numbering: {
config: [
{
reference: "my-bullet-points",
levels: [
{
level: 0,
format: LevelFormat.BULLET,
text: "\u1F60",
alignment: AlignmentType.LEFT,
style: {
paragraph: {
indent: { left: convertInchesToTwip(0.5), hanging: convertInchesToTwip(0.25) },
},
},
},
],
},
],
},
styles: {
paragraphStyles: [
{
id: 'bullet',
name: 'Bullet',
basedOn: 'Normal',
next: 'Normal',
run: {},
paragraph: {
numbering: {
reference: 'my-bullet-points',
level: 0,
},
},
},
],
},
...
});
```
```ts
new Paragraph({
text: "No bullet points!",
style: "Bullet",
numbering: false,
}),
```
## Full Example ## Full Example
[Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/3-numbering-and-bullet-points.ts ":include") [Example](https://raw.githubusercontent.com/dolanmiu/docx/master/demo/3-numbering-and-bullet-points.ts ":include")

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 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`, `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. 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.
### Export as Buffer ### Export as Buffer
@ -14,14 +14,6 @@ Packer.toBuffer(doc).then((buffer) => {
}); });
``` ```
### Export as string
```ts
Packer.toString(doc).then((string) => {
console.log(string);
});
```
### Export as a `base64` string ### Export as a `base64` string
```ts ```ts
@ -40,46 +32,3 @@ Packer.toBlob(doc).then((blob) => {
saveAs(blob, "example.docx"); 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

@ -35,9 +35,6 @@ interface Patch {
| type | `PatchType` | Required | `DOCUMENT`, `PARAGRAPH` | | type | `PatchType` | Required | `DOCUMENT`, `PARAGRAPH` |
| children | `FileChild[] or ParagraphChild[]` | Required | The contents to replace with. A `FileChild` is a `Paragraph` or `Table`, whereas a `ParagraphChild` is typical `Paragraph` children. | | children | `FileChild[] or ParagraphChild[]` | Required | The contents to replace with. A `FileChild` is a `Paragraph` or `Table`, whereas a `ParagraphChild` is typical `Paragraph` children. |
The patcher also takes in a `keepOriginalStyles` boolean, which will preserve the styles of the patched text when set to true.
### How to patch existing document ### How to patch existing document
1. Open your existing word document in your favorite Word Processor 1. Open your existing word document in your favorite Word Processor
@ -79,7 +76,7 @@ patchDocument(fs.readFileSync("My Document.docx"), {
], ],
link: "https://www.google.co.uk", link: "https://www.google.co.uk",
}), }),
new ImageRun({ type: 'png', data: fs.readFileSync("./demo/images/dog.png"), transformation: { width: 100, height: 100 } }), new ImageRun({ data: fs.readFileSync("./demo/images/dog.png"), transformation: { width: 100, height: 100 } }),
], ],
}), }),
], ],

View File

@ -126,10 +126,10 @@ const doc = new Document({
next: "Normal", next: "Normal",
quickFormat: true, quickFormat: true,
run: { run: {
size: 26, size: 26
bold: true, bold: true,
color: "999999", color: "999999",
underline: { {
type: UnderlineType.DOUBLE, type: UnderlineType.DOUBLE,
color: "FF0000", color: "FF0000",
}, },

View File

@ -22,7 +22,7 @@ Then add the table in the `section`
const doc = new Document({ const doc = new Document({
sections: [{ sections: [{
children: [table], children: [table],
}], }];
}); });
``` ```

View File

@ -1,26 +0,0 @@
# Text Box
Similar `Text Frames`, but the difference being that it is `VML` `Shape` based.
!> `Text Boxes` requires an understanding of [Paragraphs](usage/paragraph.md).
> `Text boxes` are paragraphs of text in a document which are positioned in a separate region or frame in the document, and can be positioned with a specific size and position relative to non-frame paragraphs in the current document.
## Intro
To make a `Text Box`, simply create a `Textbox` object inside the `Document`:
```ts
new Textbox({
alignment: "center",
children: [
new Paragraph({
children: [new TextRun("Hi i'm a textbox!")],
}),
],
style: {
width: "200pt",
height: "auto",
},
});
```

View File

@ -1,6 +1,6 @@
# Text Frames # Text Frames
> Similar to `Text Boxes`! Also known as `Text Boxes`
!> Text Frames requires an understanding of [Paragraphs](usage/paragraph.md). !> Text Frames requires an understanding of [Paragraphs](usage/paragraph.md).

View File

@ -1,370 +0,0 @@
import eslint from "@eslint/js";
import type { Linter } from "eslint";
import importPlugin from "eslint-plugin-import";
import unicorn from "eslint-plugin-unicorn";
import jsdoc from "eslint-plugin-jsdoc";
import preferArrow from "eslint-plugin-prefer-arrow";
import functional from "eslint-plugin-functional";
import globals from "globals";
import tsEslint from "typescript-eslint";
const config: Linter.Config<Linter.RulesRecord>[] = [
{
ignores: ["**/vite.config.ts", "**/dist/**", "**/coverage/**", "**/*.js", "eslint.config.ts", "**/demo/**", "**/scripts/**"],
},
eslint.configs.recommended,
importPlugin.flatConfigs.recommended,
...tsEslint.configs.recommended,
...tsEslint.configs.stylistic,
{
files: ["**/src/**/*.ts"],
plugins: {
unicorn,
jsdoc,
"prefer-arrow": preferArrow,
functional,
},
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
settings: {
"import/resolver": {
typescript: true,
node: 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"],
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/consistent-type-definitions": ["error", "type"],
"@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/no-inferrable-types": "off",
"@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",
"sort-imports": [
"error",
{
allowSeparatedGroups: true,
ignoreDeclarationSort: true,
},
],
"import/order": [
"error",
{
groups: [["external", "builtin"], "internal", ["sibling", "parent", "index"]],
"newlines-between": "always",
pathGroups: [
{ pattern: "@file/**/*", group: "internal" },
{ pattern: "@file/**", group: "internal" },
{ pattern: "@export/**", group: "internal" },
],
pathGroupsExcludedImportTypes: ["internal"],
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
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-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",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^[_]+$",
},
],
},
},
{
files: ["**/*.spec.ts"],
plugins: {
unicorn,
jsdoc,
"prefer-arrow": preferArrow,
functional,
},
languageOptions: {
globals: {
...globals.browser,
...globals.node,
},
sourceType: "module",
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
project: ["tsconfig.json"],
},
},
rules: {
"@typescript-eslint/no-unused-expressions": "off",
"@typescript-eslint/dot-notation": "off",
"prefer-destructuring": "off",
"@typescript-eslint/explicit-function-return-type": "off",
"no-unused-vars": [
"error",
{
argsIgnorePattern: "^[_]+$",
},
],
},
},
];
export default config;

15830
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,32 +1,28 @@
{ {
"name": "docx", "name": "docx",
"version": "9.4.1", "version": "8.4.0",
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.", "description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
"type": "module", "type": "module",
"main": "dist/index.umd.cjs", "main": "build/index.umd.js",
"module": "./dist/index.mjs", "module": "./build/index.mjs",
"types": "./dist/index.d.ts", "types": "./build/index.d.ts",
"exports": { "exports": {
".": { ".": {
"import": { "require": "./build/index.cjs",
"types": "./dist/index.d.ts", "types": "./build/index.d.ts",
"default": "./dist/index.mjs" "import": "./build/index.mjs",
}, "default": "./build/index.mjs"
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
} }
}, },
"files": [ "files": [
"dist" "build"
], ],
"scripts": { "scripts": {
"build": "tsc && vite build", "build": "tsc && vite build",
"test": "vitest --ui --coverage", "test": "vitest --ui --coverage",
"test:ci": "vitest run --coverage", "test:ci": "vitest run --coverage",
"prepublishOnly": "npm run build --omit=dev", "prepublishOnly": "npm run build --omit=dev",
"lint": "eslint --flag unstable_ts_config --config eslint.config.ts", "lint": "eslint --ext .ts src",
"predemo": "npm run build", "predemo": "npm run build",
"demo": "tsx ./demo/index.ts", "demo": "tsx ./demo/index.ts",
"typedoc": "typedoc src/index.ts --tsconfig tsconfig.typedoc.json", "typedoc": "typedoc src/index.ts --tsconfig tsconfig.typedoc.json",
@ -58,10 +54,9 @@
"clippy" "clippy"
], ],
"dependencies": { "dependencies": {
"@types/node": "^22.7.5", "@types/node": "^20.3.1",
"hash.js": "^1.1.7",
"jszip": "^3.10.1", "jszip": "^3.10.1",
"nanoid": "^5.1.3", "nanoid": "^5.0.4",
"xml": "^1.0.1", "xml": "^1.0.1",
"xml-js": "^1.6.8" "xml-js": "^1.6.8"
}, },
@ -72,43 +67,39 @@
}, },
"homepage": "https://docx.js.org", "homepage": "https://docx.js.org",
"devDependencies": { "devDependencies": {
"@types/eslint__js": "^8.42.3",
"@types/inquirer": "^9.0.3", "@types/inquirer": "^9.0.3",
"@types/prompt": "^1.1.1", "@types/prompt": "^1.1.1",
"@types/unzipper": "^0.10.4", "@types/unzipper": "^0.10.4",
"@types/xml": "^1.0.8", "@types/xml": "^1.0.8",
"@typescript-eslint/eslint-plugin": "^8.8.1", "@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^8.8.1", "@typescript-eslint/parser": "^6.9.1",
"@vitest/coverage-v8": "^3.0.8", "@vitest/coverage-v8": "^1.1.0",
"@vitest/ui": "^3.0.8", "@vitest/ui": "^1.1.0",
"cspell": "^8.2.3", "cspell": "^8.2.3",
"docsify-cli": "^4.3.0", "docsify-cli": "^4.3.0",
"eslint": "^9.13.0", "eslint": "^8.23.0",
"eslint-import-resolver-typescript": "^4.3.2", "eslint-plugin-functional": "^6.0.0",
"eslint-plugin-functional": "^7.0.2",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsdoc": "^50.3.1", "eslint-plugin-jsdoc": "^46.2.6",
"eslint-plugin-no-null": "^1.0.2", "eslint-plugin-no-null": "^1.0.2",
"eslint-plugin-prefer-arrow": "^1.2.3", "eslint-plugin-prefer-arrow": "^1.2.3",
"eslint-plugin-unicorn": "^58.0.0", "eslint-plugin-unicorn": "^50.0.1",
"execa": "^9.4.0", "execa": "^8.0.1",
"glob": "^11.0.0", "glob": "^10.2.7",
"inquirer": "^12.0.0", "inquirer": "^9.2.7",
"jiti": "^2.3.3", "jsdom": "^23.0.1",
"jsdom": "^26.0.0",
"pre-commit": "^1.2.2", "pre-commit": "^1.2.2",
"prettier": "^3.1.1", "prettier": "^3.1.1",
"tsconfig-paths": "^4.0.0", "tsconfig-paths": "^4.0.0",
"tsx": "^4.7.0", "tsx": "^4.7.0",
"typedoc": "^0.28.2", "typedoc": "^0.25.4",
"typescript": "5.3.3", "typescript": "5.3.3",
"typescript-eslint": "^8.10.0", "unzipper": "^0.10.11",
"unzipper": "^0.12.3", "vite": "^5.0.10",
"vite": "^6.0.1", "vite-plugin-dts": "^3.3.1",
"vite-plugin-dts": "^4.2.4", "vite-plugin-node-polyfills": "^0.9.0",
"vite-plugin-node-polyfills": "^0.23.0", "vite-tsconfig-paths": "^4.2.0",
"vite-tsconfig-paths": "^5.0.1", "vitest": "^1.1.0"
"vitest": "^3.0.8"
}, },
"engines": { "engines": {
"node": ">=10" "node": ">=10"

View File

@ -1,6 +1,7 @@
import { BaseXmlComponent, IContext, IXmlableObject } from "@file/xml-components"; import { BaseXmlComponent, IContext, IXmlableObject } from "@file/xml-components";
export class Formatter { export class Formatter {
// tslint:disable-next-line: no-object-literal-type-assertion
public format(input: BaseXmlComponent, context: IContext = { stack: [] } as unknown as IContext): IXmlableObject { public format(input: BaseXmlComponent, context: IContext = { stack: [] } as unknown as IContext): IXmlableObject {
const output = input.prepForXml(context); const output = input.prepForXml(context);

View File

@ -12,8 +12,7 @@ describe("ImageReplacer", () => {
"test {test-image.png} test", "test {test-image.png} test",
[ [
{ {
type: "png", stream: Buffer.from(""),
data: Buffer.from(""),
fileName: "test-image.png", fileName: "test-image.png",
transformation: { transformation: {
pixels: { pixels: {

View File

@ -36,7 +36,7 @@ describe("Compiler", () => {
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name); const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array); expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(20); expect(fileNames).has.length(17);
expect(fileNames).to.include("word/document.xml"); expect(fileNames).to.include("word/document.xml");
expect(fileNames).to.include("word/styles.xml"); expect(fileNames).to.include("word/styles.xml");
expect(fileNames).to.include("docProps/core.xml"); expect(fileNames).to.include("docProps/core.xml");
@ -47,9 +47,7 @@ describe("Compiler", () => {
expect(fileNames).to.include("word/_rels/footnotes.xml.rels"); expect(fileNames).to.include("word/_rels/footnotes.xml.rels");
expect(fileNames).to.include("word/settings.xml"); expect(fileNames).to.include("word/settings.xml");
expect(fileNames).to.include("word/comments.xml"); expect(fileNames).to.include("word/comments.xml");
expect(fileNames).to.include("word/fontTable.xml");
expect(fileNames).to.include("word/_rels/document.xml.rels"); expect(fileNames).to.include("word/_rels/document.xml.rels");
expect(fileNames).to.include("word/_rels/fontTable.xml.rels");
expect(fileNames).to.include("[Content_Types].xml"); expect(fileNames).to.include("[Content_Types].xml");
expect(fileNames).to.include("_rels/.rels"); expect(fileNames).to.include("_rels/.rels");
}, },
@ -96,7 +94,7 @@ describe("Compiler", () => {
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name); const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array); expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(28); expect(fileNames).has.length(25);
expect(fileNames).to.include("word/header1.xml"); expect(fileNames).to.include("word/header1.xml");
expect(fileNames).to.include("word/_rels/header1.xml.rels"); expect(fileNames).to.include("word/_rels/header1.xml.rels");
@ -112,41 +110,6 @@ 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", () => { 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 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. // This also caused issues such as running prepForXml multiple times as format() was ran multiple times.
@ -160,13 +123,16 @@ describe("Compiler", () => {
], ],
}); });
// tslint:disable-next-line: no-string-literal
const spy = vi.spyOn(compiler["formatter"], "format"); const spy = vi.spyOn(compiler["formatter"], "format");
compiler.compile(file); compiler.compile(file);
expect(spy).toBeCalledTimes(16); expect(spy).toBeCalledTimes(13);
}); });
it("should work with media datas", () => { it("should work with media datas", () => {
// 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.
const file = new File({ const file = new File({
sections: [ sections: [
{ {
@ -184,25 +150,12 @@ describe("Compiler", () => {
new Paragraph({ new Paragraph({
children: [ children: [
new ImageRun({ new ImageRun({
type: "png",
data: Buffer.from("", "base64"), data: Buffer.from("", "base64"),
transformation: { transformation: {
width: 100, width: 100,
height: 100, height: 100,
}, },
}), }),
new ImageRun({
type: "svg",
data: Buffer.from("", "base64"),
transformation: {
width: 100,
height: 100,
},
fallback: {
type: "png",
data: Buffer.from("", "base64"),
},
}),
], ],
}), }),
], ],
@ -212,8 +165,7 @@ describe("Compiler", () => {
vi.spyOn(compiler["imageReplacer"], "getMediaData").mockReturnValue([ vi.spyOn(compiler["imageReplacer"], "getMediaData").mockReturnValue([
{ {
type: "png", stream: Buffer.from(""),
data: Buffer.from(""),
fileName: "test", fileName: "test",
transformation: { transformation: {
pixels: { pixels: {
@ -226,48 +178,9 @@ describe("Compiler", () => {
}, },
}, },
}, },
{
type: "svg",
data: Buffer.from(""),
fileName: "test",
transformation: {
pixels: {
x: 100,
y: 100,
},
emus: {
x: 100,
y: 100,
},
},
fallback: {
type: "png",
data: Buffer.from(""),
fileName: "test",
transformation: {
pixels: {
x: 100,
y: 100,
},
emus: {
x: 100,
y: 100,
},
},
},
},
]); ]);
compiler.compile(file); compiler.compile(file);
}); });
it("should work with fonts", () => {
const file = new File({
sections: [],
fonts: [{ name: "Pacifico", data: Buffer.from("") }],
});
compiler.compile(file);
});
}); });
}); });

View File

@ -2,19 +2,18 @@ import JSZip from "jszip";
import xml from "xml"; import xml from "xml";
import { File } from "@file/file"; import { File } from "@file/file";
import { obfuscate } from "@file/fonts/obfuscate-ttf-to-odttf";
import { Formatter } from "../formatter"; import { Formatter } from "../formatter";
import { ImageReplacer } from "./image-replacer"; import { ImageReplacer } from "./image-replacer";
import { NumberingReplacer } from "./numbering-replacer"; import { NumberingReplacer } from "./numbering-replacer";
import { PrettifyType } from "./packer"; import { PrettifyType } from "./packer";
export type IXmlifyedFile = { interface IXmlifyedFile {
readonly data: string; readonly data: string;
readonly path: string; readonly path: string;
}; }
type IXmlifyedFileMapping = { interface IXmlifyedFileMapping {
readonly Document: IXmlifyedFile; readonly Document: IXmlifyedFile;
readonly Styles: IXmlifyedFile; readonly Styles: IXmlifyedFile;
readonly Properties: IXmlifyedFile; readonly Properties: IXmlifyedFile;
@ -32,10 +31,7 @@ type IXmlifyedFileMapping = {
readonly FootNotesRelationships: IXmlifyedFile; readonly FootNotesRelationships: IXmlifyedFile;
readonly Settings: IXmlifyedFile; readonly Settings: IXmlifyedFile;
readonly Comments?: IXmlifyedFile; readonly Comments?: IXmlifyedFile;
readonly CommentsRelationships?: IXmlifyedFile; }
readonly FontTable?: IXmlifyedFile;
readonly FontTableRelationships?: IXmlifyedFile;
};
export class Compiler { export class Compiler {
private readonly formatter: Formatter; private readonly formatter: Formatter;
@ -48,11 +44,7 @@ export class Compiler {
this.numberingReplacer = new NumberingReplacer(); this.numberingReplacer = new NumberingReplacer();
} }
public compile( public compile(file: File, prettifyXml?: (typeof PrettifyType)[keyof typeof PrettifyType]): JSZip {
file: File,
prettifyXml?: (typeof PrettifyType)[keyof typeof PrettifyType],
overrides: readonly IXmlifyedFile[] = [],
): JSZip {
const zip = new JSZip(); const zip = new JSZip();
const xmlifiedFileMapping = this.xmlifyFile(file, prettifyXml); const xmlifiedFileMapping = this.xmlifyFile(file, prettifyXml);
const map = new Map<string, IXmlifyedFile | readonly IXmlifyedFile[]>(Object.entries(xmlifiedFileMapping)); const map = new Map<string, IXmlifyedFile | readonly IXmlifyedFile[]>(Object.entries(xmlifiedFileMapping));
@ -67,22 +59,8 @@ export class Compiler {
} }
} }
for (const subFile of overrides) { for (const { stream, fileName } of file.Media.Array) {
zip.file(subFile.path, subFile.data); zip.file(`word/media/${fileName}`, stream);
}
for (const data of file.Media.Array) {
if (data.type !== "svg") {
zip.file(`word/media/${data.fileName}`, data.data);
} else {
zip.file(`word/media/${data.fileName}`, data.data);
zip.file(`word/media/${data.fallback.fileName}`, data.fallback.data);
}
}
for (const { data: buffer, name, fontKey } of file.FontTable.fontOptionsWithKey) {
const [nameWithoutExtension] = name.split(".");
zip.file(`word/fonts/${nameWithoutExtension}.odttf`, obfuscate(buffer, fontKey));
} }
return zip; return zip;
@ -105,28 +83,7 @@ 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 documentMediaDatas = this.imageReplacer.getMediaData(documentXmlData, file.Media);
const commentMediaDatas = this.imageReplacer.getMediaData(commentXmlData, file.Media);
return { return {
Relationships: { Relationships: {
@ -139,12 +96,6 @@ export class Compiler {
); );
}); });
file.Document.Relationships.createRelationship(
file.Document.Relationships.RelationshipCount + 1,
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable",
"fontTable.xml",
);
return xml( return xml(
this.formatter.format(file.Document.Relationships, { this.formatter.format(file.Document.Relationships, {
viewWrapper: file.Document, viewWrapper: file.Document,
@ -472,44 +423,8 @@ export class Compiler {
path: "word/settings.xml", path: "word/settings.xml",
}, },
Comments: { Comments: {
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( data: xml(
this.formatter.format(file.FontTable.View, { this.formatter.format(file.Comments, {
viewWrapper: file.Document, viewWrapper: file.Document,
file, file,
stack: [], stack: [],
@ -522,24 +437,7 @@ export class Compiler {
}, },
}, },
), ),
path: "word/fontTable.xml", path: "word/comments.xml",
},
FontTableRelationships: {
data: (() =>
xml(
this.formatter.format(file.FontTable.Relationships, {
viewWrapper: file.Document,
file,
stack: [],
}),
{
indent: prettify,
declaration: {
encoding: "UTF-8",
},
},
))(),
path: "word/_rels/fontTable.xml.rels",
}, },
}; };
} }

View File

@ -46,7 +46,7 @@ describe("Packer", () => {
await Packer.toString(file, true); await Packer.toString(file, true);
expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_2_BLANKS, expect.anything()); expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_2_BLANKS);
}); });
it("should use a prettify value", async () => { it("should use a prettify value", async () => {
@ -55,7 +55,7 @@ describe("Packer", () => {
await Packer.toString(file, PrettifyType.WITH_4_BLANKS); await Packer.toString(file, PrettifyType.WITH_4_BLANKS);
expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_4_BLANKS, expect.anything()); expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_4_BLANKS);
}); });
it("should use an undefined prettify value", async () => { it("should use an undefined prettify value", async () => {
@ -64,32 +64,7 @@ describe("Packer", () => {
await Packer.toString(file, false); await Packer.toString(file, false);
expect(spy).toBeCalledWith(expect.anything(), undefined, expect.anything()); expect(spy).toBeCalledWith(expect.anything(), undefined);
});
});
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, []);
}); });
}); });
@ -164,6 +139,7 @@ describe("Packer", () => {
it("should create a standard docx file", async () => { it("should create a standard docx file", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
vi.spyOn((Packer as any).compiler, "compile").mockReturnValue({ vi.spyOn((Packer as any).compiler, "compile").mockReturnValue({
// tslint:disable-next-line: no-empty
generateAsync: () => vi.fn(), generateAsync: () => vi.fn(),
}); });
const str = await Packer.toBlob(file); const str = await Packer.toBlob(file);
@ -187,37 +163,11 @@ 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()", () => { describe("#toStream()", () => {
it("should create a standard docx file", async () => { it("should create a standard docx file", async () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
vi.spyOn((Packer as any).compiler, "compile").mockReturnValue({ vi.spyOn((Packer as any).compiler, "compile").mockReturnValue({
// tslint:disable-next-line: no-empty
generateAsync: () => Promise.resolve(vi.fn()), generateAsync: () => Promise.resolve(vi.fn()),
}); });
const stream = Packer.toStream(file); const stream = Packer.toStream(file);

View File

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

View File

@ -1,5 +1,4 @@
import { XmlComponent } from "@file/xml-components"; import { XmlComponent } from "@file/xml-components";
import { AppPropertiesAttributes } from "./app-properties-attributes"; import { AppPropertiesAttributes } from "./app-properties-attributes";
export class AppProperties extends XmlComponent { export class AppProperties extends XmlComponent {

View File

@ -22,7 +22,7 @@
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { eighthPointMeasureValue, hexColorValue, pointMeasureValue } from "@util/values"; import { eighthPointMeasureValue, hexColorValue, pointMeasureValue } from "@util/values";
export type IBorderOptions = { export interface IBorderOptions {
readonly style: (typeof BorderStyle)[keyof typeof BorderStyle]; readonly style: (typeof BorderStyle)[keyof typeof BorderStyle];
/** Border color, in hex (eg 'FF00AA') */ /** Border color, in hex (eg 'FF00AA') */
readonly color?: string; readonly color?: string;
@ -30,7 +30,7 @@ export type IBorderOptions = {
readonly size?: number; readonly size?: number;
/** Spacing offset. Values are specified in pt */ /** Spacing offset. Values are specified in pt */
readonly space?: number; readonly space?: number;
}; }
export class BorderElement extends XmlComponent { export class BorderElement extends XmlComponent {
public constructor(elementName: string, { color, size, space, style }: IBorderOptions) { public constructor(elementName: string, { color, size, space, style }: IBorderOptions) {
@ -55,101 +55,34 @@ class BordersAttributes extends XmlAttributeComponent<IBorderOptions> {
}; };
} }
/** /* eslint-disable @typescript-eslint/naming-convention */
* 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 = { export const BorderStyle = {
/** a single line */
SINGLE: "single", SINGLE: "single",
/** a line with a series of alternating thin and thick strokes */
DASH_DOT_STROKED: "dashDotStroked", DASH_DOT_STROKED: "dashDotStroked",
/** a dashed line */
DASHED: "dashed", DASHED: "dashed",
/** a dashed line with small gaps */
DASH_SMALL_GAP: "dashSmallGap", DASH_SMALL_GAP: "dashSmallGap",
/** a line with alternating dots and dashes */
DOT_DASH: "dotDash", DOT_DASH: "dotDash",
/** a line with a repeating dot - dot - dash sequence */
DOT_DOT_DASH: "dotDotDash", DOT_DOT_DASH: "dotDotDash",
/** a dotted line */
DOTTED: "dotted", DOTTED: "dotted",
/** a double line */
DOUBLE: "double", DOUBLE: "double",
/** a double wavy line */
DOUBLE_WAVE: "doubleWave", DOUBLE_WAVE: "doubleWave",
/** an inset set of lines */
INSET: "inset", INSET: "inset",
/** no border */
NIL: "nil", NIL: "nil",
/** no border */
NONE: "none", NONE: "none",
/** an outset set of lines */
OUTSET: "outset", OUTSET: "outset",
/** a single line */
THICK: "thick", THICK: "thick",
/** a thick line contained within a thin line with a large-sized intermediate gap */
THICK_THIN_LARGE_GAP: "thickThinLargeGap", THICK_THIN_LARGE_GAP: "thickThinLargeGap",
/** a thick line contained within a thin line with a medium-sized intermediate gap */
THICK_THIN_MEDIUM_GAP: "thickThinMediumGap", THICK_THIN_MEDIUM_GAP: "thickThinMediumGap",
/** a thick line contained within a thin line with a small intermediate gap */
THICK_THIN_SMALL_GAP: "thickThinSmallGap", THICK_THIN_SMALL_GAP: "thickThinSmallGap",
/** a thin line contained within a thick line with a large-sized intermediate gap */
THIN_THICK_LARGE_GAP: "thinThickLargeGap", THIN_THICK_LARGE_GAP: "thinThickLargeGap",
/** a thick line contained within a thin line with a medium-sized intermediate gap */
THIN_THICK_MEDIUM_GAP: "thinThickMediumGap", THIN_THICK_MEDIUM_GAP: "thinThickMediumGap",
/** a thick line contained within a thin line with a small intermediate gap */
THIN_THICK_SMALL_GAP: "thinThickSmallGap", THIN_THICK_SMALL_GAP: "thinThickSmallGap",
/** a thin-thick-thin line with a large gap */
THIN_THICK_THIN_LARGE_GAP: "thinThickThinLargeGap", THIN_THICK_THIN_LARGE_GAP: "thinThickThinLargeGap",
/** a thin-thick-thin line with a medium gap */
THIN_THICK_THIN_MEDIUM_GAP: "thinThickThinMediumGap", THIN_THICK_THIN_MEDIUM_GAP: "thinThickThinMediumGap",
/** a thin-thick-thin line with a small gap */
THIN_THICK_THIN_SMALL_GAP: "thinThickThinSmallGap", THIN_THICK_THIN_SMALL_GAP: "thinThickThinSmallGap",
/** a three-staged gradient line, getting darker towards the paragraph */
THREE_D_EMBOSS: "threeDEmboss", THREE_D_EMBOSS: "threeDEmboss",
/** a three-staged gradient like, getting darker away from the paragraph */
THREE_D_ENGRAVE: "threeDEngrave", THREE_D_ENGRAVE: "threeDEngrave",
/** a triple line */
TRIPLE: "triple", TRIPLE: "triple",
/** a wavy line */
WAVE: "wave", WAVE: "wave",
} as const; } as const;
/* eslint-enable */

View File

@ -1,7 +1,5 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter"; import { Formatter } from "@export/formatter";
import { CheckBoxUtil } from "."; import { CheckBoxUtil } from ".";
describe("CheckBoxUtil", () => { describe("CheckBoxUtil", () => {

View File

@ -7,20 +7,20 @@
// </xsd:complexType> // </xsd:complexType>
// <xsd:element name="checkbox" type="CT_SdtCheckbox"/> // <xsd:element name="checkbox" type="CT_SdtCheckbox"/>
import { CheckBoxSymbolElement } from "@file/checkbox/checkbox-symbol";
import { XmlComponent } from "@file/xml-components"; import { XmlComponent } from "@file/xml-components";
import { CheckBoxSymbolElement } from "@file/checkbox/checkbox-symbol";
export type ICheckboxSymbolProperties = { export interface ICheckboxSymbolProperties {
readonly value?: string; readonly value?: string;
readonly font?: string; readonly font?: string;
}; }
export type ICheckboxSymbolOptions = { export interface ICheckboxSymbolOptions {
readonly alias?: string; readonly alias?: string;
readonly checked?: boolean; readonly checked?: boolean;
readonly checkedState?: ICheckboxSymbolProperties; readonly checkedState?: ICheckboxSymbolProperties;
readonly uncheckedState?: ICheckboxSymbolProperties; readonly uncheckedState?: ICheckboxSymbolProperties;
}; }
export class CheckBoxUtil extends XmlComponent { export class CheckBoxUtil extends XmlComponent {
private readonly DEFAULT_UNCHECKED_SYMBOL: string = "2610"; private readonly DEFAULT_UNCHECKED_SYMBOL: string = "2610";

View File

@ -1,5 +1,4 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter"; import { Formatter } from "@export/formatter";
import { CheckBox } from "./checkbox"; import { CheckBox } from "./checkbox";

View File

@ -1,8 +1,7 @@
import { SymbolRun } from "@file/paragraph/run/symbol-run"; import { SymbolRun } from "@file/paragraph/run/symbol-run";
import { StructuredDocumentTagContent } from "@file/table-of-contents/sdt-content";
import { StructuredDocumentTagProperties } from "@file/table-of-contents/sdt-properties"; import { StructuredDocumentTagProperties } from "@file/table-of-contents/sdt-properties";
import { StructuredDocumentTagContent } from "@file/table-of-contents/sdt-content";
import { XmlComponent } from "@file/xml-components"; import { XmlComponent } from "@file/xml-components";
import { CheckBoxUtil, ICheckboxSymbolOptions } from "./checkbox-util"; import { CheckBoxUtil, ICheckboxSymbolOptions } from "./checkbox-util";
export class CheckBox extends XmlComponent { export class CheckBox extends XmlComponent {

View File

@ -1,3 +1,5 @@
// tslint:disable:no-string-literal
import { beforeEach, describe, expect, it } from "vitest"; import { beforeEach, describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter"; import { Formatter } from "@export/formatter";
@ -23,21 +25,11 @@ describe("ContentTypes", () => {
expect(tree["Types"][3]).to.deep.equal({ Default: { _attr: { ContentType: "image/jpeg", Extension: "jpg" } } }); expect(tree["Types"][3]).to.deep.equal({ Default: { _attr: { ContentType: "image/jpeg", Extension: "jpg" } } });
expect(tree["Types"][4]).to.deep.equal({ Default: { _attr: { ContentType: "image/bmp", Extension: "bmp" } } }); expect(tree["Types"][4]).to.deep.equal({ Default: { _attr: { ContentType: "image/bmp", Extension: "bmp" } } });
expect(tree["Types"][5]).to.deep.equal({ Default: { _attr: { ContentType: "image/gif", Extension: "gif" } } }); expect(tree["Types"][5]).to.deep.equal({ Default: { _attr: { ContentType: "image/gif", Extension: "gif" } } });
expect(tree["Types"][6]).to.deep.equal({ Default: { _attr: { ContentType: "image/svg+xml", Extension: "svg" } } }); expect(tree["Types"][6]).to.deep.equal({
expect(tree["Types"][7]).to.deep.equal({
Default: { _attr: { ContentType: "application/vnd.openxmlformats-package.relationships+xml", Extension: "rels" } }, Default: { _attr: { ContentType: "application/vnd.openxmlformats-package.relationships+xml", Extension: "rels" } },
}); });
expect(tree["Types"][8]).to.deep.equal({ Default: { _attr: { ContentType: "application/xml", Extension: "xml" } } }); expect(tree["Types"][7]).to.deep.equal({ Default: { _attr: { ContentType: "application/xml", Extension: "xml" } } });
expect(tree["Types"][8]).to.deep.equal({
expect(tree["Types"][9]).to.deep.equal({
Default: {
_attr: {
ContentType: "application/vnd.openxmlformats-officedocument.obfuscatedFont",
Extension: "odttf",
},
},
});
expect(tree["Types"][10]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
@ -45,7 +37,7 @@ describe("ContentTypes", () => {
}, },
}, },
}); });
expect(tree["Types"][11]).to.deep.equal({ expect(tree["Types"][9]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml",
@ -53,7 +45,7 @@ describe("ContentTypes", () => {
}, },
}, },
}); });
expect(tree["Types"][12]).to.deep.equal({ expect(tree["Types"][10]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-package.core-properties+xml", ContentType: "application/vnd.openxmlformats-package.core-properties+xml",
@ -61,7 +53,7 @@ describe("ContentTypes", () => {
}, },
}, },
}); });
expect(tree["Types"][13]).to.deep.equal({ expect(tree["Types"][11]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.custom-properties+xml", ContentType: "application/vnd.openxmlformats-officedocument.custom-properties+xml",
@ -69,7 +61,7 @@ describe("ContentTypes", () => {
}, },
}, },
}); });
expect(tree["Types"][14]).to.deep.equal({ expect(tree["Types"][12]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.extended-properties+xml", ContentType: "application/vnd.openxmlformats-officedocument.extended-properties+xml",
@ -77,7 +69,7 @@ describe("ContentTypes", () => {
}, },
}, },
}); });
expect(tree["Types"][15]).to.deep.equal({ expect(tree["Types"][13]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml", ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml",
@ -85,7 +77,7 @@ describe("ContentTypes", () => {
}, },
}, },
}); });
expect(tree["Types"][16]).to.deep.equal({ expect(tree["Types"][14]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml",
@ -93,7 +85,7 @@ describe("ContentTypes", () => {
}, },
}, },
}); });
expect(tree["Types"][17]).to.deep.equal({ expect(tree["Types"][15]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml", ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml",
@ -110,7 +102,7 @@ describe("ContentTypes", () => {
contentTypes.addFooter(102); contentTypes.addFooter(102);
const tree = new Formatter().format(contentTypes); const tree = new Formatter().format(contentTypes);
expect(tree["Types"][20]).to.deep.equal({ expect(tree["Types"][17]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
@ -119,7 +111,7 @@ describe("ContentTypes", () => {
}, },
}); });
expect(tree["Types"][21]).to.deep.equal({ expect(tree["Types"][18]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml", ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
@ -136,7 +128,7 @@ describe("ContentTypes", () => {
contentTypes.addHeader(202); contentTypes.addHeader(202);
const tree = new Formatter().format(contentTypes); const tree = new Formatter().format(contentTypes);
expect(tree["Types"][20]).to.deep.equal({ expect(tree["Types"][17]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
@ -145,7 +137,7 @@ describe("ContentTypes", () => {
}, },
}); });
expect(tree["Types"][21]).to.deep.equal({ expect(tree["Types"][18]).to.deep.equal({
Override: { Override: {
_attr: { _attr: {
ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml", ContentType: "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",

View File

@ -1,5 +1,4 @@
import { XmlComponent } from "@file/xml-components"; import { XmlComponent } from "@file/xml-components";
import { ContentTypeAttributes } from "./content-types-attributes"; import { ContentTypeAttributes } from "./content-types-attributes";
import { Default } from "./default/default"; import { Default } from "./default/default";
import { Override } from "./override/override"; import { Override } from "./override/override";
@ -19,10 +18,8 @@ export class ContentTypes extends XmlComponent {
this.root.push(new Default("image/jpeg", "jpg")); this.root.push(new Default("image/jpeg", "jpg"));
this.root.push(new Default("image/bmp", "bmp")); this.root.push(new Default("image/bmp", "bmp"));
this.root.push(new Default("image/gif", "gif")); this.root.push(new Default("image/gif", "gif"));
this.root.push(new Default("image/svg+xml", "svg"));
this.root.push(new Default("application/vnd.openxmlformats-package.relationships+xml", "rels")); this.root.push(new Default("application/vnd.openxmlformats-package.relationships+xml", "rels"));
this.root.push(new Default("application/xml", "xml")); this.root.push(new Default("application/xml", "xml"));
this.root.push(new Default("application/vnd.openxmlformats-officedocument.obfuscatedFont", "odttf"));
this.root.push( this.root.push(
new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", "/word/document.xml"), new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", "/word/document.xml"),
@ -36,7 +33,6 @@ export class ContentTypes extends XmlComponent {
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", "/word/footnotes.xml")); this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml", "/word/footnotes.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml", "/word/settings.xml")); this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml", "/word/settings.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml", "/word/comments.xml")); this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml", "/word/comments.xml"));
this.root.push(new Override("application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml", "/word/fontTable.xml"));
} }
public addFooter(index: number): void { public addFooter(index: number): void {

View File

@ -1,5 +1,4 @@
import { XmlComponent } from "@file/xml-components"; import { XmlComponent } from "@file/xml-components";
import { DefaultAttributes } from "./default-attributes"; import { DefaultAttributes } from "./default-attributes";
export class Default extends XmlComponent { export class Default extends XmlComponent {

View File

@ -1,5 +1,4 @@
import { XmlComponent } from "@file/xml-components"; import { XmlComponent } from "@file/xml-components";
import { OverrideAttributes } from "./override-attributes"; import { OverrideAttributes } from "./override-attributes";
export class Override extends XmlComponent { export class Override extends XmlComponent {

View File

@ -45,7 +45,7 @@ describe("Properties", () => {
expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array); expect(tree["cp:coreProperties"]).to.be.an.instanceof(Array);
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
const key = (obj: Readonly<Record<string, any>>) => Object.keys(obj)[0]; const key = (obj: { readonly [key: string]: any }) => Object.keys(obj)[0];
expect(tree["cp:coreProperties"].map(key)).to.include.members([ expect(tree["cp:coreProperties"].map(key)).to.include.members([
"_attr", "_attr",
"cp:keywords", "cp:keywords",

View File

@ -1,19 +1,18 @@
import { FontOptions } from "@file/fonts/font-table";
import { ICommentsOptions } from "@file/paragraph/run/comment-run"; import { ICommentsOptions } from "@file/paragraph/run/comment-run";
import { IHyphenationOptions } from "@file/settings";
import { ICompatibilityOptions } from "@file/settings/compatibility"; import { ICompatibilityOptions } from "@file/settings/compatibility";
import { StringContainer, XmlAttributeComponent, XmlComponent } from "@file/xml-components"; import { StringContainer, XmlComponent } from "@file/xml-components";
import { dateTimeValue } from "@util/values"; import { dateTimeValue } from "@util/values";
import { ICustomPropertyOptions } from "../custom-properties"; import { ICustomPropertyOptions } from "../custom-properties";
import { IDocumentBackgroundOptions } from "../document"; import { IDocumentBackgroundOptions } from "../document";
import { DocumentAttributes } from "../document/document-attributes"; import { DocumentAttributes } from "../document/document-attributes";
import { ISectionOptions } from "../file"; import { ISectionOptions } from "../file";
import { INumberingOptions } from "../numbering"; import { INumberingOptions } from "../numbering";
import { Paragraph } from "../paragraph"; import { Paragraph } from "../paragraph";
import { IStylesOptions } from "../styles"; import { IStylesOptions } from "../styles";
export type IPropertiesOptions = { export interface IPropertiesOptions {
readonly sections: readonly ISectionOptions[]; readonly sections: readonly ISectionOptions[];
readonly title?: string; readonly title?: string;
readonly subject?: string; readonly subject?: string;
@ -26,14 +25,11 @@ export type IPropertiesOptions = {
readonly styles?: IStylesOptions; readonly styles?: IStylesOptions;
readonly numbering?: INumberingOptions; readonly numbering?: INumberingOptions;
readonly comments?: ICommentsOptions; readonly comments?: ICommentsOptions;
readonly footnotes?: Readonly< readonly footnotes?: {
Record< readonly [key: string]: {
string, readonly children: readonly Paragraph[];
{ };
readonly children: readonly Paragraph[]; };
}
>
>;
readonly background?: IDocumentBackgroundOptions; readonly background?: IDocumentBackgroundOptions;
readonly features?: { readonly features?: {
readonly trackRevisions?: boolean; readonly trackRevisions?: boolean;
@ -44,9 +40,7 @@ export type IPropertiesOptions = {
readonly customProperties?: readonly ICustomPropertyOptions[]; readonly customProperties?: readonly ICustomPropertyOptions[];
readonly evenAndOddHeaderAndFooters?: boolean; readonly evenAndOddHeaderAndFooters?: boolean;
readonly defaultTabStop?: number; readonly defaultTabStop?: number;
readonly fonts?: readonly FontOptions[]; }
readonly hyphenation?: IHyphenationOptions;
};
// <xs:element name="coreProperties" type="CT_CoreProperties"/> // <xs:element name="coreProperties" type="CT_CoreProperties"/>
@ -75,7 +69,15 @@ export type IPropertiesOptions = {
export class CoreProperties extends XmlComponent { export class CoreProperties extends XmlComponent {
public constructor(options: Omit<IPropertiesOptions, "sections">) { public constructor(options: Omit<IPropertiesOptions, "sections">) {
super("cp:coreProperties"); super("cp:coreProperties");
this.root.push(new DocumentAttributes(["cp", "dc", "dcterms", "dcmitype", "xsi"])); 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",
}),
);
if (options.title) { if (options.title) {
this.root.push(new StringContainer("dc:title", options.title)); this.root.push(new StringContainer("dc:title", options.title));
} }
@ -102,15 +104,11 @@ export class CoreProperties extends XmlComponent {
} }
} }
class TimestampElementProperties extends XmlAttributeComponent<{ readonly type: string }> {
protected readonly xmlKeys = { type: "xsi:type" };
}
class TimestampElement extends XmlComponent { class TimestampElement extends XmlComponent {
public constructor(name: string) { public constructor(name: string) {
super(name); super(name);
this.root.push( this.root.push(
new TimestampElementProperties({ new DocumentAttributes({
type: "dcterms:W3CDTF", type: "dcterms:W3CDTF",
}), }),
); );

View File

@ -1,5 +1,4 @@
import { IContext, IXmlableObject, XmlComponent } from "@file/xml-components"; import { IContext, IXmlableObject, XmlComponent } from "@file/xml-components";
import { CustomPropertiesAttributes } from "./custom-properties-attributes"; import { CustomPropertiesAttributes } from "./custom-properties-attributes";
import { CustomProperty, ICustomPropertyOptions } from "./custom-property"; import { CustomProperty, ICustomPropertyOptions } from "./custom-property";

View File

@ -1,11 +1,10 @@
import { XmlComponent } from "@file/xml-components"; import { XmlComponent } from "@file/xml-components";
import { CustomPropertyAttributes } from "./custom-property-attributes"; import { CustomPropertyAttributes } from "./custom-property-attributes";
export type ICustomPropertyOptions = { export interface ICustomPropertyOptions {
readonly name: string; readonly name: string;
readonly value: string; readonly value: string;
}; }
export class CustomProperty extends XmlComponent { export class CustomProperty extends XmlComponent {
public constructor(id: number, properties: ICustomPropertyOptions) { public constructor(id: number, properties: ICustomPropertyOptions) {

View File

@ -3,12 +3,11 @@ import { Footer } from "./footer/footer";
import { FootNotes } from "./footnotes"; import { FootNotes } from "./footnotes";
import { Header } from "./header/header"; import { Header } from "./header/header";
import { Relationships } from "./relationships"; import { Relationships } from "./relationships";
import { XmlComponent } from "./xml-components";
export type IViewWrapper = { export interface IViewWrapper {
readonly View: Document | Footer | Header | FootNotes | XmlComponent; readonly View: Document | Footer | Header | FootNotes;
readonly Relationships: Relationships; readonly Relationships: Relationships;
}; }
export class DocumentWrapper implements IViewWrapper { export class DocumentWrapper implements IViewWrapper {
private readonly document: Document; private readonly document: Document;

View File

@ -1,5 +1,5 @@
import { NextAttributeComponent, XmlComponent } from "@file/xml-components"; import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
import { PositiveUniversalMeasure, decimalNumber, twipsMeasureValue } from "@util/values"; import { decimalNumber, PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
import { Column } from "./column"; import { Column } from "./column";

View File

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

View File

@ -1,113 +1,55 @@
import { BuilderElement, XmlComponent } from "@file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
import { decimalNumber } from "@util/values"; import { decimalNumber } from "@util/values";
/** // not implemented
* Specifies the type of the current document grid, which defines the grid behavior. // <xsd:simpleType name="ST_DocGrid">
* // <xsd:restriction base="xsd:string">
* 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. // <xsd:enumeration value="default"/>
* // <xsd:enumeration value="lines"/>
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_DocGrid_topic_ID0ELYP2.html // <xsd:enumeration value="linesAndChars"/>
* // <xsd:enumeration value="snapToChars"/>
* ## XSD Schema // </xsd:restriction>
* ```xml // </xsd:simpleType>
* <xsd:simpleType name="ST_DocGrid">
* <xsd:restriction base="xsd:string"> // <xsd:complexType name="CT_DocGrid">
* <xsd:enumeration value="default"/> // <xsd:attribute name="type" type="ST_DocGrid"/>
* <xsd:enumeration value="lines"/> // <xsd:attribute name="linePitch" type="ST_DecimalNumber"/>
* <xsd:enumeration value="linesAndChars"/> // <xsd:attribute name="charSpace" type="ST_DecimalNumber"/>
* <xsd:enumeration value="snapToChars"/> // </xsd:complexType>
* </xsd:restriction>
* </xsd:simpleType> /* eslint-disable @typescript-eslint/naming-convention */
* ```
*/
export const DocumentGridType = { export const DocumentGridType = {
/**
* Specifies that no document grid shall be applied to the contents of the current section in the document.
*/
DEFAULT: "default", 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", 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", 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", SNAP_TO_CHARS: "snapToChars",
} as const; } as const;
export type IDocGridAttributesProperties = { /* eslint-enable */
/** export interface 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 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; readonly charSpace?: number;
}; }
/** export class DocGridAttributes extends XmlAttributeComponent<IDocGridAttributesProperties> {
* 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. protected readonly xmlKeys = {
* type: "w:type",
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_docGrid_topic_ID0EHU5S.html linePitch: "w:linePitch",
* charSpace: "w:charSpace",
* ```xml };
* <xsd:complexType name="CT_DocGrid"> }
* <xsd:attribute name="type" type="ST_DocGrid"/>
* <xsd:attribute name="linePitch" type="ST_DecimalNumber"/> export class DocumentGrid extends XmlComponent {
* <xsd:attribute name="charSpace" type="ST_DecimalNumber"/> public constructor(linePitch: number, charSpace?: number, type?: (typeof DocumentGridType)[keyof typeof DocumentGridType]) {
* </xsd:complexType> super("w:docGrid");
* ```
* @returns this.root.push(
*/ new DocGridAttributes({
export const createDocumentGrid = ({ type, linePitch, charSpace }: IDocGridAttributesProperties): XmlComponent => type: type,
new BuilderElement<IDocGridAttributesProperties>({ linePitch: decimalNumber(linePitch),
name: "w:docGrid", charSpace: charSpace ? decimalNumber(charSpace) : undefined,
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,7 +1,6 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter"; import { Formatter } from "@export/formatter";
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./header-footer-reference"; import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./header-footer-reference";
describe("HeaderFooterReference", () => { describe("HeaderFooterReference", () => {

View File

@ -1,30 +1,19 @@
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
/** // <xsd:simpleType name="ST_HdrFtr">
* 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. // <xsd:restriction base="xsd:string">
* // <xsd:enumeration value="even"/>
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_HdrFtr_topic_ID0E2UW2.html // <xsd:enumeration value="default"/>
* // <xsd:enumeration value="first"/>
* ## XSD Schema // </xsd:restriction>
* ```xml // </xsd:simpleType>
* <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 = { 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", 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", 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", EVEN: "even",
} as const; } as const;
// </xsd:complexType>
// <xsd:group name="EG_HdrFtrReferences"> // <xsd:group name="EG_HdrFtrReferences">
// <xsd:choice> // <xsd:choice>
// <xsd:element name="headerReference" type="CT_HdrFtrRef" minOccurs="0"/> // <xsd:element name="headerReference" type="CT_HdrFtrRef" minOccurs="0"/>
@ -43,10 +32,10 @@ export const HeaderFooterReferenceType = {
// <xsd:attribute ref="r:id" use="required"/> // <xsd:attribute ref="r:id" use="required"/>
// </xsd:complexType> // </xsd:complexType>
export type IHeaderFooterOptions = { export interface IHeaderFooterOptions {
readonly type?: (typeof HeaderFooterReferenceType)[keyof typeof HeaderFooterReferenceType]; readonly type?: (typeof HeaderFooterReferenceType)[keyof typeof HeaderFooterReferenceType];
readonly id?: number; readonly id?: number;
}; }
class FooterReferenceAttributes extends XmlAttributeComponent<{ class FooterReferenceAttributes extends XmlAttributeComponent<{
readonly type: (typeof HeaderFooterReferenceType)[keyof typeof HeaderFooterReferenceType]; readonly type: (typeof HeaderFooterReferenceType)[keyof typeof HeaderFooterReferenceType];

View File

@ -1,34 +0,0 @@
import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { createLineNumberType } from "./line-number";
describe("createLineNumberType", () => {
it("should work", () => {
const textDirection = createLineNumberType({ countBy: 0, start: 0, restart: "newPage", distance: 10 });
const tree = new Formatter().format(textDirection);
expect(tree).to.deep.equal({
"w:lnNumType": { _attr: { "w:countBy": 0, "w:start": 0, "w:restart": "newPage", "w:distance": 10 } },
});
});
it("should work with string measures for distance", () => {
const textDirection = createLineNumberType({ countBy: 0, start: 0, restart: "newPage", distance: "10mm" });
const tree = new Formatter().format(textDirection);
expect(tree).to.deep.equal({
"w:lnNumType": { _attr: { "w:countBy": 0, "w:start": 0, "w:restart": "newPage", "w:distance": "10mm" } },
});
});
it("should work with blank entries", () => {
const textDirection = createLineNumberType({});
const tree = new Formatter().format(textDirection);
expect(tree).to.deep.equal({
"w:lnNumType": { _attr: {} },
});
});
});

View File

@ -1,128 +1,37 @@
// http://officeopenxml.com/WPsectionLineNumbering.php
import { BuilderElement, XmlComponent } from "@file/xml-components"; import { BuilderElement, XmlComponent } from "@file/xml-components";
import { PositiveUniversalMeasure, decimalNumber, twipsMeasureValue } from "@util/values"; import { decimalNumber, PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
/** // <xsd:simpleType name="ST_LineNumberRestart">
* 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. // <xsd:restriction base="xsd:string">
* // <xsd:enumeration value="newPage"/>
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_LineNumberRestart_topic_ID0EUS42.html // <xsd:enumeration value="newSection"/>
* // <xsd:enumeration value="continuous"/>
* ## XSD Schema // </xsd:restriction>
* // </xsd:simpleType>
* ```xml
* <xsd:simpleType name="ST_LineNumberRestart"> /* eslint-disable @typescript-eslint/naming-convention */
* <xsd:restriction base="xsd:string">
* <xsd:enumeration value="newPage"/>
* <xsd:enumeration value="newSection"/>
* <xsd:enumeration value="continuous"/>
* </xsd:restriction>
* </xsd:simpleType>
* ```
*/
export const LineNumberRestartFormat = { 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", 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", 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", CONTINUOUS: "continuous",
} as const; } as const;
/* eslint-enable */
// <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 = { 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; 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; 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]; 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; 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 => export const createLineNumberType = ({ countBy, start, restart, distance }: ILineNumberAttributes): XmlComponent =>
new BuilderElement<ILineNumberAttributes>({ new BuilderElement<ILineNumberAttributes>({
name: "w:lnNumType", name: "w:lnNumType",

View File

@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter"; import { Formatter } from "@export/formatter";
import { BorderStyle } from "@file/border"; import { BorderStyle } from "@file/border";
import { PageBorderDisplay, PageBorderZOrder, PageBorders } from "./page-borders"; import { PageBorderDisplay, PageBorders, PageBorderZOrder } from "./page-borders";
describe("PageBorders", () => { describe("PageBorders", () => {
describe("#constructor()", () => { describe("#constructor()", () => {

View File

@ -10,11 +10,13 @@ import { IgnoreIfEmptyXmlComponent, XmlAttributeComponent } from "@file/xml-comp
// </xsd:restriction> // </xsd:restriction>
// </xsd:simpleType> // </xsd:simpleType>
/* eslint-disable @typescript-eslint/naming-convention */
export const PageBorderDisplay = { export const PageBorderDisplay = {
ALL_PAGES: "allPages", ALL_PAGES: "allPages",
FIRST_PAGE: "firstPage", FIRST_PAGE: "firstPage",
NOT_FIRST_PAGE: "notFirstPage", NOT_FIRST_PAGE: "notFirstPage",
} as const; } as const;
/* eslint-enable */
// <xsd:simpleType name="ST_PageBorderOffset"> // <xsd:simpleType name="ST_PageBorderOffset">
// <xsd:restriction base="xsd:string"> // <xsd:restriction base="xsd:string">
@ -38,19 +40,19 @@ export const PageBorderZOrder = {
FRONT: "front", FRONT: "front",
} as const; } as const;
export type IPageBorderAttributes = { export interface IPageBorderAttributes {
readonly display?: (typeof PageBorderDisplay)[keyof typeof PageBorderDisplay]; readonly display?: (typeof PageBorderDisplay)[keyof typeof PageBorderDisplay];
readonly offsetFrom?: (typeof PageBorderOffsetFrom)[keyof typeof PageBorderOffsetFrom]; readonly offsetFrom?: (typeof PageBorderOffsetFrom)[keyof typeof PageBorderOffsetFrom];
readonly zOrder?: (typeof PageBorderZOrder)[keyof typeof PageBorderZOrder]; readonly zOrder?: (typeof PageBorderZOrder)[keyof typeof PageBorderZOrder];
}; }
export type IPageBordersOptions = { export interface IPageBordersOptions {
readonly pageBorders?: IPageBorderAttributes; readonly pageBorders?: IPageBorderAttributes;
readonly pageBorderTop?: IBorderOptions; readonly pageBorderTop?: IBorderOptions;
readonly pageBorderRight?: IBorderOptions; readonly pageBorderRight?: IBorderOptions;
readonly pageBorderBottom?: IBorderOptions; readonly pageBorderBottom?: IBorderOptions;
readonly pageBorderLeft?: IBorderOptions; readonly pageBorderLeft?: IBorderOptions;
}; }
class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> { class PageBordersAttributes extends XmlAttributeComponent<IPageBorderAttributes> {
protected readonly xmlKeys = { protected readonly xmlKeys = {

View File

@ -1,5 +1,5 @@
import { NextAttributeComponent, XmlComponent } from "@file/xml-components"; import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
import { PositiveUniversalMeasure, UniversalMeasure, signedTwipsMeasureValue, twipsMeasureValue } from "@util/values"; import { PositiveUniversalMeasure, signedTwipsMeasureValue, twipsMeasureValue, UniversalMeasure } from "@util/values";
// <xsd:complexType name="CT_PageMar"> // <xsd:complexType name="CT_PageMar">
// <xsd:attribute name="top" type="ST_SignedTwipsMeasure" use="required"/> // <xsd:attribute name="top" type="ST_SignedTwipsMeasure" use="required"/>

View File

@ -13,6 +13,7 @@ import { decimalNumber } from "@util/values";
// </xsd:restriction> // </xsd:restriction>
// </xsd:simpleType> // </xsd:simpleType>
/* eslint-disable @typescript-eslint/naming-convention */
export const PageNumberSeparator = { export const PageNumberSeparator = {
HYPHEN: "hyphen", HYPHEN: "hyphen",
PERIOD: "period", PERIOD: "period",
@ -21,11 +22,13 @@ export const PageNumberSeparator = {
EN_DASH: "endash", EN_DASH: "endash",
} as const; } as const;
export type IPageNumberTypeAttributes = { /* eslint-enable */
export interface IPageNumberTypeAttributes {
readonly start?: number; readonly start?: number;
readonly formatType?: (typeof NumberFormat)[keyof typeof NumberFormat]; readonly formatType?: (typeof NumberFormat)[keyof typeof NumberFormat];
readonly separator?: (typeof PageNumberSeparator)[keyof typeof PageNumberSeparator]; readonly separator?: (typeof PageNumberSeparator)[keyof typeof PageNumberSeparator];
}; }
// <xsd:complexType name="CT_PageNumber"> // <xsd:complexType name="CT_PageNumber">
// <xsd:attribute name="fmt" type="ST_NumberFormat" use="optional" default="decimal"/> // <xsd:attribute name="fmt" type="ST_NumberFormat" use="optional" default="decimal"/>

View File

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

View File

@ -1,132 +1,48 @@
import { BuilderElement, XmlComponent } from "@file/xml-components"; import { NextAttributeComponent, XmlComponent } from "@file/xml-components";
import { PositiveUniversalMeasure, twipsMeasureValue } from "@util/values"; import { PositiveUniversalMeasure, twipsMeasureValue } from "@util/values";
/** // <xsd:simpleType name="ST_PageOrientation">
* 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. // <xsd:restriction base="xsd:string">
* // <xsd:enumeration value="portrait"/>
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_ST_PageOrientation_topic_ID0EKBK3.html // <xsd:enumeration value="landscape"/>
* // </xsd:restriction>
* ## XSD Schema // </xsd:simpleType>
*
* ```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 = { export const PageOrientation = {
/**
* ## Portrait Mode
*
* Specifies that pages in this section shall be printed in portrait mode.
*/
PORTRAIT: "portrait", 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", LANDSCAPE: "landscape",
} as const; } 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 = { export type IPageSizeAttributes = {
/** readonly width?: number | PositiveUniversalMeasure;
* ## Page Width readonly height?: number | PositiveUniversalMeasure;
*
* 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]; 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 {
* This element specifies the properties (size and orientation) for all pages in the current section. public constructor(
* width: number | PositiveUniversalMeasure,
* Reference: https://c-rex.net/samples/ooxml/e1/Part4/OOXML_P4_DOCX_pgSz_topic_ID0ENEDT.html?hl=pgsz%2Cpage%2Csize height: number | PositiveUniversalMeasure,
* orientation: (typeof PageOrientation)[keyof typeof PageOrientation],
* ## XSD Schema ) {
* super("w:pgSz");
* ```xml
* <xsd:complexType name="CT_PageSz"> const flip = orientation === PageOrientation.LANDSCAPE;
* <xsd:attribute name="w" type="s:ST_TwipsMeasure"/>
* <xsd:attribute name="h" type="s:ST_TwipsMeasure"/> const widthTwips = twipsMeasureValue(width);
* <xsd:attribute name="orient" type="ST_PageOrientation" use="optional"/> const heightTwips = twipsMeasureValue(height);
* <xsd:attribute name="code" type="ST_DecimalNumber" use="optional"/>
* </xsd:complexType> this.root.push(
* ``` new NextAttributeComponent<IPageSizeAttributes>({
*/ width: { key: "w:w", value: flip ? heightTwips : widthTwips },
export const createPageSize = ({ width, height, orientation, code }: IPageSizeAttributes): XmlComponent => { height: { key: "w:h", value: flip ? widthTwips : heightTwips },
const widthTwips = twipsMeasureValue(width); orientation: { key: "w:orient", value: orientation },
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

@ -1,7 +1,6 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter"; import { Formatter } from "@export/formatter";
import { PageTextDirection, PageTextDirectionType } from "./page-text-direction"; import { PageTextDirection, PageTextDirectionType } from "./page-text-direction";
describe("PageTextDirection", () => { describe("PageTextDirection", () => {

View File

@ -1,10 +1,13 @@
import { XmlAttributeComponent, XmlComponent } from "@file/xml-components"; import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
/* eslint-disable @typescript-eslint/naming-convention */
export const PageTextDirectionType = { export const PageTextDirectionType = {
LEFT_TO_RIGHT_TOP_TO_BOTTOM: "lrTb", LEFT_TO_RIGHT_TOP_TO_BOTTOM: "lrTb",
TOP_TO_BOTTOM_RIGHT_TO_LEFT: "tbRl", TOP_TO_BOTTOM_RIGHT_TO_LEFT: "tbRl",
} as const; } as const;
/* eslint-enable */
class PageTextDirectionAttributes extends XmlAttributeComponent<{ class PageTextDirectionAttributes extends XmlAttributeComponent<{
readonly val: (typeof PageTextDirectionType)[keyof typeof PageTextDirectionType]; readonly val: (typeof PageTextDirectionType)[keyof typeof PageTextDirectionType];
}> { }> {

View File

@ -1,7 +1,6 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter"; import { Formatter } from "@export/formatter";
import { SectionType, Type } from "./section-type"; import { SectionType, Type } from "./section-type";
describe("Type", () => { describe("Type", () => {

View File

@ -11,6 +11,7 @@ import { XmlAttributeComponent, XmlComponent } from "@file/xml-components";
// </xsd:restriction> // </xsd:restriction>
// </xsd:simpleType> // </xsd:simpleType>
/* eslint-disable @typescript-eslint/naming-convention */
export const SectionType = { export const SectionType = {
NEXT_PAGE: "nextPage", NEXT_PAGE: "nextPage",
NEXT_COLUMN: "nextColumn", NEXT_COLUMN: "nextColumn",
@ -18,6 +19,7 @@ export const SectionType = {
EVEN_PAGE: "evenPage", EVEN_PAGE: "evenPage",
ODD_PAGE: "oddPage", ODD_PAGE: "oddPage",
} as const; } as const;
/* eslint-enable */
// <xsd:complexType name="CT_SectType"> // <xsd:complexType name="CT_SectType">
// <xsd:attribute name="val" type="ST_SectionMark"/> // <xsd:attribute name="val" type="ST_SectionMark"/>

View File

@ -15,7 +15,7 @@ import { LineNumberRestartFormat } from "./properties/line-number";
import { PageBorderOffsetFrom } from "./properties/page-borders"; import { PageBorderOffsetFrom } from "./properties/page-borders";
import { PageTextDirectionType } from "./properties/page-text-direction"; import { PageTextDirectionType } from "./properties/page-text-direction";
import { SectionType } from "./properties/section-type"; import { SectionType } from "./properties/section-type";
import { SectionProperties, sectionMarginDefaults, sectionPageSizeDefaults } from "./section-properties"; import { sectionMarginDefaults, sectionPageSizeDefaults, SectionProperties } from "./section-properties";
const DEFAULT_MARGINS = { const DEFAULT_MARGINS = {
"w:bottom": sectionMarginDefaults.BOTTOM, "w:bottom": sectionMarginDefaults.BOTTOM,

View File

@ -1,36 +1,37 @@
// http://officeopenxml.com/WPsection.php // http://officeopenxml.com/WPsection.php
// tslint:disable: no-unnecessary-initializer
import { FooterWrapper } from "@file/footer-wrapper"; import { FooterWrapper } from "@file/footer-wrapper";
import { HeaderWrapper } from "@file/header-wrapper"; import { HeaderWrapper } from "@file/header-wrapper";
import { VerticalAlign, VerticalAlignElement } from "@file/vertical-align"; import { VerticalAlign, VerticalAlignElement } from "@file/vertical-align";
import { OnOffElement, XmlComponent } from "@file/xml-components"; import { OnOffElement, XmlComponent } from "@file/xml-components";
import { Columns, IColumnsAttributes } from "./properties/columns";
import { IDocGridAttributesProperties, createDocumentGrid } from "./properties/doc-grid";
import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./properties/header-footer-reference"; import { HeaderFooterReference, HeaderFooterReferenceType, HeaderFooterType } from "./properties/header-footer-reference";
import { Columns, IColumnsAttributes } from "./properties/columns";
import { DocumentGrid, IDocGridAttributesProperties } from "./properties/doc-grid";
import { ILineNumberAttributes, createLineNumberType } from "./properties/line-number"; import { ILineNumberAttributes, createLineNumberType } from "./properties/line-number";
import { IPageBordersOptions, PageBorders } from "./properties/page-borders"; import { IPageBordersOptions, PageBorders } from "./properties/page-borders";
import { IPageMarginAttributes, PageMargin } from "./properties/page-margin"; import { IPageMarginAttributes, PageMargin } from "./properties/page-margin";
import { IPageNumberTypeAttributes, PageNumberType } from "./properties/page-number"; import { IPageNumberTypeAttributes, PageNumberType } from "./properties/page-number";
import { IPageSizeAttributes, PageOrientation, createPageSize } from "./properties/page-size"; import { IPageSizeAttributes, PageOrientation, PageSize } from "./properties/page-size";
import { PageTextDirection, PageTextDirectionType } from "./properties/page-text-direction"; import { PageTextDirection, PageTextDirectionType } from "./properties/page-text-direction";
import { SectionType, Type } from "./properties/section-type"; import { SectionType, Type } from "./properties/section-type";
export type IHeaderFooterGroup<T> = { export interface IHeaderFooterGroup<T> {
readonly default?: T; readonly default?: T;
readonly first?: T; readonly first?: T;
readonly even?: T; readonly even?: T;
}; }
export type ISectionPropertiesOptions = { export interface ISectionPropertiesOptions {
readonly page?: { readonly page?: {
readonly size?: Partial<IPageSizeAttributes>; readonly size?: IPageSizeAttributes;
readonly margin?: IPageMarginAttributes; readonly margin?: IPageMarginAttributes;
readonly pageNumbers?: IPageNumberTypeAttributes; readonly pageNumbers?: IPageNumberTypeAttributes;
readonly borders?: IPageBordersOptions; readonly borders?: IPageBordersOptions;
readonly textDirection?: (typeof PageTextDirectionType)[keyof typeof PageTextDirectionType]; readonly textDirection?: (typeof PageTextDirectionType)[keyof typeof PageTextDirectionType];
}; };
readonly grid?: Partial<IDocGridAttributesProperties>; readonly grid?: IDocGridAttributesProperties;
readonly headerWrapperGroup?: IHeaderFooterGroup<HeaderWrapper>; readonly headerWrapperGroup?: IHeaderFooterGroup<HeaderWrapper>;
readonly footerWrapperGroup?: IHeaderFooterGroup<FooterWrapper>; readonly footerWrapperGroup?: IHeaderFooterGroup<FooterWrapper>;
readonly lineNumbers?: ILineNumberAttributes; readonly lineNumbers?: ILineNumberAttributes;
@ -38,7 +39,7 @@ export type ISectionPropertiesOptions = {
readonly verticalAlign?: (typeof VerticalAlign)[keyof typeof VerticalAlign]; readonly verticalAlign?: (typeof VerticalAlign)[keyof typeof VerticalAlign];
readonly column?: IColumnsAttributes; readonly column?: IColumnsAttributes;
readonly type?: (typeof SectionType)[keyof typeof SectionType]; readonly type?: (typeof SectionType)[keyof typeof SectionType];
}; }
// <xsd:complexType name="CT_SectPr"> // <xsd:complexType name="CT_SectPr">
// <xsd:sequence> // <xsd:sequence>
@ -128,7 +129,7 @@ export class SectionProperties extends XmlComponent {
this.root.push(new Type(type)); this.root.push(new Type(type));
} }
this.root.push(createPageSize({ width, height, orientation })); this.root.push(new PageSize(width, height, orientation));
this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter)); this.root.push(new PageMargin(top, right, bottom, left, header, footer, gutter));
if (borders) { if (borders) {
@ -157,7 +158,7 @@ export class SectionProperties extends XmlComponent {
this.root.push(new PageTextDirection(textDirection)); this.root.push(new PageTextDirection(textDirection));
} }
this.root.push(createDocumentGrid({ linePitch, charSpace, type: gridType })); this.root.push(new DocumentGrid(linePitch, charSpace, gridType));
} }
private addHeaderFooterGroup( private addHeaderFooterGroup(

View File

@ -1,60 +1,89 @@
import { AttributeMap, XmlAttributeComponent } from "@file/xml-components"; import { XmlAttributeComponent } from "@file/xml-components";
/* cSpell:disable */ /* cSpell:disable */
export const DocumentAttributeNamespaces = { export interface IDocumentAttributesProperties {
wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas", readonly wpc?: string;
mc: "http://schemas.openxmlformats.org/markup-compatibility/2006", readonly mc?: string;
o: "urn:schemas-microsoft-com:office:office", readonly o?: string;
r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships", readonly r?: string;
m: "http://schemas.openxmlformats.org/officeDocument/2006/math", readonly m?: string;
v: "urn:schemas-microsoft-com:vml", readonly v?: string;
wp14: "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing", readonly wp14?: string;
wp: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing", readonly wp?: string;
w10: "urn:schemas-microsoft-com:office:word", readonly w10?: string;
w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main", readonly w?: string;
w14: "http://schemas.microsoft.com/office/word/2010/wordml", readonly w14?: string;
w15: "http://schemas.microsoft.com/office/word/2012/wordml", readonly w15?: string;
wpg: "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup", readonly wpg?: string;
wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk", readonly wpi?: string;
wne: "http://schemas.microsoft.com/office/word/2006/wordml", readonly wne?: string;
wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape", readonly wps?: string;
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; 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;
}
/* cSpell:enable */
export class DocumentAttributes extends XmlAttributeComponent<IDocumentAttributesProperties> { export class DocumentAttributes extends XmlAttributeComponent<IDocumentAttributesProperties> {
protected readonly xmlKeys = { 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", Ignorable: "mc:Ignorable",
...Object.fromEntries(Object.keys(DocumentAttributeNamespaces).map((key) => [key, `xmlns:${key}`])), cp: "xmlns:cp",
} as AttributeMap<IDocumentAttributesProperties>; dc: "xmlns:dc",
dcterms: "xmlns:dcterms",
public constructor(ns: readonly DocumentAttributeNamespace[], Ignorable?: string) { dcmitype: "xmlns:dcmitype",
super({ Ignorable, ...Object.fromEntries(ns.map((n) => [n, DocumentAttributeNamespaces[n]])) }); 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",
};
} }

View File

@ -39,12 +39,12 @@ export class DocumentBackgroundAttributes extends XmlAttributeComponent<{
}; };
} }
export type IDocumentBackgroundOptions = { export interface IDocumentBackgroundOptions {
readonly color?: string; readonly color?: string;
readonly themeColor?: string; readonly themeColor?: string;
readonly themeShade?: string; readonly themeShade?: string;
readonly themeTint?: string; readonly themeTint?: string;
}; }
// <xsd:complexType name="CT_Background"> // <xsd:complexType name="CT_Background">
// <xsd:sequence> // <xsd:sequence>

View File

@ -1,6 +1,5 @@
// http://officeopenxml.com/WPdocument.php // http://officeopenxml.com/WPdocument.php
import { XmlComponent } from "@file/xml-components"; import { XmlComponent } from "@file/xml-components";
import { ConcreteHyperlink, Paragraph } from "../paragraph"; import { ConcreteHyperlink, Paragraph } from "../paragraph";
import { Table } from "../table"; import { Table } from "../table";
import { TableOfContents } from "../table-of-contents"; import { TableOfContents } from "../table-of-contents";
@ -8,9 +7,9 @@ import { Body } from "./body";
import { DocumentAttributes } from "./document-attributes"; import { DocumentAttributes } from "./document-attributes";
import { DocumentBackground, IDocumentBackgroundOptions } from "./document-background"; import { DocumentBackground, IDocumentBackgroundOptions } from "./document-background";
export type IDocumentOptions = { export interface IDocumentOptions {
readonly background?: IDocumentBackgroundOptions; readonly background?: IDocumentBackgroundOptions;
}; }
// <xsd:element name="document" type="CT_Document"/> // <xsd:element name="document" type="CT_Document"/>
// //
@ -37,43 +36,41 @@ export class Document extends XmlComponent {
public constructor(options: IDocumentOptions) { public constructor(options: IDocumentOptions) {
super("w:document"); super("w:document");
this.root.push( this.root.push(
new DocumentAttributes( new DocumentAttributes({
[ wpc: "http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas",
"wpc", mc: "http://schemas.openxmlformats.org/markup-compatibility/2006",
"mc", o: "urn:schemas-microsoft-com:office:office",
"o", r: "http://schemas.openxmlformats.org/officeDocument/2006/relationships",
"r", m: "http://schemas.openxmlformats.org/officeDocument/2006/math",
"m", v: "urn:schemas-microsoft-com:vml",
"v", wp14: "http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing",
"wp14", wp: "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing",
"wp", w10: "urn:schemas-microsoft-com:office:word",
"w10", w: "http://schemas.openxmlformats.org/wordprocessingml/2006/main",
"w", w14: "http://schemas.microsoft.com/office/word/2010/wordml",
"w14", w15: "http://schemas.microsoft.com/office/word/2012/wordml",
"w15", wpg: "http://schemas.microsoft.com/office/word/2010/wordprocessingGroup",
"wpg", wpi: "http://schemas.microsoft.com/office/word/2010/wordprocessingInk",
"wpi", wne: "http://schemas.microsoft.com/office/word/2006/wordml",
"wne", wps: "http://schemas.microsoft.com/office/word/2010/wordprocessingShape",
"wps", cx: "http://schemas.microsoft.com/office/drawing/2014/chartex",
"cx", cx1: "http://schemas.microsoft.com/office/drawing/2015/9/8/chartex",
"cx1", cx2: "http://schemas.microsoft.com/office/drawing/2015/10/21/chartex",
"cx2", cx3: "http://schemas.microsoft.com/office/drawing/2016/5/9/chartex",
"cx3", cx4: "http://schemas.microsoft.com/office/drawing/2016/5/10/chartex",
"cx4", cx5: "http://schemas.microsoft.com/office/drawing/2016/5/11/chartex",
"cx5", cx6: "http://schemas.microsoft.com/office/drawing/2016/5/12/chartex",
"cx6", cx7: "http://schemas.microsoft.com/office/drawing/2016/5/13/chartex",
"cx7", cx8: "http://schemas.microsoft.com/office/drawing/2016/5/14/chartex",
"cx8", aink: "http://schemas.microsoft.com/office/drawing/2016/ink",
"aink", am3d: "http://schemas.microsoft.com/office/drawing/2017/model3d",
"am3d", w16cex: "http://schemas.microsoft.com/office/word/2018/wordml/cex",
"w16cex", w16cid: "http://schemas.microsoft.com/office/word/2016/wordml/cid",
"w16cid", w16: "http://schemas.microsoft.com/office/word/2018/wordml",
"w16", w16sdtdh: "http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash",
"w16sdtdh", w16se: "http://schemas.microsoft.com/office/word/2015/wordml/symex",
"w16se", Ignorable: "w14 w15 wp14",
], }),
"w14 w15 wp14",
),
); );
this.body = new Body(); this.body = new Body();
if (options.background) { if (options.background) {
@ -83,6 +80,7 @@ export class Document extends XmlComponent {
} }
public add(item: Paragraph | Table | TableOfContents | ConcreteHyperlink): Document { public add(item: Paragraph | Table | TableOfContents | ConcreteHyperlink): Document {
// eslint-disable-next-line functional/immutable-data
this.body.push(item); this.body.push(item);
return this; return this;
} }

View File

@ -1,15 +1,14 @@
import { XmlAttributeComponent } from "@file/xml-components"; import { XmlAttributeComponent } from "@file/xml-components";
import { IDistance } from "../drawing"; import { IDistance } from "../drawing";
export type IAnchorAttributes = { export interface IAnchorAttributes extends IDistance {
readonly allowOverlap?: "0" | "1"; readonly allowOverlap?: "0" | "1";
readonly behindDoc?: "0" | "1"; readonly behindDoc?: "0" | "1";
readonly layoutInCell?: "0" | "1"; readonly layoutInCell?: "0" | "1";
readonly locked?: "0" | "1"; readonly locked?: "0" | "1";
readonly relativeHeight?: number; readonly relativeHeight?: number;
readonly simplePos?: "0" | "1"; readonly simplePos?: "0" | "1";
} & IDistance; }
export class AnchorAttributes extends XmlAttributeComponent<IAnchorAttributes> { export class AnchorAttributes extends XmlAttributeComponent<IAnchorAttributes> {
protected readonly xmlKeys = { protected readonly xmlKeys = {

View File

@ -1,6 +1,7 @@
import { assert, describe, expect, it } from "vitest"; import { assert, describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter"; import { Formatter } from "@export/formatter";
import { Utility } from "tests/utility"; import { Utility } from "tests/utility";
import { IDrawingOptions } from "../drawing"; import { IDrawingOptions } from "../drawing";
@ -10,9 +11,8 @@ import { Anchor } from "./anchor";
const createAnchor = (drawingOptions: IDrawingOptions): Anchor => const createAnchor = (drawingOptions: IDrawingOptions): Anchor =>
new Anchor({ new Anchor({
mediaData: { mediaData: {
type: "png",
fileName: "test.png", fileName: "test.png",
data: Buffer.from(""), stream: Buffer.from(""),
transformation: { transformation: {
pixels: { pixels: {
x: 0, x: 0,
@ -91,20 +91,28 @@ describe("Anchor", () => {
// 2: horizontal position // 2: horizontal position
const horizontalPosition = newJson.root[2]; const horizontalPosition = newJson.root[2];
assert.equal(horizontalPosition.rootKey, "wp:positionH"); assert.equal(horizontalPosition.rootKey, "wp:positionH");
assert.include(horizontalPosition.root[0].root, {
relativeFrom: "page",
});
assert.equal(horizontalPosition.root[1].rootKey, "wp:posOffset"); assert.equal(horizontalPosition.root[1].rootKey, "wp:posOffset");
assert.include(horizontalPosition.root[1].root[0], 0); assert.include(horizontalPosition.root[1].root[0], 0);
// 3: vertical position // 3: vertical position
const verticalPosition = newJson.root[3]; const verticalPosition = newJson.root[3];
assert.equal(verticalPosition.rootKey, "wp:positionV"); assert.equal(verticalPosition.rootKey, "wp:positionV");
assert.include(verticalPosition.root[0].root, {
relativeFrom: "page",
});
assert.equal(verticalPosition.root[1].rootKey, "wp:posOffset"); assert.equal(verticalPosition.root[1].rootKey, "wp:posOffset");
assert.include(verticalPosition.root[1].root[0], 0); assert.include(verticalPosition.root[1].root[0], 0);
// 4: extent // 4: extent
const extent = newJson.root[4]; const extent = newJson.root[4];
assert.equal(extent.rootKey, "wp:extent"); assert.equal(extent.rootKey, "wp:extent");
assert.include(extent.root[0].root, {
cx: 952500,
cy: 952500,
});
// 5: effect extent // 5: effect extent
const effectExtent = newJson.root[5]; const effectExtent = newJson.root[5];

View File

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

View File

@ -1,6 +1,7 @@
// https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_docPr_topic_ID0ES32OB.html // https://c-rex.net/projects/samples/ooxml/e1/Part4/OOXML_P4_DOCX_docPr_topic_ID0ES32OB.html
import { ConcreteHyperlink } from "@file/paragraph";
import { IContext, IXmlableObject, NextAttributeComponent, XmlComponent } from "@file/xml-components"; import { IContext, IXmlableObject, NextAttributeComponent, XmlComponent } from "@file/xml-components";
import { ConcreteHyperlink } from "@file/paragraph";
import { docPropertiesUniqueNumericIdGen } from "@util/convenience-functions"; import { docPropertiesUniqueNumericIdGen } from "@util/convenience-functions";
import { createHyperlinkClick } from "./doc-properties-children"; import { createHyperlinkClick } from "./doc-properties-children";
@ -17,11 +18,11 @@ import { createHyperlinkClick } from "./doc-properties-children";
// <attribute name="hidden" type="xsd:boolean" use="optional" default="false" /> // <attribute name="hidden" type="xsd:boolean" use="optional" default="false" />
// </complexType> // </complexType>
export type DocPropertiesOptions = { export interface DocPropertiesOptions {
readonly name: string; readonly name: string;
readonly description: string; readonly description: string;
readonly title: string; readonly title: string;
}; }
export class DocProperties extends XmlComponent { export class DocProperties extends XmlComponent {
private readonly docPropertiesUniqueNumericId = docPropertiesUniqueNumericIdGen(); private readonly docPropertiesUniqueNumericId = docPropertiesUniqueNumericIdGen();

View File

@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { Formatter } from "@export/formatter";
import { IContext } from "@file/xml-components"; import { IContext } from "@file/xml-components";
import { Formatter } from "@export/formatter";
import { ConcreteHyperlink, TextRun } from "../"; import { ConcreteHyperlink, TextRun } from "../";
import { Drawing, IDrawingOptions } from "./drawing"; import { Drawing, IDrawingOptions } from "./drawing";
@ -11,9 +11,8 @@ const imageBase64Data = `iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAACzVBMVEU
const createDrawing = (drawingOptions?: IDrawingOptions): Drawing => const createDrawing = (drawingOptions?: IDrawingOptions): Drawing =>
new Drawing( new Drawing(
{ {
type: "jpg",
fileName: "test.jpg", fileName: "test.jpg",
data: Buffer.from(imageBase64Data, "base64"), stream: Buffer.from(imageBase64Data, "base64"),
transformation: { transformation: {
pixels: { pixels: {
x: 100, x: 100,
@ -80,6 +79,7 @@ describe("Drawing", () => {
{ {
"a:graphicFrameLocks": { "a:graphicFrameLocks": {
_attr: { _attr: {
// tslint:disable-next-line:object-literal-key-quotes
noChangeAspect: 1, noChangeAspect: 1,
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", "xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
}, },
@ -138,6 +138,7 @@ describe("Drawing", () => {
{ {
"a:blip": { "a:blip": {
_attr: { _attr: {
// tslint:disable-next-line:object-literal-key-quotes
cstate: "none", cstate: "none",
"r:embed": "rId{test.jpg}", "r:embed": "rId{test.jpg}",
}, },
@ -309,6 +310,7 @@ describe("Drawing", () => {
{ {
"a:graphicFrameLocks": { "a:graphicFrameLocks": {
_attr: { _attr: {
// tslint:disable-next-line:object-literal-key-quotes
noChangeAspect: 1, noChangeAspect: 1,
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", "xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
}, },
@ -367,6 +369,7 @@ describe("Drawing", () => {
{ {
"a:blip": { "a:blip": {
_attr: { _attr: {
// tslint:disable-next-line:object-literal-key-quotes
cstate: "none", cstate: "none",
"r:embed": "rId{test.jpg}", "r:embed": "rId{test.jpg}",
}, },
@ -550,6 +553,7 @@ describe("Drawing", () => {
{ {
"a:graphicFrameLocks": { "a:graphicFrameLocks": {
_attr: { _attr: {
// tslint:disable-next-line:object-literal-key-quotes
noChangeAspect: 1, noChangeAspect: 1,
"xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main", "xmlns:a": "http://schemas.openxmlformats.org/drawingml/2006/main",
}, },
@ -617,6 +621,7 @@ describe("Drawing", () => {
{ {
"a:blip": { "a:blip": {
_attr: { _attr: {
// tslint:disable-next-line:object-literal-key-quotes
cstate: "none", cstate: "none",
"r:embed": "rId{test.jpg}", "r:embed": "rId{test.jpg}",
}, },

View File

@ -14,11 +14,11 @@ export type IDistance = {
readonly distR?: number; readonly distR?: number;
}; };
export type IDrawingOptions = { export interface IDrawingOptions {
readonly floating?: IFloating; readonly floating?: IFloating;
readonly docProperties?: DocPropertiesOptions; readonly docProperties?: DocPropertiesOptions;
readonly outline?: OutlineOptions; readonly outline?: OutlineOptions;
}; }
// <xsd:complexType name="CT_Drawing"> // <xsd:complexType name="CT_Drawing">
// <xsd:choice minOccurs="1" maxOccurs="unbounded"> // <xsd:choice minOccurs="1" maxOccurs="unbounded">

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