@asciidoctor/core 3.0.4 → 4.0.0-alpha.2

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 (92) hide show
  1. package/README.md +42 -10
  2. package/build/browser/index.js +24156 -0
  3. package/build/node/index.cjs +24737 -0
  4. package/{dist/css/asciidoctor.css → data/asciidoctor-default.css} +54 -53
  5. package/package.json +55 -97
  6. package/src/abstract_block.js +857 -0
  7. package/src/abstract_node.js +954 -0
  8. package/src/attribute_entry.js +12 -0
  9. package/src/attribute_list.js +380 -0
  10. package/src/block.js +168 -0
  11. package/src/browser/asset.js +22 -0
  12. package/src/browser/reader.js +138 -0
  13. package/src/browser.js +121 -0
  14. package/src/callouts.js +85 -0
  15. package/src/compliance.js +54 -0
  16. package/src/constants.js +665 -0
  17. package/src/convert.js +370 -0
  18. package/src/converter/composite.js +83 -0
  19. package/src/converter/docbook5.js +1031 -0
  20. package/src/converter/html5.js +1893 -0
  21. package/src/converter/manpage.js +935 -0
  22. package/src/converter/template.js +459 -0
  23. package/src/converter.js +478 -0
  24. package/src/data/stylesheet-data.js +2 -0
  25. package/src/document.js +2134 -0
  26. package/src/extensions.js +1952 -0
  27. package/src/footnote.js +28 -0
  28. package/src/helpers.js +355 -0
  29. package/src/index.js +138 -0
  30. package/src/inline.js +158 -0
  31. package/src/list.js +240 -0
  32. package/src/load.js +276 -0
  33. package/src/logging.js +526 -0
  34. package/src/parser.js +3661 -0
  35. package/src/path_resolver.js +472 -0
  36. package/src/reader.js +1755 -0
  37. package/src/rx.js +829 -0
  38. package/src/section.js +354 -0
  39. package/src/stylesheets.js +30 -0
  40. package/src/substitutors.js +2241 -0
  41. package/src/syntaxHighlighter/highlightjs.js +90 -0
  42. package/src/syntaxHighlighter/html_pipeline.js +33 -0
  43. package/src/syntax_highlighter.js +304 -0
  44. package/src/table.js +952 -0
  45. package/src/timings.js +78 -0
  46. package/types/abstract_block.d.ts +346 -0
  47. package/types/abstract_node.d.ts +471 -0
  48. package/types/attribute_entry.d.ts +7 -0
  49. package/types/attribute_list.d.ts +52 -0
  50. package/types/block.d.ts +55 -0
  51. package/types/browser/asset.d.ts +7 -0
  52. package/types/browser/reader.d.ts +29 -0
  53. package/types/callouts.d.ts +36 -0
  54. package/types/compliance.d.ts +23 -0
  55. package/types/constants.d.ts +268 -0
  56. package/types/convert.d.ts +34 -0
  57. package/types/converter/composite.d.ts +20 -0
  58. package/types/converter/docbook5.d.ts +41 -0
  59. package/types/converter/html5.d.ts +51 -0
  60. package/types/converter/manpage.d.ts +59 -0
  61. package/types/converter/template.d.ts +83 -0
  62. package/types/converter.d.ts +150 -0
  63. package/types/data/stylesheet-data.d.ts +2 -0
  64. package/types/document.d.ts +495 -0
  65. package/types/extensions.d.ts +876 -0
  66. package/types/footnote.d.ts +18 -0
  67. package/types/helpers.d.ts +146 -0
  68. package/types/index.d.cts +75 -0
  69. package/types/index.d.ts +73 -3731
  70. package/types/inline.d.ts +69 -0
  71. package/types/list.d.ts +114 -0
  72. package/types/load.d.ts +39 -0
  73. package/types/logging.d.ts +187 -0
  74. package/types/parser.d.ts +114 -0
  75. package/types/path_resolver.d.ts +103 -0
  76. package/types/reader.d.ts +184 -0
  77. package/types/rx.d.ts +513 -0
  78. package/types/section.d.ts +122 -0
  79. package/types/stylesheets.d.ts +10 -0
  80. package/types/substitutors.d.ts +208 -0
  81. package/types/syntaxHighlighter/highlightjs.d.ts +33 -0
  82. package/types/syntaxHighlighter/html_pipeline.d.ts +16 -0
  83. package/types/syntax_highlighter.d.ts +167 -0
  84. package/types/table.d.ts +231 -0
  85. package/types/timings.d.ts +25 -0
  86. package/types/tsconfig.json +9 -0
  87. package/LICENSE +0 -21
  88. package/dist/browser/asciidoctor.js +0 -47654
  89. package/dist/browser/asciidoctor.min.js +0 -1452
  90. package/dist/graalvm/asciidoctor.js +0 -47402
  91. package/dist/node/asciidoctor.cjs +0 -21567
  92. package/dist/node/asciidoctor.js +0 -23037
