main: parallelize image processing

This reduces the procsesing time of the 1to10.note from about 7 seconds
to 1.5s. It should be significant for anyone with note files with many
pages.
This commit is contained in:
Brandon Philips 2024-12-28 00:17:16 -08:00
parent 439506b58e
commit 9f3ed397d4
7 changed files with 346 additions and 55 deletions

View file

@ -1,6 +1,7 @@
import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
import inlineWorkerPlugin from "esbuild-plugin-inline-worker";
const banner =
`/*
@ -15,8 +16,12 @@ const context = await esbuild.context({
banner: {
js: banner,
},
entryPoints: ["main.ts"],
entryPoints: ["src/main.ts"],
alias: {
'supernote-typescript': 'supernote-typescript'
},
bundle: true,
plugins: [inlineWorkerPlugin()],
external: [
"obsidian",
"electron",

190
package-lock.json generated
View file

@ -9,6 +9,7 @@
"version": "2.3.0",
"license": "MIT",
"dependencies": {
"esbuild-plugin-inline-worker": "^0.1.1",
"image-js": "^0.35.5",
"supernote": "github:philips/supernote-typescript"
},
@ -189,7 +190,6 @@
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"android"
@ -205,7 +205,6 @@
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"android"
@ -221,7 +220,6 @@
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"android"
@ -237,7 +235,6 @@
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
@ -253,7 +250,6 @@
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"darwin"
@ -269,7 +265,6 @@
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
@ -285,7 +280,6 @@
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"freebsd"
@ -301,7 +295,6 @@
"cpu": [
"arm"
],
"dev": true,
"optional": true,
"os": [
"linux"
@ -317,7 +310,6 @@
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"linux"
@ -333,7 +325,6 @@
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"linux"
@ -349,7 +340,6 @@
"cpu": [
"loong64"
],
"dev": true,
"optional": true,
"os": [
"linux"
@ -365,7 +355,6 @@
"cpu": [
"mips64el"
],
"dev": true,
"optional": true,
"os": [
"linux"
@ -381,7 +370,6 @@
"cpu": [
"ppc64"
],
"dev": true,
"optional": true,
"os": [
"linux"
@ -397,7 +385,6 @@
"cpu": [
"riscv64"
],
"dev": true,
"optional": true,
"os": [
"linux"
@ -413,7 +400,6 @@
"cpu": [
"s390x"
],
"dev": true,
"optional": true,
"os": [
"linux"
@ -429,7 +415,6 @@
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"linux"
@ -445,7 +430,6 @@
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"netbsd"
@ -461,7 +445,6 @@
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"openbsd"
@ -477,7 +460,6 @@
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"sunos"
@ -493,7 +475,6 @@
"cpu": [
"arm64"
],
"dev": true,
"optional": true,
"os": [
"win32"
@ -509,7 +490,6 @@
"cpu": [
"ia32"
],
"dev": true,
"optional": true,
"os": [
"win32"
@ -525,7 +505,6 @@
"cpu": [
"x64"
],
"dev": true,
"optional": true,
"os": [
"win32"
@ -1567,12 +1546,13 @@
}
},
"node_modules/braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.0.1"
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
@ -1673,6 +1653,12 @@
"simple-swizzle": "^0.2.2"
}
},
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
"license": "MIT"
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -1681,10 +1667,11 @@
"peer": true
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"path-key": "^3.1.0",
@ -1765,7 +1752,6 @@
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.3.tgz",
"integrity": "sha512-9n3AsBRe6sIyOc6kmoXg2ypCLgf3eZSraWFRpnkto+svt8cZNuKTkb1bhQcitBcvIqjNiK7K0J3KPmwGSfkA8g==",
"dev": true,
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
@ -1798,6 +1784,16 @@
"@esbuild/win32-x64": "0.17.3"
}
},
"node_modules/esbuild-plugin-inline-worker": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/esbuild-plugin-inline-worker/-/esbuild-plugin-inline-worker-0.1.1.tgz",
"integrity": "sha512-VmFqsQKxUlbM51C1y5bRiMeyc1x2yTdMXhKB6S//++g9aCBg8TfGsbKxl5ZDkCGquqLY+RmEk93TBNd0i35dPA==",
"license": "MIT",
"dependencies": {
"esbuild": "latest",
"find-cache-dir": "^3.3.1"
}
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@ -2173,10 +2169,11 @@
}
},
"node_modules/fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
@ -2184,6 +2181,23 @@
"node": ">=8"
}
},
"node_modules/find-cache-dir": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
"integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
"license": "MIT",
"dependencies": {
"commondir": "^1.0.1",
"make-dir": "^3.0.2",
"pkg-dir": "^4.1.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/avajs/find-cache-dir?sponsor=1"
}
},
"node_modules/find-up": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
@ -2510,6 +2524,7 @@
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@ -2731,6 +2746,30 @@
"node": ">=10"
}
},
"node_modules/make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
"license": "MIT",
"dependencies": {
"semver": "^6.0.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/make-dir/node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/median-quickselect": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/median-quickselect/-/median-quickselect-1.0.1.tgz",
@ -2746,12 +2785,13 @@
}
},
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.2",
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@ -3080,6 +3120,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/pako": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
@ -3102,8 +3151,6 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"peer": true,
"engines": {
"node": ">=8"
}
@ -3155,6 +3202,70 @@
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/pkg-dir": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
"license": "MIT",
"dependencies": {
"find-up": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/pkg-dir/node_modules/find-up": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"license": "MIT",
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/pkg-dir/node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"license": "MIT",
"dependencies": {
"p-locate": "^4.1.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/pkg-dir/node_modules/p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"license": "MIT",
"dependencies": {
"p-try": "^2.0.0"
},
"engines": {
"node": ">=6"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/pkg-dir/node_modules/p-locate": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"license": "MIT",
"dependencies": {
"p-limit": "^2.2.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@ -3531,6 +3642,7 @@
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},

View file

@ -24,6 +24,7 @@
"typescript": "4.7.4"
},
"dependencies": {
"esbuild-plugin-inline-worker": "^0.1.1",
"image-js": "^0.35.5",
"supernote": "github:philips/supernote-typescript"
}

View file

@ -1,5 +1,8 @@
import { App, Modal, TFolder, TFile, Plugin, PluginSettingTab, Editor, Setting, MarkdownView, WorkspaceLeaf, FileView } from 'obsidian';
import { SupernoteX, toImage, fetchMirrorFrame } from 'supernote-typescript';
import { App, Modal, TFile, Plugin, PluginSettingTab, Editor, Setting, MarkdownView, WorkspaceLeaf, FileView } from 'obsidian';
import { SupernoteX, fetchMirrorFrame } from 'supernote-typescript';
import { Image } from 'image-js'
import { SupernoteWorkerMessage, SupernoteWorkerResponse } from './myworker.worker';
import Worker from 'myworker.worker';
interface SupernotePluginSettings {
mirrorIP: string;
@ -32,6 +35,107 @@ function generateTimestamp(): string {
return timestamp;
}
function dataUrlToBuffer(dataUrl: string): ArrayBuffer {
// Remove data URL prefix (e.g., "data:image/png;base64,")
const base64 = dataUrl.split(',')[1];
// Convert base64 to binary string
const binaryString = atob(base64);
// Create buffer and view
const bytes = new Uint8Array(binaryString.length);
// Convert binary string to buffer
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
}
export class WorkerPool {
private workers: Worker[];
constructor(private maxWorkers: number = navigator.hardwareConcurrency) {
this.workers = Array(maxWorkers).fill(null).map(() =>
new Worker()
);
}
private processChunk(worker: Worker, note: SupernoteX, pageNumbers: number[]): Promise<any[]> {
return new Promise((resolve, reject) => {
const startTime = Date.now();
worker.onmessage = (e: MessageEvent<SupernoteWorkerResponse>) => {
const duration = Date.now() - startTime;
//console.log(`Processed pages ${pageNumbers.join(',')} in ${duration}ms`);
if (e.data.error) {
reject(new Error(e.data.error));
} else {
resolve(e.data.images);
}
};
worker.onerror = (error) => {
console.error('Worker error:', error);
reject(error);
};
const message: SupernoteWorkerMessage = {
type: 'convert',
note,
pageNumbers
};
worker.postMessage(message);
});
}
async processPages(note: SupernoteX, allPageNumbers: number[]): Promise<any[]> {
//console.time('Total processing time');
// Split pages into chunks based on number of workers
const chunkSize = Math.ceil(allPageNumbers.length / this.workers.length);
const chunks: number[][] = [];
for (let i = 0; i < allPageNumbers.length; i += chunkSize) {
chunks.push(allPageNumbers.slice(i, i + chunkSize));
}
//console.log(`Processing ${allPageNumbers.length} pages in ${chunks.length} chunks`);
// Process chunks in parallel using available workers
const results = await Promise.all(
chunks.map((chunk, index) =>
this.processChunk(this.workers[index % this.workers.length], note, chunk)
)
);
//console.timeEnd('Total processing time');
return results.flat();
}
terminate() {
this.workers.forEach(worker => worker.terminate());
this.workers = [];
}
}
export class ImageConverter {
private workerPool: WorkerPool;
constructor(maxWorkers = navigator.hardwareConcurrency) { // Default to 4 workers
this.workerPool = new WorkerPool(maxWorkers);
}
async convertToImages(note: SupernoteX, pageNumbers?: number[]): Promise<any[]> {
const pages = pageNumbers ?? Array.from({length: note.pages.length}, (_, i) => i+1);
const results = await this.workerPool.processPages(note, pages);
return results;
}
terminate() {
this.workerPool.terminate();
}
}
class VaultWriter {
app: App;
settings: SupernotePluginSettings;
@ -74,11 +178,21 @@ class VaultWriter {
}
async writeImageFiles(file: TFile, sn: SupernoteX): Promise<TFile[]> {
let images = await toImage(sn);
let images: string[] = [];
const converter = new ImageConverter();
try {
images = await converter.convertToImages(sn);
} finally {
// Clean up the worker when done
converter.terminate();
}
let imgs: TFile[] = [];
for (let i = 0; i < images.length; i++) {
let filename = await this.app.fileManager.getAvailablePathForAttachment(`${file.basename}-${i}.png`);
imgs.push(await this.app.vault.createBinary(filename, images[i].toBuffer()));
const buffer = dataUrlToBuffer(images[i]);
imgs.push(await this.app.vault.createBinary(filename, buffer));
}
return imgs;
}
@ -128,7 +242,15 @@ export class SupernoteView extends FileView {
const note = await this.app.vault.readBinary(file);
let sn = new SupernoteX(new Uint8Array(note));
let images = await toImage(sn);
let images: string[] = [];
const converter = new ImageConverter();
try {
images = await converter.convertToImages(sn);
} finally {
// Clean up the worker when done
converter.terminate();
}
if (this.settings.showExportButtons) {
const exportNoteBtn = container.createEl("p").createEl("button", {
@ -163,7 +285,7 @@ export class SupernoteView extends FileView {
}
for (let i = 0; i < images.length; i++) {
const imageDataUrl = images[i].toDataURL();
const imageDataUrl = images[i];
const pageContainer = container.createEl("div", {
cls: 'page-container',
@ -214,7 +336,8 @@ export class SupernoteView extends FileView {
saveButton.addEventListener("click", async () => {
const filename = await this.app.fileManager.getAvailablePathForAttachment(`${file.basename}}.png`);
await this.app.vault.createBinary(filename, images[i].toBuffer());
const buffer = dataUrlToBuffer(imageDataUrl);
await this.app.vault.createBinary(filename, buffer);
});
}
}
@ -472,7 +595,7 @@ class SupernoteSettingTab extends PluginSettingTab {
await this.plugin.saveSettings();
})
);
new Setting(containerEl)
.setName('Max image side length in .note files')
.setDesc('Maximum width and height (in pixels) of the note image when viewing .note files. Does not affect exported images and markdown.')

45
src/myworker.worker.ts Normal file
View file

@ -0,0 +1,45 @@
import { SupernoteX, toImage } from 'supernote-typescript';
import { Image } from 'image-js'
export {};
export type SupernoteWorkerMessage = {
type: 'convert';
note: SupernoteX;
pageNumbers?: number[];
}
export type SupernoteWorkerResponse = {
type: 'result';
images: string[];
error?: string;
}
self.onmessage = async (e: MessageEvent<SupernoteWorkerMessage>) => {
try {
const { type, note, pageNumbers } = e.data;
if (type === 'convert') {
const results = await toImage(note, pageNumbers);
// Convert canvas/images to data URLs before sending
const dataUrls = results.map(result => {
if (result && typeof result.toDataURL === 'function') {
return result.toDataURL();
}
console.error('Result is not a canvas or does not support toDataURL');
return null;
});
self.postMessage({
type: 'result',
images: dataUrls
});
}
} catch (error) {
self.postMessage({
type: 'result',
images: [],
error: error instanceof Error ? error.message : 'Unknown error occurred'
});
}
};

4
src/worker.d.ts vendored Normal file
View file

@ -0,0 +1,4 @@
declare module 'myworker.worker' {
const WorkerFactory: new () => Worker;
export default WorkerFactory;
}

View file

@ -1,6 +1,9 @@
{
"compilerOptions": {
"baseUrl": ".",
"baseUrl": "./src/",
"paths": {
"supernote-typescript": ["../supernote-typescript/src/"]
},
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
@ -11,18 +14,16 @@
"moduleResolution": "node",
"importHelpers": true,
"isolatedModules": true,
"strictNullChecks": true,
"strictNullChecks": true,
"lib": [
"DOM",
"ES5",
"ES6",
"ES7"
"ES7",
"DOM.Iterable"
]
},
"exclude": [
"supernote-typescript/**/*.ts"
],
"include": [
"**/*.ts"
"supernote-typescript/tests/*.ts"
]
}