How to create an inspection for JavaScript?

Answered

I want to write an inspections which forbids usage of jQuery selectors: `$('selector')`.

Which language(s) should I use? jQuery/JavaScript can occur in JSP, HTML, JS, Typescript files. But plugin.xml does not have any defined type for JS or typescript.

At the moment I left out the language attribute, but then my inspection is called in JSPs 3 times (for JSP_FILE, JSP_TEMPLATE, JSP_JAVA_DECLARATIONS) and therefore I have 3 registered problems.

<localInspection enabledByDefault="true" level="ERROR"
displayName="Do not use jQuery selectors"
implementationClass="net.chrono24.intellij.codequality.inspection.text.NoJQuerySelectorInspection"
/>
class NoJQuerySelectorInspection : LocalInspectionTool() {
companion object {
val JQ_PATTERN: Pattern = Pattern.compile("\\$\\([^)]+\\)")
}
override fun checkFile(file: PsiFile, manager: InspectionManager, isOnTheFly: Boolean): Array<ProblemDescriptor>? {
val matcher = JQ_PATTERN.matcher(file.text)

if (matcher.find()) {
val problemDescriptor = manager.createProblemDescriptor(
file, TextRange(matcher.start(), matcher.end()), "Do not use jQuery: #ref", GENERIC_ERROR_OR_WARNING, true
)

return arrayOf(problemDescriptor)
}

return null
}

}
4 comments
Comment actions Permalink

Hi Martin,

You should register it in the language of the inspected element. I suggest inspecting the PSI tree with https://plugins.jetbrains.com/docs/intellij/explore-api.html#31-use-internal-mode-and-psiviewer to understand how the code structure is built and what are the languages of specific elements.

Also, it seems you need to implement LocalInspectionTool.buildVisitor(ProblemsHolder, boolean) method, not checkFile().

0
Comment actions Permalink

Hi Karol,

thanks that got me a step closer.

My first error was what I missed the JavaScript plugin, which I now have added.

platformPlugins =com.intellij.jsp, JavaScript

Then I switched from checkFile() to buildVisitor()

override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : PsiElementVisitor() {
override fun visitElement(element: PsiElement) {
if (element.text == "$") {
println(element.javaClass)
}

This code and the suggested PSI viewer showed me that I should care about com.intellij.lang.javascript.psi.impl.JSReferenceExpression.

But if I try that

if (element is JSReferenceExpression)

I get an java.lang.NoClassDefFoundError: com/intellij/lang/javascript/psi/JSReferenceExpression

I also tried to use a JSElementVisitor which would be much nicer, with the same result: java.lang.NoClassDefFoundError: com/intellij/lang/javascript/psi/JSElementVisitor

override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return object : JSElementVisitor() {
override fun visitJSReferenceExpression(node: JSReferenceExpression?) {

So how can I add the JS classes available in the plugin classpath?

0
Comment actions Permalink

Hi,

Gradle dependency on the JavaScript plugin is just one part of defining dependency.

You should also define dependency in plugin.xml file according to the docs:
https://plugins.jetbrains.com/docs/intellij/plugin-dependencies.html#3-dependency-declaration-in-pluginxml

0
Comment actions Permalink

Thanks Karol for your help, that was the missing part. Now everything works properly.

(I thought, that the dependencies would be generated by the patchPluginXml based on the platformPlugins attribute.)

0

Please sign in to leave a comment.