@asciidoctor/core 4.0.0-alpha.1 → 4.0.0-alpha.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 +423 -45
- package/build/node/index.cjs +424 -46
- package/package.json +11 -5
- package/src/abstract_block.js +11 -3
- package/src/attribute_entry.js +17 -1
- package/src/browser/reader.js +2 -2
- package/src/converter/html5.js +2 -8
- package/src/converter/template.js +1 -1
- package/src/document.js +15 -4
- package/src/extensions.js +266 -8
- package/src/helpers.js +20 -2
- package/src/index.js +12 -0
- package/src/load.js +30 -13
- package/src/logging.js +65 -5
- package/src/parser.js +1 -1
- package/src/reader.js +1 -1
- package/types/abstract_block.d.ts +5 -2
- package/types/attribute_entry.d.ts +8 -0
- package/types/browser/reader.d.ts +1 -1
- package/types/extensions.d.ts +203 -9
- package/types/index.d.cts +83 -0
- package/types/index.d.ts +8 -0
- package/types/logging.d.ts +15 -4
package/build/browser/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var version = "4.0.0-alpha.
|
|
1
|
+
var version = "4.0.0-alpha.3";
|
|
2
2
|
const packageJson = {
|
|
3
3
|
version: version};
|
|
4
4
|
|
|
@@ -1507,6 +1507,65 @@ function resolveSeverity(severity) {
|
|
|
1507
1507
|
return severity ?? Severity.UNKNOWN
|
|
1508
1508
|
}
|
|
1509
1509
|
|
|
1510
|
+
// ── Per-execution logger context ─────────────────────────────────────────────
|
|
1511
|
+
|
|
1512
|
+
// Holds an AsyncLocalStorage instance once it is lazily initialised.
|
|
1513
|
+
// Allows per-execution logger isolation without mutating the global singleton,
|
|
1514
|
+
// making concurrent test execution (e.g. Deno's node:test) safe.
|
|
1515
|
+
let _loggerStore = null;
|
|
1516
|
+
|
|
1517
|
+
// Promise singleton — ensures AsyncLocalStorage is initialised at most once.
|
|
1518
|
+
let _loggerStorePromise = null;
|
|
1519
|
+
|
|
1520
|
+
/**
|
|
1521
|
+
* Lazily initialise an AsyncLocalStorage for per-execution logger context.
|
|
1522
|
+
* Falls back to null in environments that do not support node:async_hooks (e.g. browsers).
|
|
1523
|
+
* @returns {Promise<import('node:async_hooks').AsyncLocalStorage|null>}
|
|
1524
|
+
*/
|
|
1525
|
+
async function _ensureLoggerStore() {
|
|
1526
|
+
if (_loggerStorePromise === null) {
|
|
1527
|
+
_loggerStorePromise = import('node:async_hooks')
|
|
1528
|
+
.then(({ AsyncLocalStorage }) => {
|
|
1529
|
+
const store = new AsyncLocalStorage();
|
|
1530
|
+
_loggerStore = store;
|
|
1531
|
+
return store
|
|
1532
|
+
})
|
|
1533
|
+
.catch(() => null);
|
|
1534
|
+
}
|
|
1535
|
+
return _loggerStorePromise
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/** @internal — returns the logger bound to the current async context, or null */
|
|
1539
|
+
function getContextLogger() {
|
|
1540
|
+
return _loggerStore?.getStore() ?? null
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
/**
|
|
1544
|
+
* Run fn() within an async-local logger context so that all log calls via
|
|
1545
|
+
* `this.logger` (from applyLogging) automatically route to the provided logger
|
|
1546
|
+
* for the duration of the async execution chain.
|
|
1547
|
+
*
|
|
1548
|
+
* Falls back to global mutation in environments without node:async_hooks (e.g. browsers).
|
|
1549
|
+
*
|
|
1550
|
+
* @param {Logger|MemoryLogger|NullLogger} logger - The logger to activate.
|
|
1551
|
+
* @param {() => any} fn - The function to execute within the logger context.
|
|
1552
|
+
* @returns {Promise<any>}
|
|
1553
|
+
*/
|
|
1554
|
+
async function withLogger(logger, fn) {
|
|
1555
|
+
const store = await _ensureLoggerStore();
|
|
1556
|
+
if (store) {
|
|
1557
|
+
return store.run(logger, fn)
|
|
1558
|
+
}
|
|
1559
|
+
// Fallback for environments without node:async_hooks (browsers).
|
|
1560
|
+
const prev = LoggerManager.logger;
|
|
1561
|
+
if (logger !== prev) LoggerManager.logger = logger;
|
|
1562
|
+
try {
|
|
1563
|
+
return await fn()
|
|
1564
|
+
} finally {
|
|
1565
|
+
if (logger !== prev) LoggerManager.logger = prev;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1510
1569
|
// ── Logger ────────────────────────────────────────────────────────────────────
|
|
1511
1570
|
|
|
1512
1571
|
/** Standard logger that writes formatted messages to stderr or a custom pipe. */
|
|
@@ -1815,8 +1874,9 @@ class MemoryLogger {
|
|
|
1815
1874
|
// ── NullLogger ────────────────────────────────────────────────────────────────
|
|
1816
1875
|
|
|
1817
1876
|
/** Logger that discards all messages but still tracks the maximum severity. */
|
|
1818
|
-
class NullLogger {
|
|
1877
|
+
class NullLogger extends Logger {
|
|
1819
1878
|
constructor() {
|
|
1879
|
+
super();
|
|
1820
1880
|
this.level = Severity.UNKNOWN;
|
|
1821
1881
|
this._maxSeverity = null;
|
|
1822
1882
|
}
|
|
@@ -1961,12 +2021,12 @@ const LoggerManager = (() => {
|
|
|
1961
2021
|
function applyLogging(proto) {
|
|
1962
2022
|
Object.defineProperty(proto, 'logger', {
|
|
1963
2023
|
get() {
|
|
1964
|
-
return LoggerManager.logger
|
|
2024
|
+
return _loggerStore?.getStore() ?? LoggerManager.logger
|
|
1965
2025
|
},
|
|
1966
2026
|
configurable: true,
|
|
1967
2027
|
});
|
|
1968
2028
|
|
|
1969
|
-
proto.getLogger = () => LoggerManager.logger;
|
|
2029
|
+
proto.getLogger = () => _loggerStore?.getStore() ?? LoggerManager.logger;
|
|
1970
2030
|
|
|
1971
2031
|
proto.messageWithContext = (text, context = {}) =>
|
|
1972
2032
|
Logger.AutoFormattingMessage.attach({ text, ...context });
|
|
@@ -2013,7 +2073,16 @@ const rstrip = (line) => line.replace(/[ \t\r\n\f\v]+$/, '');
|
|
|
2013
2073
|
*/
|
|
2014
2074
|
function prepareSourceArray(data, trimEnd = true) {
|
|
2015
2075
|
if (!data.length) return []
|
|
2016
|
-
if (data[0].startsWith(BOM))
|
|
2076
|
+
if (data[0].startsWith(BOM)) {
|
|
2077
|
+
data[0] = data[0].slice(1);
|
|
2078
|
+
} else if (
|
|
2079
|
+
data[0].charCodeAt(0) === 0xef &&
|
|
2080
|
+
data[0].charCodeAt(1) === 0xbb &&
|
|
2081
|
+
data[0].charCodeAt(2) === 0xbf
|
|
2082
|
+
) {
|
|
2083
|
+
// Strip UTF-8 BOM encoded as three raw characters ( / \xEF\xBB\xBF) if not already decoded to U+FEFF
|
|
2084
|
+
data[0] = data[0].slice(3);
|
|
2085
|
+
}
|
|
2017
2086
|
// Strip trailing \r to normalize Windows CRLF line endings (lines were split on \n, leaving \r).
|
|
2018
2087
|
return trimEnd
|
|
2019
2088
|
? data.map(rstrip)
|
|
@@ -2033,7 +2102,16 @@ function prepareSourceArray(data, trimEnd = true) {
|
|
|
2033
2102
|
*/
|
|
2034
2103
|
function prepareSourceString(data, trimEnd = true) {
|
|
2035
2104
|
if (!data) return []
|
|
2036
|
-
if (data.startsWith(BOM))
|
|
2105
|
+
if (data.startsWith(BOM)) {
|
|
2106
|
+
data = data.slice(1);
|
|
2107
|
+
} else if (
|
|
2108
|
+
data.charCodeAt(0) === 0xef &&
|
|
2109
|
+
data.charCodeAt(1) === 0xbb &&
|
|
2110
|
+
data.charCodeAt(2) === 0xbf
|
|
2111
|
+
) {
|
|
2112
|
+
// Strip UTF-8 BOM encoded as three raw characters ( / \xEF\xBB\xBF) if not already decoded to U+FEFF
|
|
2113
|
+
data = data.slice(3);
|
|
2114
|
+
}
|
|
2037
2115
|
// Normalize Windows CRLF to LF so that split('\n') does not leave trailing \r on each line.
|
|
2038
2116
|
if (data.includes('\r'))
|
|
2039
2117
|
data = data.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
@@ -3743,7 +3821,7 @@ class AbstractBlock extends AbstractNode {
|
|
|
3743
3821
|
* - `'reject'` → skip the node and its children
|
|
3744
3822
|
* - `'stop'` → include the node (if it matched) and stop the entire traversal
|
|
3745
3823
|
*
|
|
3746
|
-
* @param {Object} [selector={}] - Selector criteria object
|
|
3824
|
+
* @param {Object|Function} [selector={}] - Selector criteria object, or a filter callback when called as `findBy(callback)`.
|
|
3747
3825
|
* @param {Function|null} [filter=null] - Per-node filter callback.
|
|
3748
3826
|
* @returns {AbstractBlock[]} array of matching block-level nodes.
|
|
3749
3827
|
*
|
|
@@ -3758,6 +3836,9 @@ class AbstractBlock extends AbstractNode {
|
|
|
3758
3836
|
*
|
|
3759
3837
|
* @example <caption>All image blocks including those inside AsciiDoc table cells</caption>
|
|
3760
3838
|
* const images = doc.findBy({ context: 'image', traverseDocuments: true })
|
|
3839
|
+
*
|
|
3840
|
+
* @example <caption>Filter-only shorthand (no selector)</caption>
|
|
3841
|
+
* const verbatim = doc.findBy((b) => b.contentModel === ContentModel.VERBATIM)
|
|
3761
3842
|
*/
|
|
3762
3843
|
findBy(selector = {}, filter = null) {
|
|
3763
3844
|
const result = [];
|
|
@@ -3766,8 +3847,13 @@ class AbstractBlock extends AbstractNode {
|
|
|
3766
3847
|
selector && typeof selector === 'object' && !Array.isArray(selector)
|
|
3767
3848
|
? selector
|
|
3768
3849
|
: {};
|
|
3769
|
-
// Normalise:
|
|
3770
|
-
const normFilter =
|
|
3850
|
+
// Normalise: support findBy(callback) shorthand — selector is the filter when it's a function.
|
|
3851
|
+
const normFilter =
|
|
3852
|
+
typeof filter === 'function'
|
|
3853
|
+
? filter
|
|
3854
|
+
: typeof selector === 'function'
|
|
3855
|
+
? selector
|
|
3856
|
+
: null;
|
|
3771
3857
|
try {
|
|
3772
3858
|
this.#findByInternal(normSelector, result, normFilter);
|
|
3773
3859
|
} catch (e) {
|
|
@@ -5957,7 +6043,7 @@ const SyntaxHighlighter = new DefaultFactory();
|
|
|
5957
6043
|
//
|
|
5958
6044
|
// This logic is specific to Asciidoctor.js and has no equivalent in the upstream Ruby asciidoctor
|
|
5959
6045
|
// implementation. It handles the case where the document is loaded in a browser environment
|
|
5960
|
-
//
|
|
6046
|
+
// where paths can be file:// or http(s):// URIs.
|
|
5961
6047
|
//
|
|
5962
6048
|
// The key behavioural differences from the standard file-system resolver:
|
|
5963
6049
|
// - Relative targets are resolved by string concatenation against a URI context dir,
|
|
@@ -6006,7 +6092,7 @@ function _linkReplacement(reader, target, attrlist) {
|
|
|
6006
6092
|
* 1. target starts with file:// → inc_path = relpath = target
|
|
6007
6093
|
* 2. target is a URI → must descend from baseDir or allow-uri-read; else → link
|
|
6008
6094
|
* 3. target is an absolute OS path → prepend file:// (or file:///)
|
|
6009
|
-
* 4. baseDir == '.' → inc_path = relpath = target (resolved by
|
|
6095
|
+
* 4. baseDir == '.' → inc_path = relpath = target (resolved by fetch)
|
|
6010
6096
|
* 5. baseDir starts with file:// OR baseDir is not a URI → inc_path = baseDir/target; relpath = target
|
|
6011
6097
|
* 6. baseDir is an absolute URL → inc_path = baseDir/target; relpath = target
|
|
6012
6098
|
*
|
|
@@ -6728,7 +6814,7 @@ class Reader {
|
|
|
6728
6814
|
return this.source()
|
|
6729
6815
|
}
|
|
6730
6816
|
getLogger() {
|
|
6731
|
-
return LoggerManager.logger
|
|
6817
|
+
return this._document?.logger ?? LoggerManager.logger
|
|
6732
6818
|
}
|
|
6733
6819
|
createLogMessage(text, context = {}) {
|
|
6734
6820
|
return Logger.AutoFormattingMessage.attach({ text, ...context })
|
|
@@ -9553,6 +9639,22 @@ class AttributeList {
|
|
|
9553
9639
|
}
|
|
9554
9640
|
}
|
|
9555
9641
|
|
|
9642
|
+
// Symbol key used to store attribute entries on a block-attributes object without
|
|
9643
|
+
// polluting the public attributes (invisible to Object.keys / for-in / JSON.stringify).
|
|
9644
|
+
// Spread ({ ...attrs }) copies Symbol-keyed properties, so the entry survives the
|
|
9645
|
+
// shallow clone made in AbstractNode's constructor.
|
|
9646
|
+
const ATTR_ENTRIES_KEY = Symbol('attribute_entries');
|
|
9647
|
+
|
|
9648
|
+
/**
|
|
9649
|
+
* Return the attribute entries stored for the given block attributes object,
|
|
9650
|
+
* or undefined if none have been saved.
|
|
9651
|
+
* @param {Object} blockAttributes
|
|
9652
|
+
* @returns {AttributeEntry[]|undefined}
|
|
9653
|
+
*/
|
|
9654
|
+
function getAttributeEntries(blockAttributes) {
|
|
9655
|
+
return blockAttributes[ATTR_ENTRIES_KEY]
|
|
9656
|
+
}
|
|
9657
|
+
|
|
9556
9658
|
class AttributeEntry {
|
|
9557
9659
|
constructor(name, value, negate = null) {
|
|
9558
9660
|
this.name = name;
|
|
@@ -9561,7 +9663,7 @@ class AttributeEntry {
|
|
|
9561
9663
|
}
|
|
9562
9664
|
|
|
9563
9665
|
saveTo(blockAttributes) {
|
|
9564
|
-
(blockAttributes
|
|
9666
|
+
(blockAttributes[ATTR_ENTRIES_KEY] ??= []).push(this);
|
|
9565
9667
|
return this
|
|
9566
9668
|
}
|
|
9567
9669
|
}
|
|
@@ -11036,7 +11138,7 @@ class Parser {
|
|
|
11036
11138
|
const Rdr = Reader;
|
|
11037
11139
|
const result = await extension.processMethod(
|
|
11038
11140
|
parent,
|
|
11039
|
-
blockReader ?? new Rdr(lines),
|
|
11141
|
+
blockReader ?? new Rdr(lines, null, { document: parent.document }),
|
|
11040
11142
|
{ ...attributes }
|
|
11041
11143
|
);
|
|
11042
11144
|
if (!result || result === parent) return null
|
|
@@ -13158,6 +13260,94 @@ function _uniform(str, chr, len) {
|
|
|
13158
13260
|
// references; they will be resolved when those modules implement the methods.
|
|
13159
13261
|
|
|
13160
13262
|
|
|
13263
|
+
// Type-only imports for JSDoc
|
|
13264
|
+
/**
|
|
13265
|
+
* @typedef {import('./document.js').Document} Document
|
|
13266
|
+
* @typedef {import('./abstract_block.js').AbstractBlock} AbstractBlock
|
|
13267
|
+
*/
|
|
13268
|
+
|
|
13269
|
+
// ── DSL interface types ───────────────────────────────────────────────────────
|
|
13270
|
+
|
|
13271
|
+
/**
|
|
13272
|
+
* DSL interface for configuring a {@link Processor} instance.
|
|
13273
|
+
* Applied to a processor instance via `Object.assign(instance, DslMixin)`.
|
|
13274
|
+
*
|
|
13275
|
+
* The `process` property behaves as a setter when called with a single Function
|
|
13276
|
+
* argument (stores the process block), or as a passthrough caller otherwise.
|
|
13277
|
+
*
|
|
13278
|
+
* @typedef {object} ProcessorDslInterface
|
|
13279
|
+
* @property {(key: string, value: unknown) => void} option - Set a config option.
|
|
13280
|
+
* @property {(fn: (...args: unknown[]) => unknown) => void} process - Register the process function.
|
|
13281
|
+
* @property {() => boolean} processBlockGiven - Returns true if a process function has been registered.
|
|
13282
|
+
*/
|
|
13283
|
+
|
|
13284
|
+
/**
|
|
13285
|
+
* DSL interface for document processors (Preprocessor, TreeProcessor, Postprocessor, DocinfoProcessor).
|
|
13286
|
+
*
|
|
13287
|
+
* @typedef {ProcessorDslInterface & { prefer(): void; prepend(): void }} DocumentProcessorDslInterface
|
|
13288
|
+
*/
|
|
13289
|
+
|
|
13290
|
+
/**
|
|
13291
|
+
* DSL interface for syntax processors (BlockProcessor, BlockMacroProcessor, InlineMacroProcessor).
|
|
13292
|
+
*
|
|
13293
|
+
* @typedef {ProcessorDslInterface & {
|
|
13294
|
+
* named(value: string): void;
|
|
13295
|
+
* contentModel(value: string): void;
|
|
13296
|
+
* parseContentAs(value: string): void;
|
|
13297
|
+
* positionalAttributes(...value: string[]): void;
|
|
13298
|
+
* namePositionalAttributes(...value: string[]): void;
|
|
13299
|
+
* positionalAttrs(...value: string[]): void;
|
|
13300
|
+
* defaultAttributes(value: Record<string, string>): void;
|
|
13301
|
+
* defaultAttrs(value: Record<string, string>): void;
|
|
13302
|
+
* resolveAttributes(...args: unknown[]): void;
|
|
13303
|
+
* resolvesAttributes(...args: unknown[]): void;
|
|
13304
|
+
* }} SyntaxProcessorDslInterface
|
|
13305
|
+
*/
|
|
13306
|
+
|
|
13307
|
+
/**
|
|
13308
|
+
* DSL interface for include processors.
|
|
13309
|
+
*
|
|
13310
|
+
* @typedef {DocumentProcessorDslInterface & {
|
|
13311
|
+
* handles(fn: (doc: Document, target: string) => boolean): void;
|
|
13312
|
+
* }} IncludeProcessorDslInterface
|
|
13313
|
+
*/
|
|
13314
|
+
|
|
13315
|
+
/**
|
|
13316
|
+
* DSL interface for docinfo processors.
|
|
13317
|
+
*
|
|
13318
|
+
* @typedef {DocumentProcessorDslInterface & {
|
|
13319
|
+
* atLocation(value: string): void;
|
|
13320
|
+
* }} DocinfoProcessorDslInterface
|
|
13321
|
+
*/
|
|
13322
|
+
|
|
13323
|
+
/**
|
|
13324
|
+
* DSL interface for block processors.
|
|
13325
|
+
*
|
|
13326
|
+
* @typedef {SyntaxProcessorDslInterface & {
|
|
13327
|
+
* contexts(...value: (string | string[])[]): void;
|
|
13328
|
+
* onContexts(...value: (string | string[])[]): void;
|
|
13329
|
+
* onContext(...value: (string | string[])[]): void;
|
|
13330
|
+
* bindTo(...value: (string | string[])[]): void;
|
|
13331
|
+
* }} BlockProcessorDslInterface
|
|
13332
|
+
*/
|
|
13333
|
+
|
|
13334
|
+
/**
|
|
13335
|
+
* DSL interface for macro processors (block and inline macros).
|
|
13336
|
+
*
|
|
13337
|
+
* @typedef {SyntaxProcessorDslInterface} MacroProcessorDslInterface
|
|
13338
|
+
*/
|
|
13339
|
+
|
|
13340
|
+
/**
|
|
13341
|
+
* DSL interface for inline macro processors.
|
|
13342
|
+
*
|
|
13343
|
+
* @typedef {MacroProcessorDslInterface & {
|
|
13344
|
+
* format(value: string): void;
|
|
13345
|
+
* matchFormat(value: string): void;
|
|
13346
|
+
* usingFormat(value: string): void;
|
|
13347
|
+
* match(value: RegExp): void;
|
|
13348
|
+
* }} InlineMacroProcessorDslInterface
|
|
13349
|
+
*/
|
|
13350
|
+
|
|
13161
13351
|
// ── DSL Mixins ────────────────────────────────────────────────────────────────
|
|
13162
13352
|
|
|
13163
13353
|
/**
|
|
@@ -13753,7 +13943,12 @@ class Processor {
|
|
|
13753
13943
|
* Extensions.register(function () { this.preprocessor(CommentStripPreprocessor) })
|
|
13754
13944
|
*/
|
|
13755
13945
|
class Preprocessor extends Processor {
|
|
13756
|
-
|
|
13946
|
+
/**
|
|
13947
|
+
* @param {Document} document - The document being parsed.
|
|
13948
|
+
* @param {Reader} reader - The reader positioned at the beginning of the source.
|
|
13949
|
+
* @returns {Reader|undefined} The same or a substitute Reader, or undefined to use the original.
|
|
13950
|
+
*/
|
|
13951
|
+
process(document, reader) {
|
|
13757
13952
|
throw new Error(
|
|
13758
13953
|
`${this.constructor.name} must implement the process method`
|
|
13759
13954
|
)
|
|
@@ -13778,7 +13973,11 @@ Preprocessor.DSL = DocumentProcessorDsl;
|
|
|
13778
13973
|
* Extensions.register(function () { this.treeProcessor(ShoutTreeProcessor) })
|
|
13779
13974
|
*/
|
|
13780
13975
|
class TreeProcessor extends Processor {
|
|
13781
|
-
|
|
13976
|
+
/**
|
|
13977
|
+
* @param {Document} document - The parsed document.
|
|
13978
|
+
* @returns {void}
|
|
13979
|
+
*/
|
|
13980
|
+
process(document) {
|
|
13782
13981
|
throw new Error(
|
|
13783
13982
|
`${this.constructor.name} must implement the process method`
|
|
13784
13983
|
)
|
|
@@ -13804,7 +14003,12 @@ TreeProcessor.DSL = DocumentProcessorDsl;
|
|
|
13804
14003
|
* Extensions.register(function () { this.postprocessor(FooterPostprocessor) })
|
|
13805
14004
|
*/
|
|
13806
14005
|
class Postprocessor extends Processor {
|
|
13807
|
-
|
|
14006
|
+
/**
|
|
14007
|
+
* @param {Document} document - The converted document.
|
|
14008
|
+
* @param {string} output - The converted output string.
|
|
14009
|
+
* @returns {string} The (possibly modified) output string.
|
|
14010
|
+
*/
|
|
14011
|
+
process(document, output) {
|
|
13808
14012
|
throw new Error(
|
|
13809
14013
|
`${this.constructor.name} must implement the process method`
|
|
13810
14014
|
)
|
|
@@ -13818,13 +14022,25 @@ Postprocessor.DSL = DocumentProcessorDsl;
|
|
|
13818
14022
|
* Implementations must extend IncludeProcessor.
|
|
13819
14023
|
*/
|
|
13820
14024
|
class IncludeProcessor extends Processor {
|
|
13821
|
-
|
|
14025
|
+
/**
|
|
14026
|
+
* @param {Document} document - The document being parsed.
|
|
14027
|
+
* @param {Reader} reader - The reader for the including document.
|
|
14028
|
+
* @param {string} target - The target of the include directive.
|
|
14029
|
+
* @param {Record<string, string>} attributes - The parsed include attributes.
|
|
14030
|
+
* @returns {void}
|
|
14031
|
+
*/
|
|
14032
|
+
process(document, reader, target, attributes) {
|
|
13822
14033
|
throw new Error(
|
|
13823
14034
|
`${this.constructor.name} must implement the process method`
|
|
13824
14035
|
)
|
|
13825
14036
|
}
|
|
13826
14037
|
|
|
13827
|
-
|
|
14038
|
+
/**
|
|
14039
|
+
* @param {Document} doc - The document being parsed.
|
|
14040
|
+
* @param {string} target - The target of the include directive.
|
|
14041
|
+
* @returns {boolean} true if this processor handles the given target.
|
|
14042
|
+
*/
|
|
14043
|
+
handles(doc, target) {
|
|
13828
14044
|
return true
|
|
13829
14045
|
}
|
|
13830
14046
|
}
|
|
@@ -13842,7 +14058,11 @@ class DocinfoProcessor extends Processor {
|
|
|
13842
14058
|
this.config.location ??= 'head';
|
|
13843
14059
|
}
|
|
13844
14060
|
|
|
13845
|
-
|
|
14061
|
+
/**
|
|
14062
|
+
* @param {Document} document - The document being converted.
|
|
14063
|
+
* @returns {string} The docinfo content to inject into the document.
|
|
14064
|
+
*/
|
|
14065
|
+
process(document) {
|
|
13846
14066
|
throw new Error(
|
|
13847
14067
|
`${this.constructor.name} must implement the process method`
|
|
13848
14068
|
)
|
|
@@ -13898,7 +14118,13 @@ class BlockProcessor extends Processor {
|
|
|
13898
14118
|
this.config.content_model ??= 'compound';
|
|
13899
14119
|
}
|
|
13900
14120
|
|
|
13901
|
-
|
|
14121
|
+
/**
|
|
14122
|
+
* @param {AbstractBlock} parent - The enclosing block.
|
|
14123
|
+
* @param {Reader} reader - The reader positioned at the block content.
|
|
14124
|
+
* @param {Record<string, unknown>} attributes - The parsed block attributes.
|
|
14125
|
+
* @returns {Block|void} A block node, or void to let the parser handle it.
|
|
14126
|
+
*/
|
|
14127
|
+
process(parent, reader, attributes) {
|
|
13902
14128
|
throw new Error(
|
|
13903
14129
|
`${this.constructor.name} must implement the process method`
|
|
13904
14130
|
)
|
|
@@ -13916,7 +14142,13 @@ class MacroProcessor extends Processor {
|
|
|
13916
14142
|
this.config.content_model ??= 'attributes';
|
|
13917
14143
|
}
|
|
13918
14144
|
|
|
13919
|
-
|
|
14145
|
+
/**
|
|
14146
|
+
* @param {AbstractBlock} parent - The enclosing block.
|
|
14147
|
+
* @param {string} target - The macro target (text between `name:` and `[`).
|
|
14148
|
+
* @param {Record<string, unknown>} attributes - The parsed macro attributes.
|
|
14149
|
+
* @returns {Block|Inline|void}
|
|
14150
|
+
*/
|
|
14151
|
+
process(parent, target, attributes) {
|
|
13920
14152
|
throw new Error(
|
|
13921
14153
|
`${this.constructor.name} must implement the process method`
|
|
13922
14154
|
)
|
|
@@ -13962,6 +14194,16 @@ class BlockMacroProcessor extends MacroProcessor {
|
|
|
13962
14194
|
set name(value) {
|
|
13963
14195
|
this._name = value;
|
|
13964
14196
|
}
|
|
14197
|
+
|
|
14198
|
+
/**
|
|
14199
|
+
* @param {AbstractBlock} parent - The enclosing block.
|
|
14200
|
+
* @param {string} target - The macro target.
|
|
14201
|
+
* @param {Record<string, unknown>} attributes - The parsed macro attributes.
|
|
14202
|
+
* @returns {Block} A block node created with one of the `createBlock` helpers.
|
|
14203
|
+
*/
|
|
14204
|
+
process(parent, target, attributes) {
|
|
14205
|
+
return super.process(parent, target, attributes)
|
|
14206
|
+
}
|
|
13965
14207
|
}
|
|
13966
14208
|
BlockMacroProcessor.DSL = MacroProcessorDsl;
|
|
13967
14209
|
|
|
@@ -14005,6 +14247,16 @@ class InlineMacroProcessor extends MacroProcessor {
|
|
|
14005
14247
|
))
|
|
14006
14248
|
}
|
|
14007
14249
|
|
|
14250
|
+
/**
|
|
14251
|
+
* @param {AbstractBlock} parent - The enclosing block.
|
|
14252
|
+
* @param {string} target - The macro target.
|
|
14253
|
+
* @param {Record<string, unknown>} attributes - The parsed macro attributes.
|
|
14254
|
+
* @returns {Inline} An Inline node created with `this.createInline(...)`.
|
|
14255
|
+
*/
|
|
14256
|
+
process(parent, target, attributes) {
|
|
14257
|
+
return super.process(parent, target, attributes)
|
|
14258
|
+
}
|
|
14259
|
+
|
|
14008
14260
|
resolveRegexp(name, format) {
|
|
14009
14261
|
if (!MacroNameRx.test(name)) {
|
|
14010
14262
|
throw new Error(`invalid name for inline macro: ${name}`)
|
|
@@ -14368,6 +14620,15 @@ class Registry {
|
|
|
14368
14620
|
return !!this._block_extensions
|
|
14369
14621
|
}
|
|
14370
14622
|
|
|
14623
|
+
/**
|
|
14624
|
+
* Retrieve all BlockProcessor Extension proxy objects.
|
|
14625
|
+
*
|
|
14626
|
+
* @returns {ProcessorExtension[]}
|
|
14627
|
+
*/
|
|
14628
|
+
blocks() {
|
|
14629
|
+
return this._block_extensions ? Object.values(this._block_extensions) : []
|
|
14630
|
+
}
|
|
14631
|
+
|
|
14371
14632
|
/**
|
|
14372
14633
|
* Check whether a BlockProcessor is registered for the given name and context.
|
|
14373
14634
|
*
|
|
@@ -14414,6 +14675,17 @@ class Registry {
|
|
|
14414
14675
|
return !!this._block_macro_extensions
|
|
14415
14676
|
}
|
|
14416
14677
|
|
|
14678
|
+
/**
|
|
14679
|
+
* Retrieve all BlockMacroProcessor Extension proxy objects.
|
|
14680
|
+
*
|
|
14681
|
+
* @returns {ProcessorExtension[]}
|
|
14682
|
+
*/
|
|
14683
|
+
blockMacros() {
|
|
14684
|
+
return this._block_macro_extensions
|
|
14685
|
+
? Object.values(this._block_macro_extensions)
|
|
14686
|
+
: []
|
|
14687
|
+
}
|
|
14688
|
+
|
|
14417
14689
|
/**
|
|
14418
14690
|
* Check whether a BlockMacroProcessor is registered for the given name.
|
|
14419
14691
|
*
|
|
@@ -14519,6 +14791,85 @@ class Registry {
|
|
|
14519
14791
|
return extension
|
|
14520
14792
|
}
|
|
14521
14793
|
|
|
14794
|
+
// ── JavaScript-style accessors ───────────────────────────────────────────────
|
|
14795
|
+
|
|
14796
|
+
/** @returns {object} the plain Object that maps names to groups for this registry. */
|
|
14797
|
+
getGroups() {
|
|
14798
|
+
return this.groups
|
|
14799
|
+
}
|
|
14800
|
+
|
|
14801
|
+
/** Alias for {@link preprocessors}. */
|
|
14802
|
+
getPreprocessors() {
|
|
14803
|
+
return this.preprocessors()
|
|
14804
|
+
}
|
|
14805
|
+
|
|
14806
|
+
/** Alias for {@link treeProcessors}. */
|
|
14807
|
+
getTreeProcessors() {
|
|
14808
|
+
return this.treeProcessors()
|
|
14809
|
+
}
|
|
14810
|
+
|
|
14811
|
+
/** Alias for {@link includeProcessors}. */
|
|
14812
|
+
getIncludeProcessors() {
|
|
14813
|
+
return this.includeProcessors()
|
|
14814
|
+
}
|
|
14815
|
+
|
|
14816
|
+
/** Alias for {@link postprocessors}. */
|
|
14817
|
+
getPostprocessors() {
|
|
14818
|
+
return this.postprocessors()
|
|
14819
|
+
}
|
|
14820
|
+
|
|
14821
|
+
/**
|
|
14822
|
+
* Alias for {@link docinfoProcessors}.
|
|
14823
|
+
*
|
|
14824
|
+
* @param {string|null} [location=null]
|
|
14825
|
+
*/
|
|
14826
|
+
getDocinfoProcessors(location = null) {
|
|
14827
|
+
return this.docinfoProcessors(location)
|
|
14828
|
+
}
|
|
14829
|
+
|
|
14830
|
+
/** Alias for {@link blocks}. */
|
|
14831
|
+
getBlocks() {
|
|
14832
|
+
return this.blocks()
|
|
14833
|
+
}
|
|
14834
|
+
|
|
14835
|
+
/** Alias for {@link blockMacros}. */
|
|
14836
|
+
getBlockMacros() {
|
|
14837
|
+
return this.blockMacros()
|
|
14838
|
+
}
|
|
14839
|
+
|
|
14840
|
+
/** Alias for {@link inlineMacros}. */
|
|
14841
|
+
getInlineMacros() {
|
|
14842
|
+
return this.inlineMacros()
|
|
14843
|
+
}
|
|
14844
|
+
|
|
14845
|
+
/**
|
|
14846
|
+
* Alias for {@link registeredForInlineMacro}.
|
|
14847
|
+
*
|
|
14848
|
+
* @param {string} name
|
|
14849
|
+
*/
|
|
14850
|
+
getInlineMacroFor(name) {
|
|
14851
|
+
return this.registeredForInlineMacro(name)
|
|
14852
|
+
}
|
|
14853
|
+
|
|
14854
|
+
/**
|
|
14855
|
+
* Alias for {@link registeredForBlock}.
|
|
14856
|
+
*
|
|
14857
|
+
* @param {string} name
|
|
14858
|
+
* @param {string} context
|
|
14859
|
+
*/
|
|
14860
|
+
getBlockFor(name, context) {
|
|
14861
|
+
return this.registeredForBlock(name, context)
|
|
14862
|
+
}
|
|
14863
|
+
|
|
14864
|
+
/**
|
|
14865
|
+
* Alias for {@link registeredForBlockMacro}.
|
|
14866
|
+
*
|
|
14867
|
+
* @param {string} name
|
|
14868
|
+
*/
|
|
14869
|
+
getBlockMacroFor(name) {
|
|
14870
|
+
return this.registeredForBlockMacro(name)
|
|
14871
|
+
}
|
|
14872
|
+
|
|
14522
14873
|
// ── Private helpers ──────────────────────────────────────────────────────────
|
|
14523
14874
|
|
|
14524
14875
|
/** @internal */
|
|
@@ -14744,6 +15095,15 @@ const Extensions = {
|
|
|
14744
15095
|
return _groups
|
|
14745
15096
|
},
|
|
14746
15097
|
|
|
15098
|
+
/**
|
|
15099
|
+
* Alias for {@link groups}.
|
|
15100
|
+
*
|
|
15101
|
+
* @returns {object}
|
|
15102
|
+
*/
|
|
15103
|
+
getGroups() {
|
|
15104
|
+
return this.groups()
|
|
15105
|
+
},
|
|
15106
|
+
|
|
14747
15107
|
/**
|
|
14748
15108
|
* Create a new Registry, optionally pre-populated with a named block.
|
|
14749
15109
|
*
|
|
@@ -15971,8 +16331,9 @@ class Document extends AbstractBlock {
|
|
|
15971
16331
|
* @param {Object} blockAttributes
|
|
15972
16332
|
*/
|
|
15973
16333
|
playbackAttributes(blockAttributes) {
|
|
15974
|
-
|
|
15975
|
-
|
|
16334
|
+
const entries = getAttributeEntries(blockAttributes);
|
|
16335
|
+
if (!entries) return
|
|
16336
|
+
for (const entry of entries) {
|
|
15976
16337
|
if (entry.negate) {
|
|
15977
16338
|
delete this.attributes[entry.name];
|
|
15978
16339
|
if (entry.name === 'compat-mode') this.compatMode = false;
|
|
@@ -16701,6 +17062,12 @@ class Document extends AbstractBlock {
|
|
|
16701
17062
|
* Handles titles (AbstractBlock), list item text, table cell text, and reftexts.
|
|
16702
17063
|
*/
|
|
16703
17064
|
async _resolveAllTexts(block) {
|
|
17065
|
+
// The header section lives outside document.blocks; pre-compute its title here so
|
|
17066
|
+
// that doc.doctitle() returns the fully-substituted title (with replacements applied,
|
|
17067
|
+
// e.g. ' → ’) rather than the header-subs-only fallback.
|
|
17068
|
+
if (block === this && this.header) {
|
|
17069
|
+
await this.header.precomputeTitle?.();
|
|
17070
|
+
}
|
|
16704
17071
|
// Skip title pre-computation for blocks with an explicit empty id ([id=]).
|
|
16705
17072
|
// In Ruby, apply_title_subs is lazy: it is never called during parsing for such
|
|
16706
17073
|
// blocks because section.title is never accessed. An explicit empty id is
|
|
@@ -16784,7 +17151,7 @@ class Document extends AbstractBlock {
|
|
|
16784
17151
|
* @internal
|
|
16785
17152
|
*/
|
|
16786
17153
|
_clearPlaybackAttributes(attributes) {
|
|
16787
|
-
delete attributes
|
|
17154
|
+
delete attributes[ATTR_ENTRIES_KEY];
|
|
16788
17155
|
}
|
|
16789
17156
|
|
|
16790
17157
|
/**
|
|
@@ -19512,17 +19879,23 @@ async function load$1(input, options = {}) {
|
|
|
19512
19879
|
// Shallow-copy options so we don't mutate the caller's object.
|
|
19513
19880
|
options = Object.assign({}, options);
|
|
19514
19881
|
|
|
19515
|
-
const timings = options.timings ?? null;
|
|
19516
|
-
if (timings) timings.start('read');
|
|
19517
|
-
|
|
19518
19882
|
// ── Logger override ───────────────────────────────────────────────────────
|
|
19883
|
+
// When a logger option is supplied, run the conversion in an async-local
|
|
19884
|
+
// context so the logger is scoped to this call only — no global mutation,
|
|
19885
|
+
// which makes concurrent callers (e.g. parallel Deno tests) safe.
|
|
19519
19886
|
if ('logger' in options) {
|
|
19520
|
-
const
|
|
19521
|
-
|
|
19522
|
-
|
|
19523
|
-
}
|
|
19887
|
+
const newLogger = options.logger ?? new NullLogger();
|
|
19888
|
+
delete options.logger;
|
|
19889
|
+
return withLogger(newLogger, () => _doLoad(input, options, newLogger))
|
|
19524
19890
|
}
|
|
19525
19891
|
|
|
19892
|
+
return _doLoad(input, options)
|
|
19893
|
+
}
|
|
19894
|
+
|
|
19895
|
+
async function _doLoad(input, options, explicitLogger = null) {
|
|
19896
|
+
const timings = options.timings ?? null;
|
|
19897
|
+
if (timings) timings.start('read');
|
|
19898
|
+
|
|
19526
19899
|
// ── Attributes normalisation ──────────────────────────────────────────────
|
|
19527
19900
|
let attrs = options.attributes;
|
|
19528
19901
|
if (!attrs) {
|
|
@@ -19554,11 +19927,9 @@ async function load$1(input, options = {}) {
|
|
|
19554
19927
|
attrs.docname = basename(inputPath, docfilesuffix);
|
|
19555
19928
|
}
|
|
19556
19929
|
source = await _readStream(input);
|
|
19557
|
-
} else if (
|
|
19558
|
-
|
|
19559
|
-
|
|
19560
|
-
) {
|
|
19561
|
-
source = input.toString('utf8');
|
|
19930
|
+
} else if (input instanceof Uint8Array) {
|
|
19931
|
+
// Covers both Node.js Buffer (a Uint8Array subclass) and browser Uint8Array shims.
|
|
19932
|
+
source = new TextDecoder('utf-8').decode(input);
|
|
19562
19933
|
} else if (typeof input === 'string') {
|
|
19563
19934
|
source = input;
|
|
19564
19935
|
} else if (Array.isArray(input)) {
|
|
@@ -19621,6 +19992,19 @@ async function load$1(input, options = {}) {
|
|
|
19621
19992
|
}
|
|
19622
19993
|
|
|
19623
19994
|
if (timings) timings.record('parse');
|
|
19995
|
+
|
|
19996
|
+
// Persist the logger on the Document instance so that doc.convert()
|
|
19997
|
+
// (called by convert.js after the async-local context ends) still routes
|
|
19998
|
+
// logging through the caller-supplied logger.
|
|
19999
|
+
// ALS provides it in Node.js/Deno; the explicit parameter covers browser fallback.
|
|
20000
|
+
const contextLogger = getContextLogger() ?? explicitLogger;
|
|
20001
|
+
if (contextLogger) {
|
|
20002
|
+
Object.defineProperty(doc, 'logger', {
|
|
20003
|
+
get: () => contextLogger,
|
|
20004
|
+
configurable: true,
|
|
20005
|
+
});
|
|
20006
|
+
}
|
|
20007
|
+
|
|
19624
20008
|
return doc
|
|
19625
20009
|
}
|
|
19626
20010
|
|
|
@@ -20967,10 +21351,7 @@ ${await node.content()}
|
|
|
20967
21351
|
img =
|
|
20968
21352
|
(await this.readSvgContents(node, target)) ||
|
|
20969
21353
|
`<span class="alt">${node.getAlt()}</span>`;
|
|
20970
|
-
} else if (
|
|
20971
|
-
node.hasOption('interactive') &&
|
|
20972
|
-
node.document.safe >= SafeMode.SERVER
|
|
20973
|
-
) {
|
|
21354
|
+
} else if (node.hasOption('interactive')) {
|
|
20974
21355
|
const fallback = node.hasAttribute('fallback')
|
|
20975
21356
|
? `<img src="${await node.imageUri(node.getAttribute('fallback'))}" alt="${this._encodeAttrValue(node.getAlt())}"${widthAttr}${heightAttr}${slash}>`
|
|
20976
21357
|
: `<span class="alt">${node.getAlt()}</span>`;
|
|
@@ -21811,10 +22192,7 @@ Your browser does not support the video tag.
|
|
|
21811
22192
|
img =
|
|
21812
22193
|
(await this.readSvgContents(node, target)) ||
|
|
21813
22194
|
`<span class="alt">${node.getAlt()}</span>`;
|
|
21814
|
-
} else if (
|
|
21815
|
-
node.hasOption('interactive') &&
|
|
21816
|
-
node.document.safe >= SafeMode.SERVER
|
|
21817
|
-
) {
|
|
22195
|
+
} else if (node.hasOption('interactive')) {
|
|
21818
22196
|
const fallback = node.hasAttribute('fallback')
|
|
21819
22197
|
? `<img src="${await node.imageUri(node.getAttribute('fallback'))}" alt="${this._encodeAttrValue(node.getAlt())}"${attrs}${this._voidSlash}>`
|
|
21820
22198
|
: `<span class="alt">${node.getAlt()}</span>`;
|