@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/node/index.cjs
CHANGED
|
@@ -5,7 +5,7 @@ const node_fs = require('node:fs');
|
|
|
5
5
|
const path = require('node:path');
|
|
6
6
|
|
|
7
7
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
8
|
-
var version = "4.0.0-alpha.
|
|
8
|
+
var version = "4.0.0-alpha.3";
|
|
9
9
|
const packageJson = {
|
|
10
10
|
version: version};
|
|
11
11
|
|
|
@@ -1514,6 +1514,65 @@ function resolveSeverity(severity) {
|
|
|
1514
1514
|
return severity ?? Severity.UNKNOWN
|
|
1515
1515
|
}
|
|
1516
1516
|
|
|
1517
|
+
// ── Per-execution logger context ─────────────────────────────────────────────
|
|
1518
|
+
|
|
1519
|
+
// Holds an AsyncLocalStorage instance once it is lazily initialised.
|
|
1520
|
+
// Allows per-execution logger isolation without mutating the global singleton,
|
|
1521
|
+
// making concurrent test execution (e.g. Deno's node:test) safe.
|
|
1522
|
+
let _loggerStore = null;
|
|
1523
|
+
|
|
1524
|
+
// Promise singleton — ensures AsyncLocalStorage is initialised at most once.
|
|
1525
|
+
let _loggerStorePromise = null;
|
|
1526
|
+
|
|
1527
|
+
/**
|
|
1528
|
+
* Lazily initialise an AsyncLocalStorage for per-execution logger context.
|
|
1529
|
+
* Falls back to null in environments that do not support node:async_hooks (e.g. browsers).
|
|
1530
|
+
* @returns {Promise<import('node:async_hooks').AsyncLocalStorage|null>}
|
|
1531
|
+
*/
|
|
1532
|
+
async function _ensureLoggerStore() {
|
|
1533
|
+
if (_loggerStorePromise === null) {
|
|
1534
|
+
_loggerStorePromise = import('node:async_hooks')
|
|
1535
|
+
.then(({ AsyncLocalStorage }) => {
|
|
1536
|
+
const store = new AsyncLocalStorage();
|
|
1537
|
+
_loggerStore = store;
|
|
1538
|
+
return store
|
|
1539
|
+
})
|
|
1540
|
+
.catch(() => null);
|
|
1541
|
+
}
|
|
1542
|
+
return _loggerStorePromise
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
/** @internal — returns the logger bound to the current async context, or null */
|
|
1546
|
+
function getContextLogger() {
|
|
1547
|
+
return _loggerStore?.getStore() ?? null
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
/**
|
|
1551
|
+
* Run fn() within an async-local logger context so that all log calls via
|
|
1552
|
+
* `this.logger` (from applyLogging) automatically route to the provided logger
|
|
1553
|
+
* for the duration of the async execution chain.
|
|
1554
|
+
*
|
|
1555
|
+
* Falls back to global mutation in environments without node:async_hooks (e.g. browsers).
|
|
1556
|
+
*
|
|
1557
|
+
* @param {Logger|MemoryLogger|NullLogger} logger - The logger to activate.
|
|
1558
|
+
* @param {() => any} fn - The function to execute within the logger context.
|
|
1559
|
+
* @returns {Promise<any>}
|
|
1560
|
+
*/
|
|
1561
|
+
async function withLogger(logger, fn) {
|
|
1562
|
+
const store = await _ensureLoggerStore();
|
|
1563
|
+
if (store) {
|
|
1564
|
+
return store.run(logger, fn)
|
|
1565
|
+
}
|
|
1566
|
+
// Fallback for environments without node:async_hooks (browsers).
|
|
1567
|
+
const prev = LoggerManager.logger;
|
|
1568
|
+
if (logger !== prev) LoggerManager.logger = logger;
|
|
1569
|
+
try {
|
|
1570
|
+
return await fn()
|
|
1571
|
+
} finally {
|
|
1572
|
+
if (logger !== prev) LoggerManager.logger = prev;
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1517
1576
|
// ── Logger ────────────────────────────────────────────────────────────────────
|
|
1518
1577
|
|
|
1519
1578
|
/** Standard logger that writes formatted messages to stderr or a custom pipe. */
|
|
@@ -1822,8 +1881,9 @@ class MemoryLogger {
|
|
|
1822
1881
|
// ── NullLogger ────────────────────────────────────────────────────────────────
|
|
1823
1882
|
|
|
1824
1883
|
/** Logger that discards all messages but still tracks the maximum severity. */
|
|
1825
|
-
class NullLogger {
|
|
1884
|
+
class NullLogger extends Logger {
|
|
1826
1885
|
constructor() {
|
|
1886
|
+
super();
|
|
1827
1887
|
this.level = Severity.UNKNOWN;
|
|
1828
1888
|
this._maxSeverity = null;
|
|
1829
1889
|
}
|
|
@@ -1968,12 +2028,12 @@ const LoggerManager = (() => {
|
|
|
1968
2028
|
function applyLogging(proto) {
|
|
1969
2029
|
Object.defineProperty(proto, 'logger', {
|
|
1970
2030
|
get() {
|
|
1971
|
-
return LoggerManager.logger
|
|
2031
|
+
return _loggerStore?.getStore() ?? LoggerManager.logger
|
|
1972
2032
|
},
|
|
1973
2033
|
configurable: true,
|
|
1974
2034
|
});
|
|
1975
2035
|
|
|
1976
|
-
proto.getLogger = () => LoggerManager.logger;
|
|
2036
|
+
proto.getLogger = () => _loggerStore?.getStore() ?? LoggerManager.logger;
|
|
1977
2037
|
|
|
1978
2038
|
proto.messageWithContext = (text, context = {}) =>
|
|
1979
2039
|
Logger.AutoFormattingMessage.attach({ text, ...context });
|
|
@@ -2020,7 +2080,16 @@ const rstrip = (line) => line.replace(/[ \t\r\n\f\v]+$/, '');
|
|
|
2020
2080
|
*/
|
|
2021
2081
|
function prepareSourceArray(data, trimEnd = true) {
|
|
2022
2082
|
if (!data.length) return []
|
|
2023
|
-
if (data[0].startsWith(BOM))
|
|
2083
|
+
if (data[0].startsWith(BOM)) {
|
|
2084
|
+
data[0] = data[0].slice(1);
|
|
2085
|
+
} else if (
|
|
2086
|
+
data[0].charCodeAt(0) === 0xef &&
|
|
2087
|
+
data[0].charCodeAt(1) === 0xbb &&
|
|
2088
|
+
data[0].charCodeAt(2) === 0xbf
|
|
2089
|
+
) {
|
|
2090
|
+
// Strip UTF-8 BOM encoded as three raw characters ( / \xEF\xBB\xBF) if not already decoded to U+FEFF
|
|
2091
|
+
data[0] = data[0].slice(3);
|
|
2092
|
+
}
|
|
2024
2093
|
// Strip trailing \r to normalize Windows CRLF line endings (lines were split on \n, leaving \r).
|
|
2025
2094
|
return trimEnd
|
|
2026
2095
|
? data.map(rstrip)
|
|
@@ -2040,7 +2109,16 @@ function prepareSourceArray(data, trimEnd = true) {
|
|
|
2040
2109
|
*/
|
|
2041
2110
|
function prepareSourceString(data, trimEnd = true) {
|
|
2042
2111
|
if (!data) return []
|
|
2043
|
-
if (data.startsWith(BOM))
|
|
2112
|
+
if (data.startsWith(BOM)) {
|
|
2113
|
+
data = data.slice(1);
|
|
2114
|
+
} else if (
|
|
2115
|
+
data.charCodeAt(0) === 0xef &&
|
|
2116
|
+
data.charCodeAt(1) === 0xbb &&
|
|
2117
|
+
data.charCodeAt(2) === 0xbf
|
|
2118
|
+
) {
|
|
2119
|
+
// Strip UTF-8 BOM encoded as three raw characters ( / \xEF\xBB\xBF) if not already decoded to U+FEFF
|
|
2120
|
+
data = data.slice(3);
|
|
2121
|
+
}
|
|
2044
2122
|
// Normalize Windows CRLF to LF so that split('\n') does not leave trailing \r on each line.
|
|
2045
2123
|
if (data.includes('\r'))
|
|
2046
2124
|
data = data.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
@@ -5972,7 +6050,7 @@ const SyntaxHighlighter = new DefaultFactory();
|
|
|
5972
6050
|
//
|
|
5973
6051
|
// This logic is specific to Asciidoctor.js and has no equivalent in the upstream Ruby asciidoctor
|
|
5974
6052
|
// implementation. It handles the case where the document is loaded in a browser environment
|
|
5975
|
-
//
|
|
6053
|
+
// where paths can be file:// or http(s):// URIs.
|
|
5976
6054
|
//
|
|
5977
6055
|
// The key behavioural differences from the standard file-system resolver:
|
|
5978
6056
|
// - Relative targets are resolved by string concatenation against a URI context dir,
|
|
@@ -6021,7 +6099,7 @@ function _linkReplacement(reader, target, attrlist) {
|
|
|
6021
6099
|
* 1. target starts with file:// → inc_path = relpath = target
|
|
6022
6100
|
* 2. target is a URI → must descend from baseDir or allow-uri-read; else → link
|
|
6023
6101
|
* 3. target is an absolute OS path → prepend file:// (or file:///)
|
|
6024
|
-
* 4. baseDir == '.' → inc_path = relpath = target (resolved by
|
|
6102
|
+
* 4. baseDir == '.' → inc_path = relpath = target (resolved by fetch)
|
|
6025
6103
|
* 5. baseDir starts with file:// OR baseDir is not a URI → inc_path = baseDir/target; relpath = target
|
|
6026
6104
|
* 6. baseDir is an absolute URL → inc_path = baseDir/target; relpath = target
|
|
6027
6105
|
*
|
|
@@ -6743,7 +6821,7 @@ class Reader {
|
|
|
6743
6821
|
return this.source()
|
|
6744
6822
|
}
|
|
6745
6823
|
getLogger() {
|
|
6746
|
-
return LoggerManager.logger
|
|
6824
|
+
return this._document?.logger ?? LoggerManager.logger
|
|
6747
6825
|
}
|
|
6748
6826
|
createLogMessage(text, context = {}) {
|
|
6749
6827
|
return Logger.AutoFormattingMessage.attach({ text, ...context })
|
|
@@ -9568,6 +9646,22 @@ class AttributeList {
|
|
|
9568
9646
|
}
|
|
9569
9647
|
}
|
|
9570
9648
|
|
|
9649
|
+
// Symbol key used to store attribute entries on a block-attributes object without
|
|
9650
|
+
// polluting the public attributes (invisible to Object.keys / for-in / JSON.stringify).
|
|
9651
|
+
// Spread ({ ...attrs }) copies Symbol-keyed properties, so the entry survives the
|
|
9652
|
+
// shallow clone made in AbstractNode's constructor.
|
|
9653
|
+
const ATTR_ENTRIES_KEY = Symbol('attribute_entries');
|
|
9654
|
+
|
|
9655
|
+
/**
|
|
9656
|
+
* Return the attribute entries stored for the given block attributes object,
|
|
9657
|
+
* or undefined if none have been saved.
|
|
9658
|
+
* @param {Object} blockAttributes
|
|
9659
|
+
* @returns {AttributeEntry[]|undefined}
|
|
9660
|
+
*/
|
|
9661
|
+
function getAttributeEntries(blockAttributes) {
|
|
9662
|
+
return blockAttributes[ATTR_ENTRIES_KEY]
|
|
9663
|
+
}
|
|
9664
|
+
|
|
9571
9665
|
class AttributeEntry {
|
|
9572
9666
|
constructor(name, value, negate = null) {
|
|
9573
9667
|
this.name = name;
|
|
@@ -9576,7 +9670,7 @@ class AttributeEntry {
|
|
|
9576
9670
|
}
|
|
9577
9671
|
|
|
9578
9672
|
saveTo(blockAttributes) {
|
|
9579
|
-
(blockAttributes
|
|
9673
|
+
(blockAttributes[ATTR_ENTRIES_KEY] ??= []).push(this);
|
|
9580
9674
|
return this
|
|
9581
9675
|
}
|
|
9582
9676
|
}
|
|
@@ -11051,7 +11145,7 @@ class Parser {
|
|
|
11051
11145
|
const Rdr = Reader;
|
|
11052
11146
|
const result = await extension.processMethod(
|
|
11053
11147
|
parent,
|
|
11054
|
-
blockReader ?? new Rdr(lines),
|
|
11148
|
+
blockReader ?? new Rdr(lines, null, { document: parent.document }),
|
|
11055
11149
|
{ ...attributes }
|
|
11056
11150
|
);
|
|
11057
11151
|
if (!result || result === parent) return null
|
|
@@ -13173,6 +13267,94 @@ function _uniform(str, chr, len) {
|
|
|
13173
13267
|
// references; they will be resolved when those modules implement the methods.
|
|
13174
13268
|
|
|
13175
13269
|
|
|
13270
|
+
// Type-only imports for JSDoc
|
|
13271
|
+
/**
|
|
13272
|
+
* @typedef {import('./document.js').Document} Document
|
|
13273
|
+
* @typedef {import('./abstract_block.js').AbstractBlock} AbstractBlock
|
|
13274
|
+
*/
|
|
13275
|
+
|
|
13276
|
+
// ── DSL interface types ───────────────────────────────────────────────────────
|
|
13277
|
+
|
|
13278
|
+
/**
|
|
13279
|
+
* DSL interface for configuring a {@link Processor} instance.
|
|
13280
|
+
* Applied to a processor instance via `Object.assign(instance, DslMixin)`.
|
|
13281
|
+
*
|
|
13282
|
+
* The `process` property behaves as a setter when called with a single Function
|
|
13283
|
+
* argument (stores the process block), or as a passthrough caller otherwise.
|
|
13284
|
+
*
|
|
13285
|
+
* @typedef {object} ProcessorDslInterface
|
|
13286
|
+
* @property {(key: string, value: unknown) => void} option - Set a config option.
|
|
13287
|
+
* @property {(fn: (...args: unknown[]) => unknown) => void} process - Register the process function.
|
|
13288
|
+
* @property {() => boolean} processBlockGiven - Returns true if a process function has been registered.
|
|
13289
|
+
*/
|
|
13290
|
+
|
|
13291
|
+
/**
|
|
13292
|
+
* DSL interface for document processors (Preprocessor, TreeProcessor, Postprocessor, DocinfoProcessor).
|
|
13293
|
+
*
|
|
13294
|
+
* @typedef {ProcessorDslInterface & { prefer(): void; prepend(): void }} DocumentProcessorDslInterface
|
|
13295
|
+
*/
|
|
13296
|
+
|
|
13297
|
+
/**
|
|
13298
|
+
* DSL interface for syntax processors (BlockProcessor, BlockMacroProcessor, InlineMacroProcessor).
|
|
13299
|
+
*
|
|
13300
|
+
* @typedef {ProcessorDslInterface & {
|
|
13301
|
+
* named(value: string): void;
|
|
13302
|
+
* contentModel(value: string): void;
|
|
13303
|
+
* parseContentAs(value: string): void;
|
|
13304
|
+
* positionalAttributes(...value: string[]): void;
|
|
13305
|
+
* namePositionalAttributes(...value: string[]): void;
|
|
13306
|
+
* positionalAttrs(...value: string[]): void;
|
|
13307
|
+
* defaultAttributes(value: Record<string, string>): void;
|
|
13308
|
+
* defaultAttrs(value: Record<string, string>): void;
|
|
13309
|
+
* resolveAttributes(...args: unknown[]): void;
|
|
13310
|
+
* resolvesAttributes(...args: unknown[]): void;
|
|
13311
|
+
* }} SyntaxProcessorDslInterface
|
|
13312
|
+
*/
|
|
13313
|
+
|
|
13314
|
+
/**
|
|
13315
|
+
* DSL interface for include processors.
|
|
13316
|
+
*
|
|
13317
|
+
* @typedef {DocumentProcessorDslInterface & {
|
|
13318
|
+
* handles(fn: (doc: Document, target: string) => boolean): void;
|
|
13319
|
+
* }} IncludeProcessorDslInterface
|
|
13320
|
+
*/
|
|
13321
|
+
|
|
13322
|
+
/**
|
|
13323
|
+
* DSL interface for docinfo processors.
|
|
13324
|
+
*
|
|
13325
|
+
* @typedef {DocumentProcessorDslInterface & {
|
|
13326
|
+
* atLocation(value: string): void;
|
|
13327
|
+
* }} DocinfoProcessorDslInterface
|
|
13328
|
+
*/
|
|
13329
|
+
|
|
13330
|
+
/**
|
|
13331
|
+
* DSL interface for block processors.
|
|
13332
|
+
*
|
|
13333
|
+
* @typedef {SyntaxProcessorDslInterface & {
|
|
13334
|
+
* contexts(...value: (string | string[])[]): void;
|
|
13335
|
+
* onContexts(...value: (string | string[])[]): void;
|
|
13336
|
+
* onContext(...value: (string | string[])[]): void;
|
|
13337
|
+
* bindTo(...value: (string | string[])[]): void;
|
|
13338
|
+
* }} BlockProcessorDslInterface
|
|
13339
|
+
*/
|
|
13340
|
+
|
|
13341
|
+
/**
|
|
13342
|
+
* DSL interface for macro processors (block and inline macros).
|
|
13343
|
+
*
|
|
13344
|
+
* @typedef {SyntaxProcessorDslInterface} MacroProcessorDslInterface
|
|
13345
|
+
*/
|
|
13346
|
+
|
|
13347
|
+
/**
|
|
13348
|
+
* DSL interface for inline macro processors.
|
|
13349
|
+
*
|
|
13350
|
+
* @typedef {MacroProcessorDslInterface & {
|
|
13351
|
+
* format(value: string): void;
|
|
13352
|
+
* matchFormat(value: string): void;
|
|
13353
|
+
* usingFormat(value: string): void;
|
|
13354
|
+
* match(value: RegExp): void;
|
|
13355
|
+
* }} InlineMacroProcessorDslInterface
|
|
13356
|
+
*/
|
|
13357
|
+
|
|
13176
13358
|
// ── DSL Mixins ────────────────────────────────────────────────────────────────
|
|
13177
13359
|
|
|
13178
13360
|
/**
|
|
@@ -13768,7 +13950,12 @@ class Processor {
|
|
|
13768
13950
|
* Extensions.register(function () { this.preprocessor(CommentStripPreprocessor) })
|
|
13769
13951
|
*/
|
|
13770
13952
|
class Preprocessor extends Processor {
|
|
13771
|
-
|
|
13953
|
+
/**
|
|
13954
|
+
* @param {Document} document - The document being parsed.
|
|
13955
|
+
* @param {Reader} reader - The reader positioned at the beginning of the source.
|
|
13956
|
+
* @returns {Reader|undefined} The same or a substitute Reader, or undefined to use the original.
|
|
13957
|
+
*/
|
|
13958
|
+
process(document, reader) {
|
|
13772
13959
|
throw new Error(
|
|
13773
13960
|
`${this.constructor.name} must implement the process method`
|
|
13774
13961
|
)
|
|
@@ -13793,7 +13980,11 @@ Preprocessor.DSL = DocumentProcessorDsl;
|
|
|
13793
13980
|
* Extensions.register(function () { this.treeProcessor(ShoutTreeProcessor) })
|
|
13794
13981
|
*/
|
|
13795
13982
|
class TreeProcessor extends Processor {
|
|
13796
|
-
|
|
13983
|
+
/**
|
|
13984
|
+
* @param {Document} document - The parsed document.
|
|
13985
|
+
* @returns {void}
|
|
13986
|
+
*/
|
|
13987
|
+
process(document) {
|
|
13797
13988
|
throw new Error(
|
|
13798
13989
|
`${this.constructor.name} must implement the process method`
|
|
13799
13990
|
)
|
|
@@ -13819,7 +14010,12 @@ TreeProcessor.DSL = DocumentProcessorDsl;
|
|
|
13819
14010
|
* Extensions.register(function () { this.postprocessor(FooterPostprocessor) })
|
|
13820
14011
|
*/
|
|
13821
14012
|
class Postprocessor extends Processor {
|
|
13822
|
-
|
|
14013
|
+
/**
|
|
14014
|
+
* @param {Document} document - The converted document.
|
|
14015
|
+
* @param {string} output - The converted output string.
|
|
14016
|
+
* @returns {string} The (possibly modified) output string.
|
|
14017
|
+
*/
|
|
14018
|
+
process(document, output) {
|
|
13823
14019
|
throw new Error(
|
|
13824
14020
|
`${this.constructor.name} must implement the process method`
|
|
13825
14021
|
)
|
|
@@ -13833,13 +14029,25 @@ Postprocessor.DSL = DocumentProcessorDsl;
|
|
|
13833
14029
|
* Implementations must extend IncludeProcessor.
|
|
13834
14030
|
*/
|
|
13835
14031
|
class IncludeProcessor extends Processor {
|
|
13836
|
-
|
|
14032
|
+
/**
|
|
14033
|
+
* @param {Document} document - The document being parsed.
|
|
14034
|
+
* @param {Reader} reader - The reader for the including document.
|
|
14035
|
+
* @param {string} target - The target of the include directive.
|
|
14036
|
+
* @param {Record<string, string>} attributes - The parsed include attributes.
|
|
14037
|
+
* @returns {void}
|
|
14038
|
+
*/
|
|
14039
|
+
process(document, reader, target, attributes) {
|
|
13837
14040
|
throw new Error(
|
|
13838
14041
|
`${this.constructor.name} must implement the process method`
|
|
13839
14042
|
)
|
|
13840
14043
|
}
|
|
13841
14044
|
|
|
13842
|
-
|
|
14045
|
+
/**
|
|
14046
|
+
* @param {Document} doc - The document being parsed.
|
|
14047
|
+
* @param {string} target - The target of the include directive.
|
|
14048
|
+
* @returns {boolean} true if this processor handles the given target.
|
|
14049
|
+
*/
|
|
14050
|
+
handles(doc, target) {
|
|
13843
14051
|
return true
|
|
13844
14052
|
}
|
|
13845
14053
|
}
|
|
@@ -13857,7 +14065,11 @@ class DocinfoProcessor extends Processor {
|
|
|
13857
14065
|
this.config.location ??= 'head';
|
|
13858
14066
|
}
|
|
13859
14067
|
|
|
13860
|
-
|
|
14068
|
+
/**
|
|
14069
|
+
* @param {Document} document - The document being converted.
|
|
14070
|
+
* @returns {string} The docinfo content to inject into the document.
|
|
14071
|
+
*/
|
|
14072
|
+
process(document) {
|
|
13861
14073
|
throw new Error(
|
|
13862
14074
|
`${this.constructor.name} must implement the process method`
|
|
13863
14075
|
)
|
|
@@ -13913,7 +14125,13 @@ class BlockProcessor extends Processor {
|
|
|
13913
14125
|
this.config.content_model ??= 'compound';
|
|
13914
14126
|
}
|
|
13915
14127
|
|
|
13916
|
-
|
|
14128
|
+
/**
|
|
14129
|
+
* @param {AbstractBlock} parent - The enclosing block.
|
|
14130
|
+
* @param {Reader} reader - The reader positioned at the block content.
|
|
14131
|
+
* @param {Record<string, unknown>} attributes - The parsed block attributes.
|
|
14132
|
+
* @returns {Block|void} A block node, or void to let the parser handle it.
|
|
14133
|
+
*/
|
|
14134
|
+
process(parent, reader, attributes) {
|
|
13917
14135
|
throw new Error(
|
|
13918
14136
|
`${this.constructor.name} must implement the process method`
|
|
13919
14137
|
)
|
|
@@ -13931,7 +14149,13 @@ class MacroProcessor extends Processor {
|
|
|
13931
14149
|
this.config.content_model ??= 'attributes';
|
|
13932
14150
|
}
|
|
13933
14151
|
|
|
13934
|
-
|
|
14152
|
+
/**
|
|
14153
|
+
* @param {AbstractBlock} parent - The enclosing block.
|
|
14154
|
+
* @param {string} target - The macro target (text between `name:` and `[`).
|
|
14155
|
+
* @param {Record<string, unknown>} attributes - The parsed macro attributes.
|
|
14156
|
+
* @returns {Block|Inline|void}
|
|
14157
|
+
*/
|
|
14158
|
+
process(parent, target, attributes) {
|
|
13935
14159
|
throw new Error(
|
|
13936
14160
|
`${this.constructor.name} must implement the process method`
|
|
13937
14161
|
)
|
|
@@ -13977,6 +14201,16 @@ class BlockMacroProcessor extends MacroProcessor {
|
|
|
13977
14201
|
set name(value) {
|
|
13978
14202
|
this._name = value;
|
|
13979
14203
|
}
|
|
14204
|
+
|
|
14205
|
+
/**
|
|
14206
|
+
* @param {AbstractBlock} parent - The enclosing block.
|
|
14207
|
+
* @param {string} target - The macro target.
|
|
14208
|
+
* @param {Record<string, unknown>} attributes - The parsed macro attributes.
|
|
14209
|
+
* @returns {Block} A block node created with one of the `createBlock` helpers.
|
|
14210
|
+
*/
|
|
14211
|
+
process(parent, target, attributes) {
|
|
14212
|
+
return super.process(parent, target, attributes)
|
|
14213
|
+
}
|
|
13980
14214
|
}
|
|
13981
14215
|
BlockMacroProcessor.DSL = MacroProcessorDsl;
|
|
13982
14216
|
|
|
@@ -14020,6 +14254,16 @@ class InlineMacroProcessor extends MacroProcessor {
|
|
|
14020
14254
|
))
|
|
14021
14255
|
}
|
|
14022
14256
|
|
|
14257
|
+
/**
|
|
14258
|
+
* @param {AbstractBlock} parent - The enclosing block.
|
|
14259
|
+
* @param {string} target - The macro target.
|
|
14260
|
+
* @param {Record<string, unknown>} attributes - The parsed macro attributes.
|
|
14261
|
+
* @returns {Inline} An Inline node created with `this.createInline(...)`.
|
|
14262
|
+
*/
|
|
14263
|
+
process(parent, target, attributes) {
|
|
14264
|
+
return super.process(parent, target, attributes)
|
|
14265
|
+
}
|
|
14266
|
+
|
|
14023
14267
|
resolveRegexp(name, format) {
|
|
14024
14268
|
if (!MacroNameRx.test(name)) {
|
|
14025
14269
|
throw new Error(`invalid name for inline macro: ${name}`)
|
|
@@ -14383,6 +14627,15 @@ class Registry {
|
|
|
14383
14627
|
return !!this._block_extensions
|
|
14384
14628
|
}
|
|
14385
14629
|
|
|
14630
|
+
/**
|
|
14631
|
+
* Retrieve all BlockProcessor Extension proxy objects.
|
|
14632
|
+
*
|
|
14633
|
+
* @returns {ProcessorExtension[]}
|
|
14634
|
+
*/
|
|
14635
|
+
blocks() {
|
|
14636
|
+
return this._block_extensions ? Object.values(this._block_extensions) : []
|
|
14637
|
+
}
|
|
14638
|
+
|
|
14386
14639
|
/**
|
|
14387
14640
|
* Check whether a BlockProcessor is registered for the given name and context.
|
|
14388
14641
|
*
|
|
@@ -14429,6 +14682,17 @@ class Registry {
|
|
|
14429
14682
|
return !!this._block_macro_extensions
|
|
14430
14683
|
}
|
|
14431
14684
|
|
|
14685
|
+
/**
|
|
14686
|
+
* Retrieve all BlockMacroProcessor Extension proxy objects.
|
|
14687
|
+
*
|
|
14688
|
+
* @returns {ProcessorExtension[]}
|
|
14689
|
+
*/
|
|
14690
|
+
blockMacros() {
|
|
14691
|
+
return this._block_macro_extensions
|
|
14692
|
+
? Object.values(this._block_macro_extensions)
|
|
14693
|
+
: []
|
|
14694
|
+
}
|
|
14695
|
+
|
|
14432
14696
|
/**
|
|
14433
14697
|
* Check whether a BlockMacroProcessor is registered for the given name.
|
|
14434
14698
|
*
|
|
@@ -14534,6 +14798,85 @@ class Registry {
|
|
|
14534
14798
|
return extension
|
|
14535
14799
|
}
|
|
14536
14800
|
|
|
14801
|
+
// ── JavaScript-style accessors ───────────────────────────────────────────────
|
|
14802
|
+
|
|
14803
|
+
/** @returns {object} the plain Object that maps names to groups for this registry. */
|
|
14804
|
+
getGroups() {
|
|
14805
|
+
return this.groups
|
|
14806
|
+
}
|
|
14807
|
+
|
|
14808
|
+
/** Alias for {@link preprocessors}. */
|
|
14809
|
+
getPreprocessors() {
|
|
14810
|
+
return this.preprocessors()
|
|
14811
|
+
}
|
|
14812
|
+
|
|
14813
|
+
/** Alias for {@link treeProcessors}. */
|
|
14814
|
+
getTreeProcessors() {
|
|
14815
|
+
return this.treeProcessors()
|
|
14816
|
+
}
|
|
14817
|
+
|
|
14818
|
+
/** Alias for {@link includeProcessors}. */
|
|
14819
|
+
getIncludeProcessors() {
|
|
14820
|
+
return this.includeProcessors()
|
|
14821
|
+
}
|
|
14822
|
+
|
|
14823
|
+
/** Alias for {@link postprocessors}. */
|
|
14824
|
+
getPostprocessors() {
|
|
14825
|
+
return this.postprocessors()
|
|
14826
|
+
}
|
|
14827
|
+
|
|
14828
|
+
/**
|
|
14829
|
+
* Alias for {@link docinfoProcessors}.
|
|
14830
|
+
*
|
|
14831
|
+
* @param {string|null} [location=null]
|
|
14832
|
+
*/
|
|
14833
|
+
getDocinfoProcessors(location = null) {
|
|
14834
|
+
return this.docinfoProcessors(location)
|
|
14835
|
+
}
|
|
14836
|
+
|
|
14837
|
+
/** Alias for {@link blocks}. */
|
|
14838
|
+
getBlocks() {
|
|
14839
|
+
return this.blocks()
|
|
14840
|
+
}
|
|
14841
|
+
|
|
14842
|
+
/** Alias for {@link blockMacros}. */
|
|
14843
|
+
getBlockMacros() {
|
|
14844
|
+
return this.blockMacros()
|
|
14845
|
+
}
|
|
14846
|
+
|
|
14847
|
+
/** Alias for {@link inlineMacros}. */
|
|
14848
|
+
getInlineMacros() {
|
|
14849
|
+
return this.inlineMacros()
|
|
14850
|
+
}
|
|
14851
|
+
|
|
14852
|
+
/**
|
|
14853
|
+
* Alias for {@link registeredForInlineMacro}.
|
|
14854
|
+
*
|
|
14855
|
+
* @param {string} name
|
|
14856
|
+
*/
|
|
14857
|
+
getInlineMacroFor(name) {
|
|
14858
|
+
return this.registeredForInlineMacro(name)
|
|
14859
|
+
}
|
|
14860
|
+
|
|
14861
|
+
/**
|
|
14862
|
+
* Alias for {@link registeredForBlock}.
|
|
14863
|
+
*
|
|
14864
|
+
* @param {string} name
|
|
14865
|
+
* @param {string} context
|
|
14866
|
+
*/
|
|
14867
|
+
getBlockFor(name, context) {
|
|
14868
|
+
return this.registeredForBlock(name, context)
|
|
14869
|
+
}
|
|
14870
|
+
|
|
14871
|
+
/**
|
|
14872
|
+
* Alias for {@link registeredForBlockMacro}.
|
|
14873
|
+
*
|
|
14874
|
+
* @param {string} name
|
|
14875
|
+
*/
|
|
14876
|
+
getBlockMacroFor(name) {
|
|
14877
|
+
return this.registeredForBlockMacro(name)
|
|
14878
|
+
}
|
|
14879
|
+
|
|
14537
14880
|
// ── Private helpers ──────────────────────────────────────────────────────────
|
|
14538
14881
|
|
|
14539
14882
|
/** @internal */
|
|
@@ -14759,6 +15102,15 @@ const Extensions = {
|
|
|
14759
15102
|
return _groups
|
|
14760
15103
|
},
|
|
14761
15104
|
|
|
15105
|
+
/**
|
|
15106
|
+
* Alias for {@link groups}.
|
|
15107
|
+
*
|
|
15108
|
+
* @returns {object}
|
|
15109
|
+
*/
|
|
15110
|
+
getGroups() {
|
|
15111
|
+
return this.groups()
|
|
15112
|
+
},
|
|
15113
|
+
|
|
14762
15114
|
/**
|
|
14763
15115
|
* Create a new Registry, optionally pre-populated with a named block.
|
|
14764
15116
|
*
|
|
@@ -15986,8 +16338,9 @@ class Document extends AbstractBlock {
|
|
|
15986
16338
|
* @param {Object} blockAttributes
|
|
15987
16339
|
*/
|
|
15988
16340
|
playbackAttributes(blockAttributes) {
|
|
15989
|
-
|
|
15990
|
-
|
|
16341
|
+
const entries = getAttributeEntries(blockAttributes);
|
|
16342
|
+
if (!entries) return
|
|
16343
|
+
for (const entry of entries) {
|
|
15991
16344
|
if (entry.negate) {
|
|
15992
16345
|
delete this.attributes[entry.name];
|
|
15993
16346
|
if (entry.name === 'compat-mode') this.compatMode = false;
|
|
@@ -16716,6 +17069,12 @@ class Document extends AbstractBlock {
|
|
|
16716
17069
|
* Handles titles (AbstractBlock), list item text, table cell text, and reftexts.
|
|
16717
17070
|
*/
|
|
16718
17071
|
async _resolveAllTexts(block) {
|
|
17072
|
+
// The header section lives outside document.blocks; pre-compute its title here so
|
|
17073
|
+
// that doc.doctitle() returns the fully-substituted title (with replacements applied,
|
|
17074
|
+
// e.g. ' → ’) rather than the header-subs-only fallback.
|
|
17075
|
+
if (block === this && this.header) {
|
|
17076
|
+
await this.header.precomputeTitle?.();
|
|
17077
|
+
}
|
|
16719
17078
|
// Skip title pre-computation for blocks with an explicit empty id ([id=]).
|
|
16720
17079
|
// In Ruby, apply_title_subs is lazy: it is never called during parsing for such
|
|
16721
17080
|
// blocks because section.title is never accessed. An explicit empty id is
|
|
@@ -16799,7 +17158,7 @@ class Document extends AbstractBlock {
|
|
|
16799
17158
|
* @internal
|
|
16800
17159
|
*/
|
|
16801
17160
|
_clearPlaybackAttributes(attributes) {
|
|
16802
|
-
delete attributes
|
|
17161
|
+
delete attributes[ATTR_ENTRIES_KEY];
|
|
16803
17162
|
}
|
|
16804
17163
|
|
|
16805
17164
|
/**
|
|
@@ -19527,17 +19886,23 @@ async function load$1(input, options = {}) {
|
|
|
19527
19886
|
// Shallow-copy options so we don't mutate the caller's object.
|
|
19528
19887
|
options = Object.assign({}, options);
|
|
19529
19888
|
|
|
19530
|
-
const timings = options.timings ?? null;
|
|
19531
|
-
if (timings) timings.start('read');
|
|
19532
|
-
|
|
19533
19889
|
// ── Logger override ───────────────────────────────────────────────────────
|
|
19890
|
+
// When a logger option is supplied, run the conversion in an async-local
|
|
19891
|
+
// context so the logger is scoped to this call only — no global mutation,
|
|
19892
|
+
// which makes concurrent callers (e.g. parallel Deno tests) safe.
|
|
19534
19893
|
if ('logger' in options) {
|
|
19535
|
-
const
|
|
19536
|
-
|
|
19537
|
-
|
|
19538
|
-
}
|
|
19894
|
+
const newLogger = options.logger ?? new NullLogger();
|
|
19895
|
+
delete options.logger;
|
|
19896
|
+
return withLogger(newLogger, () => _doLoad(input, options, newLogger))
|
|
19539
19897
|
}
|
|
19540
19898
|
|
|
19899
|
+
return _doLoad(input, options)
|
|
19900
|
+
}
|
|
19901
|
+
|
|
19902
|
+
async function _doLoad(input, options, explicitLogger = null) {
|
|
19903
|
+
const timings = options.timings ?? null;
|
|
19904
|
+
if (timings) timings.start('read');
|
|
19905
|
+
|
|
19541
19906
|
// ── Attributes normalisation ──────────────────────────────────────────────
|
|
19542
19907
|
let attrs = options.attributes;
|
|
19543
19908
|
if (!attrs) {
|
|
@@ -19569,11 +19934,9 @@ async function load$1(input, options = {}) {
|
|
|
19569
19934
|
attrs.docname = basename(inputPath, docfilesuffix);
|
|
19570
19935
|
}
|
|
19571
19936
|
source = await _readStream(input);
|
|
19572
|
-
} else if (
|
|
19573
|
-
|
|
19574
|
-
|
|
19575
|
-
) {
|
|
19576
|
-
source = input.toString('utf8');
|
|
19937
|
+
} else if (input instanceof Uint8Array) {
|
|
19938
|
+
// Covers both Node.js Buffer (a Uint8Array subclass) and browser Uint8Array shims.
|
|
19939
|
+
source = new TextDecoder('utf-8').decode(input);
|
|
19577
19940
|
} else if (typeof input === 'string') {
|
|
19578
19941
|
source = input;
|
|
19579
19942
|
} else if (Array.isArray(input)) {
|
|
@@ -19636,6 +19999,19 @@ async function load$1(input, options = {}) {
|
|
|
19636
19999
|
}
|
|
19637
20000
|
|
|
19638
20001
|
if (timings) timings.record('parse');
|
|
20002
|
+
|
|
20003
|
+
// Persist the logger on the Document instance so that doc.convert()
|
|
20004
|
+
// (called by convert.js after the async-local context ends) still routes
|
|
20005
|
+
// logging through the caller-supplied logger.
|
|
20006
|
+
// ALS provides it in Node.js/Deno; the explicit parameter covers browser fallback.
|
|
20007
|
+
const contextLogger = getContextLogger() ?? explicitLogger;
|
|
20008
|
+
if (contextLogger) {
|
|
20009
|
+
Object.defineProperty(doc, 'logger', {
|
|
20010
|
+
get: () => contextLogger,
|
|
20011
|
+
configurable: true,
|
|
20012
|
+
});
|
|
20013
|
+
}
|
|
20014
|
+
|
|
19639
20015
|
return doc
|
|
19640
20016
|
}
|
|
19641
20017
|
|
|
@@ -22534,7 +22910,7 @@ class TemplateConverter extends ConverterBase {
|
|
|
22534
22910
|
|
|
22535
22911
|
let entries;
|
|
22536
22912
|
try {
|
|
22537
|
-
entries = await node_fs.promises.readdir(templateDir);
|
|
22913
|
+
entries = (await node_fs.promises.readdir(templateDir)).sort();
|
|
22538
22914
|
} catch {
|
|
22539
22915
|
return result
|
|
22540
22916
|
}
|