opal-sprockets 0.4.5.1.0.3.7 → 1.0.0
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/.github/workflows/build.yml +26 -0
- data/CHANGELOG.md +39 -0
- data/bin/console +14 -0
- data/bin/rake +6 -0
- data/bin/rspec +29 -0
- data/bin/setup +8 -0
- data/example/Gemfile.lock +1 -1
- data/lib/opal/environment.rb +4 -0
- data/lib/opal/processor.rb +4 -0
- data/lib/opal/sprockets.rb +13 -81
- data/lib/opal/sprockets/assets_helper.rb +78 -0
- data/lib/opal/sprockets/environment.rb +12 -14
- data/lib/opal/sprockets/erb.rb +12 -16
- data/lib/opal/sprockets/mime_types.rb +19 -0
- data/lib/opal/sprockets/processor.rb +111 -114
- data/lib/opal/sprockets/server.rb +94 -98
- data/lib/opal/sprockets/version.rb +1 -8
- data/opal-sprockets.gemspec +38 -24
- data/spec/fixtures/complex_sprockets.js.rb.erb +1 -1
- data/spec/fixtures/{jst_file.js.jst → jst_file.jst.ejs} +0 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/sprockets/erb_spec.rb +15 -25
- data/spec/sprockets/processor_spec.rb +53 -57
- data/spec/sprockets/server_spec.rb +95 -25
- data/spec/sprockets_spec.rb +9 -9
- data/spec/tilt/opal_spec.rb +1 -1
- metadata +69 -27
- data/.travis.yml +0 -21
- data/lib/opal/sprockets/path_reader.rb +0 -36
- data/spec/shared/path_finder_shared.rb +0 -19
- data/spec/shared/path_reader_shared.rb +0 -31
- data/spec/sprockets/path_reader_spec.rb +0 -41
@@ -3,158 +3,147 @@ require 'base64'
|
|
3
3
|
require 'tilt/opal'
|
4
4
|
require 'sprockets'
|
5
5
|
require 'opal/builder'
|
6
|
-
require 'opal/sprockets
|
6
|
+
require 'opal/sprockets'
|
7
|
+
|
8
|
+
# Internal: The Processor class is used to make ruby files (with .rb or .opal
|
9
|
+
# extensions) available to any sprockets based server. Processor will then
|
10
|
+
# get passed any ruby source file to build.
|
11
|
+
class Opal::Sprockets::Processor
|
12
|
+
@@cache_key = nil
|
13
|
+
def self.cache_key
|
14
|
+
@@cache_key ||= ['Opal', Opal::VERSION, Opal::Config.config].to_json.freeze
|
15
|
+
end
|
7
16
|
|
8
|
-
|
9
|
-
# Internal: The Processor class is used to make ruby files (with .rb or .opal
|
10
|
-
# extensions) available to any sprockets based server. Processor will then
|
11
|
-
# get passed any ruby source file to build.
|
12
|
-
class Processor < TiltTemplate
|
17
|
+
def self.reset_cache_key!
|
13
18
|
@@cache_key = nil
|
14
|
-
|
15
|
-
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.call(input)
|
22
|
+
data, map, dependencies, required = input[:cache].fetch([self.cache_key, input[:filename], input[:data]]) do
|
23
|
+
new(input).call
|
16
24
|
end
|
17
25
|
|
18
|
-
|
19
|
-
|
26
|
+
if map
|
27
|
+
map = ::Sprockets::SourceMapUtils.combine_source_maps(input[:metadata][:map], map)
|
20
28
|
end
|
21
29
|
|
22
|
-
|
23
|
-
|
30
|
+
{
|
31
|
+
data: data,
|
32
|
+
map: map,
|
33
|
+
dependencies: input[:metadata][:dependencies].to_a + dependencies.to_a,
|
34
|
+
required: input[:metadata][:required].to_a + required.to_a,
|
35
|
+
}
|
36
|
+
end
|
24
37
|
|
25
|
-
|
38
|
+
def initialize(input)
|
39
|
+
@input = input
|
40
|
+
@sprockets = input[:environment]
|
41
|
+
@context = sprockets.context_class.new(input)
|
42
|
+
@data = input[:data]
|
43
|
+
end
|
26
44
|
|
27
|
-
|
28
|
-
# thus we need to bake our own logical_path
|
29
|
-
filename = context.respond_to?(:filename) ? context.filename : context.pathname.to_s
|
30
|
-
root_path_regexp = Regexp.escape(context.root_path)
|
31
|
-
logical_path = filename.gsub(%r{^#{root_path_regexp}/?(.*?)#{sprockets_extnames_regexp}}, '\1')
|
45
|
+
attr_reader :input, :sprockets, :context, :data
|
32
46
|
|
33
|
-
|
47
|
+
# In Sprockets 3 logical_path has an odd behavior when the filename is "index"
|
48
|
+
# thus we need to bake our own logical_path
|
49
|
+
def logical_path
|
50
|
+
@logical_path ||= context.filename.gsub(%r{^#{Regexp.escape(context.root_path)}/?(.*?)}, '\1')
|
51
|
+
end
|
34
52
|
|
35
|
-
|
36
|
-
|
53
|
+
def call
|
54
|
+
compiler_options = Opal::Config.compiler_options.merge(requirable: true, file: logical_path)
|
37
55
|
|
38
|
-
|
39
|
-
|
56
|
+
compiler = Opal::Compiler.new(data, compiler_options)
|
57
|
+
result = compiler.compile
|
40
58
|
|
41
|
-
|
42
|
-
|
43
|
-
# Opal 0.11 doesn't fill sourcesContent
|
44
|
-
add_sources_content_if_missing(map_data, data)
|
45
|
-
"#{result}\n#{to_data_uri_comment(map_data.to_json)}"
|
46
|
-
else
|
47
|
-
result.to_s
|
48
|
-
end
|
49
|
-
end
|
59
|
+
process_requires(compiler.requires, context)
|
60
|
+
process_required_trees(compiler.required_trees, context)
|
50
61
|
|
51
|
-
|
52
|
-
|
53
|
-
|
62
|
+
if Opal::Config.source_map_enabled
|
63
|
+
map = compiler.source_map.as_json.transform_keys!(&:to_s)
|
64
|
+
map["sources"][0] = input[:filename]
|
65
|
+
map = ::Sprockets::SourceMapUtils.format_source_map(map, input)
|
54
66
|
end
|
55
67
|
|
56
|
-
|
57
|
-
|
58
|
-
end
|
68
|
+
[result.to_s, map , context.metadata[:dependencies], context.metadata[:required]]
|
69
|
+
end
|
59
70
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
71
|
+
def sprockets_extnames_regexp
|
72
|
+
@sprockets_extnames_regexp ||= Opal::Sprockets.sprockets_extnames_regexp(@sprockets)
|
73
|
+
end
|
74
|
+
|
75
|
+
def process_requires(requires, context)
|
76
|
+
requires.each do |required|
|
77
|
+
required = required.to_s.sub(sprockets_extnames_regexp, '')
|
78
|
+
context.require_asset required unless ::Opal::Config.stubbed_files.include? required
|
65
79
|
end
|
80
|
+
end
|
66
81
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
82
|
+
# Internal: Add files required with `require_tree` as asset dependencies.
|
83
|
+
#
|
84
|
+
# Mimics (v2) Sprockets::DirectiveProcessor#process_require_tree_directive
|
85
|
+
def process_required_trees(required_trees, context)
|
86
|
+
return if required_trees.empty?
|
72
87
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
88
|
+
# This is the root dir of the logical path, we need this because
|
89
|
+
# the compiler gives us the path relative to the file's logical path.
|
90
|
+
dirname = File.dirname(input[:filename]).gsub(/#{Regexp.escape File.dirname(context.logical_path)}#{Opal::REGEXP_END}/, '')
|
91
|
+
dirname = Pathname(dirname)
|
77
92
|
|
78
|
-
|
79
|
-
|
93
|
+
required_trees.each do |original_required_tree|
|
94
|
+
required_tree = Pathname(original_required_tree)
|
80
95
|
|
81
|
-
|
82
|
-
|
83
|
-
|
96
|
+
unless required_tree.relative?
|
97
|
+
raise ArgumentError, "require_tree argument must be a relative path: #{required_tree.inspect}"
|
98
|
+
end
|
84
99
|
|
85
|
-
|
100
|
+
required_tree = dirname.join(input[:filename], '..', required_tree)
|
86
101
|
|
87
|
-
|
88
|
-
|
89
|
-
|
102
|
+
unless required_tree.directory?
|
103
|
+
raise ArgumentError, "require_tree argument must be a directory: #{{source: original_required_tree, pathname: required_tree}.inspect}"
|
104
|
+
end
|
90
105
|
|
91
|
-
|
106
|
+
context.depend_on required_tree.to_s
|
92
107
|
|
93
|
-
|
108
|
+
environment = context.environment
|
94
109
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
110
|
+
processor = ::Sprockets::DirectiveProcessor.new
|
111
|
+
processor.instance_variable_set('@dirname', File.dirname(input[:filename]))
|
112
|
+
processor.instance_variable_set('@environment', environment)
|
113
|
+
path = processor.__send__(:expand_relative_dirname, :require_tree, original_required_tree)
|
114
|
+
absolute_paths = environment.__send__(:stat_sorted_tree_with_dependencies, path).first.map(&:first)
|
100
115
|
|
101
|
-
|
102
|
-
|
103
|
-
|
116
|
+
absolute_paths.each do |path|
|
117
|
+
path = Pathname(path)
|
118
|
+
pathname = path.relative_path_from(dirname).to_s
|
119
|
+
pathname_noext = pathname.sub(sprockets_extnames_regexp, '')
|
104
120
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
121
|
+
if path.to_s == logical_path then next
|
122
|
+
elsif ::Opal::Config.stubbed_files.include?(pathname_noext) then next
|
123
|
+
elsif path.directory? then context.depend_on(path.to_s)
|
124
|
+
else context.require_asset(pathname_noext)
|
109
125
|
end
|
110
126
|
end
|
111
127
|
end
|
128
|
+
end
|
112
129
|
|
113
|
-
|
114
|
-
def self.stubbed_files
|
115
|
-
warn "Deprecated: `::Opal::Processor.stubbed_files' is deprecated, use `::Opal::Config.stubbed_files' instead"
|
116
|
-
puts caller(5)
|
117
|
-
::Opal::Config.stubbed_files
|
118
|
-
end
|
119
|
-
|
120
|
-
# @deprecated
|
121
|
-
def self.stub_file(name)
|
122
|
-
warn "Deprecated: `::Opal::Processor.stub_file' is deprecated, use `::Opal::Config.stubbed_files << #{name.inspect}.to_s' instead"
|
123
|
-
puts caller(5)
|
124
|
-
::Opal::Config.stubbed_files << name.to_s
|
125
|
-
end
|
126
|
-
|
127
|
-
|
128
|
-
private
|
129
|
-
|
130
|
-
def add_sources_content_if_missing(data, content)
|
131
|
-
data[:sourcesContent] = data.delete(:sourcesContent) || data.delete('sourcesContent') || [content]
|
132
|
-
end
|
130
|
+
private
|
133
131
|
|
134
|
-
|
135
|
-
|
136
|
-
|
132
|
+
def to_data_uri_comment(map_to_json)
|
133
|
+
"//# sourceMappingURL=data:application/json;base64,#{Base64.encode64(map_to_json).delete("\n")}"
|
134
|
+
end
|
137
135
|
|
138
|
-
|
139
|
-
|
140
|
-
end
|
136
|
+
def stubbed_files
|
137
|
+
::Opal::Config.stubbed_files
|
141
138
|
end
|
142
|
-
end
|
143
139
|
|
144
|
-
module Opal::Sprockets::Processor
|
145
140
|
module PlainJavaScriptLoader
|
146
141
|
def self.call(input)
|
147
142
|
sprockets = input[:environment]
|
148
|
-
asset = OpenStruct.new(input)
|
149
|
-
|
150
|
-
opal_extnames = sprockets.engines.map do |ext, engine|
|
151
|
-
ext if engine <= ::Opal::Processor
|
152
|
-
end.compact
|
153
143
|
|
154
|
-
|
155
|
-
processed_by_opal = -> asset { (path_extnames[asset.filename] & opal_extnames).any? }
|
144
|
+
opal_extnames_regexp = Opal::Sprockets.sprockets_extnames_regexp(sprockets, opal_only: true)
|
156
145
|
|
157
|
-
if
|
146
|
+
if input[:filename] =~ opal_extnames_regexp
|
158
147
|
input[:data]
|
159
148
|
else
|
160
149
|
"#{input[:data]}\n#{Opal::Sprockets.loaded_asset(input[:name])}"
|
@@ -163,7 +152,15 @@ module Opal::Sprockets::Processor
|
|
163
152
|
end
|
164
153
|
end
|
165
154
|
|
166
|
-
Sprockets.
|
167
|
-
Sprockets.
|
168
|
-
Sprockets.
|
155
|
+
Sprockets.register_mime_type 'application/ruby', extensions: ['.rb', '.opal', '.js.rb', '.js.opal']
|
156
|
+
Sprockets.register_transformer 'application/ruby', 'application/javascript', Opal::Sprockets::Processor
|
157
|
+
Opal::Sprockets.register_mime_type 'application/ruby'
|
158
|
+
|
159
|
+
Sprockets.register_mime_type 'application/ruby+ruby', extensions: ['.rb.erb', '.opal.erb', '.js.rb.erb', '.js.opal.erb']
|
160
|
+
Sprockets.register_transformer 'application/ruby+ruby', 'application/ruby', Sprockets::ERBProcessor
|
161
|
+
Opal::Sprockets.register_mime_type 'application/ruby+ruby'
|
169
162
|
|
163
|
+
Sprockets.register_preprocessor 'application/ruby', Sprockets::DirectiveProcessor.new(comments: ["#"])
|
164
|
+
Sprockets.register_preprocessor 'application/ruby+ruby', Sprockets::DirectiveProcessor.new(comments: ["#"])
|
165
|
+
|
166
|
+
Sprockets.register_postprocessor 'application/javascript', Opal::Sprockets::Processor::PlainJavaScriptLoader
|
@@ -2,115 +2,111 @@ require 'erb'
|
|
2
2
|
require 'rack'
|
3
3
|
require 'sprockets'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
create_app
|
23
|
-
end
|
5
|
+
class Opal::Sprockets::Server
|
6
|
+
attr_accessor :debug, :use_index, :index_path, :main, :public_root,
|
7
|
+
:public_urls, :sprockets, :prefix
|
8
|
+
|
9
|
+
def initialize options = {}
|
10
|
+
@use_index = true
|
11
|
+
@public_root = nil
|
12
|
+
@public_urls = ['/']
|
13
|
+
@sprockets = options.fetch(:sprockets, ::Sprockets::Environment.new)
|
14
|
+
@debug = options.fetch(:debug, true)
|
15
|
+
@prefix = options.fetch(:prefix, '/assets')
|
16
|
+
|
17
|
+
Opal.paths.each { |p| @sprockets.append_path(p) }
|
18
|
+
|
19
|
+
yield self if block_given?
|
20
|
+
create_app
|
21
|
+
end
|
24
22
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
23
|
+
def public_dir=(dir)
|
24
|
+
@public_root = dir
|
25
|
+
@public_urls = ["/"]
|
26
|
+
end
|
29
27
|
|
30
|
-
|
31
|
-
|
32
|
-
|
28
|
+
def source_map=(enabled)
|
29
|
+
Opal::Config.source_map_enabled = enabled
|
30
|
+
end
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
def source_map_enabled
|
33
|
+
Opal::Config.source_map_enabled
|
34
|
+
end
|
37
35
|
|
38
|
-
|
39
|
-
|
40
|
-
|
36
|
+
def append_path path
|
37
|
+
@sprockets.append_path path
|
38
|
+
end
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
def use_gem gem_name
|
41
|
+
@sprockets.use_gem gem_name
|
42
|
+
end
|
45
43
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
44
|
+
def create_app
|
45
|
+
server, sprockets, prefix = self, @sprockets, self.prefix
|
46
|
+
sprockets.logger.level ||= Logger::DEBUG
|
47
|
+
|
48
|
+
@app = Rack::Builder.app do
|
49
|
+
not_found = lambda { |env| [404, {}, []] }
|
50
|
+
use Rack::Deflater
|
51
|
+
use Rack::ShowExceptions
|
52
|
+
use Index, server if server.use_index
|
53
|
+
map(prefix) { run sprockets }
|
54
|
+
run Rack::Static.new(not_found, root: server.public_root, urls: server.public_urls)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def call(env)
|
59
|
+
@app.call env
|
60
|
+
end
|
61
|
+
|
62
|
+
class Index
|
63
|
+
|
64
|
+
def initialize(app, server)
|
65
|
+
@app = app
|
66
|
+
@server = server
|
67
|
+
@index_path = server.index_path
|
68
|
+
end
|
59
69
|
|
60
|
-
|
70
|
+
def call(env)
|
71
|
+
if %w[/ /index.html].include? env['PATH_INFO']
|
72
|
+
[200, { 'Content-Type' => 'text/html' }, [html]]
|
73
|
+
else
|
61
74
|
@app.call env
|
62
75
|
end
|
76
|
+
end
|
63
77
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
def call(env)
|
73
|
-
if %w[/ /index.html].include? env['PATH_INFO']
|
74
|
-
[200, { 'Content-Type' => 'text/html' }, [html]]
|
75
|
-
else
|
76
|
-
@app.call env
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# Returns the html content for the root path. Supports ERB
|
81
|
-
def html
|
82
|
-
if @index_path
|
83
|
-
raise "index does not exist: #{@index_path}" unless File.exist?(@index_path)
|
84
|
-
Tilt.new(@index_path).render(self)
|
85
|
-
else
|
86
|
-
raise "Main asset path not configured (set 'main' within Opal::Server.new block)" if @server.main.nil?
|
87
|
-
source
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def javascript_include_tag name
|
92
|
-
sprockets = @server.sprockets
|
93
|
-
prefix = @server.prefix
|
94
|
-
debug = @server.debug
|
95
|
-
|
96
|
-
::Opal::Sprockets.javascript_include_tag(name, sprockets: sprockets, prefix: prefix, debug: debug)
|
97
|
-
end
|
98
|
-
|
99
|
-
def source
|
100
|
-
<<-HTML
|
101
|
-
<!DOCTYPE html>
|
102
|
-
<html>
|
103
|
-
<head>
|
104
|
-
<meta charset="utf-8">
|
105
|
-
<title>Opal Server</title>
|
106
|
-
</head>
|
107
|
-
<body>
|
108
|
-
#{javascript_include_tag @server.main}
|
109
|
-
</body>
|
110
|
-
</html>
|
111
|
-
HTML
|
112
|
-
end
|
78
|
+
# Returns the html content for the root path. Supports ERB
|
79
|
+
def html
|
80
|
+
if @index_path
|
81
|
+
raise "index does not exist: #{@index_path}" unless File.exist?(@index_path)
|
82
|
+
Tilt.new(@index_path).render(self)
|
83
|
+
else
|
84
|
+
raise "Main asset path not configured (set 'main' within Opal::Server.new block)" if @server.main.nil?
|
85
|
+
source
|
113
86
|
end
|
114
87
|
end
|
88
|
+
|
89
|
+
def javascript_include_tag name
|
90
|
+
sprockets = @server.sprockets
|
91
|
+
prefix = @server.prefix
|
92
|
+
debug = @server.debug
|
93
|
+
|
94
|
+
::Opal::Sprockets.javascript_include_tag(name, sprockets: sprockets, prefix: prefix, debug: debug)
|
95
|
+
end
|
96
|
+
|
97
|
+
def source
|
98
|
+
<<-HTML
|
99
|
+
<!DOCTYPE html>
|
100
|
+
<html>
|
101
|
+
<head>
|
102
|
+
<meta charset="utf-8">
|
103
|
+
<title>Opal Server</title>
|
104
|
+
</head>
|
105
|
+
<body>
|
106
|
+
#{javascript_include_tag @server.main}
|
107
|
+
</body>
|
108
|
+
</html>
|
109
|
+
HTML
|
110
|
+
end
|
115
111
|
end
|
116
112
|
end
|