From a08dfe22de608e592717d7834e0d8067c00cef76 Mon Sep 17 00:00:00 2001 From: Donald Labaj Date: Tue, 9 Jun 2026 11:49:01 -0400 Subject: [PATCH 1/2] fix: Cleaned up and refactor code. --- .eslintrc.js | 2 +- .gitignore | 1 + .npmignore | 27 +++------- README.md | 11 ++++- {src => demo/src}/app/AppLayout/AppLayout.tsx | 2 +- {src => demo/src}/app/Comments/Comments.tsx | 2 +- {src => demo/src}/app/Dashboard/Dashboard.tsx | 0 {src => demo/src}/app/NotFound/NotFound.tsx | 0 .../app/Settings/General/GeneralSettings.tsx | 0 .../app/Settings/Profile/ProfileSettings.tsx | 0 {src => demo/src}/app/Support/Support.tsx | 0 .../src}/app/__snapshots__/app.test.tsx.snap | 0 {src => demo/src}/app/app.css | 0 {src => demo/src}/app/app.test.tsx | 0 .../src}/app/bgimages/Patternfly-Logo.svg | 0 {src => demo/src}/app/index.tsx | 4 +- {src => demo/src}/app/routes.tsx | 0 .../src}/app/utils/useDocumentTitle.ts | 0 {src => demo/src}/index.html | 0 {src => demo/src}/index.tsx | 0 {src => demo/src}/test/setup.ts | 0 {src => demo/src}/typings.d.ts | 0 demo/stylePaths.js | 17 +++++++ demo/tsconfig.json | 30 ++++++++++++ webpack.common.js => demo/webpack.common.js | 49 +++++++++---------- webpack.dev.js => demo/webpack.dev.js | 5 +- webpack.prod.js => demo/webpack.prod.js | 0 package-lock.json | 8 +-- package.json | 32 ++++++------ .../components/CommentOverlay.tsx | 0 .../components/CommentPanel.tsx | 0 .../components/CommentPin.tsx | 0 .../components/DetailsTab.tsx | 0 .../components/FloatingWidget.tsx | 0 .../components/GitHubIssuesTab.tsx | 0 .../components/IssuesTicketsTab.tsx | 0 .../commenting-system/components/JiraTab.tsx | 0 .../contexts/CommentContext.tsx | 0 .../contexts/GitHubAuthContext.tsx | 0 src/{app => }/commenting-system/index.ts | 0 .../services/githubAdapter.ts | 0 .../services/summarizeService.test.ts | 0 .../services/summarizeService.ts | 0 .../commenting-system/types/index.ts | 0 .../commenting-system/utils/componentUtils.ts | 0 src/{app => }/commenting-system/utils/env.ts | 0 .../utils/issueLinkRouteUtils.ts | 0 .../commenting-system/utils/selectorUtils.ts | 0 .../commenting-system/utils/version.ts | 0 stylePaths.js | 14 ------ tsconfig.json | 14 ++---- vitest.config.ts | 6 ++- 52 files changed, 123 insertions(+), 101 deletions(-) rename {src => demo/src}/app/AppLayout/AppLayout.tsx (99%) rename {src => demo/src}/app/Comments/Comments.tsx (99%) rename {src => demo/src}/app/Dashboard/Dashboard.tsx (100%) rename {src => demo/src}/app/NotFound/NotFound.tsx (100%) rename {src => demo/src}/app/Settings/General/GeneralSettings.tsx (100%) rename {src => demo/src}/app/Settings/Profile/ProfileSettings.tsx (100%) rename {src => demo/src}/app/Support/Support.tsx (100%) rename {src => demo/src}/app/__snapshots__/app.test.tsx.snap (100%) rename {src => demo/src}/app/app.css (100%) rename {src => demo/src}/app/app.test.tsx (100%) rename {src => demo/src}/app/bgimages/Patternfly-Logo.svg (100%) rename {src => demo/src}/app/index.tsx (81%) rename {src => demo/src}/app/routes.tsx (100%) rename {src => demo/src}/app/utils/useDocumentTitle.ts (100%) rename {src => demo/src}/index.html (100%) rename {src => demo/src}/index.tsx (100%) rename {src => demo/src}/test/setup.ts (100%) rename {src => demo/src}/typings.d.ts (100%) create mode 100644 demo/stylePaths.js create mode 100644 demo/tsconfig.json rename webpack.common.js => demo/webpack.common.js (62%) rename webpack.dev.js => demo/webpack.dev.js (98%) rename webpack.prod.js => demo/webpack.prod.js (100%) rename src/{app => }/commenting-system/components/CommentOverlay.tsx (100%) rename src/{app => }/commenting-system/components/CommentPanel.tsx (100%) rename src/{app => }/commenting-system/components/CommentPin.tsx (100%) rename src/{app => }/commenting-system/components/DetailsTab.tsx (100%) rename src/{app => }/commenting-system/components/FloatingWidget.tsx (100%) rename src/{app => }/commenting-system/components/GitHubIssuesTab.tsx (100%) rename src/{app => }/commenting-system/components/IssuesTicketsTab.tsx (100%) rename src/{app => }/commenting-system/components/JiraTab.tsx (100%) rename src/{app => }/commenting-system/contexts/CommentContext.tsx (100%) rename src/{app => }/commenting-system/contexts/GitHubAuthContext.tsx (100%) rename src/{app => }/commenting-system/index.ts (100%) rename src/{app => }/commenting-system/services/githubAdapter.ts (100%) rename src/{app => }/commenting-system/services/summarizeService.test.ts (100%) rename src/{app => }/commenting-system/services/summarizeService.ts (100%) rename src/{app => }/commenting-system/types/index.ts (100%) rename src/{app => }/commenting-system/utils/componentUtils.ts (100%) rename src/{app => }/commenting-system/utils/env.ts (100%) rename src/{app => }/commenting-system/utils/issueLinkRouteUtils.ts (100%) rename src/{app => }/commenting-system/utils/selectorUtils.ts (100%) rename src/{app => }/commenting-system/utils/version.ts (100%) delete mode 100644 stylePaths.js diff --git a/.eslintrc.js b/.eslintrc.js index d4b2f83..78737ef 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -29,7 +29,7 @@ module.exports = { }, "overrides": [ { - "files": ["src/**/*.ts", "src/**/*.tsx"], + "files": ["src/**/*.ts", "src/**/*.tsx", "demo/**/*.ts", "demo/**/*.tsx"], "parser": "@typescript-eslint/parser", "plugins": ["@typescript-eslint"], "extends": ["plugin:@typescript-eslint/recommended"], diff --git a/.gitignore b/.gitignore index 521a7f7..ca102f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ **/node_modules dist +demo/dist yarn-error.log yarn.lock stats.json diff --git a/.npmignore b/.npmignore index 5cdf43f..eccad43 100644 --- a/.npmignore +++ b/.npmignore @@ -1,47 +1,36 @@ # Dependencies node_modules/ -# Development files +# Demo app (not published) +demo/ + +# Development files *.md !README.md !LICENSE !GITHUB_OAUTH_ENV_TEMPLATE.md -# Build files +# Build artifacts dist/ +demo/dist/ build/ stats.json +coverage/ # Development configs .editorconfig .eslintrc.js .prettierignore .prettierrc -webpack.dev.js -webpack.common.js tsconfig.json vitest.config.ts -stylePaths.js -webpack.prod.js - -# Source files not needed in package -src/app/Dashboard/ -src/app/NotFound/ -src/app/Settings/ -src/app/Support/ -src/app/app.css -src/app/app.test.tsx -src/app/bgimages/ -src/app/utils/ -src/favicon.png -src/index.tsx -src/typings.d.ts # Tests **/*.test.ts **/*.test.tsx **/*.spec.ts **/*.spec.tsx +**/__snapshots__/ # Git .git/ diff --git a/README.md b/README.md index abb64aa..f7d8d10 100644 --- a/README.md +++ b/README.md @@ -207,10 +207,17 @@ npm run start:dev ## Development +This repository contains two parts: + +- **`src/commenting-system/`** — the npm package (published to npm) +- **`demo/`** — a PatternFly demo app for local testing (not published) + ```bash npm install # Install dependencies -npm run start:dev # Start dev server -npm run build # Production build +npm run start:dev # Start demo dev server (http://localhost:9000) +npm run build # Build demo app to demo/dist +npm run type-check # Type-check the package +npm run type-check:demo # Type-check the demo app ``` ## License diff --git a/src/app/AppLayout/AppLayout.tsx b/demo/src/app/AppLayout/AppLayout.tsx similarity index 99% rename from src/app/AppLayout/AppLayout.tsx rename to demo/src/app/AppLayout/AppLayout.tsx index ab3e883..958861b 100644 --- a/src/app/AppLayout/AppLayout.tsx +++ b/demo/src/app/AppLayout/AppLayout.tsx @@ -19,7 +19,7 @@ import { } from '@patternfly/react-core'; import { IAppRoute, IAppRouteGroup, routes } from '@app/routes'; import { BarsIcon, ExternalLinkAltIcon, GithubIcon } from '@patternfly/react-icons'; -import { CommentPanel, useComments, useGitHubAuth } from '@app/commenting-system'; +import { CommentPanel, useComments, useGitHubAuth } from '@design-comments'; interface IAppLayout { children: React.ReactNode; diff --git a/src/app/Comments/Comments.tsx b/demo/src/app/Comments/Comments.tsx similarity index 99% rename from src/app/Comments/Comments.tsx rename to demo/src/app/Comments/Comments.tsx index 35f6b8d..246c2d3 100644 --- a/src/app/Comments/Comments.tsx +++ b/demo/src/app/Comments/Comments.tsx @@ -12,7 +12,7 @@ import { Title, } from '@patternfly/react-core'; import { AngleDownIcon, AngleRightIcon, SearchIcon } from '@patternfly/react-icons'; -import { useComments } from '@app/commenting-system'; +import { useComments } from '@design-comments'; const Comments: React.FunctionComponent = () => { const navigate = useNavigate(); diff --git a/src/app/Dashboard/Dashboard.tsx b/demo/src/app/Dashboard/Dashboard.tsx similarity index 100% rename from src/app/Dashboard/Dashboard.tsx rename to demo/src/app/Dashboard/Dashboard.tsx diff --git a/src/app/NotFound/NotFound.tsx b/demo/src/app/NotFound/NotFound.tsx similarity index 100% rename from src/app/NotFound/NotFound.tsx rename to demo/src/app/NotFound/NotFound.tsx diff --git a/src/app/Settings/General/GeneralSettings.tsx b/demo/src/app/Settings/General/GeneralSettings.tsx similarity index 100% rename from src/app/Settings/General/GeneralSettings.tsx rename to demo/src/app/Settings/General/GeneralSettings.tsx diff --git a/src/app/Settings/Profile/ProfileSettings.tsx b/demo/src/app/Settings/Profile/ProfileSettings.tsx similarity index 100% rename from src/app/Settings/Profile/ProfileSettings.tsx rename to demo/src/app/Settings/Profile/ProfileSettings.tsx diff --git a/src/app/Support/Support.tsx b/demo/src/app/Support/Support.tsx similarity index 100% rename from src/app/Support/Support.tsx rename to demo/src/app/Support/Support.tsx diff --git a/src/app/__snapshots__/app.test.tsx.snap b/demo/src/app/__snapshots__/app.test.tsx.snap similarity index 100% rename from src/app/__snapshots__/app.test.tsx.snap rename to demo/src/app/__snapshots__/app.test.tsx.snap diff --git a/src/app/app.css b/demo/src/app/app.css similarity index 100% rename from src/app/app.css rename to demo/src/app/app.css diff --git a/src/app/app.test.tsx b/demo/src/app/app.test.tsx similarity index 100% rename from src/app/app.test.tsx rename to demo/src/app/app.test.tsx diff --git a/src/app/bgimages/Patternfly-Logo.svg b/demo/src/app/bgimages/Patternfly-Logo.svg similarity index 100% rename from src/app/bgimages/Patternfly-Logo.svg rename to demo/src/app/bgimages/Patternfly-Logo.svg diff --git a/src/app/index.tsx b/demo/src/app/index.tsx similarity index 81% rename from src/app/index.tsx rename to demo/src/app/index.tsx index e2672f9..c97eee1 100644 --- a/src/app/index.tsx +++ b/demo/src/app/index.tsx @@ -3,8 +3,8 @@ import '@patternfly/react-core/dist/styles/base.css'; import { BrowserRouter as Router } from 'react-router-dom'; import { AppLayout } from '@app/AppLayout/AppLayout'; import { AppRoutes } from '@app/routes'; -import { CommentProvider } from '@app/commenting-system'; -import { GitHubAuthProvider } from '@app/commenting-system'; +import { CommentProvider } from '@design-comments'; +import { GitHubAuthProvider } from '@design-comments'; import '@app/app.css'; const App: React.FunctionComponent = () => ( diff --git a/src/app/routes.tsx b/demo/src/app/routes.tsx similarity index 100% rename from src/app/routes.tsx rename to demo/src/app/routes.tsx diff --git a/src/app/utils/useDocumentTitle.ts b/demo/src/app/utils/useDocumentTitle.ts similarity index 100% rename from src/app/utils/useDocumentTitle.ts rename to demo/src/app/utils/useDocumentTitle.ts diff --git a/src/index.html b/demo/src/index.html similarity index 100% rename from src/index.html rename to demo/src/index.html diff --git a/src/index.tsx b/demo/src/index.tsx similarity index 100% rename from src/index.tsx rename to demo/src/index.tsx diff --git a/src/test/setup.ts b/demo/src/test/setup.ts similarity index 100% rename from src/test/setup.ts rename to demo/src/test/setup.ts diff --git a/src/typings.d.ts b/demo/src/typings.d.ts similarity index 100% rename from src/typings.d.ts rename to demo/src/typings.d.ts diff --git a/demo/stylePaths.js b/demo/stylePaths.js new file mode 100644 index 0000000..21e6b9f --- /dev/null +++ b/demo/stylePaths.js @@ -0,0 +1,17 @@ +const path = require('path'); +const repoRoot = path.resolve(__dirname, '..'); + +module.exports = { + stylePaths: [ + path.resolve(__dirname, 'src'), + path.resolve(repoRoot, 'src/commenting-system'), + path.resolve(repoRoot, 'node_modules/patternfly'), + path.resolve(repoRoot, 'node_modules/@patternfly/patternfly'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-styles/css'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-core/dist/styles/base.css'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-core/dist/esm/@patternfly/patternfly'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-core/node_modules/@patternfly/react-styles/css'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-table/node_modules/@patternfly/react-styles/css'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-inline-edit-extension/node_modules/@patternfly/react-styles/css'), + ], +}; diff --git a/demo/tsconfig.json b/demo/tsconfig.json new file mode 100644 index 0000000..f668d0a --- /dev/null +++ b/demo/tsconfig.json @@ -0,0 +1,30 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "outDir": "dist", + "module": "esnext", + "target": "es5", + "lib": ["es6", "dom"], + "sourceMap": true, + "jsx": "react", + "moduleResolution": "node", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": false, + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "paths": { + "@app/*": ["src/app/*"], + "@design-comments": ["../src/commenting-system"], + "@design-comments/*": ["../src/commenting-system/*"], + "@assets/*": ["../node_modules/@patternfly/react-core/dist/styles/assets/*"] + }, + "importHelpers": true, + "skipLibCheck": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/webpack.common.js b/demo/webpack.common.js similarity index 62% rename from webpack.common.js rename to demo/webpack.common.js index 5a6a0c5..cc7f9fe 100644 --- a/webpack.common.js +++ b/demo/webpack.common.js @@ -3,13 +3,17 @@ const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -const CopyPlugin = require('copy-webpack-plugin'); const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin'); const Dotenv = require('dotenv-webpack'); const BG_IMAGES_DIRNAME = 'bgimages'; const ASSET_PATH = process.env.ASSET_PATH || '/'; +const repoRoot = path.resolve(__dirname, '..'); + module.exports = (env) => { return { + entry: { + main: path.resolve(__dirname, 'src/index.tsx'), + }, module: { rules: [ { @@ -20,6 +24,7 @@ module.exports = (env) => { options: { transpileOnly: true, experimentalWatchApi: true, + configFile: path.resolve(__dirname, 'tsconfig.json'), }, }, ], @@ -27,14 +32,12 @@ module.exports = (env) => { { test: /\.(svg|ttf|eot|woff|woff2)$/, type: 'asset/resource', - // only process modules with this loader - // if they live under a 'fonts' or 'pficon' directory include: [ - path.resolve(__dirname, 'node_modules/patternfly/dist/fonts'), - path.resolve(__dirname, 'node_modules/@patternfly/react-core/dist/styles/assets/fonts'), - path.resolve(__dirname, 'node_modules/@patternfly/react-core/dist/styles/assets/pficon'), - path.resolve(__dirname, 'node_modules/@patternfly/patternfly/assets/fonts'), - path.resolve(__dirname, 'node_modules/@patternfly/patternfly/assets/pficon'), + path.resolve(repoRoot, 'node_modules/patternfly/dist/fonts'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-core/dist/styles/assets/fonts'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-core/dist/styles/assets/pficon'), + path.resolve(repoRoot, 'node_modules/@patternfly/patternfly/assets/fonts'), + path.resolve(repoRoot, 'node_modules/@patternfly/patternfly/assets/pficon'), ], }, { @@ -53,15 +56,11 @@ module.exports = (env) => { }, { test: /\.svg$/, - // only process SVG modules with this loader if they live under a 'bgimages' directory - // this is primarily useful when applying a CSS background using an SVG include: (input) => input.indexOf(BG_IMAGES_DIRNAME) > -1, type: 'asset/inline', }, { test: /\.svg$/, - // only process SVG modules with this loader when they don't live under a 'bgimages', - // 'fonts', or 'pficon' directory, those are handled with other loaders include: (input) => input.indexOf(BG_IMAGES_DIRNAME) === -1 && input.indexOf('fonts') === -1 && @@ -76,20 +75,21 @@ module.exports = (env) => { test: /\.(jpg|jpeg|png|gif)$/i, include: [ path.resolve(__dirname, 'src'), - path.resolve(__dirname, 'node_modules/patternfly'), - path.resolve(__dirname, 'node_modules/@patternfly/patternfly/assets/images'), - path.resolve(__dirname, 'node_modules/@patternfly/react-styles/css/assets/images'), - path.resolve(__dirname, 'node_modules/@patternfly/react-core/dist/styles/assets/images'), + path.resolve(repoRoot, 'src/commenting-system'), + path.resolve(repoRoot, 'node_modules/patternfly'), + path.resolve(repoRoot, 'node_modules/@patternfly/patternfly/assets/images'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-styles/css/assets/images'), + path.resolve(repoRoot, 'node_modules/@patternfly/react-core/dist/styles/assets/images'), path.resolve( - __dirname, + repoRoot, 'node_modules/@patternfly/react-core/node_modules/@patternfly/react-styles/css/assets/images' ), path.resolve( - __dirname, + repoRoot, 'node_modules/@patternfly/react-table/node_modules/@patternfly/react-styles/css/assets/images' ), path.resolve( - __dirname, + repoRoot, 'node_modules/@patternfly/react-inline-edit-extension/node_modules/@patternfly/react-styles/css/assets/images' ), ], @@ -113,18 +113,13 @@ module.exports = (env) => { }, plugins: [ new HtmlWebpackPlugin({ - template: path.resolve(__dirname, 'src', 'index.html'), + template: path.resolve(__dirname, 'src/index.html'), }), new Dotenv({ - // IMPORTANT: do not inline system env vars into the browser bundle. - // Keep `.env` for public/client-side config only (e.g. VITE_GITHUB_CLIENT_ID). - // Server-side secrets should be provided via server runtime env (functions) instead. + path: path.resolve(repoRoot, '.env'), systemvars: false, silent: true, }), - new CopyPlugin({ - patterns: [{ from: './src/favicon.png', to: 'images' }], - }), new webpack.DefinePlugin({ 'process.env.SUMMARIZE_API_URL': JSON.stringify(process.env.SUMMARIZE_API_URL || ''), }), @@ -133,7 +128,7 @@ module.exports = (env) => { extensions: ['.js', '.ts', '.tsx', '.jsx'], plugins: [ new TsconfigPathsPlugin({ - configFile: path.resolve(__dirname, './tsconfig.json'), + configFile: path.resolve(__dirname, 'tsconfig.json'), }), ], symlinks: false, diff --git a/webpack.dev.js b/demo/webpack.dev.js similarity index 98% rename from webpack.dev.js rename to demo/webpack.dev.js index 4f6f699..1858636 100644 --- a/webpack.dev.js +++ b/demo/webpack.dev.js @@ -6,6 +6,7 @@ const common = require('./webpack.common.js'); const { stylePaths } = require('./stylePaths'); const HOST = process.env.HOST || 'localhost'; const PORT = process.env.PORT || '9000'; +const repoRoot = path.resolve(__dirname, '..'); module.exports = merge(common('development'), { mode: 'development', @@ -32,9 +33,9 @@ module.exports = merge(common('development'), { try { // eslint-disable-next-line global-require const dotenv = require('dotenv'); - const envResult = dotenv.config({ path: path.resolve(__dirname, '.env') }); + const envResult = dotenv.config({ path: path.resolve(repoRoot, '.env') }); // IMPORTANT: allow server-only secrets to override anything accidentally present in `.env` or the shell env. - const envServerResult = dotenv.config({ path: path.resolve(__dirname, '.env.server'), override: true }); + const envServerResult = dotenv.config({ path: path.resolve(repoRoot, '.env.server'), override: true }); if (envServerResult.error && envServerResult.error.code !== 'ENOENT') { // eslint-disable-next-line no-console console.warn('[Commenting System] Warning loading .env.server:', envServerResult.error.message); diff --git a/webpack.prod.js b/demo/webpack.prod.js similarity index 100% rename from webpack.prod.js rename to demo/webpack.prod.js diff --git a/package-lock.json b/package-lock.json index 7c0a1a2..8df9305 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { - "name": "design-comments", - "version": "3.8.0", + "name": "@patternfly/design-comments", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "design-comments", - "version": "3.8.0", + "name": "@patternfly/design-comments", + "version": "1.0.0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 108649b..287c9bf 100644 --- a/package.json +++ b/package.json @@ -1,20 +1,19 @@ { - "name": "design-comments", - "version": "3.8.0", + "name": "@patternfly/design-comments", + "version": "1.0.0", "description": "A commenting system for PatternFly React applications that allows designers and developers to add comments directly on design pages, sync with GitHub Issues, and link Jira tickets.", - "homepage": "https://www.npmjs.com/package/design-comments", "repository": { "type": "git", - "url": "https://github.com/JustinXHale/design-comments.git" + "url": "https://github.com/patternfly/design-comments.git" }, "license": "MIT", - "main": "src/app/commenting-system/index.ts", - "types": "src/app/commenting-system/index.ts", + "main": "src/commenting-system/index.ts", + "types": "src/commenting-system/index.ts", "bin": { "design-comments": "scripts/cli.js" }, "files": [ - "src/app/commenting-system/", + "src/commenting-system/", "scripts/", "README.md", "LICENSE", @@ -23,21 +22,22 @@ "scripts": { "postinstall": "node scripts/postinstall.js || true", "preuninstall": "node scripts/auto-remove.js || true", - "prebuild": "npm run type-check && npm run clean", - "build": "webpack --config webpack.prod.js", - "start": "sirv dist --cors --single --host --port 8080", - "start:dev": "webpack serve --color --progress --config webpack.dev.js", + "prebuild": "npm run type-check && npm run type-check:demo && npm run clean", + "build": "webpack --config demo/webpack.prod.js", + "start": "sirv demo/dist --cors --single --host --port 8080", + "start:dev": "webpack serve --color --progress --config demo/webpack.dev.js", "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", - "eslint": "eslint --ext .tsx,.js ./src/", + "eslint": "eslint --ext .tsx,.ts ./src/ ./demo/", "lint": "npm run eslint", - "format": "prettier --check --write ./src/**/*.{tsx,ts}", + "format": "prettier --check --write ./src/**/*.{tsx,ts} ./demo/**/*.{tsx,ts}", "type-check": "tsc --noEmit", - "ci-checks": "npm run type-check && npm run lint && npm run test:coverage", - "build:bundle-profile": "webpack --config webpack.prod.js --profile --json > stats.json", + "type-check:demo": "tsc --noEmit -p demo/tsconfig.json", + "ci-checks": "npm run type-check && npm run type-check:demo && npm run lint && npm run test:coverage", + "build:bundle-profile": "webpack --config demo/webpack.prod.js --profile --json > stats.json", "bundle-profile:analyze": "npm run build:bundle-profile && webpack-bundle-analyzer ./stats.json", - "clean": "rimraf dist" + "clean": "rimraf demo/dist" }, "devDependencies": { "@testing-library/jest-dom": "^6.6.3", diff --git a/src/app/commenting-system/components/CommentOverlay.tsx b/src/commenting-system/components/CommentOverlay.tsx similarity index 100% rename from src/app/commenting-system/components/CommentOverlay.tsx rename to src/commenting-system/components/CommentOverlay.tsx diff --git a/src/app/commenting-system/components/CommentPanel.tsx b/src/commenting-system/components/CommentPanel.tsx similarity index 100% rename from src/app/commenting-system/components/CommentPanel.tsx rename to src/commenting-system/components/CommentPanel.tsx diff --git a/src/app/commenting-system/components/CommentPin.tsx b/src/commenting-system/components/CommentPin.tsx similarity index 100% rename from src/app/commenting-system/components/CommentPin.tsx rename to src/commenting-system/components/CommentPin.tsx diff --git a/src/app/commenting-system/components/DetailsTab.tsx b/src/commenting-system/components/DetailsTab.tsx similarity index 100% rename from src/app/commenting-system/components/DetailsTab.tsx rename to src/commenting-system/components/DetailsTab.tsx diff --git a/src/app/commenting-system/components/FloatingWidget.tsx b/src/commenting-system/components/FloatingWidget.tsx similarity index 100% rename from src/app/commenting-system/components/FloatingWidget.tsx rename to src/commenting-system/components/FloatingWidget.tsx diff --git a/src/app/commenting-system/components/GitHubIssuesTab.tsx b/src/commenting-system/components/GitHubIssuesTab.tsx similarity index 100% rename from src/app/commenting-system/components/GitHubIssuesTab.tsx rename to src/commenting-system/components/GitHubIssuesTab.tsx diff --git a/src/app/commenting-system/components/IssuesTicketsTab.tsx b/src/commenting-system/components/IssuesTicketsTab.tsx similarity index 100% rename from src/app/commenting-system/components/IssuesTicketsTab.tsx rename to src/commenting-system/components/IssuesTicketsTab.tsx diff --git a/src/app/commenting-system/components/JiraTab.tsx b/src/commenting-system/components/JiraTab.tsx similarity index 100% rename from src/app/commenting-system/components/JiraTab.tsx rename to src/commenting-system/components/JiraTab.tsx diff --git a/src/app/commenting-system/contexts/CommentContext.tsx b/src/commenting-system/contexts/CommentContext.tsx similarity index 100% rename from src/app/commenting-system/contexts/CommentContext.tsx rename to src/commenting-system/contexts/CommentContext.tsx diff --git a/src/app/commenting-system/contexts/GitHubAuthContext.tsx b/src/commenting-system/contexts/GitHubAuthContext.tsx similarity index 100% rename from src/app/commenting-system/contexts/GitHubAuthContext.tsx rename to src/commenting-system/contexts/GitHubAuthContext.tsx diff --git a/src/app/commenting-system/index.ts b/src/commenting-system/index.ts similarity index 100% rename from src/app/commenting-system/index.ts rename to src/commenting-system/index.ts diff --git a/src/app/commenting-system/services/githubAdapter.ts b/src/commenting-system/services/githubAdapter.ts similarity index 100% rename from src/app/commenting-system/services/githubAdapter.ts rename to src/commenting-system/services/githubAdapter.ts diff --git a/src/app/commenting-system/services/summarizeService.test.ts b/src/commenting-system/services/summarizeService.test.ts similarity index 100% rename from src/app/commenting-system/services/summarizeService.test.ts rename to src/commenting-system/services/summarizeService.test.ts diff --git a/src/app/commenting-system/services/summarizeService.ts b/src/commenting-system/services/summarizeService.ts similarity index 100% rename from src/app/commenting-system/services/summarizeService.ts rename to src/commenting-system/services/summarizeService.ts diff --git a/src/app/commenting-system/types/index.ts b/src/commenting-system/types/index.ts similarity index 100% rename from src/app/commenting-system/types/index.ts rename to src/commenting-system/types/index.ts diff --git a/src/app/commenting-system/utils/componentUtils.ts b/src/commenting-system/utils/componentUtils.ts similarity index 100% rename from src/app/commenting-system/utils/componentUtils.ts rename to src/commenting-system/utils/componentUtils.ts diff --git a/src/app/commenting-system/utils/env.ts b/src/commenting-system/utils/env.ts similarity index 100% rename from src/app/commenting-system/utils/env.ts rename to src/commenting-system/utils/env.ts diff --git a/src/app/commenting-system/utils/issueLinkRouteUtils.ts b/src/commenting-system/utils/issueLinkRouteUtils.ts similarity index 100% rename from src/app/commenting-system/utils/issueLinkRouteUtils.ts rename to src/commenting-system/utils/issueLinkRouteUtils.ts diff --git a/src/app/commenting-system/utils/selectorUtils.ts b/src/commenting-system/utils/selectorUtils.ts similarity index 100% rename from src/app/commenting-system/utils/selectorUtils.ts rename to src/commenting-system/utils/selectorUtils.ts diff --git a/src/app/commenting-system/utils/version.ts b/src/commenting-system/utils/version.ts similarity index 100% rename from src/app/commenting-system/utils/version.ts rename to src/commenting-system/utils/version.ts diff --git a/stylePaths.js b/stylePaths.js deleted file mode 100644 index 2ca7405..0000000 --- a/stylePaths.js +++ /dev/null @@ -1,14 +0,0 @@ -const path = require('path'); -module.exports = { - stylePaths: [ - path.resolve(__dirname, 'src'), - path.resolve(__dirname, 'node_modules/patternfly'), - path.resolve(__dirname, 'node_modules/@patternfly/patternfly'), - path.resolve(__dirname, 'node_modules/@patternfly/react-styles/css'), - path.resolve(__dirname, 'node_modules/@patternfly/react-core/dist/styles/base.css'), - path.resolve(__dirname, 'node_modules/@patternfly/react-core/dist/esm/@patternfly/patternfly'), - path.resolve(__dirname, 'node_modules/@patternfly/react-core/node_modules/@patternfly/react-styles/css'), - path.resolve(__dirname, 'node_modules/@patternfly/react-table/node_modules/@patternfly/react-styles/css'), - path.resolve(__dirname, 'node_modules/@patternfly/react-inline-edit-extension/node_modules/@patternfly/react-styles/css') - ] -} diff --git a/tsconfig.json b/tsconfig.json index 6baa558..23f0977 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "baseUrl": ".", - "rootDir": ".", + "rootDir": "src", "outDir": "dist", "module": "esnext", "target": "es5", @@ -18,17 +18,11 @@ "allowSyntheticDefaultImports": true, "strict": true, "paths": { - "@app/*": ["src/app/*"], - "@assets/*": ["node_modules/@patternfly/react-core/dist/styles/assets/*"] + "@design-comments/*": ["src/commenting-system/*"] }, "importHelpers": true, "skipLibCheck": true }, - "include": [ - "**/*.ts", - "**/*.tsx", - "**/*.jsx", - "**/*.js" - ], - "exclude": ["node_modules", "scripts/AppLayout.template.tsx"] + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "demo"] } diff --git a/vitest.config.ts b/vitest.config.ts index cce22ea..1f828b3 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -7,13 +7,15 @@ export default defineConfig({ plugins: [react()], test: { environment: 'jsdom', - setupFiles: ['./src/test/setup.ts'], + setupFiles: ['./demo/src/test/setup.ts'], globals: true, css: true, + include: ['src/**/*.test.{ts,tsx}', 'demo/**/*.test.{ts,tsx}'], }, resolve: { alias: { - '@app': path.resolve(__dirname, './src/app'), + '@app': path.resolve(__dirname, './demo/src/app'), + '@design-comments': path.resolve(__dirname, './src/commenting-system'), }, }, }); From fce137453d9507094bba719ebaeaaeca8ab52f99 Mon Sep 17 00:00:00 2001 From: Donald Labaj Date: Tue, 9 Jun 2026 13:58:40 -0400 Subject: [PATCH 2/2] fix: Replace 'any' types with proper TypeScript types - Replace all 'any' types with 'unknown' or specific interfaces - Add GitHubIssue, GitHubComment, and ReactFiber interfaces - Add ReactComponentType interface for React internals - Fix linting issues: import sorting, unused variables - Remove unused parameters in test mocks - Add proper type narrowing for GitHub API responses - All CI checks now passing (type-check, lint, tests) Co-Authored-By: Claude Sonnet 4.5 --- demo/src/test/setup.ts | 6 +- .../components/CommentOverlay.tsx | 6 +- .../contexts/CommentContext.tsx | 14 +-- .../services/githubAdapter.ts | 118 ++++++++++-------- .../services/summarizeService.test.ts | 2 +- src/commenting-system/utils/componentUtils.ts | 71 +++++++---- src/commenting-system/utils/env.ts | 2 +- src/commenting-system/utils/selectorUtils.ts | 2 +- 8 files changed, 132 insertions(+), 89 deletions(-) diff --git a/demo/src/test/setup.ts b/demo/src/test/setup.ts index 40b23ac..ce3c451 100644 --- a/demo/src/test/setup.ts +++ b/demo/src/test/setup.ts @@ -21,7 +21,7 @@ global.ResizeObserver = class ResizeObserver { observe = vi.fn(); unobserve = vi.fn(); disconnect = vi.fn(); - constructor(callback: ResizeObserverCallback) {} + constructor() {} }; // Mock IntersectionObserver @@ -29,5 +29,5 @@ global.IntersectionObserver = class IntersectionObserver { observe = vi.fn(); unobserve = vi.fn(); disconnect = vi.fn(); - constructor(callback: IntersectionObserverCallback, options?: IntersectionObserverInit) {} -} as any; + constructor() {} +} as unknown as typeof IntersectionObserver; diff --git a/src/commenting-system/components/CommentOverlay.tsx b/src/commenting-system/components/CommentOverlay.tsx index 5c94ec7..ffec520 100644 --- a/src/commenting-system/components/CommentOverlay.tsx +++ b/src/commenting-system/components/CommentOverlay.tsx @@ -158,8 +158,10 @@ export const CommentOverlay: React.FunctionComponent = () => { // Only use component name if this element IS a React component (not native) if (type && typeof type !== 'string') { const componentName = getComponentName(fiber); - const displayName = (typeof type === 'function' && (type.displayName || type.name)) || - (type?.$$typeof === Symbol.for('react.forward_ref') && (type.render?.displayName || type.render?.name)) || + const componentTypeObj = type as { $$typeof?: symbol; render?: { displayName?: string; name?: string } }; + const fn = type as { displayName?: string; name?: string }; + const displayName = (typeof type === 'function' && (fn.displayName || fn.name)) || + (componentTypeObj?.$$typeof === Symbol.for('react.forward_ref') && (componentTypeObj.render?.displayName || componentTypeObj.render?.name)) || undefined; previewName = componentName || displayName || elementDescription; } diff --git a/src/commenting-system/contexts/CommentContext.tsx b/src/commenting-system/contexts/CommentContext.tsx index 3e212dc..34bd65f 100644 --- a/src/commenting-system/contexts/CommentContext.tsx +++ b/src/commenting-system/contexts/CommentContext.tsx @@ -442,18 +442,12 @@ export const CommentProvider: React.FunctionComponent<{ children: React.ReactNod const issueUrl = issue?.html_url as string | undefined; if (!issueNumber) continue; - const metadata = parseMetadataFromIssueBody(issue?.body || ''); + const metadata = parseMetadataFromIssueBody((issue?.body as string) || ''); const commentsResult = await githubAdapter.fetchIssueComments(issueNumber); const ghComments = commentsResult.success && commentsResult.data ? commentsResult.data : []; - const mappedComments: Comment[] = (Array.isArray(ghComments) ? ghComments : []).map( - (c: { - id: number; - body?: string; - user?: { login?: string }; - created_at?: string; - }) => { + const mappedComments: Comment[] = (Array.isArray(ghComments) ? ghComments : []).map((c) => { const rawBody = c?.body || ''; return { id: `ghc-${c.id}`, @@ -469,8 +463,8 @@ export const CommentProvider: React.FunctionComponent<{ children: React.ReactNod for (const c of mappedComments) { if (c.parentGitHubCommentId) continue; const raw = (Array.isArray(ghComments) ? ghComments : []).find( - (x: { id?: number; body?: string }) => x?.id === c.githubCommentId, - )?.body || ''; + (x) => x?.id === c.githubCommentId, + )?.body as string || ''; const inferred = inferReplyParentFromQuote(raw, mappedComments); if (inferred && inferred !== c.githubCommentId) { c.parentGitHubCommentId = inferred; diff --git a/src/commenting-system/services/githubAdapter.ts b/src/commenting-system/services/githubAdapter.ts index 1b42240..14c9642 100644 --- a/src/commenting-system/services/githubAdapter.ts +++ b/src/commenting-system/services/githubAdapter.ts @@ -65,7 +65,27 @@ export const diagnoseGitHubSetup = () => { }; }; -export interface GitHubResult { +interface GitHubApiResponse { + [key: string]: unknown; +} + +export interface GitHubIssue extends GitHubApiResponse { + number: number; + title?: string; + state?: string; + html_url?: string; + body?: string; + labels?: unknown[]; +} + +export interface GitHubComment extends GitHubApiResponse { + id: number; + body?: string; + user?: { login?: string }; + created_at?: string; +} + +export interface GitHubResult { success: boolean; data?: T; error?: string; @@ -81,7 +101,7 @@ export interface GitHubIssueSummary { labels: unknown[]; } -async function githubProxyRequest(method: string, endpoint: string, data?: any): Promise { +async function githubProxyRequest(method: string, endpoint: string, data?: unknown): Promise { const token = getStoredToken(); if (!token) { throw new Error('Not authenticated with GitHub'); @@ -141,18 +161,18 @@ const base64DecodeUtf8 = (input: string): string => { return decodeURIComponent(escape(atob(input))); }; -const getLabelNames = (issue: any): string[] => { +const getLabelNames = (issue: GitHubApiResponse): string[] => { const labels = issue?.labels; if (!Array.isArray(labels)) return []; return labels - .map((l: any) => (typeof l === 'string' ? l : l?.name)) - .filter((n: any) => typeof n === 'string'); + .map((l: unknown) => (typeof l === 'string' ? l : (l as Record)?.name)) + .filter((n: unknown): n is string => typeof n === 'string'); }; -const issueHasAnyVersion = (issue: any): boolean => { +const issueHasAnyVersion = (issue: GitHubApiResponse): boolean => { const labelNames = getLabelNames(issue); if (labelNames.some((n) => n.startsWith('version:'))) return true; - const body: string = issue?.body || ''; + const body: string = (issue?.body as string) || ''; return body.includes('Version:'); }; @@ -206,13 +226,13 @@ export const githubAdapter = { // ignore label failures } - return { success: true, data }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to create issue' }; + return { success: true, data: data as { number: number; html_url: string } }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to create issue' }; } }, - async createComment(issueNumber: number, body: string): Promise { + async createComment(issueNumber: number, body: string): Promise> { if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' }; const owner = getEnv('VITE_GITHUB_OWNER'); const repo = getEnv('VITE_GITHUB_REPO'); @@ -220,12 +240,12 @@ export const githubAdapter = { try { const data = await githubProxyRequest('POST', `/repos/${owner}/${repo}/issues/${issueNumber}/comments`, { body }); return { success: true, data }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to create comment' }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to create comment' }; } }, - async fetchIssuesForRoute(route: string): Promise> { + async fetchIssuesForRoute(route: string): Promise> { return githubAdapter.fetchIssuesForRouteAndVersion(route); }, @@ -246,12 +266,12 @@ export const githubAdapter = { labels: Array.isArray(data.labels) ? data.labels : [], }, }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to fetch issue' }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to fetch issue' }; } }, - async fetchIssuesForRouteAndVersion(route: string, version?: string): Promise> { + async fetchIssuesForRouteAndVersion(route: string, version?: string): Promise> { if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' }; const owner = getEnv('VITE_GITHUB_OWNER'); const repo = getEnv('VITE_GITHUB_REPO'); @@ -262,18 +282,18 @@ export const githubAdapter = { ); // Filter by metadata OR labels (route:${route}), and optionally by version const filtered = (Array.isArray(data) ? data : []) - .filter((issue: any) => { - const body: string = issue?.body || ''; + .filter((issue: GitHubApiResponse) => { + const body: string = (issue?.body as string) || ''; const labels = getLabelNames(issue); const bodyMatch = body.includes(`Route: \`${route}\``); const labelMatch = labels.includes(`route:${route}`); return bodyMatch || labelMatch; }) - .filter((issue: any) => { + .filter((issue: GitHubApiResponse) => { if (!version) return true; const labels = getLabelNames(issue); - const body: string = issue?.body || ''; + const body: string = (issue?.body as string) || ''; const versionLabelMatch = labels.includes(`version:${version}`); const bodyVersionMatch = body.includes(`Version: \`${version}\``); @@ -282,13 +302,13 @@ export const githubAdapter = { return versionLabelMatch || bodyVersionMatch; }); - return { success: true, data: filtered }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to fetch issues' }; + return { success: true, data: filtered as GitHubIssue[] }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to fetch issues' }; } }, - async fetchIssueComments(issueNumber: number): Promise> { + async fetchIssueComments(issueNumber: number): Promise> { if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' }; const owner = getEnv('VITE_GITHUB_OWNER'); const repo = getEnv('VITE_GITHUB_REPO'); @@ -297,57 +317,57 @@ export const githubAdapter = { 'GET', `/repos/${owner}/${repo}/issues/${issueNumber}/comments?per_page=100`, ); - return { success: true, data }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to fetch issue comments' }; + return { success: true, data: data as unknown as GitHubComment[] }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to fetch issue comments' }; } }, - async updateComment(commentId: number, body: string): Promise { + async updateComment(commentId: number, body: string): Promise> { if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' }; const owner = getEnv('VITE_GITHUB_OWNER'); const repo = getEnv('VITE_GITHUB_REPO'); try { const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/comments/${commentId}`, { body }); return { success: true, data }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to update comment' }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to update comment' }; } }, - async deleteComment(commentId: number): Promise { + async deleteComment(commentId: number): Promise> { if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' }; const owner = getEnv('VITE_GITHUB_OWNER'); const repo = getEnv('VITE_GITHUB_REPO'); try { await githubProxyRequest('DELETE', `/repos/${owner}/${repo}/issues/comments/${commentId}`); return { success: true, data: {} }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to delete comment' }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to delete comment' }; } }, - async closeIssue(issueNumber: number): Promise { + async closeIssue(issueNumber: number): Promise> { if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' }; const owner = getEnv('VITE_GITHUB_OWNER'); const repo = getEnv('VITE_GITHUB_REPO'); try { const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/${issueNumber}`, { state: 'closed' }); return { success: true, data }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to close issue' }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to close issue' }; } }, - async reopenIssue(issueNumber: number): Promise { + async reopenIssue(issueNumber: number): Promise> { if (!isGitHubConfigured()) return { success: false, error: 'Please sign in with GitHub' }; const owner = getEnv('VITE_GITHUB_OWNER'); const repo = getEnv('VITE_GITHUB_REPO'); try { const data = await githubProxyRequest('PATCH', `/repos/${owner}/${repo}/issues/${issueNumber}`, { state: 'open' }); return { success: true, data }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to reopen issue' }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to reopen issue' }; } }, @@ -357,17 +377,17 @@ export const githubAdapter = { const repo = getEnv('VITE_GITHUB_REPO'); try { const data = await githubProxyRequest('GET', `/repos/${owner}/${repo}/contents/${encodePath(path)}`); - const content = typeof data?.content === 'string' ? data.content.replace(/\n/g, '') : ''; - const sha = data?.sha as string | undefined; + const content = typeof data.content === 'string' ? data.content.replace(/\n/g, '') : ''; + const sha = data.sha as string | undefined; if (!content || !sha) return { success: true, data: null }; const text = base64DecodeUtf8(content); return { success: true, data: { text, sha } }; - } catch (e: any) { + } catch (e: unknown) { // If file doesn't exist yet, treat as empty - if (String(e?.message || '').toLowerCase().includes('not found')) { + if (String((e as Error)?.message || '').toLowerCase().includes('not found')) { return { success: true, data: null }; } - return { success: false, error: e?.message || 'Failed to read repo file' }; + return { success: false, error: (e as Error)?.message || 'Failed to read repo file' }; } }, @@ -381,7 +401,7 @@ export const githubAdapter = { const owner = getEnv('VITE_GITHUB_OWNER'); const repo = getEnv('VITE_GITHUB_REPO'); try { - const payload: any = { + const payload: Record = { message: params.message, content: base64EncodeUtf8(params.text), }; @@ -391,10 +411,10 @@ export const githubAdapter = { `/repos/${owner}/${repo}/contents/${encodePath(params.path)}`, payload, ); - const newSha = data?.content?.sha as string | undefined; + const newSha = ((data as { content?: { sha?: string } }).content?.sha) as string | undefined; return { success: true, data: { sha: newSha || params.sha || '' } }; - } catch (e: any) { - return { success: false, error: e?.message || 'Failed to write repo file' }; + } catch (e: unknown) { + return { success: false, error: (e as Error)?.message || 'Failed to write repo file' }; } }, }; diff --git a/src/commenting-system/services/summarizeService.test.ts b/src/commenting-system/services/summarizeService.test.ts index 8cb2040..a88e8f3 100644 --- a/src/commenting-system/services/summarizeService.test.ts +++ b/src/commenting-system/services/summarizeService.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi, afterEach } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; import { buildPromptForThread, buildPromptForThreads, diff --git a/src/commenting-system/utils/componentUtils.ts b/src/commenting-system/utils/componentUtils.ts index e6afeb4..215177b 100644 --- a/src/commenting-system/utils/componentUtils.ts +++ b/src/commenting-system/utils/componentUtils.ts @@ -5,17 +5,25 @@ import { ComponentMetadata } from '../types'; +interface ReactFiber { + type?: unknown; + memoizedProps?: unknown; + pendingProps?: unknown; + key?: string | number | null; + [key: string]: unknown; +} + /** * Get React fiber node from a DOM element * Uses React DevTools internal API if available, otherwise traverses up the DOM tree */ -export function getFiberFromElement(element: Element | null): any { +export function getFiberFromElement(element: Element | null): ReactFiber | null { if (!element) return null; // Try React DevTools internal API first (if DevTools is installed) const key = Object.keys(element).find((k) => k.startsWith('__reactFiber') || k.startsWith('__reactInternalInstance')); if (key) { - return (element as any)[key]; + return (element as unknown as Record)[key]; } // Fallback: traverse up the DOM tree to find a React fiber @@ -24,7 +32,7 @@ export function getFiberFromElement(element: Element | null): any { const keys = Object.keys(current); const fiberKey = keys.find((k) => k.startsWith('__reactFiber') || k.startsWith('__reactInternalInstance')); if (fiberKey) { - return (current as any)[fiberKey]; + return (current as unknown as Record)[fiberKey]; } current = current.parentNode; } @@ -32,10 +40,18 @@ export function getFiberFromElement(element: Element | null): any { return null; } +interface ReactComponentType { + $$typeof?: symbol; + displayName?: string; + name?: string; + render?: { displayName?: string; name?: string }; + type?: unknown; +} + /** * Get component name from a React fiber node */ -export function getComponentName(fiber: any): string | undefined { +export function getComponentName(fiber: ReactFiber | null): string | undefined { if (!fiber) return undefined; // Try different fiber types @@ -44,19 +60,22 @@ export function getComponentName(fiber: any): string | undefined { // Function component if (typeof type === 'function') { - return type.displayName || type.name || 'Anonymous'; + const fn = type as { displayName?: string; name?: string }; + return fn.displayName || fn.name || 'Anonymous'; } // Forward ref - if (type.$$typeof === Symbol.for('react.forward_ref')) { - return type.render?.displayName || type.render?.name || 'ForwardRef'; + const componentType = type as ReactComponentType; + if (componentType.$$typeof === Symbol.for('react.forward_ref')) { + return componentType.render?.displayName || componentType.render?.name || 'ForwardRef'; } // Memo - if (type.$$typeof === Symbol.for('react.memo')) { - const innerType = type.type; + if (componentType.$$typeof === Symbol.for('react.memo')) { + const innerType = componentType.type; if (typeof innerType === 'function') { - return innerType.displayName || innerType.name || 'Memo'; + const fn = innerType as { displayName?: string; name?: string }; + return fn.displayName || fn.name || 'Memo'; } return 'Memo'; } @@ -72,7 +91,7 @@ export function getComponentName(fiber: any): string | undefined { /** * Get component type (function, class, etc.) */ -function getComponentType(fiber: any): ComponentMetadata['componentType'] { +function getComponentType(fiber: ReactFiber | null): ComponentMetadata['componentType'] { if (!fiber) return 'unknown'; const type = fiber.type; @@ -80,21 +99,23 @@ function getComponentType(fiber: any): ComponentMetadata['componentType'] { if (typeof type === 'function') { // Check if it's a class component - if (type.prototype && type.prototype.isReactComponent) { + const fn = type as { prototype?: { isReactComponent?: boolean } }; + if (fn.prototype && fn.prototype.isReactComponent) { return 'class'; } return 'function'; } - if (type.$$typeof === Symbol.for('react.forward_ref')) { + const componentType = type as ReactComponentType; + if (componentType.$$typeof === Symbol.for('react.forward_ref')) { return 'forwardRef'; } - if (type.$$typeof === Symbol.for('react.memo')) { + if (componentType.$$typeof === Symbol.for('react.memo')) { return 'memo'; } - if (type.$$typeof === Symbol.for('react.lazy')) { + if (componentType.$$typeof === Symbol.for('react.lazy')) { return 'lazy'; } @@ -122,19 +143,21 @@ export function getComponentMetadata(element: Element | null): ComponentMetadata const props = fiber.memoizedProps || fiber.pendingProps || undefined; // Get key - const key = fiber.key !== null && fiber.key !== undefined ? fiber.key : undefined; + const key = fiber.key !== null && fiber.key !== undefined ? (fiber.key as string | number) : undefined; // Get display name const type = fiber.type; + const componentTypeObj = type as ReactComponentType; + const fn = type as { displayName?: string; name?: string }; const displayName = - (typeof type === 'function' && (type.displayName || type.name)) || - (type?.$$typeof === Symbol.for('react.forward_ref') && (type.render?.displayName || type.render?.name)) || + (typeof type === 'function' && (fn.displayName || fn.name)) || + (componentTypeObj?.$$typeof === Symbol.for('react.forward_ref') && (componentTypeObj.render?.displayName || componentTypeObj.render?.name)) || undefined; return { componentName, componentType, - props: props ? sanitizeProps(props) : undefined, + props: props ? sanitizeProps(props as Record) : undefined, displayName, key, }; @@ -166,10 +189,14 @@ function sanitizeProps(props: Record): Record if (value instanceof Map) return `[Map(${value.size})]`; // React elements - if ((value as any).$$typeof) { - const type = (value as any).type; + const reactEl = value as ReactComponentType; + if (reactEl.$$typeof) { + const type = reactEl.type; if (typeof type === 'string') return `<${type} />`; - if (typeof type === 'function') return `<${type.displayName || type.name || 'Component'} />`; + if (typeof type === 'function') { + const fn = type as { displayName?: string; name?: string }; + return `<${fn.displayName || fn.name || 'Component'} />`; + } return '[React Element]'; } diff --git a/src/commenting-system/utils/env.ts b/src/commenting-system/utils/env.ts index 7cc2c9b..22d099d 100644 --- a/src/commenting-system/utils/env.ts +++ b/src/commenting-system/utils/env.ts @@ -8,7 +8,7 @@ export const getEnv = (key: string): string | undefined => { if (typeof process !== 'undefined' && process.env) { return process.env[key]; } - } catch (e) { + } catch { // process might be defined but accessing it throws an error } return undefined; diff --git a/src/commenting-system/utils/selectorUtils.ts b/src/commenting-system/utils/selectorUtils.ts index 3337bdf..6d1e419 100644 --- a/src/commenting-system/utils/selectorUtils.ts +++ b/src/commenting-system/utils/selectorUtils.ts @@ -3,7 +3,7 @@ * Now includes React component detection for component-based commenting */ -import { getComponentMetadata, getComponentPath, findNearestComponentElement } from './componentUtils'; +import { findNearestComponentElement, getComponentMetadata, getComponentPath } from './componentUtils'; import { ComponentMetadata } from '../types'; /**