@asciidoctor/core 4.0.0-alpha.2 → 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 +410 -34
- package/build/node/index.cjs +411 -35
- package/package.json +3 -2
- package/src/attribute_entry.js +17 -1
- package/src/browser/reader.js +2 -2
- 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/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 +8 -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');
|
|
@@ -5965,7 +6043,7 @@ const SyntaxHighlighter = new DefaultFactory();
|
|
|
5965
6043
|
//
|
|
5966
6044
|
// This logic is specific to Asciidoctor.js and has no equivalent in the upstream Ruby asciidoctor
|
|
5967
6045
|
// implementation. It handles the case where the document is loaded in a browser environment
|
|
5968
|
-
//
|
|
6046
|
+
// where paths can be file:// or http(s):// URIs.
|
|
5969
6047
|
//
|
|
5970
6048
|
// The key behavioural differences from the standard file-system resolver:
|
|
5971
6049
|
// - Relative targets are resolved by string concatenation against a URI context dir,
|
|
@@ -6014,7 +6092,7 @@ function _linkReplacement(reader, target, attrlist) {
|
|
|
6014
6092
|
* 1. target starts with file:// → inc_path = relpath = target
|
|
6015
6093
|
* 2. target is a URI → must descend from baseDir or allow-uri-read; else → link
|
|
6016
6094
|
* 3. target is an absolute OS path → prepend file:// (or file:///)
|
|
6017
|
-
* 4. baseDir == '.' → inc_path = relpath = target (resolved by
|
|
6095
|
+
* 4. baseDir == '.' → inc_path = relpath = target (resolved by fetch)
|
|
6018
6096
|
* 5. baseDir starts with file:// OR baseDir is not a URI → inc_path = baseDir/target; relpath = target
|
|
6019
6097
|
* 6. baseDir is an absolute URL → inc_path = baseDir/target; relpath = target
|
|
6020
6098
|
*
|
|
@@ -6736,7 +6814,7 @@ class Reader {
|
|
|
6736
6814
|
return this.source()
|
|
6737
6815
|
}
|
|
6738
6816
|
getLogger() {
|
|
6739
|
-
return LoggerManager.logger
|
|
6817
|
+
return this._document?.logger ?? LoggerManager.logger
|
|
6740
6818
|
}
|
|
6741
6819
|
createLogMessage(text, context = {}) {
|
|
6742
6820
|
return Logger.AutoFormattingMessage.attach({ text, ...context })
|
|
@@ -9561,6 +9639,22 @@ class AttributeList {
|
|
|
9561
9639
|
}
|
|
9562
9640
|
}
|
|
9563
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
|
+
|
|
9564
9658
|
class AttributeEntry {
|
|
9565
9659
|
constructor(name, value, negate = null) {
|
|
9566
9660
|
this.name = name;
|
|
@@ -9569,7 +9663,7 @@ class AttributeEntry {
|
|
|
9569
9663
|
}
|
|
9570
9664
|
|
|
9571
9665
|
saveTo(blockAttributes) {
|
|
9572
|
-
(blockAttributes
|
|
9666
|
+
(blockAttributes[ATTR_ENTRIES_KEY] ??= []).push(this);
|
|
9573
9667
|
return this
|
|
9574
9668
|
}
|
|
9575
9669
|
}
|
|
@@ -11044,7 +11138,7 @@ class Parser {
|
|
|
11044
11138
|
const Rdr = Reader;
|
|
11045
11139
|
const result = await extension.processMethod(
|
|
11046
11140
|
parent,
|
|
11047
|
-
blockReader ?? new Rdr(lines),
|
|
11141
|
+
blockReader ?? new Rdr(lines, null, { document: parent.document }),
|
|
11048
11142
|
{ ...attributes }
|
|
11049
11143
|
);
|
|
11050
11144
|
if (!result || result === parent) return null
|
|
@@ -13166,6 +13260,94 @@ function _uniform(str, chr, len) {
|
|
|
13166
13260
|
// references; they will be resolved when those modules implement the methods.
|
|
13167
13261
|
|
|
13168
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
|
+
|
|
13169
13351
|
// ── DSL Mixins ────────────────────────────────────────────────────────────────
|
|
13170
13352
|
|
|
13171
13353
|
/**
|
|
@@ -13761,7 +13943,12 @@ class Processor {
|
|
|
13761
13943
|
* Extensions.register(function () { this.preprocessor(CommentStripPreprocessor) })
|
|
13762
13944
|
*/
|
|
13763
13945
|
class Preprocessor extends Processor {
|
|
13764
|
-
|
|
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) {
|
|
13765
13952
|
throw new Error(
|
|
13766
13953
|
`${this.constructor.name} must implement the process method`
|
|
13767
13954
|
)
|
|
@@ -13786,7 +13973,11 @@ Preprocessor.DSL = DocumentProcessorDsl;
|
|
|
13786
13973
|
* Extensions.register(function () { this.treeProcessor(ShoutTreeProcessor) })
|
|
13787
13974
|
*/
|
|
13788
13975
|
class TreeProcessor extends Processor {
|
|
13789
|
-
|
|
13976
|
+
/**
|
|
13977
|
+
* @param {Document} document - The parsed document.
|
|
13978
|
+
* @returns {void}
|
|
13979
|
+
*/
|
|
13980
|
+
process(document) {
|
|
13790
13981
|
throw new Error(
|
|
13791
13982
|
`${this.constructor.name} must implement the process method`
|
|
13792
13983
|
)
|
|
@@ -13812,7 +14003,12 @@ TreeProcessor.DSL = DocumentProcessorDsl;
|
|
|
13812
14003
|
* Extensions.register(function () { this.postprocessor(FooterPostprocessor) })
|
|
13813
14004
|
*/
|
|
13814
14005
|
class Postprocessor extends Processor {
|
|
13815
|
-
|
|
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) {
|
|
13816
14012
|
throw new Error(
|
|
13817
14013
|
`${this.constructor.name} must implement the process method`
|
|
13818
14014
|
)
|
|
@@ -13826,13 +14022,25 @@ Postprocessor.DSL = DocumentProcessorDsl;
|
|
|
13826
14022
|
* Implementations must extend IncludeProcessor.
|
|
13827
14023
|
*/
|
|
13828
14024
|
class IncludeProcessor extends Processor {
|
|
13829
|
-
|
|
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) {
|
|
13830
14033
|
throw new Error(
|
|
13831
14034
|
`${this.constructor.name} must implement the process method`
|
|
13832
14035
|
)
|
|
13833
14036
|
}
|
|
13834
14037
|
|
|
13835
|
-
|
|
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) {
|
|
13836
14044
|
return true
|
|
13837
14045
|
}
|
|
13838
14046
|
}
|
|
@@ -13850,7 +14058,11 @@ class DocinfoProcessor extends Processor {
|
|
|
13850
14058
|
this.config.location ??= 'head';
|
|
13851
14059
|
}
|
|
13852
14060
|
|
|
13853
|
-
|
|
14061
|
+
/**
|
|
14062
|
+
* @param {Document} document - The document being converted.
|
|
14063
|
+
* @returns {string} The docinfo content to inject into the document.
|
|
14064
|
+
*/
|
|
14065
|
+
process(document) {
|
|
13854
14066
|
throw new Error(
|
|
13855
14067
|
`${this.constructor.name} must implement the process method`
|
|
13856
14068
|
)
|
|
@@ -13906,7 +14118,13 @@ class BlockProcessor extends Processor {
|
|
|
13906
14118
|
this.config.content_model ??= 'compound';
|
|
13907
14119
|
}
|
|
13908
14120
|
|
|
13909
|
-
|
|
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) {
|
|
13910
14128
|
throw new Error(
|
|
13911
14129
|
`${this.constructor.name} must implement the process method`
|
|
13912
14130
|
)
|
|
@@ -13924,7 +14142,13 @@ class MacroProcessor extends Processor {
|
|
|
13924
14142
|
this.config.content_model ??= 'attributes';
|
|
13925
14143
|
}
|
|
13926
14144
|
|
|
13927
|
-
|
|
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) {
|
|
13928
14152
|
throw new Error(
|
|
13929
14153
|
`${this.constructor.name} must implement the process method`
|
|
13930
14154
|
)
|
|
@@ -13970,6 +14194,16 @@ class BlockMacroProcessor extends MacroProcessor {
|
|
|
13970
14194
|
set name(value) {
|
|
13971
14195
|
this._name = value;
|
|
13972
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
|
+
}
|
|
13973
14207
|
}
|
|
13974
14208
|
BlockMacroProcessor.DSL = MacroProcessorDsl;
|
|
13975
14209
|
|
|
@@ -14013,6 +14247,16 @@ class InlineMacroProcessor extends MacroProcessor {
|
|
|
14013
14247
|
))
|
|
14014
14248
|
}
|
|
14015
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
|
+
|
|
14016
14260
|
resolveRegexp(name, format) {
|
|
14017
14261
|
if (!MacroNameRx.test(name)) {
|
|
14018
14262
|
throw new Error(`invalid name for inline macro: ${name}`)
|
|
@@ -14376,6 +14620,15 @@ class Registry {
|
|
|
14376
14620
|
return !!this._block_extensions
|
|
14377
14621
|
}
|
|
14378
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
|
+
|
|
14379
14632
|
/**
|
|
14380
14633
|
* Check whether a BlockProcessor is registered for the given name and context.
|
|
14381
14634
|
*
|
|
@@ -14422,6 +14675,17 @@ class Registry {
|
|
|
14422
14675
|
return !!this._block_macro_extensions
|
|
14423
14676
|
}
|
|
14424
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
|
+
|
|
14425
14689
|
/**
|
|
14426
14690
|
* Check whether a BlockMacroProcessor is registered for the given name.
|
|
14427
14691
|
*
|
|
@@ -14527,6 +14791,85 @@ class Registry {
|
|
|
14527
14791
|
return extension
|
|
14528
14792
|
}
|
|
14529
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
|
+
|
|
14530
14873
|
// ── Private helpers ──────────────────────────────────────────────────────────
|
|
14531
14874
|
|
|
14532
14875
|
/** @internal */
|
|
@@ -14752,6 +15095,15 @@ const Extensions = {
|
|
|
14752
15095
|
return _groups
|
|
14753
15096
|
},
|
|
14754
15097
|
|
|
15098
|
+
/**
|
|
15099
|
+
* Alias for {@link groups}.
|
|
15100
|
+
*
|
|
15101
|
+
* @returns {object}
|
|
15102
|
+
*/
|
|
15103
|
+
getGroups() {
|
|
15104
|
+
return this.groups()
|
|
15105
|
+
},
|
|
15106
|
+
|
|
14755
15107
|
/**
|
|
14756
15108
|
* Create a new Registry, optionally pre-populated with a named block.
|
|
14757
15109
|
*
|
|
@@ -15979,8 +16331,9 @@ class Document extends AbstractBlock {
|
|
|
15979
16331
|
* @param {Object} blockAttributes
|
|
15980
16332
|
*/
|
|
15981
16333
|
playbackAttributes(blockAttributes) {
|
|
15982
|
-
|
|
15983
|
-
|
|
16334
|
+
const entries = getAttributeEntries(blockAttributes);
|
|
16335
|
+
if (!entries) return
|
|
16336
|
+
for (const entry of entries) {
|
|
15984
16337
|
if (entry.negate) {
|
|
15985
16338
|
delete this.attributes[entry.name];
|
|
15986
16339
|
if (entry.name === 'compat-mode') this.compatMode = false;
|
|
@@ -16709,6 +17062,12 @@ class Document extends AbstractBlock {
|
|
|
16709
17062
|
* Handles titles (AbstractBlock), list item text, table cell text, and reftexts.
|
|
16710
17063
|
*/
|
|
16711
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
|
+
}
|
|
16712
17071
|
// Skip title pre-computation for blocks with an explicit empty id ([id=]).
|
|
16713
17072
|
// In Ruby, apply_title_subs is lazy: it is never called during parsing for such
|
|
16714
17073
|
// blocks because section.title is never accessed. An explicit empty id is
|
|
@@ -16792,7 +17151,7 @@ class Document extends AbstractBlock {
|
|
|
16792
17151
|
* @internal
|
|
16793
17152
|
*/
|
|
16794
17153
|
_clearPlaybackAttributes(attributes) {
|
|
16795
|
-
delete attributes
|
|
17154
|
+
delete attributes[ATTR_ENTRIES_KEY];
|
|
16796
17155
|
}
|
|
16797
17156
|
|
|
16798
17157
|
/**
|
|
@@ -19520,17 +19879,23 @@ async function load$1(input, options = {}) {
|
|
|
19520
19879
|
// Shallow-copy options so we don't mutate the caller's object.
|
|
19521
19880
|
options = Object.assign({}, options);
|
|
19522
19881
|
|
|
19523
|
-
const timings = options.timings ?? null;
|
|
19524
|
-
if (timings) timings.start('read');
|
|
19525
|
-
|
|
19526
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.
|
|
19527
19886
|
if ('logger' in options) {
|
|
19528
|
-
const
|
|
19529
|
-
|
|
19530
|
-
|
|
19531
|
-
}
|
|
19887
|
+
const newLogger = options.logger ?? new NullLogger();
|
|
19888
|
+
delete options.logger;
|
|
19889
|
+
return withLogger(newLogger, () => _doLoad(input, options, newLogger))
|
|
19532
19890
|
}
|
|
19533
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
|
+
|
|
19534
19899
|
// ── Attributes normalisation ──────────────────────────────────────────────
|
|
19535
19900
|
let attrs = options.attributes;
|
|
19536
19901
|
if (!attrs) {
|
|
@@ -19562,11 +19927,9 @@ async function load$1(input, options = {}) {
|
|
|
19562
19927
|
attrs.docname = basename(inputPath, docfilesuffix);
|
|
19563
19928
|
}
|
|
19564
19929
|
source = await _readStream(input);
|
|
19565
|
-
} else if (
|
|
19566
|
-
|
|
19567
|
-
|
|
19568
|
-
) {
|
|
19569
|
-
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);
|
|
19570
19933
|
} else if (typeof input === 'string') {
|
|
19571
19934
|
source = input;
|
|
19572
19935
|
} else if (Array.isArray(input)) {
|
|
@@ -19629,6 +19992,19 @@ async function load$1(input, options = {}) {
|
|
|
19629
19992
|
}
|
|
19630
19993
|
|
|
19631
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
|
+
|
|
19632
20008
|
return doc
|
|
19633
20009
|
}
|
|
19634
20010
|
|