Skip to content

Commit f436abe

Browse files
committed
eslint and test fixes
1 parent 4eda10f commit f436abe

34 files changed

Lines changed: 632 additions & 308 deletions

README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,12 @@ npm run dev
110110
2. **Existing users**: Sign in as a Patient user
111111
3. After signing in, you'll access your AI Concierge dashboard
112112

113-
### AI Assistant Examples
113+
### Load Sample Data
114+
115+
1. After signing in, click the "Load Sample Data" button to load sample data for the patient.
116+
2. The AI assistant will then be able to generate widgets based on the sample data.
117+
118+
### Widget Queries
114119

115120
The AI assistant generates widgets dynamically based on natural language queries. Try these:
116121

eslint.config.mjs

Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
import eslint from '@eslint/js';
2+
import importPlugin from 'eslint-plugin-import';
3+
import noOnlyTestsPlugin from 'eslint-plugin-no-only-tests';
4+
import reactHooks from 'eslint-plugin-react-hooks';
5+
import reactRefresh from 'eslint-plugin-react-refresh';
6+
import tseslint from 'typescript-eslint';
7+
8+
export default [
9+
// Ignores
10+
{
11+
ignores: [
12+
'.turbo',
13+
'coverage',
14+
'dist',
15+
'node_modules',
16+
'package-lock.json',
17+
'**/.turbo',
18+
'**/coverage/',
19+
'**/dist/',
20+
'**/node_modules/',
21+
'**/babel.config.*',
22+
'**/jest.sequencer.*',
23+
'**/postcss.config.*',
24+
'**/rollup.config.*',
25+
'**/webpack.config.*',
26+
'**/*.png.ts',
27+
'**/packages/definitions/src/fhir/**',
28+
'external-projects-do-not-build/**',
29+
],
30+
},
31+
// Core config - applies to all source files
32+
eslint.configs.recommended,
33+
importPlugin.flatConfigs.recommended,
34+
{
35+
languageOptions: {
36+
ecmaVersion: 'latest',
37+
sourceType: 'module',
38+
},
39+
rules: {
40+
// Disable import/no-unresolved - TypeScript handles module resolution
41+
'import/no-unresolved': 'off',
42+
// ESLint - Possible Problems
43+
'array-callback-return': 'error',
44+
curly: ['error', 'all'],
45+
eqeqeq: ['error', 'always'],
46+
'no-constant-binary-expression': 'error',
47+
'no-constructor-return': 'error',
48+
'no-new-native-nonconstructor': 'error',
49+
'no-promise-executor-return': 'error',
50+
'no-self-compare': 'error',
51+
'no-template-curly-in-string': 'error',
52+
'no-throw-literal': 'error',
53+
'no-unmodified-loop-condition': 'error',
54+
'no-unreachable-loop': 'error',
55+
'no-unused-private-class-members': 'error',
56+
57+
// ESLint - Suggestions
58+
'consistent-return': 'error',
59+
'default-case-last': 'error',
60+
'default-param-last': 'error',
61+
'guard-for-in': 'error',
62+
'no-array-constructor': 'error',
63+
'no-div-regex': 'error',
64+
'no-eq-null': 'error',
65+
'no-eval': 'error',
66+
'no-extend-native': 'error',
67+
'no-extra-bind': 'error',
68+
'no-floating-decimal': 'error',
69+
'no-implied-eval': 'error',
70+
'no-invalid-this': 'error',
71+
'no-lonely-if': 'error',
72+
'no-nested-ternary': 'error',
73+
'no-new': 'error',
74+
'no-new-func': 'error',
75+
'no-new-object': 'error',
76+
'no-new-wrappers': 'error',
77+
'no-octal-escape': 'error',
78+
'no-proto': 'error',
79+
'no-return-assign': 'error',
80+
'no-sequences': 'error',
81+
'no-unneeded-ternary': 'error',
82+
'no-unused-expressions': 'error',
83+
'no-useless-call': 'error',
84+
'no-useless-computed-key': 'error',
85+
'no-useless-concat': 'error',
86+
'no-useless-return': 'error',
87+
'no-var': 'error',
88+
'no-void': 'error',
89+
'prefer-object-has-own': 'error',
90+
'prefer-object-spread': 'error',
91+
'prefer-promise-reject-errors': 'error',
92+
'prefer-regex-literals': 'error',
93+
'prefer-rest-params': 'error',
94+
'prefer-spread': 'error',
95+
radix: 'error',
96+
97+
'no-unused-vars': [
98+
'error',
99+
{
100+
argsIgnorePattern: '^_',
101+
caughtErrorsIgnorePattern: '^_',
102+
},
103+
],
104+
},
105+
},
106+
// TypeScript config - applies to all TypeScript source files
107+
...tseslint.configs.recommended,
108+
{
109+
files: ['**/*.ts', '**/*.tsx'],
110+
languageOptions: {
111+
parserOptions: {
112+
projectService: true,
113+
},
114+
},
115+
},
116+
...tseslint.configs.strict,
117+
{
118+
files: ['**/*.ts', '**/*.tsx'],
119+
...reactHooks.configs.flat.recommended,
120+
},
121+
{
122+
files: ['**/*.ts', '**/*.tsx'],
123+
...reactRefresh.configs.recommended,
124+
},
125+
{
126+
files: ['**/*.ts', '**/*.tsx'],
127+
plugins: {
128+
'no-only-tests': noOnlyTestsPlugin,
129+
},
130+
rules: {
131+
// TypeScript+ESLint
132+
'@typescript-eslint/array-type': 'error',
133+
'@typescript-eslint/consistent-generic-constructors': 'error',
134+
'@typescript-eslint/consistent-type-assertions': 'error',
135+
'@typescript-eslint/explicit-function-return-type': 'off', // Disabled per project requirements
136+
'@typescript-eslint/explicit-module-boundary-types': 'off',
137+
'@typescript-eslint/no-base-to-string': 'error',
138+
'@typescript-eslint/no-confusing-non-null-assertion': 'error',
139+
'@typescript-eslint/no-duplicate-enum-values': 'error',
140+
'@typescript-eslint/no-duplicate-type-constituents': 'error',
141+
'@typescript-eslint/no-explicit-any': 'off',
142+
'@typescript-eslint/no-extraneous-class': 'error',
143+
'@typescript-eslint/no-floating-promises': 'error',
144+
'@typescript-eslint/no-invalid-void-type': 'error',
145+
'@typescript-eslint/no-meaningless-void-operator': 'error',
146+
'@typescript-eslint/no-mixed-enums': 'error',
147+
'@typescript-eslint/no-non-null-asserted-nullish-coalescing': 'error',
148+
'@typescript-eslint/no-redundant-type-constituents': 'error',
149+
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 'error',
150+
'@typescript-eslint/no-unnecessary-type-arguments': 'error',
151+
'@typescript-eslint/no-unsafe-declaration-merging': 'error',
152+
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
153+
'@typescript-eslint/prefer-for-of': 'error',
154+
'@typescript-eslint/prefer-includes': 'error',
155+
'@typescript-eslint/prefer-function-type': 'off',
156+
'@typescript-eslint/prefer-literal-enum-member': 'error',
157+
'@typescript-eslint/prefer-optional-chain': 'error',
158+
'@typescript-eslint/prefer-reduce-type-parameter': 'error',
159+
'@typescript-eslint/prefer-return-this-type': 'error',
160+
'@typescript-eslint/prefer-string-starts-ends-with': 'error',
161+
'@typescript-eslint/prefer-ts-expect-error': 'off',
162+
'@typescript-eslint/return-await': ['error', 'in-try-catch'],
163+
'@typescript-eslint/switch-exhaustiveness-check': [
164+
'error',
165+
{
166+
allowDefaultCaseForExhaustiveSwitch: true,
167+
considerDefaultExhaustiveForUnions: true,
168+
requireDefaultForNonUnion: false,
169+
},
170+
],
171+
'@typescript-eslint/unified-signatures': 'error',
172+
173+
'no-useless-constructor': 'off',
174+
'@typescript-eslint/no-useless-constructor': 'error',
175+
176+
'no-unused-vars': 'off',
177+
'@typescript-eslint/no-unused-vars': [
178+
'error',
179+
{
180+
argsIgnorePattern: '^_',
181+
varsIgnorePattern: '^_',
182+
caughtErrors: 'all',
183+
caughtErrorsIgnorePattern: '^_',
184+
},
185+
],
186+
187+
// New strict `@typescript-eslint` rules - need to drop all use of `any` first
188+
'@typescript-eslint/no-unsafe-assignment': 'off',
189+
'@typescript-eslint/no-unsafe-member-access': 'off',
190+
'@typescript-eslint/no-unsafe-return': 'off',
191+
'@typescript-eslint/no-unsafe-argument': 'off',
192+
193+
// imports rules for isolatedModules and verbatimModuleSyntax
194+
'no-duplicate-imports': 'off',
195+
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
196+
'import/no-duplicates': 'error',
197+
'import/no-unresolved': 'off',
198+
'@typescript-eslint/consistent-type-imports': [
199+
'error',
200+
{
201+
prefer: 'type-imports',
202+
fixStyle: 'separate-type-imports',
203+
},
204+
],
205+
'@typescript-eslint/consistent-type-exports': 'error',
206+
207+
// React Hooks
208+
'react-hooks/exhaustive-deps': 'error',
209+
'react-hooks/set-state-in-effect': 'warn',
210+
'react-hooks/refs': 'warn',
211+
'react-hooks/immutability': 'warn',
212+
'react-hooks/static-components': 'warn',
213+
'react-hooks/preserve-manual-memoization': 'warn',
214+
'react-hooks/purity': 'warn',
215+
216+
// React Refresh
217+
'react-refresh/only-export-components': 'warn',
218+
219+
// Disable warnings from typescript-eslint:strict
220+
'@typescript-eslint/non-nullable-type-assertion-style': 'off',
221+
'@typescript-eslint/dot-notation': 'off',
222+
'@typescript-eslint/consistent-indexed-object-style': 'off',
223+
'@typescript-eslint/consistent-type-definitions': 'off',
224+
'@typescript-eslint/prefer-nullish-coalescing': 'off',
225+
'@typescript-eslint/no-unnecessary-condition': 'off',
226+
'@typescript-eslint/no-dynamic-delete': 'off',
227+
'@typescript-eslint/no-empty-object-type': 'off',
228+
229+
// No Only Tests
230+
'no-only-tests/no-only-tests': ['error', { fix: true }],
231+
},
232+
},
233+
// server.js specific config
234+
{
235+
files: ['server.js'],
236+
languageOptions: {
237+
sourceType: 'module',
238+
globals: {
239+
process: 'readonly',
240+
console: 'readonly',
241+
},
242+
},
243+
},
244+
];

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"dev": "vite",
99
"server": "node server.js",
1010
"dev:all": "npm run server & npm run dev",
11-
"lint": "eslint . --ext .js,.jsx,.ts,.tsx --fix src",
11+
"lint": "eslint .",
12+
"lint:fix": "eslint . --fix",
1213
"preview": "vite preview",
1314
"test": "jest"
1415
},
@@ -52,6 +53,7 @@
5253
"react-dom": "19.2.3",
5354
"react-router": "7.10.1",
5455
"typescript": "5.9.3",
56+
"typescript-eslint": "^8.50.1",
5557
"vite": "7.2.7"
5658
},
5759
"packageManager": "npm@11.6.2",