@@ -0,0 +1,28 @@
1
+ export class Footnote {
2
+ constructor(index, id, text) {
3
+ this.index = index
4
+ this.id = id ?? null
5
+ this.text = text
6
+ }
7
+
8
+ /**
9
+ * @returns {number} the index of this footnote.
10
+ */
11
+ getIndex() {
12
+ return this.index
13
+ }
14
+
15
+ /**
16
+ * @returns {string|null} the id of this footnote, or null if not set.
17
+ */
18
+ getId() {
19
+ return this.id
20
+ }
21
+
22
+ /**
23
+ * @returns {string} the text of this footnote.
24
+ */
25
+ getText() {
26
+ return this.text
27
+ }
28
+ }
package/src/helpers.js ADDED
@@ -0,0 +1,355 @@
1
+ // ESM conversion of helpers.rb
2
+ // Internal helper functions used by the Asciidoctor parser.
3
+ //
4
+ // Ruby-to-JavaScript notes:
5
+ // - require_library / require_open_uri have no JS equivalent and are omitted.
6
+ // - resolve_class / class_for_name are Ruby-specific and are omitted.
7
+ // - BOM detection uses the Unicode BOM codepoint U+FEFF instead of raw bytes,
8
+ // since JS strings are always UTF-16 and never carry an encoding tag.
9
+ // - File.basename / File.extname are reimplemented without the Node `path` module
10
+ // so this module works in browser (Opal) and Node environments alike.
11
+ // - mkdir_p delegates to Node's fs.mkdirSync with { recursive: true }.
12
+ // - String#succ (nextval) is implemented for the ASCII alphanumeric subset
13
+ // used by Asciidoctor list-numbering sequences.
14
+
15
+ import { UriSniffRx } from './rx.js'
16
+
17
+ // ── BOM ──────────────────────────────────────────────────────────────────────
18
+ // Unicode byte-order mark (U+FEFF). In a JS string (already decoded to UTF-16)
19
+ // this is the single character that corresponds to all three BOM byte patterns:
20
+ // UTF-8 BOM 0xEF 0xBB 0xBF → U+FEFF
21
+ // UTF-16 LE 0xFF 0xFE → U+FEFF
22
+ // UTF-16 BE 0xFE 0xFF → U+FEFF
23
+ const BOM = ''
24
+
25
+ /** Trim trailing ASCII whitespace only (not Unicode line separators U+2028/U+2029). */
26
+ const rstrip = (line) => line.replace(/[ \t\r\n\f\v]+$/, '')
27
+
28
+ /**
29
+ * Prepare the source data Array for parsing.
30
+ *
31
+ * Strips a leading BOM from the first element if present, then trims trailing
32
+ * whitespace (trimEnd = true) or only the trailing newline (trimEnd = false)
33
+ * from every line.
34
+ *
35
+ * @param {string[]} data - the source data Array to prepare (no null/undefined entries allowed)
36
+ * @param {boolean} [trimEnd=true] - whether to strip all trailing whitespace (true) or only \n (false)
37
+ * @returns {string[]} Array of prepared lines
38
+ */
39
+ export function prepareSourceArray(data, trimEnd = true) {
40
+ if (!data.length) return []
41
+ if (data[0].startsWith(BOM)) data[0] = data[0].slice(1)
42
+ // Strip trailing \r to normalize Windows CRLF line endings (lines were split on \n, leaving \r).
43
+ return trimEnd
44
+ ? data.map(rstrip)
45
+ : data.map((line) => line.replace(/\r?\n$/, '').replace(/\r$/, ''))
46
+ }
47
+
48
+ /**
49
+ * Prepare the source data String for parsing.
50
+ *
51
+ * Strips a leading BOM if present, splits into an array, and trims trailing
52
+ * whitespace (trimEnd = true) or only the trailing newline (trimEnd = false)
53
+ * from every line.
54
+ *
55
+ * @param {string} data - the source data String to prepare
56
+ * @param {boolean} [trimEnd=true] - whether to strip all trailing whitespace (true) or only \n (false)
57
+ * @returns {string[]} Array of prepared lines
58
+ */
59
+ export function prepareSourceString(data, trimEnd = true) {
60
+ if (!data) return []
61
+ if (data.startsWith(BOM)) data = data.slice(1)
62
+ // Normalize Windows CRLF to LF so that split('\n') does not leave trailing \r on each line.
63
+ if (data.includes('\r'))
64
+ data = data.replace(/\r\n/g, '\n').replace(/\r/g, '\n')
65
+ // Ruby's each_line does not produce an empty trailing element when the string
66
+ // ends with \n, but JS split('\n') does. Remove the trailing empty element
67
+ // to match Ruby behaviour.
68
+ if (data.endsWith('\n')) data = data.slice(0, -1)
69
+ const lines = data.split('\n')
70
+ return trimEnd ? lines.map(rstrip) : lines
71
+ }
72
+
73
+ /**
74
+ * Efficiently check whether the specified String resembles a URI.
75
+ *
76
+ * Uses UriSniffRx to check whether the String begins with a URI prefix (e.g.
77
+ * http://). No validation of the URI is performed.
78
+ *
79
+ * @param {string} str - the String to check
80
+ * @returns {boolean} true if the String resembles a URI, false otherwise
81
+ */
82
+ export function isUriish(str) {
83
+ return str.includes(':') && UriSniffRx.test(str)
84
+ }
85
+
86
+ /**
87
+ * Encode a URI component String for safe inclusion in a URI.
88
+ *
89
+ * Encodes all characters that are not unreserved per RFC-3986. Specifically,
90
+ * encodeURIComponent leaves !, ', (, ), and * unencoded; this function encodes
91
+ * those as well so the result matches CGI.escapeURIComponent (Ruby ≥ 3.2) /
92
+ * CGI.escape + gsub('+', '%20').
93
+ *
94
+ * @param {string} str - the URI component String to encode
95
+ * @returns {string} the encoded String
96
+ */
97
+ export function encodeUriComponent(str) {
98
+ return encodeURIComponent(str).replace(
99
+ /[!'()*]/g,
100
+ (m) => `%${m.charCodeAt(0).toString(16)}`
101
+ )
102
+ }
103
+
104
+ /**
105
+ * Replace spaces with %20 in a URI path.
106
+ *
107
+ * @param {string} str - the String to encode
108
+ * @returns {string} the String with all spaces replaced with %20
109
+ */
110
+ export function encodeSpacesInUri(str) {
111
+ return str.includes(' ') ? str.replaceAll(' ', '%20') : str
112
+ }
113
+
114
+ /**
115
+ * Remove the file extension from a filename and return the result.
116
+ *
117
+ * The filename is expected to be a POSIX path. The extension is only stripped
118
+ * when no path separator follows the last dot, so paths like
119
+ * "dir.with.dots/file" are returned unchanged.
120
+ *
121
+ * @param {string} filename - the String file name to process
122
+ * @returns {string} the String filename with the file extension removed
123
+ *
124
+ * @example
125
+ * rootname('part1/chapter1.adoc')
126
+ * // => "part1/chapter1"
127
+ */
128
+ export function rootname(filename) {
129
+ const lastDotIdx = filename.lastIndexOf('.')
130
+ if (lastDotIdx < 0) return filename
131
+ return filename.indexOf('/', lastDotIdx) >= 0
132
+ ? filename
133
+ : filename.slice(0, lastDotIdx)
134
+ }
135
+
136
+ /**
137
+ * Retrieve the basename of a filename, optionally removing the extension.
138
+ *
139
+ * @param {string} filename - the String file name to process
140
+ * @param {boolean|string|null} [dropExt=null] - a Boolean flag or an explicit String extension to drop
141
+ * @returns {string} the String filename with leading directories removed and, optionally, the extension removed
142
+ *
143
+ * @example
144
+ * basename('images/tiger.png', true)
145
+ * // => "tiger"
146
+ *
147
+ * basename('images/tiger.png', '.png')
148
+ * // => "tiger"
149
+ */
150
+ export function basename(filename, dropExt = null) {
151
+ // Split on both POSIX and Windows separators, take the last non-empty segment.
152
+ const base =
153
+ filename
154
+ .replace(/[/\\]+$/, '')
155
+ .split(/[/\\]/)
156
+ .pop() ?? filename
157
+ if (!dropExt) return base
158
+ const ext = dropExt === true ? extname(base) : dropExt
159
+ return ext && base.endsWith(ext) ? base.slice(0, -ext.length) : base
160
+ }
161
+
162
+ /**
163
+ * Return whether this path has a file extension.
164
+ *
165
+ * @param {string} path - the path String to check (expects a POSIX path)
166
+ * @returns {boolean} true if the path has a file extension, false otherwise
167
+ */
168
+ export function isExtname(path) {
169
+ const lastDotIdx = path.lastIndexOf('.')
170
+ return lastDotIdx >= 0 && path.indexOf('/', lastDotIdx) < 0
171
+ }
172
+
173
+ /**
174
+ * Retrieve the file extension of the specified path.
175
+ *
176
+ * The file extension is the portion of the last path segment starting from
177
+ * the last period. Differs from Node's path.extname in that the fallback value
178
+ * is configurable.
179
+ *
180
+ * @param {string} path - the path String in which to look for a file extension
181
+ * @param {string} [fallback=''] - the fallback String to return if no file extension is present
182
+ * @returns {string} the String file extension (with the leading dot) or fallback
183
+ */
184
+ export function extname(path, fallback = '') {
185
+ const lastDotIdx = path.lastIndexOf('.')
186
+ if (lastDotIdx < 0) return fallback
187
+ // treat both '/' and '\\' as path separators (Windows support)
188
+ if (path.indexOf('/', lastDotIdx) >= 0 || path.indexOf('\\', lastDotIdx) >= 0)
189
+ return fallback
190
+ return path.slice(lastDotIdx)
191
+ }
192
+
193
+ /**
194
+ * Async-aware string replacement using matchAll.
195
+ *
196
+ * The replacer may return a string or a Promise<string>.
197
+ * The regex is treated as global regardless of its flags.
198
+ *
199
+ * @param {string} str - the String to perform replacements on
200
+ * @param {RegExp} regex - the RegExp pattern to match
201
+ * @param {Function} replacer - an async function receiving the same arguments as String#replace callbacks
202
+ * @returns {Promise<string>} the String with all matches replaced
203
+ */
204
+ export async function asyncReplace(str, regex, replacer) {
205
+ const gRegex = regex.flags.includes('g')
206
+ ? regex
207
+ : new RegExp(regex.source, `${regex.flags}g`)
208
+ const matches = [...str.matchAll(gRegex)]
209
+ if (matches.length === 0) return str
210
+ const parts = []
211
+ let lastIndex = 0
212
+ for (const match of matches) {
213
+ parts.push(str.slice(lastIndex, match.index))
214
+ // Process replacements sequentially so state mutations (e.g. footnote registration)
215
+ // are visible to subsequent replacements in the same string.
216
+ parts.push(await replacer(...match, match.index, str))
217
+ lastIndex = match.index + match[0].length
218
+ }
219
+ parts.push(str.slice(lastIndex))
220
+ return parts.join('')
221
+ }
222
+
223
+ /**
224
+ * Make a directory, creating all missing parent directories.
225
+ *
226
+ * @param {string} dir - the String path of the directory to create
227
+ * @returns {Promise<void>} Throws if the path cannot be created
228
+ */
229
+ export async function mkdirP(dir) {
230
+ const { mkdir } = await import('node:fs/promises')
231
+ await mkdir(dir, { recursive: true })
232
+ }
233
+
234
+ // ── Roman numeral helpers ─────────────────────────────────────────────────────
235
+
236
+ const ROMAN_NUMERALS_WITH_REDUCERS = [
237
+ ['M', 1000],
238
+ ['CM', 900],
239
+ ['D', 500],
240
+ ['CD', 400],
241
+ ['C', 100],
242
+ ['XC', 90],
243
+ ['L', 50],
244
+ ['XL', 40],
245
+ ['X', 10],
246
+ ['IX', 9],
247
+ ['V', 5],
248
+ ['IV', 4],
249
+ ['I', 1],
250
+ ]
251
+
252
+ const ROMAN_NUMERALS = { I: 1, V: 5, X: 10, L: 50, C: 100, D: 500, M: 1000 }
253
+
254
+ /**
255
+ * Convert an integer to a Roman numeral.
256
+ *
257
+ * @param {number} val - the integer value to convert
258
+ * @returns {string} the String Roman numeral
259
+ */
260
+ export function intToRoman(val) {
261
+ let result = ''
262
+ for (const [l, i] of ROMAN_NUMERALS_WITH_REDUCERS) {
263
+ const repeat = Math.floor(val / i)
264
+ val %= i
265
+ result += l.repeat(repeat)
266
+ }
267
+ return result
268
+ }
269
+
270
+ /**
271
+ * Convert an uppercase Roman numeral to an integer.
272
+ *
273
+ * @param {string} val - the String Roman numeral in uppercase to convert
274
+ * @returns {number} the integer value
275
+ */
276
+ export function romanToInt(val) {
277
+ const valmap = [...val].map((c) => ROMAN_NUMERALS[c])
278
+ let result = 0
279
+ for (let idx = 0; idx < valmap.length; idx++) {
280
+ const v = valmap[idx]
281
+ const succ = valmap[idx + 1]
282
+ result += succ && succ > v ? -v : v
283
+ }
284
+ return result
285
+ }
286
+
287
+ /**
288
+ * Get the next value in a sequence.
289
+ *
290
+ * Handles integer sequences (numeric increment) and alphabetic sequences
291
+ * (ASCII letter increment with carry, matching Ruby's String#succ for the
292
+ * alphanumeric subset used by Asciidoctor list labels).
293
+ *
294
+ * @param {string|number} current - the value to increment
295
+ * @returns {string|number} the next value in the sequence
296
+ */
297
+ export function nextval(current) {
298
+ if (typeof current === 'number') return current + 1
299
+ const intval = parseInt(current, 10)
300
+ if (String(intval) === String(current)) return intval + 1
301
+ // Mirrors Ruby's String#succ for single- and multi-character strings.
302
+ // Strategy: find the rightmost ASCII-alphanumeric character and increment it
303
+ // with carry. If NO alphanumeric character exists, increment the rightmost
304
+ // character's Unicode code point instead.
305
+ const chars = [...current] // split by Unicode code point (handles surrogate pairs)
306
+ let hasAlnum = false
307
+ for (let i = chars.length - 1; i >= 0; i--) {
308
+ const code = chars[i].codePointAt(0)
309
+ const isLower = code >= 97 && code <= 122
310
+ const isUpper = code >= 65 && code <= 90
311
+ const isDigit = code >= 48 && code <= 57
312
+ if (!isLower && !isUpper && !isDigit) continue
313
+ hasAlnum = true
314
+ const atEnd =
315
+ (isLower && code === 122) ||
316
+ (isUpper && code === 90) ||
317
+ (isDigit && code === 57)
318
+ if (!atEnd) {
319
+ chars[i] = String.fromCodePoint(code + 1)
320
+ return chars.join('')
321
+ }
322
+ // Carry: wrap this char and continue to the next alphanumeric to the left.
323
+ chars[i] = isLower ? 'a' : isUpper ? 'A' : '0'
324
+ // Find next alphanumeric to carry into.
325
+ let carried = false
326
+ for (let j = i - 1; j >= 0; j--) {
327
+ const c2 = chars[j].codePointAt(0)
328
+ const l2 = c2 >= 97 && c2 <= 122
329
+ const u2 = c2 >= 65 && c2 <= 90
330
+ const d2 = c2 >= 48 && c2 <= 57
331
+ if (!l2 && !u2 && !d2) continue
332
+ const end2 = (l2 && c2 === 122) || (u2 && c2 === 90) || (d2 && c2 === 57)
333
+ if (!end2) {
334
+ chars[j] = String.fromCodePoint(c2 + 1)
335
+ carried = true
336
+ break
337
+ }
338
+ chars[j] = l2 ? 'a' : u2 ? 'A' : '0'
339
+ }
340
+ if (!carried) {
341
+ // All alphanumeric characters wrapped — prepend carry character.
342
+ const carry = isLower ? 'a' : isUpper ? 'A' : '1'
343
+ return carry + chars.join('')
344
+ }
345
+ return chars.join('')
346
+ }
347
+ if (!hasAlnum) {
348
+ // No alphanumeric chars: increment the rightmost character's code point.
349
+ const last = chars.length - 1
350
+ const code = chars[last].codePointAt(0)
351
+ chars[last] = String.fromCodePoint(code + 1)
352
+ return chars.join('')
353
+ }
354
+ return current
355
+ }
package/src/index.js ADDED
@@ -0,0 +1,138 @@
1
+ import packageJson from '../package.json' with { type: 'json' }
2
+ import { load as _load, loadFile as _loadFile } from './load.js'
3
+ import { convert, convertFile } from './convert.js'
4
+ import {
5
+ Document,
6
+ DocumentTitle,
7
+ Author,
8
+ Footnote,
9
+ ImageReference,
10
+ RevisionInfo,
11
+ } from './document.js'
12
+ import { Logger, LoggerManager, MemoryLogger, NullLogger } from './logging.js'
13
+ import { SafeMode, ContentModel } from './constants.js'
14
+ import { Timings } from './timings.js'
15
+ import { AbstractNode } from './abstract_node.js'
16
+ import { AbstractBlock } from './abstract_block.js'
17
+ import {
18
+ Registry,
19
+ Processor,
20
+ ProcessorExtension,
21
+ Preprocessor,
22
+ TreeProcessor,
23
+ Postprocessor,
24
+ IncludeProcessor,
25
+ DocinfoProcessor,
26
+ BlockProcessor,
27
+ InlineMacroProcessor,
28
+ BlockMacroProcessor,
29
+ Extensions,
30
+ } from './extensions.js'
31
+ import {
32
+ Converter,
33
+ ConverterBase,
34
+ CustomFactory,
35
+ DefaultFactory as DefaultConverterFactory,
36
+ deriveBackendTraits,
37
+ } from './converter.js'
38
+ import { Inline } from './inline.js'
39
+ import { Block } from './block.js'
40
+ import { List, ListItem } from './list.js'
41
+ import { Section } from './section.js'
42
+ import { Cursor, Reader } from './reader.js'
43
+ import Html5Converter from './converter/html5.js'
44
+ import {
45
+ SyntaxHighlighter,
46
+ SyntaxHighlighterBase,
47
+ DefaultFactory as DefaultSyntaxHighlighterFactory,
48
+ } from './syntax_highlighter.js'
49
+
50
+ const ASCIIDOCTOR_CORE_VERSION = '2.0.26'
51
+
52
+ /**
53
+ * Get the version of Asciidoctor.js.
54
+ *
55
+ * @returns {string} - the version of Asciidoctor.js
56
+ */
57
+ export function getVersion() {
58
+ return packageJson.version
59
+ }
60
+
61
+ /**
62
+ * Get Asciidoctor core version number.
63
+ *
64
+ * @returns {string} - the version of Asciidoctor core (Ruby)
65
+ */
66
+ export function getCoreVersion() {
67
+ return ASCIIDOCTOR_CORE_VERSION
68
+ }
69
+
70
+ /**
71
+ * Parse the AsciiDoc source input into a Document.
72
+ *
73
+ * @param {string|string[]|Buffer} input - the AsciiDoc source as a String, String Array, or Buffer
74
+ * @param {Object} [options={}] - a plain object of options to control processing
75
+ * @returns {Promise<Document>} - the parsed Document
76
+ */
77
+ export async function load(input, options = {}) {
78
+ return _load(input, options)
79
+ }
80
+
81
+ /**
82
+ * Parse the contents of the AsciiDoc source file into a Document.
83
+ *
84
+ * @param {string} filename - the path to the AsciiDoc source file
85
+ * @param {Object} [options={}] - a plain object of options to control processing
86
+ * @returns {Promise<Document>} - the parsed Document
87
+ */
88
+ export async function loadFile(filename, options = {}) {
89
+ return _loadFile(filename, options)
90
+ }
91
+
92
+ export { convert, convertFile }
93
+
94
+ export {
95
+ Document,
96
+ DocumentTitle,
97
+ Author,
98
+ Footnote,
99
+ ImageReference,
100
+ RevisionInfo,
101
+ Logger,
102
+ AbstractNode,
103
+ AbstractBlock,
104
+ Inline,
105
+ Block,
106
+ List,
107
+ ListItem,
108
+ Section,
109
+ Reader,
110
+ SyntaxHighlighterBase,
111
+ LoggerManager,
112
+ MemoryLogger,
113
+ NullLogger,
114
+ SafeMode,
115
+ ContentModel,
116
+ Timings,
117
+ Registry,
118
+ Processor,
119
+ ProcessorExtension,
120
+ Preprocessor,
121
+ TreeProcessor,
122
+ Postprocessor,
123
+ IncludeProcessor,
124
+ DocinfoProcessor,
125
+ BlockProcessor,
126
+ InlineMacroProcessor,
127
+ BlockMacroProcessor,
128
+ Extensions,
129
+ Cursor,
130
+ Converter as ConverterFactory,
131
+ ConverterBase,
132
+ CustomFactory as ConverterCustomFactory,
133
+ DefaultConverterFactory,
134
+ deriveBackendTraits,
135
+ DefaultSyntaxHighlighterFactory,
136
+ Html5Converter,
137
+ SyntaxHighlighter,
138
+ }
package/src/inline.js ADDED
@@ -0,0 +1,158 @@
1
+ // ESM conversion of inline.rb
2
+
3
+ import { AbstractNode } from './abstract_node.js'
4
+
5
+ /**
6
+ * Represents an inline element in an AsciiDoc document.
7
+ */
8
+ export class Inline extends AbstractNode {
9
+ /** @type {string|null} */
10
+ id
11
+ /** @type {string|null} */
12
+ type
13
+ /** @type {string|null} */
14
+ target
15
+ /** @type {string|null} */
16
+ text
17
+
18
+ /**
19
+ * @param {AbstractNode} parent
20
+ * @param {string} context
21
+ * @param {string|null} [text=null] - The String text of this inline element.
22
+ * @param {Object} [opts={}] - A plain object of options:
23
+ * id - The String id of this inline element.
24
+ * type - The String type qualifier (e.g. 'ref', 'bibref').
25
+ * target - The String target (e.g. a URI).
26
+ */
27
+ constructor(parent, context, text = null, opts = {}) {
28
+ super(parent, context, opts)
29
+ this.nodeName = `inline_${context}`
30
+ this.text = text
31
+ this.id = opts.id ?? null
32
+ this.type = opts.type ?? null
33
+ this.target = opts.target ?? null
34
+ }
35
+
36
+ isBlock() {
37
+ return false
38
+ }
39
+ isInline() {
40
+ return true
41
+ }
42
+
43
+ /**
44
+ * Convert this inline element using the document's converter.
45
+ * @returns {Promise<string>}
46
+ */
47
+ async convert() {
48
+ return this.converter.convert(this)
49
+ }
50
+
51
+ /** @deprecated Use convert() instead. */
52
+ render() {
53
+ return this.convert()
54
+ }
55
+
56
+ /**
57
+ * Get the converted content (alias for text).
58
+ * @returns {string|null}
59
+ */
60
+ content() {
61
+ return this.text
62
+ }
63
+
64
+ /**
65
+ * Alias for {@link getAlt}.
66
+ * @see {getAlt}
67
+ */
68
+ get alt() {
69
+ return this.getAttribute('alt') || ''
70
+ }
71
+
72
+ /**
73
+ * Check whether this inline node has reftext.
74
+ * For ref and bibref nodes the text acts as the reftext.
75
+ * @returns {boolean}
76
+ */
77
+ hasReftext() {
78
+ return !!(this.text && (this.type === 'ref' || this.type === 'bibref'))
79
+ }
80
+
81
+ /**
82
+ * Get the reftext for this inline node with substitutions applied.
83
+ * The result is pre-computed during Document.parse() via precomputeReftext().
84
+ * Falls back to the raw text if precomputeReftext() has not been called yet.
85
+ * @returns {string|null}
86
+ */
87
+ get reftext() {
88
+ if (this._convertedReftext !== undefined) return this._convertedReftext
89
+ return this.text ?? null
90
+ }
91
+
92
+ /**
93
+ * @internal
94
+ * Pre-compute the reftext with substitutions applied asynchronously.
95
+ * Called during Document.parse() so the synchronous getter works during conversion.
96
+ * @returns {Promise<void>}
97
+ */
98
+ async precomputeReftext() {
99
+ const val = this.text
100
+ this._convertedReftext =
101
+ val != null ? await this.applyReftextSubs(val) : null
102
+ }
103
+
104
+ /**
105
+ * Generate cross-reference text (xreftext) that can be used to refer to this inline node.
106
+ *
107
+ * Uses the explicit reftext for this inline node, if specified, retrieved by calling the
108
+ * reftext method. Otherwise, returns null.
109
+ *
110
+ * @param {string|null} [_xrefstyle=null] - Not currently used.
111
+ * @returns {string|null} the reftext to refer to this inline node, or null if no reftext is defined.
112
+ */
113
+ xreftext(_xrefstyle = null) {
114
+ return this.reftext
115
+ }
116
+
117
+ // ── JavaScript-style accessors ────────────────────────────────────────────────
118
+
119
+ /**
120
+ * Return the text of this inline node.
121
+ * @returns {string|null}
122
+ */
123
+ getText() {
124
+ return this.text
125
+ }
126
+
127
+ /**
128
+ * Return the type qualifier of this inline node (e.g. 'ref', 'bibref').
129
+ * @returns {string|null}
130
+ */
131
+ getType() {
132
+ return this.type
133
+ }
134
+
135
+ /**
136
+ * Return the target (e.g. URI or anchor) of this inline node.
137
+ * @returns {string|null}
138
+ */
139
+ getTarget() {
140
+ return this.target
141
+ }
142
+
143
+ /**
144
+ * Get the alt text for this inline image.
145
+ * @returns {string} the value of the alt attribute, or ''.
146
+ */
147
+ getAlt() {
148
+ return this.alt
149
+ }
150
+
151
+ /**
152
+ * Get the reftext for this inline node with substitutions applied.
153
+ * @returns {string|null}
154
+ */
155
+ getReftext() {
156
+ return this.reftext
157
+ }
158
+ }