@asciidoctor/core 4.0.0-alpha.6 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/browser/index.js +204 -57
- package/build/node/index.cjs +204 -56
- package/package.json +2 -2
- package/src/browser/reader.js +2 -2
- package/src/browser.js +8 -1
- package/src/document.js +15 -1
- package/src/extensions.js +125 -22
- package/src/index.js +8 -1
- package/src/logging.js +41 -10
- package/src/parser.js +13 -2
- package/src/reader.js +25 -13
- package/src/substitutors.js +9 -9
- package/types/extensions.d.ts +68 -6
- package/types/index.d.cts +2 -1
- package/types/index.d.ts +2 -1
- package/types/logging.d.ts +49 -5
- package/types/reader.d.ts +2 -2
- package/types/substitutors.d.ts +18 -18
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.
|
|
8
|
+
var version = "4.0.1";
|
|
9
9
|
const packageJson = {
|
|
10
10
|
version: version};
|
|
11
11
|
|
|
@@ -1752,14 +1752,23 @@ Logger.BasicFormatter = class {
|
|
|
1752
1752
|
|
|
1753
1753
|
Logger.AutoFormattingMessage = {
|
|
1754
1754
|
/**
|
|
1755
|
-
* Attach auto-formatting to any plain object carrying
|
|
1756
|
-
*
|
|
1755
|
+
* Attach auto-formatting to any plain object carrying
|
|
1756
|
+
* { text, source_location, include_location }.
|
|
1757
|
+
*
|
|
1758
|
+
* The location(s) are rendered only by inspect()/toString() (used when a
|
|
1759
|
+
* stderr Logger formats the line); the structured `source_location` /
|
|
1760
|
+
* `include_location` remain on the object so a MemoryLogger can record them
|
|
1761
|
+
* on the resulting LogMessage without duplicating them inside `text`.
|
|
1762
|
+
* @param {{text: string, source_location?: any, include_location?: any}} obj
|
|
1757
1763
|
* @returns {typeof obj} The same object with inspect() and toString() added.
|
|
1758
1764
|
*/
|
|
1759
1765
|
attach(obj) {
|
|
1760
1766
|
obj.inspect = function () {
|
|
1761
1767
|
const sloc = this.source_location;
|
|
1762
|
-
|
|
1768
|
+
const iloc = this.include_location;
|
|
1769
|
+
let text = sloc ? `${sloc}: ${this.text}` : this.text;
|
|
1770
|
+
if (iloc) text += ` (${iloc})`;
|
|
1771
|
+
return text
|
|
1763
1772
|
};
|
|
1764
1773
|
obj.toString = obj.inspect;
|
|
1765
1774
|
return obj
|
|
@@ -1770,27 +1779,45 @@ Logger.AutoFormattingMessage = {
|
|
|
1770
1779
|
|
|
1771
1780
|
/** Wrapper stored by MemoryLogger; provides getSeverity/getText/getSourceLocation. */
|
|
1772
1781
|
class LogMessage {
|
|
1782
|
+
/**
|
|
1783
|
+
* @param {string} severity - Severity label, e.g. 'ERROR'.
|
|
1784
|
+
* @param {string|{text: string, source_location?: import('./reader.js').Cursor}|null} message
|
|
1785
|
+
*/
|
|
1773
1786
|
constructor(severity, message) {
|
|
1774
1787
|
this.message = message;
|
|
1788
|
+
/** @type {string} */
|
|
1775
1789
|
this.severity = severity; // string label, e.g. 'ERROR'
|
|
1776
1790
|
// AutoFormattingMessage objects carry { text, source_location }
|
|
1777
1791
|
if (message !== null && typeof message === 'object' && 'text' in message) {
|
|
1778
|
-
|
|
1779
|
-
this.
|
|
1792
|
+
/** @type {string} */
|
|
1793
|
+
this.text = message.text;
|
|
1794
|
+
/** @type {import('./reader.js').Cursor|null} */
|
|
1795
|
+
this.sourceLocation = message.source_location ?? null;
|
|
1780
1796
|
} else {
|
|
1781
|
-
this.
|
|
1782
|
-
this.
|
|
1797
|
+
this.text = message != null ? String(message) : '';
|
|
1798
|
+
this.sourceLocation = null;
|
|
1783
1799
|
}
|
|
1784
1800
|
}
|
|
1785
1801
|
|
|
1802
|
+
/**
|
|
1803
|
+
* @returns {string} The severity label, e.g. 'ERROR'.
|
|
1804
|
+
*/
|
|
1786
1805
|
getSeverity() {
|
|
1787
1806
|
return this.severity
|
|
1788
1807
|
}
|
|
1808
|
+
|
|
1809
|
+
/**
|
|
1810
|
+
* @returns {string} The message text.
|
|
1811
|
+
*/
|
|
1789
1812
|
getText() {
|
|
1790
|
-
return this.
|
|
1813
|
+
return this.text
|
|
1791
1814
|
}
|
|
1815
|
+
|
|
1816
|
+
/**
|
|
1817
|
+
* @returns {import('./reader.js').Cursor|undefined} The source location, if any.
|
|
1818
|
+
*/
|
|
1792
1819
|
getSourceLocation() {
|
|
1793
|
-
return this.
|
|
1820
|
+
return this.sourceLocation ?? undefined
|
|
1794
1821
|
}
|
|
1795
1822
|
}
|
|
1796
1823
|
|
|
@@ -1803,6 +1830,7 @@ class MemoryLogger {
|
|
|
1803
1830
|
// matching Ruby's MemoryLogger (level: UNKNOWN). The add() method stores all
|
|
1804
1831
|
// messages unconditionally — level is only used by the isDebug() guard.
|
|
1805
1832
|
this.level = Severity.UNKNOWN;
|
|
1833
|
+
/** @type {LogMessage[]} */
|
|
1806
1834
|
this.messages = [];
|
|
1807
1835
|
}
|
|
1808
1836
|
|
|
@@ -1810,6 +1838,9 @@ class MemoryLogger {
|
|
|
1810
1838
|
return new MemoryLogger()
|
|
1811
1839
|
}
|
|
1812
1840
|
|
|
1841
|
+
/**
|
|
1842
|
+
* @returns {LogMessage[]} The log messages recorded so far, in order.
|
|
1843
|
+
*/
|
|
1813
1844
|
getMessages() {
|
|
1814
1845
|
return this.messages
|
|
1815
1846
|
}
|
|
@@ -6275,7 +6306,7 @@ function resolveBrowserIncludePath(reader, target, attrlist) {
|
|
|
6275
6306
|
// ── Rule 2: target is an absolute URL (http:// / https:// / …) ───────────
|
|
6276
6307
|
} else if (isUriish(pTarget)) {
|
|
6277
6308
|
const descends = pathResolver.descendsFrom(pTarget, baseDir);
|
|
6278
|
-
if (descends === false && !doc.
|
|
6309
|
+
if (descends === false && !doc.hasAttribute('allow-uri-read')) {
|
|
6279
6310
|
return reader.replaceNextLine(_linkReplacement(reader, target, attrlist))
|
|
6280
6311
|
}
|
|
6281
6312
|
incPath = relpath = pTarget;
|
|
@@ -6309,7 +6340,7 @@ function resolveBrowserIncludePath(reader, target, attrlist) {
|
|
|
6309
6340
|
} else {
|
|
6310
6341
|
// Nested include: context dir is an absolute URL.
|
|
6311
6342
|
const ctxDescends = pathResolver.descendsFrom(ctxDir, baseDir);
|
|
6312
|
-
if (ctxDescends !== false || doc.
|
|
6343
|
+
if (ctxDescends !== false || doc.hasAttribute('allow-uri-read')) {
|
|
6313
6344
|
incPath = `${ctxDir}/${pTarget}`;
|
|
6314
6345
|
relpath = ctxDescends !== false ? incPath.slice(ctxDescends) : pTarget;
|
|
6315
6346
|
} else {
|
|
@@ -6973,22 +7004,34 @@ class Reader {
|
|
|
6973
7004
|
}
|
|
6974
7005
|
|
|
6975
7006
|
/** @param {string} msg @param {{ sourceLocation?: any, includeLocation?: any }} [opts] */
|
|
6976
|
-
_logWarn(msg,
|
|
6977
|
-
|
|
6978
|
-
if (includeLocation) text += ` (${includeLocation.lineInfo})`;
|
|
6979
|
-
this.logger.warn(text);
|
|
7007
|
+
_logWarn(msg, opts = {}) {
|
|
7008
|
+
this.logger.warn(this._messageWithContext(msg, opts));
|
|
6980
7009
|
}
|
|
6981
7010
|
_logError(msg, opts = {}) {
|
|
6982
|
-
|
|
6983
|
-
? `${opts.sourceLocation.lineInfo}: ${msg}`
|
|
6984
|
-
: msg;
|
|
6985
|
-
if (opts.includeLocation) text += ` (${opts.includeLocation.lineInfo})`;
|
|
6986
|
-
this.logger.error(text);
|
|
7011
|
+
this.logger.error(this._messageWithContext(msg, opts));
|
|
6987
7012
|
}
|
|
6988
7013
|
/** @param {string} msg @param {{ sourceLocation?: any }} [opts] */
|
|
6989
|
-
_logInfo(msg,
|
|
6990
|
-
|
|
6991
|
-
|
|
7014
|
+
_logInfo(msg, opts = {}) {
|
|
7015
|
+
this.logger.info(this._messageWithContext(msg, opts));
|
|
7016
|
+
}
|
|
7017
|
+
|
|
7018
|
+
/**
|
|
7019
|
+
* Build an auto-formatting message that keeps the cursor as a structured
|
|
7020
|
+
* source_location (rather than baking it into the text). When displayed by a
|
|
7021
|
+
* stderr Logger the location is rendered as a "<path>: line <N>: " prefix, but
|
|
7022
|
+
* a MemoryLogger records it separately on the LogMessage so consumers can call
|
|
7023
|
+
* getSourceLocation(). Mirrors Ruby's Logging#message_with_context.
|
|
7024
|
+
* @param {string} msg
|
|
7025
|
+
* @param {{ sourceLocation?: any, includeLocation?: any }} [opts]
|
|
7026
|
+
* @internal
|
|
7027
|
+
*/
|
|
7028
|
+
_messageWithContext(msg, { sourceLocation, includeLocation } = {}) {
|
|
7029
|
+
if (!sourceLocation && !includeLocation) return msg
|
|
7030
|
+
return Logger.AutoFormattingMessage.attach({
|
|
7031
|
+
text: msg,
|
|
7032
|
+
source_location: sourceLocation ?? null,
|
|
7033
|
+
include_location: includeLocation ?? null,
|
|
7034
|
+
})
|
|
6992
7035
|
}
|
|
6993
7036
|
}
|
|
6994
7037
|
|
|
@@ -7746,7 +7789,7 @@ class PreprocessorReader extends Reader {
|
|
|
7746
7789
|
}
|
|
7747
7790
|
|
|
7748
7791
|
if (isUriish(target) || typeof this._dir !== 'string') {
|
|
7749
|
-
if (!doc.
|
|
7792
|
+
if (!doc.hasAttribute('allow-uri-read')) {
|
|
7750
7793
|
this._logWarn(
|
|
7751
7794
|
`cannot include contents of URI: ${target} (allow-uri-read attribute not enabled)`,
|
|
7752
7795
|
{ sourceLocation: this.cursor }
|
|
@@ -10356,7 +10399,12 @@ class Parser {
|
|
|
10356
10399
|
}
|
|
10357
10400
|
}
|
|
10358
10401
|
(intro ?? section).blocks.push(newBlock);
|
|
10359
|
-
|
|
10402
|
+
// Reset the shared attributes object for the next block. Use Reflect.ownKeys
|
|
10403
|
+
// (not Object.keys) so the Symbol-keyed attribute entries (ATTR_ENTRIES_KEY)
|
|
10404
|
+
// are cleared too; otherwise the array of AttributeEntry objects leaks and
|
|
10405
|
+
// accumulates across blocks, causing reassigned attributes (e.g. a body-level
|
|
10406
|
+
// `:name:` redefined later) to all resolve to the final value at playback time.
|
|
10407
|
+
for (const key of Reflect.ownKeys(attributes)) delete attributes[key];
|
|
10360
10408
|
}
|
|
10361
10409
|
}
|
|
10362
10410
|
|
|
@@ -11203,7 +11251,13 @@ class Parser {
|
|
|
11203
11251
|
}
|
|
11204
11252
|
}
|
|
11205
11253
|
|
|
11206
|
-
|
|
11254
|
+
// Reflect.ownKeys (not Object.keys) so a block carrying only Symbol-keyed
|
|
11255
|
+
// attribute entries (ATTR_ENTRIES_KEY) — e.g. an `:attr:` entry immediately
|
|
11256
|
+
// preceding a list or table — still receives them, matching Ruby's
|
|
11257
|
+
// `attributes.empty?` where the `:attribute_entries` key is counted. Without this
|
|
11258
|
+
// the entries are dropped and the attribute is not played back for that block.
|
|
11259
|
+
if (Reflect.ownKeys(attributes).length > 0)
|
|
11260
|
+
block.updateAttributes(attributes);
|
|
11207
11261
|
block.commitSubs();
|
|
11208
11262
|
|
|
11209
11263
|
if (block.hasSub('callouts')) {
|
|
@@ -13473,6 +13527,7 @@ function _uniform(str, chr, len) {
|
|
|
13473
13527
|
* DSL interface for include processors.
|
|
13474
13528
|
*
|
|
13475
13529
|
* @typedef {DocumentProcessorDslInterface & {
|
|
13530
|
+
* handles(fn: (target: string) => boolean): void;
|
|
13476
13531
|
* handles(fn: (doc: Document, target: string) => boolean): void;
|
|
13477
13532
|
* }} IncludeProcessorDslInterface
|
|
13478
13533
|
*/
|
|
@@ -13523,7 +13578,7 @@ function _uniform(str, chr, len) {
|
|
|
13523
13578
|
* - Called with a single Function argument → stores it as the process block.
|
|
13524
13579
|
* - Called with non-Function arguments → invokes the stored process block.
|
|
13525
13580
|
*
|
|
13526
|
-
* The this context inside a stored process function is bound to the processor
|
|
13581
|
+
* The `this` context inside a stored process function is bound to the processor
|
|
13527
13582
|
* instance at definition time.
|
|
13528
13583
|
*/
|
|
13529
13584
|
const ProcessorDsl = {
|
|
@@ -13697,6 +13752,35 @@ const SyntaxProcessorDsl = {
|
|
|
13697
13752
|
const IncludeProcessorDsl = {
|
|
13698
13753
|
...DocumentProcessorDsl,
|
|
13699
13754
|
|
|
13755
|
+
/**
|
|
13756
|
+
* @overload
|
|
13757
|
+
* @param {(target: string) => boolean} fn - Predicate that receives only the include target.
|
|
13758
|
+
* @returns {void}
|
|
13759
|
+
*/
|
|
13760
|
+
/**
|
|
13761
|
+
* @overload
|
|
13762
|
+
* @param {(doc: Document, target: string) => boolean} fn - Predicate that receives the document and the include target.
|
|
13763
|
+
* @returns {void}
|
|
13764
|
+
*/
|
|
13765
|
+
/**
|
|
13766
|
+
* @overload
|
|
13767
|
+
* @param {Document} doc - The document being parsed.
|
|
13768
|
+
* @param {string} target - The include target.
|
|
13769
|
+
* @returns {boolean}
|
|
13770
|
+
*/
|
|
13771
|
+
/**
|
|
13772
|
+
* Register a function that decides whether this include processor handles a given target,
|
|
13773
|
+
* or invoke the registered handler.
|
|
13774
|
+
*
|
|
13775
|
+
* **Setter form** — register a predicate. The callback may accept either just the target
|
|
13776
|
+
* string (arity 1) or both the document and the target string (arity 2).
|
|
13777
|
+
*
|
|
13778
|
+
* **Invoker form** — call the registered predicate with `(doc, target)` and return its
|
|
13779
|
+
* result, or return `true` if no predicate has been registered.
|
|
13780
|
+
*
|
|
13781
|
+
* @param {...*} args
|
|
13782
|
+
* @returns {boolean | void}
|
|
13783
|
+
*/
|
|
13700
13784
|
handles(...args) {
|
|
13701
13785
|
if (args.length === 1 && typeof args[0] === 'function') {
|
|
13702
13786
|
const fn = args[0];
|
|
@@ -14464,6 +14548,8 @@ class ProcessorExtension extends Extension {
|
|
|
14464
14548
|
super(kind, instance, instance.config);
|
|
14465
14549
|
this.processMethod =
|
|
14466
14550
|
processMethod || ((...args) => instance.process(...args));
|
|
14551
|
+
/** @internal */
|
|
14552
|
+
this._direct = false;
|
|
14467
14553
|
}
|
|
14468
14554
|
}
|
|
14469
14555
|
|
|
@@ -14491,10 +14577,24 @@ const SYNTAX_PROCESSOR_CLASSES = {
|
|
|
14491
14577
|
* Registry holds the extensions which have been registered and activated, has
|
|
14492
14578
|
* methods for registering or defining a processor and looks up extensions
|
|
14493
14579
|
* stored in the registry during parsing.
|
|
14580
|
+
*
|
|
14581
|
+
* A registry can be reused across multiple conversions. Extensions registered
|
|
14582
|
+
* via a group block (passed to {@link Extensions.create} or
|
|
14583
|
+
* {@link Extensions.register}) are re-executed on every activation. Extensions
|
|
14584
|
+
* registered directly on the registry instance (e.g. `registry.preprocessor(fn)`)
|
|
14585
|
+
* are preserved across activations.
|
|
14586
|
+
*
|
|
14587
|
+
* @example
|
|
14588
|
+
* const registry = Extensions.create('my-ext', function () {
|
|
14589
|
+
* this.preprocessor(function () { ... })
|
|
14590
|
+
* })
|
|
14591
|
+
* // registry can be passed to multiple conversions safely
|
|
14494
14592
|
*/
|
|
14495
14593
|
class Registry {
|
|
14496
14594
|
constructor(groups = {}) {
|
|
14497
14595
|
this.groups = groups;
|
|
14596
|
+
/** @internal */
|
|
14597
|
+
this._activating = false;
|
|
14498
14598
|
this._reset();
|
|
14499
14599
|
}
|
|
14500
14600
|
|
|
@@ -14511,18 +14611,26 @@ class Registry {
|
|
|
14511
14611
|
...Object.values(Extensions.groups()),
|
|
14512
14612
|
...Object.values(this.groups),
|
|
14513
14613
|
];
|
|
14514
|
-
|
|
14515
|
-
|
|
14516
|
-
|
|
14517
|
-
if (
|
|
14518
|
-
|
|
14519
|
-
|
|
14520
|
-
|
|
14521
|
-
|
|
14614
|
+
this._activating = true;
|
|
14615
|
+
try {
|
|
14616
|
+
for (const group of extGroups) {
|
|
14617
|
+
if (typeof group === 'function') {
|
|
14618
|
+
// Check if it is a class (constructor) with an activate prototype method.
|
|
14619
|
+
if (
|
|
14620
|
+
group.prototype &&
|
|
14621
|
+
typeof group.prototype.activate === 'function'
|
|
14622
|
+
) {
|
|
14623
|
+
new group().activate(this);
|
|
14624
|
+
} else {
|
|
14625
|
+
// Plain function — call in the context of this registry (like instance_exec).
|
|
14626
|
+
group.length === 0 ? group.call(this) : group(this);
|
|
14627
|
+
}
|
|
14628
|
+
} else if (group && typeof group.activate === 'function') {
|
|
14629
|
+
group.activate(this);
|
|
14522
14630
|
}
|
|
14523
|
-
} else if (group && typeof group.activate === 'function') {
|
|
14524
|
-
group.activate(this);
|
|
14525
14631
|
}
|
|
14632
|
+
} finally {
|
|
14633
|
+
this._activating = false;
|
|
14526
14634
|
}
|
|
14527
14635
|
return this
|
|
14528
14636
|
}
|
|
@@ -15098,6 +15206,7 @@ class Registry {
|
|
|
15098
15206
|
}
|
|
15099
15207
|
|
|
15100
15208
|
const extension = new ProcessorExtension(kind, processorInstance);
|
|
15209
|
+
extension._direct = !this._activating;
|
|
15101
15210
|
extension.config.position === '>>'
|
|
15102
15211
|
? store.unshift(extension)
|
|
15103
15212
|
: store.push(extension);
|
|
@@ -15169,27 +15278,44 @@ class Registry {
|
|
|
15169
15278
|
}
|
|
15170
15279
|
|
|
15171
15280
|
store[name] = new ProcessorExtension(kind, processorInstance);
|
|
15281
|
+
store[name]._direct = !this._activating;
|
|
15172
15282
|
return store[name]
|
|
15173
15283
|
}
|
|
15174
15284
|
|
|
15175
15285
|
/** @internal */
|
|
15176
15286
|
_reset() {
|
|
15287
|
+
// Keep extensions registered directly (outside a group); only clear group-registered ones.
|
|
15288
|
+
// Extensions tagged with _direct=true survive across activations.
|
|
15289
|
+
const keepArr = (arr) => {
|
|
15290
|
+
const kept = arr?.filter((e) => e._direct) ?? [];
|
|
15291
|
+
return kept.length ? kept : null
|
|
15292
|
+
};
|
|
15293
|
+
const keepMap = (map) => {
|
|
15294
|
+
if (!map) return null
|
|
15295
|
+
const kept = Object.create(null);
|
|
15296
|
+
for (const [k, v] of Object.entries(map)) if (v._direct) kept[k] = v;
|
|
15297
|
+
return Object.keys(kept).length ? kept : null
|
|
15298
|
+
};
|
|
15177
15299
|
/** @internal */
|
|
15178
|
-
this._preprocessor_extensions =
|
|
15300
|
+
this._preprocessor_extensions = keepArr(this._preprocessor_extensions);
|
|
15179
15301
|
/** @internal */
|
|
15180
|
-
this._tree_processor_extensions =
|
|
15302
|
+
this._tree_processor_extensions = keepArr(this._tree_processor_extensions);
|
|
15181
15303
|
/** @internal */
|
|
15182
|
-
this._postprocessor_extensions =
|
|
15304
|
+
this._postprocessor_extensions = keepArr(this._postprocessor_extensions);
|
|
15183
15305
|
/** @internal */
|
|
15184
|
-
this._include_processor_extensions =
|
|
15306
|
+
this._include_processor_extensions = keepArr(
|
|
15307
|
+
this._include_processor_extensions
|
|
15308
|
+
);
|
|
15185
15309
|
/** @internal */
|
|
15186
|
-
this._docinfo_processor_extensions =
|
|
15310
|
+
this._docinfo_processor_extensions = keepArr(
|
|
15311
|
+
this._docinfo_processor_extensions
|
|
15312
|
+
);
|
|
15187
15313
|
/** @internal */
|
|
15188
|
-
this._block_extensions =
|
|
15314
|
+
this._block_extensions = keepMap(this._block_extensions);
|
|
15189
15315
|
/** @internal */
|
|
15190
|
-
this._block_macro_extensions =
|
|
15316
|
+
this._block_macro_extensions = keepMap(this._block_macro_extensions);
|
|
15191
15317
|
/** @internal */
|
|
15192
|
-
this._inline_macro_extensions =
|
|
15318
|
+
this._inline_macro_extensions = keepMap(this._inline_macro_extensions);
|
|
15193
15319
|
this.document = null;
|
|
15194
15320
|
}
|
|
15195
15321
|
|
|
@@ -15272,6 +15398,13 @@ const Extensions = {
|
|
|
15272
15398
|
/**
|
|
15273
15399
|
* Create a new Registry, optionally pre-populated with a named block.
|
|
15274
15400
|
*
|
|
15401
|
+
* When a `block` is provided it is stored as a group and re-executed on every
|
|
15402
|
+
* activation, making the registry safe to reuse across multiple conversions.
|
|
15403
|
+
* Without a `block`, any extensions registered directly on the returned registry
|
|
15404
|
+
* (e.g. `registry.preprocessor(fn)`) are stored in transient state that is
|
|
15405
|
+
* cleared on every activation — those registrations will be lost from the second
|
|
15406
|
+
* conversion onwards. Prefer the block form when the registry may be reused.
|
|
15407
|
+
*
|
|
15275
15408
|
* @param {string|null} [name=null] - Optional name for the group; auto-generated if omitted.
|
|
15276
15409
|
* @param {Function|null} [block=null] - Optional function to register as the group.
|
|
15277
15410
|
* @returns {Registry}
|
|
@@ -16152,8 +16285,16 @@ class Document extends AbstractBlock {
|
|
|
16152
16285
|
}
|
|
16153
16286
|
|
|
16154
16287
|
// Pre-compute all async text values (titles, list item text, cell text, reftexts)
|
|
16155
|
-
// so that synchronous getters work correctly during conversion.
|
|
16288
|
+
// so that synchronous getters work correctly during conversion. _resolveAllTexts
|
|
16289
|
+
// replays attribute entries in document order (mirroring conversion) so body-level
|
|
16290
|
+
// attribute (re)assignments are in scope; snapshot and restore the document
|
|
16291
|
+
// attributes so the downstream steps and conversion still start from the restored
|
|
16292
|
+
// (header) state, matching Ruby's restore_attributes-before-convert invariant.
|
|
16293
|
+
const attributesSnapshot = { ...this.attributes };
|
|
16156
16294
|
await this._resolveAllTexts(this);
|
|
16295
|
+
for (const key of Reflect.ownKeys(this.attributes))
|
|
16296
|
+
delete this.attributes[key];
|
|
16297
|
+
Object.assign(this.attributes, attributesSnapshot);
|
|
16157
16298
|
// Reset the footnote counter so that body-content footnotes (processed during conversion)
|
|
16158
16299
|
// start numbering from 1, reproducing Ruby's "out of sequence" quirk: title footnotes are
|
|
16159
16300
|
// numbered during parsing via apply_title_subs, then the counter restarts for body content.
|
|
@@ -17227,6 +17368,12 @@ class Document extends AbstractBlock {
|
|
|
17227
17368
|
* Handles titles (AbstractBlock), list item text, table cell text, and reftexts.
|
|
17228
17369
|
*/
|
|
17229
17370
|
async _resolveAllTexts(block) {
|
|
17371
|
+
// Replay this block's attribute entries (in document order, since the walk is
|
|
17372
|
+
// depth-first pre-order like conversion) so that body-level attribute assignments
|
|
17373
|
+
// and reassignments are in scope when the block's — and its descendants' and later
|
|
17374
|
+
// siblings' — title / list item / table cell / reftext values are substituted.
|
|
17375
|
+
// Mirrors AbstractBlock#convert, which calls playbackAttributes before converting.
|
|
17376
|
+
this.playbackAttributes(block.attributes);
|
|
17230
17377
|
// The header section lives outside document.blocks; pre-compute its title here so
|
|
17231
17378
|
// that doc.doctitle() returns the fully-substituted title (with replacements applied,
|
|
17232
17379
|
// e.g. ' → ’) rather than the header-subs-only fallback.
|
|
@@ -17955,7 +18102,7 @@ const Substitutors = {
|
|
|
17955
18102
|
*
|
|
17956
18103
|
* @param {string|string[]} text - The text to process; must not be null.
|
|
17957
18104
|
* @param {string[]} [subs=NORMAL_SUBS] - The substitutions to perform.
|
|
17958
|
-
* @returns {string|string[]} Text with substitutions applied.
|
|
18105
|
+
* @returns {Promise<string|string[]>} Text with substitutions applied.
|
|
17959
18106
|
*/
|
|
17960
18107
|
async applySubs(text, subs = NORMAL_SUBS) {
|
|
17961
18108
|
const isEmpty = Array.isArray(text) ? text.length === 0 : text.length === 0;
|
|
@@ -18069,7 +18216,7 @@ const Substitutors = {
|
|
|
18069
18216
|
* Substitute quoted text (emphasis, strong, monospaced, etc.)
|
|
18070
18217
|
*
|
|
18071
18218
|
* @param {string} text
|
|
18072
|
-
* @returns {string}
|
|
18219
|
+
* @returns {Promise<string>}
|
|
18073
18220
|
*/
|
|
18074
18221
|
async subQuotes(text) {
|
|
18075
18222
|
const compat = this.document.compatMode;
|
|
@@ -18241,7 +18388,7 @@ const Substitutors = {
|
|
|
18241
18388
|
* Substitute inline macros (links, images, etc.)
|
|
18242
18389
|
*
|
|
18243
18390
|
* @param {string} text
|
|
18244
|
-
* @returns {string}
|
|
18391
|
+
* @returns {Promise<string>}
|
|
18245
18392
|
*/
|
|
18246
18393
|
async subMacros(text) {
|
|
18247
18394
|
const foundSquareBracket = text.includes('[');
|
|
@@ -19136,7 +19283,7 @@ const Substitutors = {
|
|
|
19136
19283
|
* Substitute post replacements (hard line breaks).
|
|
19137
19284
|
*
|
|
19138
19285
|
* @param {string} text
|
|
19139
|
-
* @returns {string}
|
|
19286
|
+
* @returns {Promise<string>}
|
|
19140
19287
|
*/
|
|
19141
19288
|
async subPostReplacements(text) {
|
|
19142
19289
|
if (
|
|
@@ -19174,7 +19321,7 @@ const Substitutors = {
|
|
|
19174
19321
|
*
|
|
19175
19322
|
* @param {string} source
|
|
19176
19323
|
* @param {boolean} processCallouts
|
|
19177
|
-
* @returns {string}
|
|
19324
|
+
* @returns {Promise<string>}
|
|
19178
19325
|
*/
|
|
19179
19326
|
async subSource(source, processCallouts) {
|
|
19180
19327
|
return processCallouts
|
|
@@ -19186,7 +19333,7 @@ const Substitutors = {
|
|
|
19186
19333
|
* Substitute callout source references.
|
|
19187
19334
|
*
|
|
19188
19335
|
* @param {string} text
|
|
19189
|
-
* @returns {string}
|
|
19336
|
+
* @returns {Promise<string>}
|
|
19190
19337
|
*/
|
|
19191
19338
|
async subCallouts(text) {
|
|
19192
19339
|
const calloutRx = this.hasAttribute('line-comment')
|
|
@@ -19215,7 +19362,7 @@ const Substitutors = {
|
|
|
19215
19362
|
*
|
|
19216
19363
|
* @param {string} source
|
|
19217
19364
|
* @param {boolean} processCallouts
|
|
19218
|
-
* @returns {string}
|
|
19365
|
+
* @returns {Promise<string>}
|
|
19219
19366
|
*/
|
|
19220
19367
|
async highlightSource(source, processCallouts) {
|
|
19221
19368
|
const syntaxHl = this.document.syntaxHighlighter;
|
|
@@ -19561,7 +19708,7 @@ const Substitutors = {
|
|
|
19561
19708
|
* Restore passthrough text by reinserting into placeholder positions.
|
|
19562
19709
|
*
|
|
19563
19710
|
* @param {string} text
|
|
19564
|
-
* @returns {string}
|
|
19711
|
+
* @returns {Promise<string>}
|
|
19565
19712
|
*/
|
|
19566
19713
|
async restorePassthroughs(text) {
|
|
19567
19714
|
if (!text.includes(PASS_START)) return text
|
|
@@ -19753,7 +19900,7 @@ const Substitutors = {
|
|
|
19753
19900
|
* @param {string} attrlist
|
|
19754
19901
|
* @param {string[]} [posattrs=[]]
|
|
19755
19902
|
* @param {Object} [opts={}]
|
|
19756
|
-
* @returns {Object}
|
|
19903
|
+
* @returns {Promise<Object>}
|
|
19757
19904
|
*/
|
|
19758
19905
|
async parseAttributes(attrlist, posattrs = [], opts = {}) {
|
|
19759
19906
|
if (!attrlist || attrlist.length === 0) return {}
|
|
@@ -25250,6 +25397,7 @@ exports.Inline = Inline;
|
|
|
25250
25397
|
exports.InlineMacroProcessor = InlineMacroProcessor;
|
|
25251
25398
|
exports.List = List;
|
|
25252
25399
|
exports.ListItem = ListItem;
|
|
25400
|
+
exports.LogMessage = LogMessage;
|
|
25253
25401
|
exports.Logger = Logger;
|
|
25254
25402
|
exports.LoggerManager = LoggerManager;
|
|
25255
25403
|
exports.MemoryHttpCache = MemoryHttpCache;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@asciidoctor/core",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"description": "Asciidoctor.js: AsciiDoc in JavaScript powered by Asciidoctor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "build/node/index.cjs",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
},
|
|
67
67
|
"homepage": "https://github.com/asciidoctor/asciidoctor.js",
|
|
68
68
|
"volta": {
|
|
69
|
-
"node": "24.
|
|
69
|
+
"node": "24.18.0"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@biomejs/biome": "^2.4.13",
|
package/src/browser/reader.js
CHANGED
|
@@ -92,7 +92,7 @@ export function resolveBrowserIncludePath(reader, target, attrlist) {
|
|
|
92
92
|
// ── Rule 2: target is an absolute URL (http:// / https:// / …) ───────────
|
|
93
93
|
} else if (isUriish(pTarget)) {
|
|
94
94
|
const descends = pathResolver.descendsFrom(pTarget, baseDir)
|
|
95
|
-
if (descends === false && !doc.
|
|
95
|
+
if (descends === false && !doc.hasAttribute('allow-uri-read')) {
|
|
96
96
|
return reader.replaceNextLine(_linkReplacement(reader, target, attrlist))
|
|
97
97
|
}
|
|
98
98
|
incPath = relpath = pTarget
|
|
@@ -126,7 +126,7 @@ export function resolveBrowserIncludePath(reader, target, attrlist) {
|
|
|
126
126
|
} else {
|
|
127
127
|
// Nested include: context dir is an absolute URL.
|
|
128
128
|
const ctxDescends = pathResolver.descendsFrom(ctxDir, baseDir)
|
|
129
|
-
if (ctxDescends !== false || doc.
|
|
129
|
+
if (ctxDescends !== false || doc.hasAttribute('allow-uri-read')) {
|
|
130
130
|
incPath = `${ctxDir}/${pTarget}`
|
|
131
131
|
relpath = ctxDescends !== false ? incPath.slice(ctxDescends) : pTarget
|
|
132
132
|
} else {
|
package/src/browser.js
CHANGED
|
@@ -9,7 +9,13 @@ import {
|
|
|
9
9
|
ImageReference,
|
|
10
10
|
RevisionInfo,
|
|
11
11
|
} from './document.js'
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
Logger,
|
|
14
|
+
LoggerManager,
|
|
15
|
+
LogMessage,
|
|
16
|
+
MemoryLogger,
|
|
17
|
+
NullLogger,
|
|
18
|
+
} from './logging.js'
|
|
13
19
|
import { HttpCache, MemoryHttpCache, HttpCacheManager } from './http_cache.js'
|
|
14
20
|
import { SafeMode, ContentModel } from './constants.js'
|
|
15
21
|
import { Timings } from './timings.js'
|
|
@@ -110,6 +116,7 @@ export {
|
|
|
110
116
|
Reader,
|
|
111
117
|
SyntaxHighlighterBase,
|
|
112
118
|
LoggerManager,
|
|
119
|
+
LogMessage,
|
|
113
120
|
MemoryLogger,
|
|
114
121
|
NullLogger,
|
|
115
122
|
HttpCache,
|
package/src/document.js
CHANGED
|
@@ -587,8 +587,16 @@ export class Document extends AbstractBlock {
|
|
|
587
587
|
}
|
|
588
588
|
|
|
589
589
|
// Pre-compute all async text values (titles, list item text, cell text, reftexts)
|
|
590
|
-
// so that synchronous getters work correctly during conversion.
|
|
590
|
+
// so that synchronous getters work correctly during conversion. _resolveAllTexts
|
|
591
|
+
// replays attribute entries in document order (mirroring conversion) so body-level
|
|
592
|
+
// attribute (re)assignments are in scope; snapshot and restore the document
|
|
593
|
+
// attributes so the downstream steps and conversion still start from the restored
|
|
594
|
+
// (header) state, matching Ruby's restore_attributes-before-convert invariant.
|
|
595
|
+
const attributesSnapshot = { ...this.attributes }
|
|
591
596
|
await this._resolveAllTexts(this)
|
|
597
|
+
for (const key of Reflect.ownKeys(this.attributes))
|
|
598
|
+
delete this.attributes[key]
|
|
599
|
+
Object.assign(this.attributes, attributesSnapshot)
|
|
592
600
|
// Reset the footnote counter so that body-content footnotes (processed during conversion)
|
|
593
601
|
// start numbering from 1, reproducing Ruby's "out of sequence" quirk: title footnotes are
|
|
594
602
|
// numbered during parsing via apply_title_subs, then the counter restarts for body content.
|
|
@@ -1662,6 +1670,12 @@ export class Document extends AbstractBlock {
|
|
|
1662
1670
|
* Handles titles (AbstractBlock), list item text, table cell text, and reftexts.
|
|
1663
1671
|
*/
|
|
1664
1672
|
async _resolveAllTexts(block) {
|
|
1673
|
+
// Replay this block's attribute entries (in document order, since the walk is
|
|
1674
|
+
// depth-first pre-order like conversion) so that body-level attribute assignments
|
|
1675
|
+
// and reassignments are in scope when the block's — and its descendants' and later
|
|
1676
|
+
// siblings' — title / list item / table cell / reftext values are substituted.
|
|
1677
|
+
// Mirrors AbstractBlock#convert, which calls playbackAttributes before converting.
|
|
1678
|
+
this.playbackAttributes(block.attributes)
|
|
1665
1679
|
// The header section lives outside document.blocks; pre-compute its title here so
|
|
1666
1680
|
// that doc.doctitle() returns the fully-substituted title (with replacements applied,
|
|
1667
1681
|
// e.g. ' → ’) rather than the header-subs-only fallback.
|