slackmark 0.5.0 → 0.6.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/README.md +29 -17
- package/dist/adapters/block-to-plain-text.d.ts +24 -0
- package/dist/adapters/block-to-plain-text.d.ts.map +1 -0
- package/dist/adapters/blockquote-adapter.d.ts.map +1 -1
- package/dist/adapters/code-fence-adapter.d.ts +1 -1
- package/dist/adapters/code-fence-adapter.d.ts.map +1 -1
- package/dist/adapters/inline.d.ts.map +1 -1
- package/dist/adapters/list-adapter.d.ts.map +1 -1
- package/dist/adapters/math-block-adapter.d.ts +1 -1
- package/dist/adapters/math-block-adapter.d.ts.map +1 -1
- package/dist/adapters/mermaid-fence-adapter.d.ts.map +1 -1
- package/dist/adapters/table-adapter.d.ts.map +1 -1
- package/dist/adapters/task-list-adapter.d.ts.map +1 -1
- package/dist/adapters/try-render-image.d.ts +9 -0
- package/dist/adapters/try-render-image.d.ts.map +1 -0
- package/dist/assemble/message-assembler.d.ts +10 -0
- package/dist/assemble/message-assembler.d.ts.map +1 -1
- package/dist/budget/conversion-context.d.ts +5 -1
- package/dist/budget/conversion-context.d.ts.map +1 -1
- package/dist/budget/operation-scope.d.ts +9 -0
- package/dist/budget/operation-scope.d.ts.map +1 -0
- package/dist/budget/recording-receipt-collector.d.ts +13 -0
- package/dist/budget/recording-receipt-collector.d.ts.map +1 -0
- package/dist/capabilities/capabilities.d.ts.map +1 -1
- package/dist/constants.d.ts +14 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/converter/create-converter.d.ts +1 -1
- package/dist/converter/create-converter.d.ts.map +1 -1
- package/dist/converter/resolve-config.d.ts +4 -2
- package/dist/converter/resolve-config.d.ts.map +1 -1
- package/dist/converter/slackmark-converter.d.ts +11 -1
- package/dist/converter/slackmark-converter.d.ts.map +1 -1
- package/dist/errors.d.ts +81 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5080 -3585
- package/dist/index.js.map +1 -1
- package/dist/receipts.d.ts +37 -0
- package/dist/receipts.d.ts.map +1 -0
- package/dist/renderers/codecogs-renderer.d.ts +5 -5
- package/dist/renderers/codecogs-renderer.d.ts.map +1 -1
- package/dist/renderers/kroki-renderer.d.ts +5 -5
- package/dist/renderers/kroki-renderer.d.ts.map +1 -1
- package/dist/renderers/mermaid-ink-renderer.d.ts +5 -5
- package/dist/renderers/mermaid-ink-renderer.d.ts.map +1 -1
- package/dist/renderers/quickchart-renderer.d.ts +5 -5
- package/dist/renderers/quickchart-renderer.d.ts.map +1 -1
- package/dist/renderers/renderer-options.d.ts +4 -0
- package/dist/renderers/renderer-options.d.ts.map +1 -0
- package/dist/renderers/url-utils.d.ts.map +1 -1
- package/dist/renderers.d.ts +1 -0
- package/dist/renderers.d.ts.map +1 -1
- package/dist/renderers.js +412 -248
- package/dist/renderers.js.map +1 -1
- package/dist/slack/fetch-slack-uploader.d.ts +11 -2
- package/dist/slack/fetch-slack-uploader.d.ts.map +1 -1
- package/dist/slack/slack-upload-error.d.ts +18 -2
- package/dist/slack/slack-upload-error.d.ts.map +1 -1
- package/dist/slack.d.ts +2 -1
- package/dist/slack.d.ts.map +1 -1
- package/dist/slack.js +753 -230
- package/dist/slack.js.map +1 -1
- package/dist/types.d.ts +93 -11
- package/dist/types.d.ts.map +1 -1
- package/dist/validate/validate-blocks.d.ts.map +1 -1
- package/package.json +5 -4
package/dist/renderers.js
CHANGED
|
@@ -1,269 +1,433 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
//#region src/errors.ts
|
|
2
|
+
const CONFIGURATION_ERROR_BRAND = Symbol.for("slackmark.error.configuration");
|
|
3
|
+
const OPERATION_ERROR_BRAND = Symbol.for("slackmark.error.operation");
|
|
4
|
+
/**
|
|
5
|
+
* Marks a class prototype so instances from any bundled copy answer to one identity.
|
|
6
|
+
* Subclasses inherit the brand, and instances carry no extra own property.
|
|
7
|
+
*/
|
|
8
|
+
function brandErrorPrototype(prototype, brand) {
|
|
9
|
+
Object.defineProperty(prototype, brand, {
|
|
10
|
+
configurable: false,
|
|
11
|
+
enumerable: false,
|
|
12
|
+
value: true,
|
|
13
|
+
writable: false
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Reads a brand without trusting the value: a hostile getter must not escape a guard.
|
|
18
|
+
*/
|
|
19
|
+
function hasErrorBrand(value, brand) {
|
|
20
|
+
if (typeof value !== "object" || value === null) return false;
|
|
21
|
+
try {
|
|
22
|
+
return Reflect.get(value, brand) === true;
|
|
23
|
+
} catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
var ConfigurationError = class extends Error {
|
|
28
|
+
static {
|
|
29
|
+
brandErrorPrototype(this.prototype, CONFIGURATION_ERROR_BRAND);
|
|
30
|
+
}
|
|
31
|
+
name;
|
|
32
|
+
code;
|
|
33
|
+
stage;
|
|
34
|
+
retryable;
|
|
35
|
+
receipts;
|
|
36
|
+
settledReceipts;
|
|
37
|
+
constructor(message, options = {}) {
|
|
38
|
+
super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
39
|
+
this.name = "ConfigurationError";
|
|
40
|
+
this.code = options.code ?? "invalid_configuration";
|
|
41
|
+
this.stage = options.stage;
|
|
42
|
+
this.retryable = false;
|
|
43
|
+
this.receipts = freezeReceipts(options.receipts ?? []);
|
|
44
|
+
this.settledReceipts = options.settledReceipts ?? Promise.resolve(this.receipts);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
(class extends Error {
|
|
48
|
+
static {
|
|
49
|
+
brandErrorPrototype(this.prototype, OPERATION_ERROR_BRAND);
|
|
50
|
+
}
|
|
51
|
+
name;
|
|
52
|
+
code;
|
|
53
|
+
stage;
|
|
54
|
+
retryable;
|
|
55
|
+
receipts;
|
|
56
|
+
settledReceipts;
|
|
57
|
+
constructor(message, code, stage, retryable, options = {}) {
|
|
58
|
+
super(message, options.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
59
|
+
this.name = "OperationError";
|
|
60
|
+
this.code = code;
|
|
61
|
+
this.stage = stage;
|
|
62
|
+
this.retryable = retryable;
|
|
63
|
+
this.receipts = freezeReceipts(options.receipts ?? []);
|
|
64
|
+
this.settledReceipts = options.settledReceipts ?? Promise.resolve(this.receipts);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
/**
|
|
68
|
+
* Identifies a {@link ConfigurationError} from any entry of this package.
|
|
69
|
+
*
|
|
70
|
+
* Use this instead of `instanceof` when the error may have been thrown by a different
|
|
71
|
+
* entry — for example a `ConfigurationError` from `slackmark/renderers` caught by code
|
|
72
|
+
* that imported the class from `slackmark`.
|
|
73
|
+
*/
|
|
74
|
+
function isConfigurationError(value) {
|
|
75
|
+
return hasErrorBrand(value, CONFIGURATION_ERROR_BRAND);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Identifies an {@link OperationError} — abort, deadline, or shutdown — from any entry of
|
|
79
|
+
* this package, including its subclasses.
|
|
80
|
+
*
|
|
81
|
+
* Use this instead of `instanceof` when the error may have been thrown by a different
|
|
82
|
+
* entry — for example an abort raised inside `FetchSlackUploader` from `slackmark/slack`
|
|
83
|
+
* caught by code that imported the class from `slackmark`. Narrow further with `code`
|
|
84
|
+
* against {@link OperationErrorCode} rather than testing a subclass with `instanceof`.
|
|
85
|
+
*/
|
|
86
|
+
function isOperationError(value) {
|
|
87
|
+
return hasErrorBrand(value, OPERATION_ERROR_BRAND);
|
|
88
|
+
}
|
|
89
|
+
function freezeReceipts(receipts) {
|
|
90
|
+
return Object.freeze(receipts.map((receipt) => Object.freeze({ ...receipt })));
|
|
91
|
+
}
|
|
92
|
+
//#endregion
|
|
93
|
+
//#region src/renderers/encoding.ts
|
|
94
|
+
const BASE64URL_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
|
95
|
+
/**
|
|
96
|
+
* Kroki and mermaid.ink both accept zlib-deflated, unpadded base64url payloads.
|
|
97
|
+
*/
|
|
6
98
|
async function deflateBase64Url(value) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
99
|
+
const stream = new CompressionStream("deflate");
|
|
100
|
+
const compressed = readAll(stream.readable);
|
|
101
|
+
const writer = stream.writable.getWriter();
|
|
102
|
+
await writer.write(new TextEncoder().encode(value));
|
|
103
|
+
await writer.close();
|
|
104
|
+
writer.releaseLock();
|
|
105
|
+
return encodeBase64Url(await compressed);
|
|
14
106
|
}
|
|
15
107
|
async function readAll(stream) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
return output;
|
|
108
|
+
const reader = stream.getReader();
|
|
109
|
+
const chunks = [];
|
|
110
|
+
let length = 0;
|
|
111
|
+
while (true) {
|
|
112
|
+
const result = await reader.read();
|
|
113
|
+
if (result.done) break;
|
|
114
|
+
if (result.value !== void 0) {
|
|
115
|
+
chunks.push(result.value);
|
|
116
|
+
length += result.value.byteLength;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
reader.releaseLock();
|
|
120
|
+
const output = new Uint8Array(length);
|
|
121
|
+
let offset = 0;
|
|
122
|
+
for (const chunk of chunks) {
|
|
123
|
+
output.set(chunk, offset);
|
|
124
|
+
offset += chunk.byteLength;
|
|
125
|
+
}
|
|
126
|
+
return output;
|
|
37
127
|
}
|
|
38
128
|
function encodeBase64Url(bytes) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
output.push(BASE64URL_ALPHABET[(second & 15) << 2 | (third ?? 0) >> 6] ?? "");
|
|
50
|
-
}
|
|
51
|
-
if (third !== void 0) {
|
|
52
|
-
output.push(BASE64URL_ALPHABET[third & 63] ?? "");
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return output.join("");
|
|
129
|
+
const output = [];
|
|
130
|
+
for (let index = 0; index < bytes.length; index += 3) {
|
|
131
|
+
const first = bytes[index] ?? 0;
|
|
132
|
+
const second = bytes[index + 1];
|
|
133
|
+
const third = bytes[index + 2];
|
|
134
|
+
output.push(BASE64URL_ALPHABET[first >> 2] ?? "", BASE64URL_ALPHABET[(first & 3) << 4 | (second ?? 0) >> 4] ?? "");
|
|
135
|
+
if (second !== void 0) output.push(BASE64URL_ALPHABET[(second & 15) << 2 | (third ?? 0) >> 6] ?? "");
|
|
136
|
+
if (third !== void 0) output.push(BASE64URL_ALPHABET[third & 63] ?? "");
|
|
137
|
+
}
|
|
138
|
+
return output.join("");
|
|
56
139
|
}
|
|
57
|
-
|
|
58
|
-
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region src/renderers/renderer-options.ts
|
|
142
|
+
function snapshotRendererOptions(options, allowed, label) {
|
|
143
|
+
if (typeof options !== "object" || options === null || Array.isArray(options)) throw invalidRendererOptions(`${label} options must be a plain object`);
|
|
144
|
+
let prototype;
|
|
145
|
+
let keys;
|
|
146
|
+
try {
|
|
147
|
+
prototype = Object.getPrototypeOf(options);
|
|
148
|
+
keys = Object.keys(options);
|
|
149
|
+
} catch (cause) {
|
|
150
|
+
throw invalidRendererOptions(`${label} options could not be inspected`, cause);
|
|
151
|
+
}
|
|
152
|
+
if (prototype !== Object.prototype && prototype !== null) throw invalidRendererOptions(`${label} options must be a plain object`);
|
|
153
|
+
const allowedKeys = new Set(allowed);
|
|
154
|
+
const snapshot = {};
|
|
155
|
+
for (const key of keys) {
|
|
156
|
+
if (!allowedKeys.has(key)) throw invalidRendererOptions(`Unknown ${label} option: ${key}`);
|
|
157
|
+
try {
|
|
158
|
+
snapshot[key] = Reflect.get(options, key);
|
|
159
|
+
} catch (cause) {
|
|
160
|
+
throw invalidRendererOptions(`${label}.${key} could not be read`, cause);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return Object.freeze(snapshot);
|
|
164
|
+
}
|
|
165
|
+
function invalidRendererOptions(message, cause) {
|
|
166
|
+
return new ConfigurationError(message, {
|
|
167
|
+
code: "invalid_renderer_options",
|
|
168
|
+
stage: "configuration",
|
|
169
|
+
cause
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
//#endregion
|
|
173
|
+
//#region src/renderers/url-utils.ts
|
|
59
174
|
function normalizeBaseUrl(baseUrl) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
175
|
+
if (typeof baseUrl !== "string" || baseUrl.length === 0 || baseUrl !== baseUrl.trim()) throw invalidRendererOptions("baseUrl must be a nonempty trimmed string");
|
|
176
|
+
const normalized = baseUrl.replace(/\/+$/u, "");
|
|
177
|
+
try {
|
|
178
|
+
const parsed = new URL(normalized);
|
|
179
|
+
if (parsed.protocol !== "https:" || parsed.username.length > 0 || parsed.password.length > 0) throw invalidRendererOptions("baseUrl must be credential-free absolute HTTPS");
|
|
180
|
+
} catch (cause) {
|
|
181
|
+
if (isConfigurationError(cause)) throw cause;
|
|
182
|
+
throw invalidRendererOptions("baseUrl must be credential-free absolute HTTPS", cause);
|
|
183
|
+
}
|
|
184
|
+
return normalized;
|
|
65
185
|
}
|
|
66
186
|
function normalizeFenceLanguage(lang) {
|
|
67
|
-
|
|
187
|
+
return lang.trim().toLowerCase();
|
|
68
188
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
189
|
+
//#endregion
|
|
190
|
+
//#region src/renderers/kroki-renderer.ts
|
|
191
|
+
const DEFAULT_KROKI_BASE_URL = "https://kroki.io";
|
|
192
|
+
/**
|
|
193
|
+
* Fence-language aliases for Kroki's supported diagram types.
|
|
194
|
+
*
|
|
195
|
+
* @see https://docs.kroki.io/kroki/setup/usage/
|
|
196
|
+
*/
|
|
197
|
+
const KROKI_DIAGRAM_TYPES = Object.freeze({
|
|
198
|
+
blockdiag: "blockdiag",
|
|
199
|
+
bpmn: "bpmn",
|
|
200
|
+
bytefield: "bytefield",
|
|
201
|
+
c4: "c4plantuml",
|
|
202
|
+
c4plantuml: "c4plantuml",
|
|
203
|
+
d2: "d2",
|
|
204
|
+
dbml: "dbml",
|
|
205
|
+
ditaa: "ditaa",
|
|
206
|
+
dot: "graphviz",
|
|
207
|
+
erd: "erd",
|
|
208
|
+
excalidraw: "excalidraw",
|
|
209
|
+
graphviz: "graphviz",
|
|
210
|
+
mermaid: "mermaid",
|
|
211
|
+
nomnoml: "nomnoml",
|
|
212
|
+
pikchr: "pikchr",
|
|
213
|
+
plantuml: "plantuml",
|
|
214
|
+
puml: "plantuml",
|
|
215
|
+
structurizr: "structurizr",
|
|
216
|
+
svgbob: "svgbob",
|
|
217
|
+
symbolator: "symbolator",
|
|
218
|
+
tikz: "tikz",
|
|
219
|
+
umlet: "umlet",
|
|
220
|
+
vega: "vega",
|
|
221
|
+
"vega-lite": "vegalite",
|
|
222
|
+
vegalite: "vegalite",
|
|
223
|
+
wavedrom: "wavedrom",
|
|
224
|
+
wireviz: "wireviz"
|
|
100
225
|
});
|
|
226
|
+
/**
|
|
227
|
+
* Produces durable Kroki GET URLs without performing network I/O.
|
|
228
|
+
*/
|
|
101
229
|
var KrokiRenderer = class {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
230
|
+
id;
|
|
231
|
+
output;
|
|
232
|
+
baseUrl;
|
|
233
|
+
diagramTypes;
|
|
234
|
+
constructor(options = {}) {
|
|
235
|
+
const validated = snapshotRendererOptions(options, ["baseUrl", "diagramTypes"], "KrokiRenderer");
|
|
236
|
+
this.id = "kroki";
|
|
237
|
+
this.output = "url";
|
|
238
|
+
this.baseUrl = normalizeBaseUrl(validated.baseUrl === void 0 ? DEFAULT_KROKI_BASE_URL : validated.baseUrl);
|
|
239
|
+
this.diagramTypes = Object.freeze({
|
|
240
|
+
...KROKI_DIAGRAM_TYPES,
|
|
241
|
+
...validateDiagramTypes(validated.diagramTypes)
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
canRender(req) {
|
|
245
|
+
return this.diagramTypes[normalizeFenceLanguage(req.lang)] !== void 0;
|
|
246
|
+
}
|
|
247
|
+
async render(req, _context) {
|
|
248
|
+
const diagramType = this.diagramTypes[normalizeFenceLanguage(req.lang)];
|
|
249
|
+
if (diagramType === void 0) return null;
|
|
250
|
+
const encoded = await deflateBase64Url(req.source);
|
|
251
|
+
const imageUrl = `${this.baseUrl}/${encodeURIComponent(diagramType)}/png/${encoded}`;
|
|
252
|
+
if (imageUrl.length > 3e3) return null;
|
|
253
|
+
return {
|
|
254
|
+
kind: "url",
|
|
255
|
+
imageUrl,
|
|
256
|
+
altText: req.altText
|
|
257
|
+
};
|
|
258
|
+
}
|
|
130
259
|
};
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
260
|
+
function validateDiagramTypes(value) {
|
|
261
|
+
if (value === void 0) return {};
|
|
262
|
+
let keys;
|
|
263
|
+
try {
|
|
264
|
+
keys = Object.keys(value);
|
|
265
|
+
} catch (cause) {
|
|
266
|
+
throw invalidRendererOptions("KrokiRenderer.diagramTypes could not be inspected", cause);
|
|
267
|
+
}
|
|
268
|
+
const snapshot = snapshotRendererOptions(value, keys, "KrokiRenderer.diagramTypes");
|
|
269
|
+
for (const [language, diagramType] of Object.entries(snapshot)) if (language.length === 0 || typeof diagramType !== "string" || diagramType.length === 0) throw invalidRendererOptions("KrokiRenderer.diagramTypes values must be nonempty strings");
|
|
270
|
+
return snapshot;
|
|
271
|
+
}
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/renderers/mermaid-ink-renderer.ts
|
|
274
|
+
const DEFAULT_MERMAID_INK_BASE_URL = "https://mermaid.ink";
|
|
275
|
+
const DEFAULT_MERMAID_INK_BACKGROUND = "!white";
|
|
276
|
+
/**
|
|
277
|
+
* Produces mermaid.ink pako-state PNG URLs without performing network I/O.
|
|
278
|
+
*/
|
|
135
279
|
var MermaidInkRenderer = class {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
280
|
+
id;
|
|
281
|
+
output;
|
|
282
|
+
baseUrl;
|
|
283
|
+
theme;
|
|
284
|
+
bgColor;
|
|
285
|
+
constructor(options = {}) {
|
|
286
|
+
const validated = snapshotRendererOptions(options, [
|
|
287
|
+
"baseUrl",
|
|
288
|
+
"theme",
|
|
289
|
+
"bgColor"
|
|
290
|
+
], "MermaidInkRenderer");
|
|
291
|
+
this.id = "mermaid-ink";
|
|
292
|
+
this.output = "url";
|
|
293
|
+
this.baseUrl = normalizeBaseUrl(validated.baseUrl === void 0 ? DEFAULT_MERMAID_INK_BASE_URL : validated.baseUrl);
|
|
294
|
+
this.theme = validated.theme === void 0 ? "default" : validated.theme;
|
|
295
|
+
this.bgColor = validated.bgColor === void 0 ? DEFAULT_MERMAID_INK_BACKGROUND : validated.bgColor;
|
|
296
|
+
if (![
|
|
297
|
+
"default",
|
|
298
|
+
"neutral",
|
|
299
|
+
"dark",
|
|
300
|
+
"forest"
|
|
301
|
+
].includes(this.theme) || typeof this.bgColor !== "string" || this.bgColor.length === 0) throw invalidRendererOptions("MermaidInkRenderer theme or bgColor is invalid");
|
|
302
|
+
}
|
|
303
|
+
canRender(req) {
|
|
304
|
+
return normalizeFenceLanguage(req.lang) === "mermaid";
|
|
305
|
+
}
|
|
306
|
+
async render(req, _context) {
|
|
307
|
+
if (!this.canRender(req)) return null;
|
|
308
|
+
const state = {
|
|
309
|
+
code: req.source,
|
|
310
|
+
mermaid: { theme: this.theme }
|
|
311
|
+
};
|
|
312
|
+
const encoded = await deflateBase64Url(JSON.stringify(state));
|
|
313
|
+
const imageUrl = `${this.baseUrl}/img/pako:${encoded}?type=png&bgColor=${encodeURIComponent(this.bgColor)}`;
|
|
314
|
+
if (imageUrl.length > 3e3) return null;
|
|
315
|
+
return {
|
|
316
|
+
kind: "url",
|
|
317
|
+
imageUrl,
|
|
318
|
+
altText: req.altText
|
|
319
|
+
};
|
|
320
|
+
}
|
|
166
321
|
};
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
322
|
+
//#endregion
|
|
323
|
+
//#region src/renderers/codecogs-renderer.ts
|
|
324
|
+
const DEFAULT_CODECOGS_BASE_URL = "https://latex.codecogs.com";
|
|
325
|
+
const DEFAULT_CODECOGS_DPI = 200;
|
|
326
|
+
const MATH_FENCE_LANGUAGES = /* @__PURE__ */ new Set([
|
|
327
|
+
"katex",
|
|
328
|
+
"latex",
|
|
329
|
+
"math",
|
|
330
|
+
"tex"
|
|
331
|
+
]);
|
|
332
|
+
/**
|
|
333
|
+
* Produces deterministic CodeCogs `png.image` URLs for display math.
|
|
334
|
+
*/
|
|
172
335
|
var CodeCogsRenderer = class {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
336
|
+
id;
|
|
337
|
+
output;
|
|
338
|
+
baseUrl;
|
|
339
|
+
dpi;
|
|
340
|
+
constructor(options = {}) {
|
|
341
|
+
const validated = snapshotRendererOptions(options, ["baseUrl", "dpi"], "CodeCogsRenderer");
|
|
342
|
+
this.id = "codecogs";
|
|
343
|
+
this.output = "url";
|
|
344
|
+
this.baseUrl = normalizeBaseUrl(validated.baseUrl === void 0 ? DEFAULT_CODECOGS_BASE_URL : validated.baseUrl);
|
|
345
|
+
this.dpi = validated.dpi === void 0 ? DEFAULT_CODECOGS_DPI : validated.dpi;
|
|
346
|
+
if (!Number.isInteger(this.dpi) || this.dpi <= 0) throw invalidRendererOptions("dpi must be a positive integer");
|
|
347
|
+
}
|
|
348
|
+
canRender(req) {
|
|
349
|
+
return MATH_FENCE_LANGUAGES.has(normalizeFenceLanguage(req.lang));
|
|
350
|
+
}
|
|
351
|
+
async render(req, _context) {
|
|
352
|
+
if (!this.canRender(req)) return null;
|
|
353
|
+
const formula = `\\dpi{${String(this.dpi)}} ${req.source}`;
|
|
354
|
+
const imageUrl = `${this.baseUrl}/png.image?${encodeURIComponent(formula)}`;
|
|
355
|
+
if (imageUrl.length > 3e3) return null;
|
|
356
|
+
return {
|
|
357
|
+
kind: "url",
|
|
358
|
+
imageUrl,
|
|
359
|
+
altText: req.altText
|
|
360
|
+
};
|
|
361
|
+
}
|
|
200
362
|
};
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
363
|
+
//#endregion
|
|
364
|
+
//#region src/renderers/quickchart-renderer.ts
|
|
365
|
+
const DEFAULT_QUICKCHART_BASE_URL = "https://quickchart.io";
|
|
366
|
+
const DEFAULT_QUICKCHART_WIDTH = 500;
|
|
367
|
+
const DEFAULT_QUICKCHART_HEIGHT = 300;
|
|
368
|
+
const DEFAULT_QUICKCHART_BACKGROUND = "white";
|
|
369
|
+
const DEFAULT_QUICKCHART_DEVICE_PIXEL_RATIO = 2;
|
|
370
|
+
const CHART_FENCE_LANGUAGES = /* @__PURE__ */ new Set([
|
|
371
|
+
"chart",
|
|
372
|
+
"chart.js",
|
|
373
|
+
"chartjs",
|
|
374
|
+
"quickchart"
|
|
213
375
|
]);
|
|
376
|
+
/**
|
|
377
|
+
* Produces full, durable QuickChart GET URLs. It never uses the expiring
|
|
378
|
+
* `/chart/create` short-URL API.
|
|
379
|
+
*/
|
|
214
380
|
var QuickChartRenderer = class {
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
CodeCogsRenderer,
|
|
264
|
-
KROKI_DIAGRAM_TYPES,
|
|
265
|
-
KrokiRenderer,
|
|
266
|
-
MermaidInkRenderer,
|
|
267
|
-
QuickChartRenderer
|
|
381
|
+
id;
|
|
382
|
+
output;
|
|
383
|
+
baseUrl;
|
|
384
|
+
width;
|
|
385
|
+
height;
|
|
386
|
+
backgroundColor;
|
|
387
|
+
devicePixelRatio;
|
|
388
|
+
constructor(options = {}) {
|
|
389
|
+
const validated = snapshotRendererOptions(options, [
|
|
390
|
+
"baseUrl",
|
|
391
|
+
"width",
|
|
392
|
+
"height",
|
|
393
|
+
"backgroundColor",
|
|
394
|
+
"devicePixelRatio"
|
|
395
|
+
], "QuickChartRenderer");
|
|
396
|
+
this.id = "quickchart";
|
|
397
|
+
this.output = "url";
|
|
398
|
+
this.baseUrl = normalizeBaseUrl(validated.baseUrl === void 0 ? DEFAULT_QUICKCHART_BASE_URL : validated.baseUrl);
|
|
399
|
+
this.width = validated.width === void 0 ? DEFAULT_QUICKCHART_WIDTH : validated.width;
|
|
400
|
+
this.height = validated.height === void 0 ? DEFAULT_QUICKCHART_HEIGHT : validated.height;
|
|
401
|
+
this.backgroundColor = validated.backgroundColor === void 0 ? DEFAULT_QUICKCHART_BACKGROUND : validated.backgroundColor;
|
|
402
|
+
this.devicePixelRatio = validated.devicePixelRatio === void 0 ? DEFAULT_QUICKCHART_DEVICE_PIXEL_RATIO : validated.devicePixelRatio;
|
|
403
|
+
if (!Number.isInteger(this.width) || this.width <= 0) throw invalidRendererOptions("width must be a positive integer");
|
|
404
|
+
if (!Number.isInteger(this.height) || this.height <= 0) throw invalidRendererOptions("height must be a positive integer");
|
|
405
|
+
if (!Number.isFinite(this.devicePixelRatio) || this.devicePixelRatio <= 0) throw invalidRendererOptions("devicePixelRatio must be positive");
|
|
406
|
+
if (typeof this.backgroundColor !== "string" || this.backgroundColor.length === 0) throw invalidRendererOptions("backgroundColor must be a nonempty string");
|
|
407
|
+
}
|
|
408
|
+
canRender(req) {
|
|
409
|
+
return CHART_FENCE_LANGUAGES.has(normalizeFenceLanguage(req.lang));
|
|
410
|
+
}
|
|
411
|
+
async render(req, _context) {
|
|
412
|
+
if (!this.canRender(req)) return null;
|
|
413
|
+
const query = [
|
|
414
|
+
`c=${encodeURIComponent(req.source)}`,
|
|
415
|
+
`width=${String(this.width)}`,
|
|
416
|
+
`height=${String(this.height)}`,
|
|
417
|
+
`backgroundColor=${encodeURIComponent(this.backgroundColor)}`,
|
|
418
|
+
`devicePixelRatio=${String(this.devicePixelRatio)}`,
|
|
419
|
+
"format=png"
|
|
420
|
+
].join("&");
|
|
421
|
+
const imageUrl = `${this.baseUrl}/chart?${query}`;
|
|
422
|
+
if (imageUrl.length > 3e3) return null;
|
|
423
|
+
return {
|
|
424
|
+
kind: "url",
|
|
425
|
+
imageUrl,
|
|
426
|
+
altText: req.altText
|
|
427
|
+
};
|
|
428
|
+
}
|
|
268
429
|
};
|
|
430
|
+
//#endregion
|
|
431
|
+
export { CodeCogsRenderer, KROKI_DIAGRAM_TYPES, KrokiRenderer, MermaidInkRenderer, QuickChartRenderer, isConfigurationError, isOperationError };
|
|
432
|
+
|
|
269
433
|
//# sourceMappingURL=renderers.js.map
|