Use C8 for coverage

This commit is contained in:
Dolan Miu
2023-06-12 18:43:29 +01:00
parent 09ab91eeef
commit eeee01a0e0
11 changed files with 655 additions and 2090 deletions

View File

@ -1,6 +1,4 @@
/* tslint:disable:typedef space-before-function-paren */
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
import * as fflate from "fflate";
import { File } from "@file/file";
import { Footer, Header } from "@file/header";
@ -9,21 +7,6 @@ import * as convenienceFunctions from "@util/convenience-functions";
import { Compiler } from "./next-compiler";
const unzip = (zipFile: Uint8Array): Promise<ReadonlySet<string>> => {
const set = new Set<string>();
const unzipper = new fflate.Unzip((file) => {
set.add(file.name);
});
return new Promise<ReadonlySet<string>>((resolve) => {
setTimeout(() => {
resolve(set);
}, 1000);
unzipper.push(zipFile, true);
});
};
describe("Compiler", () => {
let compiler: Compiler;
@ -42,18 +25,18 @@ describe("Compiler", () => {
describe("#compile()", () => {
it(
"should pack all the content",
async () => {
() => {
const file = new File({
sections: [],
comments: {
children: [],
},
});
const zipFile = await compiler.compile(file);
const fileNames = await unzip(zipFile);
const zipFile = compiler.compile(file);
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).has.length(13);
expect(fileNames).to.include("word/document.xml");
expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(17);
expect(fileNames).to.include("word/document.xml");
expect(fileNames).to.include("word/styles.xml");
expect(fileNames).to.include("docProps/core.xml");
@ -75,7 +58,7 @@ describe("Compiler", () => {
it(
"should pack all additional headers and footers",
async () => {
() => {
const file = new File({
sections: [
{
@ -107,10 +90,12 @@ describe("Compiler", () => {
],
});
const zipFile = await compiler.compile(file);
const fileNames = await unzip(zipFile);
const zipFile = compiler.compile(file);
const fileNames = Object.keys(zipFile.files).map((f) => zipFile.files[f].name);
expect(fileNames).is.an.instanceof(Array);
expect(fileNames).has.length(25);
expect(fileNames).has.length(21);
expect(fileNames).to.include("word/header1.xml");
expect(fileNames).to.include("word/_rels/header1.xml.rels");
expect(fileNames).to.include("word/header2.xml");

View File

@ -1,4 +1,4 @@
import { strToU8, zip } from "fflate";
import JSZip from "jszip";
import xml from "xml";
import { File } from "@file/file";
@ -44,39 +44,26 @@ export class Compiler {
this.numberingReplacer = new NumberingReplacer();
}
public compile(file: File, prettifyXml?: PrettifyType): Promise<Uint8Array> {
public compile(file: File, prettifyXml?: PrettifyType): JSZip {
const zip = new JSZip();
const xmlifiedFileMapping = this.xmlifyFile(file, prettifyXml);
const map = new Map<string, IXmlifyedFile | readonly IXmlifyedFile[]>(Object.entries(xmlifiedFileMapping));
return new Promise<Uint8Array>((resolve, reject) => {
zip(
{
...Array.from(map.entries()).reduce((acc, [, obj]) => {
if (Array.isArray(obj)) {
for (const subFile of obj as readonly IXmlifyedFile[]) {
// eslint-disable-next-line functional/immutable-data
acc[subFile.path] = strToU8(subFile.data);
}
} else {
// eslint-disable-next-line functional/immutable-data
acc[(obj as IXmlifyedFile).path] = strToU8((obj as IXmlifyedFile).data);
}
for (const [, obj] of map) {
if (Array.isArray(obj)) {
for (const subFile of obj as readonly IXmlifyedFile[]) {
zip.file(subFile.path, subFile.data);
}
} else {
zip.file((obj as IXmlifyedFile).path, (obj as IXmlifyedFile).data);
}
}
return acc;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
}, {} as any),
...file.Media.Array.reduce((acc, { stream, fileName }) => ({ ...acc, [`word/media/${fileName}`]: stream }), {}),
},
{},
(err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
},
);
});
for (const { stream, fileName } of file.Media.Array) {
zip.file(`word/media/${fileName}`, stream);
}
return zip;
}
private xmlifyFile(file: File, prettify?: PrettifyType): IXmlifyedFileMapping {

View File

@ -3,7 +3,7 @@ import { afterEach, assert, beforeEach, describe, expect, it, vi } from "vitest"
import { File } from "@file/file";
import { HeadingLevel, Paragraph } from "@file/paragraph";
import { Packer } from "./packer";
import { Packer, PrettifyType } from "./packer";
describe("Packer", () => {
let file: File;
@ -35,6 +35,36 @@ describe("Packer", () => {
});
});
describe("prettify", () => {
afterEach(() => {
vi.restoreAllMocks();
});
it("should use a default prettify value", async () => {
const spy = vi.spyOn((Packer as any).compiler, "compile");
await Packer.toString(file, true);
expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_2_BLANKS);
});
it("should use a prettify value", async () => {
const spy = vi.spyOn((Packer as any).compiler, "compile");
await Packer.toString(file, PrettifyType.WITH_4_BLANKS);
expect(spy).toBeCalledWith(expect.anything(), PrettifyType.WITH_4_BLANKS);
});
it("should use an undefined prettify value", async () => {
const spy = vi.spyOn((Packer as any).compiler, "compile");
await Packer.toString(file, false);
expect(spy).toBeCalledWith(expect.anything(), undefined);
});
});
describe("#toString()", () => {
it("should return a non-empty string", async () => {
const result = await Packer.toString(file);
@ -133,7 +163,10 @@ describe("Packer", () => {
describe("#toStream()", () => {
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(Promise.resolve(new Uint8Array(255)));
vi.spyOn((Packer as any).compiler, "compile").mockReturnValue({
// tslint:disable-next-line: no-empty
generateAsync: () => Promise.resolve(vi.fn()),
});
const stream = Packer.toStream(file);
const p = new Promise<void>((resolve, reject) => {

View File

@ -1,6 +1,5 @@
import { Stream } from "stream";
import { File } from "@file/file";
import { strFromU8 } from "fflate";
import { Compiler } from "./next-compiler";
@ -14,46 +13,63 @@ export enum PrettifyType {
WITH_TAB = "\t",
}
const convertPrettifyType = (prettify?: boolean | PrettifyType): PrettifyType | undefined =>
prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify;
export class Packer {
public static async toString(file: File, prettify?: boolean | PrettifyType): Promise<string> {
const zip = await this.compiler.compile(
file,
prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify,
);
return strFromU8(zip);
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
const zipData = await zip.generateAsync({
type: "string",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
});
return zipData;
}
public static async toBuffer(file: File, prettify?: boolean | PrettifyType): Promise<Buffer> {
const zip = await this.compiler.compile(
file,
prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify,
);
return Buffer.from(zip.buffer);
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
const zipData = await zip.generateAsync({
type: "nodebuffer",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
});
return zipData;
}
public static async toBase64String(file: File, prettify?: boolean | PrettifyType): Promise<string> {
const zip = await this.compiler.compile(
file,
prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify,
);
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
const zipData = await zip.generateAsync({
type: "base64",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
});
return Promise.resolve(strFromU8(zip));
return zipData;
}
public static async toBlob(file: File, prettify?: boolean | PrettifyType): Promise<Blob> {
const zip = await this.compiler.compile(
file,
prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify,
);
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
const zipData = await zip.generateAsync({
type: "blob",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
});
return new Blob([zip.buffer]);
return zipData;
}
public static toStream(file: File, prettify?: boolean | PrettifyType): Stream {
const zip = this.compiler.compile(file, prettify === true ? PrettifyType.WITH_2_BLANKS : prettify === false ? undefined : prettify);
const stream = new Stream();
const zip = this.compiler.compile(file, convertPrettifyType(prettify));
zip.then((z) => {
zip.generateAsync({
type: "nodebuffer",
mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
compression: "DEFLATE",
}).then((z) => {
stream.emit("data", z);
stream.emit("end");
});