epuber 0.8.0 → 0.9.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +9 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +2 -2
  5. data/epuber.gemspec +3 -6
  6. data/lib/epuber/book/contributor.rb +10 -6
  7. data/lib/epuber/book/file_request.rb +2 -2
  8. data/lib/epuber/book/target.rb +10 -10
  9. data/lib/epuber/book.rb +2 -2
  10. data/lib/epuber/checker/text_checker.rb +14 -6
  11. data/lib/epuber/checker_transformer_base.rb +1 -1
  12. data/lib/epuber/command/build.rb +6 -1
  13. data/lib/epuber/command/from_file.rb +39 -0
  14. data/lib/epuber/command/init.rb +11 -9
  15. data/lib/epuber/command/server.rb +1 -1
  16. data/lib/epuber/command.rb +1 -0
  17. data/lib/epuber/compiler/file_database.rb +2 -2
  18. data/lib/epuber/compiler/file_finders/abstract.rb +3 -3
  19. data/lib/epuber/compiler/file_resolver.rb +3 -2
  20. data/lib/epuber/compiler/file_types/abstract_file.rb +1 -3
  21. data/lib/epuber/compiler/file_types/bade_file.rb +9 -9
  22. data/lib/epuber/compiler/file_types/css_file.rb +84 -0
  23. data/lib/epuber/compiler/file_types/source_file.rb +31 -0
  24. data/lib/epuber/compiler/file_types/stylus_file.rb +4 -3
  25. data/lib/epuber/compiler/nav_generator.rb +5 -5
  26. data/lib/epuber/compiler/opf_generator.rb +4 -4
  27. data/lib/epuber/compiler/xhtml_processor.rb +7 -25
  28. data/lib/epuber/compiler.rb +12 -7
  29. data/lib/epuber/config.rb +3 -3
  30. data/lib/epuber/dsl/attribute.rb +1 -1
  31. data/lib/epuber/dsl/attribute_support.rb +4 -4
  32. data/lib/epuber/dsl/object.rb +2 -2
  33. data/lib/epuber/from_file/bookspec_generator.rb +371 -0
  34. data/lib/epuber/from_file/encryption_handler.rb +146 -0
  35. data/lib/epuber/from_file/from_file_executor.rb +140 -0
  36. data/lib/epuber/from_file/nav_file.rb +163 -0
  37. data/lib/epuber/from_file/opf_file.rb +219 -0
  38. data/lib/epuber/plugin.rb +1 -1
  39. data/lib/epuber/server.rb +17 -17
  40. data/lib/epuber/transformer/book_transformer.rb +108 -0
  41. data/lib/epuber/transformer.rb +2 -0
  42. data/lib/epuber/user_interface.rb +2 -2
  43. data/lib/epuber/vendor/ruby_templater.rb +3 -3
  44. data/lib/epuber/vendor/version.rb +3 -3
  45. data/lib/epuber/version.rb +1 -1
  46. metadata +40 -59
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f0fcab4dfe82bc1ae829738a62f4915f02e79bbc105ab9eafd6d2c0a664dc60
4
- data.tar.gz: 4fcaf730a6caf5d560a1525b5a2a000d29efec2819c82e7c1fdd1bc4cd470228
3
+ metadata.gz: e7acd7fcb74da144389521daa83a8fb681015b82d5cc8a1da35de6058d26fec3
4
+ data.tar.gz: d61a1ac243fc871f6bf2a114d24936b123ed5a28666057b76fb3fc0da6109265
5
5
  SHA512:
