Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
b59fa6bb16 | |||
c0c62001fe | |||
e77a7dfdcd | |||
a0437381e7 | |||
bb686bbcbe | |||
c898d0a3c3 | |||
704c678333 | |||
c59c5350fd |
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "docx",
|
||||
"version": "8.0.2",
|
||||
"version": "8.0.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "docx",
|
||||
"version": "8.0.2",
|
||||
"version": "8.0.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "^18.0.0",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docx",
|
||||
"version": "8.0.2",
|
||||
"version": "8.0.4",
|
||||
"description": "Easily generate .docx files with JS/TS with a nice declarative API. Works for Node and on the Browser.",
|
||||
"main": "build/index.js",
|
||||
"scripts": {
|
||||
|
@ -1,8 +1,6 @@
|
||||
import { assert, expect } from "chai";
|
||||
import { SinonStub, stub } from "sinon";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
import * as convenienceFunctions from "@util/convenience-functions";
|
||||
|
||||
import { Utility } from "tests/utility";
|
||||
|
||||
@ -40,14 +38,6 @@ const createAnchor = (drawingOptions: IDrawingOptions): Anchor =>
|
||||
);
|
||||
|
||||
describe("Anchor", () => {
|
||||
before(() => {
|
||||
stub(convenienceFunctions, "uniqueNumericId").callsFake(() => 0);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
(convenienceFunctions.uniqueNumericId as SinonStub).restore();
|
||||
});
|
||||
|
||||
let anchor: Anchor;
|
||||
|
||||
describe("#constructor()", () => {
|
||||
@ -466,7 +456,7 @@ describe("Anchor", () => {
|
||||
"wp:docPr": {
|
||||
_attr: {
|
||||
descr: "test",
|
||||
id: 0,
|
||||
id: 1,
|
||||
name: "test",
|
||||
title: "test",
|
||||
},
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { IContext, IXmlableObject, NextAttributeComponent, XmlComponent } from "@file/xml-components";
|
||||
import { ConcreteHyperlink } from "@file/paragraph";
|
||||
|
||||
import { uniqueNumericId } from "@util/convenience-functions";
|
||||
import { docPropertiesUniqueNumericIdGen } from "@util/convenience-functions";
|
||||
|
||||
import { createHyperlinkClick } from "./doc-properties-children";
|
||||
|
||||
@ -25,6 +25,8 @@ export interface DocPropertiesOptions {
|
||||
}
|
||||
|
||||
export class DocProperties extends XmlComponent {
|
||||
private readonly docPropertiesUniqueNumericId = docPropertiesUniqueNumericIdGen();
|
||||
|
||||
public constructor({ name, description, title }: DocPropertiesOptions = { name: "", description: "", title: "" }) {
|
||||
super("wp:docPr");
|
||||
|
||||
@ -32,7 +34,7 @@ export class DocProperties extends XmlComponent {
|
||||
new NextAttributeComponent({
|
||||
id: {
|
||||
key: "id",
|
||||
value: uniqueNumericId(),
|
||||
value: this.docPropertiesUniqueNumericId(),
|
||||
},
|
||||
name: {
|
||||
key: "name",
|
||||
|
@ -1,9 +1,7 @@
|
||||
import { expect } from "chai";
|
||||
import { SinonStub, stub } from "sinon";
|
||||
|
||||
import { IContext } from "@file/xml-components";
|
||||
import { Formatter } from "@export/formatter";
|
||||
import * as convenienceFunctions from "@util/convenience-functions";
|
||||
|
||||
import { ConcreteHyperlink, TextRun } from "../";
|
||||
import { Drawing, IDrawingOptions } from "./drawing";
|
||||
@ -30,14 +28,6 @@ const createDrawing = (drawingOptions?: IDrawingOptions): Drawing =>
|
||||
);
|
||||
|
||||
describe("Drawing", () => {
|
||||
before(() => {
|
||||
stub(convenienceFunctions, "uniqueNumericId").callsFake(() => 0);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
(convenienceFunctions.uniqueNumericId as SinonStub).restore();
|
||||
});
|
||||
|
||||
let currentBreak: Drawing;
|
||||
|
||||
describe("#constructor()", () => {
|
||||
@ -78,7 +68,7 @@ describe("Drawing", () => {
|
||||
"wp:docPr": {
|
||||
_attr: {
|
||||
descr: "",
|
||||
id: 0,
|
||||
id: 1,
|
||||
name: "",
|
||||
title: "",
|
||||
},
|
||||
@ -309,7 +299,7 @@ describe("Drawing", () => {
|
||||
"wp:docPr": {
|
||||
_attr: {
|
||||
descr: "",
|
||||
id: 0,
|
||||
id: 1,
|
||||
name: "",
|
||||
title: "",
|
||||
},
|
||||
@ -543,7 +533,7 @@ describe("Drawing", () => {
|
||||
{
|
||||
_attr: {
|
||||
descr: "",
|
||||
id: 0,
|
||||
id: 1,
|
||||
name: "",
|
||||
title: "",
|
||||
},
|
||||
|
@ -1,20 +1,10 @@
|
||||
import { expect } from "chai";
|
||||
import { SinonStub, stub } from "sinon";
|
||||
|
||||
import { Formatter } from "@export/formatter";
|
||||
import * as convenienceFunctions from "@util/convenience-functions";
|
||||
|
||||
import { Numbering } from "./numbering";
|
||||
|
||||
describe("Numbering", () => {
|
||||
before(() => {
|
||||
stub(convenienceFunctions, "uniqueNumericId").callsFake(() => 0);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
(convenienceFunctions.uniqueNumericId as SinonStub).restore();
|
||||
});
|
||||
|
||||
describe("#constructor", () => {
|
||||
it("creates a default numbering with one abstract and one concrete instance", () => {
|
||||
const numbering = new Numbering({
|
||||
@ -26,7 +16,7 @@ describe("Numbering", () => {
|
||||
const abstractNums = tree["w:numbering"].filter((el) => el["w:abstractNum"]);
|
||||
expect(abstractNums).to.have.lengthOf(1);
|
||||
expect(abstractNums[0]["w:abstractNum"]).to.deep.include.members([
|
||||
{ _attr: { "w:abstractNumId": 0, "w15:restartNumberingAfterBreak": 0 } },
|
||||
{ _attr: { "w:abstractNumId": 1, "w15:restartNumberingAfterBreak": 0 } },
|
||||
{ "w:multiLevelType": { _attr: { "w:val": "hybridMultilevel" } } },
|
||||
]);
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
// https://stackoverflow.com/questions/58622437/purpose-of-abstractnum-and-numberinginstance
|
||||
import { AlignmentType } from "@file/paragraph";
|
||||
import { IContext, IXmlableObject, XmlComponent } from "@file/xml-components";
|
||||
import { convertInchesToTwip, uniqueNumericId } from "@util/convenience-functions";
|
||||
import { abstractNumUniqueNumericIdGen, concreteNumUniqueNumericIdGen, convertInchesToTwip } from "@util/convenience-functions";
|
||||
|
||||
import { DocumentAttributes } from "../document/document-attributes";
|
||||
import { AbstractNumbering } from "./abstract-numbering";
|
||||
@ -30,6 +30,8 @@ export class Numbering extends XmlComponent {
|
||||
private readonly abstractNumberingMap = new Map<string, AbstractNumbering>();
|
||||
private readonly concreteNumberingMap = new Map<string, ConcreteNumbering>();
|
||||
private readonly referenceConfigMap = new Map<string, object>();
|
||||
private readonly abstractNumUniqueNumericId = abstractNumUniqueNumericIdGen();
|
||||
private readonly concreteNumUniqueNumericId = concreteNumUniqueNumericIdGen();
|
||||
|
||||
public constructor(options: INumberingOptions) {
|
||||
super("w:numbering");
|
||||
@ -55,7 +57,7 @@ export class Numbering extends XmlComponent {
|
||||
}),
|
||||
);
|
||||
|
||||
const abstractNumbering = new AbstractNumbering(uniqueNumericId(), [
|
||||
const abstractNumbering = new AbstractNumbering(this.abstractNumUniqueNumericId(), [
|
||||
{
|
||||
level: 0,
|
||||
format: LevelFormat.BULLET,
|
||||
@ -176,7 +178,7 @@ export class Numbering extends XmlComponent {
|
||||
this.abstractNumberingMap.set("default-bullet-numbering", abstractNumbering);
|
||||
|
||||
for (const con of options.config) {
|
||||
this.abstractNumberingMap.set(con.reference, new AbstractNumbering(uniqueNumericId(), con.levels));
|
||||
this.abstractNumberingMap.set(con.reference, new AbstractNumbering(this.abstractNumUniqueNumericId(), con.levels));
|
||||
this.referenceConfigMap.set(con.reference, con.levels);
|
||||
}
|
||||
}
|
||||
@ -209,7 +211,7 @@ export class Numbering extends XmlComponent {
|
||||
const firstLevelStartNumber = referenceConfigLevels && referenceConfigLevels[0].start;
|
||||
|
||||
const concreteNumberingSettings = {
|
||||
numId: uniqueNumericId(),
|
||||
numId: this.concreteNumUniqueNumericId(),
|
||||
abstractNumId: abstractNumbering.id,
|
||||
reference,
|
||||
instance,
|
||||
|
@ -1,17 +1,19 @@
|
||||
// http://officeopenxml.com/WPbookmark.php
|
||||
import { XmlComponent } from "@file/xml-components";
|
||||
import { uniqueNumericId } from "@util/convenience-functions";
|
||||
import { bookmarkUniqueNumericIdGen } from "@util/convenience-functions";
|
||||
|
||||
import { ParagraphChild } from "../paragraph";
|
||||
import { BookmarkEndAttributes, BookmarkStartAttributes } from "./bookmark-attributes";
|
||||
|
||||
export class Bookmark {
|
||||
private readonly bookmarkUniqueNumericId = bookmarkUniqueNumericIdGen();
|
||||
|
||||
public readonly start: BookmarkStart;
|
||||
public readonly children: readonly ParagraphChild[];
|
||||
public readonly end: BookmarkEnd;
|
||||
|
||||
public constructor(options: { readonly id: string; readonly children: readonly ParagraphChild[] }) {
|
||||
const linkId = uniqueNumericId();
|
||||
const linkId = this.bookmarkUniqueNumericId();
|
||||
|
||||
this.start = new BookmarkStart(options.id, linkId);
|
||||
this.children = options.children;
|
||||
|
@ -20,12 +20,12 @@ import { TextRun } from "./run";
|
||||
describe("Paragraph", () => {
|
||||
before(() => {
|
||||
stub(convenienceFunctions, "uniqueId").callsFake(() => "test-unique-id");
|
||||
stub(convenienceFunctions, "uniqueNumericId").callsFake(() => -101);
|
||||
stub(convenienceFunctions, "bookmarkUniqueNumericIdGen").callsFake(() => () => -101);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
(convenienceFunctions.uniqueId as SinonStub).restore();
|
||||
(convenienceFunctions.uniqueNumericId as SinonStub).restore();
|
||||
(convenienceFunctions.bookmarkUniqueNumericIdGen as SinonStub).restore();
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
|
@ -11,12 +11,10 @@ import { ImageRun } from "./image-run";
|
||||
describe("ImageRun", () => {
|
||||
before(() => {
|
||||
stub(convenienceFunctions, "uniqueId").callsFake(() => "test-unique-id");
|
||||
stub(convenienceFunctions, "uniqueNumericId").callsFake(() => 0);
|
||||
});
|
||||
|
||||
after(() => {
|
||||
(convenienceFunctions.uniqueId as SinonStub).restore();
|
||||
(convenienceFunctions.uniqueNumericId as SinonStub).restore();
|
||||
});
|
||||
|
||||
describe("#constructor()", () => {
|
||||
@ -126,7 +124,7 @@ describe("ImageRun", () => {
|
||||
"wp:docPr": {
|
||||
_attr: {
|
||||
descr: "",
|
||||
id: 0,
|
||||
id: 1,
|
||||
name: "",
|
||||
title: "",
|
||||
},
|
||||
@ -378,7 +376,7 @@ describe("ImageRun", () => {
|
||||
"wp:docPr": {
|
||||
_attr: {
|
||||
descr: "",
|
||||
id: 0,
|
||||
id: 1,
|
||||
name: "",
|
||||
title: "",
|
||||
},
|
||||
@ -634,7 +632,7 @@ describe("ImageRun", () => {
|
||||
"wp:docPr": {
|
||||
_attr: {
|
||||
descr: "",
|
||||
id: 0,
|
||||
id: 1,
|
||||
name: "",
|
||||
title: "",
|
||||
},
|
||||
@ -893,7 +891,7 @@ describe("ImageRun", () => {
|
||||
"wp:docPr": {
|
||||
_attr: {
|
||||
descr: "",
|
||||
id: 0,
|
||||
id: 1,
|
||||
name: "",
|
||||
title: "",
|
||||
},
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { expect } from "chai";
|
||||
|
||||
import { convertInchesToTwip, convertMillimetersToTwip, uniqueId, uniqueNumericId } from "./convenience-functions";
|
||||
import { convertInchesToTwip, convertMillimetersToTwip, uniqueId, uniqueNumericIdCreator } from "./convenience-functions";
|
||||
|
||||
describe("Utility", () => {
|
||||
describe("#convertMillimetersToTwip", () => {
|
||||
@ -17,8 +17,9 @@ describe("Utility", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("#uniqueNumericId", () => {
|
||||
describe("#uniqueNumericIdCreator", () => {
|
||||
it("should generate a unique incrementing ID", () => {
|
||||
const uniqueNumericId = uniqueNumericIdCreator();
|
||||
expect(uniqueNumericId()).to.not.be.undefined;
|
||||
});
|
||||
});
|
||||
|
@ -1,12 +1,25 @@
|
||||
import { nanoid } from "nanoid/non-secure";
|
||||
|
||||
let currentCount = 0;
|
||||
|
||||
// Twip - twentieths of a point
|
||||
export const convertMillimetersToTwip = (millimeters: number): number => Math.floor((millimeters / 25.4) * 72 * 20);
|
||||
|
||||
export const convertInchesToTwip = (inches: number): number => Math.floor(inches * 72 * 20);
|
||||
|
||||
export const uniqueNumericId = (): number => ++currentCount;
|
||||
export type UniqueNumericIdCreator = () => number;
|
||||
|
||||
export const uniqueNumericIdCreator = (initial = 0): UniqueNumericIdCreator => {
|
||||
let currentCount = initial;
|
||||
|
||||
return () => ++currentCount;
|
||||
};
|
||||
|
||||
export const abstractNumUniqueNumericIdGen = (): UniqueNumericIdCreator => uniqueNumericIdCreator();
|
||||
|
||||
// Setting initial to 1 as we have numId = 1 for "default-bullet-numbering"
|
||||
export const concreteNumUniqueNumericIdGen = (): UniqueNumericIdCreator => uniqueNumericIdCreator(1);
|
||||
|
||||
export const docPropertiesUniqueNumericIdGen = (): UniqueNumericIdCreator => uniqueNumericIdCreator();
|
||||
|
||||
export const bookmarkUniqueNumericIdGen = (): UniqueNumericIdCreator => uniqueNumericIdCreator();
|
||||
|
||||
export const uniqueId = (): string => nanoid().toLowerCase();
|
||||
|
Reference in New Issue
Block a user