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.
Files changed (48) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +60 -15
  3. package/bin/asciidoctor +3 -6
  4. package/data/reference/syntax.adoc +289 -0
  5. package/index.js +2 -1
  6. package/lib/cli.js +257 -0
  7. package/package.json +29 -16
  8. package/types/README.adoc +3 -0
  9. package/types/abstract_block.d.ts +343 -0
  10. package/types/abstract_node.d.ts +471 -0
  11. package/types/attribute_entry.d.ts +7 -0
  12. package/types/attribute_list.d.ts +52 -0
  13. package/types/block.d.ts +55 -0
  14. package/types/browser/asset.d.ts +7 -0
  15. package/types/browser/reader.d.ts +29 -0
  16. package/types/callouts.d.ts +36 -0
  17. package/types/compliance.d.ts +23 -0
  18. package/types/constants.d.ts +268 -0
  19. package/types/convert.d.ts +34 -0
  20. package/types/converter/composite.d.ts +20 -0
  21. package/types/converter/docbook5.d.ts +41 -0
  22. package/types/converter/html5.d.ts +51 -0
  23. package/types/converter/manpage.d.ts +59 -0
  24. package/types/converter/template.d.ts +83 -0
  25. package/types/converter.d.ts +150 -0
  26. package/types/data/stylesheet-data.d.ts +2 -0
  27. package/types/document.d.ts +495 -0
  28. package/types/extensions.d.ts +876 -0
  29. package/types/footnote.d.ts +18 -0
  30. package/types/helpers.d.ts +146 -0
  31. package/types/index.d.ts +73 -3731
  32. package/types/inline.d.ts +69 -0
  33. package/types/list.d.ts +114 -0
  34. package/types/load.d.ts +39 -0
  35. package/types/logging.d.ts +187 -0
  36. package/types/parser.d.ts +114 -0
  37. package/types/path_resolver.d.ts +103 -0
  38. package/types/reader.d.ts +184 -0
  39. package/types/rx.d.ts +513 -0
  40. package/types/section.d.ts +122 -0
  41. package/types/stylesheets.d.ts +10 -0
  42. package/types/substitutors.d.ts +208 -0
  43. package/types/syntaxHighlighter/highlightjs.d.ts +33 -0
  44. package/types/syntaxHighlighter/html_pipeline.d.ts +16 -0
  45. package/types/syntax_highlighter.d.ts +167 -0
  46. package/types/table.d.ts +231 -0
  47. package/types/timings.d.ts +25 -0
  48. 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
- Asciidoctor.js brings AsciiDoc to the JavaScript world!
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
- This project uses [Opal](https://opalrb.com/) to transpile [Asciidoctor](http://asciidoctor.org), a modern implementation of AsciiDoc, from Ruby to JavaScript to produce _asciidoctor.js_.
6
- The _asciidoctor.js_ script can be run on any JavaScript platform, including Node.js, GraalVM and, of course, a web browser.
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
- Here is a simple example that converts AsciiDoc to HTML5:
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 Asciidoctor = asciidoctor() //
24
- const content = 'http://asciidoctor.org[*Asciidoctor*] ' +
25
- 'running on https://opalrb.com[_Opal_] ' +
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. Instantiate the Asciidoctor.js library
31
- 2. Convert AsciiDoc content to HTML5 using Asciidoctor.js
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="http://asciidoctor.org"><strong>Asciidoctor</strong></a> running on <a href="http://opalrb.com"><em>Opal</em></a> brings AsciiDoc to Node.js!</p>
44
+ <p><a href="https://asciidoctor.org"><strong>Asciidoctor</strong></a> running on Node.js!</p>
45
45
  </div>
46
46
  ```
47
47
 
48
- If you want to know more about Asciidoctor.js, please read the [User Manual](https://docs.asciidoctor.org/asciidoctor.js/latest/).
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
- process.title = 'asciidoctor'
6
- const { Options, Invoker } = require('@asciidoctor/cli')
3
+ import { run } from '../lib/cli.js'
7
4
 
8
- const options = new Options().parse(process.argv)
9
- new Invoker(options).invoke()
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
- module.exports = require('@asciidoctor/core')
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
+ }