Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
8710b7e
WIP
inxilpro Jun 19, 2025
022d8f9
wip
inxilpro Jun 19, 2025
9597421
Update AlpineTargetReferenceContributor.kt
inxilpro Jun 19, 2025
0d39913
Update CLAUDE.md
inxilpro Jun 19, 2025
be2233b
Some clean up
inxilpro Jun 19, 2025
e9a4a93
Fix x-merge
inxilpro Jun 19, 2025
2a1f131
Merge branch 'main' into alpine-ajax
inxilpro Jun 19, 2025
aee17c3
Merge branch 'main' into alpine-ajax
inxilpro Jun 19, 2025
0c8333e
Merge branch 'main' into alpine-ajax
inxilpro Jun 20, 2025
a55ae1c
Merge branch 'main' into alpine-ajax
inxilpro Jun 20, 2025
f9555b6
Fix $ajax
inxilpro Jun 20, 2025
0a180dc
wip
inxilpro Jun 20, 2025
b8fbf6a
wip
inxilpro Jun 20, 2025
4528c83
wip
inxilpro Jun 20, 2025
5f0d10e
Move wizard logic to plugin
inxilpro Jun 20, 2025
1dc1c81
Restructuring
inxilpro Jun 20, 2025
f850bde
defaults
inxilpro Jun 20, 2025
db18ea3
Clean up plugin system
inxilpro Jun 20, 2025
3a93f6e
wip
inxilpro Jun 20, 2025
09c321a
Better directive/prefix handling
inxilpro Jun 20, 2025
730ed4a
Fix how prefixes/etc are collected
inxilpro Jun 20, 2025
236cf80
Just use canBePrefix
inxilpro Jun 20, 2025
38c0281
Fix Companion calls
inxilpro Jun 20, 2025
fb57b60
Remove dead getValidAttributesWithInfo
inxilpro Jun 20, 2025
bbcb9be
getInstance() -> instance
inxilpro Jun 20, 2025
9d23b6e
Change settings file name
inxilpro Jun 20, 2025
923e6d6
New Claude instructions
inxilpro Jun 20, 2025
6e3283d
Better settings
inxilpro Jun 20, 2025
836e899
Update LanguageUtil.kt
inxilpro Jun 20, 2025
61763ef
Better completion contributor handling for plugins
inxilpro Jun 21, 2025
26ddb16
Centralize package.json checks
inxilpro Jun 21, 2025
f508886
Better detection
inxilpro Jun 21, 2025
390b6ea
Bugfix
inxilpro Jun 21, 2025
db82a9e
Add basic alpine-tooltip support
inxilpro Jun 21, 2025
2a61715
Clean up
inxilpro Jun 21, 2025
f476fe3
Fix qodana analysis
inxilpro Jun 21, 2025
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.gradle
.idea
.intellijPlatform
.kotlin
.qodana
build
.DS_Store
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@

## [Unreleased]