6
- metadata.gz: 4fd75c5cda4801241fa762d728308c3c1ebe9d668cc8cf4f9c7be3b3df48ca4715ec2498a2a4914a0c138c21adf49ecdcc66f49e47a33d0487107dd4b05a4d1b
7
- data.tar.gz: 14e7bb639a81535df13bde1f5f92ecb29cf2892d5692d93ee1b97b1045cd650c4480cccfc7262280e2ad135a31796cb04932993d6e0dac21f0cbfaa226544045
6
+ metadata.gz: 85a24b75e370556e3a028e0c118b4f4bc36395c4140472ddfde4be4c46fd95549fecf3d18c28d72bf545b13f9850d82394ea509b8a97d9e3f1078f678d28647e
7
+ data.tar.gz: 62483b8f634b572336cbede86754baa95d3627ac0c69d4f47e44ca701e57b201b53e0b9568a22fd7d4c3ebee6f345c1b132012be303f0ab73ed4db26d332deb3
data/Gemfile CHANGED
@@ -5,6 +5,15 @@ source 'https://rubygems.org'
5
5
  # Specify your gem's dependencies in Epuber.gemspec
6
6
  gemspec
7
7
 
8
+ # dev
9
+ gem 'fakefs', '>= 1.3', '< 3.0' # 2.0.0 is not compatible with Ruby 2.5
10
+ gem 'rake', '~> 13.0'
11
+ gem 'rspec', '~> 3.2'
12
+ gem 'rubocop', '~> 1.14'
13
+
14
+ # VSCode plugins
15
+ gem 'ruby-lsp', require: false
16
+
8
17
  group :dev, optional: true do
9
18
  gem 'rubocop-rspec', require: false
10
19
  end
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Roman Kříž
3
+ Copyright (c) 2015-2023 Roman Kříž
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -104,9 +104,9 @@ To install this gem onto your local machine, run `bundle exec rake install`.
104
104
 
105
105
  ## Contributing
106
106
 
107
- Bug reports and pull requests are welcome on GitHub at https://github.com/epuber-io/epuber. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
107
+ Bug reports and pull requests are welcome on GitHub at https://github.com/epuber-io/epuber. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](https://www.contributor-covenant.org/) code of conduct.
108
108
 
109
109
 
110
110
  ## License
111
111
 
112
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
112
+ The gem is available as open source under the terms of the [MIT License](./LICENSE.txt).
data/epuber.gemspec CHANGED
@@ -11,10 +11,10 @@ Gem::Specification.new do |spec|
11
11
  spec.homepage = Epuber::HOME_URL
12
12
  spec.license = 'MIT'
13
13
  spec.required_ruby_version = '>= 2.5'
14
+ spec.metadata['rubygems_mfa_required'] = 'true'
14
15
 
15
16
  spec.files = Dir['bin/**/*'] + Dir['lib/**/*'] + %w[epuber.gemspec Gemfile LICENSE.txt README.md]
16
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ['lib']
19
19
 
20
20
  spec.add_runtime_dependency 'activesupport', '>= 6.0', '< 8.0'
@@ -24,6 +24,7 @@ Gem::Specification.new do |spec|
24
24
  spec.add_runtime_dependency 'mime-types', '~> 3.0'
25
25
  spec.add_runtime_dependency 'nokogiri', '~> 1.8', '>= 1.8.2'
26
26
  spec.add_runtime_dependency 'os', '~> 1.0'
27
+ spec.add_runtime_dependency 'uuidtools', '~> 2.1'
27
28
 
28
29
  spec.add_runtime_dependency 'sinatra', '>= 2.0', '< 4.0'
29
30
  spec.add_runtime_dependency 'sinatra-contrib', '>= 2.0', '< 4.0'
@@ -37,10 +38,6 @@ Gem::Specification.new do |spec|
37
38
 
38
39
  spec.add_runtime_dependency 'bade', '~> 0.3', '>= 0.3.1'
39
40
  spec.add_runtime_dependency 'coffee-script', '~> 2.4'
41
+ spec.add_runtime_dependency 'css_parser', '>= 0.8', '< 2.0'
40
42
  spec.add_runtime_dependency 'epuber-stylus', '~> 1.1', '>= 1.1.1'
