asciidoctor 3.0.4 → 4.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +60 -15
- package/bin/asciidoctor +3 -6
- package/data/reference/syntax.adoc +289 -0
- package/index.js +2 -1
- package/lib/cli.js +257 -0
- package/package.json +29 -16
- package/types/README.adoc +3 -0
- package/types/abstract_block.d.ts +343 -0
- package/types/abstract_node.d.ts +471 -0
- package/types/attribute_entry.d.ts +7 -0
- package/types/attribute_list.d.ts +52 -0
- package/types/block.d.ts +55 -0
- package/types/browser/asset.d.ts +7 -0
- package/types/browser/reader.d.ts +29 -0
- package/types/callouts.d.ts +36 -0
- package/types/compliance.d.ts +23 -0
- package/types/constants.d.ts +268 -0
- package/types/convert.d.ts +34 -0
- package/types/converter/composite.d.ts +20 -0
- package/types/converter/docbook5.d.ts +41 -0
- package/types/converter/html5.d.ts +51 -0
- package/types/converter/manpage.d.ts +59 -0
- package/types/converter/template.d.ts +83 -0
- package/types/converter.d.ts +150 -0
- package/types/data/stylesheet-data.d.ts +2 -0
- package/types/document.d.ts +495 -0
- package/types/extensions.d.ts +876 -0
- package/types/footnote.d.ts +18 -0
- package/types/helpers.d.ts +146 -0
- package/types/index.d.ts +73 -3731
- package/types/inline.d.ts +69 -0
- package/types/list.d.ts +114 -0
- package/types/load.d.ts +39 -0
- package/types/logging.d.ts +187 -0
- package/types/parser.d.ts +114 -0
- package/types/path_resolver.d.ts +103 -0
- package/types/reader.d.ts +184 -0
- package/types/rx.d.ts +513 -0
- package/types/section.d.ts +122 -0
- package/types/stylesheets.d.ts +10 -0
- package/types/substitutors.d.ts +208 -0
- package/types/syntaxHighlighter/highlightjs.d.ts +33 -0
- package/types/syntaxHighlighter/html_pipeline.d.ts +16 -0
- package/types/syntax_highlighter.d.ts +167 -0
- package/types/table.d.ts +231 -0
- package/types/timings.d.ts +25 -0
- package/types/tsconfig.json +9 -0
package/LICENSE
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
The MIT License
|
|
2
2
|
|
|
3
|
-
Copyright (C) 2019 Dan Allen, Guillaume Grossetie, Anthonny Quérouil and the Asciidoctor Project
|
|
3
|
+
Copyright (C) 2019-present Dan Allen, Guillaume Grossetie, Anthonny Quérouil and the Asciidoctor Project
|
|
4
4
|
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
# Asciidoctor.js: AsciiDoc in JavaScript powered by Asciidoctor
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This package is a convenience wrapper that bundles `@asciidoctor/core` and the Asciidoctor CLI.
|
|
4
|
+
It provides a native JavaScript implementation of Asciidoctor with no compilation step.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
The API is asynchronous: all parsing and conversion operations return a `Promise`.
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
Node.js >= 24
|
|
7
11
|
|
|
8
12
|
## Install
|
|
9
13
|
|
|
@@ -13,23 +17,19 @@ $ npm i asciidoctor --save
|
|
|
13
17
|
|
|
14
18
|
## Usage
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
### Convert a string
|
|
17
21
|
|
|
18
22
|
**sample.js**
|
|
19
23
|
|
|
20
24
|
```javascript
|
|
21
25
|
import asciidoctor from 'asciidoctor'
|
|
22
26
|
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
'brings AsciiDoc to Node.js!'
|
|
27
|
-
const html = Asciidoctor.convert(content) // ②
|
|
28
|
-
console.log(html) // ③
|
|
27
|
+
const content = 'https://asciidoctor.org[*Asciidoctor*] running on Node.js!'
|
|
28
|
+
const html = await asciidoctor.convert(content) // ①
|
|
29
|
+
console.log(html) // ②
|
|
29
30
|
```
|
|
30
|
-
1.
|
|
31
|
-
2.
|
|
32
|
-
3. Print the HTML5 output to the console
|
|
31
|
+
1. Convert AsciiDoc content to HTML5 — the call returns a `Promise` and must be awaited
|
|
32
|
+
2. Print the HTML5 output to the console
|
|
33
33
|
|
|
34
34
|
Save the file as _sample.js_ and run it using the `node` command:
|
|
35
35
|
|
|
@@ -41,11 +41,52 @@ You should see the following output in your terminal:
|
|
|
41
41
|
|
|
42
42
|
```html
|
|
43
43
|
<div class="paragraph">
|
|
44
|
-
<p><a href="
|
|
44
|
+
<p><a href="https://asciidoctor.org"><strong>Asciidoctor</strong></a> running on Node.js!</p>
|
|
45
45
|
</div>
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
### Convert a file
|
|
49
|
+
|
|
50
|
+
**convert-file.js**
|
|
51
|
+
|
|
52
|
+
```javascript
|
|
53
|
+
import { convertFile } from 'asciidoctor'
|
|
54
|
+
|
|
55
|
+
await convertFile('document.adoc', { safe: 'safe' })
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Load without converting
|
|
59
|
+
|
|
60
|
+
Use `load` when you need to inspect the parsed document model before (or instead of) converting:
|
|
61
|
+
|
|
62
|
+
**load.js**
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
import { load } from 'asciidoctor'
|
|
66
|
+
|
|
67
|
+
const doc = await load('== Hello, World!\n\nThis is Asciidoctor.')
|
|
68
|
+
console.log(doc.getTitle()) // Hello, World!
|
|
69
|
+
console.log(doc.getBlocks()) // array of top-level blocks
|
|
70
|
+
const html = await doc.convert()
|
|
71
|
+
console.log(html)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## CLI
|
|
75
|
+
|
|
76
|
+
The `asciidoctor` command is available after installation:
|
|
77
|
+
|
|
78
|
+
```console
|
|
79
|
+
$ asciidoctor document.adoc
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Common options:
|
|
83
|
+
|
|
84
|
+
```console
|
|
85
|
+
$ asciidoctor -b html5 -a toc document.adoc
|
|
86
|
+
$ asciidoctor -o - document.adoc # output to stdout
|
|
87
|
+
$ asciidoctor --help # show all options
|
|
88
|
+
$ asciidoctor --help syntax # show AsciiDoc syntax reference
|
|
89
|
+
```
|
|
49
90
|
|
|
50
91
|
## Contributing
|
|
51
92
|
|
|
@@ -57,6 +98,10 @@ The [Contributing](https://github.com/asciidoctor/asciidoctor.js/blob/main/CONTR
|
|
|
57
98
|
|
|
58
99
|
If you want to write code, the [Contributing Code](https://github.com/asciidoctor/asciidoctor.js/blob/main/CONTRIBUTING-CODE.adoc) guide will help you to get started quickly.
|
|
59
100
|
|
|
101
|
+
## Changelog
|
|
102
|
+
|
|
103
|
+
Refer to the [CHANGELOG](https://github.com/asciidoctor/asciidoctor.js/blob/main/CHANGELOG.adoc) for a complete list of changes.
|
|
104
|
+
|
|
60
105
|
## Copyright
|
|
61
106
|
|
|
62
107
|
Copyright (C) 2013-present Dan Allen, Guillaume Grossetie, Anthonny Quérouil and the Asciidoctor Project.
|
package/bin/asciidoctor
CHANGED
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
'use strict'
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
const { Options, Invoker } = require('@asciidoctor/cli')
|
|
3
|
+
import { run } from '../lib/cli.js'
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
process.title = 'asciidoctor'
|
|
6
|
+
await run()
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
= AsciiDoc Syntax
|
|
2
|
+
:icons: font
|
|
3
|
+
:stem:
|
|
4
|
+
:toc: left
|
|
5
|
+
:url-docs: https://asciidoctor.org/docs
|
|
6
|
+
:url-gem: https://rubygems.org/gems/asciidoctor
|
|
7
|
+
|
|
8
|
+
A brief reference of the most commonly used AsciiDoc syntax.
|
|
9
|
+
You can find the full documentation for the AsciiDoc syntax at {url-docs}.
|
|
10
|
+
|
|
11
|
+
== Paragraphs
|
|
12
|
+
|
|
13
|
+
A normal paragraph.
|
|
14
|
+
Line breaks are not preserved.
|
|
15
|
+
// line comments, which are lines that start with //, are skipped
|
|
16
|
+
|
|
17
|
+
A blank line separates paragraphs.
|
|
18
|
+
|
|
19
|
+
[%hardbreaks]
|
|
20
|
+
This paragraph carries the `hardbreaks` option.
|
|
21
|
+
Notice how line breaks are now preserved.
|
|
22
|
+
|
|
23
|
+
An indented (literal) paragraph disables text formatting,
|
|
24
|
+
preserves spaces and line breaks, and is displayed in a
|
|
25
|
+
monospaced font.
|
|
26
|
+
|
|
27
|
+
[sidebar#id.role]
|
|
28
|
+
A style, ID, and/or role gives a paragraph (or block) special meaning, like this sidebar.
|
|
29
|
+
|
|
30
|
+
NOTE: An admonition paragraph, like this note, grabs the reader's attention.
|
|
31
|
+
|
|
32
|
+
TIP: Convert this document using the `asciidoctor` command to see the output produced from it.
|
|
33
|
+
|
|
34
|
+
== Text Formatting
|
|
35
|
+
:hardbreaks:
|
|
36
|
+
|
|
37
|
+
.Constrained (applied at word boundaries)
|
|
38
|
+
*strong importance* (aka bold)
|
|
39
|
+
_stress emphasis_ (aka italic)
|
|
40
|
+
`monospaced` (aka typewriter text)
|
|
41
|
+
"`double`" and '`single`' typographic quotes
|
|
42
|
+
+passthrough text+ (substitutions disabled)
|
|
43
|
+
`+literal text+` (monospaced with substitutions disabled)
|
|
44
|
+
|
|
45
|
+
.Unconstrained (applied anywhere)
|
|
46
|
+
**C**reate+**R**ead+**U**pdate+**D**elete
|
|
47
|
+
fan__freakin__tastic
|
|
48
|
+
``mono``culture
|
|
49
|
+
|
|
50
|
+
.Replacements
|
|
51
|
+
A long time ago in a galaxy far, far away...
|
|
52
|
+
(C) 1976 Arty Artisan
|
|
53
|
+
I believe I shall--no, actually I won't.
|
|
54
|
+
|
|
55
|
+
.Macros
|
|
56
|
+
// where c=specialchars, q=quotes, a=attributes, r=replacements, m=macros, p=post_replacements, etc.
|
|
57
|
+
The European icon:flag[role=blue] is blue & contains pass:[************] arranged in a icon:circle-o[role=yellow].
|
|
58
|
+
The pass:c[->] operator is often referred to as the stabby lambda.
|
|
59
|
+
Since `pass:[++]` has strong priority in AsciiDoc, you can rewrite pass:c,a,r[C++ => C{pp}].
|
|
60
|
+
// activate stem support by adding `:stem:` to the document header
|
|
61
|
+
stem:[sqrt(4) = 2]
|
|
62
|
+
|
|
63
|
+
:!hardbreaks:
|
|
64
|
+
== Attributes
|
|
65
|
+
|
|
66
|
+
// define attributes in the document header; must be flush with left margin
|
|
67
|
+
:name: value
|
|
68
|
+
|
|
69
|
+
You can download and install Asciidoctor {asciidoctor-version} from {url-gem}.
|
|
70
|
+
C{pp} is not required, only Ruby.
|
|
71
|
+
Use a leading backslash to output a word enclosed in curly braces, like \{name}.
|
|
72
|
+
|
|
73
|
+
== Links
|
|
74
|
+
|
|
75
|
+
[%hardbreaks]
|
|
76
|
+
https://example.org/page[A webpage]
|
|
77
|
+
link:../path/to/file.txt[A local file]
|
|
78
|
+
xref:document.adoc[A sibling document]
|
|
79
|
+
mailto:hello@example.org[Email to say hello!]
|
|
80
|
+
|
|
81
|
+
== Anchors
|
|
82
|
+
|
|
83
|
+
[[idname,reference text]]
|
|
84
|
+
// or written using normal block attributes as `[#idname,reftext=reference text]`
|
|
85
|
+
A paragraph (or any block) with an anchor (aka ID) and reftext.
|
|
86
|
+
|
|
87
|
+
See <<idname>> or <<idname,optional text of internal link>>.
|
|
88
|
+
|
|
89
|
+
xref:document.adoc#idname[Jumps to anchor in another document].
|
|
90
|
+
|
|
91
|
+
This paragraph has a footnote.footnote:[This is the text of the footnote.]
|
|
92
|
+
|
|
93
|
+
== Lists
|
|
94
|
+
|
|
95
|
+
=== Unordered
|
|
96
|
+
|
|
97
|
+
* level 1
|
|
98
|
+
** level 2
|
|
99
|
+
*** level 3
|
|
100
|
+
**** level 4
|
|
101
|
+
***** etc.
|
|
102
|
+
* back at level 1
|
|
103
|
+
+
|
|
104
|
+
Attach a block or paragraph to a list item using a list continuation (which you can enclose in an open block).
|
|
105
|
+
|
|
106
|
+
.Some Authors
|
|
107
|
+
[circle]
|
|
108
|
+
- Edgar Allen Poe
|
|
109
|
+
- Sheri S. Tepper
|
|
110
|
+
- Bill Bryson
|
|
111
|
+
|
|
112
|
+
=== Ordered
|
|
113
|
+
|
|
114
|
+
. Step 1
|
|
115
|
+
. Step 2
|
|
116
|
+
.. Step 2a
|
|
117
|
+
.. Step 2b
|
|
118
|
+
. Step 3
|
|
119
|
+
|
|
120
|
+
.Remember your Roman numerals?
|
|
121
|
+
[upperroman]
|
|
122
|
+
. is one
|
|
123
|
+
. is two
|
|
124
|
+
. is three
|
|
125
|
+
|
|
126
|
+
=== Checklist
|
|
127
|
+
|
|
128
|
+
* [x] checked
|
|
129
|
+
* [ ] not checked
|
|
130
|
+
|
|
131
|
+
=== Callout
|
|
132
|
+
|
|
133
|
+
// enable callout bubbles by adding `:icons: font` to the document header
|
|
134
|
+
[,ruby]
|
|
135
|
+
----
|
|
136
|
+
puts 'Hello, World!' # <1>
|
|
137
|
+
----
|
|
138
|
+
<1> Prints `Hello, World!` to the console.
|
|
139
|
+
|
|
140
|
+
=== Description
|
|
141
|
+
|
|
142
|
+
first term:: description of first term
|
|
143
|
+
second term::
|
|
144
|
+
description of second term
|
|
145
|
+
|
|
146
|
+
== Document Structure
|
|
147
|
+
|
|
148
|
+
=== Header
|
|
149
|
+
|
|
150
|
+
// header must be flush with left margin
|
|
151
|
+
= Document Title
|
|
152
|
+
Author Name <author@example.org>
|
|
153
|
+
v1.0, 2019-01-01
|
|
154
|
+
|
|
155
|
+
=== Sections
|
|
156
|
+
|
|
157
|
+
// must be flush with left margin
|
|
158
|
+
= Document Title (Level 0)
|
|
159
|
+
== Level 1
|
|
160
|
+
=== Level 2
|
|
161
|
+
==== Level 3
|
|
162
|
+
===== Level 4
|
|
163
|
+
====== Level 5
|
|
164
|
+
== Back at Level 1
|
|
165
|
+
|
|
166
|
+
=== Includes
|
|
167
|
+
|
|
168
|
+
// must be flush with left margin
|
|
169
|
+
include::basics.adoc[]
|
|
170
|
+
|
|
171
|
+
// define -a allow-uri-read to allow content to be read from URI
|
|
172
|
+
include::https://example.org/installation.adoc[]
|
|
173
|
+
|
|
174
|
+
== Blocks
|
|
175
|
+
|
|
176
|
+
--
|
|
177
|
+
open - a general-purpose content wrapper; useful for enclosing content to attach to a list item
|
|
178
|
+
--
|
|
179
|
+
|
|
180
|
+
// recognized types include CAUTION, IMPORTANT, NOTE, TIP, and WARNING
|
|
181
|
+
// enable admonition icons by setting `:icons: font` in the document header
|
|
182
|
+
[NOTE]
|
|
183
|
+
====
|
|
184
|
+
admonition - a notice for the reader, ranging in severity from a tip to an alert
|
|
185
|
+
====
|
|
186
|
+
|
|
187
|
+
====
|
|
188
|
+
example - a demonstration of the concept being documented
|
|
189
|
+
====
|
|
190
|
+
|
|
191
|
+
.Toggle Me
|
|
192
|
+
[%collapsible]
|
|
193
|
+
====
|
|
194
|
+
collapsible - these details are revealed by clicking the title
|
|
195
|
+
====
|
|
196
|
+
|
|
197
|
+
****
|
|
198
|
+
sidebar - auxiliary content that can be read independently of the main content
|
|
199
|
+
****
|
|
200
|
+
|
|
201
|
+
....
|
|
202
|
+
literal - an exhibit that features program output
|
|
203
|
+
....
|
|
204
|
+
|
|
205
|
+
----
|
|
206
|
+
listing - an exhibit that features program input, source code, or the contents of a file
|
|
207
|
+
----
|
|
208
|
+
|
|
209
|
+
[,language]
|
|
210
|
+
----
|
|
211
|
+
source - a listing that is embellished with (colorized) syntax highlighting
|
|
212
|
+
----
|
|
213
|
+
|
|
214
|
+
```language
|
|
215
|
+
fenced code - a shorthand syntax for the source block
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
[,attribution,citetitle]
|
|
219
|
+
____
|
|
220
|
+
quote - a quotation or excerpt; attribution with title of source are optional
|
|
221
|
+
____
|
|
222
|
+
|
|
223
|
+
[verse,attribution,citetitle]
|
|
224
|
+
____
|
|
225
|
+
verse - a literary excerpt, often a poem; attribution with title of source are optional
|
|
226
|
+
____
|
|
227
|
+
|
|
228
|
+
++++
|
|
229
|
+
pass - content passed directly to the output document; often raw HTML
|
|
230
|
+
++++
|
|
231
|
+
|
|
232
|
+
// activate stem support by adding `:stem:` to the document header
|
|
233
|
+
[stem]
|
|
234
|
+
++++
|
|
235
|
+
x = y^2
|
|
236
|
+
++++
|
|
237
|
+
|
|
238
|
+
////
|
|
239
|
+
comment - content which is not included in the output document
|
|
240
|
+
////
|
|
241
|
+
|
|
242
|
+
== Tables
|
|
243
|
+
|
|
244
|
+
.Table Attributes
|
|
245
|
+
[cols=>1h;2d,width=50%,frame=topbot]
|
|
246
|
+
|===
|
|
247
|
+
| Attribute Name | Values
|
|
248
|
+
|
|
249
|
+
| options
|
|
250
|
+
| header,footer,autowidth
|
|
251
|
+
|
|
252
|
+
| cols
|
|
253
|
+
| colspec[;colspec;...]
|
|
254
|
+
|
|
255
|
+
| grid
|
|
256
|
+
| all \| cols \| rows \| none
|
|
257
|
+
|
|
258
|
+
| frame
|
|
259
|
+
| all \| sides \| topbot \| none
|
|
260
|
+
|
|
261
|
+
| stripes
|
|
262
|
+
| all \| even \| odd \| none
|
|
263
|
+
|
|
264
|
+
| width
|
|
265
|
+
| (0%..100%)
|
|
266
|
+
|
|
267
|
+
| format
|
|
268
|
+
| psv {vbar} csv {vbar} dsv
|
|
269
|
+
|===
|
|
270
|
+
|
|
271
|
+
== Multimedia
|
|
272
|
+
|
|
273
|
+
image::screenshot.png[block image,800,450]
|
|
274
|
+
|
|
275
|
+
Press image:reload.svg[reload,16,opts=interactive] to reload the page.
|
|
276
|
+
|
|
277
|
+
video::movie.mp4[width=640,start=60,end=140,options=autoplay]
|
|
278
|
+
|
|
279
|
+
video::aHjpOzsQ9YI[youtube]
|
|
280
|
+
|
|
281
|
+
video::300817511[vimeo]
|
|
282
|
+
|
|
283
|
+
== Breaks
|
|
284
|
+
|
|
285
|
+
// thematic break (aka horizontal rule)
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
// page break
|
|
289
|
+
<<<
|
package/index.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
export { default } from '@asciidoctor/core'
|
|
2
|
+
export * from '@asciidoctor/core'
|
package/lib/cli.js
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util'
|
|
2
|
+
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { createRequire } from 'node:module'
|
|
4
|
+
import { join, resolve, isAbsolute, dirname, sep } from 'node:path'
|
|
5
|
+
import {
|
|
6
|
+
getVersion as _getVersion,
|
|
7
|
+
getCoreVersion,
|
|
8
|
+
Timings,
|
|
9
|
+
Extensions,
|
|
10
|
+
LoggerManager,
|
|
11
|
+
convert,
|
|
12
|
+
convertFile,
|
|
13
|
+
} from '@asciidoctor/core'
|
|
14
|
+
|
|
15
|
+
const require = createRequire(import.meta.url)
|
|
16
|
+
|
|
17
|
+
const FAILURE_LEVELS = {
|
|
18
|
+
DEBUG: 0,
|
|
19
|
+
INFO: 1,
|
|
20
|
+
WARN: 2,
|
|
21
|
+
WARNING: 2,
|
|
22
|
+
ERROR: 3,
|
|
23
|
+
FATAL: 4,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const DOT_RELATIVE_RX = new RegExp(`^\\.{1,2}[/${sep.replace('\\', '\\\\')}]`)
|
|
27
|
+
|
|
28
|
+
const HELP_TEXT = `asciidoctor [options...] files...
|
|
29
|
+
Translate the AsciiDoc source file or file(s) into the backend output format (e.g., HTML 5, DocBook 5, etc.)
|
|
30
|
+
By default, the output is written to a file with the basename of the source file and the appropriate extension
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
-b, --backend <backend> set output format backend
|
|
34
|
+
-d, --doctype <doctype> document type [article, book, manpage, inline]
|
|
35
|
+
-o, --out-file <file> output file; use '' or '-' for STDOUT
|
|
36
|
+
-S, --safe-mode <mode> safe mode level [unsafe, safe, server, secure]
|
|
37
|
+
-e, --embedded suppress enclosing document structure
|
|
38
|
+
-s, --no-header-footer suppress enclosing document structure
|
|
39
|
+
-n, --section-numbers auto-number section titles in the HTML backend
|
|
40
|
+
-B, --base-dir <dir> base directory containing the document and resources
|
|
41
|
+
-D, --destination-dir <dir> destination output directory
|
|
42
|
+
--failure-level <level> minimum logging level that triggers non-zero exit code [INFO, WARN, ERROR, FATAL]
|
|
43
|
+
-q, --quiet suppress warnings
|
|
44
|
+
--trace include backtrace information on errors
|
|
45
|
+
-v, --verbose enable verbose mode
|
|
46
|
+
-t, --timings enable timings mode
|
|
47
|
+
-T, --template-dir <dir> directory with custom converter templates (repeatable)
|
|
48
|
+
-E, --template-engine <engine> template engine to use for custom converter templates
|
|
49
|
+
-a, --attribute <key[=value]> document attribute to set (repeatable)
|
|
50
|
+
-r, --require <library> require the specified library before executing the processor (repeatable)
|
|
51
|
+
-V, --version display the version and runtime environment
|
|
52
|
+
--help [syntax] show this help; show AsciiDoc syntax overview if topic is 'syntax'`
|
|
53
|
+
|
|
54
|
+
function parseCliArgs(argv) {
|
|
55
|
+
const args = argv.slice(2)
|
|
56
|
+
const { values, positionals } = parseArgs({
|
|
57
|
+
args,
|
|
58
|
+
allowPositionals: true,
|
|
59
|
+
strict: false,
|
|
60
|
+
options: {
|
|
61
|
+
backend: { type: 'string', short: 'b' },
|
|
62
|
+
doctype: { type: 'string', short: 'd' },
|
|
63
|
+
'out-file': { type: 'string', short: 'o' },
|
|
64
|
+
'safe-mode': { type: 'string', short: 'S' },
|
|
65
|
+
embedded: { type: 'boolean', short: 'e' },
|
|
66
|
+
'no-header-footer': { type: 'boolean', short: 's' },
|
|
67
|
+
'section-numbers': { type: 'boolean', short: 'n' },
|
|
68
|
+
'base-dir': { type: 'string', short: 'B' },
|
|
69
|
+
'destination-dir': { type: 'string', short: 'D' },
|
|
70
|
+
'failure-level': { type: 'string' },
|
|
71
|
+
quiet: { type: 'boolean', short: 'q' },
|
|
72
|
+
trace: { type: 'boolean' },
|
|
73
|
+
verbose: { type: 'boolean', short: 'v' },
|
|
74
|
+
timings: { type: 'boolean', short: 't' },
|
|
75
|
+
'template-dir': { type: 'string', short: 'T', multiple: true },
|
|
76
|
+
'template-engine': { type: 'string', short: 'E' },
|
|
77
|
+
attribute: { type: 'string', short: 'a', multiple: true },
|
|
78
|
+
require: { type: 'string', short: 'r', multiple: true },
|
|
79
|
+
version: { type: 'boolean', short: 'V' },
|
|
80
|
+
help: { type: 'boolean' },
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
return { values, positionals, args }
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function buildOptions(values, extraAttrs = []) {
|
|
87
|
+
const {
|
|
88
|
+
backend,
|
|
89
|
+
doctype,
|
|
90
|
+
'safe-mode': safeMode,
|
|
91
|
+
embedded,
|
|
92
|
+
'no-header-footer': noHeaderFooter,
|
|
93
|
+
'section-numbers': sectionNumbers,
|
|
94
|
+
'base-dir': baseDir,
|
|
95
|
+
'destination-dir': destinationDir,
|
|
96
|
+
'out-file': outFile,
|
|
97
|
+
'template-dir': templateDir,
|
|
98
|
+
'template-engine': templateEngine,
|
|
99
|
+
quiet,
|
|
100
|
+
verbose,
|
|
101
|
+
timings,
|
|
102
|
+
trace,
|
|
103
|
+
'failure-level': failureLevelStr = 'FATAL',
|
|
104
|
+
attribute: cliAttributes,
|
|
105
|
+
} = values
|
|
106
|
+
|
|
107
|
+
const level = failureLevelStr.toUpperCase()
|
|
108
|
+
const failureLevel = FAILURE_LEVELS[level] ?? FAILURE_LEVELS.FATAL
|
|
109
|
+
|
|
110
|
+
const attributes = [...extraAttrs]
|
|
111
|
+
if (sectionNumbers) attributes.push('sectnums')
|
|
112
|
+
if (cliAttributes) attributes.push(...cliAttributes)
|
|
113
|
+
|
|
114
|
+
const standalone = !(embedded || noHeaderFooter)
|
|
115
|
+
const verboseMode = quiet ? 0 : verbose ? 2 : 1
|
|
116
|
+
|
|
117
|
+
const options = {
|
|
118
|
+
standalone,
|
|
119
|
+
safe: safeMode ?? 'unsafe',
|
|
120
|
+
verbose: verboseMode,
|
|
121
|
+
timings: timings ?? false,
|
|
122
|
+
trace: trace ?? false,
|
|
123
|
+
attributes,
|
|
124
|
+
mkdirs: true,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (backend) options.backend = backend
|
|
128
|
+
if (doctype) options.doctype = doctype
|
|
129
|
+
if (baseDir != null) options.base_dir = baseDir
|
|
130
|
+
if (destinationDir != null) options.to_dir = destinationDir
|
|
131
|
+
if (templateDir) options.template_dirs = templateDir
|
|
132
|
+
if (templateEngine) options.template_engine = templateEngine
|
|
133
|
+
|
|
134
|
+
const toStdout = outFile === '' || outFile === "''" || outFile === '-'
|
|
135
|
+
if (toStdout) {
|
|
136
|
+
options.to_file = false
|
|
137
|
+
} else if (outFile !== undefined) {
|
|
138
|
+
options.to_file = outFile
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return { options, failureLevel, toStdout }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function requireLibrary(requirePath, cwd = process.cwd()) {
|
|
145
|
+
if (DOT_RELATIVE_RX.test(requirePath)) {
|
|
146
|
+
requirePath = resolve(cwd, requirePath)
|
|
147
|
+
} else if (!isAbsolute(requirePath)) {
|
|
148
|
+
const paths = [cwd, dirname(import.meta.dirname)].map((s) =>
|
|
149
|
+
join(s, 'node_modules')
|
|
150
|
+
)
|
|
151
|
+
requirePath = require.resolve(requirePath, { paths })
|
|
152
|
+
}
|
|
153
|
+
return require(requirePath)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
function prepareProcessor(values) {
|
|
157
|
+
const requirePaths = values.require
|
|
158
|
+
if (!requirePaths) return
|
|
159
|
+
for (const requirePath of requirePaths) {
|
|
160
|
+
const lib = requireLibrary(requirePath)
|
|
161
|
+
if (lib && typeof lib.register === 'function') {
|
|
162
|
+
lib.register(Extensions)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function getVersion() {
|
|
168
|
+
const pkg = JSON.parse(
|
|
169
|
+
readFileSync(join(import.meta.dirname, '..', 'package.json'), 'utf8')
|
|
170
|
+
)
|
|
171
|
+
return `Asciidoctor.js ${_getVersion()} (Asciidoctor ${getCoreVersion()}) [https://asciidoctor.org]
|
|
172
|
+
Runtime Environment (node ${process.version} on ${process.platform})
|
|
173
|
+
CLI version ${pkg.version}`
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function readFromStdin() {
|
|
177
|
+
return new Promise((resolve, reject) => {
|
|
178
|
+
let data = ''
|
|
179
|
+
process.stdin.setEncoding('utf8')
|
|
180
|
+
process.stdin.on('readable', () => {
|
|
181
|
+
const chunk = process.stdin.read()
|
|
182
|
+
if (chunk !== null) data += chunk
|
|
183
|
+
})
|
|
184
|
+
process.stdin.on('error', reject)
|
|
185
|
+
process.stdin.on('end', () => resolve(data.replace(/\n$/, '')))
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function exit(failureLevel) {
|
|
190
|
+
const logger = LoggerManager.getLogger()
|
|
191
|
+
const maxSeverity = logger.getMaxSeverity()
|
|
192
|
+
const code = maxSeverity !== null && maxSeverity >= failureLevel ? 1 : 0
|
|
193
|
+
process.exit(code)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export async function run(argv = process.argv) {
|
|
197
|
+
const { values, positionals, args } = parseCliArgs(argv)
|
|
198
|
+
|
|
199
|
+
if (values.version || (values.verbose && args.length === 1)) {
|
|
200
|
+
console.log(getVersion())
|
|
201
|
+
process.exit(0)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (values.help) {
|
|
205
|
+
if (positionals[0] === 'syntax') {
|
|
206
|
+
console.log(
|
|
207
|
+
readFileSync(
|
|
208
|
+
join(import.meta.dirname, '..', 'data', 'reference', 'syntax.adoc'),
|
|
209
|
+
'utf8'
|
|
210
|
+
)
|
|
211
|
+
)
|
|
212
|
+
} else {
|
|
213
|
+
console.error(HELP_TEXT)
|
|
214
|
+
}
|
|
215
|
+
process.exit(0)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
prepareProcessor(values)
|
|
219
|
+
const { options, failureLevel, toStdout } = buildOptions(values)
|
|
220
|
+
|
|
221
|
+
// Configure logger verbosity
|
|
222
|
+
const logger = LoggerManager.getLogger()
|
|
223
|
+
if (values.quiet)
|
|
224
|
+
logger.setLevel(3) // ERROR
|
|
225
|
+
else if (values.verbose) logger.setLevel(0) // DEBUG
|
|
226
|
+
|
|
227
|
+
const files = positionals.filter((f) => f !== '-')
|
|
228
|
+
const isStdin =
|
|
229
|
+
positionals.includes('-') ||
|
|
230
|
+
(files.length === 0 && args[args.length - 1] === '-')
|
|
231
|
+
|
|
232
|
+
if (isStdin) {
|
|
233
|
+
const data = await readFromStdin()
|
|
234
|
+
const output = await convert(data, { ...options, to_file: false })
|
|
235
|
+
process.stdout.write(output)
|
|
236
|
+
} else if (files.length > 0) {
|
|
237
|
+
for (const file of files) {
|
|
238
|
+
if (values.verbose) console.log(`converting file ${file}`)
|
|
239
|
+
if (values.timings) {
|
|
240
|
+
const timings = Timings.create()
|
|
241
|
+
const fileOptions = { ...options, timings }
|
|
242
|
+
if (toStdout) fileOptions.to_file = false
|
|
243
|
+
const result = await convertFile(file, fileOptions)
|
|
244
|
+
if (toStdout && typeof result === 'string') process.stdout.write(result)
|
|
245
|
+
timings.printReport(process.stderr, file)
|
|
246
|
+
} else {
|
|
247
|
+
const result = await convertFile(file, options)
|
|
248
|
+
if (toStdout && typeof result === 'string') process.stdout.write(result)
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
} else {
|
|
252
|
+
console.error(HELP_TEXT)
|
|
253
|
+
process.exit(0)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
await exit(failureLevel)
|
|
257
|
+
}
|