htx 0.0.9 → 0.1.1

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: 395620b3af20b4da17e4413632418481ee28d6d0fe6b46427af240475087efce
4
- data.tar.gz: bc15b61294daaf218b3a3d5a106de7c9279a7d9e8cb7ebd01002fcd618491b1f
3
+ metadata.gz: bbd968d3152b9ef4c7813f1e08139a4dc386ae99f8822758a0eb2574eb8beab5
4
+ data.tar.gz: e2fa1f7035a09e3518be5e3fe5f8c053fd4d7d8022f6f3d121e8caecea180d6a
5
5
  SHA512:
6
- metadata.gz: 83805b10f30d1846a187b458579a0748339a3956a4123226b7b9ebdb6dcff6cae3dbcd94913c1bbab2c91186ef3f46642f30a4ed9c3f30b072b3efe2f2ceb1ca
7
- data.tar.gz: 26e48419a9a719f1b8b582ef9e525ffcc37affdcb279f0cba95c6fe4cd2108cc6ec66e9ba4d3216a0ef02aad506d56c4743b059916ba78409f0dc672a760a1fc
6
+ metadata.gz: 3c15b1d31a60c7447137bd599bb2e7e767896d4f8ebef93878efb5981138beddd7a712744a974ea4150edd9b511593acf1d8ca0cb6754ae04f17ffbc85ce9ed1
7
+ data.tar.gz: adab39540cfe4261e26697a0a6af1081a620ab55305b38abcae5e446a919dfd5a5ac96cc01b5fa3cdd28bbbd3e6755c1c00a98f492530333ef102da43b4c5381
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2019-2022 Nate Pickens
1
+ Copyright 2019-2023 Nate Pickens
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
4
  documentation files (the "Software"), to deal in the Software without restriction, including without
data/README.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # HTX Ruby Compiler
2
2
 
3
3
  HTX templates are compiled to JavaScript before being used. This library provides a Ruby implementation of
