From 9adc6400939cbb2dc108e6a02bb3f69e9e27fa60 Mon Sep 17 00:00:00 2001 From: Robert Hebel Date: Tue, 10 Jun 2025 00:30:22 +0200 Subject: [PATCH 1/4] feat: export basic type definitions for swagger editor and props-change-watcher plugin --- .eslintrc | 28 +- package-lock.json | 309 ++++++++++++++++++ package.json | 9 +- src/{App.jsx => App.tsx} | 55 +--- src/index.d.ts | 1 + src/{index.jsx => index.tsx} | 4 +- .../{actions.js => actions.ts} | 2 +- .../props-change-watcher/hooks/index.js | 2 - .../props-change-watcher/hooks/index.ts | 2 + ...se-mount-plugin.js => use-mount-plugin.ts} | 7 +- ...{use-prop-change.js => use-prop-change.ts} | 4 +- .../{index.js => index.ts} | 4 +- .../{plugin-impl.js => plugin-impl.ts} | 2 +- ...{reportWebVitals.js => reportWebVitals.ts} | 5 +- src/types/global.d.ts | 10 + src/types/index.d.ts | 60 ++++ src/types/swagger-editor.ts | 18 + src/types/system.ts | 19 ++ tsconfig.json | 37 +++ 19 files changed, 517 insertions(+), 61 deletions(-) rename src/{App.jsx => App.tsx} (81%) create mode 100644 src/index.d.ts rename src/{index.jsx => index.tsx} (86%) rename src/plugins/props-change-watcher/{actions.js => actions.ts} (61%) delete mode 100644 src/plugins/props-change-watcher/hooks/index.js create mode 100644 src/plugins/props-change-watcher/hooks/index.ts rename src/plugins/props-change-watcher/hooks/{use-mount-plugin.js => use-mount-plugin.ts} (56%) rename src/plugins/props-change-watcher/hooks/{use-prop-change.js => use-prop-change.ts} (75%) rename src/plugins/props-change-watcher/{index.js => index.ts} (73%) rename src/plugins/props-change-watcher/{plugin-impl.js => plugin-impl.ts} (71%) rename src/{reportWebVitals.js => reportWebVitals.ts} (67%) create mode 100644 src/types/global.d.ts create mode 100644 src/types/index.d.ts create mode 100644 src/types/swagger-editor.ts create mode 100644 src/types/system.ts create mode 100644 tsconfig.json diff --git a/.eslintrc b/.eslintrc index c80940f3cbf..f3454d75e93 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,6 +3,7 @@ "react-app", "react-app/jest", "airbnb", + "airbnb-typescript", "plugin:cypress/recommended", "plugin:jsx-a11y/recommended", "prettier", @@ -19,7 +20,8 @@ "parserOptions": { "ecmaFeatures": { "jsx": true - } + }, + "project": "tsconfig.json" }, "plugins": [ "jsx-a11y", @@ -54,5 +56,27 @@ "^@swagger-api\/apidom-json-pointer" ] }] - } + }, + "overrides": [ + { + "files": ["*.ts", "*.tsx"], + "rules": { + "import/extensions": "off", + "import/no-unresolved": "off" + } + }, + { + "files": ["*.js"], + "rules": { + "@typescript-eslint/return-await": "off" + } + }, + { + "files": ["globals.d.ts"], + "rules": { + "vars-on-top": "off", + "no-var": "off" + } + } + ] } diff --git a/package-lock.json b/package-lock.json index c3697184415..b70f318ec30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,11 +71,15 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", + "@types/lodash": "^4.17.17", + "@types/swagger-ui-react": "^5.18.0", + "@typescript-eslint/eslint-plugin": "^5.62.0", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", "cypress": "^13.15.2", "cypress-file-upload": "^5.0.8", "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-cypress": "^3.3.0", "eslint-plugin-prettier": "^5.4.0", @@ -91,6 +95,7 @@ "serve": "^14.2.4", "source-map-explorer": "^2.5.3", "start-server-and-test": "^2.0.11", + "typescript-strict-plugin": "^2.4.4", "web-vitals": "^4.2.4" } }, @@ -8153,6 +8158,13 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/lodash": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz", + "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -8332,6 +8344,16 @@ "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==" }, + "node_modules/@types/swagger-ui-react": { + "version": "5.18.0", + "resolved": "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-5.18.0.tgz", + "integrity": "sha512-c2M9adVG7t28t1pq19K9Jt20VLQf0P/fwJwnfcmsVVsdkwCWhRmbKDu+tIs0/NGwJ/7GY8lBx+iKZxuDI5gDbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -9756,6 +9778,68 @@ "node": ">=8" } }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bl/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/blob-util": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", @@ -10454,6 +10538,19 @@ "node": ">=8" } }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-table3": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", @@ -10566,6 +10663,16 @@ "node": ">=12" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -12675,6 +12782,19 @@ "node": ">= 10" } }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -13538,6 +13658,22 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-config-airbnb-typescript": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", + "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-config-airbnb-base": "^15.0.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", + "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", + "eslint": "^7.32.0 || ^8.2.0", + "eslint-plugin-import": "^2.25.3" + } + }, "node_modules/eslint-config-prettier": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", @@ -16728,6 +16864,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-map": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", @@ -22152,6 +22298,30 @@ "node": ">= 0.8.0" } }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ospath": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", @@ -28050,6 +28220,135 @@ "node": ">=4.2.0" } }, + "node_modules/typescript-strict-plugin": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/typescript-strict-plugin/-/typescript-strict-plugin-2.4.4.tgz", + "integrity": "sha512-OXcWHQk+pW9gqEL/Mb1eTgj/Yiqk1oHBERr9v4VInPOYN++p+cXejmQK/h/VlUPGD++FXQ8pgiqVMyEtxU4T6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^3.0.0", + "execa": "^4.0.0", + "minimatch": "^9.0.3", + "ora": "^5.4.1", + "yargs": "^16.2.0" + }, + "bin": { + "tsc-strict": "dist/cli/tsc-strict/index.js", + "update-strict-comments": "dist/cli/update-strict-comments/index.js" + } + }, + "node_modules/typescript-strict-plugin/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-strict-plugin/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/typescript-strict-plugin/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/typescript-strict-plugin/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript-strict-plugin/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/typescript-strict-plugin/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/typescript-strict-plugin/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", @@ -28578,6 +28877,16 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", diff --git a/package.json b/package.json index a3880e7fd48..7d04195dba7 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "module": "./dist/esm/swagger-editor.js", "browser": "./dist/esm/swagger-editor.js", "jsnext:main": "./dist/esm/swagger-editor.js", + "types": "./dist/types/app.d.ts", "exports": { "./package.json": "./package.json", "./swagger-editor.css": "./dist/swagger-editor.css", @@ -35,11 +36,12 @@ }, "scripts": { "start": "cross-env DISABLE_ESLINT_PLUGIN=false ENABLE_PROGRESS_PLUGIN=true react-scripts start", - "build": "npm run build:app && npm run build:bundle:esm && npm run build:bundle:umd", + "build": "npm run build:app && npm run build:bundle:esm && npm run build:bundle:umd && npm run build:definitions", "build:app": "cross-env NODE_OPTIONS=--max_old_space_size=4096 ENABLE_PROGRESS_PLUGIN=false DISABLE_ESLINT_PLUGIN=false react-scripts build", "build:app:serve": "serve -s build -l 3050 -L", "build:bundle:esm": "rimraf ./dist/esm && cross-env DISABLE_ESLINT_PLUGIN=false ENABLE_PROGRESS_PLUGIN=false GENERATE_SOURCEMAP=true BUILD_ESM_BUNDLE=true DIST_PATH=dist/esm react-scripts build-bundle && rimraf ./dist/esm/swagger-editor.css*", "build:bundle:umd": "rimraf ./dist/umd ./dist/swagger-editor.css && cross-env NODE_OPTIONS=--max_old_space_size=4096 DISABLE_ESLINT_PLUGIN=false ENABLE_PROGRESS_PLUGIN=false GENERATE_SOURCEMAP=false BUILD_UMD_BUNDLE=true DIST_PATH=dist/umd react-scripts build-bundle && copyfiles -u 2 ./dist/umd/swagger-editor.css ./dist && rimraf ./dist/umd/swagger-editor.css", + "build:definitions": "tsc -p tsconfig.json", "analyze": "source-map-explorer 'build/static/js/main.6d62e780.js'", "test": "react-scripts test", "cy:dev": "start-server-and-test cy:dev:server http://localhost:3003 cy:dev:open", @@ -135,11 +137,15 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", + "@types/lodash": "^4.17.17", + "@types/swagger-ui-react": "^5.18.0", + "@typescript-eslint/eslint-plugin": "^5.62.0", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", "cypress": "^13.15.2", "cypress-file-upload": "^5.0.8", "eslint-config-airbnb": "^19.0.4", + "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-cypress": "^3.3.0", "eslint-plugin-prettier": "^5.4.0", @@ -155,6 +161,7 @@ "serve": "^14.2.4", "source-map-explorer": "^2.5.3", "start-server-and-test": "^2.0.11", + "typescript-strict-plugin": "^2.4.4", "web-vitals": "^4.2.4" } } diff --git a/src/App.jsx b/src/App.tsx similarity index 81% rename from src/App.jsx rename to src/App.tsx index b08df0c67bf..e41168b6c32 100644 --- a/src/App.jsx +++ b/src/App.tsx @@ -1,7 +1,7 @@ +// @ts-strict-ignore import React, { useMemo } from 'react'; -import PropTypes from 'prop-types'; import isPlainObject from 'lodash/isPlainObject.js'; -import SwaggerUI from 'swagger-ui-react'; +import SwaggerUI, { SwaggerUIProps } from 'swagger-ui-react'; import 'swagger-ui-react/swagger-ui.css'; /** * Plugins @@ -30,17 +30,21 @@ import EditorContentFixturesPlugin from 'plugins/editor-content-fixtures/index.j import EditorContentFromFilePlugin from 'plugins/editor-content-from-file/index.js'; import EditorSafeRenderPlugin from 'plugins/editor-safe-render/index.js'; import SwaggerUIAdapterPlugin from 'plugins/swagger-ui-adapter/index.js'; -import PropsChangeWatcherPlugin from 'plugins/props-change-watcher/index.js'; +import PropsChangeWatcherPlugin from 'plugins/props-change-watcher/index.ts'; import UtilPlugin from 'plugins/util/index.js'; /** * Presets */ import TextareaPreset from 'presets/textarea/index.js'; import MonacoPreset from 'presets/monaco/index.js'; +/** + * Types + */ +import { SwaggerEditorType } from 'types/swagger-editor.ts'; import './styles/main.scss'; -const SwaggerEditor = React.memo( +const SwaggerEditor: SwaggerEditorType = React.memo( ({ spec = SwaggerUI.config.defaults.spec, url = SwaggerUI.config.defaults.url, @@ -56,7 +60,7 @@ const SwaggerEditor = React.memo( defaultModelExpandDepth = SwaggerUI.config.defaults.defaultModelExpandDepth, defaultModelsExpandDepth = SwaggerUI.config.defaults.defaultModelsExpandDepth, defaultModelRendering = SwaggerUI.config.defaults.defaultModelRendering, - presets = [SwaggerEditor.presets.default], + presets = SwaggerEditor.presets?.default ? [SwaggerEditor.presets.default] : [], deepLinking = SwaggerUI.config.defaults.deepLinking, showExtensions = true, showCommonExtensions = SwaggerUI.config.defaults.showCommonExtensions, @@ -70,7 +74,7 @@ const SwaggerEditor = React.memo( oauth2RedirectUrl = SwaggerUI.config.defaults.oauth2RedirectUrl, initialState = SwaggerUI.config.defaults.initialState, onComplete = null, - }) => { + }: SwaggerUIProps) => { const { plugin: propsChangeWatcherPlugin, getSystem } = PropsChangeWatcherPlugin.useMountPlugin(); const specStr = useMemo(() => { @@ -124,45 +128,6 @@ const SwaggerEditor = React.memo( } ); -/* eslint-disable react/require-default-props */ -SwaggerEditor.propTypes = { - spec: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), - url: PropTypes.string, - layout: PropTypes.string, - requestInterceptor: PropTypes.func, - responseInterceptor: PropTypes.func, - onComplete: PropTypes.func, - docExpansion: PropTypes.oneOf(['list', 'full', 'none']), - supportedSubmitMethods: PropTypes.arrayOf( - PropTypes.oneOf(['get', 'put', 'post', 'delete', 'options', 'head', 'patch', 'trace']) - ), - queryConfigEnabled: PropTypes.bool, - plugins: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.object), - PropTypes.arrayOf(PropTypes.func), - PropTypes.func, - ]), - displayOperationId: PropTypes.bool, - showMutatedRequest: PropTypes.bool, - defaultModelExpandDepth: PropTypes.number, - defaultModelsExpandDepth: PropTypes.number, - defaultModelRendering: PropTypes.oneOf(['example', 'model']), - presets: PropTypes.arrayOf(PropTypes.func), - deepLinking: PropTypes.bool, - showExtensions: PropTypes.bool, - showCommonExtensions: PropTypes.bool, - filter: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), - requestSnippetsEnabled: PropTypes.bool, - requestSnippets: PropTypes.shape(), - tryItOutEnabled: PropTypes.bool, - displayRequestDuration: PropTypes.bool, - persistAuthorization: PropTypes.bool, - withCredentials: PropTypes.bool, - oauth2RedirectUrl: PropTypes.string, - initialState: PropTypes.shape(), -}; -/* eslint-enable */ - SwaggerEditor.plugins = { Util: UtilPlugin, Modals: ModalsPlugin, diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 00000000000..4f3fccd85ba --- /dev/null +++ b/src/index.d.ts @@ -0,0 +1 @@ +import 'swagger-ui-react/swagger-ui.css'; diff --git a/src/index.jsx b/src/index.tsx similarity index 86% rename from src/index.jsx rename to src/index.tsx index 04dd3ff7124..92bd0d22e2b 100644 --- a/src/index.jsx +++ b/src/index.tsx @@ -2,9 +2,9 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; import 'swagger-ui-react/swagger-ui.css'; -import SwaggerEditor from './App.jsx'; +import SwaggerEditor from './App.tsx'; -const root = createRoot(document.getElementById('swagger-editor')); +const root = createRoot(document.getElementById('swagger-editor') as HTMLElement); if (process.env.REACT_APP_E2E_TESTS) { globalThis.React = React; diff --git a/src/plugins/props-change-watcher/actions.js b/src/plugins/props-change-watcher/actions.ts similarity index 61% rename from src/plugins/props-change-watcher/actions.js rename to src/plugins/props-change-watcher/actions.ts index 0cf04c07e91..4bc3b76e04e 100644 --- a/src/plugins/props-change-watcher/actions.js +++ b/src/plugins/props-change-watcher/actions.ts @@ -1,6 +1,6 @@ export const EDITOR_PROP_CHANGED = 'EDITOR_PROP_CHANGED'; -export const propChanged = (propName, newValue, oldValue) => ({ +export const propChanged = (propName: string, newValue: unknown, oldValue: unknown) => ({ type: EDITOR_PROP_CHANGED, payload: propName, meta: { newValue, oldValue }, diff --git a/src/plugins/props-change-watcher/hooks/index.js b/src/plugins/props-change-watcher/hooks/index.js deleted file mode 100644 index d3c4c06d709..00000000000 --- a/src/plugins/props-change-watcher/hooks/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export { default as usePropChange } from './use-prop-change.js'; -export { default as useMountPlugin } from './use-mount-plugin.js'; diff --git a/src/plugins/props-change-watcher/hooks/index.ts b/src/plugins/props-change-watcher/hooks/index.ts new file mode 100644 index 00000000000..22c7e021e70 --- /dev/null +++ b/src/plugins/props-change-watcher/hooks/index.ts @@ -0,0 +1,2 @@ +export { default as usePropChange } from './use-prop-change.ts'; +export { default as useMountPlugin } from './use-mount-plugin.ts'; diff --git a/src/plugins/props-change-watcher/hooks/use-mount-plugin.js b/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts similarity index 56% rename from src/plugins/props-change-watcher/hooks/use-mount-plugin.js rename to src/plugins/props-change-watcher/hooks/use-mount-plugin.ts index 27621627ae2..b207bc3cf8d 100644 --- a/src/plugins/props-change-watcher/hooks/use-mount-plugin.js +++ b/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts @@ -1,12 +1,13 @@ import { useRef } from 'react'; +import { GetSystemValues, System } from 'types/system.ts'; -import pluginImpl from '../plugin-impl.js'; +import pluginImpl from '../plugin-impl.ts'; const useMountPlugin = () => { - const system = useRef(null); + const system = useRef(null); return { - plugin(sys) { + plugin(sys: System) { system.current = sys.getSystem(); return pluginImpl; }, diff --git a/src/plugins/props-change-watcher/hooks/use-prop-change.js b/src/plugins/props-change-watcher/hooks/use-prop-change.ts similarity index 75% rename from src/plugins/props-change-watcher/hooks/use-prop-change.js rename to src/plugins/props-change-watcher/hooks/use-prop-change.ts index 39cb3f73a51..c74dad873a0 100644 --- a/src/plugins/props-change-watcher/hooks/use-prop-change.js +++ b/src/plugins/props-change-watcher/hooks/use-prop-change.ts @@ -1,6 +1,8 @@ import { useEffect, useRef } from 'react'; -const usePropChange = (prop, callback) => { +type UsePropChangeCallback = (newValue: unknown, oldValue: unknown) => void; + +const usePropChange = (prop: string | object | undefined, callback: UsePropChangeCallback) => { const isInitialMount = useRef(true); const previousProp = useRef(prop); diff --git a/src/plugins/props-change-watcher/index.js b/src/plugins/props-change-watcher/index.ts similarity index 73% rename from src/plugins/props-change-watcher/index.js rename to src/plugins/props-change-watcher/index.ts index dbaf98a8a65..87c7870fe4c 100644 --- a/src/plugins/props-change-watcher/index.js +++ b/src/plugins/props-change-watcher/index.ts @@ -1,5 +1,5 @@ -import pluginImpl from './plugin-impl.js'; -import { usePropChange, useMountPlugin } from './hooks/index.js'; +import pluginImpl from './plugin-impl.ts'; +import { usePropChange, useMountPlugin } from './hooks/index.ts'; /** * This plugin is meant to be utilized via the `useMountPlugin` hook. diff --git a/src/plugins/props-change-watcher/plugin-impl.js b/src/plugins/props-change-watcher/plugin-impl.ts similarity index 71% rename from src/plugins/props-change-watcher/plugin-impl.js rename to src/plugins/props-change-watcher/plugin-impl.ts index 6da41f0fff1..c093b158313 100644 --- a/src/plugins/props-change-watcher/plugin-impl.js +++ b/src/plugins/props-change-watcher/plugin-impl.ts @@ -1,4 +1,4 @@ -import { propChanged } from './actions.js'; +import { propChanged } from './actions.ts'; export default { statePlugins: { diff --git a/src/reportWebVitals.js b/src/reportWebVitals.ts similarity index 67% rename from src/reportWebVitals.js rename to src/reportWebVitals.ts index 9fb67546c17..007127e2325 100644 --- a/src/reportWebVitals.js +++ b/src/reportWebVitals.ts @@ -1,4 +1,7 @@ -const reportWebVitals = (onPerfEntry) => { +// eslint-disable-next-line import/no-extraneous-dependencies +import { MetricType } from 'web-vitals'; + +const reportWebVitals = (onPerfEntry?: (metric: MetricType) => void) => { if (onPerfEntry && onPerfEntry instanceof Function) { // eslint-disable-next-line import/no-extraneous-dependencies import('web-vitals').then(({ onCLS, onFID, onFCP, onLCP, onTTFB }) => { diff --git a/src/types/global.d.ts b/src/types/global.d.ts new file mode 100644 index 00000000000..bac00fefce2 --- /dev/null +++ b/src/types/global.d.ts @@ -0,0 +1,10 @@ +import { Root } from 'react-dom/client.ts'; + +import { SwaggerEditorType } from './swagger-editor.ts'; + +declare global { + var root: Root; + var SwaggerEditor: SwaggerEditorType; +} + +export {}; diff --git a/src/types/index.d.ts b/src/types/index.d.ts new file mode 100644 index 00000000000..1ccb7b92fc5 --- /dev/null +++ b/src/types/index.d.ts @@ -0,0 +1,60 @@ +declare module 'swagger-ui-react' { + interface Request { + [k: string]: any; + } + interface Response { + [k: string]: any; + } + type System = any; + + type PluginGenerator = (system: System) => object; + + type Plugin = object | PluginGenerator; + + export type Preset = () => unknown; + + export interface SwaggerUIProps { + spec?: object | string; + url?: string; + layout?: string; + onComplete?: null | ((system: System) => void); + requestInterceptor?: (req: Request) => Request | Promise; + responseInterceptor?: (res: Response) => Response | Promise; + docExpansion?: 'list' | 'full' | 'none'; + defaultModelExpandDepth?: number; + defaultModelsExpandDepth?: number; + defaultModelRendering?: 'example' | 'model'; + initialState?: object; + queryConfigEnabled?: boolean; + plugins?: Plugin[]; + supportedSubmitMethods?: Array< + 'get' | 'put' | 'post' | 'delete' | 'options' | 'head' | 'patch' | 'trace' + >; + deepLinking?: boolean; + showMutatedRequest?: boolean; + showExtensions?: boolean; + showCommonExtensions?: boolean; + presets?: Preset[]; + filter?: string | boolean; + requestSnippetsEnabled?: boolean; + requestSnippets?: object; + displayOperationId?: boolean; + tryItOutEnabled?: boolean; + displayRequestDuration?: boolean; + persistAuthorization?: boolean; + withCredentials?: boolean; + oauth2RedirectUrl?: string; + } + + class SwaggerUI extends React.Component { + static config: { + defaults: SwaggerUIProps & { + plugins: []; + }; + }; + + static presets: any; + } + + export default SwaggerUI; +} diff --git a/src/types/swagger-editor.ts b/src/types/swagger-editor.ts new file mode 100644 index 00000000000..6a18ece7719 --- /dev/null +++ b/src/types/swagger-editor.ts @@ -0,0 +1,18 @@ +import React from 'react'; +import { Preset, SwaggerUIProps } from 'swagger-ui-react'; + +interface SwaggerEditorPlugins { + plugins?: { + [key: string]: Preset; + }; +} + +interface SwaggerEditorPresets { + presets?: { + [key: string]: Preset; + }; +} + +export type SwaggerEditorType = React.NamedExoticComponent & + SwaggerEditorPresets & + SwaggerEditorPlugins; diff --git a/src/types/system.ts b/src/types/system.ts new file mode 100644 index 00000000000..2526a65a5f8 --- /dev/null +++ b/src/types/system.ts @@ -0,0 +1,19 @@ +export interface GetSystemValues { + getComponent: () => void; + editorSelectors: { + selectContent: () => unknown; + selectInferFileNameWithExtensionFromContent: () => unknown; + }; + editorActions: { + convertContentToJSON: () => void; + setContent: (content: unknown) => void; + propChanged: (spec: string, oldValue: unknown, newValue: unknown) => void; + }; + EditorContentOrigin: { + Conversion: string; + }; +} + +export interface System { + getSystem: () => GetSystemValues; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000000..e3cf6b5af71 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,37 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "nodenext", + "moduleResolution": "nodenext", + "allowImportingTsExtensions": true, + "baseUrl": "./", + "allowJs": false, + "declaration": true, + "emitDeclarationOnly": true, + "strict": false, + "rootDir": "./src", + "isolatedModules": true, + "outDir": "dist/types", + "sourceMap": true, + "composite": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "paths": { + "plugins/*": ["src/plugins/*"], + "presets/*": ["src/presets/*"], + "types/*": ["src/types/*"] + }, + "plugins": [ + { + "name": "typescript-strict-plugin" + } + ], + "typeRoots": ["./node_modules/@types"], + "types": [ + "node" + ], + "jsx": "react" + }, + "exclude": ["node_modules", "**/*.js", "**/*.jsx"], + "include": ["src/plugins/**/*.ts", "src/plugins/**/*.tsx", "src/index.tsx", "src/App.tsx", "src/index.d.ts", "src/types"] +} From ec10f8a0427aaf910a5eed7acec3d117e7a43aa0 Mon Sep 17 00:00:00 2001 From: Robert Hebel Date: Tue, 17 Jun 2025 15:25:37 +0200 Subject: [PATCH 2/4] feat: export basic type definitions for swagger editor and props-change-watcher plugin --- .eslintrc | 22 +++++++--- package-lock.json | 20 ++------- package.json | 21 ++++++--- src/App.tsx | 4 +- src/index.d.ts | 1 - src/index.tsx | 2 +- .../props-change-watcher/hooks/index.ts | 4 +- .../hooks/use-mount-plugin.ts | 4 +- src/plugins/props-change-watcher/index.ts | 4 +- .../props-change-watcher/plugin-impl.ts | 2 +- src/types/global.d.ts | 4 +- src/types/index.d.ts | 8 ++-- src/types/swagger-editor.ts | 43 ++++++++++++++++++- test/cypress/support/setup-node-events.js | 1 + tsconfig.json | 15 +++---- 15 files changed, 97 insertions(+), 58 deletions(-) delete mode 100644 src/index.d.ts diff --git a/.eslintrc b/.eslintrc index f3454d75e93..82db37fd109 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,13 +1,14 @@ { + "parser": "@typescript-eslint/parser", "extends": [ "react-app", "react-app/jest", "airbnb", - "airbnb-typescript", "plugin:cypress/recommended", "plugin:jsx-a11y/recommended", "prettier", - "plugin:prettier/recommended" + "plugin:prettier/recommended", + "plugin:@typescript-eslint/recommended" ], "globals": { "File": true, @@ -20,8 +21,7 @@ "parserOptions": { "ecmaFeatures": { "jsx": true - }, - "project": "tsconfig.json" + } }, "plugins": [ "jsx-a11y", @@ -38,8 +38,10 @@ }], "no-nested-ternary": "off", "prettier/prettier": "error", + "no-shadow": "off", "react/react-in-jsx-scope": 0, "react/require-default-props": "off", + "@typescript-eslint/no-empty-function": "off", "react/function-component-definition": [1, { "namedComponents": ["arrow-function"] }], @@ -55,7 +57,15 @@ "^@codingame\/monaco-vscode-api", "^@swagger-api\/apidom-json-pointer" ] - }] + }], + "react/jsx-filename-extension": [2, + { + "extensions": [ + ".tsx", + ".jsx" + ] + } + ] }, "overrides": [ { @@ -72,7 +82,7 @@ } }, { - "files": ["globals.d.ts"], + "files": ["*.d.ts"], "rules": { "vars-on-top": "off", "no-var": "off" diff --git a/package-lock.json b/package-lock.json index b70f318ec30..a3baf27bba4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,12 +74,12 @@ "@types/lodash": "^4.17.17", "@types/swagger-ui-react": "^5.18.0", "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", "cypress": "^13.15.2", "cypress-file-upload": "^5.0.8", "eslint-config-airbnb": "^19.0.4", - "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-cypress": "^3.3.0", "eslint-plugin-prettier": "^5.4.0", @@ -8466,6 +8466,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -13658,22 +13659,6 @@ "semver": "bin/semver.js" } }, - "node_modules/eslint-config-airbnb-typescript": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.1.0.tgz", - "integrity": "sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-config-airbnb-base": "^15.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.13.0 || ^6.0.0", - "@typescript-eslint/parser": "^5.0.0 || ^6.0.0", - "eslint": "^7.32.0 || ^8.2.0", - "eslint-plugin-import": "^2.25.3" - } - }, "node_modules/eslint-config-prettier": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", @@ -28211,6 +28196,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "dev": true, + "license": "Apache-2.0", "peer": true, "bin": { "tsc": "bin/tsc", diff --git a/package.json b/package.json index 7d04195dba7..b520476638f 100644 --- a/package.json +++ b/package.json @@ -14,15 +14,17 @@ "module": "./dist/esm/swagger-editor.js", "browser": "./dist/esm/swagger-editor.js", "jsnext:main": "./dist/esm/swagger-editor.js", - "types": "./dist/types/app.d.ts", + "types": "./dist/types/App.d.ts", "exports": { "./package.json": "./package.json", "./swagger-editor.css": "./dist/swagger-editor.css", ".": { - "browser": "./dist/esm/swagger-editor.js" + "browser": "./dist/esm/swagger-editor.js", + "types": "./dist/types/App.d.ts" }, "./plugins/*": { - "browser": "./dist/esm/plugins/*/index.js" + "browser": "./dist/esm/plugins/*/index.js", + "types": "./dist/types/plugins/*/index.d.ts" }, "./presets/*": { "browser": "./dist/esm/presets/*/index.js" @@ -34,6 +36,13 @@ "browser": "./dist/esm/editor.worker.js" } }, + "typesVersions": { + "*": { + "plugins/*": [ + "./dist/types/plugins/*/index.d.ts" + ] + } + }, "scripts": { "start": "cross-env DISABLE_ESLINT_PLUGIN=false ENABLE_PROGRESS_PLUGIN=true react-scripts start", "build": "npm run build:app && npm run build:bundle:esm && npm run build:bundle:umd && npm run build:definitions", @@ -52,8 +61,8 @@ "cy:run:chrome": "cross-env BROWSERSLIST_ENV=production cypress run --browser chrome", "cy:run:firefox": "cross-env BROWSERSLIST_ENV=production cypress run --browser firefox", "cy:run:electron": "cross-env BROWSERSLIST_ENV=production cypress run --browser electron", - "lint": "eslint . --ext .jsx,.js", - "lint:fix": "eslint . --ext .jsx,.js --fix", + "lint": "eslint . --ext .jsx,.js,.tsx,.ts", + "lint:fix": "eslint . --ext .jsx,.js,.tsx,.ts --fix", "clean": "rimraf ./build ./dist", "link:apidom": "npm link @swagger-api/apidom-ast @swagger-api/apidom-core @swagger-api/apidom-error @swagger-api/apidom-json-path @swagger-api/apidom-json-pointer @swagger-api/apidom-ls @swagger-api/apidom-ns-api-design-systems @swagger-api/apidom-ns-asyncapi-2 @swagger-api/apidom-ns-json-schema-draft-4 @swagger-api/apidom-ns-json-schema-draft-6 @swagger-api/apidom-ns-json-schema-draft-7 @swagger-api/apidom-ns-openapi-2 @swagger-api/apidom-ns-openapi-3-0 @swagger-api/apidom-ns-openapi-3-1 @swagger-api/apidom-parser-adapter-api-design-systems-json @swagger-api/apidom-parser-adapter-api-design-systems-yaml @swagger-api/apidom-parser-adapter-asyncapi-json-2 @swagger-api/apidom-parser-adapter-asyncapi-yaml-2 @swagger-api/apidom-parser-adapter-json @swagger-api/apidom-parser-adapter-openapi-json-2 @swagger-api/apidom-parser-adapter-openapi-json-3-0 @swagger-api/apidom-parser-adapter-openapi-json-3-1 @swagger-api/apidom-parser-adapter-openapi-yaml-2 @swagger-api/apidom-parser-adapter-openapi-yaml-3-0 @swagger-api/apidom-parser-adapter-openapi-yaml-3-1 @swagger-api/apidom-parser-adapter-yaml-1-2 @swagger-api/apidom-parser @swagger-api/apidom-reference", "link:apidom-ls": "npm link @swagger-api/apidom-ls" @@ -140,12 +149,12 @@ "@types/lodash": "^4.17.17", "@types/swagger-ui-react": "^5.18.0", "@typescript-eslint/eslint-plugin": "^5.62.0", + "@typescript-eslint/parser": "^5.62.0", "copyfiles": "^2.4.1", "cross-env": "^7.0.3", "cypress": "^13.15.2", "cypress-file-upload": "^5.0.8", "eslint-config-airbnb": "^19.0.4", - "eslint-config-airbnb-typescript": "^17.1.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-cypress": "^3.3.0", "eslint-plugin-prettier": "^5.4.0", diff --git a/src/App.tsx b/src/App.tsx index e41168b6c32..3181c589d93 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -30,7 +30,7 @@ import EditorContentFixturesPlugin from 'plugins/editor-content-fixtures/index.j import EditorContentFromFilePlugin from 'plugins/editor-content-from-file/index.js'; import EditorSafeRenderPlugin from 'plugins/editor-safe-render/index.js'; import SwaggerUIAdapterPlugin from 'plugins/swagger-ui-adapter/index.js'; -import PropsChangeWatcherPlugin from 'plugins/props-change-watcher/index.ts'; +import PropsChangeWatcherPlugin from 'plugins/props-change-watcher/index'; import UtilPlugin from 'plugins/util/index.js'; /** * Presets @@ -40,7 +40,7 @@ import MonacoPreset from 'presets/monaco/index.js'; /** * Types */ -import { SwaggerEditorType } from 'types/swagger-editor.ts'; +import { SwaggerEditorType } from 'types/swagger-editor'; import './styles/main.scss'; diff --git a/src/index.d.ts b/src/index.d.ts deleted file mode 100644 index 4f3fccd85ba..00000000000 --- a/src/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -import 'swagger-ui-react/swagger-ui.css'; diff --git a/src/index.tsx b/src/index.tsx index 92bd0d22e2b..12cf57b9a43 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; import 'swagger-ui-react/swagger-ui.css'; -import SwaggerEditor from './App.tsx'; +import SwaggerEditor from './App'; const root = createRoot(document.getElementById('swagger-editor') as HTMLElement); diff --git a/src/plugins/props-change-watcher/hooks/index.ts b/src/plugins/props-change-watcher/hooks/index.ts index 22c7e021e70..c711a812255 100644 --- a/src/plugins/props-change-watcher/hooks/index.ts +++ b/src/plugins/props-change-watcher/hooks/index.ts @@ -1,2 +1,2 @@ -export { default as usePropChange } from './use-prop-change.ts'; -export { default as useMountPlugin } from './use-mount-plugin.ts'; +export { default as usePropChange } from './use-prop-change'; +export { default as useMountPlugin } from './use-mount-plugin'; diff --git a/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts b/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts index b207bc3cf8d..e63d58bc2d1 100644 --- a/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts +++ b/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts @@ -1,7 +1,7 @@ import { useRef } from 'react'; -import { GetSystemValues, System } from 'types/system.ts'; +import { GetSystemValues, System } from 'types/system'; -import pluginImpl from '../plugin-impl.ts'; +import pluginImpl from '../plugin-impl'; const useMountPlugin = () => { const system = useRef(null); diff --git a/src/plugins/props-change-watcher/index.ts b/src/plugins/props-change-watcher/index.ts index 87c7870fe4c..949290a53e3 100644 --- a/src/plugins/props-change-watcher/index.ts +++ b/src/plugins/props-change-watcher/index.ts @@ -1,5 +1,5 @@ -import pluginImpl from './plugin-impl.ts'; -import { usePropChange, useMountPlugin } from './hooks/index.ts'; +import pluginImpl from './plugin-impl'; +import { usePropChange, useMountPlugin } from './hooks/index'; /** * This plugin is meant to be utilized via the `useMountPlugin` hook. diff --git a/src/plugins/props-change-watcher/plugin-impl.ts b/src/plugins/props-change-watcher/plugin-impl.ts index c093b158313..33ff6410764 100644 --- a/src/plugins/props-change-watcher/plugin-impl.ts +++ b/src/plugins/props-change-watcher/plugin-impl.ts @@ -1,4 +1,4 @@ -import { propChanged } from './actions.ts'; +import { propChanged } from './actions'; export default { statePlugins: { diff --git a/src/types/global.d.ts b/src/types/global.d.ts index bac00fefce2..5d062a79d3d 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -1,6 +1,6 @@ -import { Root } from 'react-dom/client.ts'; +import { Root } from 'react-dom/client'; -import { SwaggerEditorType } from './swagger-editor.ts'; +import { SwaggerEditorType } from './swagger-editor'; declare global { var root: Root; diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 1ccb7b92fc5..f9c1df5b921 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,11 +1,11 @@ declare module 'swagger-ui-react' { interface Request { - [k: string]: any; + [k: string]: unknown; } interface Response { - [k: string]: any; + [k: string]: unknown; } - type System = any; + type System = unknown; type PluginGenerator = (system: System) => object; @@ -53,7 +53,7 @@ declare module 'swagger-ui-react' { }; }; - static presets: any; + static presets: unknown; } export default SwaggerUI; diff --git a/src/types/swagger-editor.ts b/src/types/swagger-editor.ts index 6a18ece7719..5ef8e716265 100644 --- a/src/types/swagger-editor.ts +++ b/src/types/swagger-editor.ts @@ -1,15 +1,54 @@ import React from 'react'; import { Preset, SwaggerUIProps } from 'swagger-ui-react'; +import { System } from 'types/system'; + +type PluginGenerator = (system: System) => object; + +type Plugin = object | PluginGenerator; + +enum presetNames { + textarea = 'textarea', + monaco = 'monaco', + default = 'default', +} + +enum pluginNames { + Util = 'Util', + Modals = 'Modals', + Dialogs = 'Dialogs', + DropdownMenu = 'DropdownMenu', + Dropzone = 'Dropzone', + Versions = 'Versions', + EditorTextarea = 'EditorTextarea', + EditorMonaco = 'EditorMonaco', + EditorMonacoLanguageApiDOM = 'EditorMonacoLanguageApiDOM', + EditorMonacoYamlPaste = 'EditorMonacoYamlPaste', + EditorContentReadOnly = 'EditorContentReadOnly', + EditorContentOrigin = 'EditorContentOrigin', + EditorContentType = 'EditorContentType', + EditorContentPersistence = 'EditorContentPersistence', + EditorContentFixtures = 'EditorContentFixtures', + EditorContentFromFile = 'EditorContentFromFile', + EditorPreview = 'EditorPreview', + EditorPreviewSwaggerUI = 'EditorPreviewSwaggerUI', + EditorPreviewAsyncAPI = 'EditorPreviewAsyncAPI', + EditorPreviewApiDesignSystems = 'EditorPreviewApiDesignSystems', + EditorSafeRender = 'EditorSafeRender', + TopBar = 'TopBar', + SplashScreenPlugin = 'SplashScreenPlugin', + Layout = 'Layout', + SwaggerUIAdapter = 'SwaggerUIAdapter', +} interface SwaggerEditorPlugins { plugins?: { - [key: string]: Preset; + [key in pluginNames]: Plugin; }; } interface SwaggerEditorPresets { presets?: { - [key: string]: Preset; + [key in presetNames]: Preset; }; } diff --git a/test/cypress/support/setup-node-events.js b/test/cypress/support/setup-node-events.js index 8d7aba484e7..6c09f55af30 100644 --- a/test/cypress/support/setup-node-events.js +++ b/test/cypress/support/setup-node-events.js @@ -24,6 +24,7 @@ const setupNodeEvents = (on, config) => { console.error('\x1b[31m', 'ERROR:', message, '\x1b[0m'); return null; }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars warn(message) { // default: disabling warnings to reduce ci pollution // console.warn('\x1b[33m', 'WARNING:', message, '\x1b[0m'); diff --git a/tsconfig.json b/tsconfig.json index e3cf6b5af71..97726062e72 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,8 @@ { "compilerOptions": { "target": "esnext", - "module": "nodenext", - "moduleResolution": "nodenext", - "allowImportingTsExtensions": true, + "module": "esnext", + "moduleResolution": "node", "baseUrl": "./", "allowJs": false, "declaration": true, @@ -13,7 +12,7 @@ "isolatedModules": true, "outDir": "dist/types", "sourceMap": true, - "composite": true, + "incremental": false, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "paths": { @@ -26,12 +25,8 @@ "name": "typescript-strict-plugin" } ], - "typeRoots": ["./node_modules/@types"], - "types": [ - "node" - ], "jsx": "react" }, - "exclude": ["node_modules", "**/*.js", "**/*.jsx"], - "include": ["src/plugins/**/*.ts", "src/plugins/**/*.tsx", "src/index.tsx", "src/App.tsx", "src/index.d.ts", "src/types"] + "exclude": ["node_modules", "src/reportWebVitals.ts"], + "include": ["src/**/*.ts", "src/**/*.tsx", "src/*.ts", "src/*.tsx"] } From a5b3faab4cbd0fdffa95421dc6498420530fd5a2 Mon Sep 17 00:00:00 2001 From: Robert Hebel Date: Fri, 20 Jun 2025 16:58:57 +0200 Subject: [PATCH 3/4] refactor: refactor types --- package-lock.json | 19 ----------------- package.json | 2 -- src/plugins/props-change-watcher/actions.ts | 10 ++++++++- .../hooks/use-mount-plugin.ts | 4 ++-- .../hooks/use-prop-change.ts | 2 +- src/types/actions.ts | 13 ++++++++++++ src/types/index.d.ts | 4 ++-- src/types/swagger-editor.ts | 7 +------ src/types/system.ts | 21 +++++++++++-------- 9 files changed, 40 insertions(+), 42 deletions(-) create mode 100644 src/types/actions.ts diff --git a/package-lock.json b/package-lock.json index a3baf27bba4..53859580bc6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,8 +71,6 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/lodash": "^4.17.17", - "@types/swagger-ui-react": "^5.18.0", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "copyfiles": "^2.4.1", @@ -8158,13 +8156,6 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, - "node_modules/@types/lodash": { - "version": "4.17.17", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.17.tgz", - "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", @@ -8344,16 +8335,6 @@ "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==" }, - "node_modules/@types/swagger-ui-react": { - "version": "5.18.0", - "resolved": "https://registry.npmjs.org/@types/swagger-ui-react/-/swagger-ui-react-5.18.0.tgz", - "integrity": "sha512-c2M9adVG7t28t1pq19K9Jt20VLQf0P/fwJwnfcmsVVsdkwCWhRmbKDu+tIs0/NGwJ/7GY8lBx+iKZxuDI5gDbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/react": "*" - } - }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", diff --git a/package.json b/package.json index b520476638f..e51fb5ebf76 100644 --- a/package.json +++ b/package.json @@ -146,8 +146,6 @@ "@testing-library/jest-dom": "^6.6.3", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.6.1", - "@types/lodash": "^4.17.17", - "@types/swagger-ui-react": "^5.18.0", "@typescript-eslint/eslint-plugin": "^5.62.0", "@typescript-eslint/parser": "^5.62.0", "copyfiles": "^2.4.1", diff --git a/src/plugins/props-change-watcher/actions.ts b/src/plugins/props-change-watcher/actions.ts index 4bc3b76e04e..75159743fde 100644 --- a/src/plugins/props-change-watcher/actions.ts +++ b/src/plugins/props-change-watcher/actions.ts @@ -1,6 +1,14 @@ +import { Action } from 'types/actions'; + export const EDITOR_PROP_CHANGED = 'EDITOR_PROP_CHANGED'; -export const propChanged = (propName: string, newValue: unknown, oldValue: unknown) => ({ +export type PropChangedAction = ( + propName: string, + newValue: unknown, + oldValue: unknown +) => Action; + +export const propChanged: PropChangedAction = (propName, newValue, oldValue) => ({ type: EDITOR_PROP_CHANGED, payload: propName, meta: { newValue, oldValue }, diff --git a/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts b/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts index e63d58bc2d1..b093276c922 100644 --- a/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts +++ b/src/plugins/props-change-watcher/hooks/use-mount-plugin.ts @@ -1,10 +1,10 @@ import { useRef } from 'react'; -import { GetSystemValues, System } from 'types/system'; +import { SystemValues, System } from 'types/system'; import pluginImpl from '../plugin-impl'; const useMountPlugin = () => { - const system = useRef(null); + const system = useRef(null); return { plugin(sys: System) { diff --git a/src/plugins/props-change-watcher/hooks/use-prop-change.ts b/src/plugins/props-change-watcher/hooks/use-prop-change.ts index c74dad873a0..12376221574 100644 --- a/src/plugins/props-change-watcher/hooks/use-prop-change.ts +++ b/src/plugins/props-change-watcher/hooks/use-prop-change.ts @@ -2,7 +2,7 @@ import { useEffect, useRef } from 'react'; type UsePropChangeCallback = (newValue: unknown, oldValue: unknown) => void; -const usePropChange = (prop: string | object | undefined, callback: UsePropChangeCallback) => { +const usePropChange = (prop: unknown, callback: UsePropChangeCallback) => { const isInitialMount = useRef(true); const previousProp = useRef(prop); diff --git a/src/types/actions.ts b/src/types/actions.ts new file mode 100644 index 00000000000..76453ed2ebe --- /dev/null +++ b/src/types/actions.ts @@ -0,0 +1,13 @@ +export type AnyAction = { + type: T; +}; + +export interface Action< + Payload, + Meta extends Record | unknown[] | undefined = undefined, +> extends AnyAction { + type: string; + payload: Payload; + error?: boolean; + meta?: Meta; +} diff --git a/src/types/index.d.ts b/src/types/index.d.ts index f9c1df5b921..ae94af771eb 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -7,9 +7,9 @@ declare module 'swagger-ui-react' { } type System = unknown; - type PluginGenerator = (system: System) => object; + export type PluginGenerator = (system: System) => object; - type Plugin = object | PluginGenerator; + export type Plugin = object | PluginGenerator; export type Preset = () => unknown; diff --git a/src/types/swagger-editor.ts b/src/types/swagger-editor.ts index 5ef8e716265..cedd31606b4 100644 --- a/src/types/swagger-editor.ts +++ b/src/types/swagger-editor.ts @@ -1,10 +1,5 @@ import React from 'react'; -import { Preset, SwaggerUIProps } from 'swagger-ui-react'; -import { System } from 'types/system'; - -type PluginGenerator = (system: System) => object; - -type Plugin = object | PluginGenerator; +import { Preset, SwaggerUIProps, Plugin } from 'swagger-ui-react'; enum presetNames { textarea = 'textarea', diff --git a/src/types/system.ts b/src/types/system.ts index 2526a65a5f8..9bb0a4f38f8 100644 --- a/src/types/system.ts +++ b/src/types/system.ts @@ -1,19 +1,22 @@ -export interface GetSystemValues { +import { PropChangedAction } from 'plugins/props-change-watcher/actions'; +import { Action } from 'types/actions'; + +export interface SystemValues { getComponent: () => void; editorSelectors: { - selectContent: () => unknown; - selectInferFileNameWithExtensionFromContent: () => unknown; + selectContent: () => string; + selectInferFileNameWithExtensionFromContent: () => string; }; editorActions: { - convertContentToJSON: () => void; - setContent: (content: unknown) => void; - propChanged: (spec: string, oldValue: unknown, newValue: unknown) => void; + convertContentToJSON: (content: string) => Action; + setContent: (content: string) => Action; + propChanged: PropChangedAction; }; EditorContentOrigin: { - Conversion: string; + Conversion: 'conversion'; }; } -export interface System { - getSystem: () => GetSystemValues; +export interface System extends SystemValues { + getSystem: () => SystemValues; } From 528df78e0559bc59ec96608e732937415d29f665 Mon Sep 17 00:00:00 2001 From: Robert Hebel Date: Mon, 23 Jun 2025 10:52:31 +0200 Subject: [PATCH 4/4] refactor: make types more accurate --- src/types/system.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/types/system.ts b/src/types/system.ts index 9bb0a4f38f8..36e40b14f6e 100644 --- a/src/types/system.ts +++ b/src/types/system.ts @@ -1,14 +1,19 @@ import { PropChangedAction } from 'plugins/props-change-watcher/actions'; import { Action } from 'types/actions'; +import { ComponentType } from 'react'; export interface SystemValues { - getComponent: () => void; + getComponent: ( + componentName: string, + container?: boolean, + config?: object + ) => ComponentType | null; editorSelectors: { selectContent: () => string; selectInferFileNameWithExtensionFromContent: () => string; }; editorActions: { - convertContentToJSON: (content: string) => Action; + convertContentToJSON: (content: string) => Action; setContent: (content: string) => Action; propChanged: PropChangedAction; };