ruby2js 4.0.0 → 4.0.5
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 +4 -4
- data/README.md +0 -1
- data/lib/ruby2js.rb +16 -3
- data/lib/ruby2js/converter.rb +31 -0
- data/lib/ruby2js/converter/args.rb +6 -1
- data/lib/ruby2js/converter/class.rb +3 -0
- data/lib/ruby2js/converter/class2.rb +8 -5
- data/lib/ruby2js/converter/def.rb +8 -2
- data/lib/ruby2js/converter/dstr.rb +3 -1
- data/lib/ruby2js/converter/for.rb +1 -1
- data/lib/ruby2js/converter/hash.rb +19 -1
- data/lib/ruby2js/converter/logical.rb +1 -1
- data/lib/ruby2js/converter/next.rb +10 -2
- data/lib/ruby2js/converter/redo.rb +14 -0
- data/lib/ruby2js/converter/return.rb +2 -1
- data/lib/ruby2js/converter/send.rb +30 -4
- data/lib/ruby2js/converter/taglit.rb +9 -2
- data/lib/ruby2js/converter/while.rb +1 -1
- data/lib/ruby2js/converter/whilepost.rb +1 -1
- data/lib/ruby2js/converter/xstr.rb +1 -2
- data/lib/ruby2js/filter/camelCase.rb +2 -0
- data/lib/ruby2js/filter/functions.rb +39 -11
- data/lib/ruby2js/filter/lit-element.rb +202 -0
- data/lib/ruby2js/filter/react.rb +6 -16
- data/lib/ruby2js/filter/require.rb +2 -6
- data/lib/ruby2js/filter/stimulus.rb +4 -2
- data/lib/ruby2js/filter/tagged_templates.rb +4 -2
- data/lib/ruby2js/jsx.rb +19 -1
- data/lib/ruby2js/rails.rb +6 -59
- data/lib/ruby2js/serializer.rb +16 -11
- data/lib/ruby2js/sprockets.rb +40 -0
- data/lib/ruby2js/version.rb +1 -1
- data/lib/tasks/README.md +4 -0
- data/lib/tasks/install/app/javascript/elements/index.js +2 -0
- data/lib/tasks/install/litelement.rb +9 -0
- data/lib/tasks/install/react.rb +2 -0
- data/lib/tasks/install/stimulus-sprockets.rb +32 -0
- data/lib/tasks/install/stimulus-webpacker.rb +5 -0
- data/lib/tasks/install/webpacker.rb +97 -0
- data/lib/tasks/nodetest.js +47 -0
- data/lib/tasks/ruby2js_tasks.rake +42 -0
- data/ruby2js.gemspec +1 -1
- metadata +18 -6
@@ -15,17 +15,19 @@ module Ruby2JS
|
|
15
15
|
|
16
16
|
tagged_methods = @options[:template_literal_tags] || [:html, :css]
|
17
17
|
|
18
|
-
if tagged_methods.include?(method) &&
|
18
|
+
if tagged_methods.include?(method) && args.length == 1
|
19
19
|
strnode = process args.first
|
20
20
|
if strnode.type == :str
|
21
21
|
# convert regular strings to literal strings
|
22
22
|
strnode = strnode.updated(:dstr, [s(:str, strnode.children.first.chomp("\n"))])
|
23
|
-
|
23
|
+
elsif strnode.type == :dstr
|
24
24
|
# for literal strings, chomp a newline off the end
|
25
25
|
if strnode.children.last.type == :str && strnode.children.last.children[0].end_with?("\n")
|
26
26
|
children = [*strnode.children.take(strnode.children.length - 1), s(:str, strnode.children.last.children[0].chomp)]
|
27
27
|
strnode = s(:dstr, *children)
|
28
28
|
end
|
29
|
+
else
|
30
|
+
return super
|
29
31
|
end
|
30
32
|
|
31
33
|
S(:taglit, s(:sym, method), strnode)
|
data/lib/ruby2js/jsx.rb
CHANGED
@@ -11,7 +11,7 @@ module Ruby2JS
|
|
11
11
|
|
12
12
|
class JsxParser
|
13
13
|
def initialize(stream)
|
14
|
-
@stream = stream
|
14
|
+
@stream = stream.respond_to?(:next) ? stream : OpalEnumerator.new(stream)
|
15
15
|
@state = :text
|
16
16
|
@text = ''
|
17
17
|
@result = []
|
@@ -288,4 +288,22 @@ module Ruby2JS
|
|
288
288
|
self.class.new(@stream).parse(:element)
|
289
289
|
end
|
290
290
|
end
|
291
|
+
|
292
|
+
# Opal's enumerator doesn't currently support next and peek methods.
|
293
|
+
# Build a wrapper that adds those methods.
|
294
|
+
class OpalEnumerator
|
295
|
+
def initialize(stream)
|
296
|
+
@stream = stream.to_a
|
297
|
+
end
|
298
|
+
|
299
|
+
def next
|
300
|
+
raise StopIteration.new if @stream.empty?
|
301
|
+
@stream.shift
|
302
|
+
end
|
303
|
+
|
304
|
+
def peek
|
305
|
+
raise StopIteration.new if @stream.empty?
|
306
|
+
@stream.first
|
307
|
+
end
|
308
|
+
end
|
291
309
|
end
|
data/lib/ruby2js/rails.rb
CHANGED
@@ -1,63 +1,10 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# $ echo "gem 'ruby2js', require: 'ruby2js/rails'" >> Gemfile
|
4
|
-
# $ bundle update
|
5
|
-
# $ rails generate controller Say hello
|
6
|
-
# $ echo 'alert "Hello world!"' > app/views/say/hello.js.rb
|
7
|
-
# $ rails server
|
8
|
-
# $ curl http://localhost:3000/say/hello.js
|
9
|
-
#
|
10
|
-
# Using an optional filter:
|
11
|
-
#
|
12
|
-
# $ echo 'require "ruby2js/filter/functions"' > config/initializers/ruby2js.rb
|
13
|
-
#
|
14
|
-
# Asset Pipeline:
|
15
|
-
#
|
16
|
-
# Ruby2JS registers ".rb.js" extension.
|
17
|
-
# You can add "ruby_thing.js.rb" to your app/javascript folder
|
18
|
-
# and '= require ruby_thing' from other js sources.
|
19
|
-
#
|
20
|
-
# (options are not yet supported, but by requiring the appropriate files
|
21
|
-
# as shown above, you can configure proejct wide.)
|
22
|
-
require 'ruby2js'
|
1
|
+
require 'rails'
|
2
|
+
require_relative './sprockets'
|
23
3
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
self.default_format = Mime[:js]
|
29
|
-
def self.call(template, source)
|
30
|
-
"Ruby2JS.convert(#{template.source.inspect}, file: source).to_s"
|
31
|
-
end
|
4
|
+
class Ruby2JSRailtie < Rails::Railtie
|
5
|
+
rake_tasks do
|
6
|
+
Dir[File.expand_path('../tasks/*.rake', __dir__)].each do |file|
|
7
|
+
load file
|
32
8
|
end
|
33
|
-
|
34
|
-
ActiveSupport.on_load(:action_view) do
|
35
|
-
ActionView::Template.register_template_handler :rb, Template
|
36
|
-
end
|
37
|
-
|
38
|
-
class SprocketProcessor
|
39
|
-
def initialize(file = nil)
|
40
|
-
@file = file
|
41
|
-
end
|
42
|
-
def render(context , _)
|
43
|
-
context = context.instance_eval { binding } unless context.is_a? Binding
|
44
|
-
Ruby2JS.convert(File.read(@file), binding: context).to_s
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
class Engine < ::Rails::Engine
|
49
|
-
engine_name "ruby2js"
|
50
|
-
|
51
|
-
config.app_generators.javascripts true
|
52
|
-
config.app_generators.javascript_engine :rb
|
53
|
-
|
54
|
-
config.assets.configure do |env|
|
55
|
-
env.register_mime_type 'text/ruby', extensions: ['.js.rb', '.rb']
|
56
|
-
env.register_transformer 'text/ruby', 'text/javascript', SprocketProcessor
|
57
|
-
env.register_preprocessor 'text/javascript', SprocketProcessor
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
9
|
end
|
62
|
-
|
63
10
|
end
|
data/lib/ruby2js/serializer.rb
CHANGED
@@ -303,11 +303,11 @@ module Ruby2JS
|
|
303
303
|
def vlq(*mark)
|
304
304
|
if @mark[0] == mark[0]
|
305
305
|
return if @mark[-3..-1] == mark[-3..-1]
|
306
|
-
@mappings
|
306
|
+
@mappings += ',' unless @mappings == ''
|
307
307
|
end
|
308
308
|
|
309
309
|
while @mark[0] < mark[0]
|
310
|
-
@mappings
|
310
|
+
@mappings += ';'
|
311
311
|
@mark[0] += 1
|
312
312
|
@mark[1] = 0
|
313
313
|
end
|
@@ -322,16 +322,21 @@ module Ruby2JS
|
|
322
322
|
data = diff << 1
|
323
323
|
end
|
324
324
|
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
325
|
+
if data <= 0b11111
|
326
|
+
# workaround https://github.com/opal/opal/issues/575
|
327
|
+
encoded = BASE64[data]
|
328
|
+
else
|
329
|
+
encoded = ''
|
330
|
+
|
331
|
+
begin
|
332
|
+
digit = data & 0b11111
|
333
|
+
data >>= 5
|
334
|
+
digit |= 0b100000 if data > 0
|
335
|
+
encoded += BASE64[digit]
|
336
|
+
end while data > 0
|
337
|
+
end
|
333
338
|
|
334
|
-
@mappings
|
339
|
+
@mappings += encoded
|
335
340
|
end
|
336
341
|
end
|
337
342
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'sprockets/source_map_utils'
|
3
|
+
require 'ruby2js'
|
4
|
+
require 'ruby2js/version'
|
5
|
+
|
6
|
+
module Ruby2JS
|
7
|
+
module SprocketsTransformer
|
8
|
+
include Sprockets
|
9
|
+
VERSION = '1'
|
10
|
+
|
11
|
+
@@options = {}
|
12
|
+
|
13
|
+
def self.options=(options)
|
14
|
+
@@options = options
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.cache_key
|
18
|
+
@cache_key ||= "#{name}:#{Ruby2JS::VERSION::STRING}:#{VERSION}".freeze
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.call(input)
|
22
|
+
data = input[:data]
|
23
|
+
|
24
|
+
js, map = input[:cache].fetch([self.cache_key, data]) do
|
25
|
+
result = Ruby2JS.convert(data, {**@@options, file: input[:filename]})
|
26
|
+
[result.to_s, result.sourcemap.transform_keys {|key| key.to_s}]
|
27
|
+
end
|
28
|
+
|
29
|
+
map = SourceMapUtils.format_source_map(map, input)
|
30
|
+
map = SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
31
|
+
|
32
|
+
{ data: js, map: map }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
Sprockets.register_mime_type 'application/ruby', extensions: ['.rb', '.js.rb']
|
38
|
+
|
39
|
+
Sprockets.register_transformer 'application/ruby', 'application/javascript',
|
40
|
+
Ruby2JS::SprocketsTransformer
|
data/lib/ruby2js/version.rb
CHANGED
data/lib/tasks/README.md
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
@ruby2js_options = {filters: ['lit-element']}
|
2
|
+
@yarn_add='lit-element'
|
3
|
+
eval IO.read "#{__dir__}/webpacker.rb"
|
4
|
+
|
5
|
+
directory File.expand_path("app/javascript/elements", __dir__),
|
6
|
+
Rails.root.join('app/javascript/elements').to_s
|
7
|
+
|
8
|
+
append_to_file Rails.root.join('app/javascript/packs/application.js').to_s,
|
9
|
+
"\nimport 'elements'\n"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
create_file Rails.root.join('config/initializers/ruby2js.rb').to_s,
|
2
|
+
<<~CONFIG
|
3
|
+
require 'ruby2js/filter/esm'
|
4
|
+
require 'ruby2js/filter/functions'
|
5
|
+
require 'ruby2js/filter/stimulus'
|
6
|
+
|
7
|
+
Ruby2JS::SprocketsTransformer.options = {
|
8
|
+
autoexports: :default,
|
9
|
+
eslevel: 2020
|
10
|
+
}
|
11
|
+
|
12
|
+
require 'stimulus/importmap_helper'
|
13
|
+
|
14
|
+
module Stimulus::ImportmapHelper
|
15
|
+
def find_javascript_files_in_tree(path)
|
16
|
+
exts = {'.js' => '.js', '.jsm' => '.jsm'}.merge(
|
17
|
+
Sprockets.mime_exts.map {|key, value|
|
18
|
+
next unless Sprockets.transformers[value]["application/javascript"]
|
19
|
+
[key, '.js']
|
20
|
+
}.compact.to_h)
|
21
|
+
|
22
|
+
Dir[path.join('**/*')].map {|file|
|
23
|
+
file_ext, web_ext = Sprockets::PathUtils.match_path_extname(file, exts)
|
24
|
+
next unless file_ext
|
25
|
+
|
26
|
+
next unless File.file? file
|
27
|
+
|
28
|
+
Pathname.new(file.chomp(file_ext) + web_ext)
|
29
|
+
}.compact
|
30
|
+
end
|
31
|
+
end
|
32
|
+
CONFIG
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#
|
2
|
+
# These instructions can be used standalone or in combination with other
|
3
|
+
# instructions.
|
4
|
+
#
|
5
|
+
# If used standalone on a repository which did not previously have the Ruby2JS
|
6
|
+
# webpack loader configured, it will add the '.js.rb' extension to
|
7
|
+
# `config/webpacker.yml`, install the Ruby2JS webpack-loader and add a minimal
|
8
|
+
# configuration which runs the Ruby2JS webpack loader then the babel loader to
|
9
|
+
# `config/webpacker.yml`.
|
10
|
+
#
|
11
|
+
# Other instructions can require these instructions. If they set the
|
12
|
+
# @ruby2js_options instance variable before they do so, the options provided
|
13
|
+
# will be merged and/or override the ones in the base configuration.
|
14
|
+
#
|
15
|
+
# If these instructions are run against a Rails application that was
|
16
|
+
# previously configured, the @ruby2js_options provided, if any, will be merged
|
17
|
+
# with the options found in the configuration.
|
18
|
+
#
|
19
|
+
|
20
|
+
# default options
|
21
|
+
options = @ruby2js_options || {}
|
22
|
+
|
23
|
+
# define .js.rb as a extension to webpacker
|
24
|
+
insert_into_file Rails.root.join("config/webpacker.yml").to_s,
|
25
|
+
" - .js.rb\n", after: "\n - .js\n"
|
26
|
+
|
27
|
+
# install webpack loader
|
28
|
+
run "yarn add @ruby2js/webpack-loader #{@yarn_add}"
|
29
|
+
|
30
|
+
# default config
|
31
|
+
config = <<~CONFIG
|
32
|
+
// Insert rb2js loader at the end of list
|
33
|
+
environment.loaders.append('rb2js', {
|
34
|
+
test: /\.js\.rb$/,
|
35
|
+
use: [
|
36
|
+
{
|
37
|
+
loader: "babel-loader",
|
38
|
+
options: environment.loaders.get('babel').use[0].options
|
39
|
+
},
|
40
|
+
|
41
|
+
{
|
42
|
+
loader: "@ruby2js/webpack-loader",
|
43
|
+
options: {
|
44
|
+
autoexports: "default",
|
45
|
+
eslevel: 2021,
|
46
|
+
filters: ["esm", "functions"]
|
47
|
+
}
|
48
|
+
},
|
49
|
+
]
|
50
|
+
})
|
51
|
+
CONFIG
|
52
|
+
|
53
|
+
# read current configuration
|
54
|
+
target = Rails.root.join("config/webpack/environment.js").to_s
|
55
|
+
before = IO.read(target)
|
56
|
+
|
57
|
+
# extract indentation and options either from the current configuration or the
|
58
|
+
# default configuration.
|
59
|
+
if before.include? '@ruby2js/webpack-loader'
|
60
|
+
match = /^(\s*)options: (\{.*?\n\1\})/m.match(before)
|
61
|
+
else
|
62
|
+
match = /^(\s*)options: (\{.*?\n\1\})/m.match(config)
|
63
|
+
end
|
64
|
+
|
65
|
+
# evaluate base options. Here it is handy that Ruby's syntax for hashes is
|
66
|
+
# fairly close to JavaScript's object literals. May run into problems in the
|
67
|
+
# future if there ever is a need for {"x": y} as that would need to be
|
68
|
+
# {"x" => y} in Ruby.
|
69
|
+
base = eval(match[2])
|
70
|
+
|
71
|
+
# Merge the options, initially having the new options override the original
|
72
|
+
# options.
|
73
|
+
merged = base.merge(options)
|
74
|
+
|
75
|
+
# Intelligently combine options if they are the same type.
|
76
|
+
options.keys.each do |key|
|
77
|
+
next unless base[key]
|
78
|
+
|
79
|
+
if options[key].is_a? Array and base[key].is_a? Array
|
80
|
+
merged[key] = (base[key] + options[key]).uniq
|
81
|
+
elsif options[key].is_a? Numeric and base[key].is_a? Numeric
|
82
|
+
merged[key] = [base[key], options[key]].max
|
83
|
+
elsif options[key].is_a? Hash and base[key].is_a? Hash
|
84
|
+
merged[key] = base[key].merge(options[key])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Serialize options as JavaScript, matching original indentation.
|
89
|
+
replacement = Ruby2JS.convert(merged.inspect + "\n").to_s.
|
90
|
+
gsub(/^/, match[1]).strip
|
91
|
+
|
92
|
+
# Update configuration
|
93
|
+
if before.include? '@ruby2js/webpack-loader'
|
94
|
+
gsub_file target, match[2].to_s, replacement
|
95
|
+
else
|
96
|
+
append_to_file target, "\n" + config.sub(match[2], replacement)
|
97
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
// minimal sanity test to verify usage of Ruby2JS under Node
|
2
|
+
|
3
|
+
const assert = require('assert');
|
4
|
+
|
5
|
+
const Ruby2JS = require('@ruby2js/ruby2js');
|
6
|
+
// const Ruby2JS =
|
7
|
+
// require('/home/rubys/git/ruby2js/docs/src/demo/ruby2js.js');
|
8
|
+
|
9
|
+
function to_js(string, options={}) {
|
10
|
+
return Ruby2JS.convert(string, options).toString()
|
11
|
+
}
|
12
|
+
|
13
|
+
assert.strictEqual(
|
14
|
+
to_js('foo = 1'),
|
15
|
+
'var foo = 1');
|
16
|
+
|
17
|
+
assert.strictEqual(
|
18
|
+
to_js('foo = 1', {eslevel: 2015}),
|
19
|
+
'let foo = 1');
|
20
|
+
|
21
|
+
assert.strictEqual(
|
22
|
+
to_js('foo.empty?', {filters: ['functions']}),
|
23
|
+
'foo.length == 0');
|
24
|
+
|
25
|
+
let ast = Ruby2JS.convert('String', {file: 'a.rb'}).ast
|
26
|
+
assert.strictEqual(ast.constructor, Ruby2JS.AST.Node)
|
27
|
+
assert.strictEqual(ast.type, "const")
|
28
|
+
assert.strictEqual(ast.children.length, 2)
|
29
|
+
assert.strictEqual(ast.children[0], Ruby2JS.nil)
|
30
|
+
assert.strictEqual(ast.children[1], "String")
|
31
|
+
|
32
|
+
let sourcemap = Ruby2JS.convert('a=1', {file: 'a.rb'}).sourcemap
|
33
|
+
assert.strictEqual(sourcemap.version, 3)
|
34
|
+
assert.strictEqual(sourcemap.file, 'a.rb')
|
35
|
+
assert.strictEqual(sourcemap.sources.length, 1)
|
36
|
+
assert.strictEqual(sourcemap.sources[0], 'a.rb')
|
37
|
+
assert.strictEqual(sourcemap.mappings, 'QAAE')
|
38
|
+
|
39
|
+
console.log(to_js(`
|
40
|
+
class C < LitElement
|
41
|
+
def render
|
42
|
+
x.empty?
|
43
|
+
'<h1>title</h1>'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
`, {eslevel: 2020, filters: ['lit-element', 'esm', 'functions']}))
|
@@ -0,0 +1,42 @@
|
|
1
|
+
Thor::Actions::WARNINGS[:unchanged_no_flag] = 'unchanged'
|
2
|
+
|
3
|
+
def template(location)
|
4
|
+
system "#{RbConfig.ruby} #{Rails.root.join("bin")}/rails app:template " +
|
5
|
+
"LOCATION=#{File.expand_path(location, __dir__)}"
|
6
|
+
end
|
7
|
+
|
8
|
+
namespace :ruby2js do
|
9
|
+
namespace :install do
|
10
|
+
desc "Install Ruby2JS with LitElement support"
|
11
|
+
task :litelement do
|
12
|
+
template 'install/litelement.rb'
|
13
|
+
end
|
14
|
+
|
15
|
+
desc "Install Ruby2JS with React support"
|
16
|
+
task :react do
|
17
|
+
template 'install/react.rb'
|
18
|
+
Rake::Task['webpacker:install:react'].invoke
|
19
|
+
end
|
20
|
+
|
21
|
+
namespace :stimulus do
|
22
|
+
desc "Install Ruby2JS with Stimulus Sprockets support"
|
23
|
+
task :sprockets => :"stimulus:install:asset_pipeline" do
|
24
|
+
template 'install/stimulus-sprockets.rb'
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Install Ruby2JS with Stimulus Webpacker support"
|
28
|
+
task :webpacker => :"stimulus:install" do
|
29
|
+
template 'install/stimulus-webpacker.rb'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
namespace :webpacker do
|
36
|
+
namespace :install do
|
37
|
+
desc "Install everything needed for Ruby2JS"
|
38
|
+
task :ruby2js do
|
39
|
+
template 'install/webpacker.rb'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|