4
- the compiler. For more information on HTX, see
5
- [https://github.com/npickens/htx](https://github.com/npickens/htx).
4
+ the compiler. For more information on HTX, see the main [README](https://github.com/npickens/htx).
6
5
 
7
6
  ## Installation
8
7
 
@@ -20,24 +19,39 @@ gem install htx
20
19
 
21
20
  ## Usage
22
21
 
23
- To compile an HTX template, pass a name (conventionally the path of the template file) and template content
24
- as strings to the `HTX.compile` method (all other arguments are optional):
22
+ HTX templates can be compiled to either a JavaScript module format or an IIFE assigned to a property on
23
+ either `globalThis` or a custom object. To compile as a module:
25
24
 
26
25
  ```ruby
27
26
  path = '/components/crew.htx'
28
- template = File.read(File.join('some/asset/dir', path))
27
+ content = File.read("/assets#{path}")
28
+
29
+ HTX.compile(path, content, as_module: true, import_path: 'vendor/htx.js')
30
+ # => "import * as HTX from 'vendor/htx.js'
31
+ #
32
+ # ...
33
+ #
34
+ # export function Template { ... }"
35
+ #
36
+ ```
29
37
 
30
- HTX.compile(path, template)
38
+ Note that with the module format the name of the template does not appear anywhere in its compiled form, but
39
+ is still used/useful for tracking down errors when compilation is handled by an overall asset management
40
+ system (such as [Darkroom](https://github.com/npickens/darkroom)).
31
41
 
32
- # window['/components/crew.htx'] = function(htx) {
33
- # // ...
34
- # }
42
+ To compile to an IIFE assigned to a custom object:
35
43
 
36
- HTX.compile(path, template, assign_to: 'myTemplates')
44
+ ```ruby
45
+ HTX.compile(path, content, as_module: false, assign_to: 'myTemplates')
46
+ # => "myTemplates['/components/crew.htx'] = ..."
47
+ ```
37
48
 
38
- # myTemplates['/components/crew.htx'] = function(htx) {
39
- # // ...
40
- # }
49
+ Options can be configured globally so they don't have to be passed to `HTX.compile` every time:
50
+
51
+ ```ruby
52
+ HTX.as_module = true # Default: false
53
+ HTX.import_path = 'vendor/htx.js' # Default: "/htx/htx.js"
54
+ HTX.assign_to = 'myTemplates' # Default: "globalThis"
41
55
  ```
42
56
 
43
57
  ## Contributing
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.9
1
+ 0.1.1
data/lib/htx/template.rb CHANGED
@@ -17,7 +17,6 @@ module HTX
17
17
  'svg' => 'http://www.w3.org/2000/svg',
18
18
  }.freeze
19
19
 
20
- INDENT_VALID = /^( +|\t+)$/.freeze
21
20
  INDENT_GUESS = /^( +|\t+)(?=\S)/.freeze
22
21
  INDENT_REGEX = /\n(?=[^\n])/.freeze
23
22
 
@@ -32,17 +31,14 @@ module HTX
32
31
  NON_WHITESPACE = /\S/.freeze
33
32
 
34
33
  ##
35
- # Returns false. In the near future when support for the <:> tag has been dropped (in favor of
36
- # <htx-content>), will return true if Nokogiri's HTML5 parser is available. To use it now, monkey patch
37
- # this method to return true.
34
+ # Returns true if Nokogiri's HTML5 parser is available.
38
35
  #
39
36
  def self.html5_parser?
40
- false # !!defined?(Nokogiri::HTML5)
37
+ defined?(Nokogiri::HTML5)
41
38
  end
42
39
 
43
40
  ##
44
- # Returns Nokogiri's HTML5 parser if available and enabled, and Nokogiri's regular HTML parser
45
- # otherwise.
41
+ # Returns Nokogiri's HTML5 parser if available or Nokogiri's default HTML (4) parser otherwise.
46
42
  #
47
43
  def self.nokogiri_parser
48
44
  html5_parser? ? Nokogiri::HTML5 : Nokogiri::HTML
@@ -62,24 +58,15 @@ module HTX
62
58
  ##
63
59
  # Compiles the HTX template.
64
60
  #
65
- # * +assign_to+ - JavaScript object to assign the template function to (default: +window+).
66
- # * +indent+ - DEPRECATED. Indentation amount (number) or string (must be only spaces or tabs but not
67
- # both) to use for indentation of compiled output (default: indentation of first indented line of
68
- # uncompiled template).
69
- #
70
- def compile(assign_to: nil, indent: (indent_omitted = true; nil))
71
- @assign_to = assign_to || 'window'
72
- @indent =
73
- if indent.kind_of?(Numeric)
74
- ' ' * indent
75
- elsif indent && !indent.match?(INDENT_VALID)
76
- raise("Invalid indent value #{indent.inspect}: only spaces and tabs (but not both) are allowed")
77
- else
78
- indent || @content[INDENT_GUESS] || INDENT_DEFAULT
79
- end
80
-
81
- warn('The indent: option for HTX template compilation is deprecated.') unless indent_omitted
82
-
61
+ # * +as_module+ - Boolean indicating whether or not to compile as a JavaScript module.
62
+ # * +import_path+ - Path to HTX JavaScript library for module import statement.
63
+ # * +assign_to+ - JavaScript object to assign the template function to if module not being used.
64
+ #
65
+ def compile(as_module: nil, import_path: nil, assign_to: nil)
66
+ @as_module = as_module.nil? ? HTX.as_module : as_module
67
+ @import_path = import_path || HTX.import_path
68
+ @assign_to = assign_to || HTX.assign_to
69
+ @base_indent = @indent = @content[INDENT_GUESS] || INDENT_DEFAULT
83
70
  @static_key = 0
84
71
  @close_count = 0
85
72
  @whitespace_buff = nil
@@ -158,14 +145,33 @@ module HTX
158
145
  # * +node+ - Nokogiri node to process.
159
146
  #
160
147
  def process_fragment_node(node)
161
- append("#{@assign_to}['#{@name}'] = function(htx) {")
162
- @whitespace_buff = "\n"
148
+ append("#{
149
+ @as_module ? "import * as HTX from '#{@import_path}'\n\n"
150
+ : "#{@assign_to}['#{@name}'] = ((HTX) => {\n#{@indent}"
151
+ }function render($renderer) {\n")
152
+
153
+ @indent = @base_indent * 2 unless @as_module
163
154
 
164
155
  node.children.each do |child|
165
156
  process(child)
166
157
  end
167
158
 
168
- append("\n}\n",)
159
+ append("\n\n#{@indent}return $renderer.rootNode")
160
+
161
+ @indent = @as_module ? '' : @base_indent
162
+
163
+ append(
164
+ <<~JS
165
+
166
+ #{@indent}}
167
+
168
+ #{@indent}#{@as_module ? 'export' : 'return'} function Template(context) {
169
+ #{@indent}#{@base_indent}this.render = render.bind(context, new HTX.Renderer)
170
+ #{@indent}}#{
171
+ "\n})(globalThis.HTX ||= {});" unless @as_module}
172
+ JS
173
+ )
174
+
169
175
  flush
170
176
  end
171
177
 
@@ -179,15 +185,10 @@ module HTX
179
185
  children = node.children
180
186
  childless = children.empty? || (children.size == 1 && self.class.formatting_node?(children.first))
181
187
  dynamic_key = self.class.attribute_value(node.attr(DYNAMIC_KEY_ATTR))
182
- attributes = self.class.process_attributes(node)
188
+ attributes = self.class.process_attributes(node, xmlns: xmlns)
183
189
  xmlns ||= !!self.class.namespace(node)
184
190
 
185
191
  if self.class.htx_content_node?(node)
186
- if node.name != CONTENT_TAG
187
- warn("#{@name}:#{node.line}: The <#{node.name}> tag has been deprecated. Use <#{CONTENT_TAG}> "\
188
- "for identical functionality.")
189
- end
190
-
191
192
  if attributes.size > 0
192
193
  raise(MalformedTemplateError.new("<#{node.name}> tags may not have attributes other than "\
193
194
  "#{DYNAMIC_KEY_ATTR}", @name, node))
@@ -269,7 +270,7 @@ module HTX
269
270
  close_count = @close_count
270
271
  @close_count = 0
271
272
 
272
- append("htx.close(#{close_count unless close_count == 1})")
273
+ append("$renderer.close(#{close_count unless close_count == 1})")
273
274
  end
274
275
 
275
276
  if @whitespace_buff
@@ -289,9 +290,9 @@ module HTX
289
290
  end
290
291
 
291
292
  ##
292
- # Appends an +htx.node+ call to the compiled template function string.
293
+ # Appends an +$renderer.node+ call to the compiled template function string.
293
294
  #
294
- # * +args+ - Arguments to use for the +htx.node+ call (any +nil+ ones are removed).
295
+ # * +args+ - Arguments to use for the +$renderer.node+ call (any +nil+ ones are removed).
295
296
  #
296
297
  def append_htx_node(*args)
297
298
  return if args.first.nil?
@@ -300,7 +301,7 @@ module HTX
300
301
  args << 0 unless args.last.kind_of?(Integer)
301
302
  args[-1] |= (@static_key += 1) << FLAG_BITS
302
303
 
303
- append("htx.node(#{args.join(', ')})")
304
+ append("$renderer.node(#{args.join(', ')})")
304
305
  end
305
306
 
306
307
  ##
@@ -336,7 +337,7 @@ module HTX
336
337
  # * +node+ - Nokogiri node to check.
337
338
  #
338
339
  def self.htx_content_node?(node)
339
- node && (node.name == CONTENT_TAG || node.name == 'htx-text' || node.name == ':')
340
+ node&.name == CONTENT_TAG
340
341
  end
341
342
 
342
343
  ##
@@ -344,10 +345,10 @@ module HTX
344
345
  #
345
346
  # * +node+ - Nokogiri node to process the attributes of.
346
347
  #
347
- def self.process_attributes(node)
348
+ def self.process_attributes(node, xmlns:)
348
349
  attributes = []
349
350
 
350
- if !node.attribute('xmlns') && (xmlns = namespace(node))
351
+ if !xmlns && !node.attribute('xmlns') && (xmlns = namespace(node))
351
352
  attributes.push(
352
353
  attribute_name('xmlns'),
353
354
  attribute_value(xmlns)
@@ -402,15 +403,10 @@ module HTX
402
403
  text ? TextParser.new(text, statement_allowed: false).parse : nil
403
404
  end
404
405
 
405
- # The Nokogiri HTML parser downcases all tag and attribute names, but SVG tags and attributes are case
406
- # sensitive and often mix cased. These maps are used to restore the correct case of such tags and
407
- # attributes.
408
- #
409
- # Note: Nokogiri's newer HTML5 parser resulting from the Nokogumbo merge fixes this issue, but it is
410
- # currently not available for JRuby. It also does not parse <:> as a tag, which is why it's been
411
- # deprecated in favor of <htx-content>. Once support for <:> has been completely removed, the HTML5
412
- # parser will be used for regular Ruby and this tag and attribute mapping hack reserved for JRuby (and
413
- # any other potential environments where the HTML5 parser is not available).
406
+ # The Nokogiri::HTML5 parser is used whenever possible, which correctly handles mix-cased SVG tag and
407
+ # attribute names. But when falling back to the Nokogiri::HTML parser (e.g. in JRuby environments where
408
+ # Nokogiri::HTML5 is not available), all tag and attribute names get downcased. These maps are used to
409
+ # restore the correct case.
414
410
 
415
411
  # Source: https://developer.mozilla.org/en-US/docs/Web/SVG/Element
416
412
  TAG_MAP = %w[
data/lib/htx/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HTX
4
- VERSION = '0.0.9'
4
+ VERSION = '0.1.1'
5
5
  end
data/lib/htx.rb CHANGED
@@ -11,6 +11,12 @@ require('htx/version')
11
11
  module HTX
12
12
  EMPTY_HASH = {}.freeze
13
13
 
14
+ @as_module = false
15
+ @import_path = '/htx/htx.js'
16
+ @assign_to = 'globalThis'
17
+
18
+ class << self; attr_accessor(:as_module, :import_path, :assign_to); end
19
+
14
20
  ##
15
21
  # Convenience method to create a new Template instance and compile it.
16
22
  #
@@ -21,18 +27,4 @@ module HTX
21
27
  def self.compile(name, content, options = EMPTY_HASH)
22
28
  Template.new(name, content).compile(**options)
23
29
  end
24
-
25
- ##
26
- # DEPRECATED. Use HTX::Template.new instead. HTX was formerly a class that would be instantiated for
27
- # compilation. This method allows HTX.new calls to continue working (but support will be removed in the
28
- # near future).
29
- #
30
- # * +name+ - Template name. Conventionally the path of the template file.
31
- # * +content+ - Template content.
32
- #
33
- def self.new(name, content)
34
- warn('HTX.new is deprecated. Please use HTX::Template.new instead.')
35
-
36
- Template.new(name, content)
37
- end
38
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: htx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nate Pickens
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-31 00:00:00.000000000 Z
11
+ date: 2023-07-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -96,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
98
  requirements: []
99
- rubygems_version: 3.2.32
99
+ rubygems_version: 3.4.15
100
100
  signing_key:
101
101
  specification_version: 4
102
102
  summary: A Ruby compiler for HTX templates.