server.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ if (process.env.OPENAI_MODEL) {
2121
const serviceAdapter = new OpenAIAdapter({
2222
model: model,
2323
apiKey: process.env.OPENAI_API_KEY,
24+
temperature: 0.2,
2425
});
2526

2627
const server = createServer((req, res) => {

src/App.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ describe('App', () => {
1616
medplum = new MockClient();
1717
patient = await medplum.createResource<Patient>({
1818
resourceType: 'Patient',
19-
name: [{ given: ['Test'], family: ['Patient'] }],
19+
name: [{ given: ['Test'], family: 'Patient' }],
2020
});
2121
medplum.setActiveLoginOverride({
2222
accessToken: 'token',
2323
project: { reference: 'Project/123' },
2424
profile: { reference: `Patient/${patient.id}`, display: 'Test Patient' },
25+
refreshToken: '',
2526
});
2627
});
2728

@@ -36,4 +37,3 @@ describe('App', () => {
3637
expect(container).toBeInTheDocument();
3738
});
3839
});
39-

src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { JSX } from 'react';
66
import { Suspense } from 'react';
77
import { Navigate, Route, Routes } from 'react-router';
88
import { Dashboard } from './components/Dashboard';
9-
import { DashboardProvider } from './context/DashboardContext';
9+
import { DashboardProvider } from './context/DashboardProvider';
1010
import { SignInPage } from './pages/SignInPage';
1111
import { SignOutPage } from './pages/SignOutPage';
1212

src/components/ClearPatientDataButton.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { notifications } from '@mantine/notifications';
44
import type { Patient, ResourceType } from '@medplum/fhirtypes';
55
import { useMedplum, useMedplumProfile } from '@medplum/react';
66
import { IconTrash } from '@tabler/icons-react';
7-
import { type JSX, useState } from 'react';
7+
import { useState } from 'react';
8+
import type { JSX } from 'react';
89

910
interface ResourceCounts {
1011
[key: string]: number;
@@ -96,10 +97,12 @@ export function ClearPatientDataButton({ onDataCleared }: ClearPatientDataButton
9697

9798
try {
9899
// Collect all resources to delete
99-
const resourcesToDelete: Array<{ resourceType: string; id: string }> = [];
100+
const resourcesToDelete: { resourceType: string; id: string }[] = [];
100101

101102
for (const [resourceType, count] of Object.entries(resourceCounts)) {
102-
if (count === 0) continue;
103+
if (count === 0) {
104+
continue;
105+
}
103106

104107
try {
105108
// Search for all resources of this type for the patient

0 commit comments

Comments
 (0)