asciidoctor-reducer 1.0.0.alpha.3 → 1.0.0.alpha.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4b0c9530e403be351428ec664c9a5d763a0f27686505e8328d831f46f9ad580b
4
- data.tar.gz: ea5116a19ea8e1199415f5e50ee9339dcec66b87b2c574f60306c8b68e9083b8
3
+ metadata.gz: 2a685ae408de9db32a7ec96055b70120ea6f7476436dca071cc37155cc680d56
4
+ data.tar.gz: 39d783c66481423417d64a232ee01bdaa88bef517474d22e8ec9fdeb670d09d9
5
5
  SHA512:
6
- metadata.gz: c3f8025d47b14f4701c4883151403e7fc1aa498cb3d82b9180f7935e14e2aa95a149517e9b037f92d4086d01bd1133aae3088158018ecd088de8f0dc221d5602
7
- data.tar.gz: 79ee7b026d7de3f74b2423e193b85c3e0d8d1e1a783e27af4e838522f13c7712871c1379556757ebc432999a0625590d8e03c80d6ef5259104c088a412fa8d25
6
+ metadata.gz: a3376645764a9d608f3e3aad5f29f2080748d9ecd20d90a06e2335263cdd7c88c0450a72ea061f8f36c17fa19af0f985a89002ee70e12ce950f4320c483b8140
7
+ data.tar.gz: a7899259cf2ff2daf619d13b97d88dd460a013b0bc85d2c8402e1283f1b3d6fff3780bc3c112e4c281463ad06e0bcb035385998771528a01e3aac487dd7c6e09
data/CHANGELOG.adoc CHANGED
@@ -4,6 +4,64 @@
4
4
  This document provides a high-level view of the changes to the Asciidoctor Reducer by release.
5
5
  For a detailed view of what has changed, refer to the {url-repo}/commits/main[commit history] on GitHub.
6
6
 