41
-
42
- spec.add_development_dependency 'fakefs', '>= 1.3', '< 3.0' # 2.0.0 is not compatible with Ruby 2.5
43
- spec.add_development_dependency 'rake', '~> 13.0'
44
- spec.add_development_dependency 'rspec', '~> 3.2'
45
- spec.add_development_dependency 'rubocop', '~> 1.14'
46
43
  end
@@ -31,22 +31,26 @@ module Epuber
31
31
 
32
32
  # Creates new instance of Contributor dependent on obj content
33
33
  #
34
- # @param obj [Hash<Symbol, String>, Array<Hash<Symbol,String>, String, Array<String>] input object
35
- # @param role [String] role of contributor
34
+ # @param [Hash<Symbol, String>, Array<Hash<Symbol,String>, String, Array<String>] obj input object
35
+ # @param [String] role role of contributor
36
36
  #
37
37
  # @return [Contributor]
38
38
  #
39
- def self.from_obj(obj, role)
39
+ def self.from_obj(obj, role = 'aut')
40
40
  if obj.is_a?(String)
41
- components = obj.split(' ')
41
+ components = obj.split
42
42
  if components.length >= 2
43
43
  NormalContributor.new(components.first(components.length - 1).join(' '), components.last, role)
44
+ else
45
+ Contributor.new(obj, obj, role)
44
46
  end
45
47
  elsif obj.is_a?(Hash)
46
48
  if obj.key?(:first_name)
47
- NormalContributor.new(obj[:first_name], obj[:last_name], role)
49
+ NormalContributor.new(obj[:first_name], obj[:last_name], obj[:role] || role)
48
50
  elsif obj.key?(:file_as)
49
- Contributor.new(obj[:pretty_name], obj[:file_as], role)
51
+ Contributor.new(obj[:pretty_name], obj[:file_as], obj[:role] || role)
52
+ elsif obj.key?(:name)
53
+ Contributor.from_obj(obj[:name], obj[:role] || role)
50
54
  end
51
55
  end
52
56
  end
@@ -45,10 +45,10 @@ module Epuber
45
45
  # @return [Numeric]
46
46
  #
47
47
  def hash
48
- @source_pattern.hash ^ @group.hash ^ @only_one.hash
48
+ [@source_pattern, @group, @only_one].hash
49
49
  end
50
50
 
51
- # @param other [String, self]
51
+ # @param [String, self] other
52
52
  #
53
53
  def ==(other)
54
54
  if other.is_a?(String)
@@ -215,8 +215,8 @@ module Epuber
215
215
  inherited: false
216
216
 
217
217
 
218
- # @param file_path [String | Epuber::Book::File]
219
- # @param group [Symbol]
218
+ # @param [String | Epuber::Book::File] file_path
219
+ # @param [Symbol] group
220
220
  #
221
221
  # @return [Epuber::Book::File] created file
222
222
  #
@@ -238,7 +238,7 @@ module Epuber
238
238
  end
239
239
  end
240
240
 
241
- # @param file_paths [Array<String>]
241
+ # @param [Array<String>] file_paths
242
242
  #
243
243
  # @return [void]
244
244
  #
@@ -249,8 +249,8 @@ module Epuber
249
249
  end
250
250
  end
251
251
 
252
- # @param key [String]
253
- # @param value [String]
252
+ # @param [String] key
253
+ # @param [String] value
254
254
  #
255
255
  # @return [void]
256
256
  #
@@ -262,7 +262,7 @@ module Epuber
262
262
  end
263
263
  end
264
264
 
265
- # @param file_paths [Array<String>]
265
+ # @param [Array<String>] file_paths
266
266
  #
267
267
  # @return [void]
268
268
  #
@@ -278,7 +278,7 @@ module Epuber
278
278
  # Add default styles to default target, default styles will be automatically added to xhtml document
279
279
  #
280
280
  # Only difference with #add_default_style is it adds multiple files with one pattern
