evc_rails 0.3.0 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a155f85c540ca32801ef3033f92abdc7912a3ff5c533faa19f92b00c774968b
4
- data.tar.gz: 79de2d1b2b3557009c0d9e98f5ade01418ad7e49b61567c2056898ddfe537ea9
3
+ metadata.gz: 176929bf44d50fb5c8e783d6cdd745c02f09d500b59daf5838f7b0a6f2fdda28
4
+ data.tar.gz: 285435052b2267b961ff7b670738abdccca2f9b0ad89ecc7eca8508b81a6ce8f
5
5
  SHA512:
6
- metadata.gz: 1039a2e12cc8f11c8855dd0bafd2abd9de98e61a87f9e2c49fe27f7d40a497d30d6f1b05d4da7bfb8b7eede13b75c33ab67df4cb48fe8ab8de4d825284d52388
7
- data.tar.gz: c73e72e59cd863f513bf07e60675081c3db3255b77090da206ae8652a8e6c15f1b6079641fd1e27b5dbe0b95e71ae45d80a7975b0af2479b5d4e802b9b102a0d
6
+ metadata.gz: aab13dc98534d5888de5756a7cb6ff90e993a882db66f689914d3e68b755f51cc7871f4b1a6b8f59e9a8fe6a99695d7935d584ff8790e3c13f17aa05ca981c78
7
+ data.tar.gz: e71dc0b00125dd83ea4f1c8f4734e756cdbbc38e6d0892121d5274cac47e3ae40432c83de6a29abd9c7bfce0998d6d223a4710e26f302e4c90a623830f9f7515
data/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.2] - 2024-12-19
9
+
10
+ ### Added
11
+
12
+ - **Kebab-case attribute support**: Support for HTML-style kebab-case attributes in addition to snake_case
13
+ - `<Button data-test-id="value" />` converts to `data_test_id: "value"`
14
+ - `<Button aria-label="Click me" />` converts to `aria_label: "Click me"`
15
+ - Works with boolean attributes: `<Button data-disabled aria-hidden />`
16
+ - Supports Ruby expressions: `<Button data-user-id={@user.id} />`
17
+ - Fully backward compatible with existing snake_case attributes
18
+ - Automatically converts kebab-case to snake_case for Ruby compatibility
19
+
20
+ ## [0.3.1] - 2024-12-19
21
+
22
+ ### Fixed
23
+
24
+ - **Robust attribute parsing**: Fixed a bug where complex or nested Ruby expressions (e.g., arrays or hashes with nested braces) in attribute values could cause parsing errors or incorrect output. The attribute parser is now fully robust and handles any valid Ruby expression inside `{...}` for both component and slot attributes.
25
+
8
26
  ## [0.3.0] - 2024-12-19
9
27
 
10
28
  ### Added
data/README.md CHANGED
@@ -64,6 +64,17 @@ $ bundle install
64
64
 
65
65
  The template handler will be automatically registered for `.evc` files.
66
66
 
67
+ ## Syntax Highlighting
68
+
69
+ For the best development experience with EVC files, install the [EVC Language Support](https://github.com/senordelaflor/evc-language-support) extension for VS Code. This extension provides:
70
+
71
+ - **Syntax highlighting** for ERB tags (`<% %>`, `<%= %>`, `<%# %>`)
72
+ - **JSX-like attribute syntax** support (`prop={value}`)
73
+ - **Nested bracket matching** for arrays and hashes
74
+ - **HTML tag completion** via Emmet
75
+ - **Auto-closing pairs** for brackets and ERB tags
76
+ - **Proper folding** for ERB blocks
77
+
67
78
  ## Usage
68
79
 
69
80
  ### Basic Components
@@ -13,7 +13,7 @@ module EvcRails
13
13
  CLOSE_TAG_REGEX = %r{</([A-Z][a-zA-Z0-9_]*(?:::[A-Z][a-zA-Z0-9_]*)*)>}
14
14
 
15
15
  # Regex for attributes
16
- ATTRIBUTE_REGEX = /(\w+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/
16
+ ATTRIBUTE_REGEX = /([a-zA-Z0-9_-]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|\{([^}]*)\}))?/
17
17
 
18
18
  # Cache for compiled templates
19
19
  @template_cache = {}
