diff --git a/.gitignore b/.gitignore index 4bf9729..9b85972 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ node_modules dist +.vscode-test + +test/__* + *.vsix \ No newline at end of file diff --git a/README.md b/README.md index 40215d8..f68f68a 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,56 @@ This extension modifies an internal file to make backgrounds work, if VSCode sto This extension also modifies `%LocalAppData%\Programs\Microsoft VS Code\resources\app\product.json`, replace with `product-backup.json` if VSCode stops working. +## 🔌 API + +Add this extension to your `package.json`. + +```json +{ + ... + "extensionDependencies": [ + "katsute.code-background" + ] + ... +} +``` + +Access the api by using: + +```js +const background = vscode.extensions.getExtension("katsute.code-background").exports; +``` + +* `install(): void` + + Runs the `Background: Install` command. +* `uninstall(): void` + + Runs the `Background: Uninstall` command. +* `reload(): void` + + Runs the `Background: Reload` command. +* `get(ui): string[]?` + * `ui` : Background to get from; either `window`, `editor`, `sidebar`, `panel`. + + Returns an array of globs for the specified background. +* `add(ui, glob): Promise` + * `ui` : Background to add to; either `window`, `editor`, `sidebar`, `panel`. + * `glob`: Glob to add. + + Returns true if successful. +* `replace(ui, old, glob): Promise` + * `ui` : Background to replace from; either `window`, `editor`, `sidebar`, `panel`. + * `old`: Glob to replace. + * `glob`: Updated glob. + + Returns true if successful. +* `remove(ui, glob): Promise` + * `ui` : Background to remove from; either `window`, `editor`, `sidebar`, `panel`. + * `glob`: Glob to remove. + + Returns true if successful. + ##   @@ -156,4 +206,4 @@ This extension also modifies `%LocalAppData%\Programs\Microsoft VS Code\resource -This extension is released under the [GNU General Public License (GPL) v2.0](https://github.com/KatsuteDev/Background/blob/main/LICENSE). \ No newline at end of file +This extension is released under the [GNU General Public License (GPL) v2.0](https://github.com/KatsuteDev/Background/blob/main/LICENSE). diff --git a/package-lock.json b/package-lock.json index 1f79a50..50eafde 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "code-background", - "version": "2.5.8", + "version": "2.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "code-background", - "version": "2.5.8", + "version": "2.6.0", "license": "GPL-2.0-only", "dependencies": { "@vscode/sudo-prompt": "9.3.1", @@ -17,6 +17,7 @@ "@types/node": "20.4.1", "@types/tmp": "0.2.3", "@types/vscode": "1.80.0", + "@vscode/test-electron": "2.3.3", "@vscode/vsce": "2.19.0", "rimraf": "5.0.1", "typescript": "5.1.6" @@ -50,6 +51,15 @@ "node": ">=14" } }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, "node_modules/@types/node": { "version": "20.4.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.1.tgz", @@ -73,6 +83,36 @@ "resolved": "https://registry.npmjs.org/@vscode/sudo-prompt/-/sudo-prompt-9.3.1.tgz", "integrity": "sha512-9ORTwwS74VaTn38tNbQhsA5U44zkJfcb0BdTSyyG6frP4e8KMtHuTXYmwefe5dpL8XB1aGSIVTaLjD3BbWb5iA==" }, + "node_modules/@vscode/test-electron": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-2.3.3.tgz", + "integrity": "sha512-hgXCkDP0ibboF1K6seqQYyHAzCURgTwHS/6QU7slhwznDLwsRwg9bhfw1CZdyUEw8vvCmlrKWnd7BlQnI0BC4w==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "jszip": "^3.10.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@vscode/test-electron/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@vscode/vsce": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.19.0.tgz", @@ -130,6 +170,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, "node_modules/ansi-regex": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", @@ -357,6 +409,12 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -398,6 +456,23 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/decompress-response": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", @@ -723,6 +798,33 @@ "entities": "^4.4.0" } }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -744,6 +846,12 @@ ], "optional": true }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -773,6 +881,12 @@ "node": ">=8" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -801,6 +915,48 @@ "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/keytar": { "version": "7.9.0", "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", @@ -822,6 +978,15 @@ "node": ">=6" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/linkify-it": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", @@ -935,6 +1100,12 @@ "dev": true, "optional": true }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", @@ -1013,6 +1184,12 @@ "wrappy": "1" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, "node_modules/parse-semver": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", @@ -1119,6 +1296,12 @@ "node": ">=10" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -1242,6 +1425,12 @@ "semver": "bin/semver" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1595,8 +1784,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "optional": true + "dev": true }, "node_modules/which": { "version": "2.0.2", diff --git a/package.json b/package.json index 948414a..dc29037 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "theme": "dark" }, "publisher": "Katsute", - "version": "2.5.8", + "version": "2.6.0", "private": true, "engines": { "vscode": "^1.80.0" @@ -315,7 +315,9 @@ "build": "tsc --outDir dist", "prepare": "npm run clean && npm run build", "// -- deploy -- //": "", - "package": "vsce package" + "package": "vsce package", + "// -- test -- //": "", + "test": "node ./test/index.js" }, "repository": { "type": "git", @@ -336,6 +338,7 @@ "@types/node": "20.4.1", "@types/tmp": "0.2.3", "@types/vscode": "1.80.0", + "@vscode/test-electron": "2.3.3", "@vscode/vsce": "2.19.0", "rimraf": "5.0.1", "typescript": "5.1.6" diff --git a/src/command/config/file.ts b/src/command/config/file.ts index 1f0dc89..9c22485 100644 --- a/src/command/config/file.ts +++ b/src/command/config/file.ts @@ -31,25 +31,29 @@ import { notify } from "../install"; // config -const add: (ui: UI, glob: string, skipWarning?: boolean) => Promise = async (ui: UI, glob: string, skipWarning: boolean = false) => { +export const view: (ui: UI) => string[] = (ui: UI) => { + return get(`${ui}Backgrounds`) as string[]; +} + +export const add: (ui: UI, glob: string, skipWarning?: boolean) => Promise = async (ui: UI, glob: string, skipWarning: boolean = false) => { const files: string[] = get(`${ui}Backgrounds`) as string[]; files.push(glob); await update(`${ui}Backgrounds`, files.filter(unique), undefined, skipWarning); skipWarning || cm({label: '␀', ui}); // reopen menu }; -const replace: (ui: UI, old: string, glob: string, remove?: boolean) => Promise = async (ui: UI, old: string, glob: string) => { +export const replace: (ui: UI, old: string, glob: string, skipWarning?: boolean) => Promise = async (ui: UI, old: string, glob: string, skipWarning: boolean = false) => { const files: string[] = get(`${ui}Backgrounds`) as string[]; for(let i = 0, l = files.length; i < l; i++) if(files[i] === old) files[i] = glob; - await update(`${ui}Backgrounds`, files.filter(unique), undefined, old === glob); - cm({label: '␀', ui}); // reopen menu + await update(`${ui}Backgrounds`, files.filter(unique), undefined, skipWarning || old === glob); + skipWarning || cm({label: '␀', ui}); // reopen menu }; -const remove: (ui: UI, glob: string) => Promise = async (ui: UI, glob: string) => { - await update(`${ui}Backgrounds`, (get(`${ui}Backgrounds`) as string[]).filter((f) => f !== glob).filter(unique)); - cm({label: '␀', ui}); // reopen files +export const remove: (ui: UI, glob: string, skipWarning?: boolean) => Promise = async (ui: UI, glob: string, skipWarning: boolean = false) => { + await update(`${ui}Backgrounds`, (get(`${ui}Backgrounds`) as string[]).filter((f) => f !== glob).filter(unique), undefined, skipWarning); + skipWarning || cm({label: '␀', ui}); // reopen files }; // exts diff --git a/src/extension.ts b/src/extension.ts index 12c01a5..a5c6a6e 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -56,7 +56,7 @@ const cp: (files: [string, string][], asterisk?: boolean) => string = (files: [s return commands.join(" && "); }; -export const activate: (context: vscode.ExtensionContext) => void = (context: vscode.ExtensionContext) => { +export const activate: (context: vscode.ExtensionContext) => any = (context: vscode.ExtensionContext) => { // internal files if(require.main && require.main.filename){ // %appdata%/Local/Programs/Microsoft VS Code/resources/app/out/vs/workbench/workbench.desktop.main.js @@ -110,6 +110,59 @@ export const activate: (context: vscode.ExtensionContext) => void = (context: vs context.subscriptions.push(statusbar); statusbar.show(); + + return { + install: () => installJS(), + uninstall: () => uninstallJS(), + reload: () => vscode.commands.executeCommand("workbench.action.reloadWindow"), + get: (ui: string) => { + switch(ui){ + case "window": + case "editor": + case "sidebar": + case "panel": + return file.view(ui); + default: + return undefined; + } + }, + add: async (ui: string, glob: string) => { + switch(ui){ + case "window": + case "editor": + case "sidebar": + case "panel": + await file.add(ui, glob, true); + return true; + default: + return false; + } + }, + replace: async (ui: string, old: string, glob: string) => { + switch(ui){ + case "window": + case "editor": + case "sidebar": + case "panel": + await file.replace(ui, old, glob, true); + return true; + default: + return false; + } + }, + remove: async (ui: string, glob: string) => { + switch(ui){ + case "window": + case "editor": + case "sidebar": + case "panel": + await file.remove(ui, glob, true); + return true; + default: + return false; + } + } + }; }; // diff --git a/test/index.js b/test/index.js new file mode 100644 index 0000000..832e9b6 --- /dev/null +++ b/test/index.js @@ -0,0 +1,13 @@ +const fs = require("fs"); +const path = require("path"); + +const file = path.join(__dirname, "__testno__"); + +const vscode = require("@vscode/test-electron"); + +!fs.existsSync(file) || fs.unlinkSync(file); + +vscode.runTests({ + extensionDevelopmentPath: path.join(__dirname, "../"), + extensionTestsPath: path.join(__dirname, "test.js") +}); \ No newline at end of file diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..dfbfe0c --- /dev/null +++ b/test/test.js @@ -0,0 +1,82 @@ +const fs = require("fs"); +const path = require("path"); + +const vscode = require("vscode"); + +const file = path.join(__dirname, "__testno__"); + +const images = path.join(__dirname, "*.png").replace(/\\/gm, '/'); + +module.exports = { + run: () => new Promise(async () => { + await wait(5); + + const background = vscode.extensions.getExtension("katsute.code-background").exports; + + let num; + if(!fs.existsSync(file)){ + for(const ui of ["window", "editor", "sidebar", "panel"]) + for(const image of await background.get(ui)) + await background.remove(ui, image); + fs.writeFileSync(file, '0', "utf-8"); + background.install(); + }else if((num = fs.readFileSync(file, "utf-8")) == 0){ + vscode.window.showInformationMessage("Testing empty install"); + + await wait(3); + + await background.add("window", images); + + fs.writeFileSync(file, `${++num}`, "utf-8"); + + background.install(); + }else if(num >= 1 && num <= 5){ + vscode.window.showInformationMessage(`Testing window backgrounds (${num}/5)`); + + await wait(3); + + fs.writeFileSync(file, `${++num}`, "utf-8"); + + if(num == 6){ + await background.remove("window", images); + await background.add("editor", images); + await background.add("sidebar", images); + await background.add("panel", images); + + background.install(); + }else{ + background.reload(); + } + + }else if(num >= 6 && num <= 10){ + vscode.window.showInformationMessage(`Testing other backgrounds (${num-5}/5)`); + + await wait(3); + + fs.writeFileSync(file, `${++num}`, "utf-8"); + + if(num == 11) + background.uninstall(); + else + background.reload(); + }else if(num == 11){ + vscode.window.showInformationMessage(`Testing uninstall`); + + await wait(3); + + await background.add("window", images); + + fs.writeFileSync(file, `${++num}`, "utf-8"); + + background.reload(); + }else{ + await background.replace("window", images, images.replace(".png", '')); + + vscode.window.showInformationMessage(`All tests completed!\n\nBackgrounds are: \nwindow: [${await background.get("window")}]\neditor: [${await background.get("editor")}]\nsidebar: [${await background.get("sidebar")}]\npanel: [${await background.get("panel")}]`); + + fs.unlinkSync(file); + } + }) +}; + +const wait = (time) => new Promise((res) => setTimeout(() => res(), 1000 * time)); \ No newline at end of file