Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for aurelia 2 project detection #42

Closed
Closed
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
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ Features:
* Syntax highlighting in `${}` interpolations
* Controller properties completion and navigation
* New project generation via aurelia-cli
* Supports Aurelia 1 and 2

Either `aurelia-framework.js`, `aurelia-bootstrapper.js` or `aurelia-core.js` must be present in the project sources
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, we still need to keep old behaviour for very old projects.

or attached libraries
Either `aurelia` (v2), or `aurelia-cli` (v1) must be present in the project npm dependencies

## Contributing
### Prerequisites
* JDK version 17 or later suggested

### Running the plugin
In order to test your plugin use the [runIde](https://plugins.jetbrains.com/docs/intellij/configuring-plugin-project.html#run-ide-task) Gradle. This will launch an instance of intellij with the plugin loaded.
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ repositories {
}

intellij {
pluginName = 'AureliaStorm'
pluginName = 'AureliaStorm Community'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the reason to change plugin name?

version = 'IU-LATEST-EAP-SNAPSHOT'
plugins = ['JavaScript']
}

version '1.0.231'
version '1.1.2'

patchPluginXml {
sinceBuild = "231.0"
untilBuild = "231.*"
untilBuild = "233.*"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, we cannot sure that the plugin will be compatible with 233 version.

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,16 @@ import com.intellij.xml.impl.BasicXmlAttributeDescriptor
*/
class AttributesProvider : XmlAttributeDescriptorsProvider {
override fun getAttributeDescriptors(xmlTag: XmlTag): Array<XmlAttributeDescriptor> = arrayOf(
AttributeDescriptor(Aurelia.REPEAT_FOR),
AttributeDescriptor(Aurelia.VIRTUAL_REPEAT_FOR),
AttributeDescriptor(Aurelia.AURELIA_APP),
AttributeDescriptor("if.bind"),
AttributeDescriptor("show.bind")
AttributeDescriptor(Aurelia.REPEAT_FOR),
AttributeDescriptor(Aurelia.VIRTUAL_REPEAT_FOR),
AttributeDescriptor(Aurelia.AURELIA_APP)
)

override fun getAttributeDescriptor(name: String, xmlTag: XmlTag): XmlAttributeDescriptor? {
for (attr in Aurelia.INJECTABLE) {
if (name.endsWith(".$attr")) {
val attrName = name.substring(0, name.length - attr.length - 1)
if ("if" == attrName || "show" == attrName) {
if ("if" == attrName || "show" == attrName || "switch" == attrName) {
return AttributeDescriptor(name)
}
val descriptor = xmlTag.descriptor
Expand All @@ -34,10 +32,13 @@ class AttributesProvider : XmlAttributeDescriptorsProvider {
}
}
}
return if (Aurelia.REPEAT_FOR == name || Aurelia.VIRTUAL_REPEAT_FOR == name || Aurelia.AURELIA_APP == name) AttributeDescriptor(name) else null
return if (Aurelia.REPEAT_FOR == name || Aurelia.VIRTUAL_REPEAT_FOR == name || Aurelia.AURELIA_APP == name || Aurelia.CASE == name || Aurelia.REF == name) AttributeDescriptor(
name
) else null
}

private class AttributeDescriptor(private val name: String) : BasicXmlAttributeDescriptor(), PsiPresentableMetaData {
private class AttributeDescriptor(private val name: String) : BasicXmlAttributeDescriptor(),
PsiPresentableMetaData {
override fun getIcon() = Aurelia.ICON

override fun getTypeName(): String? = null
Expand Down
50 changes: 34 additions & 16 deletions src/main/kotlin/com/github/denofevil/aurelia/Aurelia.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.github.denofevil.aurelia

import com.intellij.json.psi.JsonFile
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.openapi.util.IconLoader
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.search.FilenameIndex
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.json.psi.JsonObject
import com.intellij.psi.PsiManager

/**
* @author Dennis.Ushakov
Expand All @@ -19,21 +21,37 @@ object Aurelia {
const val REPEAT_FOR = "repeat.for"
const val VIRTUAL_REPEAT_FOR = "virtual-repeat.for"
const val AURELIA_APP = "aurelia-app"

private val AURELIA_DETECTOR_FILES = listOf(
// Aurelia is included with with module loader (from jspm_packages when using JSPM) or module bundler (from node_modules when using Webpack)
"aurelia-framework.js",
// project generated by aurelia-cli
"aurelia-bootstrapper.js",
"aurelia-bootstrapper.d.ts",
// project bootstrapped with script tag (contains aurelia-framework and other essential Aurelia modules)
"aurelia-core.js"
)
const val CASE = "case"
const val REF = "ref"

fun present(project: Project) = CachedValuesManager.getManager(project).getCachedValue(project) {
CachedValueProvider.Result.create(
AURELIA_DETECTOR_FILES.any {
FilenameIndex.getFilesByName(project, it, GlobalSearchScope.allScope(project)).isNotEmpty()
}, VirtualFileManager.VFS_STRUCTURE_MODIFICATIONS, ProjectRootModificationTracker.getInstance(project))
val aureliaLoaded = hasDependency(project)
CachedValueProvider.Result
.create(aureliaLoaded, VirtualFileManager.VFS_STRUCTURE_MODIFICATIONS, ProjectRootModificationTracker.getInstance(project))
}!!

private fun hasDependency(project: Project): Boolean {
var hasDependency = false

VfsUtilCore.iterateChildrenRecursively(project.baseDir, null) { virtualFile ->
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vfs traversing is very expensive operation. Please check methods of com.intellij.javascript.nodejs.packageJson.PackageJsonFileManager, it provide high-level API to check package.json deps.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment is still relevant. VFS processing can significantly degrade performance, especially for big projects.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moreover, it looks like all usages of the method have a proper context psi element, so the best solution could be to traverse top to package.json and check its dependencies.

if (!virtualFile.isDirectory && virtualFile.name == "package.json") {
val jsonFile = PsiManager.getInstance(project).findFile(virtualFile)
val jsonObject = (jsonFile as? JsonFile)?.topLevelValue as? JsonObject

jsonObject?.findProperty("dependencies")?.let { dependenciesProp ->
val dependenciesObject = dependenciesProp.value as? JsonObject
val aureliaDependency = dependenciesObject?.findProperty("aurelia")
val aureliaCliDependency = dependenciesObject?.findProperty("aurelia-cli")
if (aureliaCliDependency != null || aureliaDependency != null) {
hasDependency = true
return@iterateChildrenRecursively false
}
}
}

true
}

return hasDependency
}
}
18 changes: 11 additions & 7 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
<idea-plugin>
<name>AureliaStorm</name>
<id>AureliaStorm</id>
<name>AureliaStorm Community</name>
<id>AureliaStormCommunity</id>
<idea-version since-build="191.3684" until-build="201.0000"/>
<vendor email="dennis.ushakov@jetbrains.com" url="https://github.com/denofevil/AureliaStorm">Dennis Ushakov</vendor>
<vendor email="rustaddicts@gmail.com" url="https://github.com/CollinHerber/AureliaStorm">Collin Herber</vendor>
<description><![CDATA[
This plugin is a fork from <a href="https://plugins.jetbrains.com/plugin/8567-aureliastorm">AureliaStorm</a>
This plugin brings support for <a href="https://aurelia.io/">Aurelia</a> framework to the IntelliJ platform
Features:
<ul>
<li>Supports Aurelia 1 and 2</li>
<li>Code insight for specific Aurelia attributes (such as <code>*.bind</code> or <code>*.trigger</code>)</li>
<li>Syntax highlighting in <code>${}</code> interpolations</li>
<li>Controller properties completion and navigation</li>
</ul>
Either <code>aurelia-framework.js</code>, <code>aurelia-bootstrapper.js</code> or <code>aurelia-core.js</code> must be present in the project sources
or attached libraries
Either aurelia or aurelia-cli must be included as a dependency in package.json.
]]></description>
<depends>com.intellij.modules.lang</depends>
<depends>JavaScript</depends>
Expand All @@ -24,11 +25,14 @@
<pattern type="xml">xmlAttributeValue("aurelia-app", "data-aurelia-app")</pattern>
</psi.referenceProvider>
<javascript.rename.extension implementation="com.github.denofevil.aurelia.RenameExtension"/>
<lang.inspectionSuppressor language="JavaScript" implementationClass="com.github.denofevil.aurelia.InspectionSuppressor" order="first"/>
<lang.inspectionSuppressor language="JavaScript"
implementationClass="com.github.denofevil.aurelia.InspectionSuppressor"
order="first"/>

<directoryProjectGenerator
implementation="com.github.denofevil.aurelia.cli.ProjectGenerator"/> <!-- works in WebStorm and other SmallIDEs -->
<projectTemplatesFactory implementation="com.github.denofevil.aurelia.cli.ProjectTemplateFactory"/> <!-- works in IntelliJ IDEA -->
<projectTemplatesFactory
implementation="com.github.denofevil.aurelia.cli.ProjectTemplateFactory"/> <!-- works in IntelliJ IDEA -->
</extensions>
<extensions defaultExtensionNs="JavaScript">
<frameworkIndexingHandler implementation="com.github.denofevil.aurelia.FrameworkHandler"/>
Expand Down