Skip to content

Commit

Permalink
feat: detect class property access with MemberExpression and type inf…
Browse files Browse the repository at this point in the history
…erence
  • Loading branch information
MengLinMaker committed Nov 4, 2024
1 parent 4c90e13 commit 6daa83d
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 11 deletions.
19 changes: 16 additions & 3 deletions src/rules/runtime-compat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const runtimeCompatRule = (filterRuntimes: data.RuntimeName[], ruleConfig
defaultOptions: [],
create: (context) => {
const services = ESLintUtils.getParserServices(context)
const checker = services.program.getTypeChecker()

const unsupportedApis = filterSupportCompatData(
mapCompatData(data),
Expand All @@ -41,13 +42,25 @@ export const runtimeCompatRule = (filterRuntimes: data.RuntimeName[], ruleConfig
}

return {
// Check compat for class instantiations
NewExpression: (node) => {
const type = services.getTypeAtLocation(node)
const checker = services.program.getTypeChecker()
const className = checker.typeToString(type)
const classType = services.getTypeAtLocation(node)
const className = checker.typeToString(classType)

const unsupportesApiId = JSON.stringify([className])
reportError(node, unsupportesApiId)
},
// Check compat for class property access
MemberExpression: (node) => {
const classType = services.getTypeAtLocation(node.object)
const className = checker.typeToString(classType)

const propertyType = services.getTypeAtLocation(node.property)
const propertyName = propertyType.getSymbol()?.escapedName

const unsupportesApiId = JSON.stringify([className, propertyName])
reportError(node, unsupportesApiId)
},
}
},
})
21 changes: 13 additions & 8 deletions tests/rules/runtimeCompatRule.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { runtimeCompatRule } from '../../src/rules/runtime-compat'
import { ruleTester } from './setup'

const filterRuntimes: RuntimeName[] = ['node']
const cacheInstantiationError =
"'Cache' - Unsupported API in node.\nDocs - https://developer.mozilla.org/docs/Web/API/Cache"
const cacheInstantiationError = `'Cache' - Unsupported API in node.\nDocs - https://developer.mozilla.org/docs/Web/API/Cache`
const cachePropertyAccessError = `'Cache.add' - Unsupported API in node.\nDocs - https://developer.mozilla.org/docs/Web/API/Cache/add`

ruleTester.run(
'runtime-compat',
Expand All @@ -16,21 +16,26 @@ ruleTester.run(
valid: ['fetch("https://www.google.com")'],
invalid: [
{
// Detect unsupported API constructor call.
code: /*javascript*/ `
code: `
const _Cache = Cache
let cache = new _Cache()
cache.add("test.html")
`,
errors: [{ message: cacheInstantiationError }],
errors: [{ message: cacheInstantiationError }, { message: cachePropertyAccessError }],
},
{
// Detect unsupported API variable assignment.
code: /*javascript*/ `
code: `
const cache = new Cache()
cache.add("test.html")
`,
errors: [{ message: cacheInstantiationError }],
errors: [{ message: cacheInstantiationError }, { message: cachePropertyAccessError }],
},
{
code: `
new Cache().add("test.html")
`,
// Interestingly property access error is thrown before class instantiation error
errors: [{ message: cachePropertyAccessError }, { message: cacheInstantiationError }],
},
],
},
Expand Down

0 comments on commit 6daa83d

Please sign in to comment.