@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/src/extensions.js
CHANGED
|
@@ -75,6 +75,7 @@ import { MacroNameRx, CC_ANY } from './rx.js'
|
|
|
75
75
|
* DSL interface for include processors.
|
|
76
76
|
*
|
|
77
77
|
* @typedef {DocumentProcessorDslInterface & {
|
|
78
|
+
* handles(fn: (target: string) => boolean): void;
|
|
78
79
|
* handles(fn: (doc: Document, target: string) => boolean): void;
|
|
79
80
|
* }} IncludeProcessorDslInterface
|
|
80
81
|
*/
|
|
@@ -125,7 +126,7 @@ import { MacroNameRx, CC_ANY } from './rx.js'
|
|
|
125
126
|
* - Called with a single Function argument → stores it as the process block.
|
|
126
127
|
* - Called with non-Function arguments → invokes the stored process block.
|
|
127
128
|
*
|
|
128
|
-
* The this context inside a stored process function is bound to the processor
|
|
129
|
+
* The `this` context inside a stored process function is bound to the processor
|
|
129
130
|
* instance at definition time.
|
|
130
131
|
*/
|
|
131
132
|
export const ProcessorDsl = {
|
|
@@ -299,6 +300,35 @@ export const SyntaxProcessorDsl = {
|
|
|
299
300
|
export const IncludeProcessorDsl = {
|
|
300
301
|
...DocumentProcessorDsl,
|
|
301
302
|
|
|
303
|
+
/**
|
|
304
|
+
* @overload
|
|
305
|
+
* @param {(target: string) => boolean} fn - Predicate that receives only the include target.
|
|
306
|
+
* @returns {void}
|
|
307
|
+
*/
|
|
308
|
+
/**
|
|
309
|
+
* @overload
|
|
310
|
+
* @param {(doc: Document, target: string) => boolean} fn - Predicate that receives the document and the include target.
|
|
311
|
+
* @returns {void}
|
|
312
|
+
*/
|
|
313
|
+
/**
|
|
314
|
+
* @overload
|
|
315
|
+
* @param {Document} doc - The document being parsed.
|
|
316
|
+
* @param {string} target - The include target.
|
|
317
|
+
* @returns {boolean}
|
|
318
|
+
*/
|
|
319
|
+
/**
|
|
320
|
+
* Register a function that decides whether this include processor handles a given target,
|
|
321
|
+
* or invoke the registered handler.
|
|
322
|
+
*
|
|
323
|
+
* **Setter form** — register a predicate. The callback may accept either just the target
|
|
324
|
+
* string (arity 1) or both the document and the target string (arity 2).
|
|
325
|
+
*
|
|
326
|
+
* **Invoker form** — call the registered predicate with `(doc, target)` and return its
|
|
327
|
+
* result, or return `true` if no predicate has been registered.
|
|
328
|
+
*
|
|
329
|
+
* @param {...*} args
|
|
330
|
+
* @returns {boolean | void}
|
|
331
|
+
*/
|
|
302
332
|
handles(...args) {
|
|
303
333
|
if (args.length === 1 && typeof args[0] === 'function') {
|
|
304
334
|
const fn = args[0]
|
|
@@ -1072,22 +1102,48 @@ export class ProcessorExtension extends Extension {
|
|
|
1072
1102
|
super(kind, instance, instance.config)
|
|
1073
1103
|
this.processMethod =
|
|
1074
1104
|
processMethod || ((...args) => instance.process(...args))
|
|
1105
|
+
/** @internal */
|
|
1106
|
+
this._direct = false
|
|
1075
1107
|
}
|
|
1076
1108
|
}
|
|
1077
1109
|
|
|
1078
1110
|
// ── Group ─────────────────────────────────────────────────────────────────────
|
|
1079
1111
|
|
|
1080
1112
|
/**
|
|
1081
|
-
* A Group
|
|
1113
|
+
* A Group bundles one or more extension registrations that are re-executed on
|
|
1114
|
+
* every document conversion, making the registry safe to reuse.
|
|
1115
|
+
*
|
|
1116
|
+
* Subclass Group, override {@link Group#activate}, and either call
|
|
1117
|
+
* {@link Group.register} to add it globally or pass the subclass to
|
|
1118
|
+
* {@link Extensions.create} / {@link Extensions.register}.
|
|
1082
1119
|
*
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1120
|
+
* @example
|
|
1121
|
+
* class MyGroup extends Group {
|
|
1122
|
+
* activate (registry) {
|
|
1123
|
+
* registry.preprocessor(MyPreprocessor)
|
|
1124
|
+
* }
|
|
1125
|
+
* }
|
|
1126
|
+
* MyGroup.register()
|
|
1085
1127
|
*/
|
|
1086
1128
|
export class Group {
|
|
1129
|
+
/**
|
|
1130
|
+
* Register this Group class globally under the given name.
|
|
1131
|
+
*
|
|
1132
|
+
* Equivalent to calling `Extensions.register(name, this)`.
|
|
1133
|
+
*
|
|
1134
|
+
* @param {string|null} [name] - Optional name for the group.
|
|
1135
|
+
*/
|
|
1087
1136
|
static register(name = null) {
|
|
1088
1137
|
Extensions.register(name, this)
|
|
1089
1138
|
}
|
|
1090
1139
|
|
|
1140
|
+
/**
|
|
1141
|
+
* Called by {@link Registry#activate} on every document conversion.
|
|
1142
|
+
*
|
|
1143
|
+
* Override this method to register extensions with the provided registry.
|
|
1144
|
+
*
|
|
1145
|
+
* @param {Registry} _registry - The registry to register extensions with.
|
|
1146
|
+
*/
|
|
1091
1147
|
activate(_registry) {
|
|
1092
1148
|
throw new Error(
|
|
1093
1149
|
`${this.constructor.name} must implement the activate method`
|
|
@@ -1119,10 +1175,24 @@ const SYNTAX_PROCESSOR_CLASSES = {
|
|
|
1119
1175
|
* Registry holds the extensions which have been registered and activated, has
|
|
1120
1176
|
* methods for registering or defining a processor and looks up extensions
|
|
1121
1177
|
* stored in the registry during parsing.
|
|
1178
|
+
*
|
|
1179
|
+
* A registry can be reused across multiple conversions. Extensions registered
|
|
1180
|
+
* via a group block (passed to {@link Extensions.create} or
|
|
1181
|
+
* {@link Extensions.register}) are re-executed on every activation. Extensions
|
|
1182
|
+
* registered directly on the registry instance (e.g. `registry.preprocessor(fn)`)
|
|
1183
|
+
* are preserved across activations.
|
|
1184
|
+
*
|
|
1185
|
+
* @example
|
|
1186
|
+
* const registry = Extensions.create('my-ext', function () {
|
|
1187
|
+
* this.preprocessor(function () { ... })
|
|
1188
|
+
* })
|
|
1189
|
+
* // registry can be passed to multiple conversions safely
|
|
1122
1190
|
*/
|
|
1123
1191
|
export class Registry {
|
|
1124
1192
|
constructor(groups = {}) {
|
|
1125
1193
|
this.groups = groups
|
|
1194
|
+
/** @internal */
|
|
1195
|
+
this._activating = false
|
|
1126
1196
|
this._reset()
|
|
1127
1197
|
}
|
|
1128
1198
|
|
|
@@ -1139,18 +1209,26 @@ export class Registry {
|
|
|
1139
1209
|
...Object.values(Extensions.groups()),
|
|
1140
1210
|
...Object.values(this.groups),
|
|
1141
1211
|
]
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
if (
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1212
|
+
this._activating = true
|
|
1213
|
+
try {
|
|
1214
|
+
for (const group of extGroups) {
|
|
1215
|
+
if (typeof group === 'function') {
|
|
1216
|
+
// Check if it is a class (constructor) with an activate prototype method.
|
|
1217
|
+
if (
|
|
1218
|
+
group.prototype &&
|
|
1219
|
+
typeof group.prototype.activate === 'function'
|
|
1220
|
+
) {
|
|
1221
|
+
new group().activate(this)
|
|
1222
|
+
} else {
|
|
1223
|
+
// Plain function — call in the context of this registry (like instance_exec).
|
|
1224
|
+
group.length === 0 ? group.call(this) : group(this)
|
|
1225
|
+
}
|
|
1226
|
+
} else if (group && typeof group.activate === 'function') {
|
|
1227
|
+
group.activate(this)
|
|
1150
1228
|
}
|
|
1151
|
-
} else if (group && typeof group.activate === 'function') {
|
|
1152
|
-
group.activate(this)
|
|
1153
1229
|
}
|
|
1230
|
+
} finally {
|
|
1231
|
+
this._activating = false
|
|
1154
1232
|
}
|
|
1155
1233
|
return this
|
|
1156
1234
|
}
|
|
@@ -1726,6 +1804,7 @@ export class Registry {
|
|
|
1726
1804
|
}
|
|
1727
1805
|
|
|
1728
1806
|
const extension = new ProcessorExtension(kind, processorInstance)
|
|
1807
|
+
extension._direct = !this._activating
|
|
1729
1808
|
extension.config.position === '>>'
|
|
1730
1809
|
? store.unshift(extension)
|
|
1731
1810
|
: store.push(extension)
|
|
@@ -1797,27 +1876,44 @@ export class Registry {
|
|
|
1797
1876
|
}
|
|
1798
1877
|
|
|
1799
1878
|
store[name] = new ProcessorExtension(kind, processorInstance)
|
|
1879
|
+
store[name]._direct = !this._activating
|
|
1800
1880
|
return store[name]
|
|
1801
1881
|
}
|
|
1802
1882
|
|
|
1803
1883
|
/** @internal */
|
|
1804
1884
|
_reset() {
|
|
1885
|
+
// Keep extensions registered directly (outside a group); only clear group-registered ones.
|
|
1886
|
+
// Extensions tagged with _direct=true survive across activations.
|
|
1887
|
+
const keepArr = (arr) => {
|
|
1888
|
+
const kept = arr?.filter((e) => e._direct) ?? []
|
|
1889
|
+
return kept.length ? kept : null
|
|
1890
|
+
}
|
|
1891
|
+
const keepMap = (map) => {
|
|
1892
|
+
if (!map) return null
|
|
1893
|
+
const kept = Object.create(null)
|
|
1894
|
+
for (const [k, v] of Object.entries(map)) if (v._direct) kept[k] = v
|
|
1895
|
+
return Object.keys(kept).length ? kept : null
|
|
1896
|
+
}
|
|
1805
1897
|
/** @internal */
|
|
1806
|
-
this._preprocessor_extensions =
|
|
1898
|
+
this._preprocessor_extensions = keepArr(this._preprocessor_extensions)
|
|
1807
1899
|
/** @internal */
|
|
1808
|
-
this._tree_processor_extensions =
|
|
1900
|
+
this._tree_processor_extensions = keepArr(this._tree_processor_extensions)
|
|
1809
1901
|
/** @internal */
|
|
1810
|
-
this._postprocessor_extensions =
|
|
1902
|
+
this._postprocessor_extensions = keepArr(this._postprocessor_extensions)
|
|
1811
1903
|
/** @internal */
|
|
1812
|
-
this._include_processor_extensions =
|
|
1904
|
+
this._include_processor_extensions = keepArr(
|
|
1905
|
+
this._include_processor_extensions
|
|
1906
|
+
)
|
|
1813
1907
|
/** @internal */
|
|
1814
|
-
this._docinfo_processor_extensions =
|
|
1908
|
+
this._docinfo_processor_extensions = keepArr(
|
|
1909
|
+
this._docinfo_processor_extensions
|
|
1910
|
+
)
|
|
1815
1911
|
/** @internal */
|
|
1816
|
-
this._block_extensions =
|
|
1912
|
+
this._block_extensions = keepMap(this._block_extensions)
|
|
1817
1913
|
/** @internal */
|
|
1818
|
-
this._block_macro_extensions =
|
|
1914
|
+
this._block_macro_extensions = keepMap(this._block_macro_extensions)
|
|
1819
1915
|
/** @internal */
|
|
1820
|
-
this._inline_macro_extensions =
|
|
1916
|
+
this._inline_macro_extensions = keepMap(this._inline_macro_extensions)
|
|
1821
1917
|
this.document = null
|
|
1822
1918
|
}
|
|
1823
1919
|
|
|
@@ -1900,6 +1996,13 @@ export const Extensions = {
|
|
|
1900
1996
|
/**
|
|
1901
1997
|
* Create a new Registry, optionally pre-populated with a named block.
|
|
1902
1998
|
*
|
|
1999
|
+
* When a `block` is provided it is stored as a group and re-executed on every
|
|
2000
|
+
* activation, making the registry safe to reuse across multiple conversions.
|
|
2001
|
+
* Without a `block`, any extensions registered directly on the returned registry
|
|
2002
|
+
* (e.g. `registry.preprocessor(fn)`) are stored in transient state that is
|
|
2003
|
+
* cleared on every activation — those registrations will be lost from the second
|
|
2004
|
+
* conversion onwards. Prefer the block form when the registry may be reused.
|
|
2005
|
+
*
|
|
1903
2006
|
* @param {string|null} [name=null] - Optional name for the group; auto-generated if omitted.
|
|
1904
2007
|
* @param {Function|null} [block=null] - Optional function to register as the group.
|
|
1905
2008
|
* @returns {Registry}
|
package/src/index.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'
|
|
@@ -122,6 +128,7 @@ export {
|
|
|
122
128
|
Reader,
|
|
123
129
|
SyntaxHighlighterBase,
|
|
124
130
|
LoggerManager,
|
|
131
|
+
LogMessage,
|
|
125
132
|
MemoryLogger,
|
|
126
133
|
NullLogger,
|
|
127
134
|
HttpCache,
|
package/src/logging.js
CHANGED
|
@@ -277,14 +277,23 @@ Logger.BasicFormatter = class {
|
|
|
277
277
|
|
|
278
278
|
Logger.AutoFormattingMessage = {
|
|
279
279
|
/**
|
|
280
|
-
* Attach auto-formatting to any plain object carrying
|
|
281
|
-
*
|
|
280
|
+
* Attach auto-formatting to any plain object carrying
|
|
281
|
+
* { text, source_location, include_location }.
|
|
282
|
+
*
|
|
283
|
+
* The location(s) are rendered only by inspect()/toString() (used when a
|
|
284
|
+
* stderr Logger formats the line); the structured `source_location` /
|
|
285
|
+
* `include_location` remain on the object so a MemoryLogger can record them
|
|
286
|
+
* on the resulting LogMessage without duplicating them inside `text`.
|
|
287
|
+
* @param {{text: string, source_location?: any, include_location?: any}} obj
|
|
282
288
|
* @returns {typeof obj} The same object with inspect() and toString() added.
|
|
283
289
|
*/
|
|
284
290
|
attach(obj) {
|
|
285
291
|
obj.inspect = function () {
|
|
286
292
|
const sloc = this.source_location
|
|
287
|
-
|
|
293
|
+
const iloc = this.include_location
|
|
294
|
+
let text = sloc ? `${sloc}: ${this.text}` : this.text
|
|
295
|
+
if (iloc) text += ` (${iloc})`
|
|
296
|
+
return text
|
|
288
297
|
}
|
|
289
298
|
obj.toString = obj.inspect
|
|
290
299
|
return obj
|
|
@@ -294,28 +303,46 @@ Logger.AutoFormattingMessage = {
|
|
|
294
303
|
// ── LogMessage ────────────────────────────────────────────────────────────────
|
|
295
304
|
|
|
296
305
|
/** Wrapper stored by MemoryLogger; provides getSeverity/getText/getSourceLocation. */
|
|
297
|
-
class LogMessage {
|
|
306
|
+
export class LogMessage {
|
|
307
|
+
/**
|
|
308
|
+
* @param {string} severity - Severity label, e.g. 'ERROR'.
|
|
309
|
+
* @param {string|{text: string, source_location?: import('./reader.js').Cursor}|null} message
|
|
310
|
+
*/
|
|
298
311
|
constructor(severity, message) {
|
|
299
312
|
this.message = message
|
|
313
|
+
/** @type {string} */
|
|
300
314
|
this.severity = severity // string label, e.g. 'ERROR'
|
|
301
315
|
// AutoFormattingMessage objects carry { text, source_location }
|
|
302
316
|
if (message !== null && typeof message === 'object' && 'text' in message) {
|
|
303
|
-
|
|
304
|
-
this.
|
|
317
|
+
/** @type {string} */
|
|
318
|
+
this.text = message.text
|
|
319
|
+
/** @type {import('./reader.js').Cursor|null} */
|
|
320
|
+
this.sourceLocation = message.source_location ?? null
|
|
305
321
|
} else {
|
|
306
|
-
this.
|
|
307
|
-
this.
|
|
322
|
+
this.text = message != null ? String(message) : ''
|
|
323
|
+
this.sourceLocation = null
|
|
308
324
|
}
|
|
309
325
|
}
|
|
310
326
|
|
|
327
|
+
/**
|
|
328
|
+
* @returns {string} The severity label, e.g. 'ERROR'.
|
|
329
|
+
*/
|
|
311
330
|
getSeverity() {
|
|
312
331
|
return this.severity
|
|
313
332
|
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* @returns {string} The message text.
|
|
336
|
+
*/
|
|
314
337
|
getText() {
|
|
315
|
-
return this.
|
|
338
|
+
return this.text
|
|
316
339
|
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* @returns {import('./reader.js').Cursor|undefined} The source location, if any.
|
|
343
|
+
*/
|
|
317
344
|
getSourceLocation() {
|
|
318
|
-
return this.
|
|
345
|
+
return this.sourceLocation ?? undefined
|
|
319
346
|
}
|
|
320
347
|
}
|
|
321
348
|
|
|
@@ -328,6 +355,7 @@ export class MemoryLogger {
|
|
|
328
355
|
// matching Ruby's MemoryLogger (level: UNKNOWN). The add() method stores all
|
|
329
356
|
// messages unconditionally — level is only used by the isDebug() guard.
|
|
330
357
|
this.level = Severity.UNKNOWN
|
|
358
|
+
/** @type {LogMessage[]} */
|
|
331
359
|
this.messages = []
|
|
332
360
|
}
|
|
333
361
|
|
|
@@ -335,6 +363,9 @@ export class MemoryLogger {
|
|
|
335
363
|
return new MemoryLogger()
|
|
336
364
|
}
|
|
337
365
|
|
|
366
|
+
/**
|
|
367
|
+
* @returns {LogMessage[]} The log messages recorded so far, in order.
|
|
368
|
+
*/
|
|
338
369
|
getMessages() {
|
|
339
370
|
return this.messages
|
|
340
371
|
}
|
package/src/parser.js
CHANGED
|
@@ -598,7 +598,12 @@ export class Parser {
|
|
|
598
598
|
}
|
|
599
599
|
}
|
|
600
600
|
;(intro ?? section).blocks.push(newBlock)
|
|
601
|
-
|
|
601
|
+
// Reset the shared attributes object for the next block. Use Reflect.ownKeys
|
|
602
|
+
// (not Object.keys) so the Symbol-keyed attribute entries (ATTR_ENTRIES_KEY)
|
|
603
|
+
// are cleared too; otherwise the array of AttributeEntry objects leaks and
|
|
604
|
+
// accumulates across blocks, causing reassigned attributes (e.g. a body-level
|
|
605
|
+
// `:name:` redefined later) to all resolve to the final value at playback time.
|
|
606
|
+
for (const key of Reflect.ownKeys(attributes)) delete attributes[key]
|
|
602
607
|
}
|
|
603
608
|
}
|
|
604
609
|
|
|
@@ -1449,7 +1454,13 @@ export class Parser {
|
|
|
1449
1454
|
}
|
|
1450
1455
|
}
|
|
1451
1456
|
|
|
1452
|
-
|
|
1457
|
+
// Reflect.ownKeys (not Object.keys) so a block carrying only Symbol-keyed
|
|
1458
|
+
// attribute entries (ATTR_ENTRIES_KEY) — e.g. an `:attr:` entry immediately
|
|
1459
|
+
// preceding a list or table — still receives them, matching Ruby's
|
|
1460
|
+
// `attributes.empty?` where the `:attribute_entries` key is counted. Without this
|
|
1461
|
+
// the entries are dropped and the attribute is not played back for that block.
|
|
1462
|
+
if (Reflect.ownKeys(attributes).length > 0)
|
|
1463
|
+
block.updateAttributes(attributes)
|
|
1453
1464
|
block.commitSubs()
|
|
1454
1465
|
|
|
1455
1466
|
if (block.hasSub('callouts')) {
|
package/src/reader.js
CHANGED
|
@@ -675,22 +675,34 @@ export class Reader {
|
|
|
675
675
|
}
|
|
676
676
|
|
|
677
677
|
/** @param {string} msg @param {{ sourceLocation?: any, includeLocation?: any }} [opts] */
|
|
678
|
-
_logWarn(msg,
|
|
679
|
-
|
|
680
|
-
if (includeLocation) text += ` (${includeLocation.lineInfo})`
|
|
681
|
-
this.logger.warn(text)
|
|
678
|
+
_logWarn(msg, opts = {}) {
|
|
679
|
+
this.logger.warn(this._messageWithContext(msg, opts))
|
|
682
680
|
}
|
|
683
681
|
_logError(msg, opts = {}) {
|
|
684
|
-
|
|
685
|
-
? `${opts.sourceLocation.lineInfo}: ${msg}`
|
|
686
|
-
: msg
|
|
687
|
-
if (opts.includeLocation) text += ` (${opts.includeLocation.lineInfo})`
|
|
688
|
-
this.logger.error(text)
|
|
682
|
+
this.logger.error(this._messageWithContext(msg, opts))
|
|
689
683
|
}
|
|
690
684
|
/** @param {string} msg @param {{ sourceLocation?: any }} [opts] */
|
|
691
|
-
_logInfo(msg,
|
|
692
|
-
|
|
693
|
-
|
|
685
|
+
_logInfo(msg, opts = {}) {
|
|
686
|
+
this.logger.info(this._messageWithContext(msg, opts))
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Build an auto-formatting message that keeps the cursor as a structured
|
|
691
|
+
* source_location (rather than baking it into the text). When displayed by a
|
|
692
|
+
* stderr Logger the location is rendered as a "<path>: line <N>: " prefix, but
|
|
693
|
+
* a MemoryLogger records it separately on the LogMessage so consumers can call
|
|
694
|
+
* getSourceLocation(). Mirrors Ruby's Logging#message_with_context.
|
|
695
|
+
* @param {string} msg
|
|
696
|
+
* @param {{ sourceLocation?: any, includeLocation?: any }} [opts]
|
|
697
|
+
* @internal
|
|
698
|
+
*/
|
|
699
|
+
_messageWithContext(msg, { sourceLocation, includeLocation } = {}) {
|
|
700
|
+
if (!sourceLocation && !includeLocation) return msg
|
|
701
|
+
return Logger.AutoFormattingMessage.attach({
|
|
702
|
+
text: msg,
|
|
703
|
+
source_location: sourceLocation ?? null,
|
|
704
|
+
include_location: includeLocation ?? null,
|
|
705
|
+
})
|
|
694
706
|
}
|
|
695
707
|
}
|
|
696
708
|
|
|
@@ -1448,7 +1460,7 @@ export class PreprocessorReader extends Reader {
|
|
|
1448
1460
|
}
|
|
1449
1461
|
|
|
1450
1462
|
if (isUriish(target) || typeof this._dir !== 'string') {
|
|
1451
|
-
if (!doc.
|
|
1463
|
+
if (!doc.hasAttribute('allow-uri-read')) {
|
|
1452
1464
|
this._logWarn(
|
|
1453
1465
|
`cannot include contents of URI: ${target} (allow-uri-read attribute not enabled)`,
|
|
1454
1466
|
{ sourceLocation: this.cursor }
|
package/src/substitutors.js
CHANGED
|
@@ -176,7 +176,7 @@ export const Substitutors = {
|
|
|
176
176
|
*
|
|
177
177
|
* @param {string|string[]} text - The text to process; must not be null.
|
|
178
178
|
* @param {string[]} [subs=NORMAL_SUBS] - The substitutions to perform.
|
|
179
|
-
* @returns {string|string[]} Text with substitutions applied.
|
|
179
|
+
* @returns {Promise<string|string[]>} Text with substitutions applied.
|
|
180
180
|
*/
|
|
181
181
|
async applySubs(text, subs = NORMAL_SUBS) {
|
|
182
182
|
const isEmpty = Array.isArray(text) ? text.length === 0 : text.length === 0
|
|
@@ -290,7 +290,7 @@ export const Substitutors = {
|
|
|
290
290
|
* Substitute quoted text (emphasis, strong, monospaced, etc.)
|
|
291
291
|
*
|
|
292
292
|
* @param {string} text
|
|
293
|
-
* @returns {string}
|
|
293
|
+
* @returns {Promise<string>}
|
|
294
294
|
*/
|
|
295
295
|
async subQuotes(text) {
|
|
296
296
|
const compat = this.document.compatMode
|
|
@@ -462,7 +462,7 @@ export const Substitutors = {
|
|
|
462
462
|
* Substitute inline macros (links, images, etc.)
|
|
463
463
|
*
|
|
464
464
|
* @param {string} text
|
|
465
|
-
* @returns {string}
|
|
465
|
+
* @returns {Promise<string>}
|
|
466
466
|
*/
|
|
467
467
|
async subMacros(text) {
|
|
468
468
|
const foundSquareBracket = text.includes('[')
|
|
@@ -1357,7 +1357,7 @@ export const Substitutors = {
|
|
|
1357
1357
|
* Substitute post replacements (hard line breaks).
|
|
1358
1358
|
*
|
|
1359
1359
|
* @param {string} text
|
|
1360
|
-
* @returns {string}
|
|
1360
|
+
* @returns {Promise<string>}
|
|
1361
1361
|
*/
|
|
1362
1362
|
async subPostReplacements(text) {
|
|
1363
1363
|
if (
|
|
@@ -1395,7 +1395,7 @@ export const Substitutors = {
|
|
|
1395
1395
|
*
|
|
1396
1396
|
* @param {string} source
|
|
1397
1397
|
* @param {boolean} processCallouts
|
|
1398
|
-
* @returns {string}
|
|
1398
|
+
* @returns {Promise<string>}
|
|
1399
1399
|
*/
|
|
1400
1400
|
async subSource(source, processCallouts) {
|
|
1401
1401
|
return processCallouts
|
|
@@ -1407,7 +1407,7 @@ export const Substitutors = {
|
|
|
1407
1407
|
* Substitute callout source references.
|
|
1408
1408
|
*
|
|
1409
1409
|
* @param {string} text
|
|
1410
|
-
* @returns {string}
|
|
1410
|
+
* @returns {Promise<string>}
|
|
1411
1411
|
*/
|
|
1412
1412
|
async subCallouts(text) {
|
|
1413
1413
|
const calloutRx = this.hasAttribute('line-comment')
|
|
@@ -1436,7 +1436,7 @@ export const Substitutors = {
|
|
|
1436
1436
|
*
|
|
1437
1437
|
* @param {string} source
|
|
1438
1438
|
* @param {boolean} processCallouts
|
|
1439
|
-
* @returns {string}
|
|
1439
|
+
* @returns {Promise<string>}
|
|
1440
1440
|
*/
|
|
1441
1441
|
async highlightSource(source, processCallouts) {
|
|
1442
1442
|
const syntaxHl = this.document.syntaxHighlighter
|
|
@@ -1782,7 +1782,7 @@ export const Substitutors = {
|
|
|
1782
1782
|
* Restore passthrough text by reinserting into placeholder positions.
|
|
1783
1783
|
*
|
|
1784
1784
|
* @param {string} text
|
|
1785
|
-
* @returns {string}
|
|
1785
|
+
* @returns {Promise<string>}
|
|
1786
1786
|
*/
|
|
1787
1787
|
async restorePassthroughs(text) {
|
|
1788
1788
|
if (!text.includes(PASS_START)) return text
|
|
@@ -1974,7 +1974,7 @@ export const Substitutors = {
|
|
|
1974
1974
|
* @param {string} attrlist
|
|
1975
1975
|
* @param {string[]} [posattrs=[]]
|
|
1976
1976
|
* @param {Object} [opts={}]
|
|
1977
|
-
* @returns {Object}
|
|
1977
|
+
* @returns {Promise<Object>}
|
|
1978
1978
|
*/
|
|
1979
1979
|
async parseAttributes(attrlist, posattrs = [], opts = {}) {
|
|
1980
1980
|
if (!attrlist || attrlist.length === 0) return {}
|
package/types/extensions.d.ts
CHANGED
|
@@ -38,7 +38,25 @@ export namespace SyntaxProcessorDsl {
|
|
|
38
38
|
function resolvesAttributes(...args: any[]): void;
|
|
39
39
|
}
|
|
40
40
|
export namespace IncludeProcessorDsl {
|
|
41
|
-
|
|
41
|
+
/**
|
|
42
|
+
* @overload
|
|
43
|
+
* @param {(target: string) => boolean} fn - Predicate that receives only the include target.
|
|
44
|
+
* @returns {void}
|
|
45
|
+
*/
|
|
46
|
+
function handles(fn: (target: string) => boolean): void;
|
|
47
|
+
/**
|
|
48
|
+
* @overload
|
|
49
|
+
* @param {(doc: Document, target: string) => boolean} fn - Predicate that receives the document and the include target.
|
|
50
|
+
* @returns {void}
|
|
51
|
+
*/
|
|
52
|
+
function handles(fn: (doc: Document, target: string) => boolean): void;
|
|
53
|
+
/**
|
|
54
|
+
* @overload
|
|
55
|
+
* @param {Document} doc - The document being parsed.
|
|
56
|
+
* @param {string} target - The include target.
|
|
57
|
+
* @returns {boolean}
|
|
58
|
+
*/
|
|
59
|
+
function handles(doc: Document, target: string): boolean;
|
|
42
60
|
}
|
|
43
61
|
export namespace DocinfoProcessorDsl {
|
|
44
62
|
function atLocation(value: any): void;
|
|
@@ -486,14 +504,38 @@ export class ProcessorExtension extends Extension {
|
|
|
486
504
|
processMethod: any;
|
|
487
505
|
}
|
|
488
506
|
/**
|
|
489
|
-
* A Group
|
|
507
|
+
* A Group bundles one or more extension registrations that are re-executed on
|
|
508
|
+
* every document conversion, making the registry safe to reuse.
|
|
490
509
|
*
|
|
491
|
-
* Subclass Group
|
|
492
|
-
*
|
|
510
|
+
* Subclass Group, override {@link Group#activate}, and either call
|
|
511
|
+
* {@link Group.register} to add it globally or pass the subclass to
|
|
512
|
+
* {@link Extensions.create} / {@link Extensions.register}.
|
|
513
|
+
*
|
|
514
|
+
* @example
|
|
515
|
+
* class MyGroup extends Group {
|
|
516
|
+
* activate (registry) {
|
|
517
|
+
* registry.preprocessor(MyPreprocessor)
|
|
518
|
+
* }
|
|
519
|
+
* }
|
|
520
|
+
* MyGroup.register()
|
|
493
521
|
*/
|
|
494
522
|
export class Group {
|
|
495
|
-
|
|
496
|
-
|
|
523
|
+
/**
|
|
524
|
+
* Register this Group class globally under the given name.
|
|
525
|
+
*
|
|
526
|
+
* Equivalent to calling `Extensions.register(name, this)`.
|
|
527
|
+
*
|
|
528
|
+
* @param {string|null} [name] - Optional name for the group.
|
|
529
|
+
*/
|
|
530
|
+
static register(name?: string | null): void;
|
|
531
|
+
/**
|
|
532
|
+
* Called by {@link Registry#activate} on every document conversion.
|
|
533
|
+
*
|
|
534
|
+
* Override this method to register extensions with the provided registry.
|
|
535
|
+
*
|
|
536
|
+
* @param {Registry} _registry - The registry to register extensions with.
|
|
537
|
+
*/
|
|
538
|
+
activate(_registry: Registry): void;
|
|
497
539
|
}
|
|
498
540
|
/**
|
|
499
541
|
* The primary entry point into the extension system.
|
|
@@ -501,6 +543,18 @@ export class Group {
|
|
|
501
543
|
* Registry holds the extensions which have been registered and activated, has
|
|
502
544
|
* methods for registering or defining a processor and looks up extensions
|
|
503
545
|
* stored in the registry during parsing.
|
|
546
|
+
*
|
|
547
|
+
* A registry can be reused across multiple conversions. Extensions registered
|
|
548
|
+
* via a group block (passed to {@link Extensions.create} or
|
|
549
|
+
* {@link Extensions.register}) are re-executed on every activation. Extensions
|
|
550
|
+
* registered directly on the registry instance (e.g. `registry.preprocessor(fn)`)
|
|
551
|
+
* are preserved across activations.
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* const registry = Extensions.create('my-ext', function () {
|
|
555
|
+
* this.preprocessor(function () { ... })
|
|
556
|
+
* })
|
|
557
|
+
* // registry can be passed to multiple conversions safely
|
|
504
558
|
*/
|
|
505
559
|
export class Registry {
|
|
506
560
|
constructor(groups?: {});
|
|
@@ -826,6 +880,13 @@ export namespace Extensions {
|
|
|
826
880
|
/**
|
|
827
881
|
* Create a new Registry, optionally pre-populated with a named block.
|
|
828
882
|
*
|
|
883
|
+
* When a `block` is provided it is stored as a group and re-executed on every
|
|
884
|
+
* activation, making the registry safe to reuse across multiple conversions.
|
|
885
|
+
* Without a `block`, any extensions registered directly on the returned registry
|
|
886
|
+
* (e.g. `registry.preprocessor(fn)`) are stored in transient state that is
|
|
887
|
+
* cleared on every activation — those registrations will be lost from the second
|
|
888
|
+
* conversion onwards. Prefer the block form when the registry may be reused.
|
|
889
|
+
*
|
|
829
890
|
* @param {string|null} [name=null] - Optional name for the group; auto-generated if omitted.
|
|
830
891
|
* @param {Function|null} [block=null] - Optional function to register as the group.
|
|
831
892
|
* @returns {Registry}
|
|
@@ -1032,6 +1093,7 @@ export type SyntaxProcessorDslInterface = ProcessorDslInterface & {
|
|
|
1032
1093
|
* DSL interface for include processors.
|
|
1033
1094
|
*/
|
|
1034
1095
|
export type IncludeProcessorDslInterface = DocumentProcessorDslInterface & {
|
|
1096
|
+
handles(fn: (target: string) => boolean): void;
|
|
1035
1097
|
handles(fn: (doc: Document, target: string) => boolean): void;
|
|
1036
1098
|
};
|
|
1037
1099
|
/**
|
package/types/index.d.cts
CHANGED
|
@@ -54,6 +54,7 @@ import { Section } from './section.js';
|
|
|
54
54
|
import { Reader } from './reader.js';
|
|
55
55
|
import { SyntaxHighlighterBase } from './syntax_highlighter.js';
|
|
56
56
|
import { LoggerManager } from './logging.js';
|
|
57
|
+
import { LogMessage } from './logging.js';
|
|
57
58
|
import { MemoryLogger } from './logging.js';
|
|
58
59
|
import { NullLogger } from './logging.js';
|
|
59
60
|
import { HttpCache } from './http_cache.js';
|
|
@@ -83,4 +84,4 @@ import { deriveBackendTraits } from './converter.js';
|
|
|
83
84
|
import { DefaultFactory as DefaultSyntaxHighlighterFactory } from './syntax_highlighter.js';
|
|
84
85
|
import Html5Converter from './converter/html5.js';
|
|
85
86
|
import { SyntaxHighlighter } from './syntax_highlighter.js';
|
|
86
|
-
export { convert, convertFile, Document, DocumentTitle, Author, Footnote, ImageReference, RevisionInfo, Logger, AbstractNode, AbstractBlock, Inline, Block, List, ListItem, Section, Reader, SyntaxHighlighterBase, LoggerManager, MemoryLogger, NullLogger, HttpCache, MemoryHttpCache, HttpCacheManager, SafeMode, ContentModel, Timings, Registry, Processor, ProcessorExtension, Preprocessor, TreeProcessor, Postprocessor, IncludeProcessor, DocinfoProcessor, BlockProcessor, InlineMacroProcessor, BlockMacroProcessor, Extensions, Cursor, Converter as ConverterFactory, ConverterBase, CustomFactory as ConverterCustomFactory, DefaultConverterFactory, deriveBackendTraits, DefaultSyntaxHighlighterFactory, Html5Converter, SyntaxHighlighter };
|
|
87
|
+
export { convert, convertFile, Document, DocumentTitle, Author, Footnote, ImageReference, RevisionInfo, Logger, AbstractNode, AbstractBlock, Inline, Block, List, ListItem, Section, Reader, SyntaxHighlighterBase, LoggerManager, LogMessage, MemoryLogger, NullLogger, HttpCache, MemoryHttpCache, HttpCacheManager, SafeMode, ContentModel, Timings, Registry, Processor, ProcessorExtension, Preprocessor, TreeProcessor, Postprocessor, IncludeProcessor, DocinfoProcessor, BlockProcessor, InlineMacroProcessor, BlockMacroProcessor, Extensions, Cursor, Converter as ConverterFactory, ConverterBase, CustomFactory as ConverterCustomFactory, DefaultConverterFactory, deriveBackendTraits, DefaultSyntaxHighlighterFactory, Html5Converter, SyntaxHighlighter };
|
package/types/index.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ import { Section } from './section.js';
|
|
|
53
53
|
import { Reader } from './reader.js';
|
|
54
54
|
import { SyntaxHighlighterBase } from './syntax_highlighter.js';
|
|
55
55
|
import { LoggerManager } from './logging.js';
|
|
56
|
+
import { LogMessage } from './logging.js';
|
|
56
57
|
import { MemoryLogger } from './logging.js';
|
|
57
58
|
import { NullLogger } from './logging.js';
|
|
58
59
|
import { HttpCache } from './http_cache.js';
|
|
@@ -82,4 +83,4 @@ import { deriveBackendTraits } from './converter.js';
|
|
|
82
83
|
import { DefaultFactory as DefaultSyntaxHighlighterFactory } from './syntax_highlighter.js';
|
|
83
84
|
import Html5Converter from './converter/html5.js';
|
|
84
85
|
import { SyntaxHighlighter } from './syntax_highlighter.js';
|
|
85
|
-
export { convert, convertFile, Document, DocumentTitle, Author, Footnote, ImageReference, RevisionInfo, Logger, AbstractNode, AbstractBlock, Inline, Block, List, ListItem, Section, Reader, SyntaxHighlighterBase, LoggerManager, MemoryLogger, NullLogger, HttpCache, MemoryHttpCache, HttpCacheManager, SafeMode, ContentModel, Timings, Registry, Processor, ProcessorExtension, Preprocessor, TreeProcessor, Postprocessor, IncludeProcessor, DocinfoProcessor, BlockProcessor, InlineMacroProcessor, BlockMacroProcessor, Extensions, Cursor, Converter as ConverterFactory, ConverterBase, CustomFactory as ConverterCustomFactory, DefaultConverterFactory, deriveBackendTraits, DefaultSyntaxHighlighterFactory, Html5Converter, SyntaxHighlighter };
|
|
86
|
+
export { convert, convertFile, Document, DocumentTitle, Author, Footnote, ImageReference, RevisionInfo, Logger, AbstractNode, AbstractBlock, Inline, Block, List, ListItem, Section, Reader, SyntaxHighlighterBase, LoggerManager, LogMessage, MemoryLogger, NullLogger, HttpCache, MemoryHttpCache, HttpCacheManager, SafeMode, ContentModel, Timings, Registry, Processor, ProcessorExtension, Preprocessor, TreeProcessor, Postprocessor, IncludeProcessor, DocinfoProcessor, BlockProcessor, InlineMacroProcessor, BlockMacroProcessor, Extensions, Cursor, Converter as ConverterFactory, ConverterBase, CustomFactory as ConverterCustomFactory, DefaultConverterFactory, deriveBackendTraits, DefaultSyntaxHighlighterFactory, Html5Converter, SyntaxHighlighter };
|