diff --git a/babel.config.js b/babel.config.js index e955840..e5fda6f 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,5 +1,15 @@ module.exports = { presets: [ - '@vue/cli-plugin-babel/preset' + '@vue/cli-plugin-babel/preset', + ['@babel/preset-env', { + targets: { + node: 'current', + browsers: ['> 1%', 'last 2 versions', 'not dead'] + } + }] + ], + plugins: [ + '@babel/plugin-proposal-optional-chaining', + '@babel/plugin-proposal-class-properties' ] } diff --git a/package-lock.json b/package-lock.json index 9a5a3dc..fca40ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,6 +71,12 @@ "semver": "^6.3.1" }, "dependencies": { + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "debug": { "version": "4.4.1", "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.1.tgz", @@ -123,15 +129,6 @@ "semver": "^6.3.1" }, "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, "semver": { "version": "6.3.1", "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", @@ -408,6 +405,17 @@ "@babel/plugin-syntax-decorators": "^7.27.1" } }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, "@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmmirror.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", @@ -459,6 +467,15 @@ "@babel/helper-plugin-utils": "^7.27.1" } }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, "@babel/plugin-syntax-unicode-sets-regex": { "version": "7.18.6", "resolved": "https://registry.npmmirror.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", @@ -1578,12 +1595,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -1766,14 +1777,6 @@ "integrity": "sha512-T7VNNlYVM1SgQ+VsMYhnDkcGmWhQdL0bDyGm5TlQ3GBXnJscEClUUOKduWTmm2zCnvNLC1hc3JpuXjs/nFOc5w==", "dev": true }, - "@swc/helpers": { - "version": "0.3.17", - "resolved": "https://registry.npmmirror.com/@swc/helpers/-/helpers-0.3.17.tgz", - "integrity": "sha512-tb7Iu+oZ+zWJZ3HJqwx8oNwSDIU440hmVMDPhpACWQWnrZHK99Bxs70gT1L2dnr5Hg50ZRWEFkQCAnOVVV0z1Q==", - "requires": { - "tslib": "^2.4.0" - } - }, "@szmarczak/http-timer": { "version": "4.0.6", "resolved": "https://registry.npmmirror.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", @@ -2026,14 +2029,6 @@ "dev": true, "requires": { "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "@types/webpack": { @@ -2048,14 +2043,6 @@ "@types/webpack-sources": "*", "anymatch": "^3.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "@types/webpack-dev-server": { @@ -2385,12 +2372,6 @@ "integrity": "sha512-DUmfdkG3pCdkP7Iznd87RfE9Qm42mgp2hcrNcYQYSru1W1gX2dG/JcW8bxmeGSa06lsxi9LEIc/QD1yPajSCZw==", "dev": true }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2591,15 +2572,6 @@ "chalk": "^2.0.1" } }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-1.2.0.tgz", @@ -2722,6 +2694,17 @@ "magic-string": "^0.30.17", "postcss": "^8.5.6", "source-map-js": "^1.2.1" + }, + "dependencies": { + "magic-string": { + "version": "0.30.18", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.18.tgz", + "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", + "dev": true, + "requires": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + } } }, "@vue/compiler-ssr": { @@ -2767,6 +2750,15 @@ "yallist": "^2.1.2" } }, + "merge-source-map": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/merge-source-map/-/merge-source-map-1.1.0.tgz", + "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + } + }, "picocolors": { "version": "0.2.1", "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-0.2.1.tgz", @@ -2783,12 +2775,6 @@ "source-map": "^0.6.1" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmmirror.com/yallist/-/yallist-2.1.2.tgz", @@ -3026,16 +3012,24 @@ } }, "acorn": { - "version": "6.4.2", - "resolved": "https://registry.npmmirror.com/acorn/-/acorn-6.4.2.tgz", - "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", - "dev": true + "version": "7.4.1", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmmirror.com/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } }, "acorn-walk": { "version": "7.2.0", "resolved": "https://registry.npmmirror.com/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" }, "address": { "version": "1.2.2", @@ -3117,6 +3111,12 @@ "integrity": "sha512-0FcBfdcmaumGPQ0qPn7Q5qTgz/ooXgIyp1rf8ik5bGX8mpE2YHjC0P/eyQvxu1GURYQgq9ozf2mteQ5ZD9YiyQ==", "dev": true }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "optional": true + }, "ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/ansi-align/-/ansi-align-3.0.1.tgz", @@ -3351,6 +3351,7 @@ "version": "1.0.2", "resolved": "https://registry.npmmirror.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, "requires": { "call-bound": "^1.0.3", "is-array-buffer": "^3.0.5" @@ -3362,6 +3363,11 @@ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "dev": true }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha512-GQTc6Uupx1FCavi5mPzBvVT7nEOeWMmUA9P95wpfpW1XwMSKs+KaymD5C2Up7KAUKg/mYwbsUYzdZWcoajlNZg==" + }, "array-union": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/array-union/-/array-union-1.0.2.tgz", @@ -3481,6 +3487,58 @@ "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==", "dev": true }, + "ast-transform": { + "version": "0.0.0", + "resolved": "https://registry.npmmirror.com/ast-transform/-/ast-transform-0.0.0.tgz", + "integrity": "sha512-e/JfLiSoakfmL4wmTGPjv0HpTICVmxwXgYOB8x+mzozHL8v+dSfCbrJ8J8hJ0YBP0XcYu1aLZ6b/3TnxNK3P2A==", + "requires": { + "escodegen": "~1.2.0", + "esprima": "~1.0.4", + "through": "~2.3.4" + }, + "dependencies": { + "escodegen": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/escodegen/-/escodegen-1.2.0.tgz", + "integrity": "sha512-yLy3Cc+zAC0WSmoT2fig3J87TpQ8UaZGx8ahCAs9FL8qNbyV7CVyPKS74DG4bsHiL5ew9sxdYx131OkBQMFnvA==", + "requires": { + "esprima": "~1.0.4", + "estraverse": "~1.5.0", + "esutils": "~1.0.0", + "source-map": "~0.1.30" + } + }, + "esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==" + }, + "estraverse": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-1.5.1.tgz", + "integrity": "sha512-FpCjJDfmo3vsc/1zKSeqR5k42tcIhxFIlvq+h9j0fO2q/h2uLKyweq7rYJ+0CoVvrGQOxIS5wyBrW/+vF58BUQ==" + }, + "esutils": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/esutils/-/esutils-1.0.0.tgz", + "integrity": "sha512-x/iYH53X3quDwfHRz4y8rn4XcEwwCJeWsul9pF1zldMbGtgOtMNBEOuYWwB1EQlK2LRa1fev3YAgym/RElp5Cg==" + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "optional": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "ast-types": { + "version": "0.7.8", + "resolved": "https://registry.npmmirror.com/ast-types/-/ast-types-0.7.8.tgz", + "integrity": "sha512-RIOpVnVlltB6PcBJ5BMLx+H+6JJ/zjDGU0t7f0L6c2M1dqcK92VQopLBlPQ9R80AVXelfqYgjcPLtHtDbNFg0Q==" + }, "async": { "version": "3.2.6", "resolved": "https://registry.npmmirror.com/async/-/async-3.2.6.tgz", @@ -3567,12 +3625,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -3580,6 +3632,7 @@ "version": "1.0.7", "resolved": "https://registry.npmmirror.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, "requires": { "possible-typed-array-names": "^1.0.0" } @@ -4011,6 +4064,17 @@ } } }, + "brfs": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/brfs/-/brfs-2.0.2.tgz", + "integrity": "sha512-IrFjVtwu4eTJZyu8w/V2gxU7iLTtcHih67sgEdzrhjLBMHp2uYefUBfdM4k2UvcuWMgV7PQDZHSLeNWnLFKWVQ==", + "requires": { + "quote-stream": "^1.0.1", + "resolve": "^1.1.5", + "static-module": "^3.0.2", + "through2": "^2.0.0" + } + }, "brorand": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/brorand/-/brorand-1.1.0.tgz", @@ -4025,6 +4089,21 @@ "base64-js": "^1.1.2" } }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmmirror.com/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg==" + } + } + }, "browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmmirror.com/browserify-aes/-/browserify-aes-1.2.0.tgz", @@ -4062,6 +4141,16 @@ "safe-buffer": "^5.1.2" } }, + "browserify-optional": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/browserify-optional/-/browserify-optional-1.0.1.tgz", + "integrity": "sha512-VrhjbZ+Ba5mDiSYEuPelekQMfTbhcA2DhLk2VQWqdcCROWeFqlTcXZ7yfRkXCIl8E+g4gINJYJiRB7WEtfomAQ==", + "requires": { + "ast-transform": "0.0.0", + "ast-types": "^0.7.0", + "browser-resolve": "^1.8.1" + } + }, "browserify-rsa": { "version": "4.1.1", "resolved": "https://registry.npmmirror.com/browserify-rsa/-/browserify-rsa-4.1.1.tgz", @@ -4114,6 +4203,14 @@ "dev": true, "requires": { "pako": "~1.0.5" + }, + "dependencies": { + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + } } }, "browserslist": { @@ -4144,11 +4241,15 @@ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", "dev": true }, + "buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==" + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmmirror.com/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "buffer-indexof": { "version": "1.1.1", @@ -4309,6 +4410,12 @@ "once": "^1.3.0" } }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, "minimatch": { "version": "5.1.6", "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz", @@ -4743,14 +4850,6 @@ "dev": true, "requires": { "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "clean-stack": { @@ -4930,8 +5029,7 @@ "clone": { "version": "1.0.4", "resolved": "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" }, "clone-response": { "version": "1.0.3", @@ -5166,7 +5264,6 @@ "version": "1.6.2", "resolved": "https://registry.npmmirror.com/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -5255,10 +5352,9 @@ "dev": true }, "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "version": "1.9.0", + "resolved": "https://registry.npmmirror.com/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, "cookie": { "version": "0.7.1", @@ -5428,15 +5524,6 @@ "path-exists": "^3.0.0" } }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz", @@ -5642,9 +5729,9 @@ } }, "crypto-js": { - "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + "version": "3.3.0", + "resolved": "https://registry.npmmirror.com/crypto-js/-/crypto-js-3.3.0.tgz", + "integrity": "sha512-DIT51nX0dCfKltpRiXV+/TVZq+Qq2NgF4644+K7Ttnla7zEzqc+kjJyiB96BHNyUTBxyjzRcZYpUdZa+QAqi6Q==" }, "crypto-random-string": { "version": "2.0.0", @@ -5683,12 +5770,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -5754,12 +5835,6 @@ "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -5789,14 +5864,6 @@ "requires": { "mdn-data": "2.0.4", "source-map": "^0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "css-what": { @@ -5838,12 +5905,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -5900,12 +5961,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -5945,12 +6000,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -5984,12 +6033,6 @@ "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -5999,6 +6042,20 @@ "integrity": "sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==", "dev": true }, + "d": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/d/-/d-1.0.2.tgz", + "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==", + "requires": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + } + }, + "dash-ast": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/dash-ast/-/dash-ast-2.0.1.tgz", + "integrity": "sha512-5TXltWJGc+RdnabUGzhRae1TRq6m4gr+3K2wQX0is5/F2yS6MJXJvLyI3ErAnsAXuJoGqvfVD5icRgim07DrxQ==" + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmmirror.com/dashdash/-/dashdash-1.14.1.tgz", @@ -6088,7 +6145,6 @@ "version": "1.1.2", "resolved": "https://registry.npmmirror.com/deep-equal/-/deep-equal-1.1.2.tgz", "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", - "dev": true, "requires": { "is-arguments": "^1.1.1", "is-date-object": "^1.0.5", @@ -6103,6 +6159,11 @@ "resolved": "https://registry.npmmirror.com/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" + }, "deepmerge": { "version": "1.5.2", "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-1.5.2.tgz", @@ -6507,6 +6568,14 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmmirror.com/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "requires": { + "readable-stream": "^2.0.2" + } + }, "duplexer3": { "version": "0.1.5", "resolved": "https://registry.npmmirror.com/duplexer3/-/duplexer3-0.1.5.tgz", @@ -6967,29 +7036,6 @@ "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, - "es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } - } - }, "es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -7021,6 +7067,17 @@ "is-symbol": "^1.0.4" } }, + "es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + } + }, "es6-error": { "version": "4.1.1", "resolved": "https://registry.npmmirror.com/es6-error/-/es6-error-4.1.1.tgz", @@ -7028,6 +7085,51 @@ "dev": true, "optional": true }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha512-mz3UqCh0uPCIqsw1SSAkB/p0rOzF/M0V++vyN7JqlPtSW/VsYgQBvVvqMLmfBuyMzTpLnNqi6JmcSizs4jy19A==", + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-set": { + "version": "0.1.6", + "resolved": "https://registry.npmmirror.com/es6-set/-/es6-set-0.1.6.tgz", + "integrity": "sha512-TE3LgGLDIBX332jq3ypv6bcOpkLO0AslAQo7p2VqX/1N46YNsvIWgvjojjSEnWEGWMhr1qUbYeTSir5J6mFHOw==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "es6-iterator": "~2.0.3", + "es6-symbol": "^3.1.3", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + } + }, + "es6-symbol": { + "version": "3.1.4", + "resolved": "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.4.tgz", + "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==", + "requires": { + "d": "^1.0.2", + "ext": "^1.7.0" + } + }, "escalade": { "version": "3.2.0", "resolved": "https://registry.npmmirror.com/escalade/-/escalade-3.2.0.tgz", @@ -7052,6 +7154,18 @@ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, + "escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmmirror.com/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, "eslint-scope": { "version": "4.0.3", "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-4.0.3.tgz", @@ -7062,11 +7176,21 @@ "estraverse": "^4.1.1" } }, + "esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmmirror.com/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" }, "esrecurse": { "version": "4.3.0", @@ -7088,8 +7212,12 @@ "estraverse": { "version": "4.3.0", "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "estree-is-function": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/estree-is-function/-/estree-is-function-1.0.0.tgz", + "integrity": "sha512-nSCWn1jkSq2QAtkaVLJZY2ezwcFO161HVc174zL1KPW3RJ+O6C3eJb8Nx7OXzvhoEv+nLgSR1g71oWUHUDTrJA==" }, "estree-walker": { "version": "2.0.2", @@ -7100,8 +7228,7 @@ "esutils": { "version": "2.0.3", "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, "etag": { "version": "1.8.1", @@ -7109,6 +7236,15 @@ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, "event-pubsub": { "version": "4.3.0", "resolved": "https://registry.npmmirror.com/event-pubsub/-/event-pubsub-4.3.0.tgz", @@ -7339,6 +7475,14 @@ } } }, + "ext": { + "version": "1.7.0", + "resolved": "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz", + "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==", + "requires": { + "type": "^2.7.2" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", @@ -7496,6 +7640,11 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" + }, "faye-websocket": { "version": "0.11.4", "resolved": "https://registry.npmmirror.com/faye-websocket/-/faye-websocket-0.11.4.tgz", @@ -7687,62 +7836,28 @@ "dev": true }, "fontkit": { - "version": "1.9.0", - "resolved": "https://registry.npmmirror.com/fontkit/-/fontkit-1.9.0.tgz", - "integrity": "sha512-HkW/8Lrk8jl18kzQHvAw9aTHe1cqsyx5sDnxncx652+CIfhawokEPkeM3BoIC+z/Xv7a0yMr0f3pRRwhGH455g==", + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/fontkit/-/fontkit-1.8.1.tgz", + "integrity": "sha512-BsNCjDoYRxmNWFdAuK1y9bQt+igIxGtTC9u/jSFjR9MKhmI00rP1fwSvERt+5ddE82544l0XH5mzXozQVUy2Tw==", "requires": { - "@swc/helpers": "^0.3.13", - "brotli": "^1.3.2", - "clone": "^2.1.2", - "deep-equal": "^2.0.5", + "babel-runtime": "^6.26.0", + "brfs": "^2.0.0", + "brotli": "^1.2.0", + "browserify-optional": "^1.0.1", + "clone": "^1.0.4", + "deep-equal": "^1.0.0", "dfa": "^1.2.0", - "restructure": "^2.0.1", - "tiny-inflate": "^1.0.3", - "unicode-properties": "^1.3.1", - "unicode-trie": "^2.0.0" - }, - "dependencies": { - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/clone/-/clone-2.1.2.tgz", - "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==" - }, - "deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmmirror.com/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "requires": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - } - }, - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" - } + "restructure": "^0.5.3", + "tiny-inflate": "^1.0.2", + "unicode-properties": "^1.2.2", + "unicode-trie": "^0.3.0" } }, "for-each": { "version": "0.3.5", "resolved": "https://registry.npmmirror.com/for-each/-/for-each-0.3.5.tgz", "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, "requires": { "is-callable": "^1.2.7" } @@ -7965,6 +8080,11 @@ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true }, + "get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" + }, "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -8228,8 +8348,7 @@ "has": { "version": "1.0.4", "resolved": "https://registry.npmmirror.com/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==" }, "has-ansi": { "version": "2.0.0", @@ -8243,7 +8362,8 @@ "has-bigints": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==" + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true }, "has-flag": { "version": "4.0.0", @@ -8788,12 +8908,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -8987,6 +9101,7 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/internal-slot/-/internal-slot-1.1.0.tgz", "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, "requires": { "es-errors": "^1.3.0", "hasown": "^2.0.2", @@ -9045,6 +9160,7 @@ "version": "3.0.5", "resolved": "https://registry.npmmirror.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz", "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, "requires": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -9074,6 +9190,7 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/is-bigint/-/is-bigint-1.1.0.tgz", "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, "requires": { "has-bigints": "^1.0.2" } @@ -9091,6 +9208,7 @@ "version": "1.2.2", "resolved": "https://registry.npmmirror.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz", "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, "requires": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -9105,7 +9223,8 @@ "is-callable": { "version": "1.2.7", "resolved": "https://registry.npmmirror.com/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true }, "is-ci": { "version": "2.0.0", @@ -9134,7 +9253,6 @@ "version": "2.16.1", "resolved": "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "requires": { "hasown": "^2.0.2" } @@ -9273,7 +9391,8 @@ "is-map": { "version": "2.0.3", "resolved": "https://registry.npmmirror.com/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==" + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true }, "is-negative-zero": { "version": "2.0.3", @@ -9311,6 +9430,7 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/is-number-object/-/is-number-object-1.1.1.tgz", "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, "requires": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -9381,12 +9501,14 @@ "is-set": { "version": "2.0.3", "resolved": "https://registry.npmmirror.com/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==" + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true }, "is-shared-array-buffer": { "version": "1.0.4", "resolved": "https://registry.npmmirror.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, "requires": { "call-bound": "^1.0.3" } @@ -9401,6 +9523,7 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/is-string/-/is-string-1.1.1.tgz", "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, "requires": { "call-bound": "^1.0.3", "has-tostringtag": "^1.0.2" @@ -9410,6 +9533,7 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/is-symbol/-/is-symbol-1.1.1.tgz", "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, "requires": { "call-bound": "^1.0.2", "has-symbols": "^1.1.0", @@ -9440,7 +9564,8 @@ "is-weakmap": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==" + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true }, "is-weakref": { "version": "1.1.1", @@ -9455,6 +9580,7 @@ "version": "2.0.4", "resolved": "https://registry.npmmirror.com/is-weakset/-/is-weakset-2.0.4.tgz", "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, "requires": { "call-bound": "^1.0.3", "get-intrinsic": "^1.2.6" @@ -9535,11 +9661,6 @@ "supports-color": "^7.0.0" } }, - "jpeg-exif": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/jpeg-exif/-/jpeg-exif-1.1.4.tgz", - "integrity": "sha512-a+bKEcCjtuW5WTdgeXFzswSrdqi0jk4XlEtZlx5A94wCoBpFjfFTbo/Tra5SpNCl/YFZPvcV1dJc+TAYeg6ROQ==" - }, "jquery": { "version": "3.5.1", "resolved": "https://registry.npmmirror.com/jquery/-/jquery-3.5.1.tgz", @@ -9653,6 +9774,14 @@ "pako": "~1.0.2", "readable-stream": "~2.3.6", "setimmediate": "^1.0.5" + }, + "dependencies": { + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + } } }, "keyv": { @@ -9710,6 +9839,15 @@ "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", "dev": true }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, "lie": { "version": "3.3.0", "resolved": "https://registry.npmmirror.com/lie/-/lie-3.3.0.tgz", @@ -9732,6 +9870,15 @@ "version": "0.0.8", "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-0.0.8.tgz", "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==" + }, + "unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "requires": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } } } }, @@ -9850,18 +9997,20 @@ "dev": true }, "lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true - }, - "magic-string": { - "version": "0.30.18", - "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.18.tgz", - "integrity": "sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==", + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "requires": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.25.1", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.25.1.tgz", + "integrity": "sha512-sCuTz6pYom8Rlt4ISPFn6wuFodbKMIHUMv4Qko9P17dpxb7s52KJTmRuZZqHdGmLCK9AOcDare039nRIcfdkEg==", + "requires": { + "sourcemap-codec": "^1.4.1" } }, "make-dir": { @@ -9905,6 +10054,12 @@ "ssri": "^9.0.0" }, "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, "minipass": { "version": "3.3.6", "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", @@ -10001,19 +10156,17 @@ "dev": true }, "merge-source-map": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/merge-source-map/-/merge-source-map-1.1.0.tgz", - "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==", - "dev": true, + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha512-PGSmS0kfnTnMJCzJ16BLLCEe6oeYCamKFFdQKshi4BmM6FUwipjVOcBFGxqtQtirtAG4iZvHlqST9CpZKqlRjA==", "requires": { - "source-map": "^0.6.1" + "source-map": "^0.5.6" }, "dependencies": { "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true + "version": "0.5.7", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" } } }, @@ -10494,6 +10647,11 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmmirror.com/nice-try/-/nice-try-1.0.5.tgz", @@ -11036,6 +11194,7 @@ "version": "4.1.7", "resolved": "https://registry.npmmirror.com/object.assign/-/object.assign-4.1.7.tgz", "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, "requires": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", @@ -11143,6 +11302,19 @@ "is-wsl": "^1.1.0" } }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, "ora": { "version": "5.4.1", "resolved": "https://registry.npmmirror.com/ora/-/ora-5.4.1.tgz", @@ -11420,10 +11592,9 @@ } }, "pako": { - "version": "1.0.11", - "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "version": "0.2.9", + "resolved": "https://registry.npmmirror.com/pako/-/pako-0.2.9.tgz", + "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" }, "parallel-transform": { "version": "1.2.0", @@ -11552,8 +11723,7 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-to-regexp": { "version": "0.1.12", @@ -11632,13 +11802,12 @@ } }, "pdfkit": { - "version": "0.15.0", - "resolved": "https://registry.npmmirror.com/pdfkit/-/pdfkit-0.15.0.tgz", - "integrity": "sha512-Z0dx0sEPKLW2kbThS1SWZ0iSHlRPoFMpP+oSjNrtwRjsfGivwE+r6emyEFwQG/fx1Ri0AGUHmDcGOSMMlLLnSg==", + "version": "0.11.0", + "resolved": "https://registry.npmmirror.com/pdfkit/-/pdfkit-0.11.0.tgz", + "integrity": "sha512-1s9gaumXkYxcVF1iRtSmLiISF2r4nHtsTgpwXiK8Swe+xwk/1pm8FJjYqN7L3x13NsWnGyUFntWcO8vfqq+wwA==", "requires": { - "crypto-js": "^4.2.0", - "fontkit": "^1.8.1", - "jpeg-exif": "^1.1.4", + "crypto-js": "^3.1.9-1", + "fontkit": "^1.8.0", "linebreak": "^1.0.2", "png-js": "^1.0.0" } @@ -11746,7 +11915,8 @@ "possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmmirror.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==" + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true }, "postcss": { "version": "8.5.6", @@ -11785,12 +11955,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -11828,12 +11992,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -11868,12 +12026,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -11901,12 +12053,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -11934,12 +12080,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -11967,12 +12107,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12000,12 +12134,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12077,12 +12205,6 @@ "ajv-errors": "^1.0.0", "ajv-keywords": "^3.1.0" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12119,12 +12241,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12168,12 +12284,6 @@ "indexes-of": "^1.0.1", "uniq": "^1.0.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12208,12 +12318,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12250,12 +12354,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12294,12 +12392,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12341,12 +12433,6 @@ "indexes-of": "^1.0.1", "uniq": "^1.0.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12374,12 +12460,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12410,12 +12490,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12444,12 +12518,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12478,12 +12546,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12511,12 +12573,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12552,12 +12608,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12594,12 +12644,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12636,12 +12680,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12677,12 +12715,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12718,12 +12750,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12759,12 +12785,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12807,12 +12827,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12847,12 +12861,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12888,12 +12896,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12924,12 +12926,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -12966,12 +12962,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -13017,12 +13007,6 @@ "resolved": "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -13052,12 +13036,6 @@ "picocolors": "^0.2.1", "source-map": "^0.6.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -13067,6 +13045,11 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==" + }, "prepend-http": { "version": "1.0.4", "resolved": "https://registry.npmmirror.com/prepend-http/-/prepend-http-1.0.4.tgz", @@ -13271,6 +13254,16 @@ "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true }, + "quote-stream": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/quote-stream/-/quote-stream-1.0.2.tgz", + "integrity": "sha512-kKr2uQ2AokadPjvTyKJQad9xELbZwYzWlNfI3Uz2j/ib5u6H9lDP7fUUR//rMycd0gv4Z5P1qXMfXR8YpIxrjQ==", + "requires": { + "buffer-equal": "0.0.1", + "minimist": "^1.1.3", + "through2": "^2.0.0" + } + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz", @@ -13637,7 +13630,6 @@ "version": "1.22.10", "resolved": "https://registry.npmmirror.com/resolve/-/resolve-1.22.10.tgz", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, "requires": { "is-core-module": "^2.16.0", "path-parse": "^1.0.7", @@ -13691,9 +13683,12 @@ } }, "restructure": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/restructure/-/restructure-2.0.1.tgz", - "integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg==" + "version": "0.5.4", + "resolved": "https://registry.npmmirror.com/restructure/-/restructure-0.5.4.tgz", + "integrity": "sha512-wgNbkrlRpj0NarhUyiCfOXlu8DybDIYRV7MOieKGOl16N7NmAkjTtPhn2F4CBOsyRL8m6RWZLSzjJVVPAkJuiw==", + "requires": { + "browserify-optional": "^1.0.0" + } }, "ret": { "version": "0.1.15", @@ -13827,6 +13822,7 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz", "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, "requires": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -13863,6 +13859,20 @@ "ajv-keywords": "^3.5.2" } }, + "scope-analyzer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/scope-analyzer/-/scope-analyzer-2.1.2.tgz", + "integrity": "sha512-5cfCmsTYV/wPaRIItNxatw02ua/MThdIUNnUOCYp+3LSEJvnG804ANw2VLaavNILIfWXF1D1G2KNANkBBvInwQ==", + "requires": { + "array-from": "^2.1.1", + "dash-ast": "^2.0.1", + "es6-map": "^0.1.5", + "es6-set": "^0.1.5", + "es6-symbol": "^3.1.1", + "estree-is-function": "^1.0.0", + "get-assigned-identifiers": "^1.1.0" + } + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/select-hose/-/select-hose-2.0.0.tgz", @@ -14161,6 +14171,11 @@ } } }, + "shallow-copy": { + "version": "0.0.1", + "resolved": "https://registry.npmmirror.com/shallow-copy/-/shallow-copy-0.0.1.tgz", + "integrity": "sha512-b6i4ZpVuUxB9h5gfCxPiusKYkqTMOjEbBs4wMaFbkfia4yFv92UKZ6Df8WXcKbn08JNL/abvg3FnMAOfakDvUw==" + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", @@ -14192,6 +14207,7 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.0.tgz", "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, "requires": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", @@ -14204,6 +14220,7 @@ "version": "1.0.0", "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.0.tgz", "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, "requires": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" @@ -14213,6 +14230,7 @@ "version": "1.0.1", "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, "requires": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -14224,6 +14242,7 @@ "version": "1.0.2", "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, "requires": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -14314,6 +14333,12 @@ "resolved": "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true } } }, @@ -14457,10 +14482,9 @@ "dev": true }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true + "version": "0.6.1", + "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, "source-map-js": { "version": "1.2.1", @@ -14489,14 +14513,6 @@ "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "source-map-url": { @@ -14505,6 +14521,11 @@ "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmmirror.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, "spdx-correct": { "version": "3.2.0", "resolved": "https://registry.npmmirror.com/spdx-correct/-/spdx-correct-3.2.0.tgz", @@ -14712,6 +14733,32 @@ "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", "dev": true }, + "static-eval": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/static-eval/-/static-eval-2.1.1.tgz", + "integrity": "sha512-MgWpQ/ZjGieSVB3eOJVs4OA2LT/q1vx98KPCTTQPzq/aLr0YUXTsgryTXr4SLfR0ZfUUCiedM9n/ABeDIyy4mA==", + "requires": { + "escodegen": "^2.1.0" + }, + "dependencies": { + "escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "source-map": "~0.6.1" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + } + } + }, "static-extend": { "version": "0.1.2", "resolved": "https://registry.npmmirror.com/static-extend/-/static-extend-0.1.2.tgz", @@ -14733,6 +14780,27 @@ } } }, + "static-module": { + "version": "3.0.4", + "resolved": "https://registry.npmmirror.com/static-module/-/static-module-3.0.4.tgz", + "integrity": "sha512-gb0v0rrgpBkifXCa3yZXxqVmXDVE+ETXj6YlC/jt5VzOnGXR2C15+++eXuMDUYsePnbhf+lwW0pE1UXyOLtGCw==", + "requires": { + "acorn-node": "^1.3.0", + "concat-stream": "~1.6.0", + "convert-source-map": "^1.5.1", + "duplexer2": "~0.1.4", + "escodegen": "^1.11.1", + "has": "^1.0.1", + "magic-string": "0.25.1", + "merge-source-map": "1.0.4", + "object-inspect": "^1.6.0", + "readable-stream": "~2.3.3", + "scope-analyzer": "^2.0.1", + "shallow-copy": "~0.0.1", + "static-eval": "^2.0.5", + "through2": "~2.0.3" + } + }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz", @@ -14743,6 +14811,7 @@ "version": "1.1.0", "resolved": "https://registry.npmmirror.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, "requires": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" @@ -14911,12 +14980,6 @@ "indexes-of": "^1.0.1", "uniq": "^1.0.1" } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -14952,8 +15015,7 @@ "supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" }, "svg-tags": { "version": "1.0.0", @@ -15092,14 +15154,6 @@ "commander": "^2.20.0", "source-map": "~0.6.1", "source-map-support": "~0.5.12" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "terser-webpack-plugin": { @@ -15172,15 +15226,6 @@ "path-exists": "^3.0.0" } }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, "make-dir": { "version": "2.1.0", "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-2.1.0.tgz", @@ -15226,12 +15271,6 @@ "ajv-keywords": "^3.1.0" } }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "ssri": { "version": "6.0.2", "resolved": "https://registry.npmmirror.com/ssri/-/ssri-6.0.2.tgz", @@ -15323,11 +15362,15 @@ "resolved": "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-1.1.0.tgz", "integrity": "sha512-XH8UiPCQcWNuk2LYePibW/4qL97+ZQ1AN3FNXwZRBNPPowo/NRU5fAlDCSNBJIYCKbioZfuYtMhG4quqoJhVzg==" }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmmirror.com/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, "through2": { "version": "2.0.5", "resolved": "https://registry.npmmirror.com/through2/-/through2-2.0.5.tgz", "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, "requires": { "readable-stream": "~2.3.6", "xtend": "~4.0.1" @@ -15501,11 +15544,6 @@ "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==", "dev": true }, - "tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==" - }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmmirror.com/tty-browserify/-/tty-browserify-0.0.0.tgz", @@ -15534,6 +15572,19 @@ "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true }, + "type": { + "version": "2.7.3", + "resolved": "https://registry.npmmirror.com/type/-/type-2.7.3.tgz", + "integrity": "sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "requires": { + "prelude-ls": "~1.1.2" + } + }, "type-fest": { "version": "0.6.0", "resolved": "https://registry.npmmirror.com/type-fest/-/type-fest-0.6.0.tgz", @@ -15606,8 +15657,7 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmmirror.com/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" }, "typedarray-to-buffer": { "version": "3.1.5", @@ -15633,12 +15683,6 @@ "resolved": "https://registry.npmmirror.com/commander/-/commander-2.19.0.tgz", "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==", "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true } } }, @@ -15689,6 +15733,17 @@ "requires": { "base64-js": "^1.3.0", "unicode-trie": "^2.0.0" + }, + "dependencies": { + "unicode-trie": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/unicode-trie/-/unicode-trie-2.0.0.tgz", + "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "requires": { + "pako": "^0.2.5", + "tiny-inflate": "^1.0.0" + } + } } }, "unicode-property-aliases-ecmascript": { @@ -15698,19 +15753,12 @@ "dev": true }, "unicode-trie": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/unicode-trie/-/unicode-trie-2.0.0.tgz", - "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==", + "version": "0.3.1", + "resolved": "https://registry.npmmirror.com/unicode-trie/-/unicode-trie-0.3.1.tgz", + "integrity": "sha512-WgVuO0M2jDl7hVfbPgXv2LUrD81HM0bQj/bvLGiw6fJ4Zo8nNFnDrA0/hU2Te/wz6pjxCm5cxJwtLjo2eyV51Q==", "requires": { "pako": "^0.2.5", "tiny-inflate": "^1.0.0" - }, - "dependencies": { - "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmmirror.com/pako/-/pako-0.2.9.tgz", - "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==" - } } }, "union-value": { @@ -16366,12 +16414,6 @@ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, "ssri": { "version": "8.0.1", "resolved": "https://registry.npmmirror.com/ssri/-/ssri-8.0.1.tgz", @@ -16815,6 +16857,12 @@ "webpack-sources": "^1.4.1" }, "dependencies": { + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "dev": true + }, "json5": { "version": "1.0.2", "resolved": "https://registry.npmmirror.com/json5/-/json5-1.0.2.tgz", @@ -16869,12 +16917,6 @@ "ws": "^6.0.0" }, "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmmirror.com/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -17354,14 +17396,6 @@ "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } } }, "websocket-driver": { @@ -17394,6 +17428,7 @@ "version": "1.1.1", "resolved": "https://registry.npmmirror.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, "requires": { "is-bigint": "^1.1.0", "is-boolean-object": "^1.2.1", @@ -17435,6 +17470,7 @@ "version": "1.0.2", "resolved": "https://registry.npmmirror.com/which-collection/-/which-collection-1.0.2.tgz", "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, "requires": { "is-map": "^2.0.3", "is-set": "^2.0.3", @@ -17452,6 +17488,7 @@ "version": "1.1.19", "resolved": "https://registry.npmmirror.com/which-typed-array/-/which-typed-array-1.1.19.tgz", "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, "requires": { "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.8", @@ -17523,6 +17560,11 @@ "resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz", "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==" }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==" + }, "worker-farm": { "version": "1.7.0", "resolved": "https://registry.npmmirror.com/worker-farm/-/worker-farm-1.7.0.tgz", @@ -17626,8 +17668,7 @@ "xtend": { "version": "4.0.2", "resolved": "https://registry.npmmirror.com/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" }, "y18n": { "version": "5.0.8", diff --git a/package.json b/package.json index 1133d88..d510f9d 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,9 @@ "bootstrap": "4.6.0", "core-js": "3.6.5", "element-ui": "2.15.14", + "fontkit": "1.8.1", "jquery": "3.5.1", - "pdfkit": "^0.15.0", + "pdfkit": "0.11.0", "popper.js": "1.16.1", "sqlite3": "4.2.0", "vue": "2.6.11", @@ -34,6 +35,10 @@ "xlsx": "^0.18.5" }, "devDependencies": { + "@babel/core": "^7.28.3", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.21.0", + "@babel/preset-env": "^7.28.3", "@electron/rebuild": "3.2.13", "@vue/cli-plugin-babel": "4.5.19", "@vue/cli-plugin-router": "4.5.17", diff --git a/public/favicon.ico b/public/favicon.ico index df36fcf..d73bdbc 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..3441135 Binary files /dev/null and b/public/favicon.png differ diff --git a/src/App.vue b/src/App.vue index 6c26aa6..38aee27 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,9 +1,5 @@ - - Home | - About - @@ -16,17 +12,4 @@ text-align: center; color: #2c3e50; } - -#nav { - padding: 30px; -} - -#nav a { - font-weight: bold; - color: #2c3e50; -} - -#nav a.router-link-exact-active { - color: #42b983; -} diff --git a/src/assets/base.css b/src/assets/base.css new file mode 100644 index 0000000..1eb6e04 --- /dev/null +++ b/src/assets/base.css @@ -0,0 +1,31 @@ +/* color palette from */ +:root { + --primary-color: #4096ff; /* 定义主色调,与Element Plus保持一致 */ +} + +body { + min-height: 100vh; + color: var(--color-text); + background: var(--color-background); + transition: + color 0.5s, + background-color 0.5s; + line-height: 1.6; + font-family: + Inter, + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + Oxygen, + Ubuntu, + Cantarell, + 'Fira Sans', + 'Droid Sans', + 'Helvetica Neue', + sans-serif; + font-size: 15px; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} diff --git a/src/assets/bg.jpeg b/src/assets/bg.jpeg new file mode 100644 index 0000000..02281aa Binary files /dev/null and b/src/assets/bg.jpeg differ diff --git a/src/assets/logo.png b/src/assets/logo.png index f3d2503..5938c11 100644 Binary files a/src/assets/logo.png and b/src/assets/logo.png differ diff --git a/src/assets/logo.svg b/src/assets/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/src/assets/logo.svg @@ -0,0 +1 @@ + diff --git a/src/assets/main.css b/src/assets/main.css new file mode 100644 index 0000000..a152199 --- /dev/null +++ b/src/assets/main.css @@ -0,0 +1 @@ +@import './base.css'; diff --git a/src/background/db/exam.js b/src/background/db/exam.js new file mode 100644 index 0000000..49ce5f5 --- /dev/null +++ b/src/background/db/exam.js @@ -0,0 +1,136 @@ +const { executeWithRetry } = require('./utils.js'); +const { openDatabase } = require('./utils.js'); +const { getSystemDbPath } = require('./path.js'); + +/** + * 查询所有考试 + * @returns {Promise} 考试列表 + */ +async function getAllExams() { + const db = await openDatabase(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'SELECT * FROM exam ORDER BY created_at DESC'; + return await db.allAsync(sql); + }); +} + +/** + * 根据ID查询考试 + * @param {number} id 考试ID + * @returns {Promise} 考试数据或null + */ +async function getExamById(id) { + const db = await openDatabase(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'SELECT * FROM exam WHERE id = ?'; + return await db.getAsync(sql, [id]); + }); +} + +/** + * 查询ID最大的考试记录 + * @returns {Promise} 考试数据或null + */ +async function getLastExam() { + const db = await openDatabase(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'SELECT * FROM exam ORDER BY id DESC LIMIT 1'; + return await db.getAsync(sql); + }); +} + +/** + * 添加考试 + * @param {Object} examData 考试数据 + * @returns {Promise} 添加的考试 + */ +async function createExam(examData) { + const { exam_name, exam_description, exam_examinee_type, exam_notice, exam_minutes, exam_minutes_min } = examData; + const db = await openDatabase(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'INSERT INTO exam (exam_name, exam_description, exam_examinee_type, exam_notice, exam_minutes, exam_minutes_min) VALUES (?, ?, ?, ?, ?, ?)'; + const result = await db.runAsync(sql, [ + exam_name, + exam_description || '', + exam_examinee_type, + exam_notice || '', + exam_minutes, + exam_minutes_min || 0 + ]); + + // 检查result是否存在,如果不存在则获取最后插入的ID + let lastId; + if (result && result.lastID) { + lastId = result.lastID; + } else { + // 使用另一种方式获取最后插入的ID + const idResult = await db.getAsync('SELECT last_insert_rowid() as id'); + lastId = idResult ? idResult.id : null; + } + + if (!lastId) { + throw new Error('无法获取插入的考试ID'); + } + + return { id: lastId, ...examData }; + }); +} + +/** + * 更新考试 + * @param {number} id 考试ID + * @param {Object} examData 更新的数据 + * @returns {Promise} 是否更新成功 + */ +async function updateExam(id, examData) { + const { exam_name, exam_description, exam_examinee_type, exam_notice, exam_minutes, exam_minutes_min } = examData; + const db = await openDatabase(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'UPDATE exam SET exam_name = ?, exam_description = ?, exam_examinee_type = ?, exam_notice = ?, exam_minutes = ?, exam_minutes_min = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'; + const result = await db.runAsync(sql, [ + exam_name, + exam_description || '', + exam_examinee_type, + exam_notice || '', + exam_minutes, + exam_minutes_min || 0, + id + ]); + + // 检查result是否存在以及是否有changes属性 + if (!result || result.changes === undefined) { + return false; + } + + return result.changes > 0; + }); +} + +/** + * 删除考试 + * @param {number} id 考试ID + * @returns {Promise} 是否删除成功 + */ +async function deleteExam(id) { + const db = await openDatabase(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'DELETE FROM exam WHERE id = ?'; + const result = await db.runAsync(sql, [id]); + + // 检查result是否存在以及是否有changes属性 + if (!result || result.changes === undefined) { + return false; + } + + return result.changes > 0; + }); +} + +module.exports = { + getAllExams, + getExamById, + getLastExam, + createExam, + updateExam, + deleteExam +}; \ No newline at end of file diff --git a/src/background/db/examinee.js b/src/background/db/examinee.js new file mode 100644 index 0000000..760d04f --- /dev/null +++ b/src/background/db/examinee.js @@ -0,0 +1,190 @@ +const { executeWithRetry } = require('./utils.js'); +const { getDbConnection } = require('./index.js'); +const { getSystemDbPath } = require('./index.js'); + +/** + * 查询所有考生列表 + * @returns {Promise} 考生列表 + */ +async function getAllExaminees() { + const db = await getDbConnection(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'SELECT * FROM examinee ORDER BY created_at DESC'; + return await db.allAsync(sql); + }); +} + +/** + * 根据ID查询考生 + * @param {number} id 考生ID + * @returns {Promise} 考生数据或null + */ +async function getExamineeById(id) { + const db = await getDbConnection(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'SELECT * FROM examinee WHERE id = ?'; + return await db.getAsync(sql, [id]); + }); +} + +/** + * 根据身份证号和准考证号查询考生 + * @param {string} idCard 身份证号 + * @param {string} admissionTicket 准考证号 + * @returns {Promise} 考生数据或null + */ +async function getExamineeByIdCardAndAdmissionTicket(idCard, admissionTicket) { + const db = await getDbConnection(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'SELECT * FROM examinee WHERE examinee_id_card = ? AND examinee_admission_ticket = ?'; + return await db.getAsync(sql, [idCard, admissionTicket]); + }); +} + +/** + * 添加考生 + * @param {Object} examineeData 考生数据 + * @returns {Promise} 添加的考生 + */ +async function createExaminee(examineeData) { + const { + examinee_name, + examinee_gender, + examinee_unit, + written_exam_room, + written_exam_seat, + computer_exam_room, + computer_exam_seat, + examinee_id_card, + examinee_admission_ticket + } = examineeData; + + const db = await getDbConnection(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = `INSERT INTO examinee ( + examinee_name, + examinee_gender, + examinee_unit, + written_exam_room, + written_exam_seat, + computer_exam_room, + computer_exam_seat, + examinee_id_card, + examinee_admission_ticket + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`; + + const result = await db.runAsync(sql, [ + examinee_name, + examinee_gender || '', + examinee_unit || '', + written_exam_room || '', + written_exam_seat || '', + computer_exam_room || '', + computer_exam_seat || '', + examinee_id_card || '', + examinee_admission_ticket || '' + ]); + + // 检查result是否存在,如果不存在则获取最后插入的ID + let lastId; + if (result && result.lastID) { + lastId = result.lastID; + } else { + // 使用另一种方式获取最后插入的ID + const idResult = await db.getAsync('SELECT last_insert_rowid() as id'); + lastId = idResult ? idResult.id : null; + } + + if (!lastId) { + throw new Error('无法获取插入的考生ID'); + } + + return { id: lastId, ...examineeData }; + }); +} + +/** + * 更新考生 + * @param {number} id 考生ID + * @param {Object} examineeData 更新的数据 + * @returns {Promise} 是否更新成功 + */ +async function updateExaminee(id, examineeData) { + const { + examinee_name, + examinee_gender, + examinee_unit, + written_exam_room, + written_exam_seat, + computer_exam_room, + computer_exam_seat, + examinee_id_card, + examinee_admission_ticket + } = examineeData; + + const db = await getDbConnection(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = `UPDATE examinee SET + examinee_name = ?, + examinee_gender = ?, + examinee_unit = ?, + written_exam_room = ?, + written_exam_seat = ?, + computer_exam_room = ?, + computer_exam_seat = ?, + examinee_id_card = ?, + examinee_admission_ticket = ?, + updated_at = CURRENT_TIMESTAMP + WHERE id = ?`; + + const result = await db.runAsync(sql, [ + examinee_name, + examinee_gender || '', + examinee_unit || '', + written_exam_room || '', + written_exam_seat || '', + computer_exam_room || '', + computer_exam_seat || '', + examinee_id_card || '', + examinee_admission_ticket || '', + id + ]); + + // 检查result是否存在以及是否有changes属性 + if (!result || result.changes === undefined) { + return false; + } + + return result.changes > 0; + }); +} + +/** + * 删除考生 + * @param {number} id 考生ID + * @returns {Promise} 是否删除成功 + */ +async function deleteExaminee(id) { + const db = await getDbConnection(getSystemDbPath()); + return executeWithRetry(db, async () => { + const sql = 'DELETE FROM examinee WHERE id = ?'; + const result = await db.runAsync(sql, [id]); + + // 检查result是否存在以及是否有changes属性 + if (!result || result.changes === undefined) { + return false; + } + + return result.changes > 0; + }); +} + +// 导出使用CommonJS格式 +module.exports = { + getAllExaminees, + getExamineeById, + getExamineeByIdCardAndAdmissionTicket, + createExaminee, + updateExaminee, + deleteExaminee +}; \ No newline at end of file diff --git a/src/background/db/examing.js b/src/background/db/examing.js new file mode 100644 index 0000000..b469314 --- /dev/null +++ b/src/background/db/examing.js @@ -0,0 +1,1175 @@ +const { getDbConnection, closeAllConnections } = require('./index.js'); +const { getSystemDbPath, getUserDbPath } = require('./path.js'); + +// 新增:格式化日期为年-月-日 时:分:秒 +function formatDateTime(date) { + if (!(date instanceof Date)) { + date = new Date(date); + } + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); + const day = String(date.getDate()).padStart(2, '0'); + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; +} + +/** + * 生成考生试卷 + * @param {Object} examineeData - 考生数据 + * @param {Object} examData - 考试数据 + * @returns {Promise} - 包含试卷ID和状态的对象 + */ +async function generateExamineePaper(examineeData, examData) { + try { + // 1. 获取数据库连接 + const systemDb = await getDbConnection(getSystemDbPath()); + const userDb = await getDbConnection(getUserDbPath()); + + // 2. 处理考生数据,将空值转换为空字符串 + console.log('开始处理考生数据...', examineeData); + const processedExamineeData = { + id: examineeData.id, + examinee_name: examineeData.examinee_name || '', + examinee_gender: examineeData.examinee_gender || '', + examinee_unit: examineeData.examinee_unit || '', + written_exam_room: examineeData.written_exam_room || '', + written_exam_seat: examineeData.written_exam_seat || '', + computer_exam_room: examineeData.computer_exam_room || '', + computer_exam_seat: examineeData.computer_exam_seat || '', + examinee_id_card: examineeData.examinee_id_card || '', + examinee_admission_ticket: examineeData.examinee_admission_ticket || '' + }; + + // 3. 检查考生是否已存在 + console.log('检查考生是否已存在...'); + const existingExaminee = await userDb.getAsync( + `SELECT id FROM examinee WHERE id = ?`, + [processedExamineeData.id] + ); + + let examineeId; + + if (existingExaminee) { + // 考生已存在 + examineeId = existingExaminee.id; + console.log(`考生已存在,ID: ${examineeId}`); + // 更新考生信息 + await userDb.runAsync( + `UPDATE examinee SET + examinee_name = ?, + examinee_gender = ?, + examinee_unit = ?, + written_exam_room = ?, + written_exam_seat = ?, + computer_exam_room = ?, + computer_exam_seat = ?, + examinee_admission_ticket = ?, + created_at = ? + WHERE id = ?`, + [ + processedExamineeData.examinee_name, + processedExamineeData.examinee_gender, + processedExamineeData.examinee_unit, + processedExamineeData.written_exam_room, + processedExamineeData.written_exam_seat, + processedExamineeData.computer_exam_room, + processedExamineeData.computer_exam_seat, + processedExamineeData.examinee_admission_ticket, + new Date().toISOString(), + examineeId + ] + ); + console.log(`考生信息已更新,ID: ${examineeId}`); + // 4. 检查该考生是否有试卷记录 + console.log('检查考生试卷记录...'); + const existingPaper = await userDb.getAsync( + `SELECT id, paper_status FROM examinee_papers WHERE examinee_id = ? ORDER BY created_at DESC LIMIT 1`, + [examineeId] + ); + + if (existingPaper) { + // 试卷已存在 + const paperId = existingPaper.id; + const paperStatus = existingPaper.paper_status; + console.log(`试卷已存在,ID: ${paperId},状态: ${paperStatus}`); + + if (paperStatus === 2) { + // 状态为2:已完成考试,不能重复考试 + console.log('考生已完成考试,不能重复考试'); + return { + success: false, + message: '已完成考试,不能重复考试。' + }; + } else { + // 状态为0:未开始,删除旧试卷及相关数据,重新组卷 + console.log('删除未开始的旧试卷及相关数据...'); + + // 删除question_choices记录 + await userDb.runAsync( + `DELETE FROM question_choices WHERE question_id IN ( + SELECT id FROM paper_questions WHERE paper_id = ? + )`, + [paperId] + ); + + // 删除question_fill_blanks记录 + await userDb.runAsync( + `DELETE FROM question_fill_blanks WHERE question_id IN ( + SELECT id FROM paper_questions WHERE paper_id = ? + )`, + [paperId] + ); + + // 删除question_images记录 + await userDb.runAsync( + `DELETE FROM question_images WHERE question_id IN ( + SELECT id FROM paper_questions WHERE paper_id = ? + )`, + [paperId] + ); + + // 删除question_datasets记录 + await userDb.runAsync( + `DELETE FROM question_datasets WHERE question_id IN ( + SELECT id FROM paper_questions WHERE paper_id = ? + )`, + [paperId] + ); + + // 删除paper_questions记录 + await userDb.runAsync( + `DELETE FROM paper_questions WHERE paper_id = ?`, + [paperId] + ); + + // 删除examinee_papers记录 + await userDb.runAsync( + `DELETE FROM examinee_papers WHERE id = ?`, + [paperId] + ); + + console.log('旧试卷数据删除完成'); + } + } + } else { + // 考生不存在,添加新考生 + console.log('添加新考生...'); + const examineeResult = await userDb.runAsync( + `INSERT INTO examinee ( + id, examinee_name, examinee_gender, examinee_unit, + written_exam_room, written_exam_seat, computer_exam_room, + computer_exam_seat, examinee_id_card, examinee_admission_ticket, created_at + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, + [ + processedExamineeData.id, + processedExamineeData.examinee_name, + processedExamineeData.examinee_gender, + processedExamineeData.examinee_unit, + processedExamineeData.written_exam_room, + processedExamineeData.written_exam_seat, + processedExamineeData.computer_exam_room, + processedExamineeData.computer_exam_seat, + processedExamineeData.examinee_id_card, + processedExamineeData.examinee_admission_ticket, + new Date().toISOString() + ] + ); + examineeId = examineeResult.lastID; + console.log(`新考生添加成功,ID: ${examineeId}`); + } + + // 5. 生成新的examinee_papers记录 + console.log('生成新试卷记录...'); + const paperResult = await userDb.runAsync( + `INSERT INTO examinee_papers ( + examinee_id, paper_minutes, paper_minutes_min, paper_status + ) VALUES (?, ?, ?, ?)`, + [examineeId, examData.exam_minutes, examData.exam_minutes_min, 0] // 0表示未开始 + ); + const paperId = paperResult.lastID; + console.log(`试卷记录生成成功,ID: ${paperId}`); + + // 6. 从system库获取所有questions记录 + console.log('获取系统题库...'); + const systemQuestions = await systemDb.allAsync('SELECT * FROM questions'); + console.log(`成功获取 ${systemQuestions.length} 道题目`); + + // 打乱题目顺序 + const shuffledQuestions = [...systemQuestions].sort(() => Math.random() - 0.5); + + // 7. 准备paper_questions数据 + console.log('准备试卷题目数据...'); + const paperQuestionsData = shuffledQuestions.map(question => ({ + examinee_id: examineeId, + paper_id: paperId, + question_type: question.question_type, + question_name: question.question_name, + question_description: question.question_description, + created_at: new Date().toISOString() + })); + + // 创建question_id映射关系(system_id -> user_id) + const questionIdMap = new Map(); + + // 8. 插入paper_questions数据并记录映射关系 + console.log('插入试卷题目数据...'); + for (let i = 0; i < paperQuestionsData.length; i++) { + const result = await userDb.runAsync( + `INSERT INTO paper_questions ( + examinee_id, paper_id, question_type, + question_name, question_description, created_at + ) VALUES (?, ?, ?, ?, ?, ?)`, + [ + paperQuestionsData[i].examinee_id, + paperQuestionsData[i].paper_id, + paperQuestionsData[i].question_type, + paperQuestionsData[i].question_name, + paperQuestionsData[i].question_description, + paperQuestionsData[i].created_at + ] + ); + // 使用shuffledQuestions[i].id而不是systemQuestions[i].id + questionIdMap.set(shuffledQuestions[i].id, result.lastID); + } + console.log(`成功插入 ${paperQuestionsData.length} 条试卷题目数据`); + + // 9. 处理question_datasets表 + console.log('处理数据集...'); + const systemDatasets = await systemDb.allAsync('SELECT * FROM question_datasets'); + const userDatasets = systemDatasets + .filter(dataset => questionIdMap.has(dataset.question_id)) + .map(dataset => ({ + question_id: questionIdMap.get(dataset.question_id), + dataset_name: dataset.dataset_name, + dataset_data: dataset.dataset_data, + created_at: new Date().toISOString() + })); + if (userDatasets.length > 0) { + await batchInsert(userDb, 'question_datasets', userDatasets); + } + console.log(`成功处理 ${userDatasets.length} 个数据集`); + + // 10. 处理question_images表 + console.log('处理图片...'); + const systemImages = await systemDb.allAsync('SELECT * FROM question_images'); + const userImages = systemImages + .filter(image => questionIdMap.has(image.question_id)) + .map(image => ({ + question_id: questionIdMap.get(image.question_id), + image_name: image.image_name, + image_base64: image.image_base64, + created_at: new Date().toISOString(), + updated_at: new Date().toISOString() + })); + if (userImages.length > 0) { + await batchInsert(userDb, 'question_images', userImages); + } + console.log(`成功处理 ${userImages.length} 张图片`); + + // 11. 处理question_choices表 + console.log('处理选择题...'); + const systemChoices = await systemDb.allAsync('SELECT * FROM question_choices'); + let userChoices = systemChoices + .filter(choice => questionIdMap.has(choice.question_id)) + .map(choice => { + // 打乱选项顺序 + const options = JSON.parse(choice.choice_options); + + return { + question_id: questionIdMap.get(choice.question_id), + choice_description: choice.choice_description, + choice_type: choice.choice_type, + choice_options: JSON.stringify(options), + correct_answers: choice.correct_answers, + examinee_answers: '', + score: choice.score, + score_real: 0, + created_at: new Date().toISOString(), + updated_at: new Date().toISOString() + }; + }); + + // 打乱选择题顺序 + userChoices = userChoices.sort(() => Math.random() - 0.5); + + if (userChoices.length > 0) { + await batchInsert(userDb, 'question_choices', userChoices); + } + console.log(`成功处理 ${userChoices.length} 道选择题`); + + // 12. 处理question_fill_blanks表 + console.log('处理填空题...'); + const systemFillBlanks = await systemDb.allAsync('SELECT * FROM question_fill_blanks'); + let userFillBlanks = systemFillBlanks + .filter(blank => questionIdMap.has(blank.question_id)) + .map(blank => ({ + question_id: questionIdMap.get(blank.question_id), + blank_description: blank.blank_description, + blank_count: blank.blank_count, + correct_answers: blank.correct_answers, + examinee_answers: '', + score: blank.score, + score_real: 0, + created_at: new Date().toISOString(), + updated_at: new Date().toISOString() + })); + + // 打乱填空题顺序 + userFillBlanks = userFillBlanks.sort(() => Math.random() - 0.5); + + if (userFillBlanks.length > 0) { + await batchInsert(userDb, 'question_fill_blanks', userFillBlanks); + } + console.log(`成功处理 ${userFillBlanks.length} 道填空题`); + + // 计算试卷总分 + console.log('计算试卷总分...'); + // 查询所有选择题分数 + const choicesScoreResult = await userDb.getAsync( + `SELECT SUM(score) as total FROM question_choices WHERE question_id IN ( + SELECT id FROM paper_questions WHERE paper_id = ? + )`, + [paperId] + ); + const choicesScore = choicesScoreResult.total || 0; + + // 查询所有填空题分数 + const fillBlanksScoreResult = await userDb.getAsync( + `SELECT SUM(score) as total FROM question_fill_blanks WHERE question_id IN ( + SELECT id FROM paper_questions WHERE paper_id = ? + )`, + [paperId] + ); + const fillBlanksScore = fillBlanksScoreResult.total || 0; + + // 计算总分 + const paperScore = choicesScore + fillBlanksScore; + console.log(`试卷总分计算完成: ${paperScore}分`); + + // 更新试卷总分 + await userDb.runAsync( + `UPDATE examinee_papers SET paper_score = ? WHERE id = ?`, + [paperScore, paperId] + ); + + // 返回成功结果 + // 先查询完整的试卷数据 + const paperData = await userDb.getAsync( + `SELECT * FROM examinee_papers WHERE id = ?`, + [paperId] + ); + + // 查询试卷题目数量 + const questionCount = await userDb.getAsync( + `SELECT COUNT(*) as count FROM paper_questions WHERE paper_id = ?`, + [paperId] + ); + + // 构建完整的试卷数据对象 + const completePaperData = { + ...paperData, + question_count: questionCount.count, + examinee_id: examineeId, + examinee_name: processedExamineeData.examinee_name, + examinee_id_card: processedExamineeData.examinee_id_card, + examinee_admission_ticket: processedExamineeData.examinee_admission_ticket + }; + + return { + success: true, + message: '试卷生成成功', + data: completePaperData + }; + } catch (error) { + console.error('生成试卷失败:', error); + return { + success: false, + message: `生成试卷失败: ${error.message}`, + data: null + }; + } +} + +/** + * 加载试卷试题序列 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含试题序列的数组 + */ +async function loadPaperSerial(paperId) { + try { + // 1. 获取数据库连接 + const userDb = await getDbConnection(getUserDbPath()); + const systemDb = await getDbConnection(getSystemDbPath()); + + // 2. 查询题型字典,获取题型名称 + console.log('开始查询题型字典...'); + const questionTypeDict = await systemDb.allAsync( + `SELECT item_code, item_name FROM dict_items WHERE type_code = ?`, + ['question_type'] + ); + const questionTypeMap = new Map(); + questionTypeDict.forEach(item => { + questionTypeMap.set(item.item_code, item.item_name); + }); + console.log('成功获取题型字典'); + + // 3. 查询试卷中的所有题目,并按question_type和id升序排序 + console.log(`开始查询试卷 ${paperId} 的所有题目...`); + const paperQuestions = await userDb.allAsync( + `SELECT * FROM paper_questions + WHERE paper_id = ? + ORDER BY question_type ASC, id ASC`, + [paperId] + ); + console.log(`成功获取试卷 ${paperId} 的 ${paperQuestions.length} 道题目`); + + // 4. 构建试题序列 + const paperSerial = []; + let addedCount = 0; + let skippedCount = 0; + let globalSerialNo = 1; // 全局序列号 + + console.log('开始构建试题序列...'); + console.log(`试卷 ${paperId} 的题目列表:`); + paperQuestions.forEach((q, idx) => { + console.log(` ${idx + 1}. ID: ${q.id}, 题型: ${q.question_type}`); + }); + + for (let i = 0; i < paperQuestions.length; i++) { + const question = paperQuestions[i]; + const questionType = question.question_type; + const questionTypeName = questionTypeMap.get(questionType) || '未知题型'; + + console.log(`处理第 ${i + 1} 题题干 (ID: ${question.id}, 题型: ${questionType})`); + + let tableName = ''; + let relatedRecords = []; + + // 根据题型查询相关表的所有记录 + if (questionType === 'choice') { // 选择题 + tableName = 'question_choices'; + relatedRecords = await userDb.allAsync( + `SELECT id, examinee_answers FROM question_choices WHERE question_id = ?`, + [question.id] + ); + console.log(` 找到 ${relatedRecords.length} 条选择题记录`); + } else if (questionType === 'fill_blank') { // 填空题 + tableName = 'question_fill_blanks'; + relatedRecords = await userDb.allAsync( + `SELECT id, examinee_answers FROM question_fill_blanks WHERE question_id = ?`, + [question.id] + ); + console.log(` 找到 ${relatedRecords.length} 条填空题记录`); + } else { + console.log(` 未处理的题型: ${questionType}`); + } + + // 为每条记录添加到试题序列 + if (relatedRecords.length > 0) { + relatedRecords.forEach((record, recordIdx) => { + const answered = record.examinee_answers ? 1 : 0; + const serialNo = globalSerialNo++; + + // 添加到试题序列 + paperSerial.push({ + serial_no: serialNo, + id: record.id, + table_name: tableName, + question_id: question.id, + question_type: questionType, + question_type_name: questionTypeName, + [tableName === 'question_choices' ? 'choice_id' : 'fill_blank_id']: record.id, + answered + }); + + console.log(` 添加第 ${recordIdx + 1} 个具体问题到试题序列,序列号: ${serialNo}`); + addedCount++; + }); + } else { + console.log(` 未找到相关记录,跳过`); + skippedCount++; + } + } + console.log(`试题序列构建完成: 共 ${paperQuestions.length} 道题,添加 ${addedCount} 道,跳过 ${skippedCount} 道`); + return paperSerial; + } catch (error) { + console.error('加载试卷试题序列失败:', error); + return []; + } +} + +/** + * 根据表名和ID获取完整的试题数据 + * @param {string} tableName - 表名 (question_choices 或 question_fill_blanks) + * @param {number} id - 记录ID + * @returns {Promise} - 完整的试题数据 + */ +async function getQuestionByRelatedId(tableName, id) { + try { + // 1. 获取数据库连接 + const userDb = await getDbConnection(getUserDbPath()); + const systemDb = await getDbConnection(getSystemDbPath()); + + // 3. 查询相关表获取question_id + console.log(`查询 ${tableName} 表,ID: ${id}`); + const relatedRecord = await userDb.getAsync( + `SELECT * FROM ${tableName} WHERE id = ?`, + [id] + ); + + if (!relatedRecord) { + throw new Error(`未找到 ${tableName} 表中ID为 ${id} 的记录`); + } + + const questionId = relatedRecord.question_id; + console.log(`找到关联的题干ID: ${questionId}`); + + // 4. 查询题干信息 + const question = await userDb.getAsync( + `SELECT * FROM paper_questions WHERE id = ?`, + [questionId] + ); + + if (!question) { + throw new Error(`未找到题干ID为 ${questionId} 的记录`); + } + + // 5. 查询题型字典信息 + const questionType = question.question_type; + const dictItem = await systemDb.getAsync( + `SELECT * FROM dict_items WHERE item_code = ? AND type_code = 'question_type'`, + [questionType] + ); + + // 6. 查询关联的数据集 + const datasets = await userDb.allAsync( + `SELECT * FROM question_datasets WHERE question_id = ?`, + [questionId] + ); + + // 7. 查询关联的图片 + const images = await userDb.allAsync( + `SELECT * FROM question_images WHERE question_id = ?`, + [questionId] + ); + + // 解析选项、答案等数据 + if (question.question_type === 'choice') { + if (relatedRecord.choice_options) { + try { + relatedRecord.choice_options = JSON.parse(relatedRecord.choice_options); + if (!Array.isArray(relatedRecord.choice_options)) { + relatedRecord.choice_options = [relatedRecord.choice_options]; + } + } catch (e) { + console.error('解析选项失败:', e); + relatedRecord.choice_options = []; + } + } else { + relatedRecord.choice_options = []; + } + } + + if (question.question_type === 'choice') { + if (relatedRecord.correct_answers) { + try { + relatedRecord.correct_answers = JSON.parse(relatedRecord.correct_answers); + if (!Array.isArray(relatedRecord.correct_answers)) { + relatedRecord.correct_answers = [relatedRecord.correct_answers]; + } + } catch (e) { + console.error('解析正确答案失败:', e); + relatedRecord.correct_answers = []; + } + } else { + relatedRecord.correct_answers = []; + } + } + + if (question.question_type === 'choice') { + if (relatedRecord.examinee_answers) { + try { + relatedRecord.examinee_answers = JSON.parse(relatedRecord.examinee_answers); + if (!Array.isArray(relatedRecord.examinee_answers)) { + relatedRecord.examinee_answers = [relatedRecord.examinee_answers]; + } + } catch (e) { + console.error('解析考生答案失败:', e); + relatedRecord.examinee_answers = []; + } + } else { + relatedRecord.examinee_answers = []; + } + } + + if (question.question_type === 'fill_blank') { + if (relatedRecord.correct_answers) { + try { + relatedRecord.correct_answers = JSON.parse(relatedRecord.correct_answers); + if (!Array.isArray(relatedRecord.correct_answers)) { + relatedRecord.correct_answers = [relatedRecord.correct_answers]; + } + } catch (e) { + console.error('解析正确答案失败:', e); + relatedRecord.correct_answers = []; + } + } else { + relatedRecord.correct_answers = []; + } + } + + if (question.question_type === 'fill_blank') { + if (relatedRecord.examinee_answers) { + try { + relatedRecord.examinee_answers = JSON.parse(relatedRecord.examinee_answers); + if (!Array.isArray(relatedRecord.examinee_answers)) { + relatedRecord.examinee_answers = [relatedRecord.examinee_answers]; + } + } catch (e) { + console.error('解析考生答案失败:', e); + relatedRecord.examinee_answers = []; + } + } else { + relatedRecord.examinee_answers = []; + } + } + + // 9. 构建返回结果 + question.datasets = datasets; + question.images = images; + question.type_info = dictItem || null; + + const result = { + question_detail: relatedRecord, + question: question + }; + + console.log('成功获取完整试题数据'); + return result; + } catch (error) { + console.error('获取试题数据失败:', error); + throw error; + } +} + +/** + * 更新考生答案 + * @param {string} tableName - 表名 (question_choices 或 question_fill_blanks) + * @param {number} id - 记录ID + * @param {Array|string} answers - 考生答案 + * @returns {Promise} - 是否更新成功 + */ +async function updateExamineeAnswer(tableName, id, answers) { + try { + // 验证表名 + if (!['question_choices', 'question_fill_blanks'].includes(tableName)) { + throw new Error('无效的表名,只能是 question_choices 或 question_fill_blanks'); + } + + // 获取数据库连接 + const userDb = await getDbConnection(getUserDbPath()); + + // 确保答案是JSON字符串 + const answersJson = Array.isArray(answers) ? JSON.stringify(answers) : answers; + + // 更新考生答案 + const result = await userDb.runAsync( + `UPDATE ${tableName} SET examinee_answers = ?, updated_at = ? WHERE id = ?`, + [answersJson, new Date().toISOString(), id] + ); + + return result.changes > 0; + } catch (error) { + console.error('更新考生答案失败:', error); + throw error; + } +} + +/** + * 开始考试 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果和试卷数据的对象 + */ +async function startPaper(paperId) { + try { + const userDb = await getDbConnection(getUserDbPath()); + const currentTime = formatDateTime(new Date()); + + await userDb.runAsync( + `UPDATE examinee_papers + SET paper_status = 1, + paper_start_time = ? + WHERE id = ?`, + [currentTime, paperId] + ); + + // 查询更新后的试卷数据 + const paper = await userDb.getAsync( + `SELECT * FROM examinee_papers WHERE id = ?`, + [paperId] + ); + + return { + success: true, + message: '考试已成功开始', + data: paper + }; + } catch (error) { + console.error('开始考试失败:', error); + return { + success: false, + message: `开始考试失败: ${error.message}`, + data: null + }; + } +} + +/** + * 提交考试 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果和试卷数据的对象 + */ +async function submitPaper(paperId) { + try { + const userDb = await getDbConnection(getUserDbPath()); + const currentTime = formatDateTime(new Date()); + + await userDb.runAsync( + `UPDATE examinee_papers + SET paper_status = 2, + paper_submit_time = ?, + paper_end_time = ? + WHERE id = ?`, + [currentTime, currentTime, paperId] + ); + + // 查询更新后的试卷数据 + const paper = await userDb.getAsync( + `SELECT * FROM examinee_papers WHERE id = ?`, + [paperId] + ); + + return { + success: true, + message: '考试已成功提交', + data: paper + }; + } catch (error) { + console.error('提交考试失败:', error); + return { + success: false, + message: `提交考试失败: ${error.message}`, + data: null + }; + } +} + +/** + * 结束考试 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果和试卷数据的对象 + */ +async function endPaper(paperId) { + try { + const userDb = await getDbConnection(getUserDbPath()); + const currentTime = formatDateTime(new Date()); + + await userDb.runAsync( + `UPDATE examinee_papers + SET paper_status = 2, + paper_end_time = ? + WHERE id = ?`, + [currentTime, paperId] + ); + + // 查询更新后的试卷数据 + const paper = await userDb.getAsync( + `SELECT * FROM examinee_papers WHERE id = ?`, + [paperId] + ); + + return { + success: true, + message: '考试已成功结束', + data: paper + }; + } catch (error) { + console.error('结束考试失败:', error); + return { + success: false, + message: `结束考试失败: ${error.message}`, + data: null + }; + } +} + +/** + * 更新试卷最后操作时间 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果和试卷数据的对象 + */ +async function processPaper(paperId) { + try { + const userDb = await getDbConnection(getUserDbPath()); + const currentTime = formatDateTime(new Date()); + + await userDb.runAsync( + `UPDATE examinee_papers + SET paper_last_time = ? + WHERE id = ?`, + [currentTime, paperId] + ); + + // 查询更新后的试卷数据 + const paper = await userDb.getAsync( + `SELECT * FROM examinee_papers WHERE id = ?`, + [paperId] + ); + console.log('更新试卷最后操作时间成功:', paper); + return { + success: true, + message: '试卷处理时间已更新', + data: paper + }; + } catch (error) { + console.error('处理试卷失败:', error); + return { + success: false, + message: `处理试卷失败: ${error.message}`, + data: null + }; + } +} + +/** + * 检查试卷答案并计算得分 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果和带关联的试卷数据的对象 + */ +async function checkPaperAnswers(paperId) { + try { + // 获取用户数据库路径 + const userDbPath = getUserDbPath(); + // 连接用户数据库 + const userDb = await getDbConnection(userDbPath); + + // 1. 查询试卷基本信息 + const paper = await userDb.getAsync( + `SELECT * FROM examinee_papers WHERE id = ?`, + [paperId] + ); + + if (!paper) { + await closeAllConnections(); + return { + success: false, + message: `未找到ID为${paperId}的试卷`, + data: null + }; + } + + // 2. 查询试卷关联的所有试题 + const paperQuestions = await userDb.allAsync( + `SELECT * FROM paper_questions WHERE paper_id = ?`, + [paperId] + ); + + let totalScore = 0; + + // 3. 遍历所有试题,查询并比对答案 + for (const question of paperQuestions) { + const questionId = question.id; + const questionType = question.question_type; + + // 根据题型查询对应的答案表 + if (questionType === 'choice') { + // 选择题 + const choices = await userDb.allAsync( + `SELECT * FROM question_choices WHERE question_id = ?`, + [questionId] + ); + + for (const choice of choices) { + // 解析正确答案和考生答案 + const correctAnswers = JSON.parse(choice.correct_answers || '[]'); + const examineeAnswers = JSON.parse(choice.examinee_answers || '[]'); + + // 打印题目信息 + console.log(`\n选择题ID: ${choice.id}`); + console.log(`正确答案:`, correctAnswers); + console.log(`考生答案:`, examineeAnswers); + + // 比对答案 - 不考虑顺序 + let isCorrect = true; + if (correctAnswers.length !== examineeAnswers.length) { + isCorrect = false; + } else { + // 创建正确答案的副本用于比对 + const correctAnswersCopy = [...correctAnswers]; + + // 检查考生答案中的每个元素是否在正确答案中存在 + for (const answer of examineeAnswers) { + const index = correctAnswersCopy.indexOf(answer); + if (index === -1) { + isCorrect = false; + break; + } + // 移除已匹配的答案,避免重复匹配 + correctAnswersCopy.splice(index, 1); + } + } + + // 计算得分 + const scoreReal = isCorrect ? (choice.score || 0) : 0; + totalScore += scoreReal; + + // 打印判断结果和得分 + console.log(`判断结果: ${isCorrect ? '正确' : '错误'}`); + console.log(`本题得分: ${scoreReal}`); + + // 更新本题得分 + await userDb.runAsync( + `UPDATE question_choices SET score_real = ? WHERE id = ?`, + [scoreReal, choice.id] + ); + } + } else if (questionType === 'fill_blank') { + // 填空题 + const blanks = await userDb.allAsync( + `SELECT * FROM question_fill_blanks WHERE question_id = ?`, + [questionId] + ); + + for (const blank of blanks) { + // 解析正确答案和考生答案 + const correctAnswers = JSON.parse(blank.correct_answers || '[]'); + const examineeAnswers = JSON.parse(blank.examinee_answers || '[]'); + + // 打印题目信息 + console.log(`\n填空题ID: ${blank.id}`); + console.log(`正确答案:`, correctAnswers); + console.log(`考生答案:`, examineeAnswers); + + // 比对答案 - 不考虑顺序 + let isCorrect = true; + if (correctAnswers.length !== examineeAnswers.length) { + isCorrect = false; + } else { + // 创建正确答案的副本用于比对 + const correctAnswersCopy = [...correctAnswers]; + + // 检查考生答案中的每个元素是否在正确答案中存在 + for (const answer of examineeAnswers) { + const index = correctAnswersCopy.indexOf(answer); + if (index === -1) { + isCorrect = false; + for (const correct of correctAnswersCopy) { + if (Number(answer) === Number(correct)) { + isCorrect = true; + break; + } + } + break; + } + // 移除已匹配的答案,避免重复匹配 + correctAnswersCopy.splice(index, 1); + } + } + + // 计算得分 + const scoreReal = isCorrect ? (blank.score || 0) : 0; + totalScore += scoreReal; + + // 打印判断结果和得分 + console.log(`判断结果: ${isCorrect ? '正确' : '错误'}`); + console.log(`本题得分: ${scoreReal}`); + + // 更新本题得分 + await userDb.runAsync( + `UPDATE question_fill_blanks SET score_real = ? WHERE id = ?`, + [scoreReal, blank.id] + ); + } + } + // 可以根据需要添加其他题型的处理 + } + + // 4. 更新试卷总分 + await userDb.runAsync( + `UPDATE examinee_papers SET paper_score_real = ? WHERE id = ?`, + [totalScore, paperId] + ); + + // 5. 查询更新后的试卷信息(包含关联数据) + const updatedPaper = await getPaper(paperId); + console.log(updatedPaper); + + return { + success: true, + message: '试卷判卷成功', + data: updatedPaper.data + }; + } catch (error) { + console.error('判卷过程中发生错误:', error); + return { + success: false, + message: `判卷失败: ${error.message}`, + data: null + }; + } +} + +/** + * 获取试卷详细信息 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含试卷详细信息的对象 + */ +async function getPaper(paperId) { + try { + // 获取数据库路径 + const systemDbPath = getSystemDbPath(); + const userDbPath = getUserDbPath(); + + // 连接数据库 + const systemDb = await getDbConnection(systemDbPath); + const userDb = await getDbConnection(userDbPath); + + // 1. 查询试卷基本信息 + const paper = await userDb.getAsync( + `SELECT * FROM examinee_papers WHERE id = ?`, + [paperId] + ); + + if (!paper) { + await closeAllConnections(); + return { + success: false, + message: `未找到ID为${paperId}的试卷`, + data: null + }; + } + + // 补充: 查询关联的examinee + const examinee = await userDb.getAsync( + `SELECT * FROM examinee WHERE id = ?`, + [paper.examinee_id] + ); + + // 2. 查询试卷关联的题目 + const paperQuestions = await userDb.allAsync( + `SELECT * FROM paper_questions WHERE paper_id = ?`, + [paperId] + ); + + // 3. 为每个题目获取详细信息 + const questionsWithDetails = []; + for (const question of paperQuestions) { + const questionId = question.id; + const questionType = question.question_type; + + // 3.1 查询题型名称 + const dictItem = await systemDb.getAsync( + `SELECT item_name FROM dict_items WHERE type_code = 'question_type' AND item_code = ?`, + [questionType] + ); + + const questionWithDetails = { + ...question, + question_type_name: dictItem && dictItem.item_name ? dictItem.item_name : '', + images: [], + datasets: [], + choices: [], + blanks: [] + }; + + // 3.2 查询题目图片 + const images = await userDb.allAsync( + `SELECT * FROM question_images WHERE question_id = ?`, + [questionId] + ); + questionWithDetails.images = images; + + // 3.3 查询题目数据集 + const datasets = await userDb.allAsync( + `SELECT * FROM question_datasets WHERE question_id = ?`, + [questionId] + ); + // 解析dataset_data为数组 + questionWithDetails.datasets = datasets.map(dataset => ({ + ...dataset, + dataset_data: JSON.parse(dataset.dataset_data || '[]') + })); + + // 3.4 根据题型查询对应的答案表 + if (questionType === 'choice') { + // 查询选择题 + const choices = await userDb.allAsync( + `SELECT * FROM question_choices WHERE question_id = ?`, + [questionId] + ); + // 解析数组列 + questionWithDetails.choices = choices.map(choice => ({ + ...choice, + choice_options: JSON.parse(choice.choice_options || '[]'), + correct_answers: JSON.parse(choice.correct_answers || '[]'), + examinee_answers: JSON.parse(choice.examinee_answers || '[]') + })); + } else if (questionType === 'fill_blank') { + // 查询填空题 + const blanks = await userDb.allAsync( + `SELECT * FROM question_fill_blanks WHERE question_id = ?`, + [questionId] + ); + // 解析数组列 + questionWithDetails.blanks = blanks.map(blank => ({ + ...blank, + correct_answers: JSON.parse(blank.correct_answers || '[]'), + examinee_answers: JSON.parse(blank.examinee_answers || '[]') + })); + } + + questionsWithDetails.push(questionWithDetails); + } + + // 4. 构建完整的试卷对象 + const fullPaper = { + ...paper, + examinee: examinee, + questions: questionsWithDetails + }; + + // 关闭数据库连接 + await closeAllConnections(); + + return { + success: true, + message: '获取试卷成功', + data: JSON.stringify(fullPaper) + }; + } catch (error) { + console.error('获取试卷过程中发生错误:', error); + await closeAllConnections(); + return { + success: false, + message: `获取试卷失败: ${error.message}`, + data: null + }; + } +} + +// 在文件末尾添加所有导出 +module.exports = { + formatDateTime, + generateExamineePaper, + loadPaperSerial, + getQuestionByRelatedId, + updateExamineeAnswer, + startPaper, + submitPaper, + endPaper, + processPaper, + checkPaperAnswers, + getPaper +}; \ No newline at end of file diff --git a/src/background/main.js b/src/background/main.js index b22e3ee..6bdd0d6 100644 --- a/src/background/main.js +++ b/src/background/main.js @@ -15,6 +15,14 @@ const { initConfigIpc } = require('./service/configService.js'); const { initDictIpc } = require('./service/dictService.js'); // 导入试题服务 const { initQuestionIpc } = require('./service/questionService.js'); +// 导入考试服务 +const { initExamIpc } = require('./service/examService.js'); +// 导入考生服务 +const { initExamineeIpc } = require('./service/examineeService.js'); +// 导入考生考试服务 +const { initExamingIpc } = require('./service/examingService.js'); +// 导入文件服务 +const { initFileIpc } = require('./service/fileService.js'); // Scheme must be registered before the app is ready protocol.registerSchemesAsPrivileged([ @@ -83,57 +91,20 @@ app.on('ready', async () => { } } - // 测试SQLite连接 - try { - console.log('尝试连接SQLite...'); - const db = new sqlite3.Database(':memory:', (err) => { - if (err) { - console.error('SQLite连接失败:', err.message); - } else { - console.log('SQLite连接成功!'); - - // 执行简单的SQL操作 - db.serialize(() => { - console.log('创建测试表...'); - db.run('CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY, name TEXT)', (err) => { - if (err) { - console.error('创建表失败:', err.message); - } else { - console.log('表创建成功'); - - // 插入测试数据 - db.run('INSERT INTO test (name) VALUES (?)', ['测试数据'], function(err) { - if (err) { - console.error('插入数据失败:', err.message); - } else { - console.log('数据插入成功,ID:', this.lastID); - - // 查询数据 - db.all('SELECT * FROM test', [], (err, rows) => { - if (err) { - console.error('查询失败:', err.message); - } else { - console.log('查询结果:', rows); - } - db.close(); - }); - } - }); - } - }); - }); - } - }); - } catch (error) { - console.error('SQLite测试异常:', error); - } - // 初始化配置相关的IPC处理程序 initConfigIpc(ipcMain); // 初始化字典相关的IPC处理程序 initDictIpc(ipcMain); // 初始化试题相关的IPC处理程序 - await initQuestionIpc(ipcMain); + initQuestionIpc(ipcMain); + // 初始化考试相关的IPC处理程序 + initExamIpc(ipcMain); + // 初始化考生相关的IPC处理程序 + initExamineeIpc(ipcMain); + // 初始化考生考试相关的IPC处理程序 + initExamingIpc(ipcMain); + // 初始化文件相关的IPC处理程序 + initFileIpc(ipcMain); createWindow(); }); diff --git a/src/background/service/examService.js b/src/background/service/examService.js new file mode 100644 index 0000000..5780417 --- /dev/null +++ b/src/background/service/examService.js @@ -0,0 +1,262 @@ +const { + createExam, + getAllExams, + getExamById, + updateExam, + deleteExam, + getLastExam +} = require('../db/exam.js'); + +/** + * 服务层:创建考试 + * @param {Object} examData 考试数据 + * @returns {Promise} 创建的考试 + */ +async function createNewExam(examData) { + try { + // 数据验证 - 修改为exam_minutes和exam_minutes_min必填 + if (!examData.exam_minutes || !examData.exam_minutes_min) { + throw new Error("考试时长和最少考试时间为必填项"); + } + + // 移除默认值设置,因为现在是必填项 + if (typeof examData.exam_minutes_min !== "number") { + throw new Error("最少考试时间必须是数字"); + } + + // 确保最少考试时间不大于考试时长 + if (examData.exam_minutes_min > examData.exam_minutes) { + throw new Error("最少考试时间不能大于考试时长"); + } + + return await createExam(examData); + } catch (error) { + console.error("服务层: 创建考试失败", error); + throw error; + } +} + +/** + * 服务层:查询所有考试 + * @returns {Promise} 考试列表 + */ +async function fetchAllExams() { + try { + return await getAllExams(); + } catch (error) { + console.error("服务层: 查询所有考试失败", error); + throw error; + } +} + +/** + * 服务层:根据ID查询考试 + * @param {number} id 考试ID + * @returns {Promise} 考试数据 + */ +async function fetchExamById(id) { + try { + if (!id) { + throw new Error("考试ID不能为空"); + } + + const exam = await getExamById(id); + if (!exam) { + throw new Error("未找到指定考试"); + } + + return exam; + } catch (error) { + console.error("服务层: 根据ID查询考试失败", error); + throw error; + } +} + +/** + * 服务层:更新考试 + * @param {number} id 考试ID + * @param {Object} examData 更新的数据 + * @returns {Promise} 是否更新成功 + */ +async function modifyExam(id, examData) { + try { + if (!id) { + throw new Error("考试ID不能为空"); + } + + // 验证考试是否存在 + const existingExam = await getExamById(id); + if (!existingExam) { + throw new Error("未找到指定考试"); + } + + // 数据验证 - 修改为exam_minutes和exam_minutes_min必填 + if (!examData.exam_minutes || !examData.exam_minutes_min) { + throw new Error("考试时长和最少考试时间为必填项"); + } + + // 移除默认值设置,因为现在是必填项 + if (typeof examData.exam_minutes_min !== "number") { + throw new Error("最少考试时间必须是数字"); + } + + // 确保最少考试时间不大于考试时长 + if (examData.exam_minutes_min > examData.exam_minutes) { + throw new Error("最少考试时间不能大于考试时长"); + } + + return await updateExam(id, examData); + } catch (error) { + console.error("服务层: 更新考试失败", error); + throw error; + } +} + +/** + * 服务层:删除考试 + * @param {number} id 考试ID + * @returns {Promise} 是否删除成功 + */ +async function removeExam(id) { + try { + if (!id) { + throw new Error("考试ID不能为空"); + } + + // 验证考试是否存在 + const existingExam = await getExamById(id); + if (!existingExam) { + throw new Error("未找到指定考试"); + } + + return await deleteExam(id); + } catch (error) { + console.error("服务层: 删除考试失败", error); + throw error; + } +} + +/** + * 服务层:查询ID最大的考试记录 + * @returns {Promise} 考试数据 + */ +async function fetchLastExam() { + try { + return await getLastExam(); + } catch (error) { + console.error("服务层: 查询ID最大的考试失败", error); + throw error; + } +} + +/** + * 初始化考试相关的IPC处理程序 + * @param {Object} ipcMain Electron的ipcMain实例 + */ +function initExamIpc(ipcMain) { + // 考试管理相关IPC + ipcMain.handle("exam-create", async (event, examData) => { + try { + // 确保exam_notice是序列化的JSON字符串 + if (examData.exam_notice && typeof examData.exam_notice === "object") { + examData.exam_notice = JSON.stringify(examData.exam_notice); + } + return await createNewExam(examData); + } catch (error) { + console.error("Failed to create exam:", error); + throw error; + } + }); + + ipcMain.handle("exam-update", async (event, { id, examData }) => { + try { + // 确保exam_notice是序列化的JSON字符串 + if (examData.exam_notice && typeof examData.exam_notice === "object") { + examData.exam_notice = JSON.stringify(examData.exam_notice); + } + return await modifyExam(id, examData); + } catch (error) { + console.error("Failed to update exam:", error); + throw error; + } + }); + + ipcMain.handle("exam-fetch-last", async () => { + try { + const exam = await fetchLastExam(); + // 将exam_notice字符串解析为数组 + if (exam && exam.exam_notice) { + try { + exam.exam_notice = JSON.parse(exam.exam_notice); + } catch (e) { + console.error("解析考试须知失败:", e); + exam.exam_notice = []; + } + } + return exam; + } catch (error) { + console.error("Failed to fetch last exam:", error); + throw error; + } + }); + + ipcMain.handle("exam-fetch-all", async () => { + try { + const exams = await fetchAllExams(); + // 处理每个考试的exam_notice + return exams.map(exam => { + if (exam.exam_notice) { + try { + exam.exam_notice = JSON.parse(exam.exam_notice); + } catch (e) { + console.error(`解析考试(ID: ${exam.id})须知失败:`, e); + exam.exam_notice = []; + } + } + return exam; + }); + } catch (error) { + console.error("Failed to fetch all exams:", error); + return { success: false, error: error.message }; + } + }); + + ipcMain.handle("exam-fetch-by-id", async (event, id) => { + try { + const exam = await fetchExamById(id); + // 处理exam_notice + if (exam && exam.exam_notice) { + try { + exam.exam_notice = JSON.parse(exam.exam_notice); + } catch (e) { + console.error(`解析考试(ID: ${id})须知失败:`, e); + exam.exam_notice = []; + } + } + return { success: true, data: exam }; + } catch (error) { + console.error(`Failed to fetch exam by id ${id}:`, error); + return { success: false, error: error.message }; + } + }); + + ipcMain.handle("exam-delete", async (event, id) => { + try { + const result = await removeExam(id); + return { success: result, data: { id } }; + } catch (error) { + console.error(`Failed to delete exam ${id}:`, error); + return { success: false, error: error.message }; + } + }); +} + +module.exports = { + createNewExam, + fetchAllExams, + fetchExamById, + modifyExam, + removeExam, + fetchLastExam, + initExamIpc +}; \ No newline at end of file diff --git a/src/background/service/examineeService.js b/src/background/service/examineeService.js new file mode 100644 index 0000000..9575cfa --- /dev/null +++ b/src/background/service/examineeService.js @@ -0,0 +1,187 @@ +const { + getAllExaminees, + getExamineeById, + createExaminee, + updateExaminee, + deleteExaminee, + getExamineeByIdCardAndAdmissionTicket +} = require('../db/examinee.js'); + +/** + * 服务层:获取所有考生列表 + * @returns {Promise} 考生列表 + */ +async function fetchAllExamineesService() { + try { + return await getAllExaminees(); + } catch (error) { + console.error('服务层: 获取所有考生列表失败', error); + throw error; + } +} + +/** + * 服务层:根据ID查询考生 + * @param {number} id 考生ID + * @returns {Promise} 考生数据 + */ +async function fetchExamineeByIdService(id) { + try { + return await getExamineeById(id); + } catch (error) { + console.error('服务层: 根据ID查询考生失败', error); + throw error; + } +} + +/** + * 服务层:添加考生 + * @param {Object} examineeData 考生数据 + * @returns {Promise} 添加的考生 + */ +async function createExamineeService(examineeData) { + try { + // 数据验证 + if (!examineeData.examinee_name || !examineeData.examinee_id_card) { + throw new Error('考生姓名和身份证号为必填项'); + } + + return await createExaminee(examineeData); + } catch (error) { + console.error('服务层: 添加考生失败', error); + throw error; + } +} + +/** + * 服务层:更新考生 + * @param {number} id 考生ID + * @param {Object} examineeData 更新的数据 + * @returns {Promise} 是否更新成功 + */ +async function updateExamineeService(id, examineeData) { + try { + if (!id) { + throw new Error('考生ID不能为空'); + } + + // 验证考生是否存在 + const existingExaminee = await getExamineeById(id); + if (!existingExaminee) { + throw new Error('未找到指定考生'); + } + + // 数据验证 + if (!examineeData.examinee_name || !examineeData.examinee_id_card) { + throw new Error('考生姓名和身份证号为必填项'); + } + + return await updateExaminee(id, examineeData); + } catch (error) { + console.error('服务层: 更新考生失败', error); + throw error; + } +} + +/** + * 服务层:删除考生 + * @param {number} id 考生ID + * @returns {Promise} 是否删除成功 + */ +async function deleteExamineeService(id) { + try { + return await deleteExaminee(id); + } catch (error) { + console.error('服务层: 删除考生失败', error); + throw error; + } +} + +/** + * 服务层:考生登录 + * @param {string} idCard 身份证号 + * @param {string} admissionTicket 准考证号 + * @returns {Promise} 考生数据或null + */ +async function fetchExamineeByIdCardAndAdmissionTicketService(idCard, admissionTicket) { + try { + if (!idCard || !admissionTicket) { + throw new Error('身份证号和准考证号不能为空'); + } + return await getExamineeByIdCardAndAdmissionTicket(idCard, admissionTicket); + } catch (error) { + console.error('服务层: 考生登录失败', error); + throw error; + } +} + +/** + * 初始化考生相关的IPC处理程序 + * @param {Object} ipcMain Electron的ipcMain实例 + */ +function initExamineeIpc(ipcMain) { + ipcMain.handle("examinee-fetch-all", async (event) => { + try { + return await fetchAllExamineesService(); + } catch (error) { + console.error("Failed to fetch all examinees:", error); + return []; + } + }); + + ipcMain.handle("user-login", async (event, {idCard, admissionTicket}) => { + try { + return await fetchExamineeByIdCardAndAdmissionTicketService(idCard, admissionTicket); + } catch (error) { + console.error("Failed to login examinee:", error); + return null; + } + }); + + ipcMain.handle("examinee-fetch-by-id", async (event, id) => { + try { + return await fetchExamineeByIdService(id); + } catch (error) { + console.error("Failed to fetch examinee by id:", error); + return null; + } + }); + + ipcMain.handle("examinee-create", async (event, examineeData) => { + try { + return await createExamineeService(examineeData); + } catch (error) { + console.error("Failed to create examinee:", error); + return null; + } + }); + + ipcMain.handle("examinee-update", async (event, {id, examineeData}) => { + try { + return await updateExamineeService(id, examineeData); + } catch (error) { + console.error("Failed to update examinee:", error); + return null; + } + }); + + ipcMain.handle("examinee-delete", async (event, id) => { + try { + return await deleteExamineeService(id); + } catch (error) { + console.error("Failed to delete examinee:", error); + return null; + } + }); +} + +// 导出使用CommonJS格式 +module.exports = { + fetchAllExamineesService, + fetchExamineeByIdService, + createExamineeService, + updateExamineeService, + deleteExamineeService, + fetchExamineeByIdCardAndAdmissionTicketService, + initExamineeIpc +}; \ No newline at end of file diff --git a/src/background/service/examingService.js b/src/background/service/examingService.js new file mode 100644 index 0000000..2297bce --- /dev/null +++ b/src/background/service/examingService.js @@ -0,0 +1,499 @@ +const { + generateExamineePaper, + loadPaperSerial, + getQuestionByRelatedId, + updateExamineeAnswer, + startPaper, + submitPaper, + endPaper, + processPaper, + checkPaperAnswers, + getPaper +} = require('../db/examing.js'); +const { getDbConnection, closeAllConnections } = require('../db/index.js'); +const { getUserDbPath } = require('../db/path.js'); + +/** + * 服务层:生成考生试卷 + * @param {Object} examineeData - 考生数据 + * @param {number} examDuration - 考试时长(分钟) + * @returns {Promise} - 包含试卷ID和状态的对象 + */ +async function generateExamineePaperService(examineeData, examData) { + try { + // 数据验证 + if (!examineeData || !examineeData.id || !examineeData.examinee_name) { + throw new Error("考生数据不完整,必须包含ID和姓名"); + } + + if (!examData || !examData.exam_minutes || examData.exam_minutes <= 0) { + throw new Error("考试时长必须为正数"); + } + + if ( + examData.exam_minutes_min === undefined || + examData.exam_minutes_min < 0 + ) { + throw new Error("最短考试时长必须为非负数"); + } + + const result = await generateExamineePaper(examineeData, examData); + return result; + } catch (error) { + console.error("服务层: 生成考生试卷失败", error); + return { + success: false, + message: `生成试卷失败: ${error.message}`, + }; + } +} + +/** + * 服务层:获取考生试卷状态 + * @param {number} examineeId - 考生ID + * @returns {Promise} - 试卷状态信息 + */ +async function getExamineePaperStatusService(examineeId) { + try { + if (!examineeId || examineeId <= 0) { + throw new Error("考生ID必须为正数"); + } + + const userDb = await getDbConnection(getUserDbPath()); + const paperStatus = await userDb.getAsync( + "SELECT * FROM examinee_papers WHERE examinee_id = ?", + [examineeId] + ); + + return paperStatus; + } catch (error) { + console.error("服务层: 获取考生试卷状态失败", error); + throw error; + } +} + +/** + * 服务层:更新试卷状态 + * @param {number} paperId - 试卷ID + * @param {Object} statusData - 状态数据 + * @returns {Promise} - 是否更新成功 + */ +async function updatePaperStatusService(paperId, statusData) { + try { + if (!paperId || paperId <= 0) { + throw new Error("试卷ID必须为正数"); + } + + const userDb = await getDbConnection(getUserDbPath()); + + // 构建更新字段 + const fields = []; + const values = []; + + if (statusData.paper_start_time !== undefined) { + fields.push("paper_start_time = ?"); + values.push(statusData.paper_start_time); + } + + if (statusData.paper_last_time !== undefined) { + fields.push("paper_last_time = ?"); + values.push(statusData.paper_last_time); + } + + if (statusData.paper_submit_time !== undefined) { + fields.push("paper_submit_time = ?"); + values.push(statusData.paper_submit_time); + } + + if (statusData.paper_end_time !== undefined) { + fields.push("paper_end_time = ?"); + values.push(statusData.paper_end_time); + } + + if (statusData.paper_status !== undefined) { + fields.push("paper_status = ?"); + values.push(statusData.paper_status); + } + + if (statusData.paper_score_real !== undefined) { + fields.push("paper_score_real = ?"); + values.push(statusData.paper_score_real); + } + + if (fields.length === 0) { + return true; // 没有需要更新的字段 + } + + // 添加WHERE条件的值 + values.push(paperId); + + const sql = `UPDATE examinee_papers SET ${fields.join(", ")} WHERE id = ?`; + await userDb.runAsync(sql, values); + + return true; + } catch (error) { + console.error("服务层: 更新试卷状态失败", error); + throw error; + } +} + +/** + * 服务层:加载试卷试题序列 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含试题序列的数组 + */ +async function loadPaperSerialService(paperId) { + try { + if (!paperId || paperId <= 0) { + throw new Error("试卷ID必须为正数"); + } + + const result = await loadPaperSerial(paperId); + return { + success: true, + data: result, + }; + } catch (error) { + console.error("服务层: 加载试卷试题序列失败", error); + return { + success: false, + message: `加载试卷试题序列失败: ${error.message}`, + }; + } +} + +/** + * 服务层:根据表名和ID获取完整的试题数据 + * @param {string} tableName - 表名 (question_choices 或 question_fill_blanks) + * @param {number} id - 记录ID + * @returns {Promise} - 包含试题数据的对象 + */ +async function getQuestionByRelatedIdService(tableName, id) { + try { + const result = await getQuestionByRelatedId(tableName, id); + return { + success: true, + data: result, + }; + } catch (error) { + console.error("服务层: 获取试题数据失败", error); + return { + success: false, + message: `获取试题数据失败: ${error.message}`, + }; + } +} + +/** + * 服务层:更新考生答案 + * @param {string} tableName - 表名 (question_choices 或 question_fill_blanks) + * @param {number} id - 记录ID + * @param {Array|string} answers - 考生答案 + * @returns {Promise} - 包含更新结果的对象 + */ +async function updateExamineeAnswerService(tableName, id, answers) { + try { + if (!["question_choices", "question_fill_blanks"].includes(tableName)) { + throw new Error( + "无效的表名,只能是 question_choices 或 question_fill_blanks" + ); + } + + if (!id || id <= 0) { + throw new Error("记录ID必须为正数"); + } + + const result = await updateExamineeAnswer(tableName, id, answers); + return { + success: true, + message: "答案更新成功", + }; + } catch (error) { + console.error("服务层: 更新考生答案失败", error); + return { + success: false, + message: `更新答案失败: ${error.message}`, + }; + } +} + +/** + * 服务层:开始考试 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果的对象 + */ +async function startPaperService(paperId) { + try { + if (!paperId || paperId <= 0) { + throw new Error("试卷ID必须为正数"); + } + + const result = await startPaper(paperId); + return result; + } catch (error) { + console.error("服务层: 开始考试失败", error); + return { + success: false, + message: `开始考试失败: ${error.message}`, + }; + } +} + +/** + * 服务层:提交考试 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果的对象 + */ +async function submitPaperService(paperId) { + try { + if (!paperId || paperId <= 0) { + throw new Error("试卷ID必须为正数"); + } + + const result = await submitPaper(paperId); + return result; + } catch (error) { + console.error("服务层: 提交考试失败", error); + return { + success: false, + message: `提交考试失败: ${error.message}`, + }; + } +} + +/** + * 服务层:结束考试 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果的对象 + */ +async function endPaperService(paperId) { + try { + if (!paperId || paperId <= 0) { + throw new Error("试卷ID必须为正数"); + } + + const result = await endPaper(paperId); + return result; + } catch (error) { + console.error("服务层: 结束考试失败", error); + return { + success: false, + message: `结束考试失败: ${error.message}`, + }; + } +} + +/** + * 服务层:处理试卷 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果的对象 + */ +async function processPaperService(paperId) { + try { + if (!paperId || paperId <= 0) { + throw new Error("试卷ID必须为正数"); + } + + const result = await processPaper(paperId); + return result; + } catch (error) { + console.error("服务层: 处理试卷失败", error); + return { + success: false, + message: `处理试卷失败: ${error.message}`, + }; + } +} + +/** + * 服务层:检查试卷答案并计算得分 + * @param {number} paperId - 试卷ID + * @returns {Promise} - 包含操作结果和试卷数据的对象 + */ +async function checkPaperAnswersService(paperId) { + try { + if (!paperId || paperId <= 0) { + throw new Error("试卷ID必须为正数"); + } + + const result = await checkPaperAnswers(paperId); + return result; + } catch (error) { + console.error("服务层: 检查试卷答案失败", error); + return { + success: false, + message: `检查试卷答案失败: ${error.message}`, + }; + } +} + +/** + * 初始化考试相关的IPC处理程序 + * @param {import('electron').IpcMain} ipcMain - IPC主进程实例 + */ +function initExamingIpc(ipcMain) { + // 生成考生试卷 + ipcMain.handle( + "examing-generate-paper", + async (event, { examineeData, examData }) => { + try { + return await generateExamineePaperService(examineeData, examData); + } catch (error) { + console.error("生成考生试卷失败:", error); + return { + success: false, + message: `生成试卷失败: ${error.message}`, + }; + } + } + ); + + // 获取考生试卷状态 + ipcMain.handle("examing-get-paper-status", async (event, examineeId) => { + try { + return await getExamineePaperStatusService(examineeId); + } catch (error) { + console.error("获取考生试卷状态失败:", error); + return null; + } + }); + + // 更新试卷状态 + ipcMain.handle( + "examing-update-paper-status", + async (event, { paperId, statusData }) => { + try { + return await updatePaperStatusService(paperId, statusData); + } catch (error) { + console.error("更新试卷状态失败:", error); + return false; + } + } + ); + + // 加载试卷试题序列 + ipcMain.handle("examing-load-paper-serial", async (event, paperId) => { + try { + return await loadPaperSerialService(paperId); + } catch (error) { + console.error("加载试卷试题序列失败:", error); + return { + success: false, + message: `加载试卷试题序列失败: ${error.message}`, + }; + } + }); + + // 根据表名和ID获取完整的试题数据 + ipcMain.handle( + "examing-get-question-by-related-id", + async (event, { tableName, id }) => { + try { + return await getQuestionByRelatedIdService(tableName, id); + } catch (error) { + console.error("获取试题数据失败:", error); + return { + success: false, + message: `获取试题数据失败: ${error.message}`, + }; + } + } + ); + + // 更新考生答案 + ipcMain.handle( + "examing-update-answer", + async (event, { tableName, id, answers }) => { + try { + return await updateExamineeAnswerService(tableName, id, answers); + } catch (error) { + console.error("更新考生答案失败:", error); + return { + success: false, + message: `更新答案失败: ${error.message}`, + }; + } + } + ); + + // 开始考试 + ipcMain.handle("examing-start-paper", async (event, paperId) => { + try { + return await startPaperService(paperId); + } catch (error) { + console.error("开始考试失败:", error); + return { + success: false, + message: `开始考试失败: ${error.message}`, + }; + } + }); + + // 提交考试 + ipcMain.handle("examing-submit-paper", async (event, paperId) => { + try { + return await submitPaperService(paperId); + } catch (error) { + console.error("提交考试失败:", error); + return { + success: false, + message: `提交考试失败: ${error.message}`, + }; + } + }); + + // 结束考试 + ipcMain.handle("examing-end-paper", async (event, paperId) => { + try { + return await endPaperService(paperId); + } catch (error) { + console.error("结束考试失败:", error); + return { + success: false, + message: `结束考试失败: ${error.message}`, + }; + } + }); + + // 处理试卷 + ipcMain.handle("examing-process-paper", async (event, paperId) => { + try { + return await processPaperService(paperId); + } catch (error) { + console.error("处理试卷失败:", error); + return { + success: false, + message: `处理试卷失败: ${error.message}`, + }; + } + }); + + // 检查试卷答案并计算得分 + ipcMain.handle("examing-check-paper-answers", async (event, paperId) => { + try { + return await checkPaperAnswersService(paperId); + } catch (error) { + console.error("检查试卷答案失败:", error); + return { + success: false, + message: `检查试卷答案失败: ${error.message}`, + }; + } + }); +} + +// 导出使用CommonJS格式 +module.exports = { + generateExamineePaperService, + getExamineePaperStatusService, + updatePaperStatusService, + loadPaperSerialService, + getQuestionByRelatedIdService, + updateExamineeAnswerService, + startPaperService, + submitPaperService, + endPaperService, + processPaperService, + checkPaperAnswersService, + initExamingIpc +}; \ No newline at end of file diff --git a/src/background/service/fileService.js b/src/background/service/fileService.js new file mode 100644 index 0000000..3cd7b53 --- /dev/null +++ b/src/background/service/fileService.js @@ -0,0 +1,849 @@ +const fs = require('fs'); +const path = require('path'); +const PDFDocument = require('pdfkit'); +const { app } = require('electron'); + +// 使用更可靠的方式获取应用路径 +const appPath = app.getAppPath(); + +// 修正字体路径常量 - 从应用根路径开始构建 +const FONT_PATH = path.join(appPath, 'src', 'background', 'font'); +// 优先使用SourceHanSansSC字体 +const primaryFontPath = path.join(FONT_PATH, 'SourceHanSansSC-Regular.otf'); +const boldFontPath = path.join(FONT_PATH, 'SourceHanSansSC-Bold.otf'); +// 保留宋体作为备选 +const simsunPath = path.join(FONT_PATH, 'simsun.ttf'); +const fallbackFontPath = path.join(FONT_PATH, 'simsun.ttc'); // 备选字体路径 + +/** + * 服务层:获取所有考生列表 + * @returns {Promise} 考生列表 + */ +exports.createFileService = async function() { + try { + // TODO 测试用 + return '文件服务测试成功'; + } catch (error) { + console.error('服务层: 创建文件失败', error); + throw error; + } +}; + +/** + * 生成PDF文件并保存到合适的目录 + * @param {Object} pdfData - PDF数据 + * @param {string} fileName - 文件名 + * @returns {Promise} 文件保存路径 + */ +exports.generatePdfService = async function(pdfData, fileName) { + try { + // 获取合适的保存目录 + const appDir = path.join(getAppSaveDir(), '..'); + const filePath = path.join(appDir, `${fileName || 'document'}.pdf`); + + return new Promise((resolve, reject) => { + // 创建PDF文档 + const doc = new PDFDocument(); + + // 加载中文字体的标志 + let chineseFontLoaded = false; + let boldFontLoaded = false; + + // 保存当前字体 + let currentFont = null; + + // 修改字体加载逻辑 + try { + // 1. 尝试加载SourceHanSansSC常规字体 + if (fs.existsSync(primaryFontPath)) { + try { + doc.registerFont('SourceHanSans', primaryFontPath); + doc.font('SourceHanSans'); + currentFont = 'SourceHanSans'; + chineseFontLoaded = true; + console.log('成功加载SourceHanSansSC-Regular.otf字体'); + } catch (error) { + console.error('加载SourceHanSansSC-Regular.otf字体失败:', error); + } + } + + // 2. 尝试加载SourceHanSansSC粗体字体(用于标题) + if (fs.existsSync(boldFontPath)) { + try { + doc.registerFont('SourceHanSansBold', boldFontPath); + boldFontLoaded = true; + console.log('成功加载SourceHanSansSC-Bold.otf字体'); + } catch (error) { + console.error('加载SourceHanSansSC-Bold.otf字体失败:', error); + } + } + + // 3. 如果SourceHanSansSC字体加载失败,尝试加载宋体 + if (!chineseFontLoaded) { + if (fs.existsSync(simsunPath)) { + try { + doc.registerFont('SimSun', simsunPath); + doc.font('SimSun'); + currentFont = 'SimSun'; + chineseFontLoaded = true; + console.log('成功加载simsun.ttf字体'); + } catch (ttfError) { + console.error('加载simsun.ttf字体失败:', ttfError); + // 尝试加载备选TTC字体 + if (fs.existsSync(fallbackFontPath)) { + try { + doc.registerFont('SimSun', fallbackFontPath); + doc.font('SimSun'); + currentFont = 'SimSun'; + chineseFontLoaded = true; + console.log('成功加载simsun.ttc字体'); + } catch (ttcError) { + console.error('加载simsun.ttc字体失败:', ttcError); + } + } + } + } else { + console.warn(`未找到simsun.ttf字体文件: ${simsunPath}`); + // 检查是否有备选TTC字体 + if (fs.existsSync(fallbackFontPath)) { + try { + doc.registerFont('SimSun', fallbackFontPath); + doc.font('SimSun'); + currentFont = 'SimSun'; + chineseFontLoaded = true; + console.log('成功加载simsun.ttc字体'); + } catch (error) { + console.error('加载simsun.ttc字体失败:', error); + } + } + } + } + + if (!chineseFontLoaded) { + console.warn('无法加载中文字体,将使用默认字体,可能导致中文显示异常'); + // 在macOS上尝试使用系统字体 + if (process.platform === 'darwin') { + try { + doc.font('Arial Unicode MS'); // macOS内置支持多语言的字体 + currentFont = 'Arial Unicode MS'; + chineseFontLoaded = true; + console.log('成功加载系统Arial Unicode MS字体'); + } catch (error) { + console.error('加载系统字体失败:', error); + } + } + } + } catch (error) { + console.error('加载字体失败:', error); + console.warn('将使用默认字体,可能导致中文显示异常'); + } + + // 保存到文件 + const writeStream = fs.createWriteStream(filePath); + doc.pipe(writeStream); + + // 设置文档标题 + if (pdfData.title) { + // 保存当前字体 + const tempFont = currentFont; + try { + // 尝试使用粗体字体 + if (boldFontLoaded) { + doc.fontSize(20).font('SourceHanSansBold').text(pdfData.title, { align: 'center' }).moveDown(); + } else if (process.platform === 'darwin') { + doc.fontSize(20).font('Arial Unicode MS Bold').text(pdfData.title, { align: 'center' }).moveDown(); + } else { + doc.fontSize(20).text(pdfData.title, { align: 'center' }).moveDown(); + } + } catch (error) { + console.error('设置标题字体失败:', error); + doc.fontSize(20).text(pdfData.title, { align: 'center' }).moveDown(); + } + // 恢复字体 + if (currentFont) { + doc.font(currentFont); + } + } + + // 添加内容 + if (pdfData.content) { + pdfData.content.forEach(item => { + if (item.type === 'text') { + doc.fontSize(item.fontSize || 12).text(item.text, item.options || {}).moveDown(); + } else if (item.type === 'heading') { + // 保存当前字体 + const tempFont = currentFont; + try { + // 尝试使用SourceHanSansBold粗体字体 + if (boldFontLoaded) { + doc.fontSize(item.fontSize || 16).font('SourceHanSansBold').text(item.text, item.options || {}).moveDown(); + } else if (process.platform === 'darwin') { + doc.fontSize(item.fontSize || 16).font('Arial Unicode MS Bold').text(item.text, item.options || {}).moveDown(); + } else { + // 如果没有粗体字体,使用当前字体加大字号 + doc.fontSize(item.fontSize || 16).text(item.text, item.options || {}).moveDown(); + } + } catch (error) { + console.error('切换到粗体字体失败:', error); + doc.fontSize(item.fontSize || 16).text(item.text, item.options || {}).moveDown(); + } + // 恢复之前的字体 + if (currentFont) { + doc.font(currentFont); + } + } else if (item.type === 'table') { + // 改进表格实现 + const { headers, rows } = item; + const cellWidth = 100; + const baseCellHeight = 25; // 增加基础单元格高度,更好地适应中文 + const marginLeft = 50; + let currentY = doc.y; + const fontSize = 12; + + // 辅助函数:计算文本在指定宽度内的行数 + const calculateLines = (text, width) => { + // 估算每行字符数(假设平均字符宽度为字体大小的一半) + const charsPerLine = Math.floor(width / (fontSize / 2)); + const lines = []; + let currentText = text; + + while (currentText.length > 0) { + // 找到合适的换行位置 + let splitIndex = Math.min(currentText.length, charsPerLine); + // 尝试在空格处换行 + if (currentText.length > splitIndex && currentText[splitIndex] !== ' ') { + const lastSpace = currentText.lastIndexOf(' ', splitIndex); + if (lastSpace > 0) { + splitIndex = lastSpace; + } + } + lines.push(currentText.substring(0, splitIndex).trim()); + currentText = currentText.substring(splitIndex).trim(); + } + return lines; + }; + + // 绘制表头 + headers.forEach((header, i) => { + // 计算单元格实际高度(考虑换行) + const lines = calculateLines(header, cellWidth - 10); + const cellHeight = Math.max(baseCellHeight, lines.length * 15); + + doc.rect(marginLeft + i * cellWidth, currentY, cellWidth, cellHeight).stroke(); + + // 保存当前字体 + const tempFont = currentFont; + try { + if (boldFontLoaded) { + doc.font('SourceHanSansBold'); + } else if (process.platform === 'darwin') { + doc.font('Arial Unicode MS Bold'); + } + // 垂直居中显示文本 + doc.fontSize(fontSize).text(header, marginLeft + i * cellWidth + 5, currentY + (cellHeight - lines.length * 15) / 2, { + width: cellWidth - 10, + height: cellHeight - 10 + }); + } catch (error) { + console.error('设置表头字体失败:', error); + doc.fontSize(fontSize).text(header, marginLeft + i * cellWidth + 5, currentY + (cellHeight - lines.length * 15) / 2, { + width: cellWidth - 10, + height: cellHeight - 10 + }); + } + // 恢复字体 + if (currentFont) { + doc.font(currentFont); + } + }); + // 移动到下一行,考虑最高的表头单元格高度 + const headerLines = headers.map(header => calculateLines(header, cellWidth - 10).length); + const maxHeaderLines = Math.max(...headerLines); + currentY += Math.max(baseCellHeight, maxHeaderLines * 15) + 5; // 添加一些间距 + + // 绘制行 + rows.forEach(row => { + // 计算这一行中最高的单元格 + const rowLines = row.map(cell => calculateLines(cell.toString(), cellWidth - 10).length); + const maxRowLines = Math.max(...rowLines); + const rowHeight = Math.max(baseCellHeight, maxRowLines * 15); + + row.forEach((cell, i) => { + doc.rect(marginLeft + i * cellWidth, currentY, cellWidth, rowHeight).stroke(); + const cellLines = calculateLines(cell.toString(), cellWidth - 10); + doc.fontSize(fontSize).text(cell.toString(), marginLeft + i * cellWidth + 5, currentY + (rowHeight - cellLines.length * 15) / 2, { + width: cellWidth - 10, + height: rowHeight - 10 + }); + }); + + // 移动到下一行 + currentY += rowHeight + 5; // 添加一些间距 + }); + + // 更新文档的当前Y位置 + doc.y = currentY; + } + }); + } + + // 结束文档 + doc.end(); + + // 监听完成事件 + writeStream.on('finish', () => { + resolve(filePath); + }); + + // 监听错误事件 + writeStream.on('error', (error) => { + reject(error); + }); + }); + } catch (error) { + console.error('服务层: 生成PDF失败', error); + throw error; + } +}; + +/** + * 初始化文件相关IPC服务 + * @param {ipcMain} ipcMain - Electron IPC主进程实例 + */ +exports.initFileIpc = function(ipcMain) { + // 测试用接口 + ipcMain.handle('file-test', async () => { + try { + // 测试用 + return '文件服务测试成功'; + } catch (error) { + console.error('服务层: 文件测试失败:', error); + return { success: false, message: error.message }; + } + }); + + // 生成PDF文件接口 + ipcMain.handle('file-generate-pdf', async (event, pdfData, fileName) => { + try { + const filePath = await exports.generatePdfService(pdfData, fileName); + return { success: true, filePath }; + } catch (error) { + console.error('服务层: 生成PDF失败:', error); + return { success: false, message: error.message }; + } + }); + + // 生成试卷PDF文件接口 + ipcMain.handle('file-generate-paper-pdf', async (event, jsonString) => { + try { + const filePath = await exports.generatePaperPdf(jsonString); + return { success: true, filePath }; + } catch (error) { + console.error('服务层: 生成试卷PDF失败:', error); + return { success: false, message: error.message }; + } + }); + + // 复制文件到桌面接口 + ipcMain.handle('file-copy-to-desktop', async (event, filePath) => { + try { + const destPath = await exports.copyToDesk(filePath); + return { success: true, filePath: destPath }; + } catch (error) { + console.error('服务层: 复制文件到桌面失败:', error); + return { success: false, message: error.message }; + } + }); +}; + +/** + * 获取应用保存目录,适配不同操作系统和环境 + * @returns {string} 保存目录路径 + */ +function getAppSaveDir() { + // 判断是否为开发环境 + const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged; + + if (isDev) { + // 开发环境:使用项目根目录 + const outputDir = path.join(process.cwd(), 'output'); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + return outputDir; + } else { + // 检测是否为便携模式 + const exePath = app.getPath('exe'); + const appDir = path.dirname(exePath); + const portableFlagPath = path.join(appDir, 'portable.txt'); + const isPortable = fs.existsSync(portableFlagPath); + + // 便携模式:使用应用根目录 + if (isPortable) { + return appDir; + } else { + // 非便携模式:使用应用同级的output目录 + const outputDir = path.join(appDir, 'output'); + if (!fs.existsSync(outputDir)) { + fs.mkdirSync(outputDir, { recursive: true }); + } + return outputDir; + } + } +} + +/** + * 获取用户桌面目录路径 + * @returns {string} 用户桌面绝对路径 + */ +function getDesktopDir() { + try { + // 使用Electron的app.getPath方法获取桌面路径 + return app.getPath('desktop'); + } catch (error) { + console.error('获取桌面路径失败:', error); + // 发生错误时,返回当前工作目录作为备选 + return process.cwd(); + } +} + +/** + * 将文件复制到用户桌面 + * @param {string} filePath - 要复制的文件的绝对路径 + * @returns {Promise} 复制后的文件路径 + */ +exports.copyToDesk = async function(filePath) { + try { + const desktopDir = getDesktopDir(); + const fileName = path.basename(filePath); + const destPath = path.join(desktopDir, fileName); + + // 使用fs.promises进行文件复制 + await fs.promises.copyFile(filePath, destPath); + console.log(`文件已成功复制到桌面: ${destPath}`); + return destPath; + } catch (error) { + console.error('复制文件到桌面失败:', error); + throw error; + } +}; + +/** + * 生成试卷PDF文件 + * @param {string} jsonString - 包含试卷信息的JSON字符串 + * @returns {Promise} - 生成的PDF文件绝对路径 + */ +exports.generatePaperPdf = async function(jsonString) { + try { + // 解析JSON字符串 + const paperData = JSON.parse(jsonString); + + // 提取考生信息 + const { examinee } = paperData; + const examineeName = examinee.examinee_name; + const idCard = examinee.examinee_id_card; + const admissionTicket = examinee.examinee_admission_ticket; + + // 提取考试时间信息 + const startTime = paperData.paper_start_time; + const endTime = paperData.paper_end_time; + // 截取考试日期 (假设格式为 'YYYY-MM-DD HH:mm:ss') + const examDate = startTime.split(' ')[0]; + // 计算用时(分钟) + const start = new Date(startTime.replace(/-/g, '/')); + const end = new Date(endTime.replace(/-/g, '/')); + const durationMinutes = Math.round((end - start) / (1000 * 60)); + + // 提取试卷信息 + // 计算总题量(每个question下的choice题和fill_blank题的数量之和) + let totalQuestions = 0; + paperData.questions.forEach(question => { + if (question.choices && question.choices.length > 0) { + totalQuestions += question.choices.length; + } + if (question.blanks && question.blanks.length > 0) { + totalQuestions += question.blanks.length; + } + }); + const totalScore = paperData.paper_score; + const realScore = paperData.paper_score_real; + + // 对questions列表按照question_type和id进行排序 + paperData.questions.sort((a, b) => { + // 先按题型排序 + if (a.question_type !== b.question_type) { + return a.question_type.localeCompare(b.question_type); + } + // 再按id排序 + return a.id - b.id; + }); + + // 生成文件名 + // 格式化paper_end_time,移除特殊字符 + const endDate = new Date(endTime.replace(/-/g, '/')); + const formattedEndTime = [ + endDate.getFullYear(), + String(endDate.getMonth() + 1).padStart(2, '0'), + String(endDate.getDate()).padStart(2, '0'), + String(endDate.getHours()).padStart(2, '0'), + String(endDate.getMinutes()).padStart(2, '0'), + String(endDate.getSeconds()).padStart(2, '0') + ].join(''); + const fileName = `${examineeName}_${idCard}_${formattedEndTime}.pdf`; + + // 获取保存路径 + const appDir = getAppSaveDir(); + // 确保目录存在 + if (!fs.existsSync(appDir)) { + fs.mkdirSync(appDir, { recursive: true }); + } + const filePath = path.join(appDir, fileName); + + // 创建PDF文档,保留默认边距 + const doc = new PDFDocument({ + size: 'A4', + margin: 50 + }); + + // 加载中文字体 + const FONT_PATH = path.join(__dirname, '..', 'font'); + const primaryFontPath = path.join(FONT_PATH, 'SourceHanSansSC-Regular.otf'); + const boldFontPath = path.join(FONT_PATH, 'SourceHanSansSC-Bold.otf'); + const simsunPath = path.join(FONT_PATH, 'simsun.ttf'); + const fallbackFontPath = path.join(FONT_PATH, 'simsun.ttc'); + + let chineseFontLoaded = false; + let boldFontLoaded = false; + let currentFont = null; + + // 尝试加载字体 + try { + if (fs.existsSync(primaryFontPath)) { + doc.registerFont('SourceHanSans', primaryFontPath); + doc.font('SourceHanSans'); + currentFont = 'SourceHanSans'; + chineseFontLoaded = true; + } else if (fs.existsSync(simsunPath)) { + doc.registerFont('SimSun', simsunPath); + doc.font('SimSun'); + currentFont = 'SimSun'; + chineseFontLoaded = true; + } else if (fs.existsSync(fallbackFontPath)) { + doc.registerFont('SimSun', fallbackFontPath); + doc.font('SimSun'); + currentFont = 'SimSun'; + chineseFontLoaded = true; + } else if (process.platform === 'darwin') { + doc.font('Arial Unicode MS'); + currentFont = 'Arial Unicode MS'; + chineseFontLoaded = true; + } + + if (fs.existsSync(boldFontPath)) { + doc.registerFont('SourceHanSansBold', boldFontPath); + boldFontLoaded = true; + } + + if (!chineseFontLoaded) { + console.warn('无法加载中文字体,可能导致中文显示异常'); + } + } catch (error) { + console.error('加载字体失败:', error); + } + + // 保存到文件 + const writeStream = fs.createWriteStream(filePath); + doc.pipe(writeStream); + + // 添加标题 + if (boldFontLoaded) { + doc.font('SourceHanSansBold'); + } else if (process.platform === 'darwin' && currentFont === 'Arial Unicode MS') { + doc.font('Arial Unicode MS Bold'); + } + doc.fontSize(24).text('机考试卷', { align: 'center' }).moveDown(2); + + // 恢复常规字体 + if (currentFont) { + doc.font(currentFont); + } + + // 辅助函数:绘制表格 + function drawTable(headers, rows, cellWidth = 120, baseCellHeight = 25) { + // 从左边距开始 + const marginLeft = doc.page.margins.left; + let currentY = doc.y; + const fontSize = 12; + const pageWidth = doc.page.width - doc.page.margins.left - doc.page.margins.right; + + // 计算文本在指定宽度内的行数 + const calculateLines = (text, width) => { + const charsPerLine = Math.floor(width / (fontSize / 2)); + const lines = []; + let currentText = text; + + while (currentText.length > 0) { + let splitIndex = Math.min(currentText.length, charsPerLine); + if (currentText.length > splitIndex && currentText[splitIndex] !== ' ') { + const lastSpace = currentText.lastIndexOf(' ', splitIndex); + if (lastSpace > 0) { + splitIndex = lastSpace; + } + } + lines.push(currentText.substring(0, splitIndex).trim()); + currentText = currentText.substring(splitIndex).trim(); + } + return lines; + }; + + // 确保表格不会超出页面宽度 + const totalTableWidth = headers.length * cellWidth; + const adjustedCellWidth = totalTableWidth > pageWidth ? pageWidth / headers.length : cellWidth; + + // 绘制表头 + headers.forEach((header, i) => { + const lines = calculateLines(header, adjustedCellWidth - 10); + const cellHeight = Math.max(baseCellHeight, lines.length * 15); + + doc.rect(marginLeft + i * adjustedCellWidth, currentY, adjustedCellWidth, cellHeight).stroke(); + + if (boldFontLoaded) { + doc.font('SourceHanSansBold'); + } else if (process.platform === 'darwin' && currentFont === 'Arial Unicode MS') { + doc.font('Arial Unicode MS Bold'); + } + + doc.fontSize(fontSize).text(header, marginLeft + i * adjustedCellWidth + 5, currentY + (cellHeight - lines.length * 15) / 2, { + width: adjustedCellWidth - 10, + height: cellHeight - 10 + }); + + if (currentFont) { + doc.font(currentFont); + } + }); + + // 移动到下一行(无间隙) + const headerLines = headers.map(header => calculateLines(header, adjustedCellWidth - 10).length); + const maxHeaderLines = Math.max(...headerLines); + currentY += Math.max(baseCellHeight, maxHeaderLines * 15); + + // 绘制行 + rows.forEach(row => { + const rowLines = row.map(cell => calculateLines(cell.toString(), adjustedCellWidth - 10).length); + const maxRowLines = Math.max(...rowLines); + const rowHeight = Math.max(baseCellHeight, maxRowLines * 15); + + row.forEach((cell, i) => { + doc.rect(marginLeft + i * adjustedCellWidth, currentY, adjustedCellWidth, rowHeight).stroke(); + const cellLines = calculateLines(cell.toString(), adjustedCellWidth - 10); + doc.fontSize(fontSize).text(cell.toString(), marginLeft + i * adjustedCellWidth + 5, currentY + (rowHeight - cellLines.length * 15) / 2, { + width: adjustedCellWidth - 10, + height: rowHeight - 10 + }); + }); + + currentY += rowHeight; // 无间隙 + }); + + doc.y = currentY; + } + + // 辅助函数:添加base64图片 + function addBase64Image(base64String, maxWidth = 400, maxHeight = 300) { + try { + // 移除base64前缀 + const base64Data = base64String.replace(/^data:image\/\w+;base64,/, ''); + // 将base64转换为缓冲区 + const imageBuffer = Buffer.from(base64Data, 'base64'); + // 获取图片尺寸 + const image = doc.openImage(imageBuffer); + // 计算缩放比例 + const scale = Math.min(maxWidth / image.width, maxHeight / image.height, 1); + // 添加图片,从左边距开始 + doc.image(image, doc.page.margins.left, doc.y, { + width: image.width * scale, + height: image.height * scale + }); + // 移动文档指针 + doc.y += image.height * scale + 10; + } catch (error) { + console.error('添加图片失败:', error); + doc.fontSize(10).text('图片加载失败', doc.page.margins.left, doc.y).moveDown(); + } + } + + // 绘制考生信息表格 + drawTable( + ['姓名', '身份证号', '准考证号'], + [[examineeName, idCard, admissionTicket]] + ); + doc.moveDown(); + + // 绘制考试信息表格 + drawTable( + ['考试日期', '开始时间', '结束时间', '用时(分钟)'], + [[examDate, startTime.split(' ')[1], endTime.split(' ')[1], durationMinutes.toString()]] + ); + doc.moveDown(); + + // 绘制试卷信息表格 + drawTable( + ['总题量', '试卷总分', '考试得分'], + [[totalQuestions.toString(), totalScore.toString(), realScore.toString()]] + ); + doc.moveDown(2); + + // 添加题目信息 + paperData.questions.forEach((question, index) => { + // 题目类型和描述 + if (boldFontLoaded) { + doc.font('SourceHanSansBold'); + } else if (process.platform === 'darwin' && currentFont === 'Arial Unicode MS') { + doc.font('Arial Unicode MS Bold'); + } + doc.fontSize(14).text(`第 ${index + 1} 题 (${question.question_type_name})`, doc.page.margins.left).moveDown(); + + if (currentFont) { + doc.font(currentFont); + } + // 确保题干描述从左边距开始 + doc.fontSize(12).text(question.question_description, { + x: doc.page.margins.left, + width: doc.page.width - doc.page.margins.left - doc.page.margins.right + }).moveDown(); + + // 添加图片 + if (question.images && question.images.length > 0) { + doc.fontSize(12).text('图片:', doc.page.margins.left).moveDown(); + question.images.forEach((image) => { + if (image.image_base64) { + addBase64Image(image.image_base64); + } else { + doc.fontSize(10).text(`图片: ${image.image_name || '无名称'}`, doc.page.margins.left).moveDown(); + } + }); + } + + // 添加数据集 + if (question.datasets && question.datasets.length > 0) { + doc.fontSize(12).text('数据集:', doc.page.margins.left).moveDown(); + question.datasets.forEach((dataset, dataIndex) => { + doc.fontSize(10).text(`数据集 ${dataIndex + 1} (${dataset.dataset_name || '无名称'})`, doc.page.margins.left).moveDown(); + // 尝试解析数据集数据为表格 + try { + const datasetData = JSON.parse(dataset.dataset_data); + if (Array.isArray(datasetData) && datasetData.length > 0) { + // 假设第一行是表头 + const headers = Object.keys(datasetData[0]); + const rows = datasetData.map(item => headers.map(header => item[header])); + // 缩小单元格宽度以适应页面 + drawTable(headers, rows, 80, 20); + } + } catch (error) { + console.error('解析数据集失败:', error); + doc.fontSize(10).text(`数据集内容: ${dataset.dataset_data.substring(0, 100)}...`, doc.page.margins.left).moveDown(); + } + }); + } + + // 添加填空题 + if (question.blanks && question.blanks.length > 0) { + question.blanks.forEach((blank, blankIndex) => { + if (boldFontLoaded) { + doc.font('SourceHanSansBold'); + } else if (process.platform === 'darwin' && currentFont === 'Arial Unicode MS') { + doc.font('Arial Unicode MS Bold'); + } + doc.fontSize(12).text(`填空 ${blankIndex + 1}`, doc.page.margins.left).moveDown(); + + if (currentFont) { + doc.font(currentFont); + } + // 确保问题描述从左边距开始 + doc.fontSize(12).text(blank.blank_description, { + x: doc.page.margins.left, + width: doc.page.width - doc.page.margins.left - doc.page.margins.right + }).moveDown(); + drawTable( + ['正确答案', '考生答案', '分值', '得分'], + [ + [ + Array.isArray(blank.correct_answers) ? blank.correct_answers.join(', ') : blank.correct_answers, + Array.isArray(blank.examinee_answers) ? blank.examinee_answers.join(', ') : blank.examinee_answers, + blank.score.toString(), + blank.score_real.toString() + ] + ], + 100 + ); + }); + } + + // 添加选择题 + if (question.choices && question.choices.length > 0) { + question.choices.forEach((choice, choiceIndex) => { + if (boldFontLoaded) { + doc.font('SourceHanSansBold'); + } else if (process.platform === 'darwin' && currentFont === 'Arial Unicode MS') { + doc.font('Arial Unicode MS Bold'); + } + doc.fontSize(12).text(`选择题 ${choiceIndex + 1}`, doc.page.margins.left).moveDown(); + + if (currentFont) { + doc.font(currentFont); + } + // 确保问题描述从左边距开始 + doc.fontSize(12).text(choice.choice_description, { + x: doc.page.margins.left, + width: doc.page.width - doc.page.margins.left - doc.page.margins.right + }).moveDown(); + // 显示选项 + if (choice.choice_options && choice.choice_options.length > 0) { + const optionsText = choice.choice_options.map((option, i) => { + const optionLabel = String.fromCharCode(65 + i); // A, B, C, D... + return `${optionLabel}. ${option}`; + }).join(' '); + doc.fontSize(10).text(`选项: ${optionsText}`, doc.page.margins.left).moveDown(); + } + drawTable( + ['正确答案', '考生答案', '分值', '得分'], + [ + [ + Array.isArray(choice.correct_answers) ? choice.correct_answers.join(', ') : choice.correct_answers, + Array.isArray(choice.examinee_answers) ? choice.examinee_answers.join(', ') : choice.examinee_answers, + choice.score.toString(), + choice.score_real.toString() + ] + ], + 100 + ); + }); + } + + // 分页处理 + if (doc.y > 700) { + doc.addPage(); + } + }); + + // 结束文档 + doc.end(); + + return new Promise((resolve, reject) => { + writeStream.on('finish', async () => { + try { + // 调用copyToDesk方法将文件复制到桌面,获取新的路径 + const newFilePath = await exports.copyToDesk(filePath); + resolve(newFilePath); + } catch (error) { + reject(error); + } + }); + writeStream.on('error', reject); + }); + } catch (error) { + console.error('生成PDF失败:', error); + throw error; + } +}; \ No newline at end of file diff --git a/src/background/service/questionService.js b/src/background/service/questionService.js index e0bcfc0..e049c75 100644 --- a/src/background/service/questionService.js +++ b/src/background/service/questionService.js @@ -248,7 +248,7 @@ async function fetchQuestionsCountAndScore() { * 初始化试题相关IPC通信 * @param {Electron.IpcMain} ipcMain - IPC主进程实例 */ -async function initQuestionIpc(ipcMain) { +function initQuestionIpc(ipcMain) { // 题干管理相关IPC ipcMain.handle("question-create", async (event, questionData) => { try { diff --git a/src/components/HelloWorld.vue b/src/components/HelloWorld.vue deleted file mode 100644 index b9f3c7d..0000000 --- a/src/components/HelloWorld.vue +++ /dev/null @@ -1,59 +0,0 @@ - - - {{ msg }} - - For a guide and recipes on how to configure / customize this project, - check out the - vue-cli documentation. - - Installed CLI Plugins - - babel - router - vuex - - Essential Links - - Core Docs - Forum - Community Chat - Twitter - News - - Ecosystem - - vue-router - vuex - vue-devtools - vue-loader - awesome-vue - - - - - - - - diff --git a/src/components/common/Footer.vue b/src/components/common/Footer.vue new file mode 100644 index 0000000..05ed7c5 --- /dev/null +++ b/src/components/common/Footer.vue @@ -0,0 +1,53 @@ + + + + + + + \ No newline at end of file diff --git a/src/components/common/Header.vue b/src/components/common/Header.vue new file mode 100644 index 0000000..9dcec78 --- /dev/null +++ b/src/components/common/Header.vue @@ -0,0 +1,36 @@ + + + + + + + + {{ thisYear }}年抚顺市统计行业职工技能大赛考试系统 + + + + + + + + + + \ No newline at end of file diff --git a/src/components/common/Loading.vue b/src/components/common/Loading.vue new file mode 100644 index 0000000..ac60870 --- /dev/null +++ b/src/components/common/Loading.vue @@ -0,0 +1,52 @@ + + + + + {{ text || '加载中...' }} + + + + + + + \ No newline at end of file diff --git a/src/preload.js b/src/preload.js index 640d39c..238e968 100644 --- a/src/preload.js +++ b/src/preload.js @@ -47,6 +47,41 @@ contextBridge.exposeInMainWorld('electronAPI', { questionGetStatistics: () => ipcRenderer.invoke('question-get-statistics'), questionGetQuestionById: (questionId) => ipcRenderer.invoke('question-get-question-by-id', questionId), + // 考试服务相关接口 + examCreate: (examData) => ipcRenderer.invoke('exam-create', examData), + examUpdate: (id, examData) => ipcRenderer.invoke('exam-update', { id, examData }), + examFetchLast: () => ipcRenderer.invoke('exam-fetch-last'), + examFetchAll: () => ipcRenderer.invoke('exam-fetch-all'), + examFetchById: (id) => ipcRenderer.invoke('exam-fetch-by-id', id), + examDelete: (id) => ipcRenderer.invoke('exam-delete', id), + + // 考生服务相关接口 + examineeFetchAll: () => ipcRenderer.invoke('examinee-fetch-all'), + userLogin: ({ idCard, admissionTicket }) => ipcRenderer.invoke('user-login', { idCard, admissionTicket }), + examineeFetchById: (id) => ipcRenderer.invoke('examinee-fetch-by-id', id), + examineeCreate: (examineeData) => ipcRenderer.invoke('examinee-create', examineeData), + examineeUpdate: (id, examineeData) => ipcRenderer.invoke('examinee-update', { id, examineeData }), + examineeDelete: (id) => ipcRenderer.invoke('examinee-delete', id), + + // 考生考试服务相关接口 + examingGeneratePaper: ({ examineeId, examId }) => ipcRenderer.invoke('examing-generate-paper', { examineeId, examId }), + examingGetPaperStatus: ({ examineeId, examId }) => ipcRenderer.invoke('examing-get-paper-status', { examineeId, examId }), + examingUpdatePaperStatus: ({ paperId, status }) => ipcRenderer.invoke('examing-update-paper-status', { paperId, status }), + examingLoadPaperSerial: ({ paperId }) => ipcRenderer.invoke('examing-load-paper-serial', { paperId }), + examingGetQuestionByRelatedId: ({ tableName, relatedId }) => ipcRenderer.invoke('examing-get-question-by-related-id', { tableName, relatedId }), + examingUpdateAnswer: ({ paperId, questionId, answer }) => ipcRenderer.invoke('examing-update-answer', { paperId, questionId, answer }), + examingStartPaper: ({ paperId }) => ipcRenderer.invoke('examing-start-paper', { paperId }), + examingSubmitPaper: ({ paperId }) => ipcRenderer.invoke('examing-submit-paper', { paperId }), + examingEndPaper: ({ paperId }) => ipcRenderer.invoke('examing-end-paper', { paperId }), + examingProcessPaper: ({ paperId }) => ipcRenderer.invoke('examing-process-paper', { paperId }), + examingCheckPaperAnswers: ({ paperId }) => ipcRenderer.invoke('examing-check-paper-answers', { paperId }), + + // 文件服务相关接口 + fileTest: () => ipcRenderer.invoke('file-test'), + fileGeneratePdf: (pdfData, fileName) => ipcRenderer.invoke('file-generate-pdf', pdfData, fileName), + fileGeneratePaperPdf: (jsonString) => ipcRenderer.invoke('file-generate-paper-pdf', jsonString), + fileCopyToDesktop: (filePath) => ipcRenderer.invoke('file-copy-to-desktop', filePath), + // 保留原有的ipcRenderer接口,确保兼容性 ipcRenderer: { invoke: (channel, data) => ipcRenderer.invoke(channel, data) diff --git a/src/router/index.js b/src/router/index.js index d36779e..30d5e33 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,22 +1,14 @@ import Vue from 'vue' import VueRouter from 'vue-router' -import Home from '../views/Home.vue' +import WelcomeView from '../views/WelcomeView.vue' Vue.use(VueRouter) const routes = [ { path: '/', - name: 'Home', - component: Home - }, - { - path: '/about', - name: 'About', - // route level code-splitting - // this generates a separate chunk (about.[hash].js) for this route - // which is lazy-loaded when the route is visited. - component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') + name: 'Welcome', + component: WelcomeView } ] diff --git a/src/store/index.js b/src/store/index.js index 332b916..793e671 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -5,8 +5,18 @@ Vue.use(Vuex) export default new Vuex.Store({ state: { + examinee: null, // 保存考生信息 + isLoggedIn: false // 登录状态 }, mutations: { + setExaminee(state, examineeInfo) { + state.examinee = examineeInfo + state.isLoggedIn = true + }, + clearExaminee(state) { + state.examinee = null + state.isLoggedIn = false + } }, actions: { }, diff --git a/src/views/About.vue b/src/views/About.vue deleted file mode 100644 index 3fa2807..0000000 --- a/src/views/About.vue +++ /dev/null @@ -1,5 +0,0 @@ - - - This is an about page - - diff --git a/src/views/Home.vue b/src/views/Home.vue deleted file mode 100644 index b908b7e..0000000 --- a/src/views/Home.vue +++ /dev/null @@ -1,627 +0,0 @@ - - - Argon2 Test - - - - FontAwesome 图标测试 - - - - - - - - - - - - - - Element UI 组件测试 - - - - Argon2哈希计算 - 打开对话框 - - - - - - - - - - {{ result }} - - - - - - - - - - - - - 这是一个Element UI对话框组件 - - - - - - - - 请选择一个图标 - - - - 取 消 - 确 定 - - - - - - 数据库初始化测试 - - - - 数据库状态 - - - - - - - - - - {{ initializing ? '正在初始化...' : '初始化数据库' }} - - - - - - - 失败原因: {{ dbInitResult.error }} - - - - - - - - - - - - - 配置列表 - - - - 系统配置项 - 刷新列表 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {{ scope.row.value }} - - - - - - - - - 编辑 - - 保存 - 取消 - - - - - - - - - - - - - - - Bootstrap 组件测试 - - - - 按钮样式 - Primary - Secondary - Success - Danger - Warning - Info - Light - - - - - Bootstrap 卡片标题 - - 这是一个Bootstrap卡片 - 卡片内容区域,可以放置文本、图片等各种内容。 - 打开模态框 - - - - - - Bootstrap 表单 - - - - 邮箱地址 - - 我们不会分享您的邮箱给任何人 - - - 密码 - - - - - 记住我 - - 提交 - - - - - - - 导航栏 - - Bootstrap - - - - - - - 首页 (current) - - - 特性 - - - 关于 - - - - - - - - - - - - Bootstrap模态框 - - × - - - - 这是一个Bootstrap模态框,它使用JavaScript来控制显示和隐藏。 - 如果您能看到这个模态框,说明Bootstrap的JavaScript组件正常工作! - - - - - - - - - - - - diff --git a/src/views/WelcomeView.vue b/src/views/WelcomeView.vue new file mode 100644 index 0000000..747745d --- /dev/null +++ b/src/views/WelcomeView.vue @@ -0,0 +1,325 @@ + + + + + + + + + + + + + + + 系统未初始化 + 请点击下方按钮进行系统初始化,初始化完成后将自动显示登录界面 + + + + {{ isInitializing ? '初始化中...' : '数据初始化' }} + + + + + + + + + + + + 考生登录 + + + + + + 系统管理 + + + + + + + + + + + 身份证号 + + + + + + + + + 准考证号 + + + + + + + + + + + 登录 + + + + + + + + + + 管理员密码 + + + + + + + + + + + + + {{ isLoading ? '登录中...' : '登录' }} + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vue.config.js b/vue.config.js index adb202c..90df805 100644 --- a/vue.config.js +++ b/vue.config.js @@ -4,11 +4,34 @@ module.exports = { nodeIntegration: false, contextIsolation: true, preload: 'src/preload.js', - // 添加这一行,指定主进程文件路径 mainProcessFile: 'src/background/main.js', - // If you want to use ESLint for your preload script, - // set lintPreloadFiles to true - lintPreloadFiles: false + lintPreloadFiles: false, + // 将externals改为数组格式 + externals: ['fontkit', 'pdfkit'], + chainWebpackMainProcess: (config) => { + config.module + .rule('babel') + .test(/\.js$/) + .use('babel-loader') + .loader('babel-loader') + .options({ + presets: ['@babel/preset-env'], + plugins: [ + '@babel/plugin-proposal-optional-chaining', + '@babel/plugin-proposal-class-properties' + ] + }) + .end() + + // 添加对mjs文件的处理 + config.module + .rule('mjs') + .test(/\.mjs$/) + .include + .add(/node_modules/) + .end() + .type('javascript/auto') + } } } } \ No newline at end of file
- For a guide and recipes on how to configure / customize this project, - check out the - vue-cli documentation. -
{{ text || '加载中...' }}
{{ result }}
这是一个Element UI对话框组件
卡片内容区域,可以放置文本、图片等各种内容。
请点击下方按钮进行系统初始化,初始化完成后将自动显示登录界面