diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index f3af2557..00000000 --- a/.eslintignore +++ /dev/null @@ -1,8 +0,0 @@ -node_modules -dist -coverage -*.log -**/*.js -sdks/typescript/client/src/remote-dom/iframe-bundle.ts - -examples \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 9a4ebbef..00000000 --- a/.eslintrc.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "root": true, - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint", "react"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:react/recommended", - "plugin:react/jsx-runtime", - "prettier" - ], - "settings": { - "react": { - "version": "detect" - } - }, - "env": { - "node": true, - "browser": true, - "es2021": true, - "jest": true - }, - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module", - "ecmaFeatures": { - "jsx": true - } - }, - "rules": { - "react/prop-types": "off" - } -} diff --git a/docs/src/.vitepress/config.ts b/docs/src/.vitepress/config.ts index eabee191..d653dddf 100644 --- a/docs/src/.vitepress/config.ts +++ b/docs/src/.vitepress/config.ts @@ -319,7 +319,7 @@ export default withMermaid( dark: 'github-dark', }, lineNumbers: true, - config: (md) => { + config: (_md) => { // Add any markdown-it plugins here }, }, diff --git a/docs/src/.vitepress/theme/index.ts b/docs/src/.vitepress/theme/index.ts index 09015433..cd90e6c3 100644 --- a/docs/src/.vitepress/theme/index.ts +++ b/docs/src/.vitepress/theme/index.ts @@ -15,7 +15,7 @@ export default { ]) }) }, - enhanceApp({ app, router, siteData }) { + enhanceApp({ app: _app, router: _router, siteData: _siteData }) { // Custom app enhancements can go here }, } satisfies Theme; diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 00000000..b3f9d0b8 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,191 @@ +const tseslint = require('@typescript-eslint/eslint-plugin'); +const tsparser = require('@typescript-eslint/parser'); +const react = require('eslint-plugin-react'); +const prettierConfig = require('eslint-config-prettier'); + +module.exports = [ + // Global ignores + { + ignores: [ + '**/node_modules/**', + '**/dist/**', + '**/coverage/**', + '**/*.log', + '**/*.js', + 'sdks/typescript/client/src/remote-dom/iframe-bundle.ts', + 'examples/**', + ], + }, + + // Base configuration for all files + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parser: tsparser, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + // Node globals + console: 'readonly', + process: 'readonly', + Buffer: 'readonly', + __dirname: 'readonly', + __filename: 'readonly', + module: 'readonly', + require: 'readonly', + exports: 'readonly', + global: 'readonly', + setTimeout: 'readonly', + clearTimeout: 'readonly', + setInterval: 'readonly', + clearInterval: 'readonly', + setImmediate: 'readonly', + clearImmediate: 'readonly', + // Browser globals + window: 'readonly', + Window: 'readonly', + document: 'readonly', + navigator: 'readonly', + localStorage: 'readonly', + sessionStorage: 'readonly', + fetch: 'readonly', + btoa: 'readonly', + atob: 'readonly', + URL: 'readonly', + URLSearchParams: 'readonly', + customElements: 'readonly', + // DOM types + HTMLElement: 'readonly', + HTMLDivElement: 'readonly', + HTMLSpanElement: 'readonly', + HTMLButtonElement: 'readonly', + HTMLImageElement: 'readonly', + HTMLIFrameElement: 'readonly', + Element: 'readonly', + Node: 'readonly', + Event: 'readonly', + MessageEvent: 'readonly', + CustomEvent: 'readonly', + // Web APIs + TextEncoder: 'readonly', + TextDecoder: 'readonly', + Console: 'readonly', + Transferable: 'readonly', + WindowPostMessageOptions: 'readonly', + // ES2021 globals + Promise: 'readonly', + Symbol: 'readonly', + WeakMap: 'readonly', + WeakSet: 'readonly', + Proxy: 'readonly', + Reflect: 'readonly', + // Jest/Vitest globals + describe: 'readonly', + it: 'readonly', + test: 'readonly', + expect: 'readonly', + beforeEach: 'readonly', + afterEach: 'readonly', + beforeAll: 'readonly', + afterAll: 'readonly', + jest: 'readonly', + vi: 'readonly', + }, + }, + plugins: { + '@typescript-eslint': tseslint, + react: react, + }, + rules: { + // ESLint recommended rules (manually specified to avoid needing @eslint/js) + 'constructor-super': 'error', + 'for-direction': 'error', + 'getter-return': 'error', + 'no-async-promise-executor': 'error', + 'no-case-declarations': 'error', + 'no-class-assign': 'error', + 'no-compare-neg-zero': 'error', + 'no-cond-assign': 'error', + 'no-const-assign': 'error', + 'no-constant-condition': 'error', + 'no-control-regex': 'error', + 'no-debugger': 'error', + 'no-delete-var': 'error', + 'no-dupe-args': 'error', + 'no-dupe-class-members': 'error', + 'no-dupe-else-if': 'error', + 'no-dupe-keys': 'error', + 'no-duplicate-case': 'error', + 'no-empty': 'error', + 'no-empty-character-class': 'error', + 'no-empty-pattern': 'error', + 'no-ex-assign': 'error', + 'no-extra-boolean-cast': 'error', + 'no-fallthrough': 'error', + 'no-func-assign': 'error', + 'no-global-assign': 'error', + 'no-import-assign': 'error', + 'no-inner-declarations': 'error', + 'no-invalid-regexp': 'error', + 'no-irregular-whitespace': 'error', + 'no-loss-of-precision': 'error', + 'no-misleading-character-class': 'error', + 'no-mixed-spaces-and-tabs': 'error', + 'no-new-symbol': 'error', + 'no-nonoctal-decimal-escape': 'error', + 'no-obj-calls': 'error', + 'no-octal': 'error', + 'no-prototype-builtins': 'error', + 'no-redeclare': 'error', + 'no-regex-spaces': 'error', + 'no-self-assign': 'error', + 'no-setter-return': 'error', + 'no-shadow-restricted-names': 'error', + 'no-sparse-arrays': 'error', + 'no-this-before-super': 'error', + 'no-undef': 'error', + 'no-unexpected-multiline': 'error', + 'no-unreachable': 'error', + 'no-unsafe-finally': 'error', + 'no-unsafe-negation': 'error', + 'no-unsafe-optional-chaining': 'error', + 'no-unused-labels': 'error', + 'no-unused-vars': 'error', + 'no-useless-backreference': 'error', + 'no-useless-catch': 'error', + 'no-useless-escape': 'error', + 'no-with': 'error', + 'require-yield': 'error', + 'use-isnan': 'error', + 'valid-typeof': 'error', + + // TypeScript ESLint recommended rules + ...tseslint.configs.recommended.rules, + + // React recommended rules + ...react.configs.recommended.rules, + ...react.configs['jsx-runtime'].rules, + + // Custom overrides + 'react/prop-types': 'off', + '@typescript-eslint/no-unused-vars': ['error', { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_' + }], + }, + settings: { + react: { + version: 'detect', + }, + }, + }, + + // Prettier config (should be last to override other formatting rules) + prettierConfig, +]; diff --git a/package.json b/package.json index 9c280320..c60276ba 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "test:ruby": "cd sdks/ruby && bundle install && bundle exec rake spec", "test:watch": "vitest watch", "coverage": "vitest run --coverage", - "lint": "eslint . --ext .ts,.tsx,.js,.jsx", - "lint:fix": "eslint . --ext .ts,.tsx,.js,.jsx --fix", + "lint": "eslint .", + "lint:fix": "eslint . --fix", "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,md}\"", "version:patch": "echo \"Versioning with Changesets, then run pnpm install\" && pnpm changeset version && pnpm install --lockfile-only", "publish-packages": "pnpm build && pnpm changeset publish", diff --git a/sdks/typescript/server/src/adapters/mcp-apps/adapter-runtime.ts b/sdks/typescript/server/src/adapters/mcp-apps/adapter-runtime.ts index 7b1614a7..69648fa1 100644 --- a/sdks/typescript/server/src/adapters/mcp-apps/adapter-runtime.ts +++ b/sdks/typescript/server/src/adapters/mcp-apps/adapter-runtime.ts @@ -45,7 +45,6 @@ const LATEST_PROTOCOL_VERSION = '2025-11-21'; * * @see https://github.com/modelcontextprotocol/ext-apps/blob/main/src/spec.types.ts */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -- Used in switch cases below const METHODS = { // Lifecycle INITIALIZE: 'ui/initialize', @@ -234,7 +233,7 @@ class McpAppsAdapter { try { await initPromise; - } catch (error) { + } catch (_error) { // Initialization failed, but we still try to work this.config.logger.warn('[MCP Apps Adapter] Continuing despite initialization error'); } @@ -533,7 +532,7 @@ class McpAppsAdapter { this.sendJsonRpcRequest(jsonRpcId, METHODS.MESSAGE, { role: 'user', - content: { type: 'text', text: prompt } + content: [{ type: 'text', text: prompt }] }); break; } @@ -576,7 +575,7 @@ class McpAppsAdapter { // Translate intent to a message this.sendJsonRpcRequest(jsonRpcId, METHODS.MESSAGE, { role: 'user', - content: { type: 'text', text: `Intent: ${intent}. Parameters: ${JSON.stringify(params)}` } + content: [{ type: 'text', text: `Intent: ${intent}. Parameters: ${JSON.stringify(params)}` }], }); break; } diff --git a/sdks/typescript/server/src/utils.ts b/sdks/typescript/server/src/utils.ts index d5dadd7e..b823b5a5 100644 --- a/sdks/typescript/server/src/utils.ts +++ b/sdks/typescript/server/src/utils.ts @@ -55,7 +55,7 @@ export function utf8ToBase64(str: string): string { ); try { return btoa(str); - } catch (e) { + } catch (_e) { throw new Error( 'MCP-UI SDK: Suitable UTF-8 to Base64 encoding method not found, and fallback btoa failed.', ); diff --git a/sdks/typescript/server/vite.config.ts b/sdks/typescript/server/vite.config.ts index 2b8b7ebe..4dcbb46f 100644 --- a/sdks/typescript/server/vite.config.ts +++ b/sdks/typescript/server/vite.config.ts @@ -11,7 +11,6 @@ export default defineConfig({ tsconfigPath: path.resolve(__dirname, 'tsconfig.json'), exclude: ['**/__tests__/**', '**/*.test.ts', '**/*.spec.ts'], }), - // eslint-disable-next-line @typescript-eslint/no-explicit-any ], build: { lib: {