### Changed
- Improved support for [alpine-wizard](https://github.com/glhd/alpine-wizard)
- Improved overall performance of plugin

### Added
- Added support for [alpine-ajax](https://alpine-ajax.js.org/)
- Added basic support for [alpine-tooltip](https://github.com/ryangjchandler/alpine-tooltip)
- Added configuration for plugins (enable/disable) when not auto-detected
- Added support for newer IntelliJ platforms
- Added better local PhpStorm testing
- Added better handling of non-HTML file types
- Added new plugin extension system

## [0.6.6] - 2025-06-19

Expand Down
55 changes: 55 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Code Guidelines

- Always use modern idiomatic Kotlin code
- When implementing singletons, prefer `Foo.instance` over `Foo.Companion.instance` or `Foo.getInstance()`
- Only add docblocks and comments when they provide substantive value. Comments should always explain "why" not "what."

## Commands

### Building & Running
- `./gradlew build` - Build the plugin
- `./gradlew buildPlugin` - Assemble plugin ZIP for deployment
- `./gradlew runIde` - Run IntelliJ IDEA with the plugin installed for testing
- `./gradlew runIdeForUiTests` - Run IDE with robot-server for UI testing

### Testing & Verification
- `./gradlew test` - Run unit tests
- `./gradlew check` - Run all checks (tests + verification)
- `./gradlew verifyPlugin` - Validate plugin structure and descriptors
- `./gradlew runPluginVerifier` - Check binary compatibility with target IDEs
- `./gradlew runInspections` - Run Qodana code inspections
- `./gradlew koverReport` - Generate code coverage reports

## Architecture

This is an IntelliJ IDEA plugin that adds Alpine.js support. The plugin provides:

- Auto-completion for Alpine directives (x-data, x-show, x-model, etc.)
- JavaScript language injection in Alpine attributes
- Syntax highlighting within Alpine directives
- Plugin support for third-party alpine plugins

### Plugin Configuration

The plugin is configured via:

- `plugin.xml` - Main plugin manifest defining extensions and dependencies
- `gradle.properties` - Version and platform configuration
- `build.gradle.kts` - Build configuration and dependencies

The plugin requires:

- IntelliJ IDEA 2025.1 or newer
- JavaScript and HtmlTools plugins as dependencies
- Java 21 runtime

### Release Process

1. Update version in `gradle.properties`
2. Update `CHANGELOG.md` Unreleased section with version number
3. Push changes to main branch
4. Create and publish a GitHub release - this triggers automatic publishing to JetBrains Marketplace
2 changes: 0 additions & 2 deletions src/main/kotlin/com/github/inxilpro/intellijalpine/Alpine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,4 @@ import com.intellij.openapi.util.IconLoader
object Alpine {
@JvmField
val ICON = IconLoader.getIcon("/alpineicon.svg", javaClass)

val NAMESPACE = "Alpine.js Plugin"
}

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.github.inxilpro.intellijalpine
package com.github.inxilpro.intellijalpine.attributes

import com.github.inxilpro.intellijalpine.Alpine
import com.intellij.psi.PsiElement
import com.intellij.psi.meta.PsiPresentableMetaData
import com.intellij.psi.xml.XmlTag
Expand Down Expand Up @@ -46,4 +47,4 @@ class AlpineAttributeDescriptor(
override fun getDefaultValue(): String? = null

override fun getEnumeratedValues(): Array<String>? = ArrayUtil.EMPTY_STRING_ARRAY
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.github.inxilpro.intellijalpine
package com.github.inxilpro.intellijalpine.attributes

import com.github.inxilpro.intellijalpine.core.AlpinePluginRegistry

@Suppress("MemberVisibilityCanBePrivate")
class AttributeInfo(val attribute: String) {
private val typeTexts = hashMapOf<String, String>(

private val typeTexts = hashMapOf(
"x-data" to "New Alpine.js component scope",
"x-init" to "Run on initialization",
"x-show" to "Toggles 'display: none'",
Expand Down Expand Up @@ -32,9 +35,6 @@ class AttributeInfo(val attribute: String) {
"x-intersect" to "Bind an intersection observer",
"x-trap" to "Add focus trap",
"x-collapse" to "Collapse element when hidden",
"x-wizard:step" to "Add wizard step",
"x-wizard:if" to "Add wizard condition",
"x-wizard:title" to "Add title to wizard step",
)

val name: String
Expand All @@ -50,40 +50,30 @@ class AttributeInfo(val attribute: String) {
}

@Suppress("ComplexCondition")
fun isAlpine(): Boolean {
return this.isEvent() || this.isBound() || this.isTransition() || this.isDirective() || this.isWizard()
}
fun isAlpine(): Boolean = isDirective() || isPrefixed() || canBePrefix()

fun isEvent(): Boolean {
return "@" == prefix || "x-on:" == prefix
}
fun isEvent(): Boolean = "@" == prefix || "x-on:" == prefix

fun isBound(): Boolean {
return ":" == prefix || "x-bind:" == prefix
}
fun isBound(): Boolean = ":" == prefix || "x-bind:" == prefix

fun isTransition(): Boolean {
return "x-transition:" == prefix
}
fun isTransition(): Boolean = "x-transition:" == prefix

fun isDirective(): Boolean {
return AttributeUtil.directives.contains(name)
}
fun isDirective(): Boolean = AttributeUtil.directives.contains(name)

fun isWizard(): Boolean {
return "x-wizard:" == prefix
}
fun hasValue(): Boolean = "x-cloak" != name && "x-ignore" != name

fun hasValue(): Boolean {
return "x-cloak" != name && "x-ignore" != name
}
fun canBePrefix(): Boolean = AttributeUtil.prefixes.contains(name)

fun canBePrefix(): Boolean {
return "x-bind" == name || "x-transition" == name || "x-on" == name || "x-wizard" == name
}
fun isPrefixed(): Boolean = prefix != ""

@Suppress("ReturnCount")
private fun extractPrefix(): String {
for (prefix in AttributeUtil.prefixes) {
if (attribute.startsWith("$prefix:")) {
return "$prefix:"
}
}

for (eventPrefix in AttributeUtil.eventPrefixes) {
if (attribute.startsWith(eventPrefix)) {
return eventPrefix
Expand All @@ -96,14 +86,6 @@ class AttributeInfo(val attribute: String) {
}
}

if (attribute.startsWith("x-transition:")) {
return "x-transition:"
}

if (attribute.startsWith("x-wizard:")) {
return "x-wizard:"
}

return ""
}

Expand All @@ -121,6 +103,12 @@ class AttributeInfo(val attribute: String) {
return "CSS classes for '$name' transition phase"
}

// First check plugin registry for type text
val pluginTypeText = AlpinePluginRegistry.instance.getTypeText(this)
if (pluginTypeText != null) {
return pluginTypeText
}

return typeTexts.getOrDefault(attribute, "Alpine.js")
}
}
}
Loading
Loading