@asciidoctor/core 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 (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
@@ -0,0 +1,90 @@
1
+ // ESM conversion of syntax_highlighter/highlightjs.rb
2
+ //
3
+ // Ruby-to-JavaScript notes:
4
+ // - Ruby class SyntaxHighlighter::HighlightJsAdapter → HighlightJsAdapter extends SyntaxHighlighterBase.
5
+ // - register_for 'highlightjs', 'highlight.js' → handled by the parent SyntaxHighlighter factory.
6
+ // - HIGHLIGHT_JS_VERSION constant imported from constants.js.
7
+ // - Ruby doc.getAttribute(name, default) → doc.getAttribute(name) with fallback using ?? operator.
8
+ // - Ruby doc.attr? 'name' → doc.hasAttribute('name').
9
+ // - Ruby string interpolation / multiline heredocs → template literals.
10
+ // - Ruby :head / :footer symbols → plain strings 'head' / 'footer'.
11
+
12
+ import { SyntaxHighlighterBase } from '../syntax_highlighter.js'
13
+ import { HIGHLIGHT_JS_VERSION } from '../constants.js'
14
+
15
+ export class HighlightJsAdapter extends SyntaxHighlighterBase {
16
+ constructor(...args) {
17
+ super(...args)
18
+ this.name = 'highlightjs'
19
+ this._preClass = 'highlightjs'
20
+ }
21
+
22
+ /**
23
+ * Wrap the source block in `<pre><code>` with highlight.js CSS classes.
24
+ *
25
+ * Adds `language-<lang>` and `hljs` to the `<code>` class attribute, and strips
26
+ * the `highlight` class from `<pre>` when the `nohighlight-option` attribute is set.
27
+ * @param {object} node - the source Block being processed
28
+ * @param {string|null} lang - the source language string, or falsy if none
29
+ * @param {object} opts - options passed to the base format()
30
+ * @returns {Promise<string>}
31
+ */
32
+ async format(node, lang, opts) {
33
+ const transform = (pre, code) => {
34
+ if (node.hasAttribute('nohighlight-option')) {
35
+ pre.class = pre.class.replace(' highlight', '')
36
+ }
37
+ code.class = `language-${lang || 'none'} hljs`
38
+ }
39
+ return super.format(node, lang, { ...opts, transform })
40
+ }
41
+
42
+ /**
43
+ * Always returns true — highlight.js injects markup into the document.
44
+ * @param {string} location - 'head' or 'footer'
45
+ * @returns {true}
46
+ */
47
+ hasDocinfo(location) {
48
+ return true
49
+ }
50
+
51
+ /**
52
+ * Returns the CSS `<link>` tag (head) or the `<script>` tags (footer).
53
+ * @param {string} location - 'head' or 'footer'
54
+ * @param {object} doc - the Document being converted
55
+ * @param {{ cdn_base_url: string, self_closing_tag_slash: string }} opts
56
+ * @returns {string}
57
+ */
58
+ docinfo(location, doc, opts) {
59
+ const baseUrl =
60
+ doc.getAttribute('highlightjsdir') ??
61
+ `${opts.cdn_base_url}/highlight.js/${HIGHLIGHT_JS_VERSION}`
62
+
63
+ if (location === 'head') {
64
+ const theme = doc.getAttribute('highlightjs-theme') ?? 'github'
65
+ return `<link rel="stylesheet" href="${baseUrl}/styles/${theme}.min.css"${opts.self_closing_tag_slash ?? ''}>`
66
+ }
67
+
68
+ // footer
69
+ const langScripts = doc.getAttribute('highlightjs-languages')
70
+ ? doc
71
+ .getAttribute('highlightjs-languages')
72
+ .split(',')
73
+ .map(
74
+ (lang) =>
75
+ `<script src="${baseUrl}/languages/${lang.trimStart()}.min.js"></script>\n`
76
+ )
77
+ .join('')
78
+ : ''
79
+
80
+ return `<script src="${baseUrl}/highlight.min.js"></script>
81
+ ${langScripts}<script>
82
+ if (!hljs.initHighlighting.called) {
83
+ hljs.initHighlighting.called = true
84
+ ;[].slice.call(document.querySelectorAll('pre.highlight > code[data-lang]')).forEach(function (el) { hljs.highlightBlock(el) })
85
+ }
86
+ </script>`
87
+ }
88
+ }
89
+
90
+ export default HighlightJsAdapter
@@ -0,0 +1,33 @@
1
+ // ESM conversion of syntax_highlighter/html_pipeline.rb
2
+ //
3
+ // Ruby-to-JavaScript notes:
4
+ // - Ruby class SyntaxHighlighter::HtmlPipelineAdapter → HtmlPipelineAdapter extends SyntaxHighlighterBase.
5
+ // - register_for 'html-pipeline' → registration delegated to load.js for consistency.
6
+ // - format() overrides the base class to emit <pre lang="..."><code>…</code></pre> without
7
+ // highlight CSS classes — the html-pipeline gem processes the markup downstream.
8
+ // - Ruby string interpolation → template literals.
9
+
10
+ import { SyntaxHighlighterBase } from '../syntax_highlighter.js'
11
+
12
+ export class HtmlPipelineAdapter extends SyntaxHighlighterBase {
13
+ constructor(...args) {
14
+ super(...args)
15
+ this.name = 'html-pipeline'
16
+ }
17
+
18
+ /**
19
+ * Wrap the source block in `<pre><code>` without highlight classes.
20
+ *
21
+ * The html-pipeline gem processes the markup downstream, so only a bare
22
+ * `<pre lang="<lang>"><code>` wrapper is emitted (no CSS classes, no data-lang).
23
+ * @param {object} node - the source Block being processed
24
+ * @param {string|null} lang - the source language string, or falsy if none
25
+ * @param {object} opts - options (unused by this adapter)
26
+ * @returns {Promise<string>} the wrapped source string
27
+ */
28
+ async format(node, lang, opts) {
29
+ return `<pre${lang ? ` lang="${lang}"` : ''}><code>${await node.content()}</code></pre>`
30
+ }
31
+ }
32
+
33
+ export default HtmlPipelineAdapter
@@ -0,0 +1,304 @@
1
+ /** @import { Block } from './block.js' */
2
+
3
+ // ESM conversion of syntax_highlighter.rb
4
+ //
5
+ // Ruby-to-JavaScript notes:
6
+ // - Ruby module SyntaxHighlighter used as mixin → SyntaxHighlighterBase class.
7
+ // - Ruby module Factory → mixed into CustomFactory and DefaultFactory classes.
8
+ // - Ruby @@registry class var → module-level _defaultRegistry Map for DefaultFactory.
9
+ // - Ruby Mutex thread-safety → not needed in single-threaded JS.
10
+ // - Ruby lazy require (PROVIDED map) → async dynamic import() in DefaultFactory.
11
+ // - Ruby DefaultFactoryProxy (overrides #for with custom-first lookup) → DefaultFactory
12
+ // already handles this with _registry (custom) checked before _defaultRegistry (built-in).
13
+ // - Ruby module Config / register_for static helper → static registerFor() on each subclass.
14
+ // - Ruby :symbol keys → plain strings throughout.
15
+ // - highlightjs is always registered; coderay/pygments/rouge are Ruby-only (not ported).
16
+
17
+ // ── SyntaxHighlighterBase ─────────────────────────────────────────────────────
18
+
19
+ /**
20
+ * Base class for syntax highlighter adapters.
21
+ *
22
+ * Subclasses should override the methods they need. Two usage patterns:
23
+ * 1. Server-side highlighting: override `handlesHighlighting()` → true and `highlight()`.
24
+ * 2. Client-side highlighting: override `hasDocinfo()` → true and `docinfo()`.
25
+ *
26
+ * Both patterns may also override `format()`.
27
+ */
28
+ export class SyntaxHighlighterBase {
29
+ /**
30
+ * @param {string} name - the name identifying this adapter
31
+ * @param {string} [backend='html5'] - the backend name
32
+ * @param {Object} [opts={}] - options
33
+ */
34
+ constructor(name, backend = 'html5', opts = {}) {
35
+ this.name = name
36
+ this._preClass = name
37
+ }
38
+
39
+ /**
40
+ * Indicates whether this highlighter has docinfo markup to insert at the specified location.
41
+ *
42
+ * @param {string} location - the location slot ('head' or 'footer')
43
+ * @returns {boolean} false by default; subclasses return true to enable {@link docinfo}
44
+ */
45
+ hasDocinfo(location) {
46
+ return false
47
+ }
48
+
49
+ /**
50
+ * Generates docinfo markup to insert at the specified location in the output document.
51
+ *
52
+ * @param {string} location - the location slot ('head' or 'footer')
53
+ * @param {Document} doc - the Document in which this highlighter is used
54
+ * @param {Object} opts - options
55
+ * @param {boolean} [opts.linkcss] - link stylesheet instead of embedding
56
+ * @param {string} [opts.cdn_base_url] - base URL for CDN assets
57
+ * @param {string} [opts.self_closing_tag_slash] - '/' for self-closing tags
58
+ * @returns {string} the markup to insert
59
+ */
60
+ docinfo(location, doc, opts) {
61
+ throw new Error(
62
+ `${this.constructor.name} must implement docinfo() since hasDocinfo() returns true`
63
+ )
64
+ }
65
+
66
+ /**
67
+ * Indicates whether highlighting is handled server-side by this highlighter.
68
+ *
69
+ * @returns {boolean} false by default; subclasses return true to enable {@link highlight}
70
+ */
71
+ handlesHighlighting() {
72
+ return false
73
+ }
74
+
75
+ /**
76
+ * Highlights the specified source when this source block is being converted.
77
+ *
78
+ * If the source contains callout marks, the caller assumes the source remains on the same
79
+ * lines and no closing tags are added to the end of each line. If the source gets shifted
80
+ * by one or more lines, return a tuple of the highlighted source and the line offset.
81
+ *
82
+ * @param {Block} node - the source Block to highlight
83
+ * @param {string} source - the raw source text
84
+ * @param {string} lang - the source language (e.g. 'ruby')
85
+ * @param {Object} opts - options
86
+ * @param {Object} [opts.callouts] - callouts indexed by line number
87
+ * @param {string} [opts.css_mode] - CSS mode ('class' or 'inline')
88
+ * @param {number[]} [opts.highlight_lines] - 1-based line numbers to emphasize
89
+ * @param {string} [opts.number_lines] - 'table' or 'inline' if lines should be numbered
90
+ * @param {number} [opts.start_line_number] - starting line number (default: 1)
91
+ * @param {string} [opts.style] - theme name
92
+ * @returns {string|[string, number]} the highlighted source, or a tuple with a line offset
93
+ */
94
+ highlight(node, source, lang, opts) {
95
+ throw new Error(
96
+ `${this.constructor.name} must implement highlight() since handlesHighlighting() returns true`
97
+ )
98
+ }
99
+
100
+ /**
101
+ * Formats the highlighted source for inclusion in an HTML document.
102
+ *
103
+ * @param {Block} node - the source Block being processed
104
+ * @param {string} lang - the source language (e.g. 'ruby')
105
+ * @param {Object} opts - options
106
+ * @param {boolean} [opts.nowrap] - disable line wrapping
107
+ * @param {Function} [opts.transform] - called with (pre, code) attribute objects before building tags
108
+ * @returns {Promise<string>|string} the highlighted source wrapped in &lt;pre&gt;&lt;code&gt; tags.
109
+ * Subclasses may return a plain `string` — the caller always `await`s the result.
110
+ */
111
+ format(node, lang, opts) {
112
+ const classAttrVal = opts.nowrap
113
+ ? `${this._preClass} highlight nowrap`
114
+ : `${this._preClass} highlight`
115
+ return node.content().then((content) => {
116
+ const transform = opts.transform
117
+ if (transform) {
118
+ const pre = { class: classAttrVal }
119
+ const code = lang ? { 'data-lang': lang } : {}
120
+ transform(pre, code)
121
+ // NOTE keep data-lang as the last attribute on <code> to match Ruby 1.5.x behaviour
122
+ const dataLang = code['data-lang']
123
+ delete code['data-lang']
124
+ if (dataLang) code['data-lang'] = dataLang
125
+ const preAttrs = Object.entries(pre)
126
+ .map(([k, v]) => ` ${k}="${v}"`)
127
+ .join('')
128
+ const codeAttrs = Object.entries(code)
129
+ .map(([k, v]) => ` ${k}="${v}"`)
130
+ .join('')
131
+ return `<pre${preAttrs}><code${codeAttrs}>${content}</code></pre>`
132
+ }
133
+ return `<pre class="${classAttrVal}"><code${lang ? ` data-lang="${lang}"` : ''}>${content}</code></pre>`
134
+ })
135
+ }
136
+
137
+ /**
138
+ * Indicates whether this highlighter wants to write a stylesheet to disk.
139
+ *
140
+ * @param {Document} doc - the Document in which this highlighter is being used
141
+ * @returns {boolean} false by default; subclasses return true to enable {@link writeStylesheetToDisk}
142
+ */
143
+ writeStylesheet(doc) {
144
+ return false
145
+ }
146
+
147
+ /**
148
+ * Writes the stylesheet to disk.
149
+ *
150
+ * @param {Document} doc - the Document in which this highlighter is used
151
+ * @param {string} toDir - the absolute path of the output directory
152
+ */
153
+ writeStylesheetToDisk(doc, toDir) {
154
+ throw new Error(
155
+ `${this.constructor.name} must implement writeStylesheetToDisk() since writeStylesheet() returns true`
156
+ )
157
+ }
158
+ }
159
+
160
+ // ── CustomFactory ─────────────────────────────────────────────────────────────
161
+
162
+ /**
163
+ * A syntax highlighter factory backed by a caller-supplied registry.
164
+ */
165
+ export class CustomFactory {
166
+ /**
167
+ * @param {Object|null} [seedRegistry=null] - initial registry entries
168
+ */
169
+ constructor(seedRegistry = null) {
170
+ this._registry = seedRegistry ? { ...seedRegistry } : {}
171
+ }
172
+
173
+ /**
174
+ * Associates a syntax highlighter class or instance with one or more names.
175
+ *
176
+ * @param {Function|SyntaxHighlighterBase} syntaxHighlighter - the class or instance to register
177
+ * @param {...string} names - one or more names to associate
178
+ */
179
+ register(syntaxHighlighter, ...names) {
180
+ for (const name of names) {
181
+ this._registry[name] = syntaxHighlighter
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Retrieves the syntax highlighter class or instance registered for the given name.
187
+ *
188
+ * @param {string} name - the name to look up
189
+ * @returns {Function|SyntaxHighlighterBase|null} the registered class or instance, or null
190
+ */
191
+ for(name) {
192
+ return this._registry[name] ?? null
193
+ }
194
+
195
+ /**
196
+ * Resolves a name to a syntax highlighter instance.
197
+ *
198
+ * @param {string} name - the name of the syntax highlighter
199
+ * @param {string} [backend='html5'] - the backend name
200
+ * @param {Object} [opts={}] - options passed to the constructor
201
+ * @returns {SyntaxHighlighterBase|null} a highlighter instance, or null if not registered
202
+ */
203
+ create(name, backend = 'html5', opts = {}) {
204
+ let syntaxHl = this.for(name)
205
+ if (!syntaxHl) return null
206
+ if (typeof syntaxHl === 'function' && syntaxHl.prototype) {
207
+ syntaxHl = new syntaxHl(name, backend, opts)
208
+ }
209
+ if (!syntaxHl.name) {
210
+ throw new Error(
211
+ `${syntaxHl.constructor.name} must specify a value for 'name'`
212
+ )
213
+ }
214
+ return syntaxHl
215
+ }
216
+ }
217
+
218
+ // ── DefaultFactoryProxy ───────────────────────────────────────────────────────
219
+
220
+ // Wraps a `syntax_highlighters` hash (per-load overrides) and falls back to a
221
+ // delegate factory (typically the global SyntaxHighlighter singleton) for names
222
+ // not present in the overrides. Setting a name to null disables that highlighter.
223
+
224
+ export class DefaultFactoryProxy extends CustomFactory {
225
+ /**
226
+ * @param {Object} overrides - map of name → class/instance/null
227
+ * @param {CustomFactory} fallback - factory to delegate to when name is not overridden
228
+ */
229
+ constructor(overrides, fallback) {
230
+ super(overrides)
231
+ this._fallback = fallback
232
+ }
233
+
234
+ for(name) {
235
+ // Use hasOwnProperty so that null (disabled) is returned as-is
236
+ if (Object.hasOwn(this._registry, name)) {
237
+ return this._registry[name]
238
+ }
239
+ return this._fallback.for(name)
240
+ }
241
+ }
242
+
243
+ // ── DefaultFactory ────────────────────────────────────────────────────────────
244
+
245
+ // Global registry that distinguishes built-in adapters (registered by the
246
+ // adapters themselves via self-registration) from custom adapters (registered
247
+ // by user code). unregisterAll() clears only the custom layer so built-ins
248
+ // remain available after a reset, mirroring Ruby's DefaultFactory behaviour.
249
+
250
+ export class DefaultFactory extends CustomFactory {
251
+ constructor() {
252
+ super()
253
+ // _registry (inherited) → custom registrations
254
+ // _defaultRegistry → built-in registrations (populated by adapters)
255
+ this._defaultRegistry = {}
256
+ }
257
+
258
+ // Register into the built-in layer (called by built-in adapters).
259
+ register(syntaxHighlighter, ...names) {
260
+ for (const name of names) {
261
+ this._defaultRegistry[name] = syntaxHighlighter
262
+ }
263
+ }
264
+
265
+ // Custom registrations shadow built-ins.
266
+ for(name) {
267
+ return this._registry[name] ?? this._defaultRegistry[name] ?? null
268
+ }
269
+
270
+ /**
271
+ * Retrieves the syntax highlighter class or instance registered for the given name.
272
+ *
273
+ * @param {string} name - the name of the syntax highlighter to retrieve
274
+ * @returns {Function|SyntaxHighlighterBase|undefined} the registered class or instance, or undefined
275
+ */
276
+ get(name) {
277
+ return this.for(name) ?? undefined
278
+ }
279
+
280
+ create(name, backend = 'html5', opts = {}) {
281
+ let syntaxHl = this.for(name)
282
+ if (!syntaxHl) return null
283
+ if (typeof syntaxHl === 'function' && syntaxHl.prototype) {
284
+ syntaxHl = new syntaxHl(name, backend, opts)
285
+ }
286
+ if (!syntaxHl.name) {
287
+ throw new Error(
288
+ `${syntaxHl.constructor.name} must specify a value for 'name'`
289
+ )
290
+ }
291
+ return syntaxHl
292
+ }
293
+
294
+ /**
295
+ * Clears all custom (user) registrations; built-in adapters are preserved.
296
+ */
297
+ unregisterAll() {
298
+ this._registry = {}
299
+ }
300
+ }
301
+
302
+ // ── The global SyntaxHighlighter registry ─────────────────────────────────────
303
+
304
+ export const SyntaxHighlighter = new DefaultFactory()