epuber 0.7.4 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +10 -2
- data/LICENSE.txt +1 -1
- data/README.md +4 -3
- data/epuber.gemspec +11 -16
- data/lib/epuber/book/contributor.rb +10 -7
- data/lib/epuber/book/file_request.rb +3 -3
- data/lib/epuber/book/target.rb +30 -33
- data/lib/epuber/book/toc_item.rb +2 -4
- data/lib/epuber/book.rb +21 -21
- data/lib/epuber/checker/bookspec_checker.rb +26 -0
- data/lib/epuber/checker/text_checker.rb +16 -7
- data/lib/epuber/checker.rb +16 -2
- data/lib/epuber/checker_transformer_base.rb +3 -6
- data/lib/epuber/command/build.rb +40 -25
- data/lib/epuber/command/from_file.rb +39 -0
- data/lib/epuber/command/init.rb +34 -32
- data/lib/epuber/command/server.rb +3 -3
- data/lib/epuber/command.rb +18 -20
- data/lib/epuber/compiler/compilation_context.rb +10 -8
- data/lib/epuber/compiler/file_database.rb +2 -4
- data/lib/epuber/compiler/file_finders/abstract.rb +36 -26
- data/lib/epuber/compiler/file_finders/imaginary.rb +40 -35
- data/lib/epuber/compiler/file_resolver.rb +79 -89
- data/lib/epuber/compiler/file_stat.rb +4 -4
- data/lib/epuber/compiler/file_types/abstract_file.rb +4 -7
- data/lib/epuber/compiler/file_types/bade_file.rb +20 -15
- data/lib/epuber/compiler/file_types/coffee_script_file.rb +1 -1
- data/lib/epuber/compiler/file_types/css_file.rb +103 -0
- data/lib/epuber/compiler/file_types/generated_file.rb +1 -1
- data/lib/epuber/compiler/file_types/image_file.rb +4 -2
- data/lib/epuber/compiler/file_types/nav_file.rb +0 -1
- data/lib/epuber/compiler/file_types/opf_file.rb +0 -1
- data/lib/epuber/compiler/file_types/source_file.rb +8 -3
- data/lib/epuber/compiler/file_types/stylus_file.rb +4 -3
- data/lib/epuber/compiler/file_types/xhtml_file.rb +67 -13
- data/lib/epuber/compiler/generator.rb +1 -2
- data/lib/epuber/compiler/meta_inf_generator.rb +1 -1
- data/lib/epuber/compiler/nav_generator.rb +10 -11
- data/lib/epuber/compiler/opf_generator.rb +26 -27
- data/lib/epuber/compiler/problem.rb +12 -21
- data/lib/epuber/compiler/xhtml_processor.rb +63 -32
- data/lib/epuber/compiler.rb +77 -25
- data/lib/epuber/config.rb +16 -10
- data/lib/epuber/dsl/attribute.rb +17 -18
- data/lib/epuber/dsl/attribute_support.rb +7 -7
- data/lib/epuber/dsl/object.rb +19 -17
- data/lib/epuber/dsl/tree_object.rb +2 -3
- data/lib/epuber/epubcheck.rb +15 -0
- data/lib/epuber/from_file/bookspec_generator.rb +371 -0
- data/lib/epuber/from_file/encryption_handler.rb +146 -0
- data/lib/epuber/from_file/from_file_executor.rb +140 -0
- data/lib/epuber/from_file/nav_file.rb +163 -0
- data/lib/epuber/from_file/opf_file.rb +219 -0
- data/lib/epuber/helper.rb +0 -1
- data/lib/epuber/lockfile.rb +7 -9
- data/lib/epuber/plugin.rb +2 -3
- data/lib/epuber/ruby_extensions/match_data.rb +1 -1
- data/lib/epuber/ruby_extensions/thread.rb +1 -0
- data/lib/epuber/server/base.styl +0 -1
- data/lib/epuber/server/basic.styl +1 -30
- data/lib/epuber/server/handlers.rb +1 -1
- data/lib/epuber/server.rb +81 -80
- data/lib/epuber/third_party/bower.rb +5 -5
- data/lib/epuber/transformer/book_transformer.rb +108 -0
- data/lib/epuber/transformer/text_transformer.rb +4 -2
- data/lib/epuber/transformer.rb +4 -2
- data/lib/epuber/user_interface.rb +49 -38
- data/lib/epuber/vendor/hash_binding.rb +9 -2
- data/lib/epuber/vendor/ruby_templater.rb +4 -8
- data/lib/epuber/vendor/version.rb +12 -12
- data/lib/epuber/version.rb +1 -1
- metadata +79 -100
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Bold.ttf +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-BoldItalic.ttf +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Italic.ttf +0 -0
- data/lib/epuber/server/fonts/AvenirNext/AvenirNext-Regular.ttf +0 -0
@@ -11,6 +11,8 @@ module Epuber
|
|
11
11
|
#
|
12
12
|
attr_accessor :entries
|
13
13
|
|
14
|
+
# @return [String]
|
15
|
+
#
|
14
16
|
attr_reader :name
|
15
17
|
|
16
18
|
def initialize(name)
|
@@ -32,8 +34,12 @@ module Epuber
|
|
32
34
|
end
|
33
35
|
|
34
36
|
class FileEntry
|
37
|
+
# @return [String]
|
38
|
+
#
|
35
39
|
attr_reader :name
|
36
40
|
|
41
|
+
# @return [String]
|
42
|
+
#
|
37
43
|
attr_reader :absolute_path
|
38
44
|
|
39
45
|
def initialize(name, absolute_path)
|
@@ -42,7 +48,7 @@ module Epuber
|
|
42
48
|
end
|
43
49
|
|
44
50
|
def ==(other)
|
45
|
-
other.is_a?(FileEntry) ?
|
51
|
+
name == (other.is_a?(FileEntry) ? other.name : other.to_s)
|
46
52
|
end
|
47
53
|
end
|
48
54
|
|
@@ -83,14 +89,11 @@ module Epuber
|
|
83
89
|
make_dir_p(path)[file_name] = FileEntry.new(file_name, file_path)
|
84
90
|
end
|
85
91
|
|
86
|
-
|
87
92
|
def __core_find_files_from_pattern(pattern)
|
88
93
|
parts = self.class.path_parts(pattern)
|
89
94
|
found_entries = find_recurser(root, parts).flatten
|
90
95
|
file_entries = found_entries.reject { |entry| entry.is_a?(DirEntry) }
|
91
|
-
file_entries.map
|
92
|
-
item.absolute_path
|
93
|
-
end
|
96
|
+
file_entries.map(&:absolute_path)
|
94
97
|
end
|
95
98
|
|
96
99
|
def __core_file?(path)
|
@@ -104,12 +107,14 @@ module Epuber
|
|
104
107
|
current.is_a?(FileEntry)
|
105
108
|
end
|
106
109
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
110
|
+
class << self
|
111
|
+
def path_parts(path)
|
112
|
+
path.split(File::SEPARATOR).reject(&:empty?)
|
113
|
+
end
|
111
114
|
end
|
112
115
|
|
116
|
+
private
|
117
|
+
|
113
118
|
def find_recurser(dir, parts)
|
114
119
|
return [] unless dir.respond_to? :[]
|
115
120
|
|
@@ -117,25 +122,25 @@ module Epuber
|
|
117
122
|
return [] if pattern.nil?
|
118
123
|
|
119
124
|
matches = case pattern
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
else
|
134
|
-
directories_under(dir)
|
135
|
-
end
|
125
|
+
when '**'
|
126
|
+
case parts
|
127
|
+
when ['*']
|
128
|
+
parts = [] # end recursion
|
129
|
+
directories_under(dir).map do |d|
|
130
|
+
d.entries.select do |f|
|
131
|
+
(f.is_a?(FileEntry) || f.is_a?(DirEntry)) &&
|
132
|
+
f.name.match(/\A(?!\.)/)
|
133
|
+
end
|
134
|
+
end.flatten.uniq
|
135
|
+
when []
|
136
|
+
parts = [] # end recursion
|
137
|
+
dir.entries.values.flatten.uniq
|
136
138
|
else
|
137
|
-
|
138
|
-
|
139
|
+
directories_under(dir)
|
140
|
+
end
|
141
|
+
else
|
142
|
+
regex_body = pattern_to_regex(pattern)
|
143
|
+
dir.entries.select { |k, _v| /\A#{regex_body}\Z/ =~ k }.values
|
139
144
|
end
|
140
145
|
|
141
146
|
if parts.empty? # we're done recursing
|
@@ -156,14 +161,14 @@ module Epuber
|
|
156
161
|
|
157
162
|
def pattern_to_regex(pattern)
|
158
163
|
pattern.gsub('.', '\.')
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
164
|
+
.gsub('?', '.')
|
165
|
+
.gsub('*', '.*')
|
166
|
+
.gsub('(', '\(')
|
167
|
+
.gsub(')', '\)')
|
168
|
+
.gsub(/\{(.*?)\}/) do
|
169
|
+
"(#{Regexp.last_match[1].gsub(',', '|')})"
|
170
|
+
end
|
171
|
+
.gsub(/\A\./, '(?!\.).')
|
167
172
|
end
|
168
173
|
end
|
169
174
|
end
|
@@ -20,12 +20,12 @@ module Epuber
|
|
20
20
|
require_relative 'file_types/container_xml_file'
|
21
21
|
require_relative 'file_types/ibooks_display_options_file'
|
22
22
|
require_relative 'file_types/coffee_script_file'
|
23
|
-
|
23
|
+
require_relative 'file_types/css_file'
|
24
24
|
|
25
25
|
class FileResolver
|
26
26
|
class ResolveError < StandardError; end
|
27
27
|
|
28
|
-
PATH_TYPES = [:spine, :manifest, :package, nil]
|
28
|
+
PATH_TYPES = [:spine, :manifest, :package, nil].freeze
|
29
29
|
|
30
30
|
# @return [String] path where should look for source files
|
31
31
|
#
|
@@ -125,24 +125,16 @@ module Epuber
|
|
125
125
|
existing_file = @final_destination_path_to_file[file.final_destination_path]
|
126
126
|
|
127
127
|
# save mapping from file_request to file, file_request can be different, but result file could be the same ...
|
128
|
-
unless file.try(:file_request).nil?
|
129
|
-
@request_to_files[file.file_request] << (existing_file || file)
|
130
|
-
end
|
128
|
+
@request_to_files[file.file_request] << (existing_file || file) unless file.try(:file_request).nil?
|
131
129
|
|
132
130
|
# return existing file if already exists, new file will be thrown away
|
133
131
|
return existing_file unless existing_file.nil?
|
134
132
|
|
135
|
-
if [:spine].include?(type)
|
136
|
-
@spine_files << file
|
137
|
-
end
|
133
|
+
@spine_files << file if [:spine].include?(type)
|
138
134
|
|
139
|
-
if [
|
140
|
-
@manifest_files << file
|
141
|
-
end
|
135
|
+
@manifest_files << file if %i[spine manifest].include?(type)
|
142
136
|
|
143
|
-
if [
|
144
|
-
@package_files << file
|
145
|
-
end
|
137
|
+
@package_files << file if %i[spine manifest package].include?(type)
|
146
138
|
|
147
139
|
@files << file
|
148
140
|
|
@@ -151,13 +143,11 @@ module Epuber
|
|
151
143
|
|
152
144
|
@final_destination_path_to_file[file.final_destination_path] = file
|
153
145
|
|
154
|
-
if file.respond_to?(:source_path) && !file.source_path.nil?
|
155
|
-
@source_path_to_file[file.source_path] = file
|
156
|
-
end
|
146
|
+
@source_path_to_file[file.source_path] = file if file.respond_to?(:source_path) && !file.source_path.nil?
|
157
147
|
|
158
|
-
|
159
|
-
|
160
|
-
|
148
|
+
return unless file.respond_to?(:abs_source_path) && !file.abs_source_path.nil?
|
149
|
+
|
150
|
+
@abs_source_path_to_file[file.abs_source_path] = file
|
161
151
|
end
|
162
152
|
|
163
153
|
# Get instance of file from request instance
|
@@ -184,7 +174,7 @@ module Epuber
|
|
184
174
|
end
|
185
175
|
|
186
176
|
if file_request.only_one
|
187
|
-
files.first
|
177
|
+
files.first # @request_to_files always returns array, see #initialize method
|
188
178
|
else
|
189
179
|
files
|
190
180
|
end
|
@@ -219,99 +209,99 @@ module Epuber
|
|
219
209
|
# @return [Array<String>] list of files that should be deleted in destination directory
|
220
210
|
#
|
221
211
|
def unneeded_files_in_destination
|
222
|
-
requested_paths = files.map
|
223
|
-
file.pkg_destination_path
|
224
|
-
end
|
212
|
+
requested_paths = files.map(&:pkg_destination_path)
|
225
213
|
|
226
214
|
existing_paths = FileFinders::Normal.new(destination_path).find_all('*')
|
227
215
|
|
228
216
|
unnecessary_paths = existing_paths - requested_paths
|
229
217
|
|
230
|
-
unnecessary_paths.
|
231
|
-
|
218
|
+
unnecessary_paths.reject! do |path|
|
219
|
+
::File.directory?(File.join(destination_path, path))
|
232
220
|
end
|
233
221
|
|
234
222
|
unnecessary_paths
|
235
223
|
end
|
236
224
|
|
237
|
-
|
238
225
|
##################################################################################################################
|
239
226
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
# @param file [Epuber::Compiler::AbstractFile]
|
258
|
-
#
|
259
|
-
# @return [nil]
|
260
|
-
#
|
261
|
-
def resolve_destination_path(file)
|
262
|
-
if file.final_destination_path.nil?
|
263
|
-
dest_path = if file.respond_to?(:source_path) && !file.source_path.nil?
|
264
|
-
file.abs_source_path = File.expand_path(file.source_path, source_path)
|
265
|
-
self.class.renamed_file_with_path(file.source_path)
|
266
|
-
elsif !file.destination_path.nil?
|
267
|
-
file.destination_path
|
268
|
-
else
|
269
|
-
raise ResolveError, "What should I do with file that doesn't have source path or destination path? file: #{file.inspect}"
|
270
|
-
end
|
271
|
-
|
272
|
-
file.destination_path = dest_path
|
273
|
-
file.pkg_destination_path = File.join(*self.class.path_comps_for(file.path_type), dest_path)
|
274
|
-
file.final_destination_path = File.join(destination_path, file.pkg_destination_path)
|
227
|
+
class << self
|
228
|
+
# @param [String] path path to some file
|
229
|
+
#
|
230
|
+
# @return [String] path with changed extension
|
231
|
+
#
|
232
|
+
def renamed_file_with_path(path)
|
233
|
+
extname = File.extname(path)
|
234
|
+
new_extname = FileFinders::EXTENSIONS_RENAME[extname]
|
235
|
+
|
236
|
+
if new_extname.nil?
|
237
|
+
path
|
238
|
+
else
|
239
|
+
path.sub(/#{Regexp.escape(extname)}$/, new_extname)
|
240
|
+
end
|
275
241
|
end
|
276
|
-
end
|
277
242
|
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
243
|
+
# @param [String] extname extension of file
|
244
|
+
#
|
245
|
+
# @return [Class]
|
246
|
+
#
|
247
|
+
def file_class_for(extname)
|
248
|
+
mapping = {
|
249
|
+
'.styl' => FileTypes::StylusFile,
|
250
|
+
'.css' => FileTypes::CSSFile,
|
285
251
|
|
286
|
-
|
252
|
+
'.coffee' => FileTypes::CoffeeScriptFile,
|
287
253
|
|
288
|
-
|
289
|
-
|
290
|
-
|
254
|
+
'.bade' => FileTypes::BadeFile,
|
255
|
+
'.xhtml' => FileTypes::XHTMLFile,
|
256
|
+
'.html' => FileTypes::XHTMLFile,
|
291
257
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
258
|
+
'.jpg' => FileTypes::ImageFile,
|
259
|
+
'.jpeg' => FileTypes::ImageFile,
|
260
|
+
'.png' => FileTypes::ImageFile,
|
261
|
+
}
|
296
262
|
|
297
|
-
|
298
|
-
|
263
|
+
mapping[extname] || FileTypes::StaticFile
|
264
|
+
end
|
299
265
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
266
|
+
# @param [String] root_path path to root of the package
|
267
|
+
# @param [Symbol] path_type path type of file
|
268
|
+
#
|
269
|
+
# @return [Array<String>] path components
|
270
|
+
#
|
271
|
+
def path_comps_for(root_path, path_type)
|
272
|
+
case path_type
|
307
273
|
when :spine, :manifest
|
308
274
|
Array(root_path) + [Compiler::EPUB_CONTENT_FOLDER]
|
309
275
|
when :package
|
310
276
|
Array(root_path)
|
311
|
-
|
312
|
-
nil
|
277
|
+
end
|
313
278
|
end
|
314
279
|
end
|
280
|
+
|
281
|
+
private
|
282
|
+
|
283
|
+
# @param [Epuber::Compiler::AbstractFile] file
|
284
|
+
#
|
285
|
+
# @return [nil]
|
286
|
+
#
|
287
|
+
def resolve_destination_path(file)
|
288
|
+
return unless file.final_destination_path.nil?
|
289
|
+
|
290
|
+
dest_path = if file.respond_to?(:source_path) && !file.source_path.nil?
|
291
|
+
file.abs_source_path = File.expand_path(file.source_path, source_path)
|
292
|
+
self.class.renamed_file_with_path(file.source_path)
|
293
|
+
elsif !file.destination_path.nil?
|
294
|
+
file.destination_path
|
295
|
+
else
|
296
|
+
raise ResolveError, <<~ERROR
|
297
|
+
What should I do with file that doesn't have source path or destination path? file: #{file.inspect}
|
298
|
+
ERROR
|
299
|
+
end
|
300
|
+
|
301
|
+
file.destination_path = dest_path
|
302
|
+
file.pkg_destination_path = File.join(*self.class.path_comps_for(nil, file.path_type), dest_path)
|
303
|
+
file.final_destination_path = File.join(destination_path, file.pkg_destination_path)
|
304
|
+
end
|
315
305
|
end
|
316
306
|
end
|
317
307
|
end
|
@@ -36,7 +36,7 @@ module Epuber
|
|
36
36
|
@mtime = stat.mtime
|
37
37
|
@ctime = stat.ctime
|
38
38
|
@size = stat.size
|
39
|
-
rescue
|
39
|
+
rescue StandardError
|
40
40
|
# noop
|
41
41
|
end
|
42
42
|
end
|
@@ -66,9 +66,9 @@ module Epuber
|
|
66
66
|
raise AttributeError, "other must be class of #{self.class}" unless other.is_a?(FileStat)
|
67
67
|
|
68
68
|
file_path == other.file_path &&
|
69
|
-
|
70
|
-
|
71
|
-
|
69
|
+
size == other.size &&
|
70
|
+
mtime == other.mtime &&
|
71
|
+
ctime == other.ctime
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
@@ -4,18 +4,18 @@ module Epuber
|
|
4
4
|
class Compiler
|
5
5
|
module FileTypes
|
6
6
|
class AbstractFile
|
7
|
-
|
8
7
|
# @return [String] relative destination path
|
9
8
|
#
|
10
9
|
attr_accessor :destination_path
|
11
10
|
|
12
|
-
# @return [Symbol] group of this file (:text, :image, :font, ...), see
|
11
|
+
# @return [Symbol] group of this file (:text, :image, :font, ...), see
|
12
|
+
# Epuber::Compiler::FileFinder::GROUP_EXTENSIONS
|
13
13
|
#
|
14
14
|
attr_accessor :group
|
15
15
|
|
16
16
|
# @return [Set<Symbol>] list of properties
|
17
17
|
#
|
18
|
-
|
18
|
+
attr_writer :properties
|
19
19
|
|
20
20
|
# @return [Set<Symbol>] list of properties
|
21
21
|
#
|
@@ -23,7 +23,6 @@ module Epuber
|
|
23
23
|
@properties ||= Set.new
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
26
|
# @return [String] final relative destination path from root of the package calculated by FileResolver
|
28
27
|
#
|
29
28
|
attr_accessor :pkg_destination_path
|
@@ -88,9 +87,7 @@ module Epuber
|
|
88
87
|
def self.write_to_file!(content, to_path)
|
89
88
|
FileUtils.mkdir_p(File.dirname(to_path))
|
90
89
|
|
91
|
-
File.
|
92
|
-
file_handle.write(content)
|
93
|
-
end
|
90
|
+
File.write(to_path, content)
|
94
91
|
end
|
95
92
|
end
|
96
93
|
end
|
@@ -26,10 +26,15 @@ module Epuber
|
|
26
26
|
__file_resolver: file_resolver,
|
27
27
|
__file: self,
|
28
28
|
__toc_item: toc_item,
|
29
|
-
__const: Hash.new
|
29
|
+
__const: Hash.new do |_hash, key|
|
30
|
+
UI.warning("Undefined constant with key `#{key}`", location: caller_locations[0])
|
31
|
+
end.merge!(target.constants),
|
30
32
|
}
|
31
33
|
|
32
|
-
should_load_from_precompiled = up_to_date &&
|
34
|
+
should_load_from_precompiled = up_to_date &&
|
35
|
+
precompiled_exists &&
|
36
|
+
compilation_context.incremental_build? &&
|
37
|
+
!compilation_context.should_write
|
33
38
|
|
34
39
|
precompiled = if should_load_from_precompiled
|
35
40
|
begin
|
@@ -40,16 +45,10 @@ module Epuber
|
|
40
45
|
end
|
41
46
|
end
|
42
47
|
|
43
|
-
if
|
44
|
-
|
45
|
-
|
46
|
-
.with_locals(variables)
|
47
|
-
renderer.file_path = source_path
|
48
|
-
|
49
|
-
renderer.render(new_line: '', indent: '')
|
48
|
+
if precompiled.nil?
|
49
|
+
if compilation_context.incremental_build?
|
50
|
+
UI.print_processing_debug_info('Parsing new version of source file')
|
50
51
|
end
|
51
|
-
else
|
52
|
-
UI.print_processing_debug_info('Parsing new version of source file') if compilation_context.incremental_build?
|
53
52
|
|
54
53
|
bade_content = load_source(compilation_context)
|
55
54
|
|
@@ -58,13 +57,19 @@ module Epuber
|
|
58
57
|
.with_locals(variables)
|
59
58
|
|
60
59
|
# turn on optimizations when can
|
61
|
-
if renderer.respond_to?(:optimize=)
|
62
|
-
renderer.optimize = true
|
63
|
-
end
|
60
|
+
renderer.optimize = true if renderer.respond_to?(:optimize=)
|
64
61
|
|
65
62
|
FileUtils.mkdir_p(File.dirname(precompiled_path))
|
66
63
|
renderer.precompiled.write_yaml_to_file(precompiled_path)
|
67
64
|
|
65
|
+
renderer.render(new_line: '', indent: '')
|
66
|
+
end
|
67
|
+
else
|
68
|
+
xhtml_content = UI.print_step_processing_time('rendering precompiled Bade') do
|
69
|
+
renderer = Bade::Renderer.from_precompiled(precompiled)
|
70
|
+
.with_locals(variables)
|
71
|
+
renderer.file_path = source_path
|
72
|
+
|
68
73
|
renderer.render(new_line: '', indent: '')
|
69
74
|
end
|
70
75
|
end
|
@@ -82,7 +87,7 @@ module Epuber
|
|
82
87
|
# @return [String]
|
83
88
|
#
|
84
89
|
def precompiled_path
|
85
|
-
File.join(Config.instance.build_cache_path(PRECOMPILED_CACHE_NAME), source_path
|
90
|
+
File.join(Config.instance.build_cache_path(PRECOMPILED_CACHE_NAME), "#{source_path}.precompiled.yml")
|
86
91
|
end
|
87
92
|
|
88
93
|
def pretty_precompiled_path
|
@@ -10,7 +10,7 @@ module Epuber
|
|
10
10
|
class CoffeeScriptFile < SourceFile
|
11
11
|
# @param [Compiler::CompilationContext] compilation_context
|
12
12
|
#
|
13
|
-
def process(
|
13
|
+
def process(_compilation_context)
|
14
14
|
return if destination_file_up_to_date?
|
15
15
|
|
16
16
|
write_compiled(CoffeeScript.compile(File.new(abs_source_path)))
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'css_parser'
|
4
|
+
|
5
|
+
module Epuber
|
6
|
+
class Compiler
|
7
|
+
module FileTypes
|
8
|
+
require_relative 'source_file'
|
9
|
+
|
10
|
+
class CSSFile < SourceFile
|
11
|
+
DECLARATION_TO_FILE_GROUP_MAP = {
|
12
|
+
'background' => :image,
|
13
|
+
'background-image' => :image,
|
14
|
+
'list-style' => :image,
|
15
|
+
'list-style-image' => :image,
|
16
|
+
'content' => :image,
|
17
|
+
'cursor' => :image,
|
18
|
+
'border-image' => :image,
|
19
|
+
'border-image-source' => :image,
|
20
|
+
'mask-image' => :image,
|
21
|
+
'mask-box-image' => :image,
|
22
|
+
'src' => :font,
|
23
|
+
}.freeze
|
24
|
+
|
25
|
+
URL_REGEXP = /url\((.+)\)/.freeze
|
26
|
+
|
27
|
+
# @param [Compiler::CompilationContext] compilation_context
|
28
|
+
#
|
29
|
+
def process(compilation_context)
|
30
|
+
return if destination_file_up_to_date?
|
31
|
+
|
32
|
+
write_processed(process_css(File.read(abs_source_path), compilation_context))
|
33
|
+
end
|
34
|
+
|
35
|
+
# Processes CSS file, resolves all linked files and adds them to file resolver
|
36
|
+
#
|
37
|
+
# @param [String] content
|
38
|
+
# @param [Compiler::CompilationContext] compilation_context
|
39
|
+
#
|
40
|
+
# @return [String]
|
41
|
+
#
|
42
|
+
def process_css(content, compilation_context)
|
43
|
+
file_resolver = compilation_context.file_resolver
|
44
|
+
|
45
|
+
parser = UI.print_step_processing_time('css parsing') do
|
46
|
+
parser = CssParser::Parser.new
|
47
|
+
parser.load_string!(content)
|
48
|
+
parser
|
49
|
+
end
|
50
|
+
|
51
|
+
# resolve links to files, add other linked resources and compute correct path
|
52
|
+
UI.print_step_processing_time('resolving url()') do
|
53
|
+
parser.each_rule_set do |rule_set, _media_types|
|
54
|
+
declarations = rule_set.instance_eval { @declarations }
|
55
|
+
declarations.each do |property, decl_value|
|
56
|
+
value = decl_value.to_s
|
57
|
+
next unless value =~ URL_REGEXP
|
58
|
+
|
59
|
+
path = Regexp.last_match(1)
|
60
|
+
if path.start_with?('"') && path.end_with?('"')
|
61
|
+
path = path[1..-2]
|
62
|
+
quote = '"'
|
63
|
+
end
|
64
|
+
if path.start_with?("'") && path.end_with?("'")
|
65
|
+
path = path[1..-2]
|
66
|
+
quote = "'"
|
67
|
+
end
|
68
|
+
|
69
|
+
next if path.start_with?('data:') || path.start_with?('http://') || path.start_with?('https://')
|
70
|
+
|
71
|
+
resource_group = DECLARATION_TO_FILE_GROUP_MAP[property]
|
72
|
+
dirname = File.dirname(destination_path)
|
73
|
+
|
74
|
+
begin
|
75
|
+
new_path = file_resolver.dest_finder.find_file(path, groups: resource_group, context_path: dirname)
|
76
|
+
rescue FileFinders::FileNotFoundError, FileFinders::MultipleFilesFoundError
|
77
|
+
new_path = XHTMLProcessor.resolved_link_to_file(path,
|
78
|
+
resource_group,
|
79
|
+
dirname,
|
80
|
+
file_resolver.source_finder).to_s
|
81
|
+
pkg_abs_path = File.expand_path(new_path, dirname).unicode_normalize
|
82
|
+
pkg_new_path = Pathname.new(pkg_abs_path)
|
83
|
+
.relative_path_from(Pathname.new(file_resolver.source_path))
|
84
|
+
.to_s
|
85
|
+
|
86
|
+
file_class = FileResolver.file_class_for(File.extname(new_path))
|
87
|
+
file = file_class.new(pkg_new_path)
|
88
|
+
file.path_type = :manifest
|
89
|
+
file_resolver.add_file(file)
|
90
|
+
end
|
91
|
+
|
92
|
+
new_url = FileResolver.renamed_file_with_path(new_path)
|
93
|
+
content = content.gsub(value, "url(#{quote}#{new_url}#{quote})")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
content
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -16,14 +16,16 @@ module Epuber
|
|
16
16
|
dest = final_destination_path
|
17
17
|
source = abs_source_path
|
18
18
|
|
19
|
-
img = Magick::Image
|
19
|
+
img = Magick::Image.read(source).first
|
20
20
|
|
21
21
|
resolution = img.columns * img.rows
|
22
22
|
max_resolution = 3_000_000
|
23
23
|
|
24
24
|
if resolution > max_resolution
|
25
25
|
img = img.change_geometry("#{max_resolution}@>") do |width, height, b_img|
|
26
|
-
UI.print_processing_debug_info(
|
26
|
+
UI.print_processing_debug_info(<<~MSG)
|
27
|
+
downscaling from resolution #{b_img.columns}x#{b_img.rows} to #{width}x#{height}
|
28
|
+
MSG
|
27
29
|
b_img.resize!(width, height)
|
28
30
|
end
|
29
31
|
|