@herb-tools/rewriter 0.9.2 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,5 +4,5 @@ import type { Node } from "@herb-tools/core";
4
4
  export declare class ActionViewTagHelperToHTMLRewriter extends ASTRewriter {
5
5
  get name(): string;
6
6
  get description(): string;
7
- rewrite<T extends Node>(node: T, _context: RewriteContext): T;
7
+ rewrite<T extends Node>(node: T, context: RewriteContext): T;
8
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herb-tools/rewriter",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "Rewriter system for transforming HTML+ERB AST nodes and formatted strings",
5
5
  "license": "MIT",
6
6
  "homepage": "https://herb-tools.dev",
@@ -38,12 +38,12 @@
38
38
  }
39
39
  },
40
40
  "dependencies": {
41
- "@herb-tools/core": "0.9.2",
42
- "@herb-tools/tailwind-class-sorter": "0.9.2",
41
+ "@herb-tools/core": "0.9.3",
42
+ "@herb-tools/tailwind-class-sorter": "0.9.3",
43
43
  "tinyglobby": "^0.2.15"
44
44
  },
45
45
  "devDependencies": {
46
- "@herb-tools/printer": "0.9.2"
46
+ "@herb-tools/printer": "0.9.3"
47
47
  },
48
48
  "files": [
49
49
  "package.json",
@@ -1,5 +1,5 @@
1
1
  import { Visitor, Location, HTMLOpenTagNode, HTMLCloseTagNode, HTMLElementNode, HTMLAttributeValueNode, WhitespaceNode, ERBContentNode } from "@herb-tools/core"
2
- import { isHTMLAttributeNode, isERBOpenTagNode, isRubyLiteralNode, isRubyHTMLAttributesSplatNode, createSyntheticToken } from "@herb-tools/core"
2
+ import { isHTMLAttributeNode, isERBOpenTagNode, isRubyLiteralNode, isRubyHTMLAttributesSplatNode, isWhitespaceNode, createSyntheticToken } from "@herb-tools/core"
3
3
 
4
4
  import { ASTRewriter } from "../ast-rewriter.js"
5
5
  import { asMutable } from "../mutable.js"
@@ -17,6 +17,45 @@ function createWhitespaceNode(): WhitespaceNode {
17
17
  }
18
18
 
19
19
  class ActionViewTagHelperToHTMLVisitor extends Visitor {
20
+ private shallow: boolean
21
+ private includeBody: boolean
22
+
23
+ constructor(options: { shallow?: boolean; includeBody?: boolean } = {}) {
24
+ super()
25
+ this.shallow = options.shallow ?? false
26
+ this.includeBody = options.includeBody ?? true
27
+ }
28
+
29
+ visitHTMLOpenTagNode(node: HTMLOpenTagNode): void {
30
+ const newChildren: Node[] = []
31
+
32
+ for (let index = 0; index < node.children.length; index++) {
33
+ const child = node.children[index]
34
+
35
+ if (isHTMLAttributeNode(child)) {
36
+ if (child.equals && child.equals.value !== "=") {
37
+ asMutable(child).equals = createSyntheticToken("=")
38
+ }
39
+
40
+ if (child.value) {
41
+ this.transformAttributeValue(child.value)
42
+ }
43
+
44
+ const previous = index > 0 ? node.children[index - 1] : null
45
+
46
+ if (!previous || !isWhitespaceNode(previous)) {
47
+ newChildren.push(createWhitespaceNode())
48
+ }
49
+ }
50
+
51
+ newChildren.push(child)
52
+ }
53
+
54
+ asMutable(node).children = newChildren
55
+
56
+ this.visitChildNodes(node)
57
+ }
58
+
20
59
  visitHTMLElementNode(node: HTMLElementNode): void {
21
60
  if (!node.element_source) {
22
61
  this.visitChildNodes(node)
@@ -104,7 +143,9 @@ class ActionViewTagHelperToHTMLVisitor extends Visitor {
104
143
 
105
144
  asMutable(node).element_source = "HTML"
106
145
 
107
- if (node.body) {
146
+ if (!this.includeBody) {
147
+ asMutable(node).body = []
148
+ } else if (node.body) {
108
149
  asMutable(node).body = node.body.map(child => {
109
150
  if (isRubyLiteralNode(child)) {
110
151
  return new ERBContentNode({
@@ -120,7 +161,10 @@ class ActionViewTagHelperToHTMLVisitor extends Visitor {
120
161
  })
121
162
  }
122
163
 
123
- this.visit(child)
164
+ if (!this.shallow) {
165
+ this.visit(child)
166
+ }
167
+
124
168
  return child
125
169
  })
126
170
  }
@@ -150,12 +194,12 @@ class ActionViewTagHelperToHTMLVisitor extends Visitor {
150
194
  })
151
195
 
152
196
  mutableValue.children = newChildren
197
+ }
153
198
 
154
- if (!value.quoted) {
155
- mutableValue.quoted = true
156
- mutableValue.open_quote = createSyntheticToken('"')
157
- mutableValue.close_quote = createSyntheticToken('"')
158
- }
199
+ if (!value.quoted) {
200
+ mutableValue.quoted = true
201
+ mutableValue.open_quote = createSyntheticToken('"')
202
+ mutableValue.close_quote = createSyntheticToken('"')
159
203
  }
160
204
  }
161
205
  }
@@ -169,8 +213,8 @@ export class ActionViewTagHelperToHTMLRewriter extends ASTRewriter {
169
213
  return "Converts ActionView tag helpers to raw HTML elements"
170
214
  }
171
215
 
172
- rewrite<T extends Node>(node: T, _context: RewriteContext): T {
173
- const visitor = new ActionViewTagHelperToHTMLVisitor()
216
+ rewrite<T extends Node>(node: T, context: RewriteContext): T {
217
+ const visitor = new ActionViewTagHelperToHTMLVisitor({ shallow: context.shallow, includeBody: context.includeBody })
174
218
 
175
219
  visitor.visit(node)
176
220
 
@@ -124,9 +124,10 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
124
124
  const isAnchor = tagName.value === "a"
125
125
  const isTurboFrame = tagName.value === "turbo-frame"
126
126
  const isScript = tagName.value === "script"
127
+ const isImg = tagName.value === "img"
127
128
  const attributes = openTag.children.filter(child => !isWhitespaceNode(child))
128
- const hasSrcAttribute = isScript && attributes.some(child => isHTMLAttributeNode(child) && getStaticAttributeName(child.name!) === "src")
129
- const { attributes: attributesString, href, id, src } = serializeAttributes(attributes, { extractHref: isAnchor, extractId: isTurboFrame, extractSrc: isScript })
129
+ const hasSrcAttribute = (isScript || isImg) && attributes.some(child => isHTMLAttributeNode(child) && getStaticAttributeName(child.name!) === "src")
130
+ const { attributes: attributesString, href, id, src } = serializeAttributes(attributes, { extractHref: isAnchor, extractId: isTurboFrame, extractSrc: isScript || isImg })
130
131
  const hasBody = node.body && node.body.length > 0 && !node.is_void
131
132
  const isInlineContent = hasBody && isTextOnlyBody(node.body)
132
133
 
@@ -145,6 +146,9 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
145
146
  } else if (isScript) {
146
147
  content = this.buildJavascriptTagContent(node, attributesString, isInlineContent)
147
148
  elementSource = "ActionView::Helpers::JavaScriptHelper#javascript_tag"
149
+ } else if (isImg) {
150
+ content = this.buildImageTagContent(attributesString, src)
151
+ elementSource = "ActionView::Helpers::AssetTagHelper#image_tag"
148
152
  } else {
149
153
  content = this.buildTagContent(tagName.value, node, attributesString, isInlineContent)
150
154
  elementSource = "ActionView::Helpers::TagHelper#tag"
@@ -165,7 +169,7 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
165
169
  asMutable(node).element_source = elementSource
166
170
 
167
171
  const isInlineLiteralContent = isScript && hasBody && node.body.length === 1 && isLiteralNode(node.body[0]) && !node.body[0].content.includes("\n")
168
- const isInlineForm = isInlineContent || isInlineLiteralContent || (isTurboFrame && !hasBody) || (isScript && hasSrcAttribute)
172
+ const isInlineForm = isInlineContent || isInlineLiteralContent || (isTurboFrame && !hasBody) || (isScript && hasSrcAttribute) || isImg
169
173
 
170
174
  if (node.is_void) {
171
175
  asMutable(node).close_tag = null
@@ -270,6 +274,17 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
270
274
  return argString ? ` javascript_include_tag ${argString} ` : ` javascript_include_tag `
271
275
  }
272
276
 
277
+ private buildImageTagContent(attributes: string, source: string | null): string {
278
+ const args: string[] = []
279
+
280
+ if (source) args.push(source)
281
+ if (attributes) args.push(attributes)
282
+
283
+ const argString = args.join(", ")
284
+
285
+ return argString ? ` image_tag ${argString} ` : ` image_tag `
286
+ }
287
+
273
288
  private buildLinkToContent(node: HTMLElementNode, attribute: string, href: string | null, isInlineContent: boolean): string {
274
289
  const args: string[] = []
275
290
 
@@ -301,7 +316,7 @@ export class HTMLToActionViewTagHelperRewriter extends ASTRewriter {
301
316
  }
302
317
 
303
318
  get description(): string {
304
- return "Converts raw HTML elements to ActionView tag helpers (tag.*, turbo_frame_tag, javascript_tag, javascript_include_tag)"
319
+ return "Converts raw HTML elements to ActionView tag helpers (tag.*, turbo_frame_tag, javascript_tag, javascript_include_tag, image_tag)"
305
320
  }
306
321
 
307
322
  rewrite<T extends Node>(node: T, _context: RewriteContext): T {