asciidoctor-reducer 1.0.0.alpha.8 → 1.0.0.alpha.9

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: 7df897a17f1fc52a4240d6c4bfe476e9072014dae43042063485634bda01eb13
4
- data.tar.gz: 5be6330e865889c0a93cf83eb6a884e5785d644d8421d962b5f33950a0da67bc
3
+ metadata.gz: 80723a5097c54761a2bee3b3ea88f827c88614b7a5572a6b5f1b10cb7af60c8c
4
+ data.tar.gz: d6f23a15e6dae8db02f5810d22018f537af9d6e67ac8362dbc2fe3155417df2d
5
5
  SHA512:
6
- metadata.gz: f4a788b3926a6f9bf925ec5607cc1756688de3ade791ea2178b3e893b9ad35bf0f2912cb0e23b5fc16a8834d2f28be4cc6c0bf6173a10858942522107991091b
7
- data.tar.gz: 04afd98f0789e686f0328eb721c56f2c2150261209a66c90025d2dd91c10d9397a969b6a45c0060d77559df549a80cf3839f2940030e47105ca11bcd9ba02e5c
6
+ metadata.gz: db4173fd2899008fec759e9d76f2732a7f5f7ca0a284f5c66a93040b9fca81dba22cf151e77e86b2b73c535545cec4b3a54c88407324514811260832b8ed1c7d
7
+ data.tar.gz: ec7a7d27cb1b87dcb0772af642f185002f7348e0a540c40bf3a6e98334d7be0b088b8b00312ca10dd5470cdaff60007e70c2d27708d97c4677c7a3302694473e
data/CHANGELOG.adoc CHANGED
@@ -4,6 +4,32 @@
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.9 (2022-04-21) - @mojavelinux
8
+
9
+ === Added
10
+
11
+ * Add `Asciidoctor::Reducer::IncludeMapper` auxiliary extension, required by `asciidoctor/reducer/include_mapper/extension` (#26)
12
+ * Register `Asciidoctor::Reducer::IncludeMapper` extension when `asciidoctor/reducer/include_mapper` is required (#26)
13
+ * Add `Asciidoctor::Reducer::Extensions.key` method that returns key for registering extension group
14
+ * Update help text to note that the `-a` and `-r` CLI options may be specified multiple times
15
+ * Automate the release process
16
+
17
+ === Changed
18
+
19
+ * Rename x_include_replacements attr on reader to include_replacements since it's public
20
+ * Don't pass `:to` option to `Asciidoctor.load_file`
21
+ * Make `Asciidoctor::Reducer::Cli` a module instead of a class
22
+
23
+ === Fixed
24
+
25
+ * Replace remote include with link if `allow-uri-read` attribute is not set
26
+ * Don't raise error if `Asciidoctor::Reducer::Extensions.unregister` is called when extensions are not registered globally
27
+ * Ensure output is written to file with universal newlines (\n) on Windows
28
+
29
+ === Details
30
+
31
+ {url-repo}/releases/tag/v1.0.0.alpha.9[git tag] | {url-repo}/compare/v1.0.0.alpha.8\...v1.0.0.alpha.9[full diff]
32
+
7
33
  == 1.0.0.alpha.8 (2022-02-23) - @mojavelinux
8
34
 
9
35
  === Added
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.8, 2022-02-23
3
+ v1.0.0.alpha.9, 2022-04-21
4
4
  :idprefix:
5
5
  :idseparator: -
6
6
  ifndef::env-github[:icons: font]
@@ -16,8 +16,8 @@ endif::[]
16
16
  :url-rvm: https://rvm.io
17
17
  :url-repo: https://github.com/asciidoctor/{project-handle}
18
18
 
19
- {project-name} is a tool that reduces a composite AsciiDoc document containing includes to a single AsciiDoc document by expanding any includes reachable from the parent document.
20
- The tool also applies preprocessor conditionals (unless the option to preserve them is specified), leaving behind only the enabled lines.
19
+ {project-name} is a tool that reduces an AsciiDoc document that contains includes to a single AsciiDoc document by expanding any includes reachable from the parent document.
20
+ The tool also applies preprocessor conditionals (unless the option to preserve them is specified), leaving behind only the selected lines.
21
21
  If the document does not contain any preprocessor directives, the tool returns the original source.
22
22
 
23
23
  == Prerequisites
@@ -197,6 +197,69 @@ This call will cause extensions that run during the load phase to be invoked aga
197
197
  An extension can check for this secondary load by checking for the `:reduced` option in the `Document#options` hash.
198
198
  If this option is set (the value of which will be `true`), then Asciidoctor is loading the reduced document.
199
199
 
200
+ == Include Mapper (Experimental)
201
+
202
+ One of the challenges of reducing a document is that interdocument xrefs that rely on the includes being registered in the document catalog no longer work.
203
+ That's because when the reduced document is converted, it has no includes and thus all interdocument xrefs are colocated in the same source file.
204
+ To work around this shortcoming, {project-name} provides a utility extension named the include mapper that will carry over the includes in the document catalog to the reduced document so they can be imported during conversion.
205
+
206
+ CAUTION: The include mapper is experimental and thus subject to change.
207
+
208
+ To use the include mapper when using the CLI to reduce the document, require it using the `-r` option as follows:
209
+
210
+ $ asciidoctor-reducer -r asciidoctor/reducer/include_mapper -o input-reduced.adoc input.adoc
211
+
212
+ To use the include mapper when converting the reduced document, again require it using the `-r` option as follows:
213
+
214
+ $ asciidoctor -r asciidoctor/reducer/include_mapper input-reduced.adoc
215
+
216
+ To use the include mapper when using the API, first require the extension:
217
+
218
+ [,ruby]
219
+ ----
220
+ require 'asciidocotor/reducer/include_mapper/extension'
221
+ ----
222
+
223
+ You then need to register the extension when reducing the document:
224
+
225
+ [,ruby]
226
+ ----
227
+ Asciidoctor::Reducer.reduce_file 'sample.adoc', to: 'sample-reduced.adoc', extensions: proc {
228
+ next if document.options[:reduced]
229
+ tree_processor Asciidoctor::Reducer::IncludeMapper
230
+ }
231
+ ----
232
+
233
+ Then register it again when converting the reduced document:
234
+
235
+ [,ruby]
236
+ ----
237
+ Asciidoctor.convert_file 'sample-reduced.adoc', safe: :safe, extensions: proc {
238
+ tree_processor Asciidoctor::Reducer::IncludeMapper
239
+ }
240
+ ----
241
+
242
+ You can also register the extension globally:
243
+
244
+ [,ruby]
245
+ ----
246
+ require 'asciidocotor/reducer/include_mapper'
247
+ ----
248
+
249
+ In this case, you don't have to pass it to the API explicitly.
250
+
251
+ === How it Works
252
+
253
+ The include mapper works by adding a magic comment to the bottom of the reduced file.
254
+ Here's an example of that comment:
255
+
256
+ [,asciidoc]
257
+ ----
258
+ //# includes=chapters/chapter-a,chapters/chapter-b
259
+ ----
260
+
261
+ When a document that contains the magic comment is converted, the include mapper reads the comma-separated paths in the value and loads them into the includes table of the document catalog.
262
+
200
263
  == Development
201
264
 
202
265
  Follow the instructions below to learn how to help develop the project or test-drive the development version.
@@ -1,11 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
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
- else
8
- require 'asciidoctor/reducer/cli'
9
- end
10
-
4
+ asciidoctor_reducer_cli = File.join (File.dirname __dir__), 'lib/asciidoctor/reducer/cli.rb'
5
+ require (File.file? asciidoctor_reducer_cli) ? asciidoctor_reducer_cli : 'asciidoctor/reducer/cli'
11
6
  exit Asciidoctor::Reducer::Cli.run
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'pathname'
3
+ autoload :Pathname, 'pathname'
4
4
  require_relative 'extensions'
5
5
 
6
6
  module Asciidoctor::Reducer
@@ -8,8 +8,12 @@ module Asciidoctor::Reducer
8
8
 
9
9
  class << self
10
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
11
+ opts = opts&.merge || {}
12
+ if (extension_registry = Extensions.prepare_registry opts[:extension_registry] || opts[:extensions])
13
+ opts[:extension_registry] = extension_registry
14
+ end
15
+ opts[:safe] ||= :safe
16
+ to = opts.delete :to
13
17
  case input
14
18
  when ::File
15
19
  doc = ::Asciidoctor.load_file input, opts
@@ -18,7 +22,7 @@ module Asciidoctor::Reducer
18
22
  else
19
23
  doc = ::Asciidoctor.load input, opts
20
24
  end
21
- write doc, opts[:to]
25
+ write doc, to
22
26
  end
23
27
 
24
28
  def reduce_file input_file, opts = {}
@@ -28,16 +32,15 @@ module Asciidoctor::Reducer
28
32
  private
29
33
 
30
34
  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
35
+ return doc unless to && to != '/dev/null'
36
+ output = doc.source
37
+ return output if to == ::String
38
+ output += LF unless output.empty?
39
+ if ::Pathname === to || (!(to.respond_to? :write) && (to = ::Pathname.new to.to_s))
40
+ to.dirname.mkpath
41
+ to.write output, encoding: UTF_8, newline: :universal
42
+ else
43
+ to.write output
41
44
  end
42
45
  doc
43
46
  end
@@ -4,134 +4,138 @@ require_relative 'api'
4
4
  autoload :OptionParser, 'optparse'
5
5
 
6
6
  module Asciidoctor::Reducer
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
-
12
- def parse args
13
- options = { attributes: {}, log_level: LOG_LEVELS['warn'], safe: :unsafe }
14
-
15
- opt_parser = ::OptionParser.new do |opts|
16
- opts.program_name = 'asciidoctor-reducer'
17
- opts.banner = <<~EOS
18
- Usage: #{opts.program_name} [OPTION]... FILE
19
-
20
- Reduces a composite AsciiDoc document containing includes and conditionals to a single AsciiDoc document.
7
+ module Cli
8
+ class << self
9
+ def parse args
10
+ options = { attributes: {}, log_level: LOG_LEVELS['warn'], safe: :unsafe }
11
+
12
+ opt_parser = ::OptionParser.new do |opts|
13
+ opts.program_name = 'asciidoctor-reducer'
14
+ opts.banner = <<~END
15
+ Usage: #{opts.program_name} [OPTION]... FILE
16
+
17
+ Reduces a composite AsciiDoc document containing includes and conditionals to a single AsciiDoc document.
18
+
19
+ END
20
+
21
+ opts.on '-a KEY[=VALUE]', '--attribute=KEY[=VALUE]',
22
+ 'set a document attribute in the AsciiDoc document: [key, key!, key=value]',
23
+ 'may be specified multiple times' do |attr|
24
+ key, val = attr.split '=', 2
25
+ val ||= ''
26
+ options[:attributes][key] = val
27
+ end
21
28
 
22
- EOS
29
+ opts.on '--log-level LEVEL', %w(debug info warn error fatal),
30
+ 'set the minimum level of messages to log: [debug, info, warn, error, fatal] (default: warn)' do |level|
31
+ options[:log_level] = level
32
+ end
23
33
 
24
- opts.on '-a KEY[=VALUE]', '--attribute=KEY[=VALUE]',
25
- 'set a document attribute in the AsciiDoc document: [key, key!, key=value]' do |attr|
26
- key, val = attr.split '=', 2
27
- val ||= ''
28
- options[:attributes][key] = val
29
- end
34
+ opts.on '-o FILE', '--output=FILE', 'set the output filename or stream' do |file|
35
+ options[:output_file] = file
36
+ end
30
37
 
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
38
+ opts.on '--preserve-conditionals', 'preserve preprocessor conditional directives in the reduced source' do
39
+ options[:preserve_conditionals] = true
40
+ end
35
41
 
36
- opts.on '-o FILE', '--output=FILE', 'set the output filename or stream' do |file|
37
- options[:output_file] = file
38
- end
42
+ opts.on '-q', '--quiet', 'suppress all application log messages' do
43
+ options[:log_level] = nil
44
+ end
39
45
 
40
- opts.on '--preserve-conditionals', 'preserve preprocessor conditional directives in the reduced source' do
41
- options[:preserve_conditionals] = true
42
- end
46
+ opts.on '-rLIBRARY', '--require LIBRARY', 'require the specified library or libraries before reducing',
47
+ 'may be specified multiple times' do |path|
48
+ (options[:requires] ||= []).concat path.split ','
49
+ end
43
50
 
44
- opts.on '-q', '--quiet', 'suppress all application log messages' do
45
- options[:log_level] = nil
46
- end
51
+ opts.on '-S', '--safe-mode SAFE_MODE', ['unsafe', 'safe', 'server', 'secure'],
52
+ 'set safe mode level: [unsafe, safe, server, secure] (default: unsafe)' do |name|
53
+ options[:safe] = name.to_sym
54
+ end
47
55
 
48
- opts.on '-rLIBRARY', '--require LIBRARY', 'require the specified library or libraries before running' do |path|
49
- (options[:requires] ||= []).concat path.split ','
50
- end
56
+ opts.on '--trace', 'trace the cause of application errors (default: false)' do
57
+ options[:trace] = true
58
+ end
51
59
 
52
- opts.on '-S', '--safe-mode SAFE_MODE', ['unsafe', 'safe', 'server', 'secure'],
53
- 'set safe mode level: [unsafe, safe, server, secure] (default: unsafe)' do |name|
54
- options[:safe] = ::Asciidoctor::SafeMode.value_for_name name
55
- end
60
+ opts.on '-v', '--version', 'display the version information and exit' do
61
+ print_version opts
62
+ return 0
63
+ end
56
64
 
57
- opts.on '--trace', 'trace the cause of application errors (default: false)' do
58
- options[:trace] = true
65
+ opts.on '-h', '--help', 'display this help text and exit' do
66
+ print_help opts
67
+ return 0
68
+ end
59
69
  end
60
70
 
61
- opts.on '-v', '--version', 'display the version information and exit' do
62
- print_version opts
63
- return 0
71
+ if (args = opt_parser.parse args).empty?
72
+ opt_parser.warn 'Please specify an AsciiDoc file to reduce.'
73
+ print_help opt_parser
74
+ 1
75
+ elsif args.size == 1
76
+ if (requires = options.delete :requires)
77
+ requires.uniq.each do |path|
78
+ require path
79
+ rescue ::LoadError
80
+ $stderr.puts %(#{opt_parser.program_name}: '#{path}' could not be required (reason: #{$!.message}))
81
+ return 1
82
+ end
83
+ end
84
+ options[:input_file] = args[0]
85
+ options[:output_file] = '-' unless options[:output_file]
86
+ [0, options]
87
+ else
88
+ opt_parser.warn %(extra arguments detected (unparsed arguments: #{(args.drop 1).join ' '}))
89
+ print_help opt_parser
90
+ 1
64
91
  end
92
+ rescue ::OptionParser::InvalidOption
93
+ $stderr.puts %(#{opt_parser.program_name}: #{$!.message})
94
+ print_help opt_parser
95
+ 1
96
+ end
65
97
 
66
- opts.on '-h', '--help', 'display this help text and exit' do
67
- print_help opts
68
- return 0
98
+ def run args = ARGV
99
+ code, options = parse (Array args)
100
+ return code unless code == 0 && options
101
+ trace = options.delete :trace
102
+ old_logger = ::Asciidoctor::LoggerManager.logger
103
+ if (log_level = options.delete :log_level)
104
+ (options[:logger] = ::Asciidoctor::Logger.new $stderr).level = log_level
105
+ else
106
+ options[:logger] = nil
69
107
  end
108
+ options[:to] = (output_file = options.delete :output_file) == '-' ? $stdout : (::Pathname.new output_file)
109
+ input = (input_file = options.delete :input_file) == '-' ? $stdin : (::Pathname.new input_file)
110
+ ::Asciidoctor::Reducer.reduce input, options
111
+ 0
112
+ rescue ::SignalException
113
+ $stderr.puts if ::Interrupt === $!
114
+ $!.signo
115
+ rescue
116
+ raise $! if trace
117
+ $stderr.puts %(asciidoctor-reducer: #{$!.message.delete_prefix 'asciidoctor: '})
118
+ $stderr.puts ' Use --trace to show backtrace'
119
+ 1
120
+ ensure
121
+ ::Asciidoctor::LoggerManager.logger = old_logger if old_logger
70
122
  end
71
123
 
72
- args = opt_parser.parse args
124
+ private
73
125
 
74
- if args.empty?
75
- opt_parser.warn 'Please specify an AsciiDoc file to reduce.'
76
- print_help opt_parser
77
- 1
78
- elsif args.size == 1
79
- if (requires = options.delete :requires)
80
- requires.uniq.each do |path|
81
- require path
82
- rescue ::LoadError
83
- $stderr.puts %(#{opt_parser.program_name}: '#{path}' could not be required (reason: #{$!.message}))
84
- return 1
85
- end
86
- end
87
- options[:input_file] = args[0]
88
- options[:output_file] = '-' unless options[:output_file]
89
- [0, options]
90
- else
91
- opt_parser.warn %(extra arguments detected (unparsed arguments: #{(args.drop 1).join ' '}))
92
- print_help opt_parser
93
- 1
126
+ def print_help opt_parser
127
+ $stdout.puts opt_parser.help.chomp
94
128
  end
95
- rescue ::OptionParser::InvalidOption
96
- $stderr.puts %(#{opt_parser.program_name}: #{$!.message})
97
- print_help opt_parser
98
- 1
99
- end
100
129
 
101
- def self.run args = ARGV
102
- code, options = new.parse (Array args)
103
- return code unless code == 0 && options
104
- trace = options.delete :trace
105
- old_logger = ::Asciidoctor::LoggerManager.logger
106
- if (log_level = options.delete :log_level)
107
- (options[:logger] = ::Asciidoctor::Logger.new $stderr).level = log_level
108
- else
109
- options[:logger] = nil
130
+ def print_version opt_parser
131
+ $stdout.puts %(#{opt_parser.program_name} #{VERSION})
110
132
  end
111
- options[:to] = (output_file = options.delete :output_file) == '-' ? $stdout : (::Pathname.new output_file)
112
- input = (input_file = options.delete :input_file) == '-' ? $stdin : (::Pathname.new input_file)
113
- ::Asciidoctor::Reducer.reduce input, options
114
- 0
115
- rescue ::SignalException
116
- $stderr.puts if ::Interrupt === $!
117
- $!.signo
118
- rescue
119
- raise $! if trace
120
- $stderr.puts %(asciidoctor-reducer: #{$!.message.delete_prefix 'asciidoctor: '})
121
- $stderr.puts ' Use --trace to show backtrace'
122
- 1
123
- ensure
124
- ::Asciidoctor::LoggerManager.logger = old_logger if old_logger
125
133
  end
126
134
 
127
- private
128
-
129
- def print_help opt_parser
130
- $stdout.puts opt_parser.help.chomp
135
+ LOG_LEVELS = (::Logger::Severity.constants false).each_with_object({}) do |level, accum|
136
+ accum[level.to_s.downcase] = (::Logger::Severity.const_get level) unless level == :UNKNOWN
131
137
  end
132
138
 
133
- def print_version opt_parser
134
- $stdout.puts %(#{opt_parser.program_name} #{VERSION})
135
- end
139
+ private_constant :LOG_LEVELS
136
140
  end
137
141
  end
@@ -8,7 +8,7 @@ module Asciidoctor::Reducer
8
8
  cond_lineno = @lineno
9
9
  result = super
10
10
  return result if @skipping && skip_active
11
- drop = @x_include_replacements.current[:drop] ||= []
11
+ drop = @include_replacements.current[:drop] ||= []
12
12
  if (depth_change = @conditional_stack.size - depth) < 0
13
13
  if skip_active
14
14
  drop.push(*(drop.pop..cond_lineno))
@@ -16,24 +16,27 @@ module Asciidoctor::Reducer
16
16
  end
17
17
  end
18
18
 
19
+ def key
20
+ :reducer
21
+ end
22
+
19
23
  def prepare_registry registry = nil
20
24
  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
25
+ return registry if ::Asciidoctor::Extensions.groups[key]
26
+ if registry
27
+ registry.groups[key] = group
28
+ registry
29
+ else
30
+ ::Asciidoctor::Extensions.create key, &group
27
31
  end
28
- registry
29
32
  end
30
33
 
31
34
  def register
32
- ::Asciidoctor::Extensions.register :reducer, &group
35
+ ::Asciidoctor::Extensions.register key, &group
33
36
  end
34
37
 
35
38
  def unregister
36
- ::Asciidoctor::Extensions.unregister :reducer
39
+ ::Asciidoctor::Extensions.groups.delete key # NOTE `Extensions.unregister key` fails if groups is not initialized
37
40
  end
38
41
  end
39
42
  end
@@ -2,34 +2,32 @@
2
2
 
3
3
  module Asciidoctor::Reducer
4
4
  module IncludeDirectiveTracker
5
+ attr_reader :include_replacements
5
6
  attr_writer :source_lines
6
- attr_reader :x_include_replacements
7
7
 
8
8
  def self.extended instance
9
- instance.instance_variable_set :@x_include_replacements, ([{}].extend CurrentPosition)
10
- instance.instance_variable_set :@x_include_directive_line, nil
11
- instance.instance_variable_set :@x_include_pushed, nil
9
+ instance.instance_variable_set :@include_replacements, ([{}].extend CurrentPosition)
10
+ instance.instance_variable_set :@x_reducer, {}
12
11
  end
13
12
 
14
13
  def preprocess_include_directive target, attrlist
15
- @x_include_directive_line = %(include::#{target}[#{attrlist}])
16
- @x_include_pushed = false
14
+ @x_reducer[:include_directive_line] = %(include::#{target}[#{attrlist}])
15
+ @x_reducer[:include_pushed] = false
17
16
  inc_lineno = @lineno # we're currently on the include line, which is 1-based
18
17
  result = super
19
- unless @x_include_pushed
20
- if (ln = peek_line true) && (ln.end_with? ']') && !(unresolved = ln.start_with? 'Unresolved directive in ')
21
- if @document.safe >= ::Asciidoctor::SafeMode::SECURE && inc_lineno == @lineno && (ln.start_with? 'link:')
22
- unresolved = !(ln = %(#{ln.slice 0, (ln.length - 1)}role=include])).nil?
23
- end
18
+ unless @x_reducer[:include_pushed]
19
+ if ((ln = peek_line true)&.end_with? ']') && !(unresolved = ln.start_with? 'Unresolved directive in ') &&
20
+ inc_lineno == @lineno && (unresolved = ln.start_with? 'link:')
21
+ ln = %(#{ln.slice 0, (ln.length - 1)}role=include])
24
22
  end
25
23
  push_include_replacement inc_lineno, (unresolved ? [ln] : []), unresolved
26
24
  end
27
- @x_include_directive_line = @x_include_pushed = nil
25
+ @x_reducer.clear
28
26
  result
29
27
  end
30
28
 
31
29
  def push_include data, file, path, lineno, attrs
32
- @x_include_pushed = true
30
+ @x_reducer[:include_pushed] = true
33
31
  inc_lineno = @lineno - 1 # we're below the include line, which is 1-based
34
32
  prev_inc_depth = @include_stack.size
35
33
  result = super
@@ -38,33 +36,41 @@ module Asciidoctor::Reducer
38
36
  end
39
37
 
40
38
  def pop_include
41
- @x_include_replacements.pos = @x_include_replacements.current[:into] unless @x_include_pushed
39
+ @include_replacements.up unless @x_reducer[:include_pushed]
42
40
  super
43
41
  end
44
42
 
45
43
  private
46
44
 
47
45
  def push_include_replacement lineno, lines, unresolved = false
48
- (inc_replacements = @x_include_replacements) << {
49
- into: inc_replacements.pos,
46
+ (inc_replacements = @include_replacements) << {
47
+ into: inc_replacements.pointer,
50
48
  lineno: lineno,
51
- line: @x_include_directive_line,
49
+ line: @x_reducer[:include_directive_line],
52
50
  lines: lines,
53
51
  }
54
- inc_replacements.pos = inc_replacements.size - 1 unless unresolved || lines.empty?
52
+ inc_replacements.to_end unless unresolved || lines.empty?
55
53
  nil
56
54
  end
57
55
  end
58
56
 
59
57
  module CurrentPosition
60
- attr_accessor :pos
58
+ attr_reader :pointer
61
59
 
62
60
  def self.extended instance
63
- instance.pos = instance.size - 1
61
+ instance.to_end
64
62
  end
65
63
 
66
64
  def current
67
- self[@pos]
65
+ self[@pointer]
66
+ end
67
+
68
+ def to_end
69
+ @pointer = size - 1
70
+ end
71
+
72
+ def up
73
+ @pointer = current[:into]
68
74
  end
69
75
  end
70
76
 
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Asciidoctor::Reducer
4
+ class IncludeMapper < ::Asciidoctor::Extensions::TreeProcessor
5
+ def process doc
6
+ if doc.extensions.groups[:reducer]
7
+ unless (includes = doc.catalog[:includes].select {|_, v| v }.keys).empty?
8
+ doc.source_lines.concat ['', %(//# includes=#{includes.join ','})]
9
+ end
10
+ elsif (last_line = doc.source_lines[-1])&.start_with? '//# includes='
11
+ doc.catalog[:includes].update ((last_line.slice 13, last_line.length).split ',').map {|it| [it, true] }.to_h
12
+ end
13
+ doc
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'include_mapper/extension'
4
+
5
+ Asciidoctor::Extensions.register do
6
+ next if document.options[:reduced]
7
+ tree_processor Asciidoctor::Reducer::IncludeMapper
8
+ end
@@ -6,8 +6,8 @@ require_relative 'conditional_directive_tracker'
6
6
  module Asciidoctor::Reducer
7
7
  class Preprocessor < ::Asciidoctor::Extensions::Preprocessor
8
8
  def process doc, reader
9
- reader.extend IncludeDirectiveTracker
10
- reader.extend ConditionalDirectiveTracker unless doc.options[:preserve_conditionals]
9
+ doc.options[:preserve_conditionals] ?
10
+ (reader.extend IncludeDirectiveTracker) : (reader.extend ConditionalDirectiveTracker, IncludeDirectiveTracker)
11
11
  end
12
12
  end
13
13
  end
@@ -3,7 +3,7 @@
3
3
  module Asciidoctor::Reducer
4
4
  class TreeProcessor < ::Asciidoctor::Extensions::TreeProcessor
5
5
  def process doc
6
- if (inc_replacements = doc.reader.x_include_replacements).size > 1 || !(inc_replacements[0][:drop] || []).empty?
6
+ if (inc_replacements = doc.reader.include_replacements).size > 1 || !(inc_replacements[0][:drop] || []).empty?
7
7
  inc_replacements[0][:lines] = doc.source_lines.dup
8
8
  inc_replacements.reverse_each do |it|
9
9
  if (into = it[:into])
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Asciidoctor
4
4
  module Reducer
5
- VERSION = '1.0.0.alpha.8'
5
+ VERSION = '1.0.0.alpha.9'
6
6
  end
7
7
  end
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.8
4
+ version: 1.0.0.alpha.9
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-23 00:00:00.000000000 Z
11
+ date: 2022-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: asciidoctor
@@ -73,6 +73,8 @@ files:
73
73
  - lib/asciidoctor/reducer/conditional_directive_tracker.rb
74
74
  - lib/asciidoctor/reducer/extensions.rb
75
75
  - lib/asciidoctor/reducer/include_directive_tracker.rb
76
+ - lib/asciidoctor/reducer/include_mapper.rb
77
+ - lib/asciidoctor/reducer/include_mapper/extension.rb
76
78
  - lib/asciidoctor/reducer/preprocessor.rb
77
79
  - lib/asciidoctor/reducer/tree_processor.rb
78
80
  - lib/asciidoctor/reducer/version.rb
@@ -99,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
101
  - !ruby/object:Gem::Version
100
102
  version: 1.3.1
101
103
  requirements: []
102
- rubygems_version: 3.2.32
104
+ rubygems_version: 3.2.33
103
105
  signing_key:
104
106
  specification_version: 4
105
107
  summary: Reduces a composite AsciiDoc document containing includes and conditionals