@asciidoctor/core 4.0.1 → 4.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/browser/index.js +275 -52
- package/build/node/index.cjs +322 -65
- package/package.json +2 -1
- package/src/abstract_node.js +6 -3
- package/src/converter/html5.js +39 -9
- package/src/converter/manpage.js +1 -1
- package/src/converter/template.js +47 -13
- package/src/converter.js +22 -9
- package/src/document.js +63 -23
- package/src/extensions.js +143 -5
- package/src/index.js +4 -0
- package/types/abstract_node.d.ts +4 -3
- package/types/document.d.ts +16 -0
- package/types/extensions.d.ts +390 -14
- package/types/index.d.cts +4 -0
- package/types/index.d.ts +4 -0
package/build/node/index.cjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const node_module = require('node:module');
|
|
4
|
+
const node_url = require('node:url');
|
|
4
5
|
const node_fs = require('node:fs');
|
|
5
6
|
const path = require('node:path');
|
|
6
7
|
|
|
7
8
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
8
|
-
var version = "4.0.
|
|
9
|
+
var version = "4.0.3";
|
|
9
10
|
const packageJson = {
|
|
10
11
|
version: version};
|
|
11
12
|
|
|
@@ -3039,9 +3040,10 @@ class AbstractNode {
|
|
|
3039
3040
|
* Construct a URI reference or data URI to the target image.
|
|
3040
3041
|
*
|
|
3041
3042
|
* If the target image is already a URI it is left untouched (unless data-uri
|
|
3042
|
-
* conversion is requested).
|
|
3043
|
-
*
|
|
3044
|
-
* the
|
|
3043
|
+
* conversion is requested). If the target image is a data URI, then it is
|
|
3044
|
+
* already an embedded image, so it is returned as-is. The image is resolved
|
|
3045
|
+
* relative to the directory named by assetDirKey. When data-uri is enabled and
|
|
3046
|
+
* the safe level permits, the image is embedded as a Base64 data URI.
|
|
3045
3047
|
*
|
|
3046
3048
|
* NOTE: When the document has both 'data-uri' and 'allow-uri-read' enabled
|
|
3047
3049
|
* and the resolved image URL is a remote URI, this method returns a Promise
|
|
@@ -3052,6 +3054,8 @@ class AbstractNode {
|
|
|
3052
3054
|
* @returns {Promise<string>} a Promise resolving to a String reference or data URI.
|
|
3053
3055
|
*/
|
|
3054
3056
|
async imageUri(targetImage, assetDirKey = 'imagesdir') {
|
|
3057
|
+
// A data URI is already an embedded image, so use it as-is rather than reading or re-encoding it.
|
|
3058
|
+
if (targetImage.startsWith('data:')) return targetImage
|
|
3055
3059
|
const doc = this.document;
|
|
3056
3060
|
if (doc.safe < SafeMode.SECURE && doc.hasAttribute('data-uri')) {
|
|
3057
3061
|
let imagesBase;
|
|
@@ -5459,7 +5463,18 @@ class SecurityError extends Error {
|
|
|
5459
5463
|
function applyBackendTraits(instance) {
|
|
5460
5464
|
instance._backendTraits = null;
|
|
5461
5465
|
|
|
5462
|
-
|
|
5466
|
+
// Install a Ruby-style trait accessor method, but never clobber a flat string
|
|
5467
|
+
// property the converter already declared (convention #2). Overwriting e.g.
|
|
5468
|
+
// `converter.outfilesuffix = '.html'` with a method would silently turn the
|
|
5469
|
+
// author's string into a function; the backend traits stay reachable through
|
|
5470
|
+
// `_getBackendTraits()` instead.
|
|
5471
|
+
const defineTraitAccessor = (name, fn) => {
|
|
5472
|
+
const existing = Object.getOwnPropertyDescriptor(instance, name);
|
|
5473
|
+
if (existing && typeof existing.value !== 'function') return
|
|
5474
|
+
instance[name] = fn;
|
|
5475
|
+
};
|
|
5476
|
+
|
|
5477
|
+
defineTraitAccessor('basebackend', function (value = null) {
|
|
5463
5478
|
if (value) {
|
|
5464
5479
|
const traits = (this._backendTraits ??= {});
|
|
5465
5480
|
traits.basebackend = value;
|
|
@@ -5473,19 +5488,19 @@ function applyBackendTraits(instance) {
|
|
|
5473
5488
|
return value
|
|
5474
5489
|
}
|
|
5475
5490
|
return this._getBackendTraits().basebackend
|
|
5476
|
-
};
|
|
5477
|
-
|
|
5491
|
+
});
|
|
5492
|
+
defineTraitAccessor('filetype', function (value = null) {
|
|
5478
5493
|
if (value) return (this._getBackendTraits().filetype = value)
|
|
5479
5494
|
return this._getBackendTraits().filetype
|
|
5480
|
-
};
|
|
5481
|
-
|
|
5495
|
+
});
|
|
5496
|
+
defineTraitAccessor('htmlsyntax', function (value = null) {
|
|
5482
5497
|
if (value) return (this._getBackendTraits().htmlsyntax = value)
|
|
5483
5498
|
return this._getBackendTraits().htmlsyntax
|
|
5484
|
-
};
|
|
5485
|
-
|
|
5499
|
+
});
|
|
5500
|
+
defineTraitAccessor('outfilesuffix', function (value = null) {
|
|
5486
5501
|
if (value) return (this._getBackendTraits().outfilesuffix = value)
|
|
5487
5502
|
return this._getBackendTraits().outfilesuffix
|
|
5488
|
-
};
|
|
5503
|
+
});
|
|
5489
5504
|
instance.supportsTemplates = function (value = true) {
|
|
5490
5505
|
this._getBackendTraits().supportsTemplates = value;
|
|
5491
5506
|
};
|
|
@@ -5569,7 +5584,9 @@ function normalizeConverter(converter, backend) {
|
|
|
5569
5584
|
}
|
|
5570
5585
|
}
|
|
5571
5586
|
|
|
5572
|
-
// Apply the BackendTraits mixin so Document can
|
|
5587
|
+
// Apply the BackendTraits mixin so Document can read traits via
|
|
5588
|
+
// _getBackendTraits(). Flat string properties (convention #2) are preserved:
|
|
5589
|
+
// applyBackendTraits does not overwrite an existing same-named data property.
|
|
5573
5590
|
applyBackendTraits(converter);
|
|
5574
5591
|
if (traits) {
|
|
5575
5592
|
converter._backendTraits = traits;
|
|
@@ -13506,6 +13523,30 @@ function _uniform(str, chr, len) {
|
|
|
13506
13523
|
* @typedef {ProcessorDslInterface & { prefer(): void; prepend(): void }} DocumentProcessorDslInterface
|
|
13507
13524
|
*/
|
|
13508
13525
|
|
|
13526
|
+
/**
|
|
13527
|
+
* DSL interface for preprocessors.
|
|
13528
|
+
*
|
|
13529
|
+
* @typedef {Omit<DocumentProcessorDslInterface, 'process'> & {
|
|
13530
|
+
* process(fn: (this: PreprocessorDslInterface, document: Document, reader: Reader) => Reader | void): void;
|
|
13531
|
+
* }} PreprocessorDslInterface
|
|
13532
|
+
*/
|
|
13533
|
+
|
|
13534
|
+
/**
|
|
13535
|
+
* DSL interface for tree processors.
|
|
13536
|
+
*
|
|
13537
|
+
* @typedef {Omit<DocumentProcessorDslInterface, 'process'> & {
|
|
13538
|
+
* process(fn: (this: TreeProcessorDslInterface, document: Document) => Document | void): void;
|
|
13539
|
+
* }} TreeProcessorDslInterface
|
|
13540
|
+
*/
|
|
13541
|
+
|
|
13542
|
+
/**
|
|
13543
|
+
* DSL interface for postprocessors.
|
|
13544
|
+
*
|
|
13545
|
+
* @typedef {Omit<DocumentProcessorDslInterface, 'process'> & {
|
|
13546
|
+
* process(fn: (this: PostprocessorDslInterface, document: Document, output: string) => string): void;
|
|
13547
|
+
* }} PostprocessorDslInterface
|
|
13548
|
+
*/
|
|
13549
|
+
|
|
13509
13550
|
/**
|
|
13510
13551
|
* DSL interface for syntax processors (BlockProcessor, BlockMacroProcessor, InlineMacroProcessor).
|
|
13511
13552
|
*
|
|
@@ -13526,28 +13567,35 @@ function _uniform(str, chr, len) {
|
|
|
13526
13567
|
/**
|
|
13527
13568
|
* DSL interface for include processors.
|
|
13528
13569
|
*
|
|
13529
|
-
* @typedef {DocumentProcessorDslInterface & {
|
|
13570
|
+
* @typedef {Omit<DocumentProcessorDslInterface, 'process'> & {
|
|
13530
13571
|
* handles(fn: (target: string) => boolean): void;
|
|
13531
13572
|
* handles(fn: (doc: Document, target: string) => boolean): void;
|
|
13573
|
+
* process(fn: (this: IncludeProcessorDslInterface, document: Document, reader: Reader, target: string, attributes: Record<string, string>) => void): void;
|
|
13532
13574
|
* }} IncludeProcessorDslInterface
|
|
13533
13575
|
*/
|
|
13534
13576
|
|
|
13535
13577
|
/**
|
|
13536
13578
|
* DSL interface for docinfo processors.
|
|
13537
13579
|
*
|
|
13538
|
-
* @typedef {DocumentProcessorDslInterface & {
|
|
13580
|
+
* @typedef {Omit<DocumentProcessorDslInterface, 'process'> & {
|
|
13539
13581
|
* atLocation(value: string): void;
|
|
13582
|
+
* process(fn: (this: DocinfoProcessorDslInterface, document: Document) => string): void;
|
|
13540
13583
|
* }} DocinfoProcessorDslInterface
|
|
13541
13584
|
*/
|
|
13542
13585
|
|
|
13543
13586
|
/**
|
|
13544
13587
|
* DSL interface for block processors.
|
|
13545
13588
|
*
|
|
13546
|
-
*
|
|
13589
|
+
* The `process` callback is bound to the processor instance, so `this` inside it
|
|
13590
|
+
* (and inside the registration function) exposes the `createBlock` helpers.
|
|
13591
|
+
*
|
|
13592
|
+
* @typedef {Omit<SyntaxProcessorDslInterface, 'process'> & {
|
|
13547
13593
|
* contexts(...value: (string | string[])[]): void;
|
|
13548
13594
|
* onContexts(...value: (string | string[])[]): void;
|
|
13549
13595
|
* onContext(...value: (string | string[])[]): void;
|
|
13550
13596
|
* bindTo(...value: (string | string[])[]): void;
|
|
13597
|
+
* createBlock(parent: AbstractBlock, context: string, source?: string | string[] | null, attrs?: object, opts?: object): Block;
|
|
13598
|
+
* process(fn: (this: BlockProcessorDslInterface, parent: AbstractBlock, reader: Reader, attributes: Record<string, unknown>) => AbstractBlock | void): void;
|
|
13551
13599
|
* }} BlockProcessorDslInterface
|
|
13552
13600
|
*/
|
|
13553
13601
|
|
|
@@ -13557,14 +13605,31 @@ function _uniform(str, chr, len) {
|
|
|
13557
13605
|
* @typedef {SyntaxProcessorDslInterface} MacroProcessorDslInterface
|
|
13558
13606
|
*/
|
|
13559
13607
|
|
|
13608
|
+
/**
|
|
13609
|
+
* DSL interface for block macro processors.
|
|
13610
|
+
*
|
|
13611
|
+
* The `process` callback is bound to the processor instance, so `this` inside it
|
|
13612
|
+
* (and inside the registration function) exposes the `createBlock` helpers.
|
|
13613
|
+
*
|
|
13614
|
+
* @typedef {Omit<MacroProcessorDslInterface, 'process'> & {
|
|
13615
|
+
* createBlock(parent: AbstractBlock, context: string, source?: string | string[] | null, attrs?: object, opts?: object): Block;
|
|
13616
|
+
* process(fn: (this: BlockMacroProcessorDslInterface, parent: AbstractBlock, target: string, attributes: Record<string, unknown>) => AbstractBlock | void): void;
|
|
13617
|
+
* }} BlockMacroProcessorDslInterface
|
|
13618
|
+
*/
|
|
13619
|
+
|
|
13560
13620
|
/**
|
|
13561
13621
|
* DSL interface for inline macro processors.
|
|
13562
13622
|
*
|
|
13563
|
-
*
|
|
13623
|
+
* The `process` callback is bound to the processor instance, so `this` inside it
|
|
13624
|
+
* (and inside the registration function) exposes the `createInline` helper.
|
|
13625
|
+
*
|
|
13626
|
+
* @typedef {Omit<MacroProcessorDslInterface, 'process'> & {
|
|
13564
13627
|
* format(value: string): void;
|
|
13565
13628
|
* matchFormat(value: string): void;
|
|
13566
13629
|
* usingFormat(value: string): void;
|
|
13567
13630
|
* match(value: RegExp): void;
|
|
13631
|
+
* createInline(parent: AbstractBlock, context: string, text: string, opts?: object): Inline;
|
|
13632
|
+
* process(fn: (this: InlineMacroProcessorDslInterface, parent: AbstractBlock, target: string, attributes: Record<string, unknown>) => Inline | void): void;
|
|
13568
13633
|
* }} InlineMacroProcessorDslInterface
|
|
13569
13634
|
*/
|
|
13570
13635
|
|
|
@@ -14285,7 +14350,15 @@ class IncludeProcessor extends Processor {
|
|
|
14285
14350
|
}
|
|
14286
14351
|
|
|
14287
14352
|
/**
|
|
14288
|
-
*
|
|
14353
|
+
* Decide whether this include processor handles the given target.
|
|
14354
|
+
*
|
|
14355
|
+
* Override this method in a subclass. The override may accept either just the
|
|
14356
|
+
* target string (Ruby-style, arity 1) or both the document and the target
|
|
14357
|
+
* (arity 2) — an arity-1 override is adapted at registration time so the
|
|
14358
|
+
* parser can always invoke it as `handles(doc, target)`. The first parameter
|
|
14359
|
+
* is therefore typed `Document | string` so both override shapes type-check.
|
|
14360
|
+
*
|
|
14361
|
+
* @param {Document|string} doc - The document being parsed, or (for a Ruby-style arity-1 override) the include target.
|
|
14289
14362
|
* @param {string} target - The target of the include directive.
|
|
14290
14363
|
* @returns {boolean} true if this processor handles the given target.
|
|
14291
14364
|
*/
|
|
@@ -14653,6 +14726,14 @@ class Registry {
|
|
|
14653
14726
|
* this.process(function (doc, reader) { ... })
|
|
14654
14727
|
* })
|
|
14655
14728
|
*
|
|
14729
|
+
* @overload
|
|
14730
|
+
* @param {typeof Preprocessor} processor - A Preprocessor subclass or instance.
|
|
14731
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14732
|
+
*
|
|
14733
|
+
* @overload
|
|
14734
|
+
* @param {(this: PreprocessorDslInterface) => void} fn - Registration function bound to the preprocessor DSL.
|
|
14735
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14736
|
+
*
|
|
14656
14737
|
* @param {...*} args - Class constructor, instance, or block function.
|
|
14657
14738
|
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14658
14739
|
*/
|
|
@@ -14686,6 +14767,14 @@ class Registry {
|
|
|
14686
14767
|
/**
|
|
14687
14768
|
* Register a TreeProcessor with the extension registry.
|
|
14688
14769
|
*
|
|
14770
|
+
* @overload
|
|
14771
|
+
* @param {typeof TreeProcessor} processor - A TreeProcessor subclass or instance.
|
|
14772
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14773
|
+
*
|
|
14774
|
+
* @overload
|
|
14775
|
+
* @param {(this: TreeProcessorDslInterface) => void} fn - Registration function bound to the tree processor DSL.
|
|
14776
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14777
|
+
*
|
|
14689
14778
|
* @param {...*} args - Class constructor, instance, or block function.
|
|
14690
14779
|
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14691
14780
|
*/
|
|
@@ -14739,6 +14828,14 @@ class Registry {
|
|
|
14739
14828
|
/**
|
|
14740
14829
|
* Register a Postprocessor with the extension registry.
|
|
14741
14830
|
*
|
|
14831
|
+
* @overload
|
|
14832
|
+
* @param {typeof Postprocessor} processor - A Postprocessor subclass or instance.
|
|
14833
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14834
|
+
*
|
|
14835
|
+
* @overload
|
|
14836
|
+
* @param {(this: PostprocessorDslInterface) => void} fn - Registration function bound to the postprocessor DSL.
|
|
14837
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14838
|
+
*
|
|
14742
14839
|
* @param {...*} args - Class constructor, instance, or block function.
|
|
14743
14840
|
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14744
14841
|
*/
|
|
@@ -14772,6 +14869,14 @@ class Registry {
|
|
|
14772
14869
|
/**
|
|
14773
14870
|
* Register an IncludeProcessor with the extension registry.
|
|
14774
14871
|
*
|
|
14872
|
+
* @overload
|
|
14873
|
+
* @param {typeof IncludeProcessor} processor - An IncludeProcessor subclass or instance.
|
|
14874
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14875
|
+
*
|
|
14876
|
+
* @overload
|
|
14877
|
+
* @param {(this: IncludeProcessorDslInterface) => void} fn - Registration function bound to the include processor DSL.
|
|
14878
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14879
|
+
*
|
|
14775
14880
|
* @param {...*} args - Class constructor, instance, or block function.
|
|
14776
14881
|
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14777
14882
|
*/
|
|
@@ -14810,6 +14915,14 @@ class Registry {
|
|
|
14810
14915
|
/**
|
|
14811
14916
|
* Register a DocinfoProcessor with the extension registry.
|
|
14812
14917
|
*
|
|
14918
|
+
* @overload
|
|
14919
|
+
* @param {typeof DocinfoProcessor} processor - A DocinfoProcessor subclass or instance.
|
|
14920
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14921
|
+
*
|
|
14922
|
+
* @overload
|
|
14923
|
+
* @param {(this: DocinfoProcessorDslInterface) => void} fn - Registration function bound to the docinfo processor DSL.
|
|
14924
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14925
|
+
*
|
|
14813
14926
|
* @param {...*} args - Class constructor, instance, or block function.
|
|
14814
14927
|
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14815
14928
|
*/
|
|
@@ -14877,6 +14990,20 @@ class Registry {
|
|
|
14877
14990
|
* this.process(function (parent, reader, attrs) { ... })
|
|
14878
14991
|
* })
|
|
14879
14992
|
*
|
|
14993
|
+
* @overload
|
|
14994
|
+
* @param {typeof BlockProcessor} processor - A BlockProcessor subclass.
|
|
14995
|
+
* @param {string} [name] - Optional explicit block name.
|
|
14996
|
+
* @returns {ProcessorExtension} an Extension proxy object.
|
|
14997
|
+
*
|
|
14998
|
+
* @overload
|
|
14999
|
+
* @param {string} name - The block name.
|
|
15000
|
+
* @param {(this: BlockProcessorDslInterface) => void} fn - Registration function bound to the block DSL.
|
|
15001
|
+
* @returns {ProcessorExtension} an Extension proxy object.
|
|
15002
|
+
*
|
|
15003
|
+
* @overload
|
|
15004
|
+
* @param {(this: BlockProcessorDslInterface) => void} fn - Registration function bound to the block DSL.
|
|
15005
|
+
* @returns {ProcessorExtension} an Extension proxy object.
|
|
15006
|
+
*
|
|
14880
15007
|
* @param {...*} args - Class constructor, instance, block function, or name + one of those.
|
|
14881
15008
|
* @returns {ProcessorExtension} an Extension proxy object.
|
|
14882
15009
|
*/
|
|
@@ -14927,6 +15054,20 @@ class Registry {
|
|
|
14927
15054
|
/**
|
|
14928
15055
|
* Register a BlockMacroProcessor with the extension registry.
|
|
14929
15056
|
*
|
|
15057
|
+
* @overload
|
|
15058
|
+
* @param {typeof BlockMacroProcessor} processor - A BlockMacroProcessor subclass.
|
|
15059
|
+
* @param {string} [name] - Optional explicit macro name.
|
|
15060
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
15061
|
+
*
|
|
15062
|
+
* @overload
|
|
15063
|
+
* @param {string} name - The macro name.
|
|
15064
|
+
* @param {(this: BlockMacroProcessorDslInterface) => void} fn - Registration function bound to the block macro DSL.
|
|
15065
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
15066
|
+
*
|
|
15067
|
+
* @overload
|
|
15068
|
+
* @param {(this: BlockMacroProcessorDslInterface) => void} fn - Registration function bound to the block macro DSL.
|
|
15069
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
15070
|
+
*
|
|
14930
15071
|
* @param {...*} args - Class constructor, instance, or block function.
|
|
14931
15072
|
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14932
15073
|
*/
|
|
@@ -14982,6 +15123,20 @@ class Registry {
|
|
|
14982
15123
|
/**
|
|
14983
15124
|
* Register an InlineMacroProcessor with the extension registry.
|
|
14984
15125
|
*
|
|
15126
|
+
* @overload
|
|
15127
|
+
* @param {typeof InlineMacroProcessor} processor - An InlineMacroProcessor subclass.
|
|
15128
|
+
* @param {string} [name] - Optional explicit macro name.
|
|
15129
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
15130
|
+
*
|
|
15131
|
+
* @overload
|
|
15132
|
+
* @param {string} name - The macro name.
|
|
15133
|
+
* @param {(this: InlineMacroProcessorDslInterface) => void} fn - Registration function bound to the inline macro DSL.
|
|
15134
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
15135
|
+
*
|
|
15136
|
+
* @overload
|
|
15137
|
+
* @param {(this: InlineMacroProcessorDslInterface) => void} fn - Registration function bound to the inline macro DSL.
|
|
15138
|
+
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
15139
|
+
*
|
|
14985
15140
|
* @param {...*} args - Class constructor, instance, or block function.
|
|
14986
15141
|
* @returns {ProcessorExtension} the Extension stored in the registry.
|
|
14987
15142
|
*/
|
|
@@ -16098,7 +16253,7 @@ class Document extends AbstractBlock {
|
|
|
16098
16253
|
|
|
16099
16254
|
const attrOverrides = this._attributeOverrides;
|
|
16100
16255
|
attrOverrides.asciidoctor = '';
|
|
16101
|
-
attrOverrides['asciidoctor-version'] =
|
|
16256
|
+
attrOverrides['asciidoctor-version'] = packageJson.version;
|
|
16102
16257
|
|
|
16103
16258
|
const safeModeName = SafeMode.nameForValue(this.safe);
|
|
16104
16259
|
attrOverrides['safe-mode-name'] = safeModeName;
|
|
@@ -16290,16 +16445,16 @@ class Document extends AbstractBlock {
|
|
|
16290
16445
|
// attribute (re)assignments are in scope; snapshot and restore the document
|
|
16291
16446
|
// attributes so the downstream steps and conversion still start from the restored
|
|
16292
16447
|
// (header) state, matching Ruby's restore_attributes-before-convert invariant.
|
|
16448
|
+
//
|
|
16449
|
+
// This runs in two passes because list item / table cell / dlist text may contain
|
|
16450
|
+
// natural cross-references (e.g. <<Some section title>>) that resolve against the
|
|
16451
|
+
// reftext→id map. Pass 1 substitutes titles and reftexts only, so every section
|
|
16452
|
+
// reftext is known; the map is then built; pass 2 substitutes the block content
|
|
16453
|
+
// text, where resolveId() can now match those natural references.
|
|
16293
16454
|
const attributesSnapshot = { ...this.attributes };
|
|
16294
|
-
|
|
16295
|
-
|
|
16296
|
-
|
|
16297
|
-
Object.assign(this.attributes, attributesSnapshot);
|
|
16298
|
-
// Reset the footnote counter so that body-content footnotes (processed during conversion)
|
|
16299
|
-
// start numbering from 1, reproducing Ruby's "out of sequence" quirk: title footnotes are
|
|
16300
|
-
// numbered during parsing via apply_title_subs, then the counter restarts for body content.
|
|
16301
|
-
delete this.attributes['footnote-number'];
|
|
16302
|
-
delete this._counters['footnote-number'];
|
|
16455
|
+
// Pass 1: titles + reftexts (no block content text yet).
|
|
16456
|
+
await this._resolveAllTexts(this, false);
|
|
16457
|
+
this._restoreAttributeSnapshot(attributesSnapshot);
|
|
16303
16458
|
// Pre-compute reftext for all registered inline anchor nodes.
|
|
16304
16459
|
for (const ref of Object.values(this.catalog.refs)) {
|
|
16305
16460
|
if (ref && typeof ref.precomputeReftext === 'function') {
|
|
@@ -16308,6 +16463,15 @@ class Document extends AbstractBlock {
|
|
|
16308
16463
|
}
|
|
16309
16464
|
// Build the reftext→id lookup map so that resolveId() is synchronous.
|
|
16310
16465
|
await this._buildReftextsMap();
|
|
16466
|
+
// Pass 2: list item / table cell / dlist text, now that natural cross-references
|
|
16467
|
+
// can be resolved against the reftext→id map.
|
|
16468
|
+
await this._resolveAllTexts(this, true);
|
|
16469
|
+
this._restoreAttributeSnapshot(attributesSnapshot);
|
|
16470
|
+
// Reset the footnote counter so that body-content footnotes (processed during conversion)
|
|
16471
|
+
// start numbering from 1, reproducing Ruby's "out of sequence" quirk: title footnotes are
|
|
16472
|
+
// numbered during parsing via apply_title_subs, then the counter restarts for body content.
|
|
16473
|
+
delete this.attributes['footnote-number'];
|
|
16474
|
+
delete this._counters['footnote-number'];
|
|
16311
16475
|
|
|
16312
16476
|
this._parsed = true;
|
|
16313
16477
|
return this
|
|
@@ -17282,6 +17446,10 @@ class Document extends AbstractBlock {
|
|
|
17282
17446
|
cell._innerDocument &&
|
|
17283
17447
|
cell._innerContent == null
|
|
17284
17448
|
) {
|
|
17449
|
+
// Recurse into the inner document first so that AsciiDoc cells
|
|
17450
|
+
// of any nested table have their content computed before the
|
|
17451
|
+
// inner document (and the nested table) is rendered.
|
|
17452
|
+
await this._convertAsciiDocCells(cell._innerDocument);
|
|
17285
17453
|
cell._innerContent = await cell._innerDocument.convert();
|
|
17286
17454
|
}
|
|
17287
17455
|
}
|
|
@@ -17362,12 +17530,33 @@ class Document extends AbstractBlock {
|
|
|
17362
17530
|
: ['attributes']
|
|
17363
17531
|
}
|
|
17364
17532
|
|
|
17533
|
+
/**
|
|
17534
|
+
* @private
|
|
17535
|
+
* Restore the document attributes to a previously captured snapshot, discarding any
|
|
17536
|
+
* body-level (re)assignments replayed while pre-computing text. Mirrors Ruby's
|
|
17537
|
+
* restore_attributes-before-convert invariant.
|
|
17538
|
+
* @param {Object} snapshot - The attributes snapshot to restore.
|
|
17539
|
+
*/
|
|
17540
|
+
_restoreAttributeSnapshot(snapshot) {
|
|
17541
|
+
for (const key of Reflect.ownKeys(this.attributes))
|
|
17542
|
+
delete this.attributes[key];
|
|
17543
|
+
Object.assign(this.attributes, snapshot);
|
|
17544
|
+
}
|
|
17545
|
+
|
|
17365
17546
|
/**
|
|
17366
17547
|
* @private
|
|
17367
17548
|
* Walk the block tree and pre-compute all async text values.
|
|
17368
17549
|
* Handles titles (AbstractBlock), list item text, table cell text, and reftexts.
|
|
17369
|
-
|
|
17370
|
-
|
|
17550
|
+
*
|
|
17551
|
+
* Runs in two passes (see {@link parse}): with `resolveContent` false only titles and
|
|
17552
|
+
* reftexts are substituted (so the reftext→id map can be built); with `resolveContent`
|
|
17553
|
+
* true the list item / table cell / dlist text is substituted, resolving any natural
|
|
17554
|
+
* cross-references against the now-complete map. Title/reftext pre-computation is
|
|
17555
|
+
* idempotent (results are cached), so running it in both passes is a no-op the second time.
|
|
17556
|
+
* @param {AbstractBlock} block - The block to resolve.
|
|
17557
|
+
* @param {boolean} resolveContent - Whether to substitute list item / cell / dlist text.
|
|
17558
|
+
*/
|
|
17559
|
+
async _resolveAllTexts(block, resolveContent) {
|
|
17371
17560
|
// Replay this block's attribute entries (in document order, since the walk is
|
|
17372
17561
|
// depth-first pre-order like conversion) so that body-level attribute assignments
|
|
17373
17562
|
// and reassignments are in scope when the block's — and its descendants' and later
|
|
@@ -17393,12 +17582,12 @@ class Document extends AbstractBlock {
|
|
|
17393
17582
|
// dlist.blocks is an array of [[term, ...], item_or_null] pairs.
|
|
17394
17583
|
for (const [terms, item] of block.blocks ?? []) {
|
|
17395
17584
|
for (const term of terms ?? []) {
|
|
17396
|
-
await term.precomputeText?.();
|
|
17397
|
-
await this._resolveAllTexts(term);
|
|
17585
|
+
if (resolveContent) await term.precomputeText?.();
|
|
17586
|
+
await this._resolveAllTexts(term, resolveContent);
|
|
17398
17587
|
}
|
|
17399
17588
|
if (item) {
|
|
17400
|
-
await item.precomputeText?.();
|
|
17401
|
-
await this._resolveAllTexts(item);
|
|
17589
|
+
if (resolveContent) await item.precomputeText?.();
|
|
17590
|
+
await this._resolveAllTexts(item, resolveContent);
|
|
17402
17591
|
}
|
|
17403
17592
|
}
|
|
17404
17593
|
} else if (ctx === 'table') {
|
|
@@ -17408,14 +17597,14 @@ class Document extends AbstractBlock {
|
|
|
17408
17597
|
...(block.rows?.foot ?? []),
|
|
17409
17598
|
]) {
|
|
17410
17599
|
for (const cell of row) {
|
|
17411
|
-
await cell.precomputeText?.();
|
|
17600
|
+
if (resolveContent) await cell.precomputeText?.();
|
|
17412
17601
|
await cell.precomputeReftext?.();
|
|
17413
17602
|
}
|
|
17414
17603
|
}
|
|
17415
17604
|
} else {
|
|
17416
17605
|
for (const child of block.blocks ?? []) {
|
|
17417
|
-
await child.precomputeText?.();
|
|
17418
|
-
await this._resolveAllTexts(child);
|
|
17606
|
+
if (resolveContent) await child.precomputeText?.();
|
|
17607
|
+
await this._resolveAllTexts(child, resolveContent);
|
|
17419
17608
|
}
|
|
17420
17609
|
}
|
|
17421
17610
|
}
|
|
@@ -17707,14 +17896,19 @@ class Document extends AbstractBlock {
|
|
|
17707
17896
|
let newBasebackend, newFiletype;
|
|
17708
17897
|
|
|
17709
17898
|
if (converter && typeof converter._getBackendTraits === 'function') {
|
|
17710
|
-
|
|
17711
|
-
|
|
17712
|
-
|
|
17899
|
+
// Read the traits object directly rather than the same-named accessor
|
|
17900
|
+
// methods. A user converter that declares flat string properties
|
|
17901
|
+
// (`converter.outfilesuffix = '.html'`, convention #2) keeps them intact,
|
|
17902
|
+
// so callers reading `converter.outfilesuffix` still see the string.
|
|
17903
|
+
const traits = converter._getBackendTraits();
|
|
17904
|
+
newBasebackend = traits.basebackend;
|
|
17905
|
+
newFiletype = traits.filetype;
|
|
17906
|
+
const htmlsyntax = traits.htmlsyntax;
|
|
17713
17907
|
if (htmlsyntax) attrs.htmlsyntax = htmlsyntax;
|
|
17714
17908
|
if (init) {
|
|
17715
|
-
attrs.outfilesuffix ??=
|
|
17909
|
+
attrs.outfilesuffix ??= traits.outfilesuffix;
|
|
17716
17910
|
} else if (!this.isAttributeLocked('outfilesuffix')) {
|
|
17717
|
-
attrs.outfilesuffix =
|
|
17911
|
+
attrs.outfilesuffix = traits.outfilesuffix;
|
|
17718
17912
|
}
|
|
17719
17913
|
} else if (converter) {
|
|
17720
17914
|
const traits = deriveBackendTraits(newBackend);
|
|
@@ -21025,7 +21219,7 @@ class Html5Converter extends ConverterBase {
|
|
|
21025
21219
|
let reproducible;
|
|
21026
21220
|
if (!(reproducible = node.hasAttribute('reproducible'))) {
|
|
21027
21221
|
result.push(
|
|
21028
|
-
`<meta name="generator" content="Asciidoctor ${node.getAttribute('asciidoctor-version')}"${slash}>`
|
|
21222
|
+
`<meta name="generator" content="Asciidoctor.js ${node.getAttribute('asciidoctor-version')}"${slash}>`
|
|
21029
21223
|
);
|
|
21030
21224
|
}
|
|
21031
21225
|
if (node.hasAttribute('app-name')) {
|
|
@@ -21742,7 +21936,9 @@ ${await node.content()}
|
|
|
21742
21936
|
const slash = this._voidSlash;
|
|
21743
21937
|
let img, src;
|
|
21744
21938
|
if (
|
|
21745
|
-
(node.hasAttribute('format', 'svg') ||
|
|
21939
|
+
(node.hasAttribute('format', 'svg') ||
|
|
21940
|
+
target.includes('.svg') ||
|
|
21941
|
+
target.startsWith('data:image/svg+xml')) &&
|
|
21746
21942
|
node.document.safe < SafeMode.SECURE
|
|
21747
21943
|
) {
|
|
21748
21944
|
if (node.hasOption('inline')) {
|
|
@@ -22583,7 +22779,9 @@ Your browser does not support the video tag.
|
|
|
22583
22779
|
if (node.hasAttribute('title'))
|
|
22584
22780
|
attrs += ` title="${node.getAttribute('title')}"`;
|
|
22585
22781
|
if (
|
|
22586
|
-
(node.hasAttribute('format', 'svg') ||
|
|
22782
|
+
(node.hasAttribute('format', 'svg') ||
|
|
22783
|
+
target.includes('.svg') ||
|
|
22784
|
+
target.startsWith('data:image/svg+xml')) &&
|
|
22587
22785
|
node.document.safe < SafeMode.SECURE
|
|
22588
22786
|
) {
|
|
22589
22787
|
if (node.hasOption('inline')) {
|
|
@@ -22676,12 +22874,17 @@ Your browser does not support the video tag.
|
|
|
22676
22874
|
|
|
22677
22875
|
// NOTE expose readSvgContents for Bespoke converter
|
|
22678
22876
|
async readSvgContents(node, target) {
|
|
22679
|
-
|
|
22680
|
-
|
|
22681
|
-
|
|
22682
|
-
|
|
22683
|
-
|
|
22684
|
-
|
|
22877
|
+
// A data-URI carries the SVG in the target itself (e.g. an embedded diagram
|
|
22878
|
+
// produced with `:data-uri:`), so decode it directly rather than trying to
|
|
22879
|
+
// read it as a file or remote URI.
|
|
22880
|
+
let svg = target.startsWith('data:')
|
|
22881
|
+
? this._decodeDataUri(target)
|
|
22882
|
+
: await node.readContents(target, {
|
|
22883
|
+
start: node.document.getAttribute('imagesdir'),
|
|
22884
|
+
normalize: true,
|
|
22885
|
+
label: 'SVG',
|
|
22886
|
+
warnIfEmpty: true,
|
|
22887
|
+
});
|
|
22685
22888
|
if (!svg) return null
|
|
22686
22889
|
if (!svg.startsWith('<svg')) svg = svg.replace(SvgPreambleRx, '');
|
|
22687
22890
|
// Fix incomplete SVG start tag (missing closing >) by inserting > before the first child element.
|
|
@@ -22713,6 +22916,27 @@ Your browser does not support the video tag.
|
|
|
22713
22916
|
|
|
22714
22917
|
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
22715
22918
|
|
|
22919
|
+
/**
|
|
22920
|
+
* Decode an inline `data:` URI to its text contents (e.g. an SVG document) so
|
|
22921
|
+
* an image whose target is a data-URI can be embedded inline. Supports both
|
|
22922
|
+
* Base64 (`;base64,`) and percent-encoded payloads. Returns null when the
|
|
22923
|
+
* payload is missing.
|
|
22924
|
+
*
|
|
22925
|
+
* @internal
|
|
22926
|
+
* @private
|
|
22927
|
+
*/
|
|
22928
|
+
_decodeDataUri(target) {
|
|
22929
|
+
const comma = target.indexOf(',');
|
|
22930
|
+
if (comma === -1) return null
|
|
22931
|
+
const meta = target.slice('data:'.length, comma);
|
|
22932
|
+
const data = target.slice(comma + 1);
|
|
22933
|
+
if (/;base64\b/i.test(meta)) {
|
|
22934
|
+
const bytes = Uint8Array.from(atob(data), (c) => c.charCodeAt(0));
|
|
22935
|
+
return new TextDecoder('utf-8').decode(bytes)
|
|
22936
|
+
}
|
|
22937
|
+
return decodeURIComponent(data)
|
|
22938
|
+
}
|
|
22939
|
+
|
|
22716
22940
|
/**
|
|
22717
22941
|
* @internal
|
|
22718
22942
|
* @private
|
|
@@ -22955,8 +23179,7 @@ const composite = /*#__PURE__*/Object.freeze({
|
|
|
22955
23179
|
// - Ruby File.directory?/File.file? → fsp.stat().isDirectory()/isFile() (async).
|
|
22956
23180
|
// - Ruby File.basename / File.expand_path → node:path basename / resolve.
|
|
22957
23181
|
// - PathResolver.system_path → pathResolver.systemPath().
|
|
22958
|
-
// - template.render(node, opts) → template.render({node, opts, helpers}).
|
|
22959
|
-
// - Helpers loaded from helpers.js/helpers.cjs; can export configure(enginesContext).
|
|
23182
|
+
// - template.render(node, opts) → template.render({node, opts, helpers}).// - Helpers loaded from helpers.js/helpers.cjs/helpers.mjs; can export configure(enginesContext).
|
|
22960
23183
|
// - Custom engines registered via TemplateConverter.TemplateEngine.register(ext, adapter).
|
|
22961
23184
|
// - Thread safety / Mutex → not needed (single-threaded JS).
|
|
22962
23185
|
// - load_eruby / eRuby support → not applicable in JS environment.
|
|
@@ -23230,7 +23453,11 @@ class TemplateConverter extends ConverterBase {
|
|
|
23230
23453
|
if (!(await _isFile(file))) continue
|
|
23231
23454
|
|
|
23232
23455
|
// Collect helpers separately; process after all templates.
|
|
23233
|
-
if (
|
|
23456
|
+
if (
|
|
23457
|
+
basename === 'helpers.js' ||
|
|
23458
|
+
basename === 'helpers.cjs' ||
|
|
23459
|
+
basename === 'helpers.mjs'
|
|
23460
|
+
) {
|
|
23234
23461
|
helpersFile = file;
|
|
23235
23462
|
continue
|
|
23236
23463
|
}
|
|
@@ -23298,8 +23525,8 @@ class TemplateConverter extends ConverterBase {
|
|
|
23298
23525
|
const pugOpts = { ...(this.engineOptions.pug ?? {}), filename: file };
|
|
23299
23526
|
const renderFn = pug.compileFile(file, pugOpts);
|
|
23300
23527
|
template = { render: renderFn, file };
|
|
23301
|
-
} else if (ext === 'js' || ext === 'cjs') {
|
|
23302
|
-
const renderFn =
|
|
23528
|
+
} else if (ext === 'js' || ext === 'cjs' || ext === 'mjs') {
|
|
23529
|
+
const renderFn = await _loadModule(file, ext);
|
|
23303
23530
|
template = { render: renderFn, file };
|
|
23304
23531
|
} else {
|
|
23305
23532
|
// Fall back to custom TemplateEngine registry.
|
|
@@ -23314,16 +23541,20 @@ class TemplateConverter extends ConverterBase {
|
|
|
23314
23541
|
result[name] = template;
|
|
23315
23542
|
}
|
|
23316
23543
|
|
|
23317
|
-
// Load helpers if found (or if a helpers
|
|
23318
|
-
|
|
23319
|
-
|
|
23320
|
-
|
|
23321
|
-
|
|
23322
|
-
|
|
23323
|
-
|
|
23544
|
+
// Load helpers if found (or if a helpers file exists at the top of the dir).
|
|
23545
|
+
if (!helpersFile) {
|
|
23546
|
+
for (const ext of ['js', 'cjs', 'mjs']) {
|
|
23547
|
+
const fallback = path.join(templateDir, `helpers.${ext}`);
|
|
23548
|
+
if (await _isFile(fallback)) {
|
|
23549
|
+
helpersFile = fallback;
|
|
23550
|
+
break
|
|
23551
|
+
}
|
|
23552
|
+
}
|
|
23553
|
+
}
|
|
23324
23554
|
|
|
23325
23555
|
if (helpersFile) {
|
|
23326
|
-
const
|
|
23556
|
+
const helpersExt = helpersFile.slice(helpersFile.lastIndexOf('.') + 1);
|
|
23557
|
+
const ctx = await _loadModule(helpersFile, helpersExt);
|
|
23327
23558
|
if (typeof ctx.configure === 'function') ctx.configure(enginesCtx);
|
|
23328
23559
|
result['helpers.js'] = { file: helpersFile, ctx };
|
|
23329
23560
|
}
|
|
@@ -23351,6 +23582,32 @@ class TemplateConverter extends ConverterBase {
|
|
|
23351
23582
|
|
|
23352
23583
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
23353
23584
|
|
|
23585
|
+
/**
|
|
23586
|
+
* Load a JavaScript module (template render function or helpers object) by
|
|
23587
|
+
* file extension.
|
|
23588
|
+
*
|
|
23589
|
+
* - `.cjs` files are always CommonJS: require() returns `module.exports`.
|
|
23590
|
+
* - `.js` and `.mjs` files are loaded with a dynamic `import()`, which Node
|
|
23591
|
+
* resolves as either ES modules or CommonJS. The export is taken from the
|
|
23592
|
+
* module's default export (`export default …` in ESM, `module.exports = …`
|
|
23593
|
+
* in CommonJS via interop); when there is no default export the module
|
|
23594
|
+
* namespace is returned instead, so ESM helpers exposing named exports
|
|
23595
|
+
* (`export function configure() {}`) work too.
|
|
23596
|
+
* @param {string} file - absolute path to the module file
|
|
23597
|
+
* @param {string} ext - file extension without the leading dot ('js' | 'cjs' | 'mjs')
|
|
23598
|
+
* @returns {Promise<*>} the module's default export, or its namespace
|
|
23599
|
+
* @internal
|
|
23600
|
+
* @private
|
|
23601
|
+
*/
|
|
23602
|
+
async function _loadModule(file, ext) {
|
|
23603
|
+
if (ext === 'cjs') {
|
|
23604
|
+
const mod = _require(file);
|
|
23605
|
+
return mod?.default ? mod.default : mod
|
|
23606
|
+
}
|
|
23607
|
+
const mod = await import(node_url.pathToFileURL(file).href);
|
|
23608
|
+
return mod.default ?? mod
|
|
23609
|
+
}
|
|
23610
|
+
|
|
23354
23611
|
/**
|
|
23355
23612
|
* @internal
|
|
23356
23613
|
* @private
|
|
@@ -24539,7 +24796,7 @@ class ManPageConverter extends ConverterBase {
|
|
|
24539
24796
|
`'\\" t
|
|
24540
24797
|
.\\" Title: ${mantitle}
|
|
24541
24798
|
.\\" Author: ${node.hasAttribute('authors') ? node.getAttribute('authors') : '[see the "AUTHOR(S)" section]'}
|
|
24542
|
-
.\\" Generator: Asciidoctor ${node.getAttribute('asciidoctor-version')}`,
|
|
24799
|
+
.\\" Generator: Asciidoctor.js ${node.getAttribute('asciidoctor-version')}`,
|
|
24543
24800
|
];
|
|
24544
24801
|
|
|
24545
24802
|
if (docdate) result.push(`.\\" Date: ${docdate}`);
|