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
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ describe('AnimatedCounter', () => {
})

// Should show intermediate value
const displayedValue = parseInt(screen.getByText(/\d+/).textContent || '0')
const displayedValue = Number.parseInt(screen.getByText(/\d+/).textContent || '0')
expect(displayedValue).toBeGreaterThan(0)
expect(displayedValue).toBeLessThanOrEqual(50)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ describe('<SearchPageLayout />', () => {
<SearchPageLayout
isLoaded={true}
totalPages={3}
currentPage={NaN}
currentPage={Number.NaN}
onSearch={() => {}}
onPageChange={handlePageChange}
searchQuery=""
Expand Down Expand Up @@ -346,7 +346,7 @@ describe('<SearchPageLayout />', () => {
render(
<SearchPageLayout
isLoaded={true}
totalPages={NaN}
totalPages={Number.NaN}
currentPage={1}
onSearch={() => {}}
onPageChange={() => {}}
Expand Down
31 changes: 31 additions & 0 deletions frontend/eslint-rules/no-global-isfinite.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const noGlobalIsFiniteRule = {
meta: {
type: 'suggestion',
docs: {
description: 'Disallow use of global isFinite, use Number.isFinite instead',
recommended: false,
},
fixable: 'code',
messages: {
useNumberIsFinite: 'Use Number.isFinite() instead of global isFinite().',
},
schema: [],
},
create(context) {
return {
CallExpression(node) {
if (node.callee.type === 'Identifier' && node.callee.name === 'isFinite') {
context.report({
node: node.callee,
messageId: 'useNumberIsFinite',
fix(fixer) {
return fixer.replaceText(node.callee, 'Number.isFinite')
},
})
}
},
}
},
}

export default noGlobalIsFiniteRule
31 changes: 31 additions & 0 deletions frontend/eslint-rules/no-global-isnan.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const noGlobalIsNaNRule = {
meta: {
type: 'suggestion',
docs: {
description: 'Disallow use of global isNaN, use Number.isNaN instead',
recommended: false,
},
fixable: 'code',
messages: {
useNumberIsNaN: 'Use Number.isNaN() instead of global isNaN().',
},
schema: [],
},
create(context) {
return {
CallExpression(node) {
if (node.callee.type === 'Identifier' && node.callee.name === 'isNaN') {
context.report({
node: node.callee,
messageId: 'useNumberIsNaN',
fix(fixer) {
return fixer.replaceText(node.callee, 'Number.isNaN')
},
})
}
},
}
},
}

export default noGlobalIsNaNRule
44 changes: 44 additions & 0 deletions frontend/eslint-rules/no-global-nan.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const noGlobalNaNRule = {
meta: {
type: 'suggestion',
docs: {
description: 'Disallow use of global NaN, use Number.NaN instead',
recommended: false,
},
fixable: 'code',
messages: {
useNumberNaN: 'Use Number.NaN instead of global NaN.',
},
schema: [],
},
create(context) {
return {
Identifier(node) {
// Only report if it's 'NaN' and not already part of 'Number.NaN'
if (node.name === 'NaN') {
const parent = node.parent
if (
parent &&
parent.type === 'MemberExpression' &&
parent.property === node &&
parent.object &&
parent.object.type === 'Identifier' &&
parent.object.name === 'Number'
) {
return
}

context.report({
node,
messageId: 'useNumberNaN',
fix(fixer) {
return fixer.replaceText(node, 'Number.NaN')
},
})
}
},
}
},
}

export default noGlobalNaNRule
31 changes: 31 additions & 0 deletions frontend/eslint-rules/no-global-parsefloat.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const noGlobalParseFloatRule = {
meta: {
type: 'suggestion',
docs: {
description: 'Disallow use of global parseFloat, use Number.parseFloat instead',
recommended: false,
},
fixable: 'code',
messages: {
useNumberParseFloat: 'Use Number.parseFloat() instead of global parseFloat().',
},
schema: [],
},
create(context) {
return {
CallExpression(node) {
if (node.callee.type === 'Identifier' && node.callee.name === 'parseFloat') {
context.report({
node: node.callee,
messageId: 'useNumberParseFloat',
fix(fixer) {
return fixer.replaceText(node.callee, 'Number.parseFloat')
},
})
}
},
}
},
}

export default noGlobalParseFloatRule
31 changes: 31 additions & 0 deletions frontend/eslint-rules/no-global-parseint.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const noGlobalParseIntRule = {
meta: {
type: 'suggestion',
docs: {
description: 'Disallow use of global parseInt, use Number.parseInt instead',
recommended: false,
},
fixable: 'code',
messages: {
useNumberParseInt: 'Use Number.parseInt() instead of global parseInt().',
},
schema: [],
},
create(context) {
return {
CallExpression(node) {
if (node.callee.type === 'Identifier' && node.callee.name === 'parseInt') {
context.report({
node: node.callee,
messageId: 'useNumberParseInt',
fix(fixer) {
return fixer.replaceText(node.callee, 'Number.parseInt')
},
})
}
},
}
},
}

export default noGlobalParseIntRule
19 changes: 19 additions & 0 deletions frontend/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import nextPlugin from '@next/eslint-plugin-next'
import globals from 'globals'
import noGlobalIsFiniteRule from './eslint-rules/no-global-isfinite.mjs'
import noGlobalIsNaNRule from './eslint-rules/no-global-isnan.mjs'
import noGlobalNaNRule from './eslint-rules/no-global-nan.mjs'
import noGlobalParseFloatRule from './eslint-rules/no-global-parsefloat.mjs'
import noGlobalParseIntRule from './eslint-rules/no-global-parseint.mjs'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
Expand Down Expand Up @@ -61,6 +66,15 @@ const eslintConfig = [
react,
'jsx-a11y': jsxA11y,
'@next/next': nextPlugin,
nest: {
rules: {
'no-global-isfinite': noGlobalIsFiniteRule,
'no-global-isnan': noGlobalIsNaNRule,
'no-global-nan': noGlobalNaNRule,
'no-global-parsefloat': noGlobalParseFloatRule,
'no-global-parseint': noGlobalParseIntRule,
},
},
},
settings: {
'import/resolver': {
Expand Down Expand Up @@ -149,6 +163,11 @@ const eslintConfig = [
'jsx-a11y/no-distracting-elements': 'warn',
'jsx-a11y/label-has-associated-control': 'error',
'jsx-a11y/click-events-have-key-events': 'warn',
'nest/no-global-isfinite': 'error',
'nest/no-global-isnan': 'error',
'nest/no-global-nan': 'error',
'nest/no-global-parsefloat': 'error',
'nest/no-global-parseint': 'error',
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/my/mentorship/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const MyMentorshipPage: React.FC = () => {
const username = (session as ExtendedSession)?.user?.login

const initialQuery = searchParams.get('q') || ''
const initialPage = parseInt(searchParams.get('page') || '1', 10)
const initialPage = Number.parseInt(searchParams.get('page') || '1', 10)

const [searchQuery, setSearchQuery] = useState(initialQuery)
const [debouncedQuery, setDebouncedQuery] = useState(initialQuery)
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/ModuleCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export default ModuleCard
export const getSimpleDuration = (start: string, end: string): string => {
const startDate = new Date(start)
const endDate = new Date(end)
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
if (Number.isNaN(startDate.getTime()) || Number.isNaN(endDate.getTime())) {
return 'Invalid duration'
}

Expand Down
4 changes: 3 additions & 1 deletion frontend/src/hooks/useSearchPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ export function useSearchPage<T>({
const searchParams = useSearchParams()

const [items, setItems] = useState<T[]>([])
const [currentPage, setCurrentPage] = useState<number>(parseInt(searchParams.get('page') || '1'))
const [currentPage, setCurrentPage] = useState<number>(
Number.parseInt(searchParams.get('page') || '1')
)
const [searchQuery, setSearchQuery] = useState<string>(searchParams.get('q') || '')
const [sortBy, setSortBy] = useState<string>(searchParams.get('sortBy') || defaultSortBy)
const [order, setOrder] = useState<string>(searchParams.get('order') || defaultOrder)
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/utils/dateFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const formatDate = (input: number | string) => {
? new Date(input * 1000) // Unix timestamp in seconds
: new Date(input) // ISO date string

if (isNaN(date.getTime())) {
if (Number.isNaN(date.getTime())) {
throw new Error('Invalid date')
}

Expand All @@ -23,7 +23,7 @@ export const formatDateRange = (startDate: number | string, endDate: number | st
const start = typeof startDate === 'number' ? new Date(startDate * 1000) : new Date(startDate)
const end = typeof endDate === 'number' ? new Date(endDate * 1000) : new Date(endDate)

if (isNaN(start.getTime()) || isNaN(end.getTime())) {
if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime())) {
throw new Error('Invalid date')
}

Expand Down Expand Up @@ -63,7 +63,7 @@ export const formatDateRange = (startDate: number | string, endDate: number | st
export const formatDateForInput = (dateStr: string) => {
if (!dateStr) return ''
const date = new Date(dateStr)
if (isNaN(date.getTime())) {
if (Number.isNaN(date.getTime())) {
throw new Error('Invalid date')
}
return date.toISOString().slice(0, 10)
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/utils/round.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const round = (value: number, precision = 2): number => {
if (isNaN(value)) return 0 // Handle NaN values
if (Number.isNaN(value)) return 0 // Handle NaN values
if (precision < 0) {
throw new Error('Precision must be a non-negative integer')
}
Expand Down