281
- # @param file_paths [Array<String>]
281
+ # @param [Array<String>] file_paths
282
282
  #
283
283
  # @return [void]
284
284
  #
@@ -291,7 +291,7 @@ module Epuber
291
291
  end
292
292
  end
293
293
 
294
- # @param file_paths [Array<String>]
294
+ # @param [Array<String>] file_paths
295
295
  #
296
296
  # @return [void]
297
297
  #
@@ -307,7 +307,7 @@ module Epuber
307
307
  # Add default scripts to target, default scripts will be automatically added to xhtml document
308
308
  #
309
309
  # Only difference with #add_default_script is it adds multiple files with one pattern
310
- # @param file_paths [Array<String>]
310
+ # @param [Array<String>] file_paths
311
311
  #
312
312
  # @return [void]
313
313
  #
@@ -330,7 +330,7 @@ module Epuber
330
330
  yield(@root_toc, self) if block_given?
331
331
  end
332
332
 
333
- # @param path [String] use some file/module/package
333
+ # @param [String] path use some file/module/package
334
334
  #
335
335
  # @return [nil]
336
336
  #
data/lib/epuber/book.rb CHANGED
@@ -160,7 +160,7 @@ module Epuber
160
160
  container: Array,
161
161
  required: true,
162
162
  singularize: true,
163
- auto_convert: { [String, Hash] => ->(value) { Contributor.from_obj(value, 'aut') } }
163
+ auto_convert: { [String, Hash] => ->(value) { Contributor.from_obj(value) } }
164
164
 
165
165
 
166
166
  # @return [String] publisher name
@@ -294,7 +294,7 @@ module Epuber
294
294
 
295
295
  # Finds target with name or nil when not found
296
296
  #
297
- # @param target_name [Symbol, String, Epuber::Book::Target]
297
+ # @param [Symbol, String, Epuber::Book::Target] target_name
298
298
  #
299
299
  # @return [Epuber::Book::Target, nil]
300
300
  #
@@ -10,9 +10,9 @@ module Epuber
10
10
  class Checker
11
11
  class TextChecker < Checker
12
12
  class MatchProblem < Compiler::Problem
13
- # @param message [String]
14
- # @param file_path [String]
15
- # @param match [MatchData]
13
+ # @param [String] message
14
+ # @param [String] file_path
15
+ # @param [MatchData] match
16
16
  #
17
17
  def initialize(match, message, file_path)
18
18
  whole_text = match.pre_match + match.matched_string + match.post_match
@@ -36,8 +36,8 @@ module Epuber
36
36
 
37
37
 
38
38
 
39
- # @param file_path [String]
40
- # @param text [String]
39
+ # @param [String] file_path
40
+ # @param [String] text
41
41
  # @param [CompilationContext] compilation_context
42
42
  #
43
43
  # @return nil
@@ -52,7 +52,7 @@ module Epuber
52
52
  @file_path = nil
53
53
  end
54
54
 
55
- # @param regexp [Regexp]
55
+ # @param [Regexp] regexp
56
56
  # @param [String] message message to display, when the regexp found something
57
57
  #
58
58
  def should_not_contain(regexp, message)
@@ -65,6 +65,14 @@ module Epuber
65
65
  Config.instance.pretty_path_from_project(file_path))
66
66
  end
67
67
  end
68
+
69
+ def error(message, location: nil)
70
+ super(message, location: location || Config.instance.pretty_path_from_project(file_path))
71
+ end
72
+
73
+ def warning(message, location: nil)
74
+ super(message, location: location || Config.instance.pretty_path_from_project(file_path))
75
+ end
68
76
  end
69
77
  end
70
78
  end
@@ -55,7 +55,7 @@ module Epuber
55
55
  {}
56
56
  end
57
57
 
58
- # @param type [Symbol]
58
+ # @param [Symbol] type
59
59
  #
