asciidoctor-reducer 1.0.0.alpha.5 → 1.0.0.alpha.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +86 -18
- data/LICENSE +1 -1
- data/README.adoc +72 -20
- data/asciidoctor-reducer.gemspec +1 -1
- data/bin/asciidoctor-reducer +4 -6
- data/lib/asciidoctor/reducer/api.rb +50 -0
- data/lib/asciidoctor/reducer/cli.rb +70 -34
- data/lib/asciidoctor/reducer/conditional_directive_tracker.rb +26 -0
- data/lib/asciidoctor/reducer/extensions.rb +35 -0
- data/lib/asciidoctor/reducer/include_directive_tracker.rb +72 -0
- data/lib/asciidoctor/reducer/preprocessor.rb +4 -2
- data/lib/asciidoctor/reducer/tree_processor.rb +16 -8
- data/lib/asciidoctor/reducer/version.rb +1 -1
- data/lib/asciidoctor/reducer.rb +1 -5
- metadata +7 -5
- data/lib/asciidoctor/reducer/preprocessor_directive_tracker.rb +0 -92
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7df897a17f1fc52a4240d6c4bfe476e9072014dae43042063485634bda01eb13
|
4
|
+
data.tar.gz: 5be6330e865889c0a93cf83eb6a884e5785d644d8421d962b5f33950a0da67bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4a788b3926a6f9bf925ec5607cc1756688de3ade791ea2178b3e893b9ad35bf0f2912cb0e23b5fc16a8834d2f28be4cc6c0bf6173a10858942522107991091b
|
7
|
+
data.tar.gz: 04afd98f0789e686f0328eb721c56f2c2150261209a66c90025d2dd91c10d9397a969b6a45c0060d77559df549a80cf3839f2940030e47105ca11bcd9ba02e5c
|
data/CHANGELOG.adoc
CHANGED
@@ -4,6 +4,74 @@
|
|
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.8 (2022-02-23) - @mojavelinux
|
8
|
+
|
9
|
+
=== Added
|
10
|
+
|
11
|
+
* Add secure mode as value of `-S` CLI option (#31)
|
12
|
+
* Add `--trace` option to CLI to trace cause of application errors (#29)
|
13
|
+
|
14
|
+
=== Changed
|
15
|
+
|
16
|
+
* Replace include directive with link macro if safe mode is secure (#31)
|
17
|
+
* Track line numbers in include replacements using 1-based index
|
18
|
+
* Only mix in preprocessor conditional tracker if `:preserve_conditionals` option is not set (#36)
|
19
|
+
|
20
|
+
=== Fixed
|
21
|
+
|
22
|
+
* Handle signals gracefully (#33)
|
23
|
+
|
24
|
+
=== Details
|
25
|
+
|
26
|
+
{url-repo}/releases/tag/v1.0.0.alpha.8[git tag]
|
27
|
+
|
28
|
+
== 1.0.0.alpha.7 (2022-02-14) - @mojavelinux
|
29
|
+
|
30
|
+
=== Added
|
31
|
+
|
32
|
+
* Add asciidoctor/reducer/api to require main API (#3)
|
33
|
+
* Add `Asciidoctor::Reducer.reduce` and `Asciidoctor::Reducer.reduce_file` API methods (#3)
|
34
|
+
* Add asciidoctor/reducer/extensions to require extensions API (#3)
|
35
|
+
* Add `Asciidoctor::Reducer::Extensions` API (#3)
|
36
|
+
|
37
|
+
=== Changed
|
38
|
+
|
39
|
+
* Scope extensions to single call instead of registering them globally (#3)
|
40
|
+
* Use `:safe` as the default safe mode when using the API
|
41
|
+
* Make `CurrentPosition` module private to the `PreprocessorDirectiveTracker` module
|
42
|
+
|
43
|
+
=== Fixed
|
44
|
+
|
45
|
+
* Require asciidoctor/reducer/version automatically when `Asciidoctor::Reducer::VERSION` is accessed
|
46
|
+
|
47
|
+
=== Details
|
48
|
+
|
49
|
+
{url-repo}/releases/tag/v1.0.0.alpha.7[git tag]
|
50
|
+
|
51
|
+
== 1.0.0.alpha.6 (2022-02-10) - @mojavelinux
|
52
|
+
|
53
|
+
=== Added
|
54
|
+
|
55
|
+
* Add `-S`, `--safe-mode` option to CLI to set safe mode (#13)
|
56
|
+
* Add `-r`, `--require` option to CLI to specify additional libraries to require before running (#17)
|
57
|
+
|
58
|
+
=== Changed
|
59
|
+
|
60
|
+
* Sort CLI options in help text, except for the `-h`, `--help` option
|
61
|
+
* Update CLI to always use a new logger instance
|
62
|
+
* Defer initializing logger until run method is called
|
63
|
+
|
64
|
+
=== Fixed
|
65
|
+
|
66
|
+
* Replace include directives that follow an unresolved include (#19)
|
67
|
+
* Don't activate reducer extensions on reduced document
|
68
|
+
* Prevent custom extension registry from activating extensions twice during reload (#21)
|
69
|
+
* Retain includes table in document catalog when reloading document (#23)
|
70
|
+
|
71
|
+
=== Details
|
72
|
+
|
73
|
+
{url-repo}/releases/tag/v1.0.0.alpha.6[git tag]
|
74
|
+
|
7
75
|
== 1.0.0.alpha.5 (2022-02-06) - @mojavelinux
|
8
76
|
|
9
77
|
=== Changed
|
@@ -17,12 +85,20 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co
|
|
17
85
|
|
18
86
|
* Suppress log messages when reloading document (#14)
|
19
87
|
|
88
|
+
=== Details
|
89
|
+
|
90
|
+
{url-repo}/releases/tag/v1.0.0.alpha.5[git tag]
|
91
|
+
|
20
92
|
== 1.0.0.alpha.4 (2022-02-03) - @mojavelinux
|
21
93
|
|
22
94
|
=== Fixed
|
23
95
|
|
24
96
|
* Fix replacement of nested empty and unresolved includes
|
25
97
|
|
98
|
+
=== Details
|
99
|
+
|
100
|
+
{url-repo}/releases/tag/v1.0.0.alpha.4[git tag]
|
101
|
+
|
26
102
|
== 1.0.0.alpha.3 (2022-02-02) - @mojavelinux
|
27
103
|
|
28
104
|
=== Changed
|
@@ -32,45 +108,37 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co
|
|
32
108
|
* Only reload document if source lines have changed; otherwise, update source lines on reader directly
|
33
109
|
* Change default safe mode for CLI to :unsafe
|
34
110
|
|
111
|
+
=== Details
|
112
|
+
|
113
|
+
{url-repo}/releases/tag/v1.0.0.alpha.3[git tag]
|
114
|
+
|
35
115
|
== 1.0.0.alpha.2 (2022-01-27) - @mojavelinux
|
36
116
|
|
37
117
|
=== Added
|
38
118
|
|
39
|
-
* Add `-a
|
119
|
+
* Add `-a`, `--attribute` option to CLI for setting an AsciiDoc document attribute at runtime (#6)
|
40
120
|
|
41
121
|
=== Changed
|
42
122
|
|
43
|
-
* Reduce preprocessor conditionals by default; add option (`--preserve-conditionals
|
123
|
+
* Reduce preprocessor conditionals by default; add option (`--preserve-conditionals`, `:preserve_conditionals`) to preserve them (#8)
|
44
124
|
* Don't enable sourcemap automatically (#4)
|
45
125
|
* Don't override logger by default; instead, rely on `:logger` API option to change logger
|
46
126
|
* Add `--log-level` option to CLI to set severity level on logger (#9)
|
47
|
-
* Add `-q
|
127
|
+
* Add `-q`, `--quiet` option to CLI to suppress log messages (#9)
|
48
128
|
* Reserve zero index in include replacements for top-level document
|
49
129
|
|
50
130
|
=== Fixed
|
51
131
|
|
52
132
|
* Preserve return value when overridding `preprocess_include_directive` method
|
53
133
|
|
54
|
-
== 1.0.0.alpha.1 (2022-01-12) - @mojavelinux
|
55
|
-
|
56
|
-
Initial release.
|
57
|
-
|
58
|
-
=== Details
|
59
|
-
|
60
|
-
{url-repo}/releases/tag/v1.0.0.alpha.1[git tag]
|
61
|
-
|
62
134
|
=== Details
|
63
135
|
|
64
136
|
{url-repo}/releases/tag/v1.0.0.alpha.2[git tag]
|
65
137
|
|
66
|
-
|
67
|
-
|
68
|
-
{url-repo}/releases/tag/v1.0.0.alpha.3[git tag]
|
69
|
-
|
70
|
-
=== Details
|
138
|
+
== 1.0.0.alpha.1 (2022-01-12) - @mojavelinux
|
71
139
|
|
72
|
-
|
140
|
+
Initial release.
|
73
141
|
|
74
142
|
=== Details
|
75
143
|
|
76
|
-
{url-repo}/releases/tag/v1.0.0.alpha.
|
144
|
+
{url-repo}/releases/tag/v1.0.0.alpha.1[git tag]
|
data/LICENSE
CHANGED
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
|
+
v1.0.0.alpha.8, 2022-02-23
|
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
|
26
|
-
|
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
|
-
|
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
|
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
|
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
|
-
===
|
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
|
-
|
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
|
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
|
-
|
97
|
-
|
98
|
-
=== As extension
|
100
|
+
=== API
|
99
101
|
|
100
|
-
You can use this tool
|
101
|
-
To
|
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,
|
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.
|
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
|
-
|
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/
|
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
|
|
data/asciidoctor-reducer.gemspec
CHANGED
data/bin/asciidoctor-reducer
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
if File.exist?
|
6
|
-
require
|
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,26 +28,43 @@ 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 '
|
38
|
-
|
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 '-
|
43
|
-
options[:
|
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 '-
|
47
|
-
|
48
|
-
|
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
|
56
|
+
|
57
|
+
opts.on '--trace', 'trace the cause of application errors (default: false)' do
|
58
|
+
options[:trace] = true
|
49
59
|
end
|
50
60
|
|
51
61
|
opts.on '-v', '--version', 'display the version information and exit' do
|
52
|
-
|
62
|
+
print_version opts
|
63
|
+
return 0
|
64
|
+
end
|
65
|
+
|
66
|
+
opts.on '-h', '--help', 'display this help text and exit' do
|
67
|
+
print_help opts
|
53
68
|
return 0
|
54
69
|
end
|
55
70
|
end
|
@@ -58,44 +73,65 @@ module Asciidoctor::Reducer
|
|
58
73
|
|
59
74
|
if args.empty?
|
60
75
|
opt_parser.warn 'Please specify an AsciiDoc file to reduce.'
|
61
|
-
|
76
|
+
print_help opt_parser
|
62
77
|
1
|
63
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
|
64
87
|
options[:input_file] = args[0]
|
65
88
|
options[:output_file] = '-' unless options[:output_file]
|
66
89
|
[0, options]
|
67
90
|
else
|
68
91
|
opt_parser.warn %(extra arguments detected (unparsed arguments: #{(args.drop 1).join ' '}))
|
69
|
-
|
70
|
-
|
92
|
+
print_help opt_parser
|
93
|
+
1
|
71
94
|
end
|
72
95
|
rescue ::OptionParser::InvalidOption
|
73
|
-
$stderr.
|
74
|
-
|
96
|
+
$stderr.puts %(#{opt_parser.program_name}: #{$!.message})
|
97
|
+
print_help opt_parser
|
75
98
|
1
|
76
99
|
end
|
77
100
|
|
78
101
|
def self.run args = ARGV
|
79
|
-
old_logger = ::Asciidoctor::LoggerManager.logger
|
80
102
|
code, options = new.parse (Array args)
|
81
103
|
return code unless code == 0 && options
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
(
|
86
|
-
end
|
87
|
-
if (input_file = options.delete :input_file) == '-'
|
88
|
-
reduced = (::Asciidoctor.load $stdin, options).source + ?\n
|
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
|
89
108
|
else
|
90
|
-
|
109
|
+
options[:logger] = nil
|
91
110
|
end
|
92
|
-
|
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
|
93
114
|
0
|
115
|
+
rescue ::SignalException
|
116
|
+
$stderr.puts if ::Interrupt === $!
|
117
|
+
$!.signo
|
94
118
|
rescue
|
95
|
-
|
119
|
+
raise $! if trace
|
120
|
+
$stderr.puts %(asciidoctor-reducer: #{$!.message.delete_prefix 'asciidoctor: '})
|
121
|
+
$stderr.puts ' Use --trace to show backtrace'
|
96
122
|
1
|
97
123
|
ensure
|
98
|
-
::Asciidoctor::LoggerManager.logger = old_logger
|
124
|
+
::Asciidoctor::LoggerManager.logger = old_logger if old_logger
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def print_help opt_parser
|
130
|
+
$stdout.puts opt_parser.help.chomp
|
131
|
+
end
|
132
|
+
|
133
|
+
def print_version opt_parser
|
134
|
+
$stdout.puts %(#{opt_parser.program_name} #{VERSION})
|
99
135
|
end
|
100
136
|
end
|
101
137
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Asciidoctor::Reducer
|
4
|
+
module ConditionalDirectiveTracker
|
5
|
+
def preprocess_conditional_directive keyword, target, delimiter, text
|
6
|
+
skip_active = @skipping
|
7
|
+
depth = @conditional_stack.size
|
8
|
+
cond_lineno = @lineno
|
9
|
+
result = super
|
10
|
+
return result if @skipping && skip_active
|
11
|
+
drop = @x_include_replacements.current[:drop] ||= []
|
12
|
+
if (depth_change = @conditional_stack.size - depth) < 0
|
13
|
+
if skip_active
|
14
|
+
drop.push(*(drop.pop..cond_lineno))
|
15
|
+
else
|
16
|
+
drop << cond_lineno
|
17
|
+
end
|
18
|
+
elsif depth_change > 0 || cond_lineno == @lineno
|
19
|
+
drop << cond_lineno
|
20
|
+
else
|
21
|
+
drop << [cond_lineno, text]
|
22
|
+
end
|
23
|
+
result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
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(®istry) 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
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Asciidoctor::Reducer
|
4
|
+
module IncludeDirectiveTracker
|
5
|
+
attr_writer :source_lines
|
6
|
+
attr_reader :x_include_replacements
|
7
|
+
|
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
|
12
|
+
end
|
13
|
+
|
14
|
+
def preprocess_include_directive target, attrlist
|
15
|
+
@x_include_directive_line = %(include::#{target}[#{attrlist}])
|
16
|
+
@x_include_pushed = false
|
17
|
+
inc_lineno = @lineno # we're currently on the include line, which is 1-based
|
18
|
+
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
|
24
|
+
end
|
25
|
+
push_include_replacement inc_lineno, (unresolved ? [ln] : []), unresolved
|
26
|
+
end
|
27
|
+
@x_include_directive_line = @x_include_pushed = nil
|
28
|
+
result
|
29
|
+
end
|
30
|
+
|
31
|
+
def push_include data, file, path, lineno, attrs
|
32
|
+
@x_include_pushed = true
|
33
|
+
inc_lineno = @lineno - 1 # we're below the include line, which is 1-based
|
34
|
+
prev_inc_depth = @include_stack.size
|
35
|
+
result = super
|
36
|
+
push_include_replacement inc_lineno, (@include_stack.size > prev_inc_depth ? lines : [])
|
37
|
+
result
|
38
|
+
end
|
39
|
+
|
40
|
+
def pop_include
|
41
|
+
@x_include_replacements.pos = @x_include_replacements.current[:into] unless @x_include_pushed
|
42
|
+
super
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def push_include_replacement lineno, lines, unresolved = false
|
48
|
+
(inc_replacements = @x_include_replacements) << {
|
49
|
+
into: inc_replacements.pos,
|
50
|
+
lineno: lineno,
|
51
|
+
line: @x_include_directive_line,
|
52
|
+
lines: lines,
|
53
|
+
}
|
54
|
+
inc_replacements.pos = inc_replacements.size - 1 unless unresolved || lines.empty?
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
module CurrentPosition
|
60
|
+
attr_accessor :pos
|
61
|
+
|
62
|
+
def self.extended instance
|
63
|
+
instance.pos = instance.size - 1
|
64
|
+
end
|
65
|
+
|
66
|
+
def current
|
67
|
+
self[@pos]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
private_constant :CurrentPosition
|
72
|
+
end
|
@@ -1,11 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative '
|
3
|
+
require_relative 'include_directive_tracker'
|
4
|
+
require_relative 'conditional_directive_tracker'
|
4
5
|
|
5
6
|
module Asciidoctor::Reducer
|
6
7
|
class Preprocessor < ::Asciidoctor::Extensions::Preprocessor
|
7
8
|
def process doc, reader
|
8
|
-
|
9
|
+
reader.extend IncludeDirectiveTracker
|
10
|
+
reader.extend ConditionalDirectiveTracker unless doc.options[:preserve_conditionals]
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
@@ -3,28 +3,36 @@
|
|
3
3
|
module Asciidoctor::Reducer
|
4
4
|
class TreeProcessor < ::Asciidoctor::Extensions::TreeProcessor
|
5
5
|
def process doc
|
6
|
-
|
7
|
-
unless (inc_replacements = doc.reader.x_include_replacements).length == 1 && inc_replacements[0][:drop].empty?
|
6
|
+
if (inc_replacements = doc.reader.x_include_replacements).size > 1 || !(inc_replacements[0][:drop] || []).empty?
|
8
7
|
inc_replacements[0][:lines] = doc.source_lines.dup
|
9
8
|
inc_replacements.reverse_each do |it|
|
10
9
|
if (into = it[:into])
|
11
10
|
target_lines = inc_replacements[into][:lines]
|
12
11
|
# adds extra bit of assurance that we're replacing the correct line
|
13
|
-
next unless target_lines[(
|
12
|
+
next unless target_lines[(idx = it[:lineno] - 1)] == it[:line]
|
14
13
|
end
|
15
14
|
lines = it[:lines]
|
16
|
-
unless (drop = it[:drop]).empty?
|
17
|
-
drop.reverse_each
|
15
|
+
unless (drop = it[:drop] || []).empty?
|
16
|
+
drop.reverse_each do |drop_it|
|
17
|
+
::Array === drop_it ? (lines[drop_it[0] - 1] = drop_it[1]) : (lines.delete_at drop_it - 1)
|
18
|
+
end
|
18
19
|
end
|
19
|
-
target_lines[
|
20
|
+
target_lines[idx] = lines if target_lines
|
20
21
|
end
|
21
22
|
source_lines = inc_replacements[0][:lines].flatten
|
22
23
|
if doc.sourcemap
|
23
24
|
logger = ::Asciidoctor::LoggerManager.logger
|
24
|
-
|
25
|
+
opts = doc.options.merge logger: nil, parse: false, reduced: true
|
26
|
+
if (ext_reg = opts[:extension_registry])
|
27
|
+
opts[:extension_registry] = ::Asciidoctor::Extensions::Registry.new ext_reg.groups
|
28
|
+
end
|
29
|
+
includes = doc.catalog[:includes]
|
30
|
+
doc = ::Asciidoctor.load source_lines, opts
|
31
|
+
doc.catalog[:includes] = includes
|
32
|
+
doc.parse
|
25
33
|
::Asciidoctor::LoggerManager.logger = logger
|
26
34
|
else
|
27
|
-
source_lines.pop while (
|
35
|
+
source_lines.pop while (source_lines[-1] || :eof).empty?
|
28
36
|
doc.reader.source_lines = source_lines
|
29
37
|
end
|
30
38
|
end
|
data/lib/asciidoctor/reducer.rb
CHANGED
@@ -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
|
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.
|
4
|
+
version: 1.0.0.alpha.8
|
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-
|
11
|
+
date: 2022-02-23 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.
|
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.
|
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,10 +68,12 @@ 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
|
73
|
+
- lib/asciidoctor/reducer/conditional_directive_tracker.rb
|
72
74
|
- lib/asciidoctor/reducer/extensions.rb
|
75
|
+
- lib/asciidoctor/reducer/include_directive_tracker.rb
|
73
76
|
- lib/asciidoctor/reducer/preprocessor.rb
|
74
|
-
- lib/asciidoctor/reducer/preprocessor_directive_tracker.rb
|
75
77
|
- lib/asciidoctor/reducer/tree_processor.rb
|
76
78
|
- lib/asciidoctor/reducer/version.rb
|
77
79
|
homepage: https://asciidoctor.org
|
@@ -1,92 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Asciidoctor::Reducer
|
4
|
-
module PreprocessorDirectiveTracker
|
5
|
-
attr_writer :source_lines
|
6
|
-
attr_reader :x_include_replacements
|
7
|
-
|
8
|
-
def self.extended instance
|
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
|
12
|
-
end
|
13
|
-
|
14
|
-
def preprocess_conditional_directive keyword, target, delimiter, text
|
15
|
-
return super if (opts = @document.options)[:preserve_conditionals] || opts[:reduced]
|
16
|
-
skip_active = @skipping
|
17
|
-
depth = @conditional_stack.length
|
18
|
-
cond_lineno = @lineno - 1
|
19
|
-
result = super
|
20
|
-
return result if @skipping && skip_active
|
21
|
-
drop = @x_include_replacements.current[:drop]
|
22
|
-
if (depth_change = @conditional_stack.length - depth) < 0
|
23
|
-
if skip_active
|
24
|
-
drop.push(*(drop.pop..cond_lineno))
|
25
|
-
else
|
26
|
-
drop << cond_lineno
|
27
|
-
end
|
28
|
-
elsif depth_change > 0 || cond_lineno == @lineno - 1
|
29
|
-
drop << cond_lineno
|
30
|
-
else
|
31
|
-
drop << [cond_lineno, text]
|
32
|
-
end
|
33
|
-
result
|
34
|
-
end
|
35
|
-
|
36
|
-
def preprocess_include_directive target, attrlist
|
37
|
-
@x_include_directive_line = %(include::#{target}[#{attrlist}])
|
38
|
-
@x_include_pushed = false
|
39
|
-
inc_lineno = @lineno - 1 # we're currently on the include line, which is 1-based
|
40
|
-
result = super
|
41
|
-
if @x_include_pushed
|
42
|
-
@x_include_directive_line = @x_include_pushed = nil
|
43
|
-
return result
|
44
|
-
end
|
45
|
-
inc_lines = ((line = lines[0].to_s).start_with? 'Unresolved directive in ') && (line.end_with? ']') ? [line] : []
|
46
|
-
push_include_replacement inc_lineno, inc_lines
|
47
|
-
@x_include_directive_line = @x_include_pushed = nil
|
48
|
-
result
|
49
|
-
end
|
50
|
-
|
51
|
-
def push_include data, file, path, lineno, attrs
|
52
|
-
@x_include_pushed = true
|
53
|
-
inc_lineno = @lineno - 2 # we're below the include line, which is 1-based
|
54
|
-
prev_inc_depth = @include_stack.length
|
55
|
-
result = super
|
56
|
-
inc_lines = lines if @include_stack.length > prev_inc_depth
|
57
|
-
push_include_replacement inc_lineno, inc_lines
|
58
|
-
result
|
59
|
-
end
|
60
|
-
|
61
|
-
def pop_include
|
62
|
-
@x_include_replacements.pos = @x_include_replacements.current[:into] unless @x_include_pushed
|
63
|
-
super
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def push_include_replacement inc_lineno, inc_lines
|
69
|
-
@x_include_replacements << {
|
70
|
-
into: @x_include_replacements.pos,
|
71
|
-
lineno: inc_lineno,
|
72
|
-
line: @x_include_directive_line,
|
73
|
-
lines: inc_lines || [],
|
74
|
-
drop: [],
|
75
|
-
}
|
76
|
-
@x_include_replacements.pos = @x_include_replacements.length - 1 if inc_lines
|
77
|
-
nil
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
module CurrentPosition
|
82
|
-
attr_accessor :pos
|
83
|
-
|
84
|
-
def self.extended instance
|
85
|
-
instance.pos = instance.length - 1
|
86
|
-
end
|
87
|
-
|
88
|
-
def current
|
89
|
-
self[@pos]
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|