7
+ == 1.0.0.alpha.7 (2022-02-14) - @mojavelinux
8
+
9
+ === Added
10
+
11
+ * Add asciidoctor/reducer/api to require main API (#3)
12
+ * Add `Asciidoctor::Reducer.reduce` and `Asciidoctor::Reducer.reduce_file` API methods (#3)
13
+ * Add asciidoctor/reducer/extensions to require extensions API (#3)
14
+ * Add `Asciidoctor::Reducer::Extensions` API (#3)
15
+
16
+ === Changed
17
+
18
+ * Scope extensions to single call instead of registering them globally (#3)
19
+ * Use `:safe` as the default safe mode when using the API
20
+ * Make `CurrentPosition` module private to the `PreprocessorDirectiveTracker` module
21
+
22
+ === Fixed
23
+
24
+ * Require asciidoctor/reducer/version automatically when `Asciidoctor::Reducer::VERSION` is accessed
25
+
26
+ == 1.0.0.alpha.6 (2022-02-10) - @mojavelinux
27
+
28
+ === Added
29
+
30
+ * Add `-S`, `--safe-mode` option to CLI to set safe mode (#13)
31
+ * Add `-r`, `--require` option to CLI to specify additional libraries to require before running (#17)
32
+
33
+ === Changed
34
+
35
+ * Sort CLI options in help text, except for the `-h`, `--help` option
36
+ * Update CLI to always use a new logger instance
37
+ * Defer initializing logger until run method is called
38
+
39
+ === Fixed
40
+
41
+ * Replace include directives that follow an unresolved include (#19)
42
+ * Don't activate reducer extensions on reduced document
43
+ * Prevent custom extension registry from activating extensions twice during reload (#21)
44
+ * Retain includes table in document catalog when reloading document (#23)
45
+
46
+ == 1.0.0.alpha.5 (2022-02-06) - @mojavelinux
47
+
48
+ === Changed
49
+
50
+ * Removing trailing empty lines after reducing when sourcemap is not enabled
51
+ * Remove unnecessary override of lineno in preprocess_include_directive override
52
+ * Simplify how include replacement target is tracked
53
+ * Classify extensions in group named `:reducer`
54
+
55
+ === Fixed
56
+
57
+ * Suppress log messages when reloading document (#14)
58
+
59
+ == 1.0.0.alpha.4 (2022-02-03) - @mojavelinux
60
+
61
+ === Fixed
62
+
63
+ * Fix replacement of nested empty and unresolved includes
64
+
7
65
  == 1.0.0.alpha.3 (2022-02-02) - @mojavelinux
8
66
 
9
67
  === Changed
@@ -17,15 +75,15 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co
17
75
 
18
76
  === Added
19
77
 
20
- * Add `-a` / `--attribute` option to CLI for setting an AsciiDoc document attribute at runtime (#6)
78
+ * Add `-a`, `--attribute` option to CLI for setting an AsciiDoc document attribute at runtime (#6)
21
79
 
22
80
  === Changed
23
81
 
24
- * Reduce preprocessor conditionals by default; add option (`--preserve-conditionals` / `:preserve_conditionals`) to preserve them (#8)
82
+ * Reduce preprocessor conditionals by default; add option (`--preserve-conditionals`, `:preserve_conditionals`) to preserve them (#8)
25
83
  * Don't enable sourcemap automatically (#4)
26
84
  * Don't override logger by default; instead, rely on `:logger` API option to change logger
27
85
  * Add `--log-level` option to CLI to set severity level on logger (#9)
28
- * Add `-q` / `--quiet` option to CLI to suppress log messages (#9)
86
+ * Add `-q`, `--quiet` option to CLI to suppress log messages (#9)
29
87
  * Reserve zero index in include replacements for top-level document
30
88
 
31
89
  === Fixed
@@ -47,3 +105,19 @@ Initial release.
47
105
  === Details
48
106
 
49
107
  {url-repo}/releases/tag/v1.0.0.alpha.3[git tag]
108
+
109
+ === Details
110
+
111
+ {url-repo}/releases/tag/v1.0.0.alpha.4[git tag]
112
+
113
+ === Details
114
+
115
+ {url-repo}/releases/tag/v1.0.0.alpha.5[git tag]
116
+
117
+ === Details
118
+
119
+ {url-repo}/releases/tag/v1.0.0.alpha.6[git tag]
120
+
121
+ === Details
122
+
123
+ {url-repo}/releases/tag/v1.0.0.alpha.7[git tag]
data/README.adoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = {project-name}
2
2
  Dan Allen <https://github.com/mojavelinux[@mojavelinux]>
3
- v1.0.0.alpha.3, 2022-02-02
3
+ v1.0.0.alpha.7, 2022-02-14
4
4
  :idprefix:
5
5
  :idseparator: -
6
6
  ifndef::env-github[:icons: font]
@@ -22,15 +22,15 @@ If the document does not contain any preprocessor directives, the tool returns t
22
22
 
23
23
  == Prerequisites
24
24
 
25
- {project-name} is a Ruby program that you install using Ruby packaging.
26
- Therefore, to install and run {project-name}, you need Ruby 2.5 or better installed.
25
+ {project-name} is a Ruby application that you install using Ruby packaging.
26
+ To install and run {project-name}, you need Ruby 2.5 or better.
27
27
 
28
- To check whether you have Ruby installed, and which version, run the following command:
28
+ Run the following command to check which version of Ruby you have installed, if any:
29
29
 
30
30
  $ ruby -v
31
31
 
32
32
  If Ruby is not installed, you can install it using {url-rvm}[RVM] (or, if you prefer, the package manager for your system).
33
- We generally recommend using RVM because it allows you to install gems without requiring elevated privileges or messing with system libraries.
33
+ We generally recommend using RVM as it allows you to install gems without requiring elevated privileges or messing with system libraries.
34
34
 
35
35
  == Installation
36
36
 
@@ -41,7 +41,9 @@ You can install the latest version of the gem using the following command:
41
41
  $ gem install asciidoctor-reducer --pre
42
42
 
43
43
  Installing this gem makes the `asciidoctor-reducer` command available on your $PATH.
44
- You can also require the gem into the Ruby runtime to use it as an Asciidoctor extension.
44
+ You can also require the gem into the Ruby runtime to use it as a library or Asciidoctor extension.
45
+
46
+ === Project-scoped
45
47
 
46
48
  If you prefer to manage the application as a project-scoped dependency, you can declare the gem in the project's [.path]_Gemfile_:
47
49
 
@@ -61,7 +63,7 @@ Installing the gem this way makes the `bundle exec asciidoctor-reducer` command
61
63
 
62
64
  == Usage
63
65
 
64
- === As command
66
+ === Command
65
67
 
66
68
  You can run this tool using the provided command (i.e., CLI), named `asciidoctor-reducer`.
67
69
  To learn how to use the command, and to verify it's available, run the command with the `-h` option:
@@ -75,7 +77,9 @@ asciidoctor-reducer [OPTION]... FILE
75
77
  ....
76
78
 
77
79
  The argument `FILE` is the AsciiDoc file you want to reduce.
78
- To use the command, pass the AsciiDoc file as the sole argument:
80
+ The options, represented by `+[OPTION]...+`, are optional, as the name suggestions.
81
+
82
+ Thus, to use the command, pass the AsciiDoc file as the sole argument:
79
83
 
80
84
  $ asciidoctor-reducer input.adoc
81
85
 
@@ -89,27 +93,26 @@ To use the command in this way, pass `-` as the first argument:
89
93
 
90
94
  $ cat input.adoc | asciidoctor-reducer -
91
95
 
92
- To write the output to a file instead of stdout, also specify an output file using the `-o` option:
96
+ To write the output to a file in this case, specify an output file using the `-o` option:
93
97
 
94
98
  $ cat input.adoc | asciidoctor-reducer -o output.adoc -
95
99
 
96
- Note that top-level include files in the input AsciiDoc document are resolved relative to current working directory.
97
-
98
- === As extension
100
+ === API
99
101
 
100
- You can use this tool as an Asciidoctor extension when using the Asciidoctor API.
101
- To do so, require it before calling the `Asciidoctor.load` method.
102
+ You can also use this tool from a Ruby application using the provided API.
103
+ To begin, require the API for this library.
102
104
 
103
105
  [,ruby]
104
106
  ----
105
- require 'asciidoctor/reducer'
107
+ require 'asciidoctor/reducer/api'
106
108
  ----
107
109
 
108
- Next, load a parent document that contains includes.
110
+ Next, reduce a parent document that contains includes.
111
+ This works without having to specify the safe mode since the default safe mode when using the API is `:safe`.
109
112
 
110
113
  [,ruby]
111
114
  ----
112
- doc = Asciidoctor.load_file 'sample.adoc', safe: :safe
115
+ doc = Asciidoctor::Reducer.reduce_file 'sample.adoc'
113
116
  ----
114
117
 
115
118
  Finally, you can retrieve the reduced source from the returned document.
@@ -119,11 +122,60 @@ Finally, you can retrieve the reduced source from the returned document.
119
122
  puts doc.source
120
123
  ----
121
124
 
122
- You can write this source to a file to save the reduced document.
125
+ The benefit of this approach is that you can access the reduced source and the parsed document that corresponds to it.
126
+
127
+ If you don't need the parsed document, you can retrieve the reduced source directly by passing the `String` type to the `:to` option:
128
+
129
+ [,ruby]
130
+ ----
131
+ puts Asciidoctor::Reducer.reduce_file 'sample.adoc', to: String
132
+ ----
133
+
134
+ You can write the reduced source directly to a file by passing a file path to the `:to` option:
135
+
136
+ [,ruby]
137
+ ----
138
+ Asciidoctor::Reducer.reduce_file 'sample.adoc', to: 'sample-reduced.adoc'
139
+ ----
140
+
141
+ == Extension
142
+
143
+ Instead of using the API for this library, you can use the load API provided by Asciidoctor.
144
+ If you want to register the extension globally, require the library as follows:
145
+
146
+ [,ruby]
147
+ ----
148
+ require 'asciidoctor/reducer'
149
+ ----
150
+
151
+ When you use the Asciidoctor load API, the document will automatically be reduced.
152
+
153
+ [,ruby]
154
+ ----
155
+ puts (Asciidoctor.load_file 'sample.adoc', safe: :safe).source
156
+ ----
157
+
158
+ If you want to keep the extension scoped to the call, require the library as follows:
159
+
160
+ [,ruby]
161
+ ----
162
+ require 'asciidoctor/reducer/extensions'
163
+ ----
164
+
165
+ Next, use the extensions API to prepare an extension registry and pass it to the Asciidoctor load API:
166
+
167
+ [,ruby]
168
+ ----
169
+ puts (Asciidoctor.load_file 'sample.adoc', safe: :safe, extension_registry: Asciidoctor::Reducer.prepare_registry).source
170
+ ----
171
+
172
+ Working with the extension directly is intended for low-level operations.
173
+ Most of the time, you should use the API provided by this library.
123
174
 
124
175
  == How it Works
125
176
 
126
177
  {project-name} uses a collection of Asciidoctor extensions to rebuild the AsciiDoc source as a single document.
178
+ Top-level include files in the input AsciiDoc document are resolved relative to current working directory.
127
179
 
128
180
  It starts by using a preprocessor extension to enhance the PreprocessorReader class to be notified each time an include is entered (pushed) or exited (popped).
129
181
  When an include directive is encountered, the enhanced reader stores the resolved lines and location of the include directive, thus keeping track of where those lines should be inserted in the original source.
@@ -189,7 +241,7 @@ For more fine-grained control, you can also run the tests directly using RSpec:
189
241
 
190
242
  To run all tests in a single spec, point RSpec at the spec file:
191
243
 
192
- $ bundle exec rspec spec/asciidoctor_reducer_spec.rb
244
+ $ bundle exec rspec spec/reducer_spec.rb
193
245
 
194
246
  ==== Run specific tests
195
247
 
@@ -234,7 +286,7 @@ When running the `asciidoctor-reducer` command from source, you must prefix the
234
286
  [subs=attributes+]
235
287
  $ bundle exec asciidoctor-reducer sample.adoc
236
288
 
237
- To avoid having to do this, or make the `asciidoctor-reducer` command available from anywhere, you need to build the development gem and install it.
289
+ To avoid having to do this, or to make the `asciidoctor-reducer` command available from anywhere, you need to build the development gem and install it.
238
290
 
239
291
  == Copyright and License
240
292
 
@@ -35,5 +35,5 @@ Gem::Specification.new do |s|
35
35
  s.add_runtime_dependency 'asciidoctor', '~> 2.0'
36
36
 
37
37
  s.add_development_dependency 'rake', '~> 13.0.0'
38
- s.add_development_dependency 'rspec', '~> 3.10.0'
38
+ s.add_development_dependency 'rspec', '~> 3.11.0'
39
39
  end
@@ -1,13 +1,11 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- asciidoctor_reducer = File.absolute_path '../lib/asciidoctor/reducer', __dir__
5
- if File.exist? asciidoctor_reducer
6
- require asciidoctor_reducer
4
+ asciidoctor_reducer_cli = File.absolute_path '../lib/asciidoctor/reducer/cli', __dir__
5
+ if File.exist? asciidoctor_reducer_cli
6
+ require asciidoctor_reducer_cli
7
7
  else
8
- require 'asciidoctor/reducer'
8
+ require 'asciidoctor/reducer/cli'
9
9
  end
10
10
 
11
- require 'asciidoctor/reducer/cli'
12
-
13
11
  exit Asciidoctor::Reducer::Cli.run
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+ require_relative 'extensions'
5
+
6
+ module Asciidoctor::Reducer
7
+ autoload :VERSION, (::File.join __dir__, 'version.rb')
8
+
9
+ class << self
10
+ def reduce input, opts = {}
11
+ opts = opts.merge extension_registry: (Extensions.prepare_registry opts[:extension_registry] || opts[:extensions])
12
+ opts[:safe] = ::Asciidoctor::SafeMode::SAFE unless opts.key? :safe
13
+ case input
14
+ when ::File
15
+ doc = ::Asciidoctor.load_file input, opts
16
+ when ::Pathname
17
+ doc = ::Asciidoctor.load_file input.to_path, opts
18
+ else
19
+ doc = ::Asciidoctor.load input, opts
20
+ end
21
+ write doc, opts[:to]
22
+ end
23
+
24
+ def reduce_file input_file, opts = {}
25
+ reduce (::Pathname.new input_file), opts
26
+ end
27
+
28
+ private
29
+
30
+ def write doc, to
31
+ if to && to != '/dev/null'
32
+ output = doc.source
33
+ return output if to == ::String
34
+ output += LF unless output.empty?
35
+ if ::Pathname === to || (!(to.respond_to? :write) && (to = ::Pathname.new to.to_s))
36
+ to.dirname.mkpath
37
+ to.write output, encoding: UTF_8
38
+ else
39
+ to.write output
40
+ end
41
+ end
42
+ doc
43
+ end
44
+ end
45
+
46
+ LF = ?\n
47
+ UTF_8 = ::Encoding::UTF_8
48
+
49
+ private_constant :LF, :UTF_8
50
+ end
@@ -1,14 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'api'
3
4
  autoload :OptionParser, 'optparse'
4
- autoload :Pathname, 'pathname'
5
5
 
6
6
  module Asciidoctor::Reducer
7
- autoload :VERSION, (::File.join __dir__, 'version.rb')
8
-
9
7
  class Cli
8
+ LOG_LEVELS = (::Logger::Severity.constants false).each_with_object({}) do |level, accum|
9
+ accum[level.to_s.downcase] = (::Logger::Severity.const_get level) unless level == :UNKNOWN
10
+ end
11
+
10
12
  def parse args
11
- options = { attributes: {}, safe: :unsafe }
13
+ options = { attributes: {}, log_level: LOG_LEVELS['warn'], safe: :unsafe }
12
14
 
13
15
  opt_parser = ::OptionParser.new do |opts|
14
16
  opts.program_name = 'asciidoctor-reducer'
@@ -19,10 +21,6 @@ module Asciidoctor::Reducer
19
21
 
20
22
  EOS
21
23
 
22
- opts.on '-o FILE', '--output=FILE', 'set the output filename or stream' do |file|
23
- options[:output_file] = file
24
- end
25
-
26
24
  opts.on '-a KEY[=VALUE]', '--attribute=KEY[=VALUE]',
27
25
  'set a document attribute in the AsciiDoc document: [key, key!, key=value]' do |attr|
28
26
  key, val = attr.split '=', 2
@@ -30,28 +28,41 @@ module Asciidoctor::Reducer
30
28
  options[:attributes][key] = val
31
29
  end
32
30
 
31
+ opts.on '--log-level LEVEL', %w(debug info warn error fatal),
32
+ 'set the minimum level of messages to log: [debug, info, warn, error, fatal] (default: warn)' do |level|
33
+ options[:log_level] = level
34
+ end
35
+
36
+ opts.on '-o FILE', '--output=FILE', 'set the output filename or stream' do |file|
37
+ options[:output_file] = file
38
+ end
39
+
33
40
  opts.on '--preserve-conditionals', 'preserve preprocessor conditional directives in the reduced source' do
34
41
  options[:preserve_conditionals] = true
35
42
  end
36
43
 
37
- opts.on '--log-level LEVEL', %w(debug info warn error fatal),
38
- 'set the minimum level of messages to log: [debug, info, warn, error, fatal] (default: warn)' do |level|
39
- (options[:logger] = ::Asciidoctor::Logger.new $stderr).level = level unless level == 'warn'
44
+ opts.on '-q', '--quiet', 'suppress all application log messages' do
45
+ options[:log_level] = nil
40
46
  end
41
47
 
42
- opts.on '-q', '--quiet', 'suppress all application log messages' do
43
- options[:logger] = ::Asciidoctor::NullLogger.new
48
+ opts.on '-rLIBRARY', '--require LIBRARY', 'require the specified library or libraries before running' do |path|
49
+ (options[:requires] ||= []).concat path.split ','
44
50
  end
45
51
 
46
- opts.on '-h', '--help', 'display this help text and exit' do
47
- $stdout.write opts.help
48
- return 0
52
+ opts.on '-S', '--safe-mode SAFE_MODE', ['unsafe', 'safe', 'server'],
53
+ 'set supported safe mode level: [unsafe, safe, server] (default: unsafe)' do |name|
54
+ options[:safe] = ::Asciidoctor::SafeMode.value_for_name name
49
55
  end
50
56
 
51
57
  opts.on '-v', '--version', 'display the version information and exit' do
52
58
  $stdout.write %(#{opts.program_name} #{VERSION}\n)
53
59
  return 0
54
60
  end
61
+
62
+ opts.on '-h', '--help', 'display this help text and exit' do
63
+ $stdout.write opts.help
64
+ return 0
65
+ end
55
66
  end
56
67
 
57
68
  args = opt_parser.parse args
@@ -61,13 +72,21 @@ module Asciidoctor::Reducer
61
72
  $stdout.write opt_parser.help
62
73
  1
63
74
  elsif args.size == 1
75
+ if (requires = options.delete :requires)
76
+ requires.uniq.each do |path|
77
+ require path
78
+ rescue ::LoadError
79
+ $stderr.write %(#{opt_parser.program_name}: '#{path}' could not be required (reason: #{$!.message})\n)
80
+ return 1
81
+ end
82
+ end
64
83
  options[:input_file] = args[0]
65
84
  options[:output_file] = '-' unless options[:output_file]
66
85
  [0, options]
67
86
  else
68
87
  opt_parser.warn %(extra arguments detected (unparsed arguments: #{(args.drop 1).join ' '}))
69
88
  $stdout.write opt_parser.help
70
- [1, options]
89
+ 1
71
90
  end
72
91
  rescue ::OptionParser::InvalidOption
73
92
  $stderr.write %(#{opt_parser.program_name}: #{$!.message}\n)
@@ -76,26 +95,23 @@ module Asciidoctor::Reducer
76
95
  end
77
96
 
78
97
  def self.run args = ARGV
79
- old_logger = ::Asciidoctor::LoggerManager.logger
80
98
  code, options = new.parse (Array args)
81
99
  return code unless code == 0 && options
82
- if (output_file = options.delete :output_file) == '-'
83
- to = $stdout
84
- else
85
- (to = ::Pathname.new output_file).dirname.mkpath
86
- end
87
- if (input_file = options.delete :input_file) == '-'
88
- reduced = (::Asciidoctor.load $stdin, options).source + ?\n
100
+ old_logger = ::Asciidoctor::LoggerManager.logger
101
+ if (log_level = options.delete :log_level)
102
+ (options[:logger] = ::Asciidoctor::Logger.new $stderr).level = log_level
89
103
  else
90
- reduced = (::Asciidoctor.load_file input_file, (options.merge to_file: false)).source + ?\n
104
+ options[:logger] = nil
91
105
  end
92
- ::Pathname === to ? (to.write reduced, encoding: ::Encoding::UTF_8) : (to.write reduced)
106
+ options[:to] = (output_file = options.delete :output_file) == '-' ? $stdout : (::Pathname.new output_file)
107
+ input = (input_file = options.delete :input_file) == '-' ? $stdin : (::Pathname.new input_file)
108
+ ::Asciidoctor::Reducer.reduce input, options
93
109
  0
94
110
  rescue
95
111
  $stderr.write %(asciidoctor-reducer: #{$!.message}\n)
96
112
  1
97
113
  ensure
98
- ::Asciidoctor::LoggerManager.logger = old_logger
114
+ ::Asciidoctor::LoggerManager.logger = old_logger if old_logger
99
115
  end
100
116
  end
101
117
  end
@@ -1,4 +1,39 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'asciidoctor' unless defined? Asciidoctor.load
3
4
  require_relative 'preprocessor'
4
5
  require_relative 'tree_processor'
6
+
7
+ module Asciidoctor::Reducer
8
+ module Extensions
9
+ module_function
10
+
11
+ def group
12
+ proc do
13
+ next if document.options[:reduced]
14
+ preprocessor Preprocessor
15
+ tree_processor TreeProcessor
16
+ end
17
+ end
18
+
19
+ def prepare_registry registry = nil
20
+ registry = ::Asciidoctor::Extensions.create(&registry) if ::Proc === registry
21
+ unless ::Asciidoctor::Extensions.groups[:reducer]
22
+ if registry
23
+ registry.groups[:reducer] = group
24
+ else
25
+ registry = ::Asciidoctor::Extensions.create :reducer, &group
26
+ end
27
+ end
28
+ registry
29
+ end
30
+
31
+ def register
32
+ ::Asciidoctor::Extensions.register :reducer, &group
33
+ end
34
+
35
+ def unregister
36
+ ::Asciidoctor::Extensions.unregister :reducer
37
+ end
38
+ end
39
+ end
@@ -4,8 +4,8 @@ require_relative 'preprocessor_directive_tracker'
4
4
 
5
5
  module Asciidoctor::Reducer
6
6
  class Preprocessor < ::Asciidoctor::Extensions::Preprocessor
7
- def process doc, reader
8
- doc.options[:reduced] ? reader : (reader.extend PreprocessorDirectiveTracker)
7
+ def process _, reader
8
+ reader.extend PreprocessorDirectiveTracker
9
9
  end
10
10
  end
11
11
  end
@@ -6,12 +6,13 @@ module Asciidoctor::Reducer
6
6
  attr_reader :x_include_replacements
7
7
 
8
8
  def self.extended instance
9
- instance.instance_variable_set :@x_include_replacements, ([{ drop: [] }].extend CurrentPointer)
10
- instance.instance_variable_set :@x_parents, [0]
9
+ instance.instance_variable_set :@x_include_replacements, ([{ drop: [] }].extend CurrentPosition)
10
+ instance.instance_variable_set :@x_include_directive_line, nil
11
+ instance.instance_variable_set :@x_include_pushed, nil
11
12
  end
12
13
 
13
14
  def preprocess_conditional_directive keyword, target, delimiter, text
14
- return super if (opts = @document.options)[:preserve_conditionals] || opts[:reduced]
15
+ return super if @document.options[:preserve_conditionals]
15
16
  skip_active = @skipping
16
17
  depth = @conditional_stack.length
17
18
  cond_lineno = @lineno - 1
@@ -34,70 +35,57 @@ module Asciidoctor::Reducer
34
35
 
35
36
  def preprocess_include_directive target, attrlist
36
37
  @x_include_directive_line = %(include::#{target}[#{attrlist}])
37
- @x_push_include_called = false
38
+ @x_include_pushed = false
38
39
  inc_lineno = @lineno - 1 # we're currently on the include line, which is 1-based
39
40
  result = super
40
- return result if @x_push_include_called
41
- parent_depth = (parents = @x_parents).length
42
- if (depth_change = @include_stack.length - (parent_depth - 1)) < 0
43
- parent_depth -= (parents.slice! parent_depth + depth_change, -depth_change).length
41
+ unless @x_include_pushed
42
+ unresolved = (l = peek_line true) && (l.start_with? 'Unresolved directive in ') && (l.end_with? ']') || nil
43
+ push_include_replacement inc_lineno, (unresolved ? [l] : []), unresolved
44
44
  end
45
- inc_lines = ((line = lines[0].to_s).start_with? 'Unresolved directive in ') && (line.end_with? ']') ? [line] : []
46
- push_include_replacement inc_lines, parent_depth, inc_lineno
45
+ @x_include_directive_line = @x_include_pushed = nil
47
46
  result
48
47
  end
49
48
 
50
49
  def push_include data, file, path, lineno, attrs
51
- @x_push_include_called = true
50
+ @x_include_pushed = true
52
51
  inc_lineno = @lineno - 2 # we're below the include line, which is 1-based
53
52
  prev_inc_depth = @include_stack.length
54
- # Q: can we do this without resetting the lineno?
55
- lineno = 1 # rubocop:disable Lint/ShadowedArgument
56
- super
57
- parent_depth = (parents = @x_parents).length
58
- # push_include did not push to the stack
59
- if (inc_depth = @include_stack.length) == prev_inc_depth
60
- if (depth_change = inc_depth - (parent_depth - 1)) < 0
61
- parent_depth -= (parents.slice! parent_depth + depth_change, -depth_change).length
62
- end
63
- else
64
- if (depth_change = inc_depth - parent_depth) > 0
65
- parents << @x_include_replacements.length.pred
66
- parent_depth += 1
67
- elsif depth_change < 0
68
- parent_depth -= (parents.slice! parent_depth + depth_change, -depth_change).length
69
- end
70
- inc_lines = lines
71
- end
72
- push_include_replacement inc_lines, parent_depth, inc_lineno
73
- self
53
+ result = super
54
+ push_include_replacement inc_lineno, (@include_stack.length > prev_inc_depth ? lines : [])
55
+ result
74
56
  end
75
57
 
76
58
  def pop_include
77
- @x_include_replacements.current = @x_include_replacements[@x_include_replacements.current[:into] || 0]
59
+ @x_include_replacements.pos = @x_include_replacements.current[:into] unless @x_include_pushed
78
60
  super
79
61
  end
80
62
 
81
63
  private
82
64
 
83
- def push_include_replacement inc_lines, parent_depth, inc_lineno
65
+ def push_include_replacement inc_lineno, inc_lines, unresolved = false
84
66
  @x_include_replacements << {
85
- lines: inc_lines || [],
67
+ into: @x_include_replacements.pos,
68
+ lineno: inc_lineno,
69
+ line: @x_include_directive_line,
70
+ lines: inc_lines,
86
71
  drop: [],
87
- into: @x_parents[parent_depth - 1],
88
- index: inc_lineno,
89
- replace: @x_include_directive_line,
90
72
  }
91
- @x_include_replacements.current = @x_include_replacements[-1] if inc_lines
73
+ @x_include_replacements.pos = @x_include_replacements.length - 1 unless unresolved || inc_lines.empty?
92
74
  nil
93
75
  end
94
76
  end
95
77
 
96
- module CurrentPointer
97
- attr_accessor :current
78
+ module CurrentPosition
79
+ attr_accessor :pos
98
80
 
99
81
  def self.extended instance
100
- instance.current = instance[-1]
82
+ instance.pos = instance.length - 1
83
+ end
84
+
85
+ def current
86
+ self[@pos]
101
87
  end
102
88
  end
89
+
90
+ private_constant :CurrentPosition
103
91
  end
@@ -3,15 +3,13 @@
3
3
  module Asciidoctor::Reducer
4
4
  class TreeProcessor < ::Asciidoctor::Extensions::TreeProcessor
5
5
  def process doc
6
- return if doc.options[:reduced]
7
- inc_replacements = doc.reader.x_include_replacements
8
- unless inc_replacements.length == 1 && inc_replacements[0][:drop].empty?
6
+ unless (inc_replacements = doc.reader.x_include_replacements).length == 1 && inc_replacements[0][:drop].empty?
9
7
  inc_replacements[0][:lines] = doc.source_lines.dup
10
8
  inc_replacements.reverse_each do |it|
11
9
  if (into = it[:into])
12
10
  target_lines = inc_replacements[into][:lines]
13
11
  # adds extra bit of assurance that we're replacing the correct line
14
- next unless target_lines[(index = it[:index])] == it[:replace]
12
+ next unless target_lines[(index = it[:lineno])] == it[:line]
15
13
  end
16
14
  lines = it[:lines]
17
15
  unless (drop = it[:drop]).empty?
@@ -21,9 +19,18 @@ module Asciidoctor::Reducer
21
19
  end
22
20
  source_lines = inc_replacements[0][:lines].flatten
23
21
  if doc.sourcemap
24
- # WARNING: if include directives remain that can still be resolved, the sourcemap won't match the source lines
25
- doc = ::Asciidoctor.load source_lines, (doc.options.merge reduced: true)
22
+ logger = ::Asciidoctor::LoggerManager.logger
23
+ opts = doc.options.merge logger: nil, parse: false, reduced: true
24
+ if (ext_reg = opts[:extension_registry])
25
+ opts[:extension_registry] = ::Asciidoctor::Extensions::Registry.new ext_reg.groups
26
+ end
27
+ includes = doc.catalog[:includes]
28
+ doc = ::Asciidoctor.load source_lines, opts
29
+ doc.catalog[:includes] = includes
30
+ doc.parse
31
+ ::Asciidoctor::LoggerManager.logger = logger
26
32
  else
33
+ source_lines.pop while (last = source_lines[-1]) && last.empty?
27
34
  doc.reader.source_lines = source_lines
28
35
  end
29
36
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Reducer
5
- VERSION = '1.0.0.alpha.3'
5
+ VERSION = '1.0.0.alpha.7'
6
6
  end
7
7
  end
@@ -1,9 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'asciidoctor'
4
3
  require_relative 'reducer/extensions'
5
4
 
6
- Asciidoctor::Extensions.register do
7
- preprocessor Asciidoctor::Reducer::Preprocessor
8
- tree_processor Asciidoctor::Reducer::TreeProcessor
9
- end
5
+ Asciidoctor::Reducer::Extensions.register
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asciidoctor-reducer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.3
4
+ version: 1.0.0.alpha.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Allen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-02 00:00:00.000000000 Z
11
+ date: 2022-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 3.10.0
47
+ version: 3.11.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 3.10.0
54
+ version: 3.11.0
55
55
  description: A tool that reduces a composite AsciiDoc document containing preprocessor
56
56
  directives (includes and conditionals) to a single AsciiDoc document by expanding
57
57
  the includes and applying the conditionals.
@@ -68,6 +68,7 @@ files:
68
68
  - bin/asciidoctor-reducer
69
69
  - lib/asciidoctor-reducer.rb
70
70
  - lib/asciidoctor/reducer.rb
71
+ - lib/asciidoctor/reducer/api.rb
71
72
  - lib/asciidoctor/reducer/cli.rb
72
73
  - lib/asciidoctor/reducer/extensions.rb
73
74
  - lib/asciidoctor/reducer/preprocessor.rb