diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9c14962..d326fc5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,487 @@ dependencies: cheerio: specifier: 1.0.0-rc.12 version: registry.npmmirror.com/cheerio@1.0.0-rc.12 + mkanki: + specifier: github:Serifold/mkanki + version: github.com/Serifold/mkanki/bb2ce294ec79dec18f9f8eed50592726254befde packages: + /archiver-utils@2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.11 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 2.3.8 + dev: false + + /archiver@5.3.1: + resolution: {integrity: sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==} + engines: {node: '>= 10'} + dependencies: + archiver-utils: 2.1.0 + async: 3.2.4 + buffer-crc32: 0.2.13 + readable-stream: 3.6.2 + readdir-glob: 1.1.3 + tar-stream: 2.2.0 + zip-stream: 4.1.0 + dev: false + + /async@3.2.4: + resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + dev: false + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /better-sqlite3@8.5.0: + resolution: {integrity: sha512-vbPcv/Hx5WYdyNg/NbcfyaBZyv9s/NVbxb7yCeC5Bq1pVocNxeL2tZmSu3Rlm4IEOTjYdGyzWQgyx0OSdORBzw==} + requiresBuild: true + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.1 + dev: false + + /bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + dependencies: + file-uri-to-path: 1.0.0 + dev: false + + /bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: false + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: false + + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: false + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + dev: false + + /compress-commons@4.1.1: + resolution: {integrity: sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==} + engines: {node: '>= 10'} + dependencies: + buffer-crc32: 0.2.13 + crc32-stream: 4.0.2 + normalize-path: 3.0.0 + readable-stream: 3.6.2 + dev: false + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: false + + /core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: false + + /crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + dev: false + + /crc32-stream@4.0.2: + resolution: {integrity: sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==} + engines: {node: '>= 10'} + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.2 + dev: false + + /decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false + + /deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: false + + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + dev: false + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + + /expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + dev: false + + /file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + dev: false + + /fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + dev: false + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: false + + /github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + dev: false + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: false + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + dev: false + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: false + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + dev: false + + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: false + + /isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: false + + /lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + dependencies: + readable-stream: 2.3.8 + dev: false + + /lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: false + + /lodash.difference@4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + dev: false + + /lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + dev: false + + /lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: false + + /lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + dev: false + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: false + + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: false + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: false + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: false + + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: false + + /napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + dev: false + + /node-abi@3.46.0: + resolution: {integrity: sha512-LXvP3AqTIrtvH/jllXjkNVbYifpRbt9ThTtymSMSuHmhugQLAWr99QQFTm+ZRht9ziUvdGOgB+esme1C6iE6Lg==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: false + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + dev: false + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: false + + /prebuild-install@7.1.1: + resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + detect-libc: 2.0.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.46.0 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + dev: false + + /process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: false + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + + /rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + dev: false + + /readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: false + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + dependencies: + minimatch: 5.1.6 + dev: false + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: false + + /safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: false + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: false + + /simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + dev: false + + /simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + dev: false + + /string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: false + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: false + + /tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 2.2.0 + dev: false + + /tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + + /tmp@0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + dependencies: + rimraf: 3.0.2 + dev: false + + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: false + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + dev: false + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: false + + /zip-stream@4.1.0: + resolution: {integrity: sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==} + engines: {node: '>= 10'} + dependencies: + archiver-utils: 2.1.0 + compress-commons: 4.1.1 + readable-stream: 3.6.2 + dev: false + + github.com/Serifold/mkanki/bb2ce294ec79dec18f9f8eed50592726254befde: + resolution: {tarball: https://codeload.github.com/Serifold/mkanki/tar.gz/bb2ce294ec79dec18f9f8eed50592726254befde} + name: mkanki + version: 1.1.0 + dependencies: + archiver: 5.3.1 + better-sqlite3: 8.5.0 + tmp: 0.2.1 + dev: false + registry.npmmirror.com/bent@7.3.12: resolution: {integrity: sha512-T3yrKnVGB63zRuoco/7Ybl7BwwGZR0lceoVG5XmQyMIH9s19SV5m+a8qam4if0zQuAmOQTyPTPmsQBdAorGK3w==, registry: https://registry.npmjs.org/, tarball: https://registry.npmmirror.com/bent/-/bent-7.3.12.tgz} name: bent diff --git a/src/mkanki.js b/src/mkanki.js index 4e5e8d9..e76d30d 100644 --- a/src/mkanki.js +++ b/src/mkanki.js @@ -1,27 +1,28 @@ -const fs = require('fs'); -const path = require('path'); -const cheerio = require('cheerio'); -const anki = require('mkanki'); -const writeToLog = require('./utils/logger'); +const fs = require("fs"); +const path = require("path"); +const cheerio = require("cheerio"); +const anki = require("mkanki"); +const writeToLog = require("./utils/logger"); const directoryPath = __dirname; -const HTML_DIR = directoryPath + '/output/html/'; -const DEFAULT_DECK_NAME = 'IELTS-CamDict-Words'; -const DEFAULT_NOTE_TYPE_NAME = 'BasicCamCard'; -const DEFAULT_CSS_FILENAME = 'common.css'; +const HTML_DIR = directoryPath + "/output/html/"; +const DEFAULT_DECK_NAME = "IELTS-CamDict-Words"; +const DEFAULT_NOTE_TYPE_NAME = "BasicCamCard"; +const DEFAULT_CSS_FILENAME = "common.css"; +const DEFAULT_APKG_NAME = DEFAULT_DECK_NAME + ".apkg"; -const cssData = fs.readFileSync(HTML_DIR + DEFAULT_CSS_FILENAME, 'utf8'); +const cssData = fs.readFileSync(HTML_DIR + DEFAULT_CSS_FILENAME, "utf8"); const model = new anki.Model({ name: DEFAULT_NOTE_TYPE_NAME, id: Date.now().toString(), - flds: [{ name: 'Word' }, { name: 'Front' }, { name: 'Back' }], - req: [[0, 'all', [0]]], + flds: [{ name: "Word" }, { name: "Front" }, { name: "Back" }], + req: [[0, "all", [0]]], tmpls: [ { - name: 'Card 1', - qfmt: '{{Front}}', - afmt: '{{FrontSide}}\n\n
\n\n{{Back}}', + name: "Card 1", + qfmt: "{{Front}}", + afmt: "{{FrontSide}}\n\n
\n\n{{Back}}", }, ], css: cssData, @@ -29,121 +30,88 @@ const model = new anki.Model({ const deck = new anki.Deck(Date.now(), DEFAULT_DECK_NAME); const package = new anki.Package(); -async function processHtmlFiles() { - fs.readdir(HTML_DIR, async (err, files) => { - if (err) { - writeToLog(err.message); - return; - } - - async function addNote(file) { - if (path.extname(file) === '.html') { - const filePath = path.join(HTML_DIR, file); - fs.readFile(filePath, 'utf8', (err, data) => { - if (err) { - writeToLog(err.message); - return; - } - try { - const $ = cheerio.load(data); - let front = ''; - $('.pos-header.dpos-h') - .toArray() - .forEach((ele) => { - front += $(ele).html() + "
"; - }); - const back = $('body').html(); - const tags = $('.def-info.ddef-info') - .toArray() - .map((ele) => $(ele).find("span[class*='epp-xref dxref']").html()) - .filter((ele) => ele !== null); - let tagResult = null; - if (tags.length != 0) { - const tagsDictinct = [...new Set(tags)].sort(); - tagResult = tagsDictinct; +async function processHtmlFilesNew() { + try { + const files = await new Promise((resolve, reject) => { + fs.readdir(HTML_DIR, (err, files) => { + if (err) { + writeToLog(err.message); + reject(err); + } + resolve(files); + }); + }); + let cnt = 0; + function addNote(file) { + return new Promise((resolve, reject) => { + if (path.extname(file) === ".html") { + const currentWord = file.match(/^(.+)\.html$/)[1]; + const filePath = path.join(HTML_DIR, file); + fs.readFile(filePath, "utf8", (err, data) => { + if (err) { + writeToLog(err.message); + reject(err); + } else { + try { + const $ = cheerio.load(data); + let front = ""; + $(".pos-header.dpos-h") + .toArray() + .forEach((ele) => { + front += $(ele).html() + "
"; + }); + const back = $("body").html(); + if (!front || !back) { + throw new Error( + "EMPTY RESULT OF EXTRACTING FRONT OR BACK NOTES" + ); + } + const tags = $(".def-info.ddef-info") + .toArray() + .map((ele) => + $(ele).find("span[class*='epp-xref dxref']").html() + ) + .filter((ele) => ele !== null); + let tagResult = null; + if (tags.length != 0) { + const tagsDictinct = [...new Set(tags)].sort(); + tagResult = tagsDictinct; + } + deck.addNote(model.note([currentWord, front, back], tagResult)); + console.log( + `[INFO] ${++cnt}/${ + files.length - 1 + } CURRENT WORD: ${currentWord}` + ); + resolve(); + } catch (err) { + writeToLog(`[ERR] ERROR PROCESSSING ${file}: ${err.message}`); + reject(err); + } } - - // console.log(`deck: ${JSON.stringify(deck)}`) - deck.addNote( - model.note( - [file.match(/^(.+)\.html$/)[1], front, back], - tagResult - ) - ); - } catch (err) { - writeToLog(`[ERR] Error processing ${file}: ${err.message}`); - } - }); - } - } - async function addNotes(_files) { - const res = await Promise.allSettled(_files.map(async (e) => await addNote(e))); - return res; + }); + } else { + resolve(); + } + }); } - - const result = await addNotes(files); - console.log(`addNotes() result: ${JSON.stringify(result)}`); - - // function asyncForEach(array, fn) { - // return new Promise((resolve) => { - // array.forEach((item) => { - // fn(item); - // }); - // resolve(); - // }); - // } - // async function addNote() { - // await asyncForEach(files, (file) => { - // if (path.extname(file) === '.html') { - // const filePath = path.join(HTML_DIR, file); - // fs.readFile(filePath, 'utf8', (err, data) => { - // if (err) { - // writeToLog(err.message); - // return; - // } - // try { - // const $ = cheerio.load(data); - // let front = ''; - // $('.pos-header.dpos-h') - // .toArray() - // .forEach((ele) => { - // front += $(ele).html() + "
"; - // }); - // const back = $('body').html(); - // const tags = $('.def-info.ddef-info') - // .toArray() - // .map((ele) => - // $(ele).find("span[class*='epp-xref dxref']").html() - // ) - // .filter((ele) => ele !== null); - // let tagResult = null; - // if (tags.length != 0) { - // const tagsDictinct = [...new Set(tags)].sort(); - // tagResult = tagsDictinct; - // } - - // // console.log(`deck: ${JSON.stringify(deck)}`) - // deck.addNote( - // model.note( - // [file.match(/^(.+)\.html$/)[1], front, back], - // tagResult - // ) - // ); - // } catch (err) { - // writeToLog(`[ERR] Error processing ${file}: ${err.message}`); - // } - // }); - // } - // }); - // } - // addNote() - }); + const result = await Promise.allSettled(files.map(addNote)); + result.forEach((e, i) => { + if (e.status === "rejected") { + writeToLog( + `[ERR] ADD ${files[i].match(/^(.+)\.html$/)[1]} FAILED: ${e.reason}` + ); + } + }); + } catch (err) { + writeToLog(`[ERR] UNKNONW ERROR ${err.message}`); + } } async function convert() { - await processHtmlFiles(); + await processHtmlFilesNew(); package.addDeck(deck); - package.writeToFile('test.apkg'); + package.writeToFile(DEFAULT_APKG_NAME); } convert(); diff --git a/src/utils/logger.js b/src/utils/logger.js index eabc104..3a7627e 100644 --- a/src/utils/logger.js +++ b/src/utils/logger.js @@ -1,13 +1,79 @@ const fs = require("fs"); const LOG_FILE = "log_html2notes.txt"; -function writeToLog(message) { - console.log(message); - const logMessage = `[${new Date().toLocaleString()}] ${message}\n`; - fs.appendFile("src/output/log/" + LOG_FILE, logMessage, (err) => { +const DEFAULT_ROOT_DIR = "src/output/log/"; + +function write(message) { + fs.appendFile(DEFAULT_ROOT_DIR + LOG_FILE, message, (err) => { if (err) { - console.error("[LOG-ERR] Failed to write to log file:", err); + console.error("[LOG-ERR] WRITE TO LOG FAILED:", err); } }); } +function logFormatter(type, logTime, message, callerName) { + const basicFormat = `[${type}] [${logTime}] - ${message}`; + if ( + callerName === null || + callerName === undefined || + callerName === "" || + callerName.trim() === "" + ) { + return basicFormat + "\n"; + } + return basicFormat + ` - [${callerName}]\n`; +} + +function writeToLog(message) { + const logTime = new Date().toLocaleString(); + const caller = arguments.callee.caller; + let callerName = caller.name; + if (caller && callerName === "") { + callerName = "ANONYMOUS ARROW FUNCTION"; + } + if (!fs.existsSync(DEFAULT_ROOT_DIR)) { + try { + fs.mkdirSync(DEFAULT_ROOT_DIR); + const successInfo = logFormatter( + "INFO", + logTime, + "DIR LOG CREATED", + callerName + ); + console.log(successInfo); + write(successInfo); + } catch (err) { + const msg = logFormatter( + "ERR", + logTime, + `MKDIR FAILED ` + err.message, + callerName + ); + console.err(msg); + write(msg); + } + } else { + console.log( + logFormatter("INFO", logTime, "LOG DIR ALREADY EXISTS", callerName) + ); + } + const typeAndMsgArr = splitHelper(message); + const type = typeAndMsgArr[0] ?? "ERR"; + const msgBody = typeAndMsgArr[1]; + const logMessage = logFormatter(type, logTime, msgBody, callerName); + console.log(logMessage); + write(logMessage); +} + +function splitHelper(errMessage) { + const regex = /\[(.*?)\]/; + const match = errMessage.match(regex); + if (match) { + const prefix = match[1]; + const remaining = errMessage.replace(match[0], "").trim(); + return [prefix, remaining]; + } else { + return [null, errMessage]; + } +} + module.exports = writeToLog;