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
}

}
0
4 comments

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

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

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

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.