Skip to content

Parser: Detect javascript_tag and javascript_include_tag helpers#1374

Merged
marcoroth merged 5 commits intomainfrom
javascript-tag-helpers
Mar 18, 2026
Merged

Parser: Detect javascript_tag and javascript_include_tag helpers#1374
marcoroth merged 5 commits intomainfrom
javascript-tag-helpers

Conversation

@marcoroth
Copy link
Owner

@marcoroth marcoroth commented Mar 13, 2026

This pull request allows the parser to be able to detect and transform the javascript_tag and javascript_include_tag helpers using the action_view_helpers parser option.

For example:

<%= javascript_tag do %>
  alert("Hello")
<% end %>

Gets parsed as:

@ DocumentNode (location: (1:0)-(4:0))
└── children: (2 items)
    ├── @ HTMLElementNode (location: (1:0)-(3:9))
       ├── open_tag:
          └── @ ERBOpenTagNode (location: (1:0)-(1:24))
              ├── tag_opening: "<%=" (location: (1:0)-(1:3))
              ├── content: " javascript_tag do " (location: (1:3)-(1:22))
              ├── tag_closing: "%>" (location: (1:22)-(1:24))
              ├── tag_name: "script" (location: (1:4)-(1:18))
              └── children: []
       
       ├── tag_name: "script" (location: (1:4)-(1:18))├── body: (1 item)
          └── @ LiteralNode (location: (1:24)-(3:0))
              └── content: "\n  alert(\"Hello\")\n"
       
       ├── close_tag:
          └── @ ERBEndNode (location: (3:0)-(3:9))
              ├── tag_opening: "<%" (location: (3:0)-(3:2))
              ├── content: " end " (location: (3:2)-(3:7))
              └── tag_closing: "%>" (location: (3:7)-(3:9))
       
       ├── is_void: false
       └── element_source: "ActionView::Helpers::JavaScriptHelper#javascript_tag"
    
    └── @ HTMLTextNode (location: (3:9)-(4:0))
        └── content: "\n"

This pull request also updates the rewriters to be able to rewrite from/to the javascript_tag syntax. The above example can be transformed to this and back:

<script>
  alert('Hello')
</script>

And for javascript_include_tag, the following:

<%= javascript_include_tag "common.javascript", "/elsewhere/cools" %>

gets transformed to:

<script src="<%= javascript_path("common.javascript") %>"></script>
<script src="<%= javascript_path("/elsewhere/cools") %>"></script>

Follow up on #1122
Follow up on #1354

Fixes #991

@marcoroth marcoroth changed the title Parser: Support for javascript_tag and javascript_include_tag Parser: Detect javascript_tag and javascript_include_tag helpers Mar 18, 2026
@marcoroth marcoroth marked this pull request as ready for review March 18, 2026 13:59
@pkg-pr-new
Copy link

pkg-pr-new bot commented Mar 18, 2026

npx https://pkg.pr.new/@herb-tools/formatter@1374
npx https://pkg.pr.new/@herb-tools/language-server@1374
npx https://pkg.pr.new/@herb-tools/linter@1374

commit: 55409f6

@github-actions
Copy link

github-actions bot commented Mar 18, 2026

🌿 Interactive Playground and Documentation Preview

A preview deployment has been built for this pull request. Try out the changes live in the interactive playground:


🌱 Grown from commit 55409f6


✅ Preview deployment has been cleaned up.

@marcoroth marcoroth merged commit d68a879 into main Mar 18, 2026
30 of 31 checks passed
@marcoroth marcoroth deleted the javascript-tag-helpers branch March 18, 2026 14:20
marcoroth pushed a commit that referenced this pull request Mar 21, 2026
closes #543

handles three things
1. html: `<script>` tags
2. erb: Rails javascript helpers, i.e. `javascript_tag`,
`javascript_include_tag`, ~and `javascript_pack_tag`~
3. erb: Rails tag helpers, i.e. `tag.script`

uses #1374 to handle both `<script>` and `javascript_tag` helpers via
`BaseRuleVisitor#visitHTMLElementNode`.

> [!NOTE]
> Does not handle `nil` values, e.g. `tag.script nonce: nil` based on
the specs of the inspiration. If wanted, we can add more specs and
handlers.
marcoroth added a commit that referenced this pull request Mar 21, 2026
This pull request allows the parser to be able to detect and transform
the `image_tag` helper using the `action_view_helpers` parser option.

For example:
```html+erb
<%= image_tag image_path("picture.png"), class: "image" %>
```

Gets parsed as:

```js
@ DocumentNode (location: (1:0)-(1:58))
└── children: (1 item)
    └── @ HTMLElementNode (location: (1:0)-(1:58))
        ├── open_tag:
        │   └── @ ERBOpenTagNode (location: (1:0)-(1:58))
        │       ├── tag_opening: "<%=" (location: (1:0)-(1:3))
        │       ├── content: " image_tag image_path("picture.png"), class: "image" " (location: (1:3)-(1:56))
        │       ├── tag_closing: "%>" (location: (1:56)-(1:58))
        │       ├── tag_name: "img" (location: (1:4)-(1:13))
        │       └── children: (2 items)
        │           ├── @ HTMLAttributeNode (location: (1:14)-(1:39))
        │           │   ├── name:
        │           │   │   └── @ HTMLAttributeNameNode (location: (1:14)-(1:39))
        │           │   │       └── children: (1 item)
        │           │   │           └── @ LiteralNode (location: (1:14)-(1:39))
        │           │   │               └── content: "src"
        │           │   │
        │           │   ├── equals: ":" (location: (1:14)-(1:39))
        │           │   └── value:
        │           │       └── @ HTMLAttributeValueNode (location: (1:14)-(1:39))
        │           │           ├── open_quote: ∅
        │           │           ├── children: (1 item)
        │           │           │   └── @ RubyLiteralNode (location: (1:14)-(1:39))
        │           │           │       └── content: "image_path(\"picture.png\")"
        │           │           │
        │           │           ├── close_quote: ∅
        │           │           └── quoted: false
        │           │
        │           └── @ HTMLAttributeNode (location: (1:41)-(1:48))
        │               ├── name:
        │               │   └── @ HTMLAttributeNameNode (location: (1:41)-(1:48))
        │               │       └── children: (1 item)
        │               │           └── @ LiteralNode (location: (1:41)-(1:48))
        │               │               └── content: "class"
        │               │
        │               ├── equals: "=" (location: (1:41)-(1:48))
        │               └── value:
        │                   └── @ HTMLAttributeValueNode (location: (1:41)-(1:48))
        │                       ├── open_quote: """ (location: (1:41)-(1:48))
        │                       ├── children: (1 item)
        │                       │   └── @ LiteralNode (location: (1:41)-(1:48))
        │                       │       └── content: "image"
        │                       │
        │                       ├── close_quote: """ (location: (1:48)-(1:48))
        │                       └── quoted: true
        │
        ├── tag_name: "img" (location: (1:4)-(1:13))
        ├── body: []
        ├── close_tag: ∅
        ├── is_void: true
        └── element_source: "ActionView::Helpers::AssetTagHelper#image_tag"
```

This pull request also updates the rewriters to be able to rewrite
from/to the `image_path` syntax. The above example can be transformed to
this and back:

```html+erb
<img src="<%= image_path("picture.png") %>" class="image" />
```

Follow up on #1122 
Follow up on #1354 
Follow up on #1374
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parser: Link within a javascript_tag block produces a parser error

1 participant