@asciidoctor/core 3.0.3 → 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 (91) hide show
  1. package/README.md +42 -10
  2. package/build/browser/index.js +24154 -0
  3. package/build/node/index.cjs +24735 -0
  4. package/{dist/css/asciidoctor.css → data/asciidoctor-default.css} +54 -53
  5. package/package.json +53 -100
  6. package/src/abstract_block.js +849 -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 +1899 -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 +343 -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.ts +73 -3731
  69. package/types/inline.d.ts +69 -0
  70. package/types/list.d.ts +114 -0
  71. package/types/load.d.ts +39 -0
  72. package/types/logging.d.ts +187 -0
  73. package/types/parser.d.ts +114 -0
  74. package/types/path_resolver.d.ts +103 -0
  75. package/types/reader.d.ts +184 -0
  76. package/types/rx.d.ts +513 -0
  77. package/types/section.d.ts +122 -0
  78. package/types/stylesheets.d.ts +10 -0
  79. package/types/substitutors.d.ts +208 -0
  80. package/types/syntaxHighlighter/highlightjs.d.ts +33 -0
  81. package/types/syntaxHighlighter/html_pipeline.d.ts +16 -0
  82. package/types/syntax_highlighter.d.ts +167 -0
  83. package/types/table.d.ts +231 -0
  84. package/types/timings.d.ts +25 -0
  85. package/types/tsconfig.json +9 -0
  86. package/LICENSE +0 -21
  87. package/dist/browser/asciidoctor.js +0 -47654
  88. package/dist/browser/asciidoctor.min.js +0 -1452
  89. package/dist/graalvm/asciidoctor.js +0 -47402
  90. package/dist/node/asciidoctor.cjs +0 -21567
  91. package/dist/node/asciidoctor.js +0 -23037
