diff --git a/build.js b/build.js index 5bbc0f3..f8d6c84 100644 --- a/build.js +++ b/build.js @@ -22,7 +22,7 @@ const glob = require("glob"); const mp = path.join(__dirname, "meta.json"); -const meta = JSON.parse(fs.readFileSync(mp, "utf-8")); +const meta = JSON.parse(fs.readFileSync(mp, {encoding: "utf-8"})); let files = []; @@ -42,7 +42,7 @@ let licenses = {}; // sort so top level (newer) dependency licenses overwrite transient (potentially older) dependency licenses for(const license of files.sort((a, b) => b.length - a.length)){ const name = license.split("node_modules").splice(-1)[0].split('/').slice(0, -1).join('/').substring(1); - licenses[name] = fs.readFileSync(license, "utf-8").trim(); + licenses[name] = fs.readFileSync(license, {encoding: "utf-8"}).trim(); } let out = "# Licenses\n\n---"; @@ -53,5 +53,5 @@ for(const k of Object.keys(licenses).sort()){ out += `\n\n${licenses[k]}`; } -fs.writeFileSync(path.join(__dirname, "LICENSES.txt"), out, "utf-8"); +fs.writeFileSync(path.join(__dirname, "LICENSES.txt"), out, {encoding: "utf-8"}); fs.rmSync(mp); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 80a02f4..0525a67 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,16 +1,16 @@ { "name": "settings-repository", - "version": "1.0.11", + "version": "2.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "settings-repository", - "version": "1.0.11", + "version": "2.0.0", "license": "GPL-2.0-only", "devDependencies": { "@types/adm-zip": "0.5.7", - "@types/node": "22.10.1", + "@types/node": "22.10.2", "@types/vscode": "1.96.0", "@vscode/vsce": "3.2.1", "adm-zip": "0.5.16", @@ -72,9 +72,9 @@ } }, "node_modules/@azure/core-rest-pipeline": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.0.tgz", - "integrity": "sha512-QSoGUp4Eq/gohEFNJaUOwTN7BCc2nHTjjbm75JT0aD7W65PWM1H/tItz0GsABn22uaKyGxiMhWQLt2r+FGU89Q==", + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.1.tgz", + "integrity": "sha512-/wS73UEDrxroUEVywEm7J0p2c+IIiVxyfigCGfsKvCxxCET4V/Hef2aURqltrXMRjNmdmt5IuOgIpl8f6xdO5A==", "dev": true, "license": "MIT", "dependencies": { @@ -158,9 +158,9 @@ } }, "node_modules/@azure/msal-browser": { - "version": "3.27.0", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.27.0.tgz", - "integrity": "sha512-+b4ZKSD8+vslCtVRVetkegEhOFMLP3rxDWJY212ct+2r6jVg6OSQKc1Qz3kCoXo0FgwaXkb+76TMZfpHp8QtgA==", + "version": "3.28.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.28.0.tgz", + "integrity": "sha512-1c1qUF6vB52mWlyoMem4xR1gdwiQWYEQB2uhDkbAL4wVJr8WmAcXybc1Qs33y19N4BdPI8/DHI7rPE8L5jMtWw==", "dev": true, "license": "MIT", "dependencies": { @@ -181,9 +181,9 @@ } }, "node_modules/@azure/msal-node": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.16.1.tgz", - "integrity": "sha512-1NEFpTmMMT2A7RnZuvRl/hUmJU+GLPjh+ShyIqPktG2PvSd2yvPnzGd/BxIBAAvJG5nr9lH4oYcQXepDbaE7fg==", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.16.2.tgz", + "integrity": "sha512-An7l1hEr0w1HMMh1LU+rtDtqL7/jw74ORlc9Wnh06v7TU/xpG39/Zdr1ZJu3QpjUfKJ+E0/OXMW8DRSWTlh7qQ==", "dev": true, "license": "MIT", "dependencies": { @@ -649,9 +649,9 @@ } }, "node_modules/@types/node": { - "version": "22.10.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", - "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -662,7 +662,8 @@ "version": "1.96.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.96.0.tgz", "integrity": "sha512-qvZbSZo+K4ZYmmDuaodMbAa67Pl6VDQzLKFka6rq+3WUTY4Kro7Bwoi0CuZLO/wema0ygcmpwow7zZfPJTs5jg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@vscode/vsce": { "version": "3.2.1", @@ -862,14 +863,11 @@ } }, "node_modules/agent-base": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", - "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, "engines": { "node": ">= 14" } @@ -1028,18 +1026,29 @@ "dev": true, "license": "BSD-3-Clause" }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -1173,9 +1182,9 @@ "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz", - "integrity": "sha512-ZVJrKKYunU38/76t0RMOulHOnUcbU9GbpWKAOZ0mhjr7CX6FVrH+4FrAapSOekrgFQ3f/8gwMEuIft0aKq6Hug==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -1218,9 +1227,9 @@ } }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "license": "MIT", "dependencies": { @@ -1263,24 +1272,6 @@ "node": ">=4.0.0" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/define-lazy-prop": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", @@ -1371,6 +1362,21 @@ "url": "https://github.com/fb55/domutils?sponsor=1" } }, + "node_modules/dunder-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", + "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -1434,14 +1440,11 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -1456,6 +1459,19 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.24.0", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz", @@ -1588,17 +1604,22 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", + "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", "dev": true, "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -1666,13 +1687,13 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1688,36 +1709,10 @@ "node": ">=4" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -1788,13 +1783,13 @@ } }, "node_modules/https-proxy-agent": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", - "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.0.2", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { @@ -2103,6 +2098,16 @@ "markdown-it": "bin/markdown-it.mjs" } }, + "node_modules/math-intrinsics": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.0.0.tgz", + "integrity": "sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/mdurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", @@ -2463,9 +2468,9 @@ } }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.1.tgz", + "integrity": "sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -2592,24 +2597,6 @@ "node": ">=10" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2634,16 +2621,73 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -2970,6 +3014,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/package.json b/package.json index 7e6331c..eb4f7ae 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "theme": "dark" }, "publisher": "Katsute", - "version": "1.0.11", + "version": "2.0.0", "private": true, "engines": { "vscode": "^1.96.0" @@ -135,7 +135,7 @@ "homepage": "https://github.com/KatsuteDev/Settings-Repository#readme", "devDependencies": { "@types/adm-zip": "0.5.7", - "@types/node": "22.10.1", + "@types/node": "22.10.2", "@types/vscode": "1.96.0", "@vscode/vsce": "3.2.1", "adm-zip": "0.5.16", diff --git a/src/command/auth.ts b/src/command/auth.ts index 8c0c7c2..5dea3a4 100644 --- a/src/command/auth.ts +++ b/src/command/auth.ts @@ -18,7 +18,6 @@ import * as vscode from "vscode"; -import * as fs from "fs"; import * as os from "os"; import { isNull, isValidJson } from "../lib/is"; @@ -53,7 +52,7 @@ const crypt: Crypt = new Crypt(os.hostname()); // export const mask: (s: string, c: credentials) => string = (s: string, c: credentials) => { - return s.replace(new RegExp(c.auth, "gm"), "***"); + return `${s}`.replace(new RegExp(c.auth, "gm"), "***"); } export const authenticate: () => void = () => { @@ -85,13 +84,13 @@ export const authenticate: () => void = () => { logger.info(`Updated authentication: ${username}`); - fs.writeFileSync( + files.write( dist.credentials, `{ "login": "${username}", "auth": "${crypt.encrypt(password)}" -}`, - "utf-8"); +}` + ); }); }); } @@ -101,7 +100,7 @@ export const authorization: () => credentials | undefined = () => { if(!files.isFile(dist.credentials)) return undefined; - const json: string = fs.readFileSync(dist.credentials, "utf-8"); + const json: string = files.read(dist.credentials)!; if(!isValidJson(json)) return undefined; diff --git a/src/distribution.ts b/src/distribution.ts index a8d7098..0e86614 100644 --- a/src/distribution.ts +++ b/src/distribution.ts @@ -27,6 +27,11 @@ import { isNotNull, isNull, isValidJson } from "./lib/is"; // +export type Profile = { + location: string; + name: string; +} + export class Distribution { public readonly Code: string; @@ -36,7 +41,9 @@ export class Distribution { public readonly keybindings: string; public readonly locale: string; public readonly settings: string; - public readonly Snippets: string; + public readonly snippets: string; + public readonly storage: string; + public readonly profiles: string; public readonly dotVscode?: string; public readonly Extensions?: string; public readonly ExtensionsObsolete?: string; @@ -52,7 +59,9 @@ export class Distribution { this.keybindings = path.join(this.User, "keybindings.json"); this.locale = path.join(this.User, "locale.json"); this.settings = path.join(this.User, "settings.json"); - this.Snippets = path.join(this.User, "snippets"); + this.snippets = path.join(this.User, "snippets"); + this.storage = path.join(this.User, "globalStorage", "storage.json"); + this.profiles = path.join(this.User, "profiles"); const exts: vscode.Extension[] = vscode.extensions.all.filter(e => !e.packageJSON.isBuiltin); @@ -69,7 +78,9 @@ export class Distribution { ├ keybindings: ${this.keybindings} ├ locale: ${this.locale} ├ settings: ${this.settings} - └ Snippets: ${this.Snippets} + ├ snippets: ${this.snippets} + ├ storage: ${this.storage} + └ profiles: ${this.profiles} .vscode: ${this.dotVscode} ├ Extensions: ${this.Extensions} ├ ExtensionsObsolete: ${this.ExtensionsObsolete} @@ -80,7 +91,7 @@ export class Distribution { public getExtensions(): string | undefined { if(!files.isDirectory(this.Extensions)) return undefined; - const dotObsolete: string = this.ExtensionsObsolete && fs.existsSync(this.ExtensionsObsolete) ? fs.readFileSync(this.ExtensionsObsolete, "utf-8") : "{}"; + const dotObsolete: string = files.read(this.ExtensionsObsolete) ?? "{}"; const obsolete: {[id: string]: boolean} = isValidJson(dotObsolete) ? JSON.parse(dotObsolete) : {}; const uninstalled: string[] = Object.entries(obsolete).filter(([k, v]) => v).map(([k, v]) => k); @@ -95,7 +106,7 @@ export class Distribution { if(!files.isFile(pkgFile)) continue; - const json: string = fs.readFileSync(pkgFile, "utf-8"); + const json: string = files.read(pkgFile) ?? ""; if(!isValidJson(json)) continue; @@ -136,7 +147,7 @@ ${json.slice(0, -2)} public updateExtensions(): void { // we cannot handle enable/disable at the moment, see if(!files.isDirectory(this.Extensions) || !files.isFile(this.extensions)) return; - const json: string = fs.readFileSync(this.extensions, "utf-8"); + const json: string = files.read(this.extensions) ?? ""; const extensions: [{ identifier: string, @@ -163,7 +174,7 @@ ${json.slice(0, -2)} if(!files.isFile(pkgFile)) continue; - const json: string = fs.readFileSync(pkgFile, "utf-8"); + const json: string = files.read(pkgFile) ?? ""; if(!isValidJson(json)) continue; @@ -185,21 +196,36 @@ ${json.slice(0, -2)} } } - public getSettings(): string | undefined { - return files.isFile(this.settings) - ? fs.readFileSync(this.settings, "utf-8").trim() - : undefined; + public getProfiles(): Profile[] | undefined { + if(files.isFile(this.storage)){ + const content = (files.read(this.storage) ?? "").trim(); + if(isValidJson(content)){ + const obj = JSON.parse(content).userDataProfiles; + return Array.isArray(obj) ? obj : []; + } + } + return undefined; + } + + public writeProfiles(profiles: Profile[]) { + if(files.isFile(this.storage)){ + const content = (files.read(this.storage) ?? "").trim(); + if(isValidJson(content)){ + const obj: {userDataProfiles: Profile[]} = JSON.parse(content); + obj.userDataProfiles = [...(obj.userDataProfiles ?? []), ...(profiles ?? [])].filter((o, i, s) => s.findIndex(o => o.location === o.location) === i); + setTimeout(() => { + files.write(this.storage, JSON.stringify(obj, null, 4)); + logger.info("Finished deferred profile write"); + }, 1000 * 20); + }else{ + logger.error("Storage was malformed"); + } + } } private static readonly ctrl: RegExp = /(?<=^\s*"key"\s*:\s*".*)\bctrl\b(?=.*",?$)/gmi; // ⌃ ctrl private static readonly cmd: RegExp = /(?<=^\s*"key"\s*:\s*".*)\bcmd\b(?=.*",?$)/gmi; // ⌘ cmd - public getKeybindings(): string | undefined { - return files.isFile(this.keybindings) - ? fs.readFileSync(this.keybindings, "utf-8").trim() - : undefined; - } - public formatKeybindings(keybindings: string, ctrl: "ctrl" | "cmd" = "ctrl"): string { return keybindings.replace(ctrl === "ctrl" ? Distribution.cmd : Distribution.ctrl, ctrl); // ⌃ ctrl ↔ ⌘ cmd } @@ -208,7 +234,7 @@ ${json.slice(0, -2)} if(!files.isFile(this.keybindings)) return; // replace local keybindings with OS specific keybinds - fs.writeFileSync(this.keybindings, this.formatKeybindings(fs.readFileSync(this.keybindings, "utf-8"), this.macos ? "cmd" : "ctrl")); + files.write(this.keybindings, this.formatKeybindings(files.read(this.keybindings)!, this.macos ? "cmd" : "ctrl")); } private static readonly locale: RegExp = /(?<=^\s*"locale"\s*:\s*")[\w-]+(?=")/mi; @@ -216,30 +242,26 @@ ${json.slice(0, -2)} public getLocale(): string | undefined { if(!files.isFile(this.argv)) return undefined; - const argv: string = fs.readFileSync(this.argv!, "utf-8"); + const argv: string = files.read(this.argv)!; const match: RegExpExecArray | null = Distribution.locale.exec(argv); - return match && match.length > 0 - ? `{ - "locale": "${match[0]}" -}` - : undefined; + return match && match.length > 0 ? JSON.stringify({locale: match[0]}, null, 4) : undefined; } public updateLocale(): void { if(!files.isFile(this.argv) || !files.isFile(this.locale)) return; - const argv: string = fs.readFileSync(this.argv!, "utf-8"); + const argv: string = files.read(this.argv)!; - const json: string = fs.readFileSync(this.locale, "utf-8"); + const json: string = files.read(this.locale)!; if(!isValidJson(json)) return; const locale: any = JSON.parse(json); if(isNotNull(locale.locale)) - fs.writeFileSync(this.argv!, argv.replace(Distribution.locale, locale.locale).trim()); + files.write(this.argv!, argv.replace(Distribution.locale, locale.locale).trim()); } } \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 49563ad..9fe210f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -82,7 +82,7 @@ export const deactivate: () => Promise = async () => { export const notify: () => void = () => { const select: string = "Reload"; - vscode.window.showWarningMessage("Settings have been modified, a reload is required to see changes. Some changes require a full restart.", select, "Ignore").then((value?: string) => { + vscode.window.showWarningMessage("Settings have been modified, a reload is required to see changes. Profile changes require a full restart.", select, "Ignore").then((value?: string) => { if(value === select) vscode.commands.executeCommand("workbench.action.reloadWindow"); }); diff --git a/src/lib/files.ts b/src/lib/files.ts index 8bd90a4..9522e9f 100644 --- a/src/lib/files.ts +++ b/src/lib/files.ts @@ -42,10 +42,25 @@ export const copyRecursiveSync: (src: string | undefined | null, dest: string) = for(const file of fs.readdirSync(src!) || []){ const fsPath: string = path.join(src!, file); if(isFile(fsPath)) - fs.copyFileSync(fsPath, path.join(dest, file)); + copy(fsPath, path.join(dest, file)); else if(isDirectory(fsPath)){ fs.mkdirSync(path.join(dest, file)); copyRecursiveSync(fsPath, path.join(dest, file)); } } +} + +export const read: (src: string | undefined | null) => string | undefined = (src: string | undefined | null) => { + if(isFile(src)) + return fs.readFileSync(src!, {encoding: "utf-8"}); + else + return undefined; +} + +export const copy: (src: string | undefined | null, dest: string | undefined | null) => void = (src: string | undefined | null, dest: string | undefined | null) => { + isFile(src) && isNotNull(dest) && fs.copyFileSync(src!, dest!); +} + +export const write: (src: string | undefined | null, content: string | undefined | null) => void = (src: string | undefined | null, content: string | undefined | null) => { + isNotNull(src) && isNotNull(content) && fs.writeFileSync(src!, content!, {encoding: "utf-8"}); } \ No newline at end of file diff --git a/src/logger.ts b/src/logger.ts index a66446c..f11323d 100644 --- a/src/logger.ts +++ b/src/logger.ts @@ -27,7 +27,7 @@ export const warning: string = '⚠️'; const logger: vscode.OutputChannel = vscode.window.createOutputChannel("Settings Repository", "log"); const indent: (message: string) => string = (message: string) => { - return message.replace(/^/gm, " ").substring(6) + return `${message}`.replace(/^/gm, " ").substring(6) } export const log: (message: string) => void = (message: string) => { diff --git a/src/sync/git.ts b/src/sync/git.ts index 0bf9ccb..c27c444 100644 --- a/src/sync/git.ts +++ b/src/sync/git.ts @@ -24,14 +24,14 @@ import * as path from "path"; import simpleGit, { GitError, SimpleGit } from "simple-git"; -import { isNull } from "../lib/is"; +import { isNull, isValidJson } from "../lib/is"; import * as config from "../config"; import * as logger from "../logger"; import * as files from "../lib/files"; import * as auth from "../command/auth"; import * as extension from "../extension"; import * as statusbar from "../statusbar"; -import { Distribution } from "../distribution"; +import { Distribution, Profile } from "../distribution"; // @@ -57,9 +57,9 @@ export const pull: (repo: string, skipNotify?: boolean) => void = async (repo: s // init directory - const temp: string = fs.mkdtempSync(path.join(os.tmpdir(), "vscode-settings-repository-")); + const staging: string = fs.mkdtempSync(path.join(os.tmpdir(), "vscode-settings-repository-")); - if(!fs.existsSync(temp)) return logger.error(`Pull failed: unable to create temporary directory '${temp}'`, true); + if(!fs.existsSync(staging)) return logger.error(`Pull failed: unable to create temporary directory '${staging}'`, true); // repo @@ -72,7 +72,7 @@ export const pull: (repo: string, skipNotify?: boolean) => void = async (repo: s const gitback: (err: GitError | null) => void = (err: GitError | null) => { if(err){ logger.error(`Failed to pull from ${config.get("repository")}:\n ${auth.mask(err.message, cred)}`, true); - cleanup(temp); + cleanup(staging); } }; @@ -84,7 +84,7 @@ export const pull: (repo: string, skipNotify?: boolean) => void = async (repo: s logger.debug(`Git clone ${auth.mask(remote, cred)}`); try{ - const git: SimpleGit = simpleGit(temp); + const git: SimpleGit = simpleGit(staging); // clone repo on branch, omit history (not needed) await git.clone(remote, ".", ["-b", branch, "--depth", "1"], (err: GitError | null) => { @@ -92,10 +92,10 @@ export const pull: (repo: string, skipNotify?: boolean) => void = async (repo: s if(!err){ /* extensions */ { - const extensions: string = path.join(temp, "extensions.json"); + const extensions: string = path.join(staging, "extensions.json"); if(files.isFile(extensions)){ - fs.copyFileSync(extensions, dist.extensions); + files.copy(extensions, dist.extensions); dist.updateExtensions(); }else @@ -103,10 +103,10 @@ export const pull: (repo: string, skipNotify?: boolean) => void = async (repo: s } /* keybindings */ { - const keybindings: string = path.join(temp, "keybindings.json"); + const keybindings: string = path.join(staging, "keybindings.json"); if(files.isFile(keybindings)){ - fs.copyFileSync(keybindings, dist.keybindings); + files.copy(keybindings, dist.keybindings); dist.updateKeybindings(); // replace with OS specific keybinds }else @@ -114,10 +114,10 @@ export const pull: (repo: string, skipNotify?: boolean) => void = async (repo: s } /* locale */ { - const locale: string = path.join(temp, "locale.json"); + const locale: string = path.join(staging, "locale.json"); if(files.isFile(locale)){ - fs.copyFileSync(locale, dist.locale); + files.copy(locale, dist.locale); dist.updateLocale(); }else @@ -125,29 +125,45 @@ export const pull: (repo: string, skipNotify?: boolean) => void = async (repo: s } /* settings */ { - const settings: string = path.join(temp, "settings.json"); + const settings: string = path.join(staging, "settings.json"); if(files.isFile(settings)) - fs.copyFileSync(settings, dist.settings); + files.copy(settings, dist.settings); else logger.warn("Settings not found"); } /* snippets */ { - const snippets: string = path.join(temp, "snippets"); + const snippets: string = path.join(staging, "snippets"); - if(files.isDirectory(snippets)){ - // remove local, use remote copy - fs.rmSync(dist.Snippets, {recursive: true, force: true}); + if(files.isDirectory(snippets)) + files.copyRecursiveSync(snippets, dist.snippets); + else + logger.warn("Snippets not found"); + } + + /* profiles */ { + const storage: string = path.join(staging, "profiles.json"); - files.copyRecursiveSync(snippets, dist.Snippets); + if(files.isFile(storage)){ + const text = files.read(storage)!; + if(isValidJson(text)){ + dist.writeProfiles(JSON.parse(text)); + } }else - logger.warn("Snippets not found"); + logger.warn("Storage not found"); + + const profiles: string = path.join(staging, "profiles"); + + if(files.isDirectory(profiles)) + files.copyRecursiveSync(profiles, dist.profiles); + else + logger.warn("Profiles not found"); } logger.info(`Imported settings from ${config.get("repository")}@${branch}`, true); - cleanup(temp); + cleanup(staging); skipNotify || extension.notify(); } @@ -155,7 +171,7 @@ export const pull: (repo: string, skipNotify?: boolean) => void = async (repo: s }catch(error: any){ logger.error(`Push failed: ${auth.mask(error, cred)}`, true); }finally{ - cleanup(temp); + cleanup(staging); } } @@ -169,9 +185,9 @@ export const push: (repo: string, ignoreBadAuth?: boolean) => Promise = as // init directory - const temp: string = fs.mkdtempSync(path.join(os.tmpdir(), "vscode-settings-repository-")); + const staging: string = fs.mkdtempSync(path.join(os.tmpdir(), "vscode-settings-repository-")); - if(!fs.existsSync(temp)) return logger.error(`Push failed: unable to create temporary directory '${temp}'`, true); + if(!fs.existsSync(staging)) return logger.error(`Push failed: unable to create temporary directory '${staging}'`, true); // repo @@ -184,7 +200,7 @@ export const push: (repo: string, ignoreBadAuth?: boolean) => Promise = as const gitback: (err: GitError | null) => void = (err: GitError | null) => { if(err){ logger.error(`Failed to push to ${config.get("repository")}:\n ${auth.mask(err.message, cred)}`, true); - cleanup(temp); + cleanup(staging); } }; @@ -197,7 +213,7 @@ export const push: (repo: string, ignoreBadAuth?: boolean) => Promise = as logger.debug(`includeHostnameInCommit: ${config.get("includeHostnameInCommitMessage")}`); try{ - const git: SimpleGit = simpleGit(temp); + const git: SimpleGit = simpleGit(staging); // clone repo on branch, omit history (not needed) await git.clone(remote, ".", ["-b", branch, "--depth", "1"], (err: GitError | null) => { @@ -209,16 +225,16 @@ export const push: (repo: string, ignoreBadAuth?: boolean) => Promise = as const extensions: string | undefined = dist.getExtensions(); if(extensions) - fs.writeFileSync(path.join(temp, "extensions.json"), extensions, "utf-8"); + files.write(path.join(staging, "extensions.json"), extensions); else logger.warn("Extensions not found"); } /* keybindings */ { - const keybindings: string | undefined = dist.getKeybindings(); + const keybindings: string | undefined = files.read(dist.keybindings); if(keybindings) // force keybindings to be saved as ctrl - fs.writeFileSync(path.join(temp, "keybindings.json"), dist.formatKeybindings(keybindings, "ctrl"), "utf-8"); + files.write(path.join(staging, "keybindings.json"), dist.formatKeybindings(keybindings, "ctrl")); else logger.warn("Keybindings not found"); } @@ -227,35 +243,63 @@ export const push: (repo: string, ignoreBadAuth?: boolean) => Promise = as const locale: string | undefined = dist.getLocale(); if(locale) - fs.writeFileSync(path.join(temp, "locale.json"), locale, "utf-8"); + files.write(path.join(staging, "locale.json"), locale); else logger.warn("Locale not found"); } /* settings */ { - const settings: string | undefined = dist.getSettings(); + const settings: string | undefined = files.read(dist.settings); if(settings) - fs.writeFileSync(path.join(temp, "settings.json"), settings, "utf-8"); + files.write(path.join(staging, "settings.json"), settings); else logger.warn("Settings not found"); } /* snippets */ { - const snippets: string = path.join(temp, "snippets"); + const snippets: string = path.join(staging, "snippets"); // remove remote, use local copy fs.rmSync(snippets, {recursive: true, force: true}); - if(files.isDirectory(dist.Snippets)) - files.copyRecursiveSync(dist.Snippets, snippets); + if(files.isDirectory(dist.snippets)) + files.copyRecursiveSync(dist.snippets, snippets); else logger.warn("Snippets not found"); } + + /* profiles */ { + const prof: Profile[] | undefined = dist.getProfiles(); + + if(prof) + files.write(path.join(staging, "profiles.json"), JSON.stringify(prof, null, 4)); + else + logger.warn("Profiles not found"); + + const profiles: string = path.join(staging, "profiles"); + + // remove remote, use local copy + fs.rmSync(profiles, {recursive: true, force: true}); + + if(files.isDirectory(dist.profiles)){ + for(const dir of fs.readdirSync(dist.profiles)){ + const profile: string = path.join(dist.profiles, dir); + if(files.isDirectory(profile)){ + for(const f of ["extensions.json", "keybindings.json", "settings.json"]){ + files.copy(path.join(profile, f), path.join(profiles, dir, f)); + } + const snippets: string = path.join(profile, "snippets"); + files.copyRecursiveSync(snippets, path.join(profiles, dir, "snippets")); + } + } + }else + logger.warn("Profiles dir not found"); + } }catch(error: any){ if(error){ logger.error(`Push failed: ${auth.mask(error, cred)}`, true); - cleanup(temp); + cleanup(staging); } } } @@ -269,12 +313,12 @@ export const push: (repo: string, ignoreBadAuth?: boolean) => Promise = as gitback(err); if(!err){ logger.info(`Pushed settings to ${config.get("repository")}@${branch}`, true); - cleanup(temp); + cleanup(staging); } }); }catch(error: any){ logger.error(`Push failed: ${auth.mask(error, cred)}`, true); }finally{ - cleanup(temp); + cleanup(staging); } } \ No newline at end of file diff --git a/src/sync/zip.ts b/src/sync/zip.ts index 128869a..aa4d24f 100644 --- a/src/sync/zip.ts +++ b/src/sync/zip.ts @@ -18,10 +18,14 @@ import AdmZip from "adm-zip"; +import * as fs from "fs"; +import * as path from "path"; + import * as logger from "../logger"; import * as files from "../lib/files"; import * as extension from "../extension"; -import { Distribution } from "../distribution"; +import { Distribution, Profile } from "../distribution"; +import { isValidJson } from "../lib/is"; // @@ -34,13 +38,15 @@ export const inport: (fsPath: string) => void = (fsPath: string) => { try{ // import from zip const zip: AdmZip = new AdmZip(fsPath); + const extract = (file: string) => zip.extractEntryTo(file, dist.User, undefined, true); + logger.info(`Preparing to import settings from ${fsPath}`); /* extensions */ { const extensions: AdmZip.IZipEntry | null = zip.getEntry("extensions.json"); if(extensions && !extensions.isDirectory){ - zip.extractEntryTo("extensions.json", dist.User, undefined, true); + extract("extensions.json"); dist.updateExtensions(); }else @@ -51,7 +57,7 @@ export const inport: (fsPath: string) => void = (fsPath: string) => { const keybindings: AdmZip.IZipEntry | null = zip.getEntry("keybindings.json"); if(keybindings && !keybindings.isDirectory){ - zip.extractEntryTo("keybindings.json", dist.User, undefined, true); + extract("keybindings.json"); dist.updateKeybindings(); // replace with OS specific keybinds }else @@ -62,7 +68,7 @@ export const inport: (fsPath: string) => void = (fsPath: string) => { const locale: AdmZip.IZipEntry | null = zip.getEntry("locale.json"); if(locale && !locale.isDirectory){ - zip.extractEntryTo("locale.json", dist.User, undefined, true); + extract("locale.json"); dist.updateLocale(); }else @@ -73,7 +79,7 @@ export const inport: (fsPath: string) => void = (fsPath: string) => { const settings: AdmZip.IZipEntry | null = zip.getEntry("settings.json"); if(settings && !settings.isDirectory) - zip.extractEntryTo("settings.json", dist.User, undefined, true); + extract("settings.json"); else logger.warn("Settings not found"); } @@ -82,13 +88,33 @@ export const inport: (fsPath: string) => void = (fsPath: string) => { let hasSnippets: boolean = false; for(const entry of zip.getEntries().filter(f => f.entryName.toLowerCase().startsWith("snippets/")).map(f => f.entryName)){ hasSnippets = true; - zip.extractEntryTo(entry, dist.User, undefined, true); + extract(entry); } if(!hasSnippets) logger.warn("Snippets not found"); } + /* profiles */ { + const storage: AdmZip.IZipEntry | null = zip.getEntry("profiles.json"); + if(storage && !storage.isDirectory){ + const text = zip.readAsText("profiles.json", "utf-8"); + if(isValidJson(text)) + dist.writeProfiles(JSON.parse(text)); + else + logger.error("Profile json was invalid"); + } + + let hasProfiles: boolean = false; + for(const entry of zip.getEntries().filter(f => f.entryName.toLowerCase().startsWith("profiles/")).map(f => f.entryName)){ + hasProfiles = true; + extract(entry); + } + + if(!hasProfiles) + logger.warn("Profiles not found"); + } + logger.info(`Imported settings from ${fsPath}`, true); extension.notify(); @@ -103,22 +129,24 @@ export const xport: (fsPath: string) => void = (fsPath: string) => { try{ const zip: AdmZip = new AdmZip(); + const insert = (file: string, content: string) => zip.addFile(file, Buffer.from(content, "utf-8")); + logger.info(`Preparing to export settings to ${fsPath}`); /* extensions */ { const extensions: string | undefined = dist.getExtensions(); if(extensions) - zip.addFile("extensions.json", Buffer.from(extensions, "utf-8")); + insert("extensions.json", extensions); else logger.warn("Extensions not found"); } /* keybindings */ { - const keybindings: string | undefined = dist.getKeybindings(); + const keybindings: string | undefined = files.read(dist.keybindings); if(keybindings) // force keybindings to be saved as ctrl - zip.addFile("keybindings.json", Buffer.from(dist.formatKeybindings(keybindings), "utf-8")); + insert("keybindings.json", dist.formatKeybindings(keybindings)); else logger.warn("Keybindings not found"); } @@ -127,27 +155,52 @@ export const xport: (fsPath: string) => void = (fsPath: string) => { const locale: string | undefined = dist.getLocale(); if(locale) - zip.addFile("locale.json", Buffer.from(locale)); + insert("locale.json", locale); else logger.warn("Locale not found"); } /* settings */ { - const settings: string | undefined = dist.getSettings(); + const settings: string | undefined = files.read(dist.settings); if(settings) - zip.addFile("settings.json", Buffer.from(settings, "utf-8")); + insert("settings.json", settings); else logger.warn("Settings not found"); } /* snippets */ { - if(files.isDirectory(dist.Snippets)) - zip.addLocalFolder(dist.Snippets, "snippets"); + if(files.isDirectory(dist.snippets)) + zip.addLocalFolder(dist.snippets, "snippets"); else logger.warn("Snippets not found"); } + /* profiles */ { + const profiles: Profile[] | undefined = dist.getProfiles(); + if(profiles) + insert("profiles.json", JSON.stringify(profiles, null, 4)); + else + logger.warn("Profiles not found"); + + if(files.isDirectory(dist.profiles)){ + for(const dir of fs.readdirSync(dist.profiles)){ + const profile: string = path.join(dist.profiles, dir); + if(files.isDirectory(profile)){ + for(const f of ["extensions.json", "keybindings.json", "settings.json"]){ + const file = path.join(profile, f); + files.isFile(file) && insert(`profiles/${dir}/${f}`, files.read(file)!); + } + const snippets: string = path.join(profile, "snippets"); + if(files.isDirectory(snippets)){ + zip.addLocalFolder(snippets, `profiles/${dir}/snippets`); + } + } + } + }else + logger.warn("Profiles dir not found"); + } + zip.writeZip(fsPath, (error: Error | null) => { if(error) logger.error(`Failed to export settings: ${error}`, true);