60
60
  # @return [Class]
61
61
  #
@@ -26,7 +26,12 @@ module Epuber
26
26
  ].concat(super)
27
27
  end
28
28
 
29
- # @param argv [CLAide::ARGV]
29
+ # To resolve problem with `compile` treating as subcommand
30
+ def self.subcommands
31
+ []
32
+ end
33
+
34
+ # @param [CLAide::ARGV] argv
30
35
  #
31
36
  def initialize(argv)
32
37
  @targets_names = argv.arguments!
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../command'
4
+ require_relative '../from_file/from_file_executor'
5
+
6
+ module Epuber
7
+ class Command
8
+ class FromFile < Command
9
+ self.summary = 'Initialize current folder to use it as Epuber project from existing EPUB file'
10
+ self.arguments = [
11
+ CLAide::Argument.new('EPUB_FILE', true),
12
+ ]
13
+
14
+ # @param [CLAide::ARGV] argv
15
+ #
16
+ def initialize(argv)
17
+ @filepath = argv.arguments!.first
18
+
19
+ super(argv)
20
+ end
21
+
22
+ def validate!
23
+ super
24
+
25
+ help! 'You must specify path to existing EPUB file' if @filepath.nil?
26
+ help! "File #{@filepath} doesn't exists" unless File.exist?(@filepath)
27
+
28
+ existing = Dir.glob('*.bookspec')
29
+ help! "Can't reinit this folder, #{existing.first} already exists." unless existing.empty?
30
+ end
31
+
32
+ def run
33
+ super
34
+
35
+ FromFileExecutor.new(@filepath).run
36
+ end
37
+ end
38
+ end
39
+ end
@@ -11,10 +11,10 @@ module Epuber
11
11
  class Init < Command
12
12
  self.summary = 'Initialize current folder to use it as Epuber project'
13
13
  self.arguments = [
14
- CLAide::Argument.new('PROJECT_NAME', false, true),
14
+ CLAide::Argument.new('PROJECT_NAME', false),
15
15
  ]
16
16
 
17
- # @param argv [CLAide::ARGV]
17
+ # @param [CLAide::ARGV] argv
18
18
  #
19
19
  def initialize(argv)
20
20
  @book_name = argv.arguments!.first
@@ -23,6 +23,8 @@ module Epuber
23
23
  end
24
24
 
25
25
  def validate!
26
+ super
27
+
26
28
  help! 'You must specify identifier-like name of the book as first argument' if @book_name.nil?
27
29
 
28
30
  existing = Dir.glob('*.bookspec')
@@ -57,7 +59,7 @@ module Epuber
57
59
 
58
60
  # Creates <book-id>.bookspec file from template
59
61
  #
60
- # @param book_id [String]
62
+ # @param [String] book_id
61
63
  #
62
64
  # @return [void]
63
65
  #
@@ -71,7 +73,7 @@ module Epuber
71
73
 
72
74
  # Creates <book-id>.sublime-project
73
75
  #
74
- # @param book_id [String]
76
+ # @param [String] book_id
75
77
  #
76
78
  # @return [void]
77
79
  #
@@ -115,8 +117,8 @@ module Epuber
115
117
  STYLUS
116
118
  end
117
119
 
118
- # @param string [String] text to file
119
- # @param file_path [String] path to file
120
+ # @param [String] string text to file
121
+ # @param [String] file_path path to file
120
122
  #
121
123
  # @return [void]
122
124
  #
@@ -125,8 +127,8 @@ module Epuber
125
127
  UI.puts " #{'create'.ansi.green} #{file_path}"
126
128
  end
127
129
 
128
- # @param string [String] text to file
129
- # @param file_path [String] path to file
130
+ # @param [String] string text to file
131
+ # @param [String] file_path path to file
130
132
  #
131
133
  # @return [void]
132
134
  #
