@prose-reader/streamer 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/archives/createArchiveFromArrayBufferList.d.ts +10 -0
- package/dist/archives/createArchiveFromArrayBufferList.js +35 -0
- package/dist/archives/createArchiveFromJszip.d.ts +34 -0
- package/dist/archives/createArchiveFromJszip.js +26 -0
- package/dist/archives/createArchiveFromText.d.ts +7 -0
- package/dist/archives/createArchiveFromText.js +67 -0
- package/dist/archives/createArchiveFromUrls.d.ts +7 -0
- package/dist/archives/createArchiveFromUrls.js +29 -0
- package/dist/archives/getArchiveOpfInfo.d.ts +15 -0
- package/dist/archives/getArchiveOpfInfo.js +8 -0
- package/dist/archives/types.d.ts +20 -0
- package/dist/archives/types.js +1 -0
- package/dist/generators/manifest.d.ts +10 -0
- package/dist/generators/manifest.js +141 -0
- package/dist/generators/resources.d.ts +2 -0
- package/dist/generators/resources.js +95 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +5709 -0
- package/dist/index.js.LICENSE.txt +10 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/kobo.d.ts +6 -0
- package/dist/parsers/kobo.js +26 -0
- package/dist/parsers/nav.d.ts +5 -0
- package/dist/parsers/nav.js +121 -0
- package/dist/report.d.ts +13 -0
- package/dist/report.js +68 -0
- package/dist/streamer/src/archives/createArchiveFromJszip.d.ts +34 -0
- package/dist/streamer/src/generators/manifest.d.ts +10 -0
- package/dist/streamer/src/generators/resources.d.ts +2 -0
- package/dist/streamer/src/index.d.ts +10 -0
- package/dist/streamer/src/parsers/kobo.d.ts +6 -0
- package/dist/streamer/src/parsers/nav.d.ts +5 -0
- package/dist/utils/blobToBAse64.d.ts +1 -0
- package/dist/utils/blobToBAse64.js +19 -0
- package/dist/utils/sortByTitleComparator.d.ts +1 -0
- package/dist/utils/sortByTitleComparator.js +18 -0
- package/dist/utils/uri.d.ts +1 -0
- package/dist/utils/uri.js +1 -0
- package/package.json +41 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import xmldoc from 'xmldoc';
|
|
11
|
+
import { getArchiveOpfInfo } from '..';
|
|
12
|
+
const extractNavChapter = (li, { opfBasePath, baseUrl }) => {
|
|
13
|
+
const chp = {
|
|
14
|
+
contents: [],
|
|
15
|
+
path: ``,
|
|
16
|
+
href: ``,
|
|
17
|
+
title: ``
|
|
18
|
+
};
|
|
19
|
+
let contentNode = li.childNamed(`span`) || li.childNamed(`a`);
|
|
20
|
+
chp.title = (contentNode === null || contentNode === void 0 ? void 0 : contentNode.attr.title) || (contentNode === null || contentNode === void 0 ? void 0 : contentNode.val.trim()) || chp.title;
|
|
21
|
+
let node = contentNode === null || contentNode === void 0 ? void 0 : contentNode.name;
|
|
22
|
+
if (node !== `a`) {
|
|
23
|
+
contentNode = li.descendantWithPath(`${node}.a`);
|
|
24
|
+
if (contentNode) {
|
|
25
|
+
node = contentNode.name.toLowerCase();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (node === `a` && (contentNode === null || contentNode === void 0 ? void 0 : contentNode.attr.href)) {
|
|
29
|
+
chp.path = opfBasePath ? `${opfBasePath}/${contentNode.attr.href}` : `${contentNode.attr.href}`;
|
|
30
|
+
chp.href = opfBasePath ? `${baseUrl}/${opfBasePath}/${contentNode.attr.href}` : `${baseUrl}/${contentNode.attr.href}`;
|
|
31
|
+
}
|
|
32
|
+
const sublistNode = li.childNamed(`ol`);
|
|
33
|
+
if (sublistNode) {
|
|
34
|
+
const children = sublistNode.childrenNamed(`li`);
|
|
35
|
+
if (children && children.length > 0) {
|
|
36
|
+
chp.contents = children.map((child) => extractNavChapter(child, { opfBasePath, baseUrl }));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return chp;
|
|
40
|
+
};
|
|
41
|
+
const buildTOCFromNav = (doc, { opfBasePath, baseUrl }) => {
|
|
42
|
+
var _a, _b;
|
|
43
|
+
const toc = [];
|
|
44
|
+
let navDataChildren;
|
|
45
|
+
if (doc.descendantWithPath(`body.nav.ol`)) {
|
|
46
|
+
navDataChildren = (_a = doc.descendantWithPath(`body.nav.ol`)) === null || _a === void 0 ? void 0 : _a.children;
|
|
47
|
+
}
|
|
48
|
+
else if (doc.descendantWithPath(`body.section.nav.ol`)) {
|
|
49
|
+
navDataChildren = (_b = doc.descendantWithPath(`body.section.nav.ol`)) === null || _b === void 0 ? void 0 : _b.children;
|
|
50
|
+
}
|
|
51
|
+
if (navDataChildren && navDataChildren.length > 0) {
|
|
52
|
+
navDataChildren
|
|
53
|
+
.filter((li) => li.name === `li`)
|
|
54
|
+
.forEach((li) => toc.push(extractNavChapter(li, { opfBasePath, baseUrl })));
|
|
55
|
+
}
|
|
56
|
+
return toc;
|
|
57
|
+
};
|
|
58
|
+
const parseTocFromNavPath = (opfXmlDoc, archive, { opfBasePath, baseUrl }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
59
|
+
var _a;
|
|
60
|
+
// Try to detect if there is a nav item
|
|
61
|
+
const navItem = (_a = opfXmlDoc.childNamed(`manifest`)) === null || _a === void 0 ? void 0 : _a.childrenNamed(`item`).find((child) => child.attr.properties === `nav`);
|
|
62
|
+
if (navItem) {
|
|
63
|
+
const tocFile = Object.values(archive.files).find(item => item.uri.endsWith(navItem.attr.href || ``));
|
|
64
|
+
if (tocFile) {
|
|
65
|
+
const doc = new xmldoc.XmlDocument(yield tocFile.string());
|
|
66
|
+
return buildTOCFromNav(doc, { opfBasePath, baseUrl });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
const mapNcxChapter = (point, { opfBasePath, baseUrl, prefix }) => {
|
|
71
|
+
var _a, _b;
|
|
72
|
+
const src = ((_a = point === null || point === void 0 ? void 0 : point.childNamed(`${prefix}content`)) === null || _a === void 0 ? void 0 : _a.attr.src) || ``;
|
|
73
|
+
const out = {
|
|
74
|
+
title: ((_b = point === null || point === void 0 ? void 0 : point.descendantWithPath(`${prefix}navLabel.${prefix}text`)) === null || _b === void 0 ? void 0 : _b.val) || ``,
|
|
75
|
+
path: opfBasePath ? `${opfBasePath}/${src}` : `${src}`,
|
|
76
|
+
href: opfBasePath ? `${baseUrl}/${opfBasePath}/${src}` : `${baseUrl}/${src}`,
|
|
77
|
+
contents: []
|
|
78
|
+
};
|
|
79
|
+
const children = point.childrenNamed(`${prefix}navPoint`);
|
|
80
|
+
if (children && children.length > 0) {
|
|
81
|
+
out.contents = children.map((pt) => mapNcxChapter(pt, { opfBasePath, baseUrl, prefix }));
|
|
82
|
+
}
|
|
83
|
+
return out;
|
|
84
|
+
};
|
|
85
|
+
const buildTOCFromNCX = (ncxData, { opfBasePath, baseUrl }) => {
|
|
86
|
+
var _a;
|
|
87
|
+
const toc = [];
|
|
88
|
+
const rootTagName = ncxData.name;
|
|
89
|
+
let prefix = ``;
|
|
90
|
+
if (rootTagName.indexOf(`:`) !== -1) {
|
|
91
|
+
prefix = rootTagName.split(`:`)[0] + `:`;
|
|
92
|
+
}
|
|
93
|
+
(_a = ncxData
|
|
94
|
+
.childNamed(`${prefix}navMap`)) === null || _a === void 0 ? void 0 : _a.childrenNamed(`${prefix}navPoint`).forEach((point) => toc.push(mapNcxChapter(point, { opfBasePath, baseUrl, prefix })));
|
|
95
|
+
return toc;
|
|
96
|
+
};
|
|
97
|
+
const parseTocFromNcx = ({ opfData, opfBasePath, baseUrl, archive }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
98
|
+
var _b;
|
|
99
|
+
const spine = opfData.childNamed(`spine`);
|
|
100
|
+
const ncxId = spine && spine.attr.toc;
|
|
101
|
+
if (ncxId) {
|
|
102
|
+
const ncxItem = (_b = opfData
|
|
103
|
+
.childNamed(`manifest`)) === null || _b === void 0 ? void 0 : _b.childrenNamed(`item`).find((item) => item.attr.id === ncxId);
|
|
104
|
+
if (ncxItem) {
|
|
105
|
+
const ncxPath = `${opfBasePath}${opfBasePath === `` ? `` : `/`}${ncxItem.attr.href}`;
|
|
106
|
+
const file = Object.values(archive.files).find(item => item.uri.endsWith(ncxPath));
|
|
107
|
+
if (file) {
|
|
108
|
+
const ncxData = new xmldoc.XmlDocument(yield file.string());
|
|
109
|
+
return buildTOCFromNCX(ncxData, { opfBasePath, baseUrl });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
export const parseToc = (opfXmlDoc, archive, { baseUrl }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
115
|
+
const { basePath: opfBasePath } = getArchiveOpfInfo(archive) || {};
|
|
116
|
+
const tocFromNcx = yield parseTocFromNcx({ opfData: opfXmlDoc, opfBasePath, archive, baseUrl });
|
|
117
|
+
if (tocFromNcx) {
|
|
118
|
+
return tocFromNcx;
|
|
119
|
+
}
|
|
120
|
+
return yield parseTocFromNavPath(opfXmlDoc, archive, { opfBasePath, baseUrl });
|
|
121
|
+
});
|
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const Report: {
|
|
2
|
+
enable: (enable: boolean) => void;
|
|
3
|
+
log: (...data: any[]) => void;
|
|
4
|
+
warn: (...data: any[]) => void;
|
|
5
|
+
error: (...data: any[]) => void;
|
|
6
|
+
time: (label?: string | undefined) => void;
|
|
7
|
+
timeEnd: (label?: string | undefined) => void;
|
|
8
|
+
metric: (performanceEntry: PerformanceEntry | {
|
|
9
|
+
name: string;
|
|
10
|
+
duration: number;
|
|
11
|
+
}, targetDuration?: number) => void;
|
|
12
|
+
measurePerformance: <F extends (...args: any[]) => any>(name: string, targetDuration: number | undefined, functionToMeasure: F) => (...args: Parameters<F>) => ReturnType<F>;
|
|
13
|
+
};
|
package/dist/report.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
let enabled = false;
|
|
2
|
+
export const Report = {
|
|
3
|
+
enable: (enable) => {
|
|
4
|
+
enabled = enable;
|
|
5
|
+
},
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
7
|
+
log: (...data) => {
|
|
8
|
+
if (enabled) {
|
|
9
|
+
// eslint-disable-next-line no-console
|
|
10
|
+
console.log(`[prose-reader-streamer]`, ...data);
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
14
|
+
warn: (...data) => {
|
|
15
|
+
if (enabled) {
|
|
16
|
+
// eslint-disable-next-line no-console
|
|
17
|
+
console.warn(`[prose-reader-streamer]`, ...data);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
+
error: (...data) => {
|
|
22
|
+
// eslint-disable-next-line no-console
|
|
23
|
+
console.error(...data);
|
|
24
|
+
},
|
|
25
|
+
time: (label) => {
|
|
26
|
+
if (enabled) {
|
|
27
|
+
// eslint-disable-next-line no-console
|
|
28
|
+
console.time(`[prose-reader-streamer] [metric] ${label}`);
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
timeEnd: (label) => {
|
|
32
|
+
if (enabled) {
|
|
33
|
+
// eslint-disable-next-line no-console
|
|
34
|
+
console.timeEnd(`[prose-reader-streamer] [metric] ${label}`);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
metric: (performanceEntry, targetDuration = Infinity) => {
|
|
38
|
+
const duration = typeof performanceEntry === `number` ? performanceEntry : performanceEntry.duration;
|
|
39
|
+
if (enabled) {
|
|
40
|
+
if (performanceEntry.duration <= targetDuration) {
|
|
41
|
+
// eslint-disable-next-line no-console
|
|
42
|
+
console.log(`[prose-reader-streamer] [metric] `, `${performanceEntry.name} took ${duration}ms`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
// eslint-disable-next-line no-console
|
|
46
|
+
console.warn(`[prose-reader-streamer] [metric] `, `${performanceEntry.name} took ${performanceEntry.duration}ms which is above the ${targetDuration}ms target for this function`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
|
+
measurePerformance: (name, targetDuration = 10, functionToMeasure) => {
|
|
52
|
+
return (...args) => {
|
|
53
|
+
const t0 = performance.now();
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
55
|
+
const response = functionToMeasure(...args);
|
|
56
|
+
if (response && response.then) {
|
|
57
|
+
return response.then((res) => {
|
|
58
|
+
const t1 = performance.now();
|
|
59
|
+
Report.metric({ name, duration: t1 - t0 }, targetDuration);
|
|
60
|
+
return res;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const t1 = performance.now();
|
|
64
|
+
Report.metric({ name, duration: t1 - t0 }, targetDuration);
|
|
65
|
+
return response;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { Archive, StreamResult } from "./types";
|
|
3
|
+
interface OutputByType {
|
|
4
|
+
base64: string;
|
|
5
|
+
string: string;
|
|
6
|
+
text: string;
|
|
7
|
+
binarystring: string;
|
|
8
|
+
array: number[];
|
|
9
|
+
uint8array: Uint8Array;
|
|
10
|
+
arraybuffer: ArrayBuffer;
|
|
11
|
+
blob: Blob;
|
|
12
|
+
nodebuffer: Buffer;
|
|
13
|
+
}
|
|
14
|
+
declare type OutputType = keyof OutputByType;
|
|
15
|
+
interface JSZipObject {
|
|
16
|
+
name: string;
|
|
17
|
+
dir: boolean;
|
|
18
|
+
date: Date;
|
|
19
|
+
comment: string;
|
|
20
|
+
unixPermissions: number | string | null;
|
|
21
|
+
dosPermissions: number | null;
|
|
22
|
+
async<T extends OutputType>(type: T): Promise<OutputByType[T]>;
|
|
23
|
+
internalStream?: (type?: `uint8array`) => StreamResult;
|
|
24
|
+
}
|
|
25
|
+
interface JSZip {
|
|
26
|
+
files: {
|
|
27
|
+
[key: string]: JSZipObject;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare const createArchiveFromJszip: (jszip: JSZip, { orderByAlpha, name }?: {
|
|
31
|
+
orderByAlpha?: boolean | undefined;
|
|
32
|
+
name?: string | undefined;
|
|
33
|
+
}) => Promise<Archive>;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import xmldoc from 'xmldoc';
|
|
2
|
+
import { Archive } from '..';
|
|
3
|
+
export declare const getManifestFromArchive: (archive: Archive, { baseUrl }?: {
|
|
4
|
+
baseUrl?: string | undefined;
|
|
5
|
+
}) => Promise<Response>;
|
|
6
|
+
export declare const getItemsFromDoc: (doc: xmldoc.XmlDocument) => {
|
|
7
|
+
href: string;
|
|
8
|
+
id: string;
|
|
9
|
+
mediaType: string | undefined;
|
|
10
|
+
}[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { getResourceFromArchive } from './generators/resources';
|
|
2
|
+
export { getManifestFromArchive } from './generators/manifest';
|
|
3
|
+
export type { Manifest } from '@oboku/shared';
|
|
4
|
+
export { Report } from './report';
|
|
5
|
+
export { Archive } from './archives/types';
|
|
6
|
+
export { getArchiveOpfInfo } from './archives/getArchiveOpfInfo';
|
|
7
|
+
export { createArchiveFromUrls } from './archives/createArchiveFromUrls';
|
|
8
|
+
export { createArchiveFromText } from './archives/createArchiveFromText';
|
|
9
|
+
export { createArchiveFromJszip } from './archives/createArchiveFromJszip';
|
|
10
|
+
export { createArchiveFromArrayBufferList } from './archives/createArchiveFromArrayBufferList';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const blobToBase64: (blob: Blob | File) => Promise<string>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
export const blobToBase64 = (blob) => __awaiter(void 0, void 0, void 0, function* () {
|
|
11
|
+
return new Promise(resolve => {
|
|
12
|
+
const reader = new FileReader();
|
|
13
|
+
reader.readAsDataURL(blob);
|
|
14
|
+
reader.onloadend = function () {
|
|
15
|
+
const base64data = reader.result;
|
|
16
|
+
resolve(base64data);
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const sortByTitleComparator: (a: string, b: string) => number;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const sortByTitleComparator = (a, b) => {
|
|
2
|
+
var _a;
|
|
3
|
+
const alist = a.split(/(\d+)/);
|
|
4
|
+
const blist = b.split(/(\d+)/);
|
|
5
|
+
alist.slice(-1) === [``] && alist.pop();
|
|
6
|
+
blist.slice(-1) === [``] && blist.pop();
|
|
7
|
+
for (let i = 0, len = alist.length; i < len; i++) {
|
|
8
|
+
if (alist[i] !== blist[i]) {
|
|
9
|
+
if ((_a = alist[i]) === null || _a === void 0 ? void 0 : _a.match(/\d/)) {
|
|
10
|
+
return +(alist[i] || ``) - +(blist[i] || ``);
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
return (alist[i] || ``).localeCompare((blist[i] || ``));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return 1;
|
|
18
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const getUriBasename: (uri: string) => string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const getUriBasename = (uri) => uri.substring(uri.lastIndexOf(`/`) + 1) || uri;
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@prose-reader/streamer",
|
|
3
|
+
"version": "0.0.22",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"files": [
|
|
7
|
+
"/dist"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"start": "NODE_ENV=development webpack build --config ./webpack.config.js --watch",
|
|
11
|
+
"build": "NODE_ENV=development webpack build --config ./webpack.config.js",
|
|
12
|
+
"build:prod": "rm -rf dist && NODE_ENV=production webpack build --config ./webpack.config.js",
|
|
13
|
+
"lint": "eslint '**/*.{js,ts,tsx}'",
|
|
14
|
+
"test": "jest"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@prose-reader/shared": "^0.0.4",
|
|
18
|
+
"@types/xmldoc": "^1.1.5",
|
|
19
|
+
"buffer": "6.0.3",
|
|
20
|
+
"xmldoc": "^1.1.2"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@babel/preset-typescript": "^7.16.0",
|
|
24
|
+
"@types/jest": "^27.0.3",
|
|
25
|
+
"@typescript-eslint/eslint-plugin": "^5.0.0",
|
|
26
|
+
"@typescript-eslint/parser": "^5.0.0",
|
|
27
|
+
"eslint": "^7.32.0",
|
|
28
|
+
"eslint-config-standard": "^16.0.3",
|
|
29
|
+
"eslint-plugin-import": "^2.25.2",
|
|
30
|
+
"eslint-plugin-jest": "^25.3.0",
|
|
31
|
+
"eslint-plugin-node": "^11.1.0",
|
|
32
|
+
"eslint-plugin-promise": "^5.1.1",
|
|
33
|
+
"jest": "^27.3.1",
|
|
34
|
+
"ts-loader": "^9.2.6",
|
|
35
|
+
"typescript": "*",
|
|
36
|
+
"webpack": "^5.64.3",
|
|
37
|
+
"webpack-cli": "^4.9.1",
|
|
38
|
+
"webpack-dev-server": "^4.6.0"
|
|
39
|
+
},
|
|
40
|
+
"gitHead": "a005ccf2d302179a488d3f5e79c1f043d3ce29de"
|
|
41
|
+
}
|