@@ -274,6 +274,12 @@ module EvcRails
274
274
  name
275
275
  end
276
276
 
277
+ def normalize_attribute_name(attribute_name)
278
+ # Convert dasherized attributes to snake_case for Ruby compatibility
279
+ # e.g., "data-test-id" -> "data_test_id"
280
+ attribute_name.gsub("-", "_")
281
+ end
282
+
277
283
  def parse_attributes(attributes_str, attribute_regex = ATTRIBUTE_REGEX)
278
284
  as_variable = nil
279
285
  # Find and remove the `as` attribute, storing its value.
@@ -283,17 +289,85 @@ module EvcRails
283
289
  end.strip
284
290
 
285
291
  params = []
286
- attributes_str.scan(attribute_regex) do |key, quoted_value, single_quoted_value, ruby_expression|
287
- params << if ruby_expression
288
- "#{key}: #{ruby_expression}"
289
- elsif quoted_value
290
- "#{key}: \"#{quoted_value.gsub('"', '\\"')}\""
291
- elsif single_quoted_value
292
- "#{key}: \"#{single_quoted_value.gsub("'", "\\'")}\""
293
- else
294
- # Standalone attribute (no value) - treat as boolean true
295
- "#{key}: true"
296
- end
292
+ str = attributes_str.dup
293
+ until str.nil? || str.empty?
294
+ str = "" if str.nil?
295
+ str.lstrip!
296
+ str = "" if str.nil?
297
+ break if str.empty?
298
+ # Match key
299
+ break unless str =~ /\A([a-zA-Z0-9_-]+)/
300
+
301
+ key = normalize_attribute_name(::Regexp.last_match(1))
302
+ str = str[::Regexp.last_match(0).length..-1]
303
+ str = "" if str.nil?
304
+ str.lstrip!
305
+ str = "" if str.nil?
306
+ if str.start_with?("=")
307
+ str = str[1..-1]
308
+ str = "" if str.nil?
309
+ str.lstrip!
310
+ str = "" if str.nil?
311
+ if str.start_with?("{")
312
+ # Parse balanced curly braces
313
+ depth = 0
314
+ i = 0
315
+ found = false
316
+ while true
317
+ str = "" if str.nil?
318
+ break if str.empty? || i >= str.length
319
+
320
+ c = str[i]
321
+ if c == "{"
322
+ depth += 1
323
+ elsif c == "}"
324
+ depth -= 1
325
+ if depth == 0
326
+ found = true
327
+ break
328
+ end
329
+ end
330
+ i += 1
331
+ end
332
+ if found
333
+ ruby_expr = str[1...i] # skip opening '{', up to before closing '}'
334
+ str = str[(i + 1)..-1]
335
+ str = "" if str.nil?
336
+ params << "#{key}: #{ruby_expr}"
337
+ else
338
+ # Unbalanced braces, treat as error or fallback
339
+ params << "#{key}: true"
340
+ str = ""
341
+ end
342
+ elsif str.start_with?("\"")
343
+ # Double-quoted string
344
+ if str =~ /\A"([^"]*)"/
345
+ str = str[::Regexp.last_match(0).length..-1]
346
+ str = "" if str.nil?
347
+ params << "#{key}: \"#{::Regexp.last_match(1).gsub('"', '\\"')}\""
348
+ else
349
+ params << "#{key}: true"
350
+ str = ""
351
+ end
352
+ elsif str.start_with?("'")
353
+ # Single-quoted string
354
+ if str =~ /\A'([^']*)'/
355
+ str = str[::Regexp.last_match(0).length..-1]
356
+ str = "" if str.nil?
357
+ params << "#{key}: \"#{::Regexp.last_match(1).gsub("'", "\\'")}\""
358
+ else
359
+ params << "#{key}: true"
360
+ str = ""
361
+ end
362
+ else
363
+ # Unquoted value or malformed, treat as boolean true
364
+ params << "#{key}: true"
365
+ str = ""
366
+ end
367
+ else
368
+ # Standalone attribute (no value) - treat as boolean true
369
+ params << "#{key}: true"
370
+ end
297
371
  end
298
372
  [params, as_variable]
299
373
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EvcRails
4
- VERSION = "0.3.0"
4
+ VERSION = "0.3.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evc_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - scttymn