@@ -158,7 +160,7 @@ module Epuber
158
160
  UI.puts " #{'create'.ansi.green} #{dir_path}/"
159
161
  end
160
162
 
161
- # @param text [String]
163
+ # @param [String] text
162
164
  #
163
165
  # @return [String] returned text without new line
164
166
  #
@@ -17,7 +17,7 @@ module Epuber
17
17
  ].concat(super)
18
18
  end
19
19
 
20
- # @param args [CLAide::ARGV]
20
+ # @param [CLAide::ARGV] args
21
21
  #
22
22
  def initialize(args)
23
23
  super
@@ -16,6 +16,7 @@ module Epuber
16
16
  require_relative 'command/compile'
17
17
  require_relative 'command/init'
18
18
  require_relative 'command/server'
19
+ require_relative 'command/from_file'
19
20
 
20
21
  self.abstract_command = true
21
22
  self.command = 'epuber'
@@ -65,7 +65,7 @@ module Epuber
65
65
  end
66
66
 
67
67
  def update_all_metadata
68
- @all_files.each do |file_path, _|
68
+ @all_files.each_key do |file_path|
69
69
  update_metadata(file_path)
70
70
  end
71
71
  end
@@ -98,7 +98,7 @@ module Epuber
98
98
  to_remove = @all_files.keys - file_paths
99
99
  to_remove.each { |key| @all_files.delete(key) }
100
100
 
101
- @all_files.each do |_, stat|
101
+ @all_files.each_value do |stat|
102
102
  _cleanup_stat_dependency_list(file_paths, stat)
103
103
  end
104
104
  end
@@ -194,7 +194,7 @@ module Epuber
194
194
  end.flatten
195
195
 
196
196
  paths.select do |file_path|
197
- valid_extensions.include?(::File.extname(file_path))
197
+ valid_extensions.include?(::File.extname(file_path).downcase)
198
198
  end
199
199
  end
200
200
  end
@@ -247,8 +247,8 @@ module Epuber
247
247
  # @return [Array<String>] list of founded files
248
248
  #
249
249
  def __core_find_files(pattern, groups, context_path, orig_context_path = context_path)
250
- context_path = __core_file?(context_path) ? File.dirname(context_path) : context_path
251
- orig_context_path = __core_file?(orig_context_path) ? File.dirname(orig_context_path) : orig_context_path
250
+ context_path = File.dirname(context_path) if __core_file?(context_path)
251
+ orig_context_path = File.dirname(orig_context_path) if __core_file?(orig_context_path)
252
252
 
253
253
  full_pattern = File.expand_path(pattern, context_path)
254
254
  file_paths = __core_find_files_from_pattern(full_pattern).map(&:unicode_normalize)
@@ -20,7 +20,7 @@ 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
@@ -247,6 +247,7 @@ module Epuber
247
247
  def file_class_for(extname)
