@herb-tools/rewriter 0.9.1 → 0.9.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@herb-tools/rewriter",
3
- "version": "0.9.1",
3
+ "version": "0.9.2",
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.1",
42
- "@herb-tools/tailwind-class-sorter": "0.9.1",
41
+ "@herb-tools/core": "0.9.2",
42
+ "@herb-tools/tailwind-class-sorter": "0.9.2",
43
43
  "tinyglobby": "^0.2.15"
44
44
  },
45
45
  "devDependencies": {
46
- "@herb-tools/printer": "0.9.1"
46
+ "@herb-tools/printer": "0.9.2"
47
47
  },
48
48
  "files": [
49
49
  "package.json",
@@ -166,7 +166,7 @@ export class ActionViewTagHelperToHTMLRewriter extends ASTRewriter {
166
166
  }
167
167
 
168
168
  get description(): string {
169
- return "Converts ActionView tag helpers (tag.*, content_tag, link_to, turbo_frame_tag) to raw HTML elements"
169
+ return "Converts ActionView tag helpers to raw HTML elements"
170
170
  }
171
171
 
172
172
  rewrite<T extends Node>(node: T, _context: RewriteContext): T {
@@ -35,14 +35,16 @@ interface SerializedAttributes {
35
35
  attributes: string
36
36
  href: string | null
37
37
  id: string | null
38
+ src: string | null
38
39
  }
39
40
 
40
- function serializeAttributes(children: Node[], options: { extractHref?: boolean, extractId?: boolean } = {}): SerializedAttributes {
41
+ function serializeAttributes(children: Node[], options: { extractHref?: boolean, extractId?: boolean, extractSrc?: boolean } = {}): SerializedAttributes {
41
42
  const regular: string[] = []
42
43
  const prefixed: Map<string, string[]> = new Map()
43
44
 
44
45
  let href: string | null = null
45
46
  let id: string | null = null
47
+ let src: string | null = null
46
48
 
47
49
  for (const child of children) {
48
50
  if (!isHTMLAttributeNode(child)) continue
@@ -62,6 +64,11 @@ function serializeAttributes(children: Node[], options: { extractHref?: boolean,
62
64
  continue
63
65
  }
64
66
 
67
+ if (options.extractSrc && name === "src") {
68
+ src = value
69
+ continue
70
+ }
71
+
65
72
  const dataMatch = name.match(/^(data|aria)-(.+)$/)
66
73
 
67
74
  if (dataMatch) {
@@ -83,7 +90,7 @@ function serializeAttributes(children: Node[], options: { extractHref?: boolean,
83
90
  parts.push(`${prefix}: { ${entries.join(", ")} }`)
84
91
  }
85
92
 
86
- return { attributes: parts.join(", "), href, id }
93
+ return { attributes: parts.join(", "), href, id, src }
87
94
  }
88
95
 
89
96
  function isTextOnlyBody(body: Node[]): boolean {
@@ -116,8 +123,10 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
116
123
 
117
124
  const isAnchor = tagName.value === "a"
118
125
  const isTurboFrame = tagName.value === "turbo-frame"
126
+ const isScript = tagName.value === "script"
119
127
  const attributes = openTag.children.filter(child => !isWhitespaceNode(child))
120
- const { attributes: attributesString, href, id } = serializeAttributes(attributes, { extractHref: isAnchor, extractId: isTurboFrame })
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 })
121
130
  const hasBody = node.body && node.body.length > 0 && !node.is_void
122
131
  const isInlineContent = hasBody && isTextOnlyBody(node.body)
123
132
 
@@ -130,6 +139,12 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
130
139
  } else if (isTurboFrame) {
131
140
  content = this.buildTurboFrameTagContent(node, attributesString, id, isInlineContent)
132
141
  elementSource = "Turbo::FramesHelper#turbo_frame_tag"
142
+ } else if (isScript && hasSrcAttribute) {
143
+ content = this.buildJavascriptIncludeTagContent(attributesString, src)
144
+ elementSource = "ActionView::Helpers::AssetTagHelper#javascript_include_tag"
145
+ } else if (isScript) {
146
+ content = this.buildJavascriptTagContent(node, attributesString, isInlineContent)
147
+ elementSource = "ActionView::Helpers::JavaScriptHelper#javascript_tag"
133
148
  } else {
134
149
  content = this.buildTagContent(tagName.value, node, attributesString, isInlineContent)
135
150
  elementSource = "ActionView::Helpers::TagHelper#tag"
@@ -149,7 +164,8 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
149
164
  asMutable(node).open_tag = erbOpenTag
150
165
  asMutable(node).element_source = elementSource
151
166
 
152
- const isInlineForm = isInlineContent || (isTurboFrame && !hasBody)
167
+ 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)
153
169
 
154
170
  if (node.is_void) {
155
171
  asMutable(node).close_tag = null
@@ -224,6 +240,36 @@ class HTMLToActionViewTagHelperVisitor extends Visitor {
224
240
  return argString ? ` turbo_frame_tag ${argString} do ` : ` turbo_frame_tag do `
225
241
  }
226
242
 
243
+ private buildJavascriptTagContent(node: HTMLElementNode, attributes: string, isInlineContent: boolean): string {
244
+ const bodyNode = node.body?.[0]
245
+ const isInlineLiteral = bodyNode && isLiteralNode(bodyNode) && !bodyNode.content.includes("\n")
246
+ const isInlineText = isInlineContent && isHTMLTextNode(bodyNode)
247
+
248
+ if (isInlineText || isInlineLiteral) {
249
+ const textContent = isHTMLTextNode(bodyNode) ? bodyNode.content : bodyNode.content
250
+ const args = [`"${textContent}"`]
251
+
252
+ if (attributes) args.push(attributes)
253
+
254
+ return ` javascript_tag ${args.join(", ")} `
255
+ }
256
+
257
+ return attributes
258
+ ? ` javascript_tag ${attributes} do `
259
+ : ` javascript_tag do `
260
+ }
261
+
262
+ private buildJavascriptIncludeTagContent(attributes: string, source: string | null): string {
263
+ const args: string[] = []
264
+
265
+ if (source) args.push(source)
266
+ if (attributes) args.push(attributes)
267
+
268
+ const argString = args.join(", ")
269
+
270
+ return argString ? ` javascript_include_tag ${argString} ` : ` javascript_include_tag `
271
+ }
272
+
227
273
  private buildLinkToContent(node: HTMLElementNode, attribute: string, href: string | null, isInlineContent: boolean): string {
228
274
  const args: string[] = []
229
275
 
@@ -255,7 +301,7 @@ export class HTMLToActionViewTagHelperRewriter extends ASTRewriter {
255
301
  }
256
302
 
257
303
  get description(): string {
258
- return "Converts raw HTML elements to ActionView tag helpers (tag.*, turbo_frame_tag)"
304
+ return "Converts raw HTML elements to ActionView tag helpers (tag.*, turbo_frame_tag, javascript_tag, javascript_include_tag)"
259
305
  }
260
306
 
261
307
  rewrite<T extends Node>(node: T, _context: RewriteContext): T {