Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 48 additions & 1 deletion .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"plugins": ["import", "promise", "unicorn"],
"plugins": ["import", "promise", "unicorn", "typescript"],
"options": {
"typeAware": true
},
"categories": {
"correctness": "error",
"pedantic": "warn",
Expand All @@ -9,6 +12,50 @@
"suspicious": "warn"
},
"rules": {
// Type-aware linting: keep the rules that catch real defects and switch off
// the stylistic ones, which fight Vue/vue-router idioms and drown the signal.
"no-void": "off", // typescript/no-floating-promises prescribes `void` as the fix
"typescript/no-floating-promises": "error",
"typescript/await-thenable": "error",
"typescript/no-misused-promises": "error",
"typescript/require-array-sort-compare": "error",
"typescript/no-wrapper-object-types": "error",
"typescript/no-redundant-type-constituents": "error",
"typescript/prefer-readonly-parameter-types": "off", // Unsatisfiable against vue-router callback signatures
"typescript/strict-boolean-expressions": "off", // Contradicts documented vue-router idioms; cannot see templates
"typescript/no-unsafe-type-assertion": "off",
"typescript/no-unsafe-member-access": "off",
"typescript/no-unsafe-assignment": "off",
"typescript/no-unsafe-call": "off",
"typescript/no-unsafe-argument": "off",
"typescript/no-unsafe-return": "off",
"typescript/no-unnecessary-type-assertion": "off", // Open upstream false-positive regression
"typescript/unbound-method": "off",
"typescript/prefer-nullish-coalescing": "off",
"typescript/no-confusing-void-expression": "off",
"typescript/return-await": "off",
"typescript/strict-void-return": "off",
"typescript/no-extraneous-class": "off",
"typescript/consistent-return": "off",
"typescript/no-unnecessary-type-conversion": "off",
"typescript/no-unnecessary-boolean-literal-compare": "off",
"typescript/ban-types": "off",
// Syntactic rules the typescript plugin brings along; the repo never opted
// into these style positions, so keep them off rather than reformat the app.
"typescript/explicit-function-return-type": "off",
"typescript/explicit-module-boundary-types": "off",
"typescript/explicit-member-accessibility": "off",
"typescript/consistent-type-definitions": "off",
"typescript/no-non-null-assertion": "off",
"typescript/promise-function-async": "off",
"typescript/no-explicit-any": "off",
"typescript/prefer-readonly": "off",
"typescript/no-inferrable-types": "off",
"typescript/consistent-type-imports": "off",
"typescript/array-type": "off",
"typescript/consistent-indexed-object-style": "off",
"typescript/prefer-regexp-exec": "off",
"typescript/dot-notation": "off",
"import/no-cycle": "error",
"import/no-duplicates": "error",
"import/no-self-import": "error",
Expand Down
12 changes: 6 additions & 6 deletions VueApp/src/CMS/__tests__/use-url-filtered-table.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ describe("useUrlFilteredTable", () => {
it("initializes the primary id and filters from route.query and sends them, omitting empties", async () => {
const { table } = await mountTable({ fileGuid: "g1", search: "report" })

table.reload()
void table.reload()
await flushPromises()

const url = lastUrl()
Expand All @@ -80,7 +80,7 @@ describe("useUrlFilteredTable", () => {
const { table, router } = await mountTable()

table.filters.value.search = "hello"
table.reload()
void table.reload()
await flushRouter()

expect(router.currentRoute.value.query.search).toBe("hello")
Expand All @@ -90,11 +90,11 @@ describe("useUrlFilteredTable", () => {

it("clearPrimaryFilter drops the deep-link id from the request and the URL, then refetches", async () => {
const { table, router } = await mountTable({ fileGuid: "g1" })
table.reload()
void table.reload()
await flushRouter()
const before = mockGet.mock.calls.length

table.clearPrimaryFilter()
void table.clearPrimaryFilter()
await flushRouter()

expect(table.primary.value).toBeNull()
Expand All @@ -105,7 +105,7 @@ describe("useUrlFilteredTable", () => {

it("re-syncs filters and refetches when external navigation changes the query", async () => {
const { table, router } = await mountTable()
table.reload()
void table.reload()
await flushRouter()
const before = mockGet.mock.calls.length

Expand All @@ -122,7 +122,7 @@ describe("useUrlFilteredTable", () => {
const { table } = await mountTable()

table.filters.value.search = "abc"
table.reload()
void table.reload()
await flushPromises()
const afterReload = mockGet.mock.calls.length

Expand Down
2 changes: 1 addition & 1 deletion VueApp/src/CMS/composables/use-url-filtered-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export function useUrlFilteredTable<TRow, F extends UrlFilters>(options: UrlFilt
}
primary.value = nextPrimary
filters.value = next
table.reloadFirstPage()
void table.reloadFirstPage()
},
)

Expand Down
2 changes: 1 addition & 1 deletion VueApp/src/CTS/__tests__/assessment-bubble.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function createWrapper(props: Record<string, unknown>) {
})
}

describe(AssessmentBubble, () => {
describe("AssessmentBubble", () => {
describe("aria-label privacy", () => {
it("uses levelName on the clickable button and does not expose the numeric value", () => {
const wrapper = createWrapper({
Expand Down
20 changes: 0 additions & 20 deletions VueApp/src/CTS/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,6 @@ type Assessment = {
serviceName: string | null
}

type StudentEpaFormData = {
epaId: number
levelId: number
comment: string
studentId: number
serviceId: number
encounterDate: Date | null
}

type Level = {
levelId: number
levelName: string
Expand Down Expand Up @@ -161,12 +152,6 @@ type Bundle = {
roles: Role[]
}

type BundleRole = {
bundleRoleId: number
bundleId: number
roleId: number
}

type BundleCompetency = {
bundleCompetencyId: number
bundleId: number
Expand Down Expand Up @@ -229,11 +214,6 @@ type MilestoneLevel = {
description: string
}

type MilestoneLevelUpdate = {
levelId: number
description: string
}

type Course = {
courseId: number
status: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ describe("ClinicalSchedulerHome - Quality Assurance", () => {
describe("Error Handling", () => {
it("handles permission store initialization errors gracefully", () => {
mockPermissionsStore.hasAnyEditPermission = true
mockPermissionsStore.initialize = vi.fn().mockRejectedValue(new Error("API Error"))
mockPermissionsStore.initialize = vi
.fn<(...args: unknown[]) => unknown>()
.mockRejectedValue(new Error("API Error"))

// Should not throw error
expect(() =>
Expand All @@ -113,8 +115,8 @@ describe("ClinicalSchedulerHome - Quality Assurance", () => {
userPermissions: null,
isLoading: false,
editableServiceCount: 0,
getEditableServicesDisplay: vi.fn().mockReturnValue("None"),
initialize: vi.fn().mockResolvedValue(undefined), // oxlint-disable-line unicorn/no-useless-undefined -- TS requires the argument
getEditableServicesDisplay: vi.fn<(...args: unknown[]) => unknown>().mockReturnValue("None"),
initialize: vi.fn<(...args: unknown[]) => unknown>().mockResolvedValue(undefined), // oxlint-disable-line unicorn/no-useless-undefined -- TS requires the argument
} as any)

// Should not throw error
Expand All @@ -135,7 +137,7 @@ describe("ClinicalSchedulerHome - Quality Assurance", () => {
// Mock router.push to throw an error
const mockRouter = {
...router,
push: vi.fn().mockRejectedValue(new Error("Navigation Error")),
push: vi.fn<(...args: unknown[]) => unknown>().mockRejectedValue(new Error("Navigation Error")),
}

const wrapper = createTestWrapper({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,9 @@ describe("ClinicalSchedulerHome Component - Accessibility & Error Handling", ()
describe("Error Handling", () => {
it("handles permission store initialization errors gracefully", () => {
mockPermissionsStore.hasAnyEditPermission = true
mockPermissionsStore.initialize = vi.fn().mockRejectedValue(new Error("API Error"))
mockPermissionsStore.initialize = vi
.fn<(...args: unknown[]) => unknown>()
.mockRejectedValue(new Error("API Error"))

// Should not throw error
expect(() => createWrapper(router)).not.toThrow()
Expand All @@ -326,8 +328,8 @@ describe("ClinicalSchedulerHome Component - Accessibility & Error Handling", ()
userPermissions: null,
isLoading: false,
editableServiceCount: 0,
getEditableServicesDisplay: vi.fn().mockReturnValue("None"),
initialize: vi.fn().mockResolvedValue(undefined), // oxlint-disable-line unicorn/no-useless-undefined -- TS requires the argument
getEditableServicesDisplay: vi.fn<(...args: unknown[]) => unknown>().mockReturnValue("None"),
initialize: vi.fn<(...args: unknown[]) => unknown>().mockResolvedValue(undefined), // oxlint-disable-line unicorn/no-useless-undefined -- TS requires the argument
} as any)

// Should not throw error
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { normalizeScheduleSemesters } from "../composables/use-schedule-normalization"
import type { ScheduleSemester } from "../components/schedule-view-types"

describe(normalizeScheduleSemesters, () => {
describe("normalizeScheduleSemesters", () => {
it("should return empty array when input is undefined", () => {
// oxlint-disable-next-line unicorn/no-useless-undefined -- Explicitly testing undefined input
const result = normalizeScheduleSemesters(undefined)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { normalizeWeek } from "../composables/use-schedule-normalization"

describe(normalizeWeek, () => {
describe("normalizeWeek", () => {
it("should preserve existing dateEnd when it has a value", () => {
const week = {
weekId: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import { PermissionService } from "../services/permission-service"
// Mock the permission service
vi.mock("../services/permission-service", () => ({
PermissionService: {
getUserPermissions: vi.fn(),
getPermissionSummary: vi.fn(),
canEditService: vi.fn(),
canEditRotation: vi.fn(),
canEditOwnSchedule: vi.fn(),
getUserPermissions: vi.fn<(...args: unknown[]) => unknown>(),
getPermissionSummary: vi.fn<(...args: unknown[]) => unknown>(),
canEditService: vi.fn<(...args: unknown[]) => unknown>(),
canEditRotation: vi.fn<(...args: unknown[]) => unknown>(),
canEditOwnSchedule: vi.fn<(...args: unknown[]) => unknown>(),
},
permissionService: {},
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { PermissionService, createMockUserPermissions } from "./test-utils"
// Mock the permission service
vi.mock("../services/permission-service", () => ({
PermissionService: {
getUserPermissions: vi.fn(),
getPermissionSummary: vi.fn(),
canEditService: vi.fn(),
canEditRotation: vi.fn(),
canEditOwnSchedule: vi.fn(),
getUserPermissions: vi.fn<(...args: unknown[]) => unknown>(),
getPermissionSummary: vi.fn<(...args: unknown[]) => unknown>(),
canEditService: vi.fn<(...args: unknown[]) => unknown>(),
canEditRotation: vi.fn<(...args: unknown[]) => unknown>(),
canEditOwnSchedule: vi.fn<(...args: unknown[]) => unknown>(),
},
permissionService: {},
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import { PermissionService, createMockUserPermissions } from "./test-utils"
// Mock the permission service
vi.mock("../services/permission-service", () => ({
PermissionService: {
getUserPermissions: vi.fn(),
getPermissionSummary: vi.fn(),
canEditService: vi.fn(),
canEditRotation: vi.fn(),
canEditOwnSchedule: vi.fn(),
getUserPermissions: vi.fn<(...args: unknown[]) => unknown>(),
getPermissionSummary: vi.fn<(...args: unknown[]) => unknown>(),
canEditService: vi.fn<(...args: unknown[]) => unknown>(),
canEditRotation: vi.fn<(...args: unknown[]) => unknown>(),
canEditOwnSchedule: vi.fn<(...args: unknown[]) => unknown>(),
},
permissionService: {},
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { createComponentLogic } from "./rotation-selector-helpers.test"
// Mock the RotationService
vi.mock("../services/rotation-service", () => ({
RotationService: {
getRotations: vi.fn(),
getRotationsWithScheduledWeeks: vi.fn(),
getRotations: vi.fn<(...args: unknown[]) => unknown>(),
getRotationsWithScheduledWeeks: vi.fn<(...args: unknown[]) => unknown>(),
},
}))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { createComponentLogic } from "./rotation-selector-helpers.test"
// Mock the RotationService
vi.mock("../services/rotation-service", () => ({
RotationService: {
getRotations: vi.fn(),
getRotationsWithScheduledWeeks: vi.fn(),
getRotations: vi.fn<(...args: unknown[]) => unknown>(),
getRotationsWithScheduledWeeks: vi.fn<(...args: unknown[]) => unknown>(),
},
}))

Expand Down
12 changes: 6 additions & 6 deletions VueApp/src/ClinicalScheduler/__tests__/test-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import type { UserPermissions } from "../types"

// Mock localStorage for tests that need it
const mockLocalStorage = {
getItem: vi.fn(),
setItem: vi.fn(),
removeItem: vi.fn(),
clear: vi.fn(),
getItem: vi.fn<(...args: unknown[]) => unknown>(),
setItem: vi.fn<(...args: unknown[]) => unknown>(),
removeItem: vi.fn<(...args: unknown[]) => unknown>(),
clear: vi.fn<(...args: unknown[]) => unknown>(),
}

// Setup localStorage mock
Expand Down Expand Up @@ -58,8 +58,8 @@ function createMockPermissionsStore() {
userPermissions: null,
isLoading: false,
editableServiceCount: 0,
getEditableServicesDisplay: vi.fn().mockReturnValue("None"),
initialize: vi.fn().mockResolvedValue(undefined), // oxlint-disable-line unicorn/no-useless-undefined -- TS requires the argument
getEditableServicesDisplay: vi.fn<(...args: unknown[]) => unknown>().mockReturnValue("None"),
initialize: vi.fn<(...args: unknown[]) => unknown>().mockResolvedValue(undefined), // oxlint-disable-line unicorn/no-useless-undefined -- TS requires the argument
}
}

Expand Down
Loading
Loading