248
248
  mapping = {
249
249
  '.styl' => FileTypes::StylusFile,
250
+ '.css' => FileTypes::CSSFile,
250
251
 
251
252
  '.coffee' => FileTypes::CoffeeScriptFile,
252
253
 
@@ -279,7 +280,7 @@ module Epuber
279
280
 
280
281
  private
281
282
 
282
- # @param file [Epuber::Compiler::AbstractFile]
283
+ # @param [Epuber::Compiler::AbstractFile] file
283
284
  #
284
285
  # @return [nil]
285
286
  #
@@ -87,9 +87,7 @@ module Epuber
87
87
  def self.write_to_file!(content, to_path)
88
88
  FileUtils.mkdir_p(File.dirname(to_path))
89
89
 
90
- File.open(to_path, 'w') do |file_handle|
91
- file_handle.write(content)
92
- end
90
+ File.write(to_path, content)
93
91
  end
94
92
  end
95
93
  end
@@ -45,15 +45,7 @@ module Epuber
45
45
  end
46
46
  end
47
47
 
48
- if !precompiled.nil?
49
- xhtml_content = UI.print_step_processing_time('rendering precompiled Bade') do
50
- renderer = Bade::Renderer.from_precompiled(precompiled)
51
- .with_locals(variables)
52
- renderer.file_path = source_path
53
-
54
- renderer.render(new_line: '', indent: '')
55
- end
56
- else
48
+ if precompiled.nil?
57
49
  if compilation_context.incremental_build?
58
50
  UI.print_processing_debug_info('Parsing new version of source file')
59
51
  end
@@ -70,6 +62,14 @@ module Epuber
70
62
  FileUtils.mkdir_p(File.dirname(precompiled_path))
71
63
  renderer.precompiled.write_yaml_to_file(precompiled_path)
72
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
+
73
73
  renderer.render(new_line: '', indent: '')
74
74
  end
75
75
  end
@@ -0,0 +1,84 @@
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
+ parser = UI.print_step_processing_time('css parsing') do
44
+ parser = CssParser::Parser.new
45
+ parser.load_string!(content)
46
+ parser
47
+ end
48
+
49
+ # resolve links to files, add other linked resources and compute correct path
50
+ UI.print_step_processing_time('resolving url()') do
51
+ parser.each_rule_set do |rule_set, _media_types|
52
+ declarations = rule_set.instance_eval { @declarations }
53
+ declarations.each do |property, decl_value|
54
+ value = decl_value.to_s
55
+ next unless value =~ URL_REGEXP
56
+
57
+ path = Regexp.last_match(1)
58
+ if path.start_with?('"') && path.end_with?('"')
59
+ path = path[1..-2]
60
+ quote = '"'
61
+ end
62
+ if path.start_with?("'") && path.end_with?("'")
63
+ path = path[1..-2]
64
+ quote = "'"
65
+ end
66
+
67
+ next if path.start_with?('data:') || path.start_with?('http://') || path.start_with?('https://')
68
+
69
+ resource_group = DECLARATION_TO_FILE_GROUP_MAP[property]
70
+ new_url = SourceFile.resolve_relative_file(destination_path,
71
+ path,
72
+ compilation_context.file_resolver,
73
+ group: resource_group)
74
+ content = content.gsub(value, "url(#{quote}#{new_url}#{quote})")
75
+ end
76
+ end
77
+ end
78
+
79
+ content
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -112,6 +112,37 @@ module Epuber
112
112
  MSG
113
113
  end
114
114
  end
115
+
116
+ def self.resolve_relative_file(destination_path, pattern, file_resolver, group: nil)
117
+ dirname = File.dirname(destination_path)
118
+
119
+ begin
120
+ new_path = file_resolver.dest_finder.find_file(pattern, groups: group, context_path: dirname)
121
+ rescue FileFinders::FileNotFoundError, FileFinders::MultipleFilesFoundError
122
+ begin
123
+ new_path = XHTMLProcessor.resolved_link_to_file(pattern,
124
+ group,
125
+ dirname,
126
+ file_resolver.source_finder).to_s
127
+ rescue XHTMLProcessor::UnparseableLinkError,
128
+ FileFinders::FileNotFoundError,
129
+ FileFinders::MultipleFilesFoundError => e
130
+ UI.warning(e.to_s, location: img)
131
+ end
132
+ end
133
+
134
+ pkg_abs_path = File.expand_path(new_path, dirname).unicode_normalize
135
+ pkg_new_path = Pathname.new(pkg_abs_path)
136
+ .relative_path_from(Pathname.new(file_resolver.source_path))
137
+ .to_s
138
+
139
+ file_class = FileResolver.file_class_for(File.extname(new_path))
140
+ file = file_class.new(pkg_new_path)
141
+ file.path_type = :manifest
142
+ file_resolver.add_file(file)
143
+
144
+ FileResolver.renamed_file_with_path(new_path)
145
+ end
115
146
  end
116
147
  end
117
148
  end