asciidoctor-reducer 1.0.0.alpha.6 → 1.0.0.alpha.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.adoc +89 -19
- data/LICENSE +1 -1
- data/README.adoc +132 -19
- data/asciidoctor-reducer.gemspec +1 -1
- data/bin/asciidoctor-reducer +2 -9
- data/lib/asciidoctor/reducer/api.rb +53 -0
- data/lib/asciidoctor/reducer/cli.rb +112 -98
- data/lib/asciidoctor/reducer/conditional_directive_tracker.rb +26 -0
- data/lib/asciidoctor/reducer/extensions.rb +38 -0
- data/lib/asciidoctor/reducer/include_directive_tracker.rb +78 -0
- data/lib/asciidoctor/reducer/include_mapper/extension.rb +16 -0
- data/lib/asciidoctor/reducer/include_mapper.rb +8 -0
- data/lib/asciidoctor/reducer/preprocessor.rb +5 -3
- data/lib/asciidoctor/reducer/tree_processor.rb +8 -6
- data/lib/asciidoctor/reducer/version.rb +1 -1
- data/lib/asciidoctor/reducer.rb +1 -6
- metadata +10 -6
- data/lib/asciidoctor/reducer/preprocessor_directive_tracker.rb +0 -89
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80723a5097c54761a2bee3b3ea88f827c88614b7a5572a6b5f1b10cb7af60c8c
|
4
|
+
data.tar.gz: d6f23a15e6dae8db02f5810d22018f537af9d6e67ac8362dbc2fe3155417df2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: db4173fd2899008fec759e9d76f2732a7f5f7ca0a284f5c66a93040b9fca81dba22cf151e77e86b2b73c535545cec4b3a54c88407324514811260832b8ed1c7d
|
7
|
+
data.tar.gz: ec7a7d27cb1b87dcb0772af642f185002f7348e0a540c40bf3a6e98334d7be0b088b8b00312ca10dd5470cdaff60007e70c2d27708d97c4677c7a3302694473e
|
data/CHANGELOG.adoc
CHANGED
@@ -4,6 +4,76 @@
|
|
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
|
+
|
33
|
+
== 1.0.0.alpha.8 (2022-02-23) - @mojavelinux
|
34
|
+
|
35
|
+
=== Added
|
36
|
+
|
37
|
+
* Add secure mode as value of `-S` CLI option (#31)
|
38
|
+
* Add `--trace` option to CLI to trace cause of application errors (#29)
|
39
|
+
|
40
|
+
=== Changed
|
41
|
+
|
42
|
+
* Replace include directive with link macro if safe mode is secure (#31)
|
43
|
+
* Track line numbers in include replacements using 1-based index
|
44
|
+
* Only mix in preprocessor conditional tracker if `:preserve_conditionals` option is not set (#36)
|
45
|
+
|
46
|
+
=== Fixed
|
47
|
+
|
48
|
+
* Handle signals gracefully (#33)
|
49
|
+
|
50
|
+
=== Details
|
51
|
+
|
52
|
+
{url-repo}/releases/tag/v1.0.0.alpha.8[git tag]
|
53
|
+
|
54
|
+
== 1.0.0.alpha.7 (2022-02-14) - @mojavelinux
|
55
|
+
|
56
|
+
=== Added
|
57
|
+
|
58
|
+
* Add asciidoctor/reducer/api to require main API (#3)
|
59
|
+
* Add `Asciidoctor::Reducer.reduce` and `Asciidoctor::Reducer.reduce_file` API methods (#3)
|
60
|
+
* Add asciidoctor/reducer/extensions to require extensions API (#3)
|
61
|
+
* Add `Asciidoctor::Reducer::Extensions` API (#3)
|
62
|
+
|
63
|
+
=== Changed
|
64
|
+
|
65
|
+
* Scope extensions to single call instead of registering them globally (#3)
|
66
|
+
* Use `:safe` as the default safe mode when using the API
|
67
|
+
* Make `CurrentPosition` module private to the `PreprocessorDirectiveTracker` module
|
68
|
+
|
69
|
+
=== Fixed
|
70
|
+
|
71
|
+
* Require asciidoctor/reducer/version automatically when `Asciidoctor::Reducer::VERSION` is accessed
|
72
|
+
|
73
|
+
=== Details
|
74
|
+
|
75
|
+
{url-repo}/releases/tag/v1.0.0.alpha.7[git tag]
|
76
|
+
|
7
77
|
== 1.0.0.alpha.6 (2022-02-10) - @mojavelinux
|
8
78
|
|
9
79
|
=== Added
|
@@ -24,6 +94,10 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co
|
|
24
94
|
* Prevent custom extension registry from activating extensions twice during reload (#21)
|
25
95
|
* Retain includes table in document catalog when reloading document (#23)
|
26
96
|
|
97
|
+
=== Details
|
98
|
+
|
99
|
+
{url-repo}/releases/tag/v1.0.0.alpha.6[git tag]
|
100
|
+
|
27
101
|
== 1.0.0.alpha.5 (2022-02-06) - @mojavelinux
|
28
102
|
|
29
103
|
=== Changed
|
@@ -37,12 +111,20 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co
|
|
37
111
|
|
38
112
|
* Suppress log messages when reloading document (#14)
|
39
113
|
|
114
|
+
=== Details
|
115
|
+
|
116
|
+
{url-repo}/releases/tag/v1.0.0.alpha.5[git tag]
|
117
|
+
|
40
118
|
== 1.0.0.alpha.4 (2022-02-03) - @mojavelinux
|
41
119
|
|
42
120
|
=== Fixed
|
43
121
|
|
44
122
|
* Fix replacement of nested empty and unresolved includes
|
45
123
|
|
124
|
+
=== Details
|
125
|
+
|
126
|
+
{url-repo}/releases/tag/v1.0.0.alpha.4[git tag]
|
127
|
+
|
46
128
|
== 1.0.0.alpha.3 (2022-02-02) - @mojavelinux
|
47
129
|
|
48
130
|
=== Changed
|
@@ -52,6 +134,10 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co
|
|
52
134
|
* Only reload document if source lines have changed; otherwise, update source lines on reader directly
|
53
135
|
* Change default safe mode for CLI to :unsafe
|
54
136
|
|
137
|
+
=== Details
|
138
|
+
|
139
|
+
{url-repo}/releases/tag/v1.0.0.alpha.3[git tag]
|
140
|
+
|
55
141
|
== 1.0.0.alpha.2 (2022-01-27) - @mojavelinux
|
56
142
|
|
57
143
|
=== Added
|
@@ -71,30 +157,14 @@ For a detailed view of what has changed, refer to the {url-repo}/commits/main[co
|
|
71
157
|
|
72
158
|
* Preserve return value when overridding `preprocess_include_directive` method
|
73
159
|
|
74
|
-
== 1.0.0.alpha.1 (2022-01-12) - @mojavelinux
|
75
|
-
|
76
|
-
Initial release.
|
77
|
-
|
78
|
-
=== Details
|
79
|
-
|
80
|
-
{url-repo}/releases/tag/v1.0.0.alpha.1[git tag]
|
81
|
-
|
82
160
|
=== Details
|
83
161
|
|
84
162
|
{url-repo}/releases/tag/v1.0.0.alpha.2[git tag]
|
85
163
|
|
86
|
-
|
87
|
-
|
88
|
-
{url-repo}/releases/tag/v1.0.0.alpha.3[git tag]
|
89
|
-
|
90
|
-
=== Details
|
91
|
-
|
92
|
-
{url-repo}/releases/tag/v1.0.0.alpha.4[git tag]
|
93
|
-
|
94
|
-
=== Details
|
164
|
+
== 1.0.0.alpha.1 (2022-01-12) - @mojavelinux
|
95
165
|
|
96
|
-
|
166
|
+
Initial release.
|
97
167
|
|
98
168
|
=== Details
|
99
169
|
|
100
|
-
{url-repo}/releases/tag/v1.0.0.alpha.
|
170
|
+
{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.9, 2022-04-21
|
4
4
|
:idprefix:
|
5
5
|
:idseparator: -
|
6
6
|
ifndef::env-github[:icons: font]
|
@@ -16,16 +16,16 @@ 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
|
20
|
-
The tool also applies preprocessor conditionals (unless the option to preserve them is specified), leaving behind only the
|
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
|
24
24
|
|
25
|
-
{project-name} is a Ruby
|
25
|
+
{project-name} is a Ruby application that you install using Ruby packaging.
|
26
26
|
To install and run {project-name}, you need Ruby 2.5 or better.
|
27
27
|
|
28
|
-
Run the following command to check
|
28
|
+
Run the following command to check which version of Ruby you have installed, if any:
|
29
29
|
|
30
30
|
$ ruby -v
|
31
31
|
|
@@ -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,7 @@ asciidoctor-reducer [OPTION]... FILE
|
|
75
77
|
....
|
76
78
|
|
77
79
|
The argument `FILE` is the AsciiDoc file you want to reduce.
|
78
|
-
The options, represented by
|
80
|
+
The options, represented by `+[OPTION]...+`, are optional, as the name suggestions.
|
79
81
|
|
80
82
|
Thus, to use the command, pass the AsciiDoc file as the sole argument:
|
81
83
|
|
@@ -91,27 +93,26 @@ To use the command in this way, pass `-` as the first argument:
|
|
91
93
|
|
92
94
|
$ cat input.adoc | asciidoctor-reducer -
|
93
95
|
|
94
|
-
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:
|
95
97
|
|
96
98
|
$ cat input.adoc | asciidoctor-reducer -o output.adoc -
|
97
99
|
|
98
|
-
|
99
|
-
|
100
|
-
=== As extension
|
100
|
+
=== API
|
101
101
|
|
102
|
-
You can use this tool
|
103
|
-
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.
|
104
104
|
|
105
105
|
[,ruby]
|
106
106
|
----
|
107
|
-
require 'asciidoctor/reducer'
|
107
|
+
require 'asciidoctor/reducer/api'
|
108
108
|
----
|
109
109
|
|
110
|
-
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`.
|
111
112
|
|
112
113
|
[,ruby]
|
113
114
|
----
|
114
|
-
doc = Asciidoctor.
|
115
|
+
doc = Asciidoctor::Reducer.reduce_file 'sample.adoc'
|
115
116
|
----
|
116
117
|
|
117
118
|
Finally, you can retrieve the reduced source from the returned document.
|
@@ -121,11 +122,60 @@ Finally, you can retrieve the reduced source from the returned document.
|
|
121
122
|
puts doc.source
|
122
123
|
----
|
123
124
|
|
124
|
-
|
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.
|
125
174
|
|
126
175
|
== How it Works
|
127
176
|
|
128
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.
|
129
179
|
|
130
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).
|
131
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.
|
@@ -147,6 +197,69 @@ This call will cause extensions that run during the load phase to be invoked aga
|
|
147
197
|
An extension can check for this secondary load by checking for the `:reduced` option in the `Document#options` hash.
|
148
198
|
If this option is set (the value of which will be `true`), then Asciidoctor is loading the reduced document.
|
149
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
|
+
|
150
263
|
== Development
|
151
264
|
|
152
265
|
Follow the instructions below to learn how to help develop the project or test-drive the development version.
|
@@ -191,7 +304,7 @@ For more fine-grained control, you can also run the tests directly using RSpec:
|
|
191
304
|
|
192
305
|
To run all tests in a single spec, point RSpec at the spec file:
|
193
306
|
|
194
|
-
$ bundle exec rspec spec/
|
307
|
+
$ bundle exec rspec spec/reducer_spec.rb
|
195
308
|
|
196
309
|
==== Run specific tests
|
197
310
|
|
data/asciidoctor-reducer.gemspec
CHANGED
data/bin/asciidoctor-reducer
CHANGED
@@ -1,13 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
require asciidoctor_reducer
|
7
|
-
else
|
8
|
-
require 'asciidoctor/reducer'
|
9
|
-
end
|
10
|
-
|
11
|
-
require 'asciidoctor/reducer/cli'
|
12
|
-
|
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'
|
13
6
|
exit Asciidoctor::Reducer::Cli.run
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
autoload :Pathname, '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 || {}
|
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
|
17
|
+
case input
|
18
|
+
when ::File
|
19
|
+
doc = ::Asciidoctor.load_file input, opts
|
20
|
+
when ::Pathname
|
21
|
+
doc = ::Asciidoctor.load_file input.to_path, opts
|
22
|
+
else
|
23
|
+
doc = ::Asciidoctor.load input, opts
|
24
|
+
end
|
25
|
+
write doc, to
|
26
|
+
end
|
27
|
+
|
28
|
+
def reduce_file input_file, opts = {}
|
29
|
+
reduce (::Pathname.new input_file), opts
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def write doc, to
|
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
|
44
|
+
end
|
45
|
+
doc
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
LF = ?\n
|
50
|
+
UTF_8 = ::Encoding::UTF_8
|
51
|
+
|
52
|
+
private_constant :LF, :UTF_8
|
53
|
+
end
|
@@ -1,127 +1,141 @@
|
|
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
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
13
28
|
|
14
|
-
|
15
|
-
|
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
|
16
33
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
Usage: #{opts.program_name} [OPTION]... FILE
|
34
|
+
opts.on '-o FILE', '--output=FILE', 'set the output filename or stream' do |file|
|
35
|
+
options[:output_file] = file
|
36
|
+
end
|
21
37
|
|
22
|
-
|
38
|
+
opts.on '--preserve-conditionals', 'preserve preprocessor conditional directives in the reduced source' do
|
39
|
+
options[:preserve_conditionals] = true
|
40
|
+
end
|
23
41
|
|
24
|
-
|
42
|
+
opts.on '-q', '--quiet', 'suppress all application log messages' do
|
43
|
+
options[:log_level] = nil
|
44
|
+
end
|
25
45
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
options[:attributes][key] = val
|
31
|
-
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
|
32
50
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
37
55
|
|
38
|
-
|
39
|
-
|
40
|
-
|
56
|
+
opts.on '--trace', 'trace the cause of application errors (default: false)' do
|
57
|
+
options[:trace] = true
|
58
|
+
end
|
41
59
|
|
42
|
-
|
43
|
-
|
44
|
-
|
60
|
+
opts.on '-v', '--version', 'display the version information and exit' do
|
61
|
+
print_version opts
|
62
|
+
return 0
|
63
|
+
end
|
45
64
|
|
46
|
-
|
47
|
-
|
65
|
+
opts.on '-h', '--help', 'display this help text and exit' do
|
66
|
+
print_help opts
|
67
|
+
return 0
|
68
|
+
end
|
48
69
|
end
|
49
70
|
|
50
|
-
|
51
|
-
|
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
|
52
91
|
end
|
92
|
+
rescue ::OptionParser::InvalidOption
|
93
|
+
$stderr.puts %(#{opt_parser.program_name}: #{$!.message})
|
94
|
+
print_help opt_parser
|
95
|
+
1
|
96
|
+
end
|
53
97
|
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
57
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
|
122
|
+
end
|
58
123
|
|
59
|
-
|
60
|
-
$stdout.write %(#{opts.program_name} #{VERSION}\n)
|
61
|
-
return 0
|
62
|
-
end
|
124
|
+
private
|
63
125
|
|
64
|
-
|
65
|
-
|
66
|
-
return 0
|
67
|
-
end
|
126
|
+
def print_help opt_parser
|
127
|
+
$stdout.puts opt_parser.help.chomp
|
68
128
|
end
|
69
129
|
|
70
|
-
|
71
|
-
|
72
|
-
if args.empty?
|
73
|
-
opt_parser.warn 'Please specify an AsciiDoc file to reduce.'
|
74
|
-
$stdout.write opt_parser.help
|
75
|
-
1
|
76
|
-
elsif args.size == 1
|
77
|
-
if (requires = options.delete :requires)
|
78
|
-
requires.uniq.each do |path|
|
79
|
-
require path
|
80
|
-
rescue ::LoadError
|
81
|
-
$stderr.write %(#{opt_parser.program_name}: '#{path}' could not be required (reason: #{$!.message})\n)
|
82
|
-
return 1
|
83
|
-
end
|
84
|
-
end
|
85
|
-
options[:input_file] = args[0]
|
86
|
-
options[:output_file] = '-' unless options[:output_file]
|
87
|
-
[0, options]
|
88
|
-
else
|
89
|
-
opt_parser.warn %(extra arguments detected (unparsed arguments: #{(args.drop 1).join ' '}))
|
90
|
-
$stdout.write opt_parser.help
|
91
|
-
1
|
130
|
+
def print_version opt_parser
|
131
|
+
$stdout.puts %(#{opt_parser.program_name} #{VERSION})
|
92
132
|
end
|
93
|
-
rescue ::OptionParser::InvalidOption
|
94
|
-
$stderr.write %(#{opt_parser.program_name}: #{$!.message}\n)
|
95
|
-
$stdout.write opt_parser.help
|
96
|
-
1
|
97
133
|
end
|
98
134
|
|
99
|
-
|
100
|
-
|
101
|
-
return code unless code == 0 && options
|
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
|
107
|
-
end
|
108
|
-
if (output_file = options.delete :output_file) == '-'
|
109
|
-
to = $stdout
|
110
|
-
else
|
111
|
-
(to = ::Pathname.new output_file).dirname.mkpath
|
112
|
-
end
|
113
|
-
if (input_file = options.delete :input_file) == '-'
|
114
|
-
reduced = (::Asciidoctor.load $stdin, options).source + ?\n
|
115
|
-
else
|
116
|
-
reduced = (::Asciidoctor.load_file input_file, options).source + ?\n
|
117
|
-
end
|
118
|
-
::Pathname === to ? (to.write reduced, encoding: ::Encoding::UTF_8) : (to.write reduced)
|
119
|
-
0
|
120
|
-
rescue
|
121
|
-
$stderr.write %(asciidoctor-reducer: #{$!.message}\n)
|
122
|
-
1
|
123
|
-
ensure
|
124
|
-
::Asciidoctor::LoggerManager.logger = old_logger if old_logger
|
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
|
125
137
|
end
|
138
|
+
|
139
|
+
private_constant :LOG_LEVELS
|
126
140
|
end
|
127
141
|
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 = @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,42 @@
|
|
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 key
|
20
|
+
:reducer
|
21
|
+
end
|
22
|
+
|
23
|
+
def prepare_registry registry = nil
|
24
|
+
registry = ::Asciidoctor::Extensions.create(®istry) if ::Proc === registry
|
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
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def register
|
35
|
+
::Asciidoctor::Extensions.register key, &group
|
36
|
+
end
|
37
|
+
|
38
|
+
def unregister
|
39
|
+
::Asciidoctor::Extensions.groups.delete key # NOTE `Extensions.unregister key` fails if groups is not initialized
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Asciidoctor::Reducer
|
4
|
+
module IncludeDirectiveTracker
|
5
|
+
attr_reader :include_replacements
|
6
|
+
attr_writer :source_lines
|
7
|
+
|
8
|
+
def self.extended instance
|
9
|
+
instance.instance_variable_set :@include_replacements, ([{}].extend CurrentPosition)
|
10
|
+
instance.instance_variable_set :@x_reducer, {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def preprocess_include_directive target, attrlist
|
14
|
+
@x_reducer[:include_directive_line] = %(include::#{target}[#{attrlist}])
|
15
|
+
@x_reducer[:include_pushed] = false
|
16
|
+
inc_lineno = @lineno # we're currently on the include line, which is 1-based
|
17
|
+
result = super
|
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])
|
22
|
+
end
|
23
|
+
push_include_replacement inc_lineno, (unresolved ? [ln] : []), unresolved
|
24
|
+
end
|
25
|
+
@x_reducer.clear
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
def push_include data, file, path, lineno, attrs
|
30
|
+
@x_reducer[:include_pushed] = true
|
31
|
+
inc_lineno = @lineno - 1 # we're below the include line, which is 1-based
|
32
|
+
prev_inc_depth = @include_stack.size
|
33
|
+
result = super
|
34
|
+
push_include_replacement inc_lineno, (@include_stack.size > prev_inc_depth ? lines : [])
|
35
|
+
result
|
36
|
+
end
|
37
|
+
|
38
|
+
def pop_include
|
39
|
+
@include_replacements.up unless @x_reducer[:include_pushed]
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def push_include_replacement lineno, lines, unresolved = false
|
46
|
+
(inc_replacements = @include_replacements) << {
|
47
|
+
into: inc_replacements.pointer,
|
48
|
+
lineno: lineno,
|
49
|
+
line: @x_reducer[:include_directive_line],
|
50
|
+
lines: lines,
|
51
|
+
}
|
52
|
+
inc_replacements.to_end unless unresolved || lines.empty?
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module CurrentPosition
|
58
|
+
attr_reader :pointer
|
59
|
+
|
60
|
+
def self.extended instance
|
61
|
+
instance.to_end
|
62
|
+
end
|
63
|
+
|
64
|
+
def current
|
65
|
+
self[@pointer]
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_end
|
69
|
+
@pointer = size - 1
|
70
|
+
end
|
71
|
+
|
72
|
+
def up
|
73
|
+
@pointer = current[:into]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private_constant :CurrentPosition
|
78
|
+
end
|
@@ -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
|
@@ -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
|
-
def process
|
8
|
-
|
8
|
+
def process doc, reader
|
9
|
+
doc.options[:preserve_conditionals] ?
|
10
|
+
(reader.extend IncludeDirectiveTracker) : (reader.extend ConditionalDirectiveTracker, IncludeDirectiveTracker)
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
@@ -3,19 +3,21 @@
|
|
3
3
|
module Asciidoctor::Reducer
|
4
4
|
class TreeProcessor < ::Asciidoctor::Extensions::TreeProcessor
|
5
5
|
def process doc
|
6
|
-
|
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])
|
10
10
|
target_lines = inc_replacements[into][:lines]
|
11
11
|
# adds extra bit of assurance that we're replacing the correct line
|
12
|
-
next unless target_lines[(
|
12
|
+
next unless target_lines[(idx = it[:lineno] - 1)] == it[:line]
|
13
13
|
end
|
14
14
|
lines = it[:lines]
|
15
|
-
unless (drop = it[:drop]).empty?
|
16
|
-
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
|
17
19
|
end
|
18
|
-
target_lines[
|
20
|
+
target_lines[idx] = lines if target_lines
|
19
21
|
end
|
20
22
|
source_lines = inc_replacements[0][:lines].flatten
|
21
23
|
if doc.sourcemap
|
@@ -30,7 +32,7 @@ module Asciidoctor::Reducer
|
|
30
32
|
doc.parse
|
31
33
|
::Asciidoctor::LoggerManager.logger = logger
|
32
34
|
else
|
33
|
-
source_lines.pop while (
|
35
|
+
source_lines.pop while (source_lines[-1] || :eof).empty?
|
34
36
|
doc.reader.source_lines = source_lines
|
35
37
|
end
|
36
38
|
end
|
data/lib/asciidoctor/reducer.rb
CHANGED
@@ -1,10 +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
|
-
next if document.options[:reduced]
|
8
|
-
preprocessor Asciidoctor::Reducer::Preprocessor
|
9
|
-
tree_processor Asciidoctor::Reducer::TreeProcessor
|
10
|
-
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.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-
|
11
|
+
date: 2022-04-21 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,14 @@ 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
|
76
|
+
- lib/asciidoctor/reducer/include_mapper.rb
|
77
|
+
- lib/asciidoctor/reducer/include_mapper/extension.rb
|
73
78
|
- lib/asciidoctor/reducer/preprocessor.rb
|
74
|
-
- lib/asciidoctor/reducer/preprocessor_directive_tracker.rb
|
75
79
|
- lib/asciidoctor/reducer/tree_processor.rb
|
76
80
|
- lib/asciidoctor/reducer/version.rb
|
77
81
|
homepage: https://asciidoctor.org
|
@@ -97,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
97
101
|
- !ruby/object:Gem::Version
|
98
102
|
version: 1.3.1
|
99
103
|
requirements: []
|
100
|
-
rubygems_version: 3.2.
|
104
|
+
rubygems_version: 3.2.33
|
101
105
|
signing_key:
|
102
106
|
specification_version: 4
|
103
107
|
summary: Reduces a composite AsciiDoc document containing includes and conditionals
|
@@ -1,89 +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 @document.options[:preserve_conditionals]
|
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
|
-
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
|
-
end
|
45
|
-
@x_include_directive_line = @x_include_pushed = nil
|
46
|
-
result
|
47
|
-
end
|
48
|
-
|
49
|
-
def push_include data, file, path, lineno, attrs
|
50
|
-
@x_include_pushed = true
|
51
|
-
inc_lineno = @lineno - 2 # we're below the include line, which is 1-based
|
52
|
-
prev_inc_depth = @include_stack.length
|
53
|
-
result = super
|
54
|
-
push_include_replacement inc_lineno, (@include_stack.length > prev_inc_depth ? lines : [])
|
55
|
-
result
|
56
|
-
end
|
57
|
-
|
58
|
-
def pop_include
|
59
|
-
@x_include_replacements.pos = @x_include_replacements.current[:into] unless @x_include_pushed
|
60
|
-
super
|
61
|
-
end
|
62
|
-
|
63
|
-
private
|
64
|
-
|
65
|
-
def push_include_replacement inc_lineno, inc_lines, unresolved = false
|
66
|
-
@x_include_replacements << {
|
67
|
-
into: @x_include_replacements.pos,
|
68
|
-
lineno: inc_lineno,
|
69
|
-
line: @x_include_directive_line,
|
70
|
-
lines: inc_lines,
|
71
|
-
drop: [],
|
72
|
-
}
|
73
|
-
@x_include_replacements.pos = @x_include_replacements.length - 1 unless unresolved || inc_lines.empty?
|
74
|
-
nil
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
module CurrentPosition
|
79
|
-
attr_accessor :pos
|
80
|
-
|
81
|
-
def self.extended instance
|
82
|
-
instance.pos = instance.length - 1
|
83
|
-
end
|
84
|
-
|
85
|
-
def current
|
86
|
-
self[@pos]
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|