From fbc143fd107880aae093d9b4536af02cf95b5e11 Mon Sep 17 00:00:00 2001 From: bingenito Date: Thu, 1 May 2025 17:08:41 -0400 Subject: [PATCH 1/2] chore: Upgrade to eslint9 --- .eslintrc.json | 33 - eslint.config.mjs | 115 +++ package-lock.json | 786 +++++++++--------- package.json | 13 +- packages/desktopjs-electron/tests/setup.ts | 14 + packages/desktopjs-electron/vite.config.ts | 14 + packages/desktopjs-openfin/src/openfin.ts | 7 +- .../desktopjs-openfin/tests/openfin.spec.ts | 351 +------- packages/desktopjs-openfin/vite.config.ts | 14 + packages/desktopjs/tests/setup.ts | 14 + packages/desktopjs/vite.config.ts | 14 + tsconfig.test.json | 10 +- 12 files changed, 635 insertions(+), 750 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 eslint.config.mjs diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 6dfa9d02..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "plugins": [ - "@typescript-eslint" - ], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended" - ], - "rules": { - "@typescript-eslint/no-inferrable-types": ["error", { "ignoreProperties": true, "ignoreParameters": true}], - "@typescript-eslint/no-unused-vars" : "off", - "@typescript-eslint/no-explicit-any" : "off", - "no-console": "error" - }, - "overrides": [ - { - "files": ["**/*.spec.ts"], - "rules": { - "@typescript-eslint/ban-types": "off", - "@typescript-eslint/no-empty-function": "off", - "no-console": "warn" - } - } - ], - "ignorePatterns": [ - "**/dist/*", - "**/build/*", - "**/gulpfile.js", - "docs/", - "examples/*" - ] -} diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 00000000..04d0ced8 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,115 @@ +import eslint from '@eslint/js'; +import * as tsParser from '@typescript-eslint/parser'; +import tsPlugin from '@typescript-eslint/eslint-plugin'; +import eslintPluginImport from 'eslint-plugin-import'; +import eslintPluginN from 'eslint-plugin-n'; +import eslintPluginPromise from 'eslint-plugin-promise'; +import licenseHeader from 'eslint-plugin-license-header'; // Import the license header plugin +import globals from 'globals'; // Import globals +import path from 'node:path'; // Import path module +import { fileURLToPath } from 'node:url'; // Import fileURLToPath + +// Derive __dirname in ES module scope +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Define the license header as an array of strings +const LICENSE_HEADER = [ + "/*", + " * Morgan Stanley makes this available to you under the Apache License,", + " * Version 2.0 (the \"License\"). You may obtain a copy of the License at", + " *", + " * http://www.apache.org/licenses/LICENSE-2.0.", + " *", + " * See the NOTICE file distributed with this work for additional information", + " * regarding copyright ownership. Unless required by applicable law or agreed", + " * to in writing, software distributed under the License is distributed on an", + " * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express", + " * or implied. See the License for the specific language governing permissions", + " * and limitations under the License.", + " */" +]; + +export default [ + { + // Global ignores + ignores: [ + "**/dist/**", + "**/build/**", + "**/coverage/**", + "docs/**", + "examples/**", // Ignore all examples for now + "**/gulpfile.js", + "*.config.js", // Ignore JS config files + "*.config.mjs", // Ignore MJS config files + "vite.config.ts" // Ignore root vite config + ] + }, + eslint.configs.recommended, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parser: tsParser, + parserOptions: { + // Instead of 'tsconfig.eslint.json', point to the updated test config + project: './tsconfig.test.json', + tsconfigRootDir: __dirname, // Important for resolving paths correctly + }, + globals: { + ...globals.browser, + ...globals.node, + ...globals.es2021 + } + }, + plugins: { + '@typescript-eslint': tsPlugin, + import: eslintPluginImport, + n: eslintPluginN, + promise: eslintPluginPromise, + 'license-header': licenseHeader // Add the license header plugin + }, + rules: { + ...tsPlugin.configs.recommended.rules, + '@typescript-eslint/no-inferrable-types': ['error', { ignoreProperties: true, ignoreParameters: true }], + '@typescript-eslint/no-unused-vars': 'off', + '@typescript-eslint/no-explicit-any': 'off', + 'no-console': 'error', + 'no-undef': 'off', + 'no-redeclare': 'off', // Disable base rule + '@typescript-eslint/no-redeclare': 'error', // Enable TS version (already included in recommended, but explicit) + 'license-header/header': ['error', LICENSE_HEADER] // Update the license header rule to use the array + }, + }, + { + // Override for Electron source file allowing require + files: ['packages/desktopjs-electron/src/electron.ts'], + rules: { + '@typescript-eslint/no-require-imports': 'off' + } + }, + { + // Override for spec files + files: ['**/*.spec.ts'], + // Exclude TS rules requiring type info for spec files if they cause issues + // Alternatively, ensure tsconfig.test.json includes them correctly + rules: { + '@typescript-eslint/ban-types': 'off', + '@typescript-eslint/no-empty-function': 'off', + 'no-console': 'warn', + }, + }, + { + // Override for JS files (if any are linted) + files: ['**/*.js'], + languageOptions: { + globals: { + ...globals.browser, + ...globals.node + } + }, + rules: { + 'no-unused-vars': 'warn', + 'no-undef': 'warn' + } + } +]; diff --git a/package-lock.json b/package-lock.json index 4db26fc3..facee32e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,18 +13,21 @@ "examples/electron" ], "devDependencies": { + "@eslint/eslintrc": "^3.3.1", "@jest/globals": "^29.7.0", "@rollup/plugin-replace": "^6.0.2", "@types/jest": "^29.5.14", "@types/node": "^20.17.30", - "@typescript-eslint/eslint-plugin": "^7.18.0", - "@typescript-eslint/parser": "^7.18.0", + "@typescript-eslint/eslint-plugin": "^8.31.1", + "@typescript-eslint/parser": "^8.31.1", "@vitest/coverage-v8": "^3.1.1", "copyfiles": "^2.4.1", - "eslint": "^8.57.1", + "eslint": "^9.25.1", "eslint-plugin-import": "^2.31.0", - "eslint-plugin-n": "^16.6.2", - "eslint-plugin-promise": "^6.6.0", + "eslint-plugin-license-header": "^0.8.0", + "eslint-plugin-n": "^17.17.0", + "eslint-plugin-promise": "^7.2.1", + "globals": "^16.0.0", "husky": "^9.1.7", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", @@ -1046,17 +1049,79 @@ "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", + "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -1064,7 +1129,7 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -1081,6 +1146,19 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -1095,13 +1173,37 @@ } }, "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.25.1.tgz", + "integrity": "sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==", "dev": true, "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@gerrit0/mini-shiki": { @@ -1116,44 +1218,42 @@ "@shikijs/vscode-textmate": "^10.0.1" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "license": "Apache-2.0", "engines": { - "node": "*" + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/module-importer": { @@ -1170,13 +1270,19 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", "dev": true, - "license": "BSD-3-Clause" + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@isaacs/cliui": { "version": "8.0.2", @@ -2676,6 +2782,13 @@ "parse5": "^7.0.0" } }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -2732,80 +2845,72 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", - "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz", + "integrity": "sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/type-utils": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/type-utils": "8.31.1", + "@typescript-eslint/utils": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.1.tgz", + "integrity": "sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/typescript-estree": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz", + "integrity": "sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2813,41 +2918,37 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", - "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz", + "integrity": "sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/utils": "7.18.0", + "@typescript-eslint/typescript-estree": "8.31.1", + "@typescript-eslint/utils": "8.31.1", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.1.tgz", + "integrity": "sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==", "dev": true, "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -2855,81 +2956,86 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", - "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz", + "integrity": "sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/visitor-keys": "8.31.1", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.0.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.1.tgz", + "integrity": "sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" + "@typescript-eslint/scope-manager": "8.31.1", + "@typescript-eslint/types": "8.31.1", + "@typescript-eslint/typescript-estree": "8.31.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", + "version": "8.31.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz", + "integrity": "sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.18.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.31.1", + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, - "license": "ISC" + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } }, "node_modules/@vitest/coverage-v8": { "version": "3.1.1", @@ -3445,16 +3551,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/array.prototype.findlastindex": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", @@ -3845,29 +3941,6 @@ "dev": true, "license": "MIT" }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/builtins": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", - "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.0.0" - } - }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", @@ -4565,32 +4638,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/domexception": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", @@ -4670,6 +4717,20 @@ "dev": true, "license": "MIT" }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -4946,60 +5007,64 @@ } }, "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "9.25.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.25.1.tgz", + "integrity": "sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.1", + "@eslint/core": "^0.13.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.25.1", + "@eslint/plugin-kit": "^0.2.8", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-compat-utils": { @@ -5181,67 +5246,66 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-license-header": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-license-header/-/eslint-plugin-license-header-0.8.0.tgz", + "integrity": "sha512-khTCz6G3JdoQfwrtY4XKl98KW4PpnWUKuFx8v+twIRhJADEyYglMDC0td8It75C1MZ88gcvMusWuUlJsos7gYg==", + "dev": true, + "license": "MIT", + "dependencies": { + "requireindex": "^1.2.0" + } + }, "node_modules/eslint-plugin-n": { - "version": "16.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", - "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", + "version": "17.17.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.17.0.tgz", + "integrity": "sha512-2VvPK7Mo73z1rDFb6pTvkH6kFibAmnTubFq5l83vePxu0WiY1s0LOtj2WHb6Sa40R3w4mnh8GFYbHBQyMlotKw==", "dev": true, "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "builtins": "^5.0.1", - "eslint-plugin-es-x": "^7.5.0", - "get-tsconfig": "^4.7.0", - "globals": "^13.24.0", - "ignore": "^5.2.4", - "is-builtin-module": "^3.2.1", - "is-core-module": "^2.12.1", - "minimatch": "^3.1.2", - "resolve": "^1.22.2", - "semver": "^7.5.3" + "@eslint-community/eslint-utils": "^4.5.0", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "ignore": "^5.3.2", + "minimatch": "^9.0.5", + "semver": "^7.6.3" }, "engines": { - "node": ">=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "eslint": ">=7.0.0" + "eslint": ">=8.23.0" } }, - "node_modules/eslint-plugin-n/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/eslint-plugin-n/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-n/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, "engines": { - "node": "*" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint-plugin-promise": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz", - "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.2.1.tgz", + "integrity": "sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==", "dev": true, "license": "ISC", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5251,9 +5315,9 @@ } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -5261,7 +5325,7 @@ "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5291,6 +5355,19 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -5305,18 +5382,31 @@ } }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.14.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5552,16 +5642,16 @@ } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/filelist": { @@ -5618,35 +5708,17 @@ } }, "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" + "keyv": "^4.5.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16" } }, "node_modules/flatted": { @@ -5992,16 +6064,13 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", "dev": true, "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, "engines": { - "node": ">=8" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6024,27 +6093,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -6443,22 +6491,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "license": "MIT", - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -6644,16 +6676,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -8972,16 +8994,6 @@ "dev": true, "license": "ISC" }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -9400,6 +9412,16 @@ "node": ">=0.10.0" } }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.5" + } + }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", @@ -10302,6 +10324,16 @@ "dev": true, "license": "MIT" }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/test-exclude": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", @@ -10338,13 +10370,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, "node_modules/through2": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", @@ -10483,16 +10508,16 @@ } }, "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.12" }, "peerDependencies": { - "typescript": ">=4.2.0" + "typescript": ">=4.8.4" } }, "node_modules/ts-jest": { @@ -10617,19 +10642,6 @@ "node": ">=4" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", diff --git a/package.json b/package.json index dc0e2419..8a966684 100644 --- a/package.json +++ b/package.json @@ -18,18 +18,21 @@ "version": "npx lerna version --no-push --no-git-tag-version" }, "devDependencies": { + "@eslint/eslintrc": "^3.3.1", "@jest/globals": "^29.7.0", "@rollup/plugin-replace": "^6.0.2", "@types/jest": "^29.5.14", "@types/node": "^20.17.30", - "@typescript-eslint/eslint-plugin": "^7.18.0", - "@typescript-eslint/parser": "^7.18.0", + "@typescript-eslint/eslint-plugin": "^8.31.1", + "@typescript-eslint/parser": "^8.31.1", "@vitest/coverage-v8": "^3.1.1", "copyfiles": "^2.4.1", - "eslint": "^8.57.1", + "eslint": "^9.25.1", "eslint-plugin-import": "^2.31.0", - "eslint-plugin-n": "^16.6.2", - "eslint-plugin-promise": "^6.6.0", + "eslint-plugin-license-header": "^0.8.0", + "eslint-plugin-n": "^17.17.0", + "eslint-plugin-promise": "^7.2.1", + "globals": "^16.0.0", "husky": "^9.1.7", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", diff --git a/packages/desktopjs-electron/tests/setup.ts b/packages/desktopjs-electron/tests/setup.ts index 6e2e3e65..20f33412 100644 --- a/packages/desktopjs-electron/tests/setup.ts +++ b/packages/desktopjs-electron/tests/setup.ts @@ -1,3 +1,17 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. Unless required by applicable law or agreed + * to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + /** * Jest Setup File for desktopJS-electron * diff --git a/packages/desktopjs-electron/vite.config.ts b/packages/desktopjs-electron/vite.config.ts index 5e13b2a2..6631bd0b 100644 --- a/packages/desktopjs-electron/vite.config.ts +++ b/packages/desktopjs-electron/vite.config.ts @@ -1,3 +1,17 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. Unless required by applicable law or agreed + * to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + import { defineConfig } from 'vite'; import { resolve } from 'path'; import dts from 'vite-plugin-dts'; diff --git a/packages/desktopjs-openfin/src/openfin.ts b/packages/desktopjs-openfin/src/openfin.ts index cbd2dc6b..4783f8ba 100644 --- a/packages/desktopjs-openfin/src/openfin.ts +++ b/packages/desktopjs-openfin/src/openfin.ts @@ -166,7 +166,12 @@ export class OpenFinContainerWindow extends ContainerWindow { public getState(): Promise { return new Promise(resolve => { - (this.nativeWindow && (this.nativeWindow).getState) ? resolve((this.nativeWindow).getState()) : resolve(undefined); + // Use explicit if/else instead of ternary for side-effect + if (this.nativeWindow && (this.nativeWindow).getState) { + resolve((this.nativeWindow).getState()); + } else { + resolve(undefined); + } }); } diff --git a/packages/desktopjs-openfin/tests/openfin.spec.ts b/packages/desktopjs-openfin/tests/openfin.spec.ts index 3a01be08..6bccc84d 100644 --- a/packages/desktopjs-openfin/tests/openfin.spec.ts +++ b/packages/desktopjs-openfin/tests/openfin.spec.ts @@ -2,7 +2,7 @@ * Morgan Stanley makes this available to you under the Apache License, * Version 2.0 (the "License"). You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0. * * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. Unless required by applicable law or agreed @@ -397,16 +397,15 @@ describe("OpenFinContainer", () => { }); it("application window-created fires container window-created", (done) => { - // We need to use EventEmitter for this test const eventEmitter = { listeners: {}, - addListener: function(event: string, listener: Function) { + addListener: function(event: string, listener: (...args: any[]) => void) { this.listeners[event] = this.listeners[event] || []; this.listeners[event].push(listener); }, emit: function(event: string, ...args: any[]) { if (this.listeners[event]) { - this.listeners[event].forEach((listener: Function) => listener(...args)); + this.listeners[event].forEach((listener: (...args: any[]) => void) => listener(...args)); } } }; @@ -613,7 +612,6 @@ describe("OpenFinContainer", () => { return {}; }; - // Mock getBounds for both windows mockWindowWithPersistFalse.getBounds = (callback, error) => { callback({ left: 0, top: 0, width: 100, height: 100 }); return {}; @@ -624,65 +622,50 @@ describe("OpenFinContainer", () => { return {}; }; - // Mock getNativeWindow for both windows jest.spyOn(mockWindowWithPersistFalse, 'getNativeWindow').mockReturnValue({ location: { toString: () => "http://example.com/false" } }); jest.spyOn(mockWindowWithPersistTrue, 'getNativeWindow').mockReturnValue({ location: { toString: () => "http://example.com/true" } }); - // Set up the container as non-platform jest.spyOn(container as any, "getIsPlatform").mockResolvedValue(false); - // Call buildLayout const layout = await container.buildLayout(); - // Verify that only the window with persist:true is in the layout expect(layout.windows.length).toBe(1); expect(layout.windows[0].name).toBe("WindowPersistTrue"); - // Verify that the window with persist:false is not in the layout const windowWithPersistFalse = layout.windows.find(w => w.name === "WindowPersistFalse"); expect(windowWithPersistFalse).toBeUndefined(); }); it("skips provider window (platform manifest)", async () => { - // Create a main window (snapshot window) const mainWindowName = "snapshot-window-name"; const mockMainWindow = new MockWindow(mainWindowName); - // Create a provider window (uuid and name = uuid) const mockProviderWindow = new MockWindow("uuid"); - // Create a regular window const mockRegularWindow = new MockWindow("Singleton"); - // Create wrapped container windows const containerMainWindow = new OpenFinContainerWindow(mockMainWindow); const containerRegularWindow = new OpenFinContainerWindow(mockRegularWindow); - // Mock platform-specific methods jest.spyOn(container as any, "getIsPlatform").mockResolvedValue(true); jest.spyOn(container as any, "getSnapshotWindow").mockResolvedValue(containerMainWindow); - // Mock Application.getCurrent().getWindow() to return the provider window const app = desktop.Application; const current = app.getCurrent(); jest.spyOn(current, "getWindow").mockReturnValue(mockProviderWindow); - // Mock getChildWindows to return our test windows jest.spyOn(current, "getChildWindows").mockImplementation((callback) => { callback([mockRegularWindow, mockMainWindow]); }); - // Mock getAllWindows to return our test windows jest.spyOn(container, 'getAllWindows').mockResolvedValue([ containerRegularWindow, containerMainWindow ]); - // Mock getState for both windows jest.spyOn(containerRegularWindow, 'getState').mockResolvedValue({}); jest.spyOn(containerMainWindow, 'getState').mockResolvedValue({}); - // Set up the mock options for both windows mockRegularWindow.getOptions = (callback, error) => { callback({ url: "http://example.com/regular" @@ -697,7 +680,6 @@ describe("OpenFinContainer", () => { return {}; }; - // Mock getBounds for both windows mockRegularWindow.getBounds = (callback, error) => { callback({ left: 0, top: 0, width: 100, height: 100 }); return {}; @@ -708,29 +690,22 @@ describe("OpenFinContainer", () => { return {}; }; - // Mock getNativeWindow for both windows jest.spyOn(mockRegularWindow, 'getNativeWindow').mockReturnValue({ location: { toString: () => "http://example.com/regular" } }); jest.spyOn(mockMainWindow, 'getNativeWindow').mockReturnValue({ location: { toString: () => "http://example.com/main" } }); - // This will set isPlatform = true and mainWindow = snapshot window await container.ready(); - // Call buildLayout const layout = await container.buildLayout(); - // Verify that the layout contains the expected windows expect(layout).toBeDefined(); expect(layout.windows.length).toBe(2); - // First window should be the regular window (not main) expect(layout.windows[0].name).toBe("Singleton"); expect(layout.windows[0].main).toBe(false); - // Second window should be the main window expect(layout.windows[1].name).toBe(mainWindowName); expect(layout.windows[1].main).toBe(true); - // Verify that the provider window is not in the layout const providerWindow = layout.windows.find(w => w.name === "uuid"); expect(providerWindow).toBeUndefined(); }); @@ -750,67 +725,52 @@ describe("OpenFinContainer", () => { describe("notifications", () => { it("createNotification creates a notification", () => { - // Create a mock Notification constructor const mockNotification = jest.fn(); - // Save the original Notification constructor const originalNotification = globalWindow.Notification; try { - // Replace the Notification constructor with our mock globalWindow.Notification = mockNotification; - // Add createNotification method to container Object.defineProperty(container, 'createNotification', { value: (title: string, options?: any) => { return new globalWindow.Notification(title, options); } }); - // Call createNotification (container as any).createNotification("title", { body: "body" }); - // Verify Notification constructor was called with the right arguments expect(mockNotification).toHaveBeenCalledWith("title", { body: "body" }); } finally { - // Restore the original Notification constructor globalWindow.Notification = originalNotification; } }); it("registerNotificationsApi creates notification wrapper", () => { - // Save original Notification const originalNotification = globalWindow.Notification; try { - // Create a mock for the original Notification const originalMock = jest.fn(); globalWindow.Notification = originalMock; - // Create a mock implementation for registerNotificationsApi Object.defineProperty(container, 'registerNotificationsApi', { value: () => { - // Replace Notification with a custom implementation globalWindow.Notification = jest.fn().mockImplementation((title, options) => { return { title, options, custom: true }; }); } }); - // Call registerNotificationsApi (container as any).registerNotificationsApi(); - // Create a notification with the new constructor const notification = new globalWindow.Notification("test", { body: "test body" }); - // Verify the notification has the expected properties expect(notification).toEqual({ title: "test", options: { body: "test body" }, custom: true }); } finally { - // Restore original Notification globalWindow.Notification = originalNotification; } }); @@ -818,7 +778,6 @@ describe("OpenFinContainer", () => { describe("getOptions", () => { it("returns options from container options", async () => { - // Mock getShortcuts to return systemStartup: true const app = desktop.Application; const current = app.getCurrent(); @@ -835,7 +794,6 @@ describe("OpenFinContainer", () => { }); it("handles error when getting options", async () => { - // Mock getShortcuts to throw an error const app = desktop.Application; const current = app.getCurrent(); @@ -848,7 +806,7 @@ describe("OpenFinContainer", () => { try { await container.getOptions(); - expect(true).toBe(false); // This will fail the test if we get here + expect(true).toBe(false); } catch (error) { expect(error).toBeDefined(); } @@ -857,7 +815,6 @@ describe("OpenFinContainer", () => { describe("isAutoStartEnabled", () => { it("returns true when systemStartup is true", async () => { - // Mock getShortcuts to return systemStartup: true const app = desktop.Application; const current = app.getCurrent(); @@ -873,7 +830,6 @@ describe("OpenFinContainer", () => { }); it("returns false when systemStartup is false", async () => { - // Mock getShortcuts to return systemStartup: false const app = desktop.Application; const current = app.getCurrent(); @@ -889,7 +845,6 @@ describe("OpenFinContainer", () => { }); it("handles error when checking autostart", async () => { - // Mock getShortcuts to throw an error const app = desktop.Application; const current = app.getCurrent(); @@ -902,7 +857,7 @@ describe("OpenFinContainer", () => { try { await (container as any).isAutoStartEnabledAtLogin(); - expect(true).toBe(false); // This will fail the test if we get here + expect(true).toBe(false); } catch (error) { expect(error).toEqual("Error"); } @@ -914,15 +869,14 @@ describe("OpenFinContainer", () => { Object.defineProperty(desktop, "Clipboard", { value: { writeText: jest.fn().mockImplementation((text: string, ...args: any[]) => { - if (args.length > 0 && typeof args[0] === 'function') args[0](); + if (args.length > 0 && typeof args[0] === 'function') (args[0] as () => void)(); }), readText: jest.fn().mockImplementation((type: string, ...args: any[]) => { - if (args.length > 0 && typeof args[0] === 'function') args[0]("Text"); + if (args.length > 0 && typeof args[0] === 'function') (args[0] as (text: string) => void)("Text"); }) } }); - // Add clipboard property to container Object.defineProperty(container, 'clipboard', { value: { writeText: async (text: string) => { @@ -951,7 +905,6 @@ describe("OpenFinContainer", () => { }); it("writeText handles error", async () => { - // Mock writeText to call the error callback desktop.Clipboard.writeText = jest.fn().mockImplementation((text: string, successCallback: () => void, errorCallback: (error: string) => void) => { errorCallback("Error writing to clipboard"); }); @@ -965,7 +918,6 @@ describe("OpenFinContainer", () => { }); it("readText handles error", async () => { - // Mock readText to call the error callback desktop.Clipboard.readText = jest.fn().mockImplementation((type: string, successCallback: (text: string) => void, errorCallback: (error: string) => void) => { errorCallback("Error reading from clipboard"); }); @@ -981,23 +933,19 @@ describe("OpenFinContainer", () => { describe("groupLayout", () => { it("joinGroup calls underlying joinGroup", async () => { - // Create a mock joinGroup function that resolves immediately const mockJoinGroup = jest.fn().mockImplementation((window, callback) => { if (callback) callback(); }); - // Create mock windows const targetWindow = { name: "target", joinGroup: mockJoinGroup }; const window = { name: "window" }; - // Create container windows with our mocks const targetContainerWindow = new OpenFinContainerWindow(targetWindow); const containerWindow = new OpenFinContainerWindow(window); - // Add joinGroup method to the window Object.defineProperty(targetContainerWindow, 'joinGroup', { value: function(window) { return new Promise((resolve) => { @@ -1006,29 +954,23 @@ describe("OpenFinContainer", () => { } }); - // Call joinGroup await targetContainerWindow.joinGroup(containerWindow); - // Verify joinGroup was called with the right arguments expect(mockJoinGroup).toHaveBeenCalledWith(window, expect.any(Function)); }); it("leaveGroup calls underlying leaveGroup", async () => { - // Create a mock leaveGroup function that calls the callback const mockLeaveGroup = jest.fn().mockImplementation((callback) => { if (callback) callback(); }); - // Create a mock window const mockWindow = { name: "window", leaveGroup: mockLeaveGroup }; - // Create a container window with our mock const containerWindow = new OpenFinContainerWindow(mockWindow); - // Add leaveGroup method to the window Object.defineProperty(containerWindow, 'leaveGroup', { value: function() { return new Promise((resolve) => { @@ -1037,33 +979,26 @@ describe("OpenFinContainer", () => { } }); - // Call leaveGroup await containerWindow.leaveGroup(); - // Verify leaveGroup was called expect(mockLeaveGroup).toHaveBeenCalledWith(expect.any(Function)); }); it("getGroup calls underlying getGroup", async () => { - // Create mock windows for the group const mockWindow1 = { name: "window1" }; const mockWindow2 = { name: "window2" }; - // Create a mock getGroup function that calls the callback with the group const mockGetGroup = jest.fn().mockImplementation((callback) => { callback([mockWindow1, mockWindow2]); }); - // Create a mock window const mockWindow = { name: "window", getGroup: mockGetGroup }; - // Create a container window with our mock const containerWindow = new OpenFinContainerWindow(mockWindow); - // Add getGroup method to the window Object.defineProperty(containerWindow, 'getGroup', { value: function() { return new Promise((resolve) => { @@ -1074,13 +1009,10 @@ describe("OpenFinContainer", () => { } }); - // Call getGroup const group = await containerWindow.getGroup(); - // Verify getGroup was called expect(mockGetGroup).toHaveBeenCalledWith(expect.any(Function)); - // Verify the group contains the expected windows expect(group.length).toEqual(2); expect(group[0].innerWindow).toEqual(mockWindow1); expect(group[1].innerWindow).toEqual(mockWindow2); @@ -1089,7 +1021,6 @@ describe("OpenFinContainer", () => { describe("getMenuHtml and getMenuItemHtml", () => { beforeEach(() => { - // Add ensureAbsoluteUrl method to container Object.assign(container, { ensureAbsoluteUrl: (url: string) => url }); @@ -1113,7 +1044,6 @@ describe("OpenFinContainer", () => { }); it("addTrayIcon invokes underlying setTrayIcon", () => { - // Add ensureAbsoluteUrl method to container Object.assign(container, { ensureAbsoluteUrl: (url: string) => url }); @@ -1178,7 +1108,6 @@ describe("OpenFinContainer", () => { describe("getMainWindow", () => { it("getMainWindow returns wrapped inner window (non platform manifest)", async () => { - // Reset mocks that might have been changed by other tests jest.spyOn(container as any, "getIsPlatform").mockResolvedValue(false); await container.ready(); @@ -1204,11 +1133,9 @@ describe("OpenFinContainer", () => { describe("registerNotificationsApi", () => { it.skip("registers notification API", () => { - // Skipped due to issues with redefining Notification property }); it("registers notification API", () => { - // Create a mock window object with a Notification property const mockWindow: any = { Notification: class MockNotification { title: string; @@ -1225,30 +1152,23 @@ describe("OpenFinContainer", () => { } }; - // Create a mock for the OpenFin notify method const mockNotify = jest.fn(); - // Create a mock window for notifications const mockWindowForNotify = { name: "window-name", notify: mockNotify }; - // Create a wrapped window for notifications const mockContainerWindow = new OpenFinContainerWindow(mockWindowForNotify); - // Add the notify method directly to the container window Object.defineProperty(mockContainerWindow, 'notify', { value: (options: any) => mockWindowForNotify.notify(options) }); - // Create a container with the mock window const desktop = new MockDesktop(); const container = new OpenFinContainer(desktop, mockWindow); - // Mock getCurrentWindow to return our mockContainerWindow jest.spyOn(container, "getCurrentWindow").mockResolvedValue(mockContainerWindow as any); - // Create the Notification implementation that we expect registerNotificationsApi to create const customNotification = function(title: string, options: any) { const containerWindow = mockContainerWindow; containerWindow.notify({ @@ -1265,12 +1185,10 @@ describe("OpenFinContainer", () => { }; }; - // Add static method to the custom Notification customNotification.requestPermission = function() { return Promise.reject("Not supported"); }; - // Mock the implementation for registerNotificationsApi Object.defineProperty(container, 'registerNotificationsApi', { value: () => { mockWindow.Notification = jest.fn().mockImplementation((title, options) => { @@ -1281,19 +1199,15 @@ describe("OpenFinContainer", () => { } }); - // Call registerNotificationsApi (container as any).registerNotificationsApi(); - // Create a notification using the new API const notification = new mockWindow.Notification("Test Title", { body: "Test Body", icon: "test-icon.png" }); - // Verify the notification was created with correct parameters expect(notification).toBeDefined(); - // Verify that notify was called with the right parameters expect(mockNotify).toHaveBeenCalledWith( expect.objectContaining({ title: "Test Title", @@ -1302,7 +1216,6 @@ describe("OpenFinContainer", () => { }) ); - // Verify requestPermission method is implemented expect(mockWindow.Notification.requestPermission).toBeDefined(); }); }); @@ -1323,7 +1236,6 @@ describe("OpenFinContainer", () => { describe("ensureAbsoluteUrl", () => { it("returns the same URL when linkHelper is not available", () => { - // Create a mock window without Office.LinkHelper const mockWindow: any = { location: { protocol: "https:", @@ -1331,52 +1243,40 @@ describe("OpenFinContainer", () => { } }; - // Create a container with our mocked window const desktop = new MockDesktop(); const container = new OpenFinContainer(desktop, mockWindow); - // Mock setTrayIcon and capture the URL that's passed const mockSetTrayIcon = jest.fn(); desktop.Application.getCurrent().setTrayIcon = mockSetTrayIcon; - // Create a mock implementation of ensureAbsoluteUrl const mockEnsureAbsoluteUrl = jest.fn((url: string) => { if (url.startsWith("http")) { - return url; // Already absolute + return url; } else { - // Simple URL resolution return url.startsWith('/') ? `${mockWindow.location.protocol}//${mockWindow.location.host}${url}` : `${mockWindow.location.protocol}//${mockWindow.location.host}/${url}`; } }); - // Replace the original ensureAbsoluteUrl with our mock Object.defineProperty(container, 'ensureAbsoluteUrl', { value: mockEnsureAbsoluteUrl }); - // Calling addTrayIcon should invoke our mocked ensureAbsoluteUrl container.addTrayIcon({ icon: 'https://example.com/icon.png', text: 'Icon' }, () => {}); - // Verify our mock was called with the absolute URL expect(mockEnsureAbsoluteUrl).toHaveBeenCalledWith('https://example.com/icon.png'); - // The mock should return the same URL since it's already absolute expect(mockEnsureAbsoluteUrl('https://example.com/icon.png')).toEqual('https://example.com/icon.png'); - // Test with a relative URL container.addTrayIcon({ icon: '/relative/path/icon.png', text: 'Icon' }, () => {}); - // Verify our mock was called with the relative URL expect(mockEnsureAbsoluteUrl).toHaveBeenCalledWith('/relative/path/icon.png'); - // The mock should resolve the URL against window.location expect(mockEnsureAbsoluteUrl('/relative/path/icon.png')).toEqual('https://example.com/relative/path/icon.png'); }); it("returns absolute URL when linkHelper is available", () => { - // Create a mock window with Office.LinkHelper const mockWindow: any = { location: { protocol: "https:", @@ -1391,48 +1291,36 @@ describe("OpenFinContainer", () => { } }; - // Create a container with our mocked window const desktop = new MockDesktop(); const container = new OpenFinContainer(desktop, mockWindow); - // Mock setTrayIcon and capture the URL that's passed const mockSetTrayIcon = jest.fn(); desktop.Application.getCurrent().setTrayIcon = mockSetTrayIcon; - // Create a mock implementation of ensureAbsoluteUrl that uses Office.LinkHelper const mockEnsureAbsoluteUrl = jest.fn((url: string) => { if (url.startsWith("http")) { - return url; // Already absolute + return url; } else { - // Use LinkHelper.resolveUrl for relative URLs return mockWindow.Office.LinkHelper.resolveUrl(url); } }); - // Replace the original ensureAbsoluteUrl with our mock Object.defineProperty(container, 'ensureAbsoluteUrl', { value: mockEnsureAbsoluteUrl }); - // Calling addTrayIcon should invoke our mocked ensureAbsoluteUrl container.addTrayIcon({ icon: 'https://example.com/icon.png', text: 'Icon' }, () => {}); - // Verify our mock was called with the absolute URL expect(mockEnsureAbsoluteUrl).toHaveBeenCalledWith('https://example.com/icon.png'); - // The mock should return the same URL since it's already absolute expect(mockEnsureAbsoluteUrl('https://example.com/icon.png')).toEqual('https://example.com/icon.png'); - // Test with a relative URL container.addTrayIcon({ icon: '/relative/path/icon.png', text: 'Icon' }, () => {}); - // Verify our mock was called with the relative URL expect(mockEnsureAbsoluteUrl).toHaveBeenCalledWith('/relative/path/icon.png'); - // Verify LinkHelper.resolveUrl was called expect(mockWindow.Office.LinkHelper.resolveUrl).toHaveBeenCalledWith('/relative/path/icon.png'); - // The mock should resolve the URL using Office.LinkHelper expect(mockEnsureAbsoluteUrl('/relative/path/icon.png')).toEqual('https://resolved.example.com/relative/path/icon.png'); }); }); @@ -1451,7 +1339,6 @@ describe("OpenFinContainer", () => { const mockWindow = { name: "window", notify: jest.fn() }; const window = new OpenFinContainerWindow(mockWindow); - // Add notify method to window Object.defineProperty(window, 'notify', { value: (options: any) => mockWindow.notify(options) }); @@ -1470,7 +1357,6 @@ describe("OpenFinContainer", () => { const mockWindow = { name: "window", notify: jest.fn() }; const window = new OpenFinContainerWindow(mockWindow); - // Add notify method to window Object.defineProperty(window, 'notify', { value: (options: any) => mockWindow.notify(options) }); @@ -1495,7 +1381,6 @@ describe("OpenFinContainer", () => { describe("showMenu", () => { it("creates a context menu window with provided menu items", () => { - // Create a mock document element for the context menu const mockContextMenuElement = { innerHTML: "", offsetWidth: 100, @@ -1503,7 +1388,6 @@ describe("OpenFinContainer", () => { addEventListener: jest.fn() }; - // Create a mock document for the window const mockDocument = { open: jest.fn(), write: jest.fn(), @@ -1516,7 +1400,6 @@ describe("OpenFinContainer", () => { }) }; - // Create a mock native window that will be returned by getNativeWindow const mockNativeWindow = { document: mockDocument, location: { @@ -1524,7 +1407,6 @@ describe("OpenFinContainer", () => { } }; - // Create the mock window with proper structure const mockContextMenuWindow = { name: "mockContextMenu", getNativeWindow: jest.fn().mockReturnValue(mockNativeWindow), @@ -1537,8 +1419,7 @@ describe("OpenFinContainer", () => { close: jest.fn() }; - // Mock desktop.Window constructor to return our mockContextMenuWindow - let storedCallback: Function | null = null; + let storedCallback: ((win?: any) => void) | null = null; // Use specific function type ((win?: any) => void) const mockWindowConstructor = jest.fn().mockImplementation((options, callback) => { if (callback) { storedCallback = callback; @@ -1546,38 +1427,31 @@ describe("OpenFinContainer", () => { return mockContextMenuWindow; }); - // Create a container with our mocks const desktop = new MockDesktop(); desktop.Window = mockWindowConstructor; - // Mock the ensureAbsoluteUrl method const container = new OpenFinContainer(desktop); - // Add missing methods Object.defineProperty(container, 'getMenuHtml', { value: () => "
" }); - // Mock getMenuItemHtml to return a simple string Object.defineProperty(container, 'getMenuItemHtml', { value: jest.fn().mockImplementation((item) => `
${item.label}
`) }); (container as any).ensureAbsoluteUrl = jest.fn().mockImplementation(url => url); - // Create unique uuid Object.defineProperty(container, 'uuid', { value: "test-uuid", writable: true }); - // Menu items to display const menuItems = [ { id: "item1", label: "Item 1", icon: "icon1.png", click: jest.fn() }, { id: "item2", label: "Item 2", click: jest.fn() } ]; - // Mock monitorInfo const mockMonitorInfo = { primaryMonitor: { monitorRect: { @@ -1589,15 +1463,12 @@ describe("OpenFinContainer", () => { } }; - // Call showMenu (container as any).showMenu(100, 100, mockMonitorInfo, menuItems); - // Now execute the stored callback after mockContextMenuWindow is set if (storedCallback) { storedCallback(); } - // Verify window constructor was called with correct options expect(desktop.Window).toHaveBeenCalledWith( expect.objectContaining({ saveWindowState: false, @@ -1610,27 +1481,23 @@ describe("OpenFinContainer", () => { expect.any(Function) ); - // Verify document methods were called expect(mockDocument.open).toHaveBeenCalledWith("text/html", "replace"); expect(mockDocument.write).toHaveBeenCalled(); expect(mockDocument.close).toHaveBeenCalled(); - // Verify getElementById was called to get the contextMenu element expect(mockDocument.getElementById).toHaveBeenCalledWith("contextMenu"); - // Verify resize and positioning expect(mockContextMenuWindow.resizeTo).toHaveBeenCalledWith(100, 100, "top-left"); expect(mockContextMenuWindow.addEventListener).toHaveBeenCalledWith("blurred", expect.any(Function)); expect(mockContextMenuWindow.showAt).toHaveBeenCalledWith( - 100, // x position - 100, // y position + 100, + 100, expect.any(Boolean), expect.any(Function) ); }); it.skip("positions menu to the left when near the right edge of the monitor", () => { - // Create a mock document element for the context menu const mockContextMenuElement = { innerHTML: "", offsetWidth: 200, @@ -1638,7 +1505,6 @@ describe("OpenFinContainer", () => { addEventListener: jest.fn() }; - // Create a mock document for the window const mockDocument = { open: jest.fn(), write: jest.fn(), @@ -1651,7 +1517,6 @@ describe("OpenFinContainer", () => { }) }; - // Create a mock native window that will be returned by getNativeWindow const mockNativeWindow = { document: mockDocument, location: { @@ -1659,7 +1524,6 @@ describe("OpenFinContainer", () => { } }; - // Create the mock window with proper structure const mockContextMenuWindow = { name: "mockContextMenu", getNativeWindow: jest.fn().mockReturnValue(mockNativeWindow), @@ -1672,8 +1536,7 @@ describe("OpenFinContainer", () => { close: jest.fn() }; - // Mock desktop.Window constructor to return our mockContextMenuWindow - let storedCallback: Function | null = null; + let storedCallback: ((win?: any) => void) | null = null; // Use specific function type ((win?: any) => void) const mockWindowConstructor = jest.fn().mockImplementation((options, callback) => { if (callback) { storedCallback = callback; @@ -1681,50 +1544,40 @@ describe("OpenFinContainer", () => { return mockContextMenuWindow; }); - // Create a container with our mocks const desktop = new MockDesktop(); desktop.Window = mockWindowConstructor; - // Mock the ensureAbsoluteUrl method const container = new OpenFinContainer(desktop); - // Add missing methods Object.defineProperty(container, 'getMenuHtml', { value: () => "
" }); (container as any).ensureAbsoluteUrl = jest.fn().mockImplementation(url => url); - // Create unique uuid Object.defineProperty(container, 'uuid', { value: "test-uuid", writable: true }); - // Mock monitorInfo with a small right edge const mockMonitorInfo = { primaryMonitor: { monitorRect: { left: 0, top: 0, - right: 900, // Right edge is at 900px + right: 900, bottom: 1000 } } }; - // Set the position near the right edge (x = 800) so menu will overflow const xPosition = 800; - const menuWidth = 200; // Menu is 200px wide from the mock + const menuWidth = 200; - // Call showMenu (container as any).showMenu(xPosition, 100, mockMonitorInfo, [{ label: "Test" }]); - // The menu should be positioned to the left of the click point - // Should be: x - width - trayIconMenuLeftOffset const expectedLeft = xPosition - menuWidth - OpenFinContainer.trayIconMenuLeftOffset; - // Verify positioning expect(mockContextMenuWindow.showAt).toHaveBeenCalledWith( expectedLeft, expect.any(Number), @@ -1734,7 +1587,6 @@ describe("OpenFinContainer", () => { }); it.skip("positions menu above when near the bottom edge of the monitor", () => { - // Create a mock document for the window const mockDocument = { open: jest.fn(), write: jest.fn(), @@ -1746,7 +1598,6 @@ describe("OpenFinContainer", () => { }) }; - // Create a mock native window that will be returned by getNativeWindow const mockNativeWindow = { document: mockDocument, location: { @@ -1754,7 +1605,6 @@ describe("OpenFinContainer", () => { } }; - // Create the mock window with proper structure const mockContextMenuWindow = { name: "mockContextMenu", getNativeWindow: jest.fn().mockReturnValue(mockNativeWindow), @@ -1767,8 +1617,7 @@ describe("OpenFinContainer", () => { close: jest.fn() }; - // Mock desktop.Window constructor to return our mockContextMenuWindow - let storedCallback: Function | null = null; + let storedCallback: ((win?: any) => void) | null = null; // Use specific function type ((win?: any) => void) const mockWindowConstructor = jest.fn().mockImplementation((options, callback) => { if (callback) { storedCallback = callback; @@ -1776,50 +1625,40 @@ describe("OpenFinContainer", () => { return mockContextMenuWindow; }); - // Create a container with our mocks const desktop = new MockDesktop(); desktop.Window = mockWindowConstructor; - // Mock the ensureAbsoluteUrl method const container = new OpenFinContainer(desktop); - // Add missing methods Object.defineProperty(container, 'getMenuHtml', { value: () => "
" }); (container as any).ensureAbsoluteUrl = jest.fn().mockImplementation(url => url); - // Create unique uuid Object.defineProperty(container, 'uuid', { value: "test-uuid", writable: true }); - // Mock monitorInfo with a low bottom edge const mockMonitorInfo = { primaryMonitor: { monitorRect: { left: 0, top: 0, right: 1000, - bottom: 800 // Bottom edge is at 800px + bottom: 800 } } }; - // Set the position near the bottom edge (y = 700) so menu will overflow const yPosition = 700; - const menuHeight = 300; // Menu is 300px tall from the mock + const menuHeight = 300; - // Call showMenu (container as any).showMenu(100, yPosition, mockMonitorInfo, [{ label: "Test" }]); - // The menu should be positioned above the click point - // Should be: y - height - trayIconMenuTopOffset const expectedTop = yPosition - menuHeight - OpenFinContainer.trayIconMenuTopOffset; - // Verify positioning expect(mockContextMenuWindow.showAt).toHaveBeenCalledWith( expect.any(Number), expectedTop, @@ -1829,7 +1668,6 @@ describe("OpenFinContainer", () => { }); it.skip("creates menu items with proper IDs and HTML", () => { - // Create a mock document element for the context menu const mockContextMenuElement = { innerHTML: "", offsetWidth: 100, @@ -1837,7 +1675,6 @@ describe("OpenFinContainer", () => { addEventListener: jest.fn() }; - // Create a mock document for the window const mockDocument = { open: jest.fn(), write: jest.fn(), @@ -1850,7 +1687,6 @@ describe("OpenFinContainer", () => { }) }; - // Create a mock native window that will be returned by getNativeWindow const mockNativeWindow = { document: mockDocument, location: { @@ -1858,7 +1694,6 @@ describe("OpenFinContainer", () => { } }; - // Create the mock window with proper structure const mockContextMenuWindow = { name: "mockContextMenu", getNativeWindow: jest.fn().mockReturnValue(mockNativeWindow), @@ -1871,8 +1706,7 @@ describe("OpenFinContainer", () => { close: jest.fn() }; - // Mock desktop.Window constructor to return our mockContextMenuWindow - let storedCallback: Function | null = null; + let storedCallback: ((win?: any) => void) | null = null; // Use specific function type ((win?: any) => void) const mockWindowConstructor = jest.fn().mockImplementation((options, callback) => { if (callback) { storedCallback = callback; @@ -1880,66 +1714,53 @@ describe("OpenFinContainer", () => { return mockContextMenuWindow; }); - // Create a container with our mocks const desktop = new MockDesktop(); desktop.Window = mockWindowConstructor; - // Mock the ensureAbsoluteUrl method const container = new OpenFinContainer(desktop); - // Add missing methods Object.defineProperty(container, 'getMenuHtml', { value: () => "
" }); - // Mock getMenuItemHtml to return a simple string Object.defineProperty(container, 'getMenuItemHtml', { value: jest.fn().mockImplementation((item) => `
${item.label}
`) }); (container as any).ensureAbsoluteUrl = jest.fn().mockImplementation(url => url); - // Create unique uuid Object.defineProperty(container, 'uuid', { value: "test-uuid", writable: true }); - // Menu items to display const menuItems = [ { id: "item1", label: "Item 1", icon: "icon1.png", click: jest.fn() }, { id: "item2", label: "Item 2", click: jest.fn() } ]; - // Call showMenu (container as any).showMenu(100, 100, { primaryMonitor: { monitorRect: { right: 1000, bottom: 1000 } } }, menuItems); - // Now execute the stored callback after mockContextMenuWindow is set if (storedCallback) { storedCallback(); } - // Verify IDs were generated expect(menuItems[0].id).toBeDefined(); expect(menuItems[1].id).toBeDefined(); - // Verify getMenuItemHtml was called for each item expect((container as any).getMenuItemHtml).toHaveBeenCalledTimes(2); expect((container as any).getMenuItemHtml).toHaveBeenCalledWith(menuItems[0]); expect((container as any).getMenuItemHtml).toHaveBeenCalledWith(menuItems[1]); - // Verify that menu items without labels are filtered out const menuItemsWithNoLabel = [ { id: "item1", label: "Item 1" }, - { id: "item2" } // No label + { id: "item2" } ]; (container as any).getMenuItemHtml.mockClear(); - // Call showMenu with items including one without a label (container as any).showMenu(100, 100, { primaryMonitor: { monitorRect: { right: 1000, bottom: 1000 } } }, menuItemsWithNoLabel); - // Only one item should have getMenuItemHtml called - the one with a label expect((container as any).getMenuItemHtml).toHaveBeenCalledTimes(1); expect((container as any).getMenuItemHtml).toHaveBeenCalledWith(menuItemsWithNoLabel[0]); }); @@ -1952,7 +1773,6 @@ describe("OpenFinContainer", () => { snapshot: { windows: [{ name: "test-window" }] } }; - // Mock the getManifest method in the application jest.spyOn(desktop.Application.getCurrent(), "getManifest") .mockImplementation((callback) => callback(mockManifest)); @@ -1964,7 +1784,6 @@ describe("OpenFinContainer", () => { it("handles error when retrieving manifest", async () => { const mockError = new Error("Failed to get manifest"); - // Mock the getManifest method to reject with an error jest.spyOn(desktop.Application.getCurrent(), "getManifest") .mockImplementation((callback, errorCallback) => errorCallback(mockError)); @@ -1976,7 +1795,6 @@ describe("OpenFinContainer", () => { it("returns the name of the first window in the snapshot", async () => { const windowName = "test-window"; - // Mock getManifest to return a valid manifest with a window name jest.spyOn(container as any, "getManifest").mockResolvedValue({ snapshot: { windows: [{ name: windowName }] @@ -1989,10 +1807,9 @@ describe("OpenFinContainer", () => { }); it("returns null if window has no name", async () => { - // Mock getManifest to return a valid manifest with a window without a name jest.spyOn(container as any, "getManifest").mockResolvedValue({ snapshot: { - windows: [{ url: "test.html" }] // No name property + windows: [{ url: "test.html" }] } }); @@ -2002,7 +1819,6 @@ describe("OpenFinContainer", () => { }); it("throws an error if no valid windows are found in snapshot", async () => { - // Mock getManifest to return a manifest with no windows jest.spyOn(container as any, "getManifest").mockResolvedValue({ snapshot: { windows: [] @@ -2013,7 +1829,6 @@ describe("OpenFinContainer", () => { }); it("throws an error if snapshot windows is undefined", async () => { - // Mock getManifest to return a manifest with no windows array jest.spyOn(container as any, "getManifest").mockResolvedValue({ snapshot: {} }); @@ -2028,10 +1843,8 @@ describe("OpenFinContainer", () => { const mockWindow = { name: snapshotWindowName }; const mockWrappedWindow = { innerWindow: mockWindow, name: snapshotWindowName }; - // Mock getAllWindows to return a window with the snapshot name jest.spyOn(container, "getAllWindows").mockResolvedValue([mockWrappedWindow] as any); - // Mock getSnapshotWindowName to return our test name jest.spyOn(container as any, "getSnapshotWindowName").mockResolvedValue(snapshotWindowName); const result = await (container as any).getSnapshotWindow(); @@ -2049,48 +1862,39 @@ describe("OpenFinContainer", () => { const mockWrappedSnapshotWindow = { innerWindow: mockSnapshotWindow, name: snapshotWindowName }; const mockWrappedInternalWindow = { innerWindow: mockInternalWindow, name: internalGeneratedName }; - // Mock getAllWindows to return both windows jest.spyOn(container, "getAllWindows").mockResolvedValue([ mockWrappedSnapshotWindow, mockWrappedInternalWindow ] as any); - // Mock getSnapshotWindowName to return a different name than what's in windows jest.spyOn(container as any, "getSnapshotWindowName").mockResolvedValue("different-name"); const result = await (container as any).getSnapshotWindow(); - // Should return the internal-generated-window since the snapshot name doesn't match expect(result).toEqual(mockWrappedInternalWindow); }); it("throws an error when no matching window is found", async () => { - // Mock getAllWindows to return a window with a different name jest.spyOn(container, "getAllWindows").mockResolvedValue([ { name: "other-window" } ] as any); - // Mock getSnapshotWindowName to return our test name jest.spyOn(container as any, "getSnapshotWindowName").mockResolvedValue("snapshot-window"); await expect((container as any).getSnapshotWindow()).rejects.toThrow("Error getting snapshot window"); }); it("throws an error when no windows are returned from getAllWindows", async () => { - // Mock getAllWindows to return empty array jest.spyOn(container, "getAllWindows").mockResolvedValue([]); - // Mock getSnapshotWindowName to return our test name jest.spyOn(container as any, "getSnapshotWindowName").mockResolvedValue("snapshot-window"); await expect((container as any).getSnapshotWindow()).rejects.toThrow("Error getting snapshot window"); }); it("throws an error when getAllWindows returns undefined", async () => { - // Mock getAllWindows to return undefined jest.spyOn(container, "getAllWindows").mockResolvedValue(undefined as any); - // Mock getSnapshotWindowName to return our test name jest.spyOn(container as any, "getSnapshotWindowName").mockResolvedValue("snapshot-window"); await expect((container as any).getSnapshotWindow()).rejects.toThrow("Error getting snapshot window"); @@ -2103,7 +1907,6 @@ describe("OpenFinContainerWindow", () => { let win: OpenFinContainerWindow; beforeEach(() => { - // Create a more complete mock window with all required methods innerWin = { name: "MockWindow", getNativeWindow: jest.fn().mockReturnValue({ @@ -2130,9 +1933,7 @@ describe("OpenFinContainerWindow", () => { stopFlashing: jest.fn().mockImplementation((callback: () => void) => callback()), getOptions: jest.fn().mockImplementation((callback: (options: any) => void, error: (reason: any) => void) => callback({ url: "url", customData: null })), getSnapshot: jest.fn().mockImplementation((callback: (snapshot: string) => void, error: (reason: any) => void) => callback("base64data")), - navigate: jest.fn().mockImplementation((url: string, callback: () => void, error: (reason: any) => void) => callback()), - addEventListener: jest.fn(), - removeEventListener: jest.fn() + navigate: jest.fn().mockImplementation((url: string, callback: () => void, error: (reason: any) => void) => callback()) }), navigate: jest.fn().mockImplementation((url: string, callback: () => void, error: (reason: any) => void) => callback()), focus: jest.fn().mockImplementation((callback: () => void, error: (reason: any) => void) => callback()), @@ -2278,44 +2079,35 @@ describe("OpenFinContainerWindow", () => { describe("setState", () => { it("setState undefined", async () => { - // Create a mock window without setState in nativeWindow const mockWindow = { name: "MockWindow", getNativeWindow: jest.fn().mockReturnValue({}) }; - // Create a container window with our mock const win = new OpenFinContainerWindow(mockWindow); - // Mock the prototype's emit method to prevent errors const originalPrototype = Object.getPrototypeOf(win); const originalEmit = originalPrototype.emit; originalPrototype.emit = jest.fn(); - // Mock the static emit method const originalStaticEmit = ContainerWindow.emit; ContainerWindow.emit = jest.fn(); try { - // Should not throw when setState is not available await win.setState({}); - // Verify getNativeWindow was called expect(mockWindow.getNativeWindow).toHaveBeenCalled(); } finally { - // Restore original methods originalPrototype.emit = originalEmit; ContainerWindow.emit = originalStaticEmit; } }); it("setState defined", async () => { - // Create a mock setState function that resolves immediately const mockSetState = jest.fn().mockImplementation(() => { return Promise.resolve(); }); - // Create a mock window with setState in nativeWindow const mockWindow = { name: "MockWindow", getNativeWindow: jest.fn().mockReturnValue({ @@ -2323,31 +2115,24 @@ describe("OpenFinContainerWindow", () => { }) }; - // Create a container window with our mock const win = new OpenFinContainerWindow(mockWindow); - // Mock the prototype's emit method to prevent errors const originalPrototype = Object.getPrototypeOf(win); const originalEmit = originalPrototype.emit; originalPrototype.emit = jest.fn(); - // Mock the static emit method const originalStaticEmit = ContainerWindow.emit; ContainerWindow.emit = jest.fn(); try { - // Call setState with a mock state const mockState = { value: "test" }; await win.setState(mockState); - // Verify setState was called with the right arguments expect(mockSetState).toHaveBeenCalledWith(mockState); - // Verify emit was called expect(originalPrototype.emit).toHaveBeenCalled(); expect(ContainerWindow.emit).toHaveBeenCalled(); } finally { - // Restore original methods originalPrototype.emit = originalEmit; ContainerWindow.emit = originalStaticEmit; } @@ -2365,8 +2150,8 @@ describe("OpenFinContainerWindow", () => { expect(bounds).toBeDefined(); expect(bounds.x).toEqual(0); expect(bounds.y).toEqual(1); - expect(bounds.width).toEqual(2); // right - left - expect(bounds.height).toEqual(3); // bottom - top + expect(bounds.width).toEqual(2); + expect(bounds.height).toEqual(3); }); it("setBounds sets underlying window position", async () => { @@ -2449,16 +2234,13 @@ describe("OpenFinContainerWindow", () => { describe("addListener", () => { it("addListener calls underlying OpenFin window addEventListener with mapped event name", () => { - // Create a mock window with addEventListener method const mockWindow = { name: "MockWindow", addEventListener: jest.fn() }; - // Create a container window const win = new OpenFinContainerWindow(mockWindow); - // Add the addListener method to the window Object.defineProperty(win, 'addListener', { value: function(eventName: string, listener: (...args: any[]) => void) { const mappedEvent = eventName === "move" ? "bounds-changing" : eventName; @@ -2466,45 +2248,36 @@ describe("OpenFinContainerWindow", () => { } }); - // Create a listener function const listener = jest.fn(); - // Call addListener with a mapped event (move maps to bounds-changing) win.addListener("move", listener); - // Verify the addEventListener was called with the mapped event name expect(mockWindow.addEventListener).toHaveBeenCalledWith("bounds-changing", listener); }); it("addListener calls underlying OpenFin window addEventListener with unmapped event name", () => { const unmappedEvent = "closed"; - // Create a mock window with addEventListener method const mockWindow = { name: "MockWindow", addEventListener: jest.fn() }; const win = new OpenFinContainerWindow(mockWindow); - // Add the addListener method to the window Object.defineProperty(win, 'addListener', { value: function(eventName: string, listener: (...args: any[]) => void) { mockWindow.addEventListener(eventName, listener); } }); - // Create a listener function const listener = jest.fn(); - // Call addListener with an unmapped event win.addListener(unmappedEvent, listener); - // Verify the addEventListener was called with the same event name expect(mockWindow.addEventListener).toHaveBeenCalledWith(unmappedEvent, listener); }); it("resize wraps filtered bounds-changing", (done) => { - // Create a mock addEventListener that invokes the listener with a changeType = 1 const mockWindow = { name: "MockWindow", addEventListener: jest.fn().mockImplementation((eventName: string, listener: (event: any) => void) => { @@ -2512,10 +2285,8 @@ describe("OpenFinContainerWindow", () => { }) }; - // Create a container window const win = new OpenFinContainerWindow(mockWindow); - // Add the addListener method to the window Object.defineProperty(win, 'addListener', { value: function(eventName: string, listener: (...args: any[]) => void) { const mappedEvent = eventName === "resize" ? "bounds-changing" : eventName; @@ -2527,16 +2298,13 @@ describe("OpenFinContainerWindow", () => { } }); - // Call addListener with resize event win.addListener("resize", (e) => { - // Verify that the innerEvent is passed correctly expect(e.innerEvent.changeType).toBeGreaterThanOrEqual(1); done(); }); }); it("move wraps filtered bounds-changing", (done) => { - // Create a mock addEventListener that invokes the listener with a changeType = 0 const mockWindow = { name: "MockWindow", addEventListener: jest.fn().mockImplementation((eventName: string, listener: (event: any) => void) => { @@ -2544,10 +2312,8 @@ describe("OpenFinContainerWindow", () => { }) }; - // Create a container window const win = new OpenFinContainerWindow(mockWindow); - // Add the addListener method to the window Object.defineProperty(win, 'addListener', { value: function(eventName: string, listener: (...args: any[]) => void) { const mappedEvent = eventName === "move" ? "bounds-changing" : eventName; @@ -2559,23 +2325,19 @@ describe("OpenFinContainerWindow", () => { } }); - // Call addListener with move event win.addListener("move", (e) => { - // Verify that the innerEvent is passed correctly expect(e.innerEvent.changeType).toEqual(0); done(); }); }); it("beforeunload attaches to underlying close-requested", () => { - // Create a mock window with addEventListener method const mockWindow = { name: "MockWindow", addEventListener: jest.fn() }; const win = new OpenFinContainerWindow(mockWindow); - // Add the addListener method to the window Object.defineProperty(win, 'addListener', { value: function(eventName: string, listener: (...args: any[]) => void) { const mappedEvent = eventName === "beforeunload" ? "close-requested" : eventName; @@ -2583,29 +2345,23 @@ describe("OpenFinContainerWindow", () => { } }); - // Create a listener function const listener = jest.fn(); - // Call addListener with beforeunload event win.addListener("beforeunload", listener); - // Verify the addEventListener was called with close-requested expect(mockWindow.addEventListener).toHaveBeenCalledWith("close-requested", listener); }); }); describe("removeListener", () => { it("removeListener calls underlying OpenFin window removeEventListener with mapped event name", () => { - // Create a mock window with removeEventListener method const mockWindow = { name: "MockWindow", removeEventListener: jest.fn() }; - // Create a container window const win = new OpenFinContainerWindow(mockWindow); - // Add the removeListener method to the window Object.defineProperty(win, 'removeListener', { value: function(eventName: string, listener: (...args: any[]) => void) { const mappedEvent = eventName === "move" ? "bounds-changing" : eventName; @@ -2613,40 +2369,32 @@ describe("OpenFinContainerWindow", () => { } }); - // Create a listener function const listener = jest.fn(); - // Call removeListener with a mapped event (move maps to bounds-changing) win.removeListener("move", listener); - // Verify the removeEventListener was called with the mapped event name expect(mockWindow.removeEventListener).toHaveBeenCalledWith("bounds-changing", listener); }); it("removeListener calls underlying OpenFin window removeEventListener with unmapped event name", () => { const unmappedEvent = "closed"; - // Create a mock window with removeEventListener method const mockWindow = { name: "MockWindow", removeEventListener: jest.fn() }; const win = new OpenFinContainerWindow(mockWindow); - // Add the removeListener method to the window Object.defineProperty(win, 'removeListener', { value: function(eventName: string, listener: (...args: any[]) => void) { mockWindow.removeEventListener(eventName, listener); } }); - // Create a listener function const listener = jest.fn(); - // Call removeListener with an unmapped event win.removeListener(unmappedEvent, listener); - // Verify the removeEventListener was called with the same event name expect(mockWindow.removeEventListener).toHaveBeenCalledWith(unmappedEvent, listener); }); }); @@ -2738,7 +2486,6 @@ describe("OpenFinDisplayManager", () => { beforeEach(() => { desktop = new MockDesktop(); - // Create a more detailed System mock system = { getMonitorInfo: jest.fn().mockImplementation((callback: (info: any) => void) => callback({ primaryMonitor: { @@ -2777,13 +2524,13 @@ describe("OpenFinDisplayManager", () => { expect(display.bounds.x).toBe(2); expect(display.bounds.y).toBe(3); - expect(display.bounds.width).toBe(2); // right - left - expect(display.bounds.height).toBe(2); // bottom - top + expect(display.bounds.width).toBe(2); + expect(display.bounds.height).toBe(2); expect(display.workArea.x).toBe(6); expect(display.workArea.y).toBe(7); - expect(display.workArea.width).toBe(2); // right - left - expect(display.workArea.height).toBe(2); // bottom - top + expect(display.workArea.width).toBe(2); + expect(display.workArea.height).toBe(2); }); it("getAllDisplays", async () => { @@ -2810,7 +2557,6 @@ describe("OpenFinGlobalShortcutManager", () => { it("Unavailable in OpenFin is unavailable on container", () => { delete desktop.GlobalHotkey; - // Mock the log method to avoid actual calls jest.spyOn(OpenFinContainer.prototype, "log").mockImplementation(() => Promise.resolve()); const container = new OpenFinContainer(desktop); @@ -2852,7 +2598,6 @@ describe("OpenFinGlobalShortcutManager", () => { }); }); -// For items 1-3 in our remaining coverage areas describe("OpenFinContainerWindow constructor", () => { it("creates a new instance with the provided window", () => { const innerWindow = { name: "test-window" }; @@ -2864,37 +2609,30 @@ describe("OpenFinContainerWindow constructor", () => { describe("registerContainer", () => { it("registers OpenFin container", () => { - // Create a mock global window const mockWindow: any = { fin: { desktop: {} } }; - // Mock the condition function to avoid window reference issues const mockConditionFunc = jest.fn().mockImplementation(() => { return typeof mockWindow !== "undefined" && "fin" in mockWindow && "desktop" in mockWindow.fin; }); - // Create a mock for registerContainer const mockRegisterContainer = jest.fn(); - // Call our mock mockRegisterContainer("OpenFin", { condition: mockConditionFunc, create: () => new OpenFinContainer(null, null, {}) }); - // Verify it was called with the right parameters expect(mockRegisterContainer).toHaveBeenCalledWith("OpenFin", { condition: mockConditionFunc, create: expect.any(Function) }); - // Verify the condition works with desktop expect(mockConditionFunc()).toBe(true); - // Modify window to make condition false delete mockWindow.fin.desktop; expect(mockConditionFunc()).toBe(false); }); @@ -2902,40 +2640,30 @@ describe("registerContainer", () => { describe("OpenFinContainer additional functions", () => { it("uses replaceNotificationApi from options", () => { - // Create a container with replaceNotificationApi set to false const desktop = new MockDesktop(); const container = new OpenFinContainer(desktop, {}, { replaceNotificationApi: false }); - // Mock registerNotificationsApi const mockRegisterNotificationsApi = jest.spyOn(container as any, "registerNotificationsApi"); - // Call setOptions with replaceNotificationApi = true container.setOptions({ replaceNotificationApi: true }); - // Verify registerNotificationsApi was called expect(mockRegisterNotificationsApi).toHaveBeenCalled(); - // Reset and try with false mockRegisterNotificationsApi.mockClear(); container.setOptions({ replaceNotificationApi: false }); - // Verify it wasn't called expect(mockRegisterNotificationsApi).not.toHaveBeenCalled(); }); it("has the static option to replace notification API", () => { - // Save original value const originalValue = OpenFinContainer.replaceNotificationApi; try { - // Verify default is true expect(OpenFinContainer.replaceNotificationApi).toBe(true); - // Change and verify OpenFinContainer.replaceNotificationApi = false; expect(OpenFinContainer.replaceNotificationApi).toBe(false); } finally { - // Restore original OpenFinContainer.replaceNotificationApi = originalValue; } }); @@ -2946,23 +2674,18 @@ describe("menu handling", () => { const desktop = new MockDesktop(); const container = new OpenFinContainer(desktop); - // Mock methods to avoid calling actual showMenu (container as any).ensureAbsoluteUrl = jest.fn(url => url); - // Test the getMenuItemHtml method directly const menuItem = { id: "test-id", label: "Test Label", icon: "icon.png" }; const menuItemHtml: string = (container as any).getMenuItemHtml(menuItem); - // Verify the HTML contains the id and label expect(menuItemHtml).toContain("test-id"); expect(menuItemHtml).toContain("Test Label"); expect(menuItemHtml).toContain("icon.png"); - // Test with no icon const menuItemNoIcon = { id: "test-id", label: "Test Label" }; const menuItemHtmlNoIcon: string = (container as any).getMenuItemHtml(menuItemNoIcon); - // Verify the HTML contains   for no icon expect(menuItemHtmlNoIcon).toContain(" "); }); @@ -2970,16 +2693,12 @@ describe("menu handling", () => { const desktop = new MockDesktop(); const container = new OpenFinContainer(desktop); - // Mock the showMenu method to avoid actual implementation const mockShowMenu = jest.fn(); (container as any).showMenu = mockShowMenu; - // Mock ensureAbsoluteUrl (container as any).ensureAbsoluteUrl = jest.fn(url => url); - // Create a mock for setTrayIcon const mockSetTrayIcon = jest.fn().mockImplementation((icon, callback) => { - // Simulate a right click callback({ button: 2, x: 100, @@ -2994,27 +2713,22 @@ describe("menu handling", () => { desktop.Application.getCurrent().setTrayIcon = mockSetTrayIcon; - // Set up the mock for Application.getCurrent const mockApp = { setTrayIcon: mockSetTrayIcon, uuid: "test-uuid" }; desktop.Application.getCurrent = jest.fn().mockReturnValue(mockApp); - // Set up a UUID Object.defineProperty(container, 'uuid', { value: "test-uuid", writable: true }); - // Add a tray icon with menu items const menuItems = [{ label: "Test Item" }]; container.addTrayIcon({ icon: "icon.png" }, () => {}, menuItems); - // Verify setTrayIcon was called expect(mockSetTrayIcon).toHaveBeenCalled(); - // Verify showMenu was called with the right parameters expect(mockShowMenu).toHaveBeenCalledWith( 100 + OpenFinContainer.trayIconMenuLeftOffset, 100 + OpenFinContainer.trayIconMenuTopOffset, @@ -3036,16 +2750,12 @@ describe("OpenFinContainer", () => { describe("handles tray icon right click", () => { it("triggers showMenu with the correct parameters", () => { - // Mock the showMenu method to avoid actual implementation const mockShowMenu = jest.fn(); (container as any).showMenu = mockShowMenu; - // Mock ensureAbsoluteUrl (container as any).ensureAbsoluteUrl = jest.fn(url => url); - // Create a mock for setTrayIcon const mockSetTrayIcon = jest.fn().mockImplementation((icon, callback) => { - // Simulate a right click callback({ button: 2, x: 100, @@ -3058,27 +2768,22 @@ describe("OpenFinContainer", () => { }); }); - // Set up the mock for Application.getCurrent const mockApp = { setTrayIcon: mockSetTrayIcon, uuid: "test-uuid" }; desktop.Application.getCurrent = jest.fn().mockReturnValue(mockApp); - // Set up a UUID Object.defineProperty(container, 'uuid', { value: "test-uuid", writable: true }); - // Add a tray icon with menu items const menuItems = [{ label: "Test Item" }]; container.addTrayIcon({ icon: "icon.png" }, () => {}, menuItems); - // Verify setTrayIcon was called expect(mockSetTrayIcon).toHaveBeenCalled(); - // Verify showMenu was called with the right parameters expect(mockShowMenu).toHaveBeenCalledWith( 100 + OpenFinContainer.trayIconMenuLeftOffset, 100 + OpenFinContainer.trayIconMenuTopOffset, diff --git a/packages/desktopjs-openfin/vite.config.ts b/packages/desktopjs-openfin/vite.config.ts index e8f3740b..4162dcd5 100644 --- a/packages/desktopjs-openfin/vite.config.ts +++ b/packages/desktopjs-openfin/vite.config.ts @@ -1,3 +1,17 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. Unless required by applicable law or agreed + * to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + import { defineConfig } from 'vite'; import { resolve } from 'path'; import dts from 'vite-plugin-dts'; diff --git a/packages/desktopjs/tests/setup.ts b/packages/desktopjs/tests/setup.ts index 282a7f81..bccde12b 100644 --- a/packages/desktopjs/tests/setup.ts +++ b/packages/desktopjs/tests/setup.ts @@ -1,3 +1,17 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. Unless required by applicable law or agreed + * to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + /** * Jest Setup File for desktopJS * diff --git a/packages/desktopjs/vite.config.ts b/packages/desktopjs/vite.config.ts index baf59993..cd66311b 100644 --- a/packages/desktopjs/vite.config.ts +++ b/packages/desktopjs/vite.config.ts @@ -1,3 +1,17 @@ +/* + * Morgan Stanley makes this available to you under the Apache License, + * Version 2.0 (the "License"). You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0. + * + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. Unless required by applicable law or agreed + * to in writing, software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the License for the specific language governing permissions + * and limitations under the License. + */ + import { defineConfig } from 'vite'; import { resolve } from 'path'; import dts from 'vite-plugin-dts'; diff --git a/tsconfig.test.json b/tsconfig.test.json index 078be5ed..7b596bcd 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -11,6 +11,14 @@ }, "include": [ "packages/*/src/**/*.ts", - "packages/*/tests/**/*.ts" + "packages/*/tests/**/*.ts", + "**/*/vite.config.ts" + ], + "exclude": [ + "node_modules", + "**/dist", + "**/build", + "**/coverage", + "docs" ] } From 6709cbfc88e375c89acf702a0359499a2b357745 Mon Sep 17 00:00:00 2001 From: bingenito Date: Fri, 2 May 2025 08:30:07 -0400 Subject: [PATCH 2/2] Add linting instructions to readme --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 9234c6e9..6aa048fc 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,20 @@ or it is recommended to define a custom keyboard binding. } ``` +### Linting + +Run the linter: + +```bash +npm run lint +``` + +Automatically fix fixable issues: + +```bash +npm run lint:fix +``` + Examples -------- Examples showcasing usage of desktopJS for various containers and scenarios can be found under