package/src/logging.js ADDED
@@ -0,0 +1,526 @@
1
+ // ESM conversion of logging.rb
2
+ //
3
+ // Ruby-to-JavaScript notes:
4
+ // - Ruby's Logger hierarchy (Logger, MemoryLogger, NullLogger) is reimplemented
5
+ // without inheriting from a stdlib Logger class.
6
+ // - Severity levels mirror Ruby's Logger::Severity constants.
7
+ // - Logger.BasicFormatter formats messages as "asciidoctor: SEVERITY: text\n".
8
+ // - Logger.AutoFormattingMessage is an interface for objects that carry both
9
+ // text and source_location; in JS it is a plain object with a custom
10
+ // toString / inspect method attached.
11
+ // - LoggerManager is a module-level singleton object (not a class instance).
12
+ // - The Logging mixin is applied via applyLogging(prototype) which installs
13
+ // `logger` and `messageWithContext` on the target prototype.
14
+ // - In JS there is no $stderr; the default pipe is console.error.
15
+
16
+ // ── Severity levels (mirrors Ruby Logger::Severity) ──────────────────────────
17
+ export const Severity = {
18
+ DEBUG: 0,
19
+ INFO: 1,
20
+ WARN: 2,
21
+ ERROR: 3,
22
+ FATAL: 4,
23
+ UNKNOWN: 5,
24
+ }
25
+
26
+ const SEVERITY_LABEL = ['DEBUG', 'INFO', 'WARN', 'ERROR', 'FATAL', 'ANY']
27
+ const SEVERITY_LABEL_SUBSTITUTES = { WARN: 'WARNING', FATAL: 'FAILED' }
28
+
29
+ /**
30
+ * Convert a string or nullable severity value to a numeric Severity constant.
31
+ * @param {number|string|null|undefined} severity
32
+ * @returns {number}
33
+ * @internal
34
+ */
35
+ function resolveSeverity(severity) {
36
+ if (typeof severity === 'number') return severity
37
+ if (typeof severity === 'string')
38
+ return Severity[severity.toUpperCase()] ?? Severity.UNKNOWN
39
+ return severity ?? Severity.UNKNOWN
40
+ }
41
+
42
+ // ── Logger ────────────────────────────────────────────────────────────────────
43
+
44
+ /** Standard logger that writes formatted messages to stderr or a custom pipe. */
45
+ export class Logger {
46
+ constructor(opts = {}) {
47
+ this.progname = opts.progname ?? 'asciidoctor'
48
+ this.level = opts.level ?? Severity.WARN
49
+ /** @internal */
50
+ this._maxSeverity = null
51
+ /** @internal */
52
+ this._formatter = opts.formatter ?? new Logger.BasicFormatter()
53
+ /** @internal */
54
+ this._pipe = opts.pipe ?? null // null → write via _writeln
55
+ }
56
+
57
+ /** getter/setter so custom logger impls can access this.formatter */
58
+ get formatter() {
59
+ return this._formatter
60
+ }
61
+ set formatter(f) {
62
+ this._formatter = f
63
+ }
64
+
65
+ /**
66
+ * @returns {number|null} The highest severity level logged so far.
67
+ */
68
+ get maxSeverity() {
69
+ return this._maxSeverity
70
+ }
71
+
72
+ // Fluent getters/setters (used by the public API consumed by tests)
73
+ getLevel() {
74
+ return this.level
75
+ }
76
+ setLevel(n) {
77
+ this.level = n
78
+ }
79
+ getFormatter() {
80
+ return this._formatter
81
+ }
82
+ setFormatter(f) {
83
+ this._formatter = f
84
+ }
85
+ getProgramName() {
86
+ return this.progname
87
+ }
88
+ setProgramName(n) {
89
+ this.progname = n
90
+ }
91
+ getMaxSeverity() {
92
+ return this._maxSeverity
93
+ }
94
+
95
+ /**
96
+ * @returns {boolean} Whether DEBUG-level messages will be logged.
97
+ */
98
+ isDebugEnabled() {
99
+ return this.level <= Severity.DEBUG
100
+ }
101
+
102
+ /**
103
+ * @returns {boolean} Whether INFO-level messages will be logged.
104
+ */
105
+ isInfoEnabled() {
106
+ return this.level <= Severity.INFO
107
+ }
108
+
109
+ /**
110
+ * @returns {boolean} Whether WARN-level messages will be logged.
111
+ */
112
+ isWarnEnabled() {
113
+ return this.level <= Severity.WARN
114
+ }
115
+
116
+ /**
117
+ * @returns {boolean} Whether ERROR-level messages will be logged.
118
+ */
119
+ isErrorEnabled() {
120
+ return this.level <= Severity.ERROR
121
+ }
122
+
123
+ /**
124
+ * @returns {boolean} Whether FATAL-level messages will be logged.
125
+ */
126
+ isFatalEnabled() {
127
+ return this.level <= Severity.FATAL
128
+ }
129
+
130
+ // Kept for internal compatibility
131
+ isDebug() {
132
+ return this.level <= Severity.DEBUG
133
+ }
134
+ isInfo() {
135
+ return this.level <= Severity.INFO
136
+ }
137
+
138
+ /**
139
+ * Log a message at the given severity level.
140
+ * @param {number|string} severity - Severity level (numeric constant or string name).
141
+ * @param {string|{inspect?(): string}|null} [message=null] - The message to log.
142
+ * @param {string|Function|null} [progname=null] - Program name or message supplier function.
143
+ * @returns {boolean}
144
+ */
145
+ add(severity, message = null, progname = null) {
146
+ severity = resolveSeverity(severity)
147
+ if (this._maxSeverity === null || severity > this._maxSeverity) {
148
+ this._maxSeverity = severity
149
+ }
150
+ if (severity < this.level) return true
151
+ const text =
152
+ message ?? (typeof progname === 'function' ? progname() : progname)
153
+ const label = SEVERITY_LABEL[severity] ?? 'ANY'
154
+ const line = this._formatter.call(label, null, this.progname, text)
155
+ this._writeln(line)
156
+ return true
157
+ }
158
+
159
+ /** Alias for {@link add} (Ruby Logger API). */
160
+ log(severity, message, progname) {
161
+ return this.add(severity, message, progname)
162
+ }
163
+
164
+ debug(msg, progname) {
165
+ return this.add(Severity.DEBUG, msg, progname)
166
+ }
167
+ info(msg, progname) {
168
+ return this.add(Severity.INFO, msg, progname)
169
+ }
170
+ warn(msg, progname) {
171
+ return this.add(Severity.WARN, msg, progname)
172
+ }
173
+ error(msg, progname) {
174
+ return this.add(Severity.ERROR, msg, progname)
175
+ }
176
+ fatal(msg, progname) {
177
+ return this.add(Severity.FATAL, msg, progname)
178
+ }
179
+ unknown(msg, progname) {
180
+ return this.add(Severity.UNKNOWN, msg, progname)
181
+ }
182
+
183
+ /**
184
+ * Write a formatted line to stderr or console.error.
185
+ * @param {string} line
186
+ * @internal
187
+ */
188
+ _writeln(line) {
189
+ if (typeof process !== 'undefined' && process.stderr?.write) {
190
+ process.stderr.write(line)
191
+ } else {
192
+ console.error(line.replace(/\n$/, ''))
193
+ }
194
+ }
195
+ }
196
+
197
+ Logger.BasicFormatter = class {
198
+ /**
199
+ * Format a log entry as "progname: SEVERITY: message\n".
200
+ * @param {number|string} severity
201
+ * @param {null} _time
202
+ * @param {string} progname
203
+ * @param {string|{inspect?(): string}} msg
204
+ * @returns {string}
205
+ */
206
+ call(severity, _time, progname, msg) {
207
+ // severity may be numeric (from newLogger impls) or a string label
208
+ const label =
209
+ typeof severity === 'number'
210
+ ? (SEVERITY_LABEL[severity] ?? 'ANY')
211
+ : severity
212
+ const substituted = SEVERITY_LABEL_SUBSTITUTES[label] ?? label
213
+ const text =
214
+ typeof msg === 'string' ? msg : (msg?.inspect?.() ?? String(msg))
215
+ return `${progname}: ${substituted}: ${text}\n`
216
+ }
217
+ }
218
+
219
+ Logger.AutoFormattingMessage = {
220
+ /**
221
+ * Attach auto-formatting to any plain object carrying { text, source_location }.
222
+ * @param {{text: string, source_location?: string}} obj
223
+ * @returns {typeof obj} The same object with inspect() and toString() added.
224
+ */
225
+ attach(obj) {
226
+ obj.inspect = function () {
227
+ const sloc = this.source_location
228
+ return sloc ? `${sloc}: ${this.text}` : this.text
229
+ }
230
+ obj.toString = obj.inspect
231
+ return obj
232
+ },
233
+ }
234
+
235
+ // ── LogMessage ────────────────────────────────────────────────────────────────
236
+
237
+ /** Wrapper stored by MemoryLogger; provides getSeverity/getText/getSourceLocation. */
238
+ class LogMessage {
239
+ constructor(severity, message) {
240
+ this.message = message
241
+ this.severity = severity // string label, e.g. 'ERROR'
242
+ // AutoFormattingMessage objects carry { text, source_location }
243
+ if (message !== null && typeof message === 'object' && 'text' in message) {
244
+ this._text = message.text
245
+ this._sourceLocation = message.source_location ?? null
246
+ } else {
247
+ this._text = message != null ? String(message) : ''
248
+ this._sourceLocation = null
249
+ }
250
+ }
251
+
252
+ getSeverity() {
253
+ return this.severity
254
+ }
255
+ getText() {
256
+ return this._text
257
+ }
258
+ getSourceLocation() {
259
+ return this._sourceLocation ?? undefined
260
+ }
261
+ }
262
+
263
+ // ── MemoryLogger ──────────────────────────────────────────────────────────────
264
+
265
+ /** In-memory logger that stores all log messages for later inspection. */
266
+ export class MemoryLogger {
267
+ constructor() {
268
+ // Default level is UNKNOWN (highest) so isDebug() returns false by default,
269
+ // matching Ruby's MemoryLogger (level: UNKNOWN). The add() method stores all
270
+ // messages unconditionally — level is only used by the isDebug() guard.
271
+ this.level = Severity.UNKNOWN
272
+ this.messages = []
273
+ }
274
+
275
+ static create() {
276
+ return new MemoryLogger()
277
+ }
278
+
279
+ getMessages() {
280
+ return this.messages
281
+ }
282
+
283
+ getMaxSeverity() {
284
+ if (this.messages.length === 0) return null
285
+ return Math.max(
286
+ ...this.messages.map((m) => Severity[m.getSeverity()] ?? Severity.UNKNOWN)
287
+ )
288
+ }
289
+
290
+ add(severity, message = null, progname = null) {
291
+ const sev = resolveSeverity(severity)
292
+ const msg =
293
+ message ?? (typeof progname === 'function' ? progname() : progname)
294
+ const severityName = SEVERITY_LABEL[sev] ?? 'UNKNOWN'
295
+ this.messages.push(new LogMessage(severityName, msg))
296
+ return true
297
+ }
298
+
299
+ debug(msg, pn) {
300
+ return this.add(Severity.DEBUG, msg, pn)
301
+ }
302
+ info(msg, pn) {
303
+ return this.add(Severity.INFO, msg, pn)
304
+ }
305
+ warn(msg, pn) {
306
+ return this.add(Severity.WARN, msg, pn)
307
+ }
308
+ error(msg, pn) {
309
+ return this.add(Severity.ERROR, msg, pn)
310
+ }
311
+ fatal(msg, pn) {
312
+ return this.add(Severity.FATAL, msg, pn)
313
+ }
314
+ unknown(msg, pn) {
315
+ return this.add(Severity.UNKNOWN, msg, pn)
316
+ }
317
+
318
+ log(severity, message, progname) {
319
+ return this.add(severity, message, progname)
320
+ }
321
+
322
+ isDebug() {
323
+ return this.level <= Severity.DEBUG
324
+ }
325
+ isInfo() {
326
+ return this.level <= Severity.INFO
327
+ }
328
+
329
+ /**
330
+ * Write a string at INFO level (trailing newline stripped).
331
+ * Allows MemoryLogger to be used with Timings.printReport().
332
+ * @param {string} s
333
+ * @returns {boolean}
334
+ */
335
+ write(s) {
336
+ return this.info(s.replace(/\n$/, ''))
337
+ }
338
+
339
+ clear() {
340
+ this.messages.length = 0
341
+ }
342
+ empty() {
343
+ return this.messages.length === 0
344
+ }
345
+ }
346
+
347
+ // ── NullLogger ────────────────────────────────────────────────────────────────
348
+
349
+ /** Logger that discards all messages but still tracks the maximum severity. */
350
+ export class NullLogger {
351
+ constructor() {
352
+ this.level = Severity.UNKNOWN
353
+ this._maxSeverity = null
354
+ }
355
+
356
+ static create() {
357
+ return new NullLogger()
358
+ }
359
+
360
+ get maxSeverity() {
361
+ return this._maxSeverity
362
+ }
363
+ getMaxSeverity() {
364
+ return this._maxSeverity
365
+ }
366
+
367
+ add(severity) {
368
+ const sev = resolveSeverity(severity)
369
+ if (this._maxSeverity === null || sev > this._maxSeverity)
370
+ this._maxSeverity = sev
371
+ return true
372
+ }
373
+
374
+ log(severity) {
375
+ return this.add(severity)
376
+ }
377
+
378
+ debug() {
379
+ return this.add(Severity.DEBUG)
380
+ }
381
+ info() {
382
+ return this.add(Severity.INFO)
383
+ }
384
+ warn() {
385
+ return this.add(Severity.WARN)
386
+ }
387
+ error() {
388
+ return this.add(Severity.ERROR)
389
+ }
390
+ fatal() {
391
+ return this.add(Severity.FATAL)
392
+ }
393
+ unknown() {
394
+ return this.add(Severity.UNKNOWN)
395
+ }
396
+ }
397
+
398
+ // ── LoggerManager ─────────────────────────────────────────────────────────────
399
+
400
+ /**
401
+ * Module-level singleton — the active logger is stored here and can be
402
+ * replaced by callers (e.g. the load function).
403
+ */
404
+ export const LoggerManager = (() => {
405
+ let _loggerClass = Logger
406
+ let _logger = null
407
+
408
+ return {
409
+ get loggerClass() {
410
+ return _loggerClass
411
+ },
412
+ set loggerClass(cls) {
413
+ _loggerClass = cls
414
+ },
415
+
416
+ get logger() {
417
+ if (!_logger) _logger = new _loggerClass()
418
+ return _logger
419
+ },
420
+ set logger(newLogger) {
421
+ _logger = newLogger ?? new _loggerClass()
422
+ },
423
+
424
+ // Public API (mirrors Ruby LoggerManager)
425
+ getLogger() {
426
+ return this.logger
427
+ },
428
+ setLogger(newLogger) {
429
+ this.logger = newLogger
430
+ },
431
+
432
+ /**
433
+ * Create a new formatter whose call() delegates to the provided impl.
434
+ * @param {string} _name
435
+ * @param {{call: Function}} impl
436
+ * @returns {{call: Function}}
437
+ */
438
+ newFormatter(_name, impl) {
439
+ return { call: impl.call.bind(impl) }
440
+ },
441
+
442
+ /**
443
+ * Create a new Logger instance with custom behaviour supplied via impl.
444
+ * @param {string} _name
445
+ * @param {{add?: (severity: number, message: any, progname: any) => boolean, postConstruct?: (this: Logger) => void}} impl
446
+ * - `add(severity, message, progname)` — overrides the default add method; severity is always numeric.
447
+ * - `postConstruct()` — called once after the instance is created (`this` is the logger instance).
448
+ * @returns {Logger}
449
+ */
450
+ newLogger(_name, impl) {
451
+ const inst = new Logger()
452
+ if (impl.add) {
453
+ const customAdd = impl.add
454
+ inst.add = function (severity, message = null, progname = null) {
455
+ const sev = resolveSeverity(severity)
456
+ if (this._maxSeverity === null || sev > this._maxSeverity) {
457
+ this._maxSeverity = sev
458
+ }
459
+ return customAdd.call(this, sev, message, progname)
460
+ }
461
+ // Re-bind shorthand methods so they resolve through the custom add
462
+ for (const [meth, sev] of [
463
+ ['debug', Severity.DEBUG],
464
+ ['info', Severity.INFO],
465
+ ['warn', Severity.WARN],
466
+ ['error', Severity.ERROR],
467
+ ['fatal', Severity.FATAL],
468
+ ['unknown', Severity.UNKNOWN],
469
+ ]) {
470
+ inst[meth] = (msg, pn) => inst.add(sev, msg, pn)
471
+ }
472
+ inst.log = (severity, msg, pn) => inst.add(severity, msg, pn)
473
+ }
474
+ if (impl.postConstruct) impl.postConstruct.call(inst)
475
+ return inst
476
+ },
477
+ }
478
+ })()
479
+
480
+ // ── Logging mixin ─────────────────────────────────────────────────────────────
481
+
482
+ /**
483
+ * Apply the Logging mixin to a class prototype.
484
+ *
485
+ * Installs the following on proto:
486
+ * - `logger` getter — returns `LoggerManager.logger`
487
+ * - `getLogger()` — method alias for the logger getter
488
+ * - `messageWithContext(text, context)` — builds an auto-formatting message object
489
+ * - `createLogMessage(text, context)` — alias for messageWithContext (used in extensions)
490
+ *
491
+ * @param {Object} proto - The prototype object (e.g. MyClass.prototype) to augment.
492
+ */
493
+ export function applyLogging(proto) {
494
+ Object.defineProperty(proto, 'logger', {
495
+ get() {
496
+ return LoggerManager.logger
497
+ },
498
+ configurable: true,
499
+ })
500
+
501
+ proto.getLogger = () => LoggerManager.logger
502
+
503
+ proto.messageWithContext = (text, context = {}) =>
504
+ Logger.AutoFormattingMessage.attach({ text, ...context })
505
+
506
+ proto.createLogMessage = proto.messageWithContext
507
+ }
508
+
509
+ /**
510
+ * Plain object implementing the Logging mixin interface, for use in non-class contexts
511
+ * (e.g. top-level module functions).
512
+ */
513
+ export const Logging = {
514
+ get logger() {
515
+ return LoggerManager.logger
516
+ },
517
+ getLogger() {
518
+ return LoggerManager.logger
519
+ },
520
+ messageWithContext(text, context = {}) {
521
+ return Logger.AutoFormattingMessage.attach({ text, ...context })
522
+ },
523
+ createLogMessage(text, context = {}) {
524
+ return Logger.AutoFormattingMessage.attach({ text, ...context })
525
+ },
526
+ }