@asciidoctor/core 4.0.0-alpha.3 → 4.0.0-alpha.5
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 +240 -98
- package/build/node/index.cjs +242 -97
- package/package.json +2 -2
- package/src/abstract_node.js +8 -13
- package/src/browser.js +21 -0
- package/src/convert.js +10 -3
- package/src/converter/html5.js +8 -27
- package/src/document.js +4 -5
- package/src/http_cache.js +139 -0
- package/src/index.js +4 -0
- package/src/path_resolver.js +20 -15
- package/src/reader.js +2 -1
- package/src/stylesheets.js +15 -0
- package/types/abstract_node.d.ts +1 -2
- package/types/http_cache.d.ts +59 -0
- package/types/index.d.cts +12 -9
- package/types/index.d.ts +12 -9
- package/types/path_resolver.d.ts +0 -5
- package/types/stylesheets.d.ts +1 -0
- package/types/table.d.ts +1 -1
package/src/abstract_node.js
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
extname,
|
|
32
32
|
prepareSourceString,
|
|
33
33
|
} from './helpers.js'
|
|
34
|
+
import { fetchUri } from './http_cache.js'
|
|
34
35
|
|
|
35
36
|
// ── Node.js fs (lazy, optional) ───────────────────────────────────────────────
|
|
36
37
|
// Loaded on first use in Node.js; silently absent in browser/WebWorker environments.
|
|
@@ -485,10 +486,7 @@ export class AbstractNode {
|
|
|
485
486
|
(targetImage = this.normalizeWebPath(targetImage, imagesBase, false)))
|
|
486
487
|
) {
|
|
487
488
|
return doc.hasAttribute('allow-uri-read')
|
|
488
|
-
? this.generateDataUriFromUri(
|
|
489
|
-
targetImage,
|
|
490
|
-
doc.hasAttribute('cache-uri')
|
|
491
|
-
)
|
|
489
|
+
? this.generateDataUriFromUri(targetImage)
|
|
492
490
|
: targetImage
|
|
493
491
|
}
|
|
494
492
|
return this.generateDataUri(targetImage, assetDirKey)
|
|
@@ -541,10 +539,7 @@ export class AbstractNode {
|
|
|
541
539
|
)
|
|
542
540
|
: this.normalizeSystemPath(targetImage)
|
|
543
541
|
if (isUriish(imagePath)) {
|
|
544
|
-
return await this.generateDataUriFromUri(
|
|
545
|
-
imagePath,
|
|
546
|
-
this.document.hasAttribute('cache-uri')
|
|
547
|
-
)
|
|
542
|
+
return await this.generateDataUriFromUri(imagePath)
|
|
548
543
|
}
|
|
549
544
|
if (await isReadable(imagePath)) {
|
|
550
545
|
const data = await _fsp.readFile(imagePath)
|
|
@@ -564,12 +559,12 @@ export class AbstractNode {
|
|
|
564
559
|
* imageUri, the caller must await the returned Promise.
|
|
565
560
|
*
|
|
566
561
|
* @param {string} imageUri - The URI from which to read the image data (http/https/ftp).
|
|
567
|
-
* @param {boolean} [cacheUri=false] - A Boolean to control caching (not yet supported in JS).
|
|
568
562
|
* @returns {Promise<string>} a Promise resolving to a String data URI.
|
|
569
563
|
*/
|
|
570
|
-
async generateDataUriFromUri(imageUri
|
|
564
|
+
async generateDataUriFromUri(imageUri) {
|
|
571
565
|
try {
|
|
572
|
-
const
|
|
566
|
+
const doc = this.document
|
|
567
|
+
const response = await fetchUri(imageUri, doc)
|
|
573
568
|
if (response.ok) {
|
|
574
569
|
const mimetype = (
|
|
575
570
|
response.headers.get('content-type') || 'application/octet-stream'
|
|
@@ -740,7 +735,7 @@ export class AbstractNode {
|
|
|
740
735
|
) {
|
|
741
736
|
if (doc.hasAttribute('allow-uri-read')) {
|
|
742
737
|
try {
|
|
743
|
-
const response = await
|
|
738
|
+
const response = await fetchUri(resolvedTarget, doc)
|
|
744
739
|
const text = await response.text()
|
|
745
740
|
contents = opts.normalize ? prepareSourceString(text).join(LF) : text
|
|
746
741
|
} catch {
|
|
@@ -765,7 +760,7 @@ export class AbstractNode {
|
|
|
765
760
|
})
|
|
766
761
|
}
|
|
767
762
|
|
|
768
|
-
if (contents && opts.warnIfEmpty && contents.length === 0) {
|
|
763
|
+
if (contents != null && opts.warnIfEmpty && contents.length === 0) {
|
|
769
764
|
this.logger.warn(`contents of ${label} is empty: ${resolvedTarget}`)
|
|
770
765
|
}
|
|
771
766
|
return contents
|
package/src/browser.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
RevisionInfo,
|
|
11
11
|
} from './document.js'
|
|
12
12
|
import { Logger, LoggerManager, MemoryLogger, NullLogger } from './logging.js'
|
|
13
|
+
import { HttpCache, MemoryHttpCache, HttpCacheManager } from './http_cache.js'
|
|
13
14
|
import { SafeMode, ContentModel } from './constants.js'
|
|
14
15
|
import { Timings } from './timings.js'
|
|
15
16
|
import { AbstractNode } from './abstract_node.js'
|
|
@@ -28,9 +29,23 @@ import {
|
|
|
28
29
|
BlockMacroProcessor,
|
|
29
30
|
Extensions,
|
|
30
31
|
} from './extensions.js'
|
|
32
|
+
// Re-export DSL interface types for TypeScript consumers.
|
|
33
|
+
/**
|
|
34
|
+
* @typedef {import('./extensions.js').ProcessorDslInterface} ProcessorDslInterface
|
|
35
|
+
* @typedef {import('./extensions.js').DocumentProcessorDslInterface} DocumentProcessorDslInterface
|
|
36
|
+
* @typedef {import('./extensions.js').SyntaxProcessorDslInterface} SyntaxProcessorDslInterface
|
|
37
|
+
* @typedef {import('./extensions.js').IncludeProcessorDslInterface} IncludeProcessorDslInterface
|
|
38
|
+
* @typedef {import('./extensions.js').DocinfoProcessorDslInterface} DocinfoProcessorDslInterface
|
|
39
|
+
* @typedef {import('./extensions.js').BlockProcessorDslInterface} BlockProcessorDslInterface
|
|
40
|
+
* @typedef {import('./extensions.js').MacroProcessorDslInterface} MacroProcessorDslInterface
|
|
41
|
+
* @typedef {import('./extensions.js').InlineMacroProcessorDslInterface} InlineMacroProcessorDslInterface
|
|
42
|
+
*/
|
|
31
43
|
import {
|
|
32
44
|
Converter,
|
|
45
|
+
ConverterBase,
|
|
46
|
+
CustomFactory,
|
|
33
47
|
DefaultFactory as DefaultConverterFactory,
|
|
48
|
+
deriveBackendTraits,
|
|
34
49
|
} from './converter.js'
|
|
35
50
|
import { Inline } from './inline.js'
|
|
36
51
|
import { Block } from './block.js'
|
|
@@ -97,6 +112,9 @@ export {
|
|
|
97
112
|
LoggerManager,
|
|
98
113
|
MemoryLogger,
|
|
99
114
|
NullLogger,
|
|
115
|
+
HttpCache,
|
|
116
|
+
MemoryHttpCache,
|
|
117
|
+
HttpCacheManager,
|
|
100
118
|
SafeMode,
|
|
101
119
|
ContentModel,
|
|
102
120
|
Timings,
|
|
@@ -114,7 +132,10 @@ export {
|
|
|
114
132
|
Extensions,
|
|
115
133
|
Cursor,
|
|
116
134
|
Converter as ConverterFactory,
|
|
135
|
+
ConverterBase,
|
|
136
|
+
CustomFactory as ConverterCustomFactory,
|
|
117
137
|
DefaultConverterFactory,
|
|
138
|
+
deriveBackendTraits,
|
|
118
139
|
DefaultSyntaxHighlighterFactory,
|
|
119
140
|
Html5Converter,
|
|
120
141
|
SyntaxHighlighter,
|
package/src/convert.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// - Ruby File.write → async writeFile() via node:fs/promises.
|
|
12
12
|
// - Ruby Helpers.mkdir_p → mkdirP() from helpers.js.
|
|
13
13
|
// - Ruby Helpers.uriish? → isUriish() from helpers.js.
|
|
14
|
-
// - Ruby Stylesheets.instance.write_primary_stylesheet →
|
|
14
|
+
// - Ruby Stylesheets.instance.write_primary_stylesheet → Stylesheets.instance.writePrimaryStylesheet() in stylesheets.js; returns false in browser environments.
|
|
15
15
|
// - Ruby doc.syntax_highlighter → doc.syntaxHighlighter.
|
|
16
16
|
// - Ruby syntax_hl.write_stylesheet? doc → syntaxHl.writeStylesheet(doc).
|
|
17
17
|
// - Ruby syntax_hl.write_stylesheet doc, dir → syntaxHl.writeStylesheetToDisk(doc, dir).
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
import { load } from './load.js'
|
|
25
25
|
import { isUriish, mkdirP } from './helpers.js'
|
|
26
26
|
import { SafeMode, DEFAULT_STYLESHEET_KEYS } from './constants.js'
|
|
27
|
+
import { Stylesheets } from './stylesheets.js'
|
|
27
28
|
|
|
28
29
|
// ── convert ───────────────────────────────────────────────────────────────────
|
|
29
30
|
|
|
@@ -214,7 +215,7 @@ export async function convert(input, options = {}) {
|
|
|
214
215
|
let copyAsciidoctorStylesheet = false
|
|
215
216
|
let copyUserStylesheet = false
|
|
216
217
|
const stylesheet = doc.getAttribute('stylesheet')
|
|
217
|
-
if (stylesheet) {
|
|
218
|
+
if (stylesheet != null) {
|
|
218
219
|
if (DEFAULT_STYLESHEET_KEYS.has(stylesheet)) {
|
|
219
220
|
copyAsciidoctorStylesheet = true
|
|
220
221
|
} else if (!isUriish(stylesheet)) {
|
|
@@ -246,7 +247,13 @@ export async function convert(input, options = {}) {
|
|
|
246
247
|
}
|
|
247
248
|
|
|
248
249
|
if (copyAsciidoctorStylesheet) {
|
|
249
|
-
|
|
250
|
+
if (
|
|
251
|
+
!(await Stylesheets.instance.writePrimaryStylesheet(stylesoutdir))
|
|
252
|
+
) {
|
|
253
|
+
doc.logger.info(
|
|
254
|
+
'skipping default stylesheet copy: filesystem writes are not supported in this environment'
|
|
255
|
+
)
|
|
256
|
+
}
|
|
250
257
|
} else if (copyUserStylesheet) {
|
|
251
258
|
let stylesheetSrc = doc.getAttribute('copycss')
|
|
252
259
|
if (stylesheetSrc === '' || stylesheetSrc === true) {
|
package/src/converter/html5.js
CHANGED
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
INLINE_MATH_DELIMITERS,
|
|
30
30
|
} from '../constants.js'
|
|
31
31
|
import { XmlSanitizeRx } from '../rx.js'
|
|
32
|
-
import { extname
|
|
32
|
+
import { extname } from '../helpers.js'
|
|
33
33
|
import { Stylesheets } from '../stylesheets.js'
|
|
34
34
|
|
|
35
35
|
// ── Local regex constants ─────────────────────────────────────────────────────
|
|
@@ -1767,32 +1767,13 @@ Your browser does not support the video tag.
|
|
|
1767
1767
|
|
|
1768
1768
|
// NOTE expose readSvgContents for Bespoke converter
|
|
1769
1769
|
async readSvgContents(node, target) {
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
warnOnFailure: true,
|
|
1778
|
-
label: 'SVG',
|
|
1779
|
-
})
|
|
1780
|
-
resolvedPath = target
|
|
1781
|
-
} else {
|
|
1782
|
-
resolvedPath = node.normalizeSystemPath(target, imagesdir, null, {
|
|
1783
|
-
targetName: 'image',
|
|
1784
|
-
})
|
|
1785
|
-
svg = await node.readAsset(resolvedPath, {
|
|
1786
|
-
normalize: true,
|
|
1787
|
-
warnOnFailure: true,
|
|
1788
|
-
label: 'SVG',
|
|
1789
|
-
})
|
|
1790
|
-
}
|
|
1791
|
-
if (svg == null) return null // file not found/readable; warning already emitted
|
|
1792
|
-
if (!svg) {
|
|
1793
|
-
node.logger.warn(`contents of SVG is empty: ${resolvedPath}`)
|
|
1794
|
-
return null
|
|
1795
|
-
}
|
|
1770
|
+
let svg = await node.readContents(target, {
|
|
1771
|
+
start: node.document.getAttribute('imagesdir'),
|
|
1772
|
+
normalize: true,
|
|
1773
|
+
label: 'SVG',
|
|
1774
|
+
warnIfEmpty: true,
|
|
1775
|
+
})
|
|
1776
|
+
if (!svg) return null
|
|
1796
1777
|
if (!svg.startsWith('<svg')) svg = svg.replace(SvgPreambleRx, '')
|
|
1797
1778
|
// Fix incomplete SVG start tag (missing closing >) by inserting > before the first child element.
|
|
1798
1779
|
// This handles cases like: <svg width="500"\n<circle .../> where the > is missing.
|
package/src/document.js
CHANGED
|
@@ -2091,11 +2091,10 @@ export class Document extends AbstractBlock {
|
|
|
2091
2091
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
2092
2092
|
|
|
2093
2093
|
function _expandPath(p) {
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
}
|
|
2094
|
+
const resolver = new PathResolver()
|
|
2095
|
+
const posixed = p.replace(/\\/g, '/')
|
|
2096
|
+
if (resolver.absolutePath(posixed)) return resolver.expandPath(posixed)
|
|
2097
|
+
return resolver.expandPath(`${resolver.workingDir}/${posixed}`)
|
|
2099
2098
|
}
|
|
2100
2099
|
|
|
2101
2100
|
function _cwd() {
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// HTTP cache system for URI fetching.
|
|
2
|
+
//
|
|
3
|
+
// Provides a pluggable caching layer for all HTTP(S) fetches performed during
|
|
4
|
+
// document conversion (includes, images, readContents). Mirrors the behaviour
|
|
5
|
+
// of Ruby's open-uri/cached mechanism activated by the `cache-uri` attribute.
|
|
6
|
+
//
|
|
7
|
+
// When `cache-uri` is set on the document:
|
|
8
|
+
// - If a cache has been registered via HttpCacheManager.setCache(), it is used.
|
|
9
|
+
// - Otherwise an ephemeral MemoryHttpCache is created for the duration of the
|
|
10
|
+
// conversion (keyed by Document instance via a WeakMap, GC'd with the doc).
|
|
11
|
+
//
|
|
12
|
+
// To implement a custom cache, extend HttpCache and override read(uri).
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Base HTTP cache class.
|
|
16
|
+
*
|
|
17
|
+
* The default implementation delegates directly to fetch() with no caching.
|
|
18
|
+
* Subclasses override read() to add caching behaviour.
|
|
19
|
+
*/
|
|
20
|
+
export class HttpCache {
|
|
21
|
+
/**
|
|
22
|
+
* Fetch content from a URI, optionally from a cache.
|
|
23
|
+
* @param {string} uri
|
|
24
|
+
* @returns {Promise<Response>}
|
|
25
|
+
*/
|
|
26
|
+
async read(uri) {
|
|
27
|
+
return fetch(uri)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* In-memory HTTP cache.
|
|
33
|
+
*
|
|
34
|
+
* Stores successful responses as ArrayBuffers keyed by URI. On a cache hit
|
|
35
|
+
* a synthetic Response is reconstructed from the stored data without touching
|
|
36
|
+
* the network. Non-OK responses (4xx, 5xx) are never cached.
|
|
37
|
+
*
|
|
38
|
+
* Safe as an ephemeral per-conversion cache or as a longer-lived process-level
|
|
39
|
+
* cache when registered via HttpCacheManager.setCache().
|
|
40
|
+
*/
|
|
41
|
+
export class MemoryHttpCache extends HttpCache {
|
|
42
|
+
/** @type {Map<string, {buffer: ArrayBuffer, status: number, statusText: string, headers: Record<string,string>}>} */
|
|
43
|
+
#cache = new Map()
|
|
44
|
+
|
|
45
|
+
async read(uri) {
|
|
46
|
+
const entry = this.#cache.get(uri)
|
|
47
|
+
if (entry) {
|
|
48
|
+
return new Response(entry.buffer.slice(0), {
|
|
49
|
+
status: entry.status,
|
|
50
|
+
statusText: entry.statusText,
|
|
51
|
+
headers: entry.headers,
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
const response = await fetch(uri)
|
|
55
|
+
if (response.ok) {
|
|
56
|
+
const buffer = await response.arrayBuffer()
|
|
57
|
+
const headers = Object.fromEntries(response.headers.entries())
|
|
58
|
+
this.#cache.set(uri, {
|
|
59
|
+
buffer,
|
|
60
|
+
status: response.status,
|
|
61
|
+
statusText: response.statusText,
|
|
62
|
+
headers,
|
|
63
|
+
})
|
|
64
|
+
return new Response(buffer.slice(0), {
|
|
65
|
+
status: response.status,
|
|
66
|
+
statusText: response.statusText,
|
|
67
|
+
headers,
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
return response
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** @type {WeakMap<object, MemoryHttpCache>} */
|
|
75
|
+
const _ephemeralCaches = new WeakMap()
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Singleton manager for the HTTP cache.
|
|
79
|
+
*
|
|
80
|
+
* Register a process-level cache:
|
|
81
|
+
* HttpCacheManager.setCache(new MemoryHttpCache())
|
|
82
|
+
* HttpCacheManager.setCache(new MyFileSystemCache('./cache'))
|
|
83
|
+
* HttpCacheManager.setCache(null) // revert to default ephemeral behaviour
|
|
84
|
+
*
|
|
85
|
+
* When no cache is registered and `cache-uri` is set, an ephemeral
|
|
86
|
+
* MemoryHttpCache is created per Document instance.
|
|
87
|
+
*/
|
|
88
|
+
export const HttpCacheManager = {
|
|
89
|
+
/** @type {HttpCache|null} */
|
|
90
|
+
_cache: null,
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Register a cache to use for all conversions.
|
|
94
|
+
* Pass null to unregister and revert to the ephemeral default.
|
|
95
|
+
* @param {HttpCache|null} cache
|
|
96
|
+
*/
|
|
97
|
+
setCache(cache) {
|
|
98
|
+
this._cache = cache
|
|
99
|
+
},
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Return the registered process-level cache, or null if none is registered.
|
|
103
|
+
* @returns {HttpCache|null}
|
|
104
|
+
*/
|
|
105
|
+
getCache() {
|
|
106
|
+
return this._cache
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Return the cache to use for a specific document conversion.
|
|
111
|
+
*
|
|
112
|
+
* Returns the registered cache if one exists; otherwise creates (or reuses)
|
|
113
|
+
* an ephemeral MemoryHttpCache scoped to the document's lifetime via a WeakMap.
|
|
114
|
+
* @param {object} doc - the current Document instance
|
|
115
|
+
* @returns {HttpCache}
|
|
116
|
+
*/
|
|
117
|
+
getCacheForDocument(doc) {
|
|
118
|
+
if (this._cache) return this._cache
|
|
119
|
+
let cache = _ephemeralCaches.get(doc)
|
|
120
|
+
if (!cache) {
|
|
121
|
+
cache = new MemoryHttpCache()
|
|
122
|
+
_ephemeralCaches.set(doc, cache)
|
|
123
|
+
}
|
|
124
|
+
return cache
|
|
125
|
+
},
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Fetch a URI, routing through the HTTP cache when `cache-uri` is set on the document.
|
|
130
|
+
* @param {string} uri
|
|
131
|
+
* @param {object} doc - the current Document instance
|
|
132
|
+
* @returns {Promise<Response>}
|
|
133
|
+
*/
|
|
134
|
+
export function fetchUri(uri, doc) {
|
|
135
|
+
if (doc.hasAttribute('cache-uri')) {
|
|
136
|
+
return HttpCacheManager.getCacheForDocument(doc).read(uri)
|
|
137
|
+
}
|
|
138
|
+
return fetch(uri)
|
|
139
|
+
}
|
package/src/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
RevisionInfo,
|
|
11
11
|
} from './document.js'
|
|
12
12
|
import { Logger, LoggerManager, MemoryLogger, NullLogger } from './logging.js'
|
|
13
|
+
import { HttpCache, MemoryHttpCache, HttpCacheManager } from './http_cache.js'
|
|
13
14
|
import { SafeMode, ContentModel } from './constants.js'
|
|
14
15
|
import { Timings } from './timings.js'
|
|
15
16
|
import { AbstractNode } from './abstract_node.js'
|
|
@@ -123,6 +124,9 @@ export {
|
|
|
123
124
|
LoggerManager,
|
|
124
125
|
MemoryLogger,
|
|
125
126
|
NullLogger,
|
|
127
|
+
HttpCache,
|
|
128
|
+
MemoryHttpCache,
|
|
129
|
+
HttpCacheManager,
|
|
126
130
|
SafeMode,
|
|
127
131
|
ContentModel,
|
|
128
132
|
Timings,
|
package/src/path_resolver.js
CHANGED
|
@@ -123,14 +123,6 @@ export class PathResolver {
|
|
|
123
123
|
: path
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
/**
|
|
127
|
-
* @param {string} path
|
|
128
|
-
* @returns {string}
|
|
129
|
-
*/
|
|
130
|
-
posixfy(path) {
|
|
131
|
-
return this.posixify(path)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
126
|
/**
|
|
135
127
|
* Expand the path by resolving parent references (..) and removing self references (.).
|
|
136
128
|
* @param {string} path
|
|
@@ -431,14 +423,27 @@ function _platformSeparator() {
|
|
|
431
423
|
* @internal
|
|
432
424
|
*/
|
|
433
425
|
function _expandPath(p) {
|
|
434
|
-
if (typeof process
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
426
|
+
if (typeof process === 'undefined') return p
|
|
427
|
+
const cwd = process.cwd().replace(/\\/g, '/')
|
|
428
|
+
const full = `${cwd}/${p.replace(/\\/g, '/')}`
|
|
429
|
+
let root, rest
|
|
430
|
+
if (full.startsWith('//')) {
|
|
431
|
+
root = '//'
|
|
432
|
+
rest = full.slice(2)
|
|
433
|
+
} else if (full.startsWith('/')) {
|
|
434
|
+
root = '/'
|
|
435
|
+
rest = full.slice(1)
|
|
436
|
+
} else {
|
|
437
|
+
const slash = full.indexOf('/')
|
|
438
|
+
root = full.slice(0, slash + 1)
|
|
439
|
+
rest = full.slice(slash + 1)
|
|
440
|
+
}
|
|
441
|
+
const resolved = []
|
|
442
|
+
for (const seg of rest.split('/')) {
|
|
443
|
+
if (seg === '..') resolved.pop()
|
|
444
|
+
else if (seg && seg !== '.') resolved.push(seg)
|
|
440
445
|
}
|
|
441
|
-
return
|
|
446
|
+
return root + resolved.join('/')
|
|
442
447
|
}
|
|
443
448
|
|
|
444
449
|
/**
|
package/src/reader.js
CHANGED
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
isUriish,
|
|
43
43
|
} from './helpers.js'
|
|
44
44
|
import { LoggerManager, Logger } from './logging.js'
|
|
45
|
+
import { fetchUri } from './http_cache.js'
|
|
45
46
|
import { Compliance } from './compliance.js'
|
|
46
47
|
import { resolveBrowserIncludePath } from './browser/reader.js'
|
|
47
48
|
|
|
@@ -1309,7 +1310,7 @@ export class PreprocessorReader extends Reader {
|
|
|
1309
1310
|
if (targetType === 'uri') {
|
|
1310
1311
|
let uriContent
|
|
1311
1312
|
try {
|
|
1312
|
-
const response = await
|
|
1313
|
+
const response = await fetchUri(incPath, this._document)
|
|
1313
1314
|
if (!response.ok)
|
|
1314
1315
|
throw new Error(`HTTP ${response.status} ${response.statusText}`)
|
|
1315
1316
|
uriContent = await response.text()
|
package/src/stylesheets.js
CHANGED
|
@@ -23,6 +23,21 @@ class StylesheetsClass {
|
|
|
23
23
|
async embedPrimaryStylesheet() {
|
|
24
24
|
return `<style>\n${defaultStylesheetData}\n</style>`
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
async writePrimaryStylesheet(stylesoutdir) {
|
|
28
|
+
try {
|
|
29
|
+
const { writeFile } = await import('node:fs/promises')
|
|
30
|
+
const { join } = await import('node:path')
|
|
31
|
+
await writeFile(
|
|
32
|
+
join(stylesoutdir, StylesheetsClass.DEFAULT_STYLESHEET_NAME),
|
|
33
|
+
defaultStylesheetData,
|
|
34
|
+
'utf8'
|
|
35
|
+
)
|
|
36
|
+
return true
|
|
37
|
+
} catch {
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
}
|
|
26
41
|
}
|
|
27
42
|
|
|
28
43
|
export const Stylesheets = {
|
package/types/abstract_node.d.ts
CHANGED
|
@@ -278,10 +278,9 @@ export abstract class AbstractNode {
|
|
|
278
278
|
* imageUri, the caller must await the returned Promise.
|
|
279
279
|
*
|
|
280
280
|
* @param {string} imageUri - The URI from which to read the image data (http/https/ftp).
|
|
281
|
-
* @param {boolean} [cacheUri=false] - A Boolean to control caching (not yet supported in JS).
|
|
282
281
|
* @returns {Promise<string>} a Promise resolving to a String data URI.
|
|
283
282
|
*/
|
|
284
|
-
generateDataUriFromUri(imageUri: string
|
|
283
|
+
generateDataUriFromUri(imageUri: string): Promise<string>;
|
|
285
284
|
/**
|
|
286
285
|
* Normalize the asset file or directory to a concrete and rinsed path.
|
|
287
286
|
*
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fetch a URI, routing through the HTTP cache when `cache-uri` is set on the document.
|
|
3
|
+
* @param {string} uri
|
|
4
|
+
* @param {object} doc - the current Document instance
|
|
5
|
+
* @returns {Promise<Response>}
|
|
6
|
+
*/
|
|
7
|
+
export function fetchUri(uri: string, doc: object): Promise<Response>;
|
|
8
|
+
/**
|
|
9
|
+
* Base HTTP cache class.
|
|
10
|
+
*
|
|
11
|
+
* The default implementation delegates directly to fetch() with no caching.
|
|
12
|
+
* Subclasses override read() to add caching behaviour.
|
|
13
|
+
*/
|
|
14
|
+
export class HttpCache {
|
|
15
|
+
/**
|
|
16
|
+
* Fetch content from a URI, optionally from a cache.
|
|
17
|
+
* @param {string} uri
|
|
18
|
+
* @returns {Promise<Response>}
|
|
19
|
+
*/
|
|
20
|
+
read(uri: string): Promise<Response>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* In-memory HTTP cache.
|
|
24
|
+
*
|
|
25
|
+
* Stores successful responses as ArrayBuffers keyed by URI. On a cache hit
|
|
26
|
+
* a synthetic Response is reconstructed from the stored data without touching
|
|
27
|
+
* the network. Non-OK responses (4xx, 5xx) are never cached.
|
|
28
|
+
*
|
|
29
|
+
* Safe as an ephemeral per-conversion cache or as a longer-lived process-level
|
|
30
|
+
* cache when registered via HttpCacheManager.setCache().
|
|
31
|
+
*/
|
|
32
|
+
export class MemoryHttpCache extends HttpCache {
|
|
33
|
+
read(uri: any): Promise<any>;
|
|
34
|
+
#private;
|
|
35
|
+
}
|
|
36
|
+
export namespace HttpCacheManager {
|
|
37
|
+
/** @type {HttpCache|null} */
|
|
38
|
+
let _cache: HttpCache | null;
|
|
39
|
+
/**
|
|
40
|
+
* Register a cache to use for all conversions.
|
|
41
|
+
* Pass null to unregister and revert to the ephemeral default.
|
|
42
|
+
* @param {HttpCache|null} cache
|
|
43
|
+
*/
|
|
44
|
+
function setCache(cache: HttpCache | null): void;
|
|
45
|
+
/**
|
|
46
|
+
* Return the registered process-level cache, or null if none is registered.
|
|
47
|
+
* @returns {HttpCache|null}
|
|
48
|
+
*/
|
|
49
|
+
function getCache(): HttpCache | null;
|
|
50
|
+
/**
|
|
51
|
+
* Return the cache to use for a specific document conversion.
|
|
52
|
+
*
|
|
53
|
+
* Returns the registered cache if one exists; otherwise creates (or reuses)
|
|
54
|
+
* an ephemeral MemoryHttpCache scoped to the document's lifetime via a WeakMap.
|
|
55
|
+
* @param {object} doc - the current Document instance
|
|
56
|
+
* @returns {HttpCache}
|
|
57
|
+
*/
|
|
58
|
+
function getCacheForDocument(doc: object): HttpCache;
|
|
59
|
+
}
|
package/types/index.d.cts
CHANGED
|
@@ -27,14 +27,14 @@ export function load(input: string | string[] | Buffer, options?: any): Promise<
|
|
|
27
27
|
* @returns {Promise<Document>} - the parsed Document
|
|
28
28
|
*/
|
|
29
29
|
export function loadFile(filename: string, options?: any): Promise<Document>;
|
|
30
|
-
export type ProcessorDslInterface
|
|
31
|
-
export type DocumentProcessorDslInterface
|
|
32
|
-
export type SyntaxProcessorDslInterface
|
|
33
|
-
export type IncludeProcessorDslInterface
|
|
34
|
-
export type DocinfoProcessorDslInterface
|
|
35
|
-
export type BlockProcessorDslInterface
|
|
36
|
-
export type MacroProcessorDslInterface
|
|
37
|
-
export type InlineMacroProcessorDslInterface
|
|
30
|
+
export type { ProcessorDslInterface } from './extensions.js';
|
|
31
|
+
export type { DocumentProcessorDslInterface } from './extensions.js';
|
|
32
|
+
export type { SyntaxProcessorDslInterface } from './extensions.js';
|
|
33
|
+
export type { IncludeProcessorDslInterface } from './extensions.js';
|
|
34
|
+
export type { DocinfoProcessorDslInterface } from './extensions.js';
|
|
35
|
+
export type { BlockProcessorDslInterface } from './extensions.js';
|
|
36
|
+
export type { MacroProcessorDslInterface } from './extensions.js';
|
|
37
|
+
export type { InlineMacroProcessorDslInterface } from './extensions.js';
|
|
38
38
|
import { Document } from './document.js';
|
|
39
39
|
import { convert } from './convert.js';
|
|
40
40
|
import { convertFile } from './convert.js';
|
|
@@ -56,6 +56,9 @@ import { SyntaxHighlighterBase } from './syntax_highlighter.js';
|
|
|
56
56
|
import { LoggerManager } from './logging.js';
|
|
57
57
|
import { MemoryLogger } from './logging.js';
|
|
58
58
|
import { NullLogger } from './logging.js';
|
|
59
|
+
import { HttpCache } from './http_cache.js';
|
|
60
|
+
import { MemoryHttpCache } from './http_cache.js';
|
|
61
|
+
import { HttpCacheManager } from './http_cache.js';
|
|
59
62
|
import { SafeMode } from './constants.js';
|
|
60
63
|
import { ContentModel } from './constants.js';
|
|
61
64
|
import { Timings } from './timings.js';
|
|
@@ -80,4 +83,4 @@ import { deriveBackendTraits } from './converter.js';
|
|
|
80
83
|
import { DefaultFactory as DefaultSyntaxHighlighterFactory } from './syntax_highlighter.js';
|
|
81
84
|
import Html5Converter from './converter/html5.js';
|
|
82
85
|
import { SyntaxHighlighter } from './syntax_highlighter.js';
|
|
83
|
-
export { convert, convertFile, Document, DocumentTitle, Author, Footnote, ImageReference, RevisionInfo, Logger, AbstractNode, AbstractBlock, Inline, Block, List, ListItem, Section, Reader, SyntaxHighlighterBase, LoggerManager, MemoryLogger, NullLogger, 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, 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
|
@@ -26,14 +26,14 @@ export function load(input: string | string[] | Buffer, options?: any): Promise<
|
|
|
26
26
|
* @returns {Promise<Document>} - the parsed Document
|
|
27
27
|
*/
|
|
28
28
|
export function loadFile(filename: string, options?: any): Promise<Document>;
|
|
29
|
-
export type ProcessorDslInterface
|
|
30
|
-
export type DocumentProcessorDslInterface
|
|
31
|
-
export type SyntaxProcessorDslInterface
|
|
32
|
-
export type IncludeProcessorDslInterface
|
|
33
|
-
export type DocinfoProcessorDslInterface
|
|
34
|
-
export type BlockProcessorDslInterface
|
|
35
|
-
export type MacroProcessorDslInterface
|
|
36
|
-
export type InlineMacroProcessorDslInterface
|
|
29
|
+
export type { ProcessorDslInterface } from './extensions.js';
|
|
30
|
+
export type { DocumentProcessorDslInterface } from './extensions.js';
|
|
31
|
+
export type { SyntaxProcessorDslInterface } from './extensions.js';
|
|
32
|
+
export type { IncludeProcessorDslInterface } from './extensions.js';
|
|
33
|
+
export type { DocinfoProcessorDslInterface } from './extensions.js';
|
|
34
|
+
export type { BlockProcessorDslInterface } from './extensions.js';
|
|
35
|
+
export type { MacroProcessorDslInterface } from './extensions.js';
|
|
36
|
+
export type { InlineMacroProcessorDslInterface } from './extensions.js';
|
|
37
37
|
import { Document } from './document.js';
|
|
38
38
|
import { convert } from './convert.js';
|
|
39
39
|
import { convertFile } from './convert.js';
|
|
@@ -55,6 +55,9 @@ import { SyntaxHighlighterBase } from './syntax_highlighter.js';
|
|
|
55
55
|
import { LoggerManager } from './logging.js';
|
|
56
56
|
import { MemoryLogger } from './logging.js';
|
|
57
57
|
import { NullLogger } from './logging.js';
|
|
58
|
+
import { HttpCache } from './http_cache.js';
|
|
59
|
+
import { MemoryHttpCache } from './http_cache.js';
|
|
60
|
+
import { HttpCacheManager } from './http_cache.js';
|
|
58
61
|
import { SafeMode } from './constants.js';
|
|
59
62
|
import { ContentModel } from './constants.js';
|
|
60
63
|
import { Timings } from './timings.js';
|
|
@@ -79,4 +82,4 @@ import { deriveBackendTraits } from './converter.js';
|
|
|
79
82
|
import { DefaultFactory as DefaultSyntaxHighlighterFactory } from './syntax_highlighter.js';
|
|
80
83
|
import Html5Converter from './converter/html5.js';
|
|
81
84
|
import { SyntaxHighlighter } from './syntax_highlighter.js';
|
|
82
|
-
export { convert, convertFile, Document, DocumentTitle, Author, Footnote, ImageReference, RevisionInfo, Logger, AbstractNode, AbstractBlock, Inline, Block, List, ListItem, Section, Reader, SyntaxHighlighterBase, LoggerManager, MemoryLogger, NullLogger, 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 };
|
|
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 };
|
package/types/path_resolver.d.ts
CHANGED
|
@@ -54,11 +54,6 @@ export class PathResolver {
|
|
|
54
54
|
* @returns {string} The posixified path.
|
|
55
55
|
*/
|
|
56
56
|
posixify(path: string): string;
|
|
57
|
-
/**
|
|
58
|
-
* @param {string} path
|
|
59
|
-
* @returns {string}
|
|
60
|
-
*/
|
|
61
|
-
posixfy(path: string): string;
|
|
62
57
|
/**
|
|
63
58
|
* Expand the path by resolving parent references (..) and removing self references (.).
|
|
64
59
|
* @param {string} path
|
package/types/stylesheets.d.ts
CHANGED
package/types/table.d.ts
CHANGED
|
@@ -113,7 +113,7 @@ declare class Cell extends AbstractBlock<string | string[]> {
|
|
|
113
113
|
imageUri(targetImage: string, assetDirKey?: string): Promise<string>;
|
|
114
114
|
mediaUri(target: string, assetDirKey?: string): string;
|
|
115
115
|
generateDataUri(targetImage: string, assetDirKey?: string | null): Promise<string>;
|
|
116
|
-
generateDataUriFromUri(imageUri: string
|
|
116
|
+
generateDataUriFromUri(imageUri: string): Promise<string>;
|
|
117
117
|
normalizeAssetPath(assetRef: string, assetName?: string, autocorrect?: boolean): string;
|
|
118
118
|
normalizeSystemPath(target: string, start?: string | null, jail?: string | null, opts?: any): string;
|
|
119
119
|
normalizeWebPath(target: string, start?: string | null, preserveUriTarget?: boolean): string;
|