slackmark 0.3.0 → 0.4.0
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/dist/adapters/html-block-adapter.d.ts.map +1 -1
- package/dist/adapters/inline.d.ts +6 -0
- package/dist/adapters/inline.d.ts.map +1 -1
- package/dist/adapters/mermaid-fence-adapter.d.ts.map +1 -1
- package/dist/adapters/paragraph-adapter.d.ts.map +1 -1
- package/dist/adapters/table-adapter.d.ts.map +1 -1
- package/dist/assemble/message-assembler.d.ts.map +1 -1
- package/dist/blocks/types.d.ts +33 -11
- package/dist/blocks/types.d.ts.map +1 -1
- package/dist/capabilities/capabilities.d.ts +2 -4
- package/dist/capabilities/capabilities.d.ts.map +1 -1
- package/dist/converter/slackmark-converter.d.ts.map +1 -1
- package/dist/index.js +500 -196
- package/dist/index.js.map +1 -1
- package/dist/utf16.d.ts +20 -0
- package/dist/utf16.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var ConfigurationError = class extends Error {
|
|
3
|
+
name;
|
|
4
|
+
constructor(message, options) {
|
|
5
|
+
super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
6
|
+
this.name = "ConfigurationError";
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
|
|
1
10
|
// src/capabilities/capabilities.ts
|
|
2
11
|
var CapabilityPresetName = {
|
|
3
12
|
Latest: "latest",
|
|
@@ -59,12 +68,13 @@ function resolveCapabilities(input, overrides) {
|
|
|
59
68
|
if (input === void 0) {
|
|
60
69
|
base = CAPABILITY_PRESETS.latest;
|
|
61
70
|
} else if (typeof input === "string") {
|
|
62
|
-
const preset = CAPABILITY_PRESETS[input];
|
|
71
|
+
const preset = isPresetName(input) ? CAPABILITY_PRESETS[input] : void 0;
|
|
63
72
|
if (preset === void 0) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
throw new ConfigurationError(
|
|
74
|
+
`Unknown capability preset ${JSON.stringify(input)}; use one of: ${Object.keys(CAPABILITY_PRESETS).join(", ")}.`
|
|
75
|
+
);
|
|
67
76
|
}
|
|
77
|
+
base = preset;
|
|
68
78
|
} else if (isFullFlags(input)) {
|
|
69
79
|
base = input;
|
|
70
80
|
} else {
|
|
@@ -75,6 +85,9 @@ function resolveCapabilities(input, overrides) {
|
|
|
75
85
|
}
|
|
76
86
|
return Object.freeze({ ...base, ...overrides });
|
|
77
87
|
}
|
|
88
|
+
function isPresetName(value) {
|
|
89
|
+
return Object.hasOwn(CAPABILITY_PRESETS, value);
|
|
90
|
+
}
|
|
78
91
|
function isFullFlags(value) {
|
|
79
92
|
return typeof value.richText === "boolean" && typeof value.markdownBlock === "boolean" && typeof value.tableBlock === "boolean" && typeof value.preformattedLanguage === "boolean" && typeof value.headerLevel === "boolean" && typeof value.dataTable === "boolean" && typeof value.dataVisualization === "boolean" && typeof value.containerBlock === "boolean";
|
|
80
93
|
}
|
|
@@ -298,6 +311,29 @@ function assertNever(value, message) {
|
|
|
298
311
|
throw new Error(`${detail}: ${JSON.stringify(value)}`);
|
|
299
312
|
}
|
|
300
313
|
|
|
314
|
+
// src/utf16.ts
|
|
315
|
+
var HIGH_SURROGATE_MIN = 55296;
|
|
316
|
+
var HIGH_SURROGATE_MAX = 56319;
|
|
317
|
+
var LOW_SURROGATE_MIN = 56320;
|
|
318
|
+
var LOW_SURROGATE_MAX = 57343;
|
|
319
|
+
function surrogateSafeEnd(text, end) {
|
|
320
|
+
if (end <= 0) {
|
|
321
|
+
return 0;
|
|
322
|
+
}
|
|
323
|
+
if (end >= text.length) {
|
|
324
|
+
return text.length;
|
|
325
|
+
}
|
|
326
|
+
const before = text.charCodeAt(end - 1);
|
|
327
|
+
const after = text.charCodeAt(end);
|
|
328
|
+
if (before >= HIGH_SURROGATE_MIN && before <= HIGH_SURROGATE_MAX && after >= LOW_SURROGATE_MIN && after <= LOW_SURROGATE_MAX) {
|
|
329
|
+
return end - 1;
|
|
330
|
+
}
|
|
331
|
+
return end;
|
|
332
|
+
}
|
|
333
|
+
function sliceSurrogateSafe(text, max) {
|
|
334
|
+
return text.slice(0, surrogateSafeEnd(text, max));
|
|
335
|
+
}
|
|
336
|
+
|
|
301
337
|
// src/types.ts
|
|
302
338
|
var OverflowMode = {
|
|
303
339
|
Degrade: "degrade",
|
|
@@ -398,7 +434,7 @@ var MessageAssembler = class {
|
|
|
398
434
|
reason: "Notification text truncated to 40k safety limit",
|
|
399
435
|
path: ctx.path
|
|
400
436
|
});
|
|
401
|
-
return { blocks, text: raw
|
|
437
|
+
return { blocks, text: sliceSurrogateSafe(raw, MESSAGE_TEXT_SAFETY_MAX_CHARS) };
|
|
402
438
|
}
|
|
403
439
|
};
|
|
404
440
|
function buildFootnoteBlocks(entries, degradations) {
|
|
@@ -417,7 +453,7 @@ function buildFootnoteBlocks(entries, degradations) {
|
|
|
417
453
|
reason: "Footnote context text truncated to 3000 chars",
|
|
418
454
|
path: "footnote"
|
|
419
455
|
});
|
|
420
|
-
elements.push({ type: "mrkdwn", text: note
|
|
456
|
+
elements.push({ type: "mrkdwn", text: sliceSurrogateSafe(note, SECTION_TEXT_MAX_CHARS) });
|
|
421
457
|
} else {
|
|
422
458
|
elements.push({ type: "mrkdwn", text: note });
|
|
423
459
|
}
|
|
@@ -622,7 +658,7 @@ function inlinesToPlain(elements) {
|
|
|
622
658
|
parts.push(`@${el.range}`);
|
|
623
659
|
break;
|
|
624
660
|
case "date":
|
|
625
|
-
parts.push(el.fallback ?? el.format);
|
|
661
|
+
parts.push(el.fallback ?? formatDateTokensUtc(el.timestamp, el.format));
|
|
626
662
|
break;
|
|
627
663
|
default:
|
|
628
664
|
break;
|
|
@@ -630,6 +666,101 @@ function inlinesToPlain(elements) {
|
|
|
630
666
|
}
|
|
631
667
|
return parts.join("");
|
|
632
668
|
}
|
|
669
|
+
var DATE_TOKEN_RE = /\{([a-z_]+)\}/g;
|
|
670
|
+
var MONTHS = [
|
|
671
|
+
"January",
|
|
672
|
+
"February",
|
|
673
|
+
"March",
|
|
674
|
+
"April",
|
|
675
|
+
"May",
|
|
676
|
+
"June",
|
|
677
|
+
"July",
|
|
678
|
+
"August",
|
|
679
|
+
"September",
|
|
680
|
+
"October",
|
|
681
|
+
"November",
|
|
682
|
+
"December"
|
|
683
|
+
];
|
|
684
|
+
var WEEKDAYS = [
|
|
685
|
+
"Sunday",
|
|
686
|
+
"Monday",
|
|
687
|
+
"Tuesday",
|
|
688
|
+
"Wednesday",
|
|
689
|
+
"Thursday",
|
|
690
|
+
"Friday",
|
|
691
|
+
"Saturday"
|
|
692
|
+
];
|
|
693
|
+
function pad2(value) {
|
|
694
|
+
return String(value).padStart(2, "0");
|
|
695
|
+
}
|
|
696
|
+
function ordinal(value) {
|
|
697
|
+
const remainder = value % 100;
|
|
698
|
+
if (remainder >= 11 && remainder <= 13) {
|
|
699
|
+
return `${String(value)}th`;
|
|
700
|
+
}
|
|
701
|
+
switch (value % 10) {
|
|
702
|
+
case 1:
|
|
703
|
+
return `${String(value)}st`;
|
|
704
|
+
case 2:
|
|
705
|
+
return `${String(value)}nd`;
|
|
706
|
+
case 3:
|
|
707
|
+
return `${String(value)}rd`;
|
|
708
|
+
default:
|
|
709
|
+
return `${String(value)}th`;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
function dateToken(token, date) {
|
|
713
|
+
const day = date.getUTCDate();
|
|
714
|
+
const month = MONTHS[date.getUTCMonth()] ?? "";
|
|
715
|
+
const shortMonth = month.slice(0, 3);
|
|
716
|
+
const weekday = WEEKDAYS[date.getUTCDay()] ?? "";
|
|
717
|
+
const year = date.getUTCFullYear();
|
|
718
|
+
switch (token) {
|
|
719
|
+
case "date_num":
|
|
720
|
+
return `${String(year)}-${pad2(date.getUTCMonth() + 1)}-${pad2(day)}`;
|
|
721
|
+
// Slack renders {date_slash} month-first: 02/18/2014 (docs example for
|
|
722
|
+
// timestamp 1392734382).
|
|
723
|
+
case "date_slash":
|
|
724
|
+
return `${pad2(date.getUTCMonth() + 1)}/${pad2(day)}/${String(year)}`;
|
|
725
|
+
case "date_long":
|
|
726
|
+
case "date_long_pretty":
|
|
727
|
+
return `${weekday}, ${month} ${ordinal(day)}, ${String(year)}`;
|
|
728
|
+
case "date_long_full":
|
|
729
|
+
return `${month} ${String(day)}, ${String(year)}`;
|
|
730
|
+
// {date} renders "February 18th, 2014" (ordinal + year), not "February 18".
|
|
731
|
+
case "date":
|
|
732
|
+
case "date_pretty":
|
|
733
|
+
return `${month} ${ordinal(day)}, ${String(year)}`;
|
|
734
|
+
case "date_short":
|
|
735
|
+
case "date_short_pretty":
|
|
736
|
+
return `${shortMonth} ${String(day)}, ${String(year)}`;
|
|
737
|
+
case "time":
|
|
738
|
+
return `${pad2(date.getUTCHours())}:${pad2(date.getUTCMinutes())}`;
|
|
739
|
+
case "time_secs":
|
|
740
|
+
return `${pad2(date.getUTCHours())}:${pad2(date.getUTCMinutes())}:${pad2(date.getUTCSeconds())}`;
|
|
741
|
+
default:
|
|
742
|
+
return void 0;
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
function formatDateTokensUtc(timestamp, format) {
|
|
746
|
+
const date = new Date(timestamp * 1e3);
|
|
747
|
+
if (!Number.isFinite(timestamp) || Number.isNaN(date.getTime())) {
|
|
748
|
+
return String(timestamp);
|
|
749
|
+
}
|
|
750
|
+
let unsupported = false;
|
|
751
|
+
const formatted = format.replace(DATE_TOKEN_RE, (_match, token) => {
|
|
752
|
+
const replacement = dateToken(token, date);
|
|
753
|
+
if (replacement === void 0) {
|
|
754
|
+
unsupported = true;
|
|
755
|
+
return "";
|
|
756
|
+
}
|
|
757
|
+
return replacement;
|
|
758
|
+
});
|
|
759
|
+
if (format.length === 0 || unsupported) {
|
|
760
|
+
return date.toISOString().slice(0, 10);
|
|
761
|
+
}
|
|
762
|
+
return formatted;
|
|
763
|
+
}
|
|
633
764
|
function tableToPlain(rows) {
|
|
634
765
|
const lines = [];
|
|
635
766
|
for (const row of rows) {
|
|
@@ -869,15 +1000,6 @@ function parseNumberList(inner) {
|
|
|
869
1000
|
// src/converter/slackmark-converter.ts
|
|
870
1001
|
import { toString } from "mdast-util-to-string";
|
|
871
1002
|
|
|
872
|
-
// src/errors.ts
|
|
873
|
-
var ConfigurationError = class extends Error {
|
|
874
|
-
name;
|
|
875
|
-
constructor(message, options) {
|
|
876
|
-
super(message, options?.cause !== void 0 ? { cause: options.cause } : void 0);
|
|
877
|
-
this.name = "ConfigurationError";
|
|
878
|
-
}
|
|
879
|
-
};
|
|
880
|
-
|
|
881
1003
|
// src/converter/resolve-config.ts
|
|
882
1004
|
function resolveConfig(defaults, overrides) {
|
|
883
1005
|
const merged = {
|
|
@@ -967,7 +1089,7 @@ var SlackMarkConverter = class {
|
|
|
967
1089
|
enableMath: config.enableMath,
|
|
968
1090
|
enableFrontmatter: config.enableFrontmatter
|
|
969
1091
|
});
|
|
970
|
-
const { definitions, footnotes, footnoteOrder } = collectRefs(tree);
|
|
1092
|
+
const { definitions, footnotes, footnoteOrder } = collectRefs(tree, degradations);
|
|
971
1093
|
let precedingHeading;
|
|
972
1094
|
const emitted = [];
|
|
973
1095
|
let index = 0;
|
|
@@ -992,11 +1114,13 @@ var SlackMarkConverter = class {
|
|
|
992
1114
|
emitted.push(...blocks);
|
|
993
1115
|
index += 1;
|
|
994
1116
|
}
|
|
1117
|
+
const footnoteNumbers = /* @__PURE__ */ new Map();
|
|
1118
|
+
footnoteOrder.forEach((id, i) => footnoteNumbers.set(id, i + 1));
|
|
995
1119
|
const footnoteEntries = footnoteOrder.map((id, i) => {
|
|
996
1120
|
const def = footnotes.get(id);
|
|
997
1121
|
return {
|
|
998
1122
|
n: i + 1,
|
|
999
|
-
text: def !== void 0 ?
|
|
1123
|
+
text: def !== void 0 ? footnoteBodyText(def, footnoteNumbers).trim() : id
|
|
1000
1124
|
};
|
|
1001
1125
|
});
|
|
1002
1126
|
const footnoteBlocks = buildFootnoteBlocks(footnoteEntries, degradations);
|
|
@@ -1105,7 +1229,7 @@ function safeNotificationText(plainText, markdown, degradations) {
|
|
|
1105
1229
|
reason: "Notification text truncated to 40k safety limit",
|
|
1106
1230
|
path: "root"
|
|
1107
1231
|
});
|
|
1108
|
-
return raw
|
|
1232
|
+
return sliceSurrogateSafe(raw, MESSAGE_TEXT_SAFETY_MAX_CHARS);
|
|
1109
1233
|
}
|
|
1110
1234
|
function clampSectionFallback(text, degradations) {
|
|
1111
1235
|
if (text.length <= SECTION_TEXT_MAX_CHARS) {
|
|
@@ -1118,17 +1242,38 @@ function clampSectionFallback(text, degradations) {
|
|
|
1118
1242
|
reason: "Section text truncated to 3000 chars",
|
|
1119
1243
|
path: "root"
|
|
1120
1244
|
});
|
|
1121
|
-
return text
|
|
1245
|
+
return sliceSurrogateSafe(text, SECTION_TEXT_MAX_CHARS);
|
|
1122
1246
|
}
|
|
1123
|
-
function collectRefs(tree) {
|
|
1247
|
+
function collectRefs(tree, degradations) {
|
|
1124
1248
|
const definitions = /* @__PURE__ */ new Map();
|
|
1125
1249
|
const footnotes = /* @__PURE__ */ new Map();
|
|
1126
1250
|
for (const node of tree.children) {
|
|
1127
1251
|
if (node.type === "definition") {
|
|
1128
|
-
|
|
1252
|
+
const key = node.identifier.toLowerCase();
|
|
1253
|
+
if (definitions.has(key)) {
|
|
1254
|
+
degradations.add({
|
|
1255
|
+
nodeType: "definition",
|
|
1256
|
+
from: node.identifier,
|
|
1257
|
+
to: "ignored",
|
|
1258
|
+
reason: "Duplicate link reference definition; first definition wins",
|
|
1259
|
+
path: "root"
|
|
1260
|
+
});
|
|
1261
|
+
} else {
|
|
1262
|
+
definitions.set(key, node);
|
|
1263
|
+
}
|
|
1129
1264
|
}
|
|
1130
1265
|
if (node.type === "footnoteDefinition") {
|
|
1131
|
-
footnotes.
|
|
1266
|
+
if (footnotes.has(node.identifier)) {
|
|
1267
|
+
degradations.add({
|
|
1268
|
+
nodeType: "footnoteDefinition",
|
|
1269
|
+
from: node.identifier,
|
|
1270
|
+
to: "ignored",
|
|
1271
|
+
reason: "Duplicate footnote definition; first definition wins",
|
|
1272
|
+
path: "root"
|
|
1273
|
+
});
|
|
1274
|
+
} else {
|
|
1275
|
+
footnotes.set(node.identifier, node);
|
|
1276
|
+
}
|
|
1132
1277
|
}
|
|
1133
1278
|
}
|
|
1134
1279
|
const footnoteOrder = [];
|
|
@@ -1139,8 +1284,46 @@ function collectRefs(tree) {
|
|
|
1139
1284
|
footnoteOrder.push(id);
|
|
1140
1285
|
}
|
|
1141
1286
|
});
|
|
1287
|
+
for (let i = 0; i < footnoteOrder.length; i += 1) {
|
|
1288
|
+
const def = footnotes.get(footnoteOrder[i] ?? "");
|
|
1289
|
+
if (def === void 0) {
|
|
1290
|
+
continue;
|
|
1291
|
+
}
|
|
1292
|
+
for (const child of def.children) {
|
|
1293
|
+
walkFootnoteReferences(child, (id) => {
|
|
1294
|
+
if (!seen.has(id)) {
|
|
1295
|
+
seen.add(id);
|
|
1296
|
+
footnoteOrder.push(id);
|
|
1297
|
+
}
|
|
1298
|
+
});
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1142
1301
|
return { definitions, footnotes, footnoteOrder };
|
|
1143
1302
|
}
|
|
1303
|
+
function footnoteBodyText(node, numbers) {
|
|
1304
|
+
if (node === null || typeof node !== "object") {
|
|
1305
|
+
return "";
|
|
1306
|
+
}
|
|
1307
|
+
const record = node;
|
|
1308
|
+
if (record.type === "footnoteReference" && typeof record.identifier === "string") {
|
|
1309
|
+
const n = numbers.get(record.identifier);
|
|
1310
|
+
return n !== void 0 ? `[${String(n)}]` : `[^${record.identifier}]`;
|
|
1311
|
+
}
|
|
1312
|
+
if (typeof record.value === "string") {
|
|
1313
|
+
return record.value;
|
|
1314
|
+
}
|
|
1315
|
+
if (typeof record.alt === "string") {
|
|
1316
|
+
return record.alt;
|
|
1317
|
+
}
|
|
1318
|
+
if (record.children !== void 0) {
|
|
1319
|
+
const parts = [];
|
|
1320
|
+
for (const child of record.children) {
|
|
1321
|
+
parts.push(footnoteBodyText(child, numbers));
|
|
1322
|
+
}
|
|
1323
|
+
return parts.join("");
|
|
1324
|
+
}
|
|
1325
|
+
return "";
|
|
1326
|
+
}
|
|
1144
1327
|
function walkFootnoteReferences(node, onRef) {
|
|
1145
1328
|
if (node === null || typeof node !== "object") {
|
|
1146
1329
|
return;
|
|
@@ -1164,8 +1347,11 @@ function chunkMarkdown(text, max) {
|
|
|
1164
1347
|
return [text.length > 0 ? text : " "];
|
|
1165
1348
|
}
|
|
1166
1349
|
const out = [];
|
|
1167
|
-
|
|
1168
|
-
|
|
1350
|
+
let i = 0;
|
|
1351
|
+
while (i < text.length) {
|
|
1352
|
+
const end = surrogateSafeEnd(text, i + max);
|
|
1353
|
+
out.push(text.slice(i, end));
|
|
1354
|
+
i = end;
|
|
1169
1355
|
}
|
|
1170
1356
|
return out;
|
|
1171
1357
|
}
|
|
@@ -1175,45 +1361,7 @@ import { toString as toString3 } from "mdast-util-to-string";
|
|
|
1175
1361
|
|
|
1176
1362
|
// src/adapters/inline.ts
|
|
1177
1363
|
import { toString as toString2 } from "mdast-util-to-string";
|
|
1178
|
-
var EMOJI_SHORTCODE_RE =
|
|
1179
|
-
var KNOWN_SLACK_EMOJI = /* @__PURE__ */ new Set([
|
|
1180
|
-
"smile",
|
|
1181
|
-
"grinning",
|
|
1182
|
-
"wink",
|
|
1183
|
-
"blush",
|
|
1184
|
-
"wave",
|
|
1185
|
-
"thumbsup",
|
|
1186
|
-
"thumbsdown",
|
|
1187
|
-
"tada",
|
|
1188
|
-
"rocket",
|
|
1189
|
-
"fire",
|
|
1190
|
-
"heart",
|
|
1191
|
-
"eyes",
|
|
1192
|
-
"thinking_face",
|
|
1193
|
-
"sweat_smile",
|
|
1194
|
-
"joy",
|
|
1195
|
-
"sob",
|
|
1196
|
-
"clap",
|
|
1197
|
-
"100",
|
|
1198
|
-
"white_check_mark",
|
|
1199
|
-
"x",
|
|
1200
|
-
"warning",
|
|
1201
|
-
"bulb",
|
|
1202
|
-
"memo",
|
|
1203
|
-
"mag",
|
|
1204
|
-
"link",
|
|
1205
|
-
"gear",
|
|
1206
|
-
"bug",
|
|
1207
|
-
"sparkles",
|
|
1208
|
-
"+1",
|
|
1209
|
-
"-1",
|
|
1210
|
-
"ok_hand",
|
|
1211
|
-
"pray",
|
|
1212
|
-
"star",
|
|
1213
|
-
"zap",
|
|
1214
|
-
"check",
|
|
1215
|
-
"heavy_check_mark"
|
|
1216
|
-
]);
|
|
1364
|
+
var EMOJI_SHORTCODE_RE = /(?<![A-Za-z0-9]):([a-z0-9_+-]{1,64}):(?![A-Za-z0-9])/g;
|
|
1217
1365
|
var HTTP_URL_RE = /^(https?:|mailto:)/i;
|
|
1218
1366
|
var IMAGE_EXT_RE = /\.(png|jpe?g|gif)(?:\?|#|$)/i;
|
|
1219
1367
|
function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
@@ -1221,26 +1369,24 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1221
1369
|
const hoistedImages = [];
|
|
1222
1370
|
const work = [...nodes];
|
|
1223
1371
|
let pendingAnchor;
|
|
1372
|
+
const htmlStyles = [];
|
|
1373
|
+
const activeStyle = () => htmlStyles[htmlStyles.length - 1] ?? baseStyle;
|
|
1224
1374
|
const flushPendingAnchor = () => {
|
|
1225
1375
|
if (pendingAnchor === void 0) {
|
|
1226
1376
|
return;
|
|
1227
1377
|
}
|
|
1228
|
-
|
|
1229
|
-
elements.push({
|
|
1230
|
-
type: "link",
|
|
1231
|
-
url: pendingAnchor.href,
|
|
1232
|
-
text: label.length > 0 ? label : pendingAnchor.href,
|
|
1233
|
-
style: styleOrUndefined(pendingAnchor.style)
|
|
1234
|
-
});
|
|
1378
|
+
elements.push(anchorInline(pendingAnchor, ctx));
|
|
1235
1379
|
pendingAnchor = void 0;
|
|
1236
1380
|
};
|
|
1237
1381
|
for (let i = 0; i < work.length; i += 1) {
|
|
1238
1382
|
const node = work[i];
|
|
1239
1383
|
if (pendingAnchor === void 0) {
|
|
1240
|
-
const reassembled = reassembleSlackLabeledLink(work, i,
|
|
1384
|
+
const reassembled = reassembleSlackLabeledLink(work, i, activeStyle());
|
|
1241
1385
|
if (reassembled !== void 0) {
|
|
1242
1386
|
if (reassembled.leadingText.value.length > 0) {
|
|
1243
|
-
elements.push(
|
|
1387
|
+
elements.push(
|
|
1388
|
+
...emitTextWithMentionsAndEmoji(reassembled.leadingText, activeStyle(), ctx)
|
|
1389
|
+
);
|
|
1244
1390
|
}
|
|
1245
1391
|
elements.push(reassembled.link);
|
|
1246
1392
|
if (reassembled.trailingText.value.length > 0) {
|
|
@@ -1270,7 +1416,7 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1270
1416
|
}
|
|
1271
1417
|
if (node.type === "html") {
|
|
1272
1418
|
const trimmed = node.value.trim();
|
|
1273
|
-
const entityInlines = slackEntityRichTextInlines(trimmed,
|
|
1419
|
+
const entityInlines = slackEntityRichTextInlines(trimmed, activeStyle());
|
|
1274
1420
|
if (entityInlines !== void 0) {
|
|
1275
1421
|
elements.push(...entityInlines);
|
|
1276
1422
|
continue;
|
|
@@ -1279,28 +1425,45 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1279
1425
|
if (openOnly !== null) {
|
|
1280
1426
|
const hrefMatch = /href\s*=\s*["']([^"']{0,3000})["']/i.exec(openOnly[1] ?? "");
|
|
1281
1427
|
const href = hrefMatch?.[1];
|
|
1282
|
-
if (href !== void 0
|
|
1283
|
-
pendingAnchor = {
|
|
1428
|
+
if (href !== void 0) {
|
|
1429
|
+
pendingAnchor = {
|
|
1430
|
+
href,
|
|
1431
|
+
style: activeStyle(),
|
|
1432
|
+
textParts: [],
|
|
1433
|
+
valid: isValidLinkUrl(href)
|
|
1434
|
+
};
|
|
1284
1435
|
continue;
|
|
1285
1436
|
}
|
|
1286
1437
|
}
|
|
1287
|
-
|
|
1438
|
+
const openTag = HTML_STYLE_OPEN_RE.exec(trimmed);
|
|
1439
|
+
if (openTag !== null) {
|
|
1440
|
+
htmlStyles.push(htmlTagStyle(activeStyle(), openTag[1] ?? ""));
|
|
1441
|
+
continue;
|
|
1442
|
+
}
|
|
1443
|
+
if (HTML_STYLE_CLOSE_RE.test(trimmed)) {
|
|
1444
|
+
htmlStyles.pop();
|
|
1445
|
+
continue;
|
|
1446
|
+
}
|
|
1447
|
+
elements.push(...emitInlineHtml(node.value, activeStyle(), ctx));
|
|
1288
1448
|
continue;
|
|
1289
1449
|
}
|
|
1290
1450
|
switch (node.type) {
|
|
1291
1451
|
case "text": {
|
|
1292
|
-
elements.push(...emitTextWithMentionsAndEmoji(node,
|
|
1452
|
+
elements.push(...emitTextWithMentionsAndEmoji(node, activeStyle(), ctx));
|
|
1293
1453
|
break;
|
|
1294
1454
|
}
|
|
1295
1455
|
case "strong": {
|
|
1296
|
-
const inner = emitPhrasing(node.children, ctx, {
|
|
1456
|
+
const inner = emitPhrasing(node.children, ctx, {
|
|
1457
|
+
...activeStyle(),
|
|
1458
|
+
bold: true
|
|
1459
|
+
});
|
|
1297
1460
|
elements.push(...inner.elements);
|
|
1298
1461
|
hoistedImages.push(...inner.hoistedImages);
|
|
1299
1462
|
break;
|
|
1300
1463
|
}
|
|
1301
1464
|
case "emphasis": {
|
|
1302
1465
|
const inner = emitPhrasing(node.children, ctx, {
|
|
1303
|
-
...
|
|
1466
|
+
...activeStyle(),
|
|
1304
1467
|
italic: true
|
|
1305
1468
|
});
|
|
1306
1469
|
elements.push(...inner.elements);
|
|
@@ -1308,7 +1471,7 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1308
1471
|
break;
|
|
1309
1472
|
}
|
|
1310
1473
|
case "delete": {
|
|
1311
|
-
const inner = emitPhrasing(node.children, ctx, { ...
|
|
1474
|
+
const inner = emitPhrasing(node.children, ctx, { ...activeStyle(), strike: true });
|
|
1312
1475
|
elements.push(...inner.elements);
|
|
1313
1476
|
hoistedImages.push(...inner.hoistedImages);
|
|
1314
1477
|
break;
|
|
@@ -1317,21 +1480,21 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1317
1480
|
const el = {
|
|
1318
1481
|
type: "text",
|
|
1319
1482
|
text: node.value,
|
|
1320
|
-
style: styleOrUndefined({ ...
|
|
1483
|
+
style: styleOrUndefined({ ...activeStyle(), code: true })
|
|
1321
1484
|
};
|
|
1322
1485
|
elements.push(el);
|
|
1323
1486
|
break;
|
|
1324
1487
|
}
|
|
1325
1488
|
case "break": {
|
|
1326
|
-
elements.push({ type: "text", text: "\n", style: styleOrUndefined(
|
|
1489
|
+
elements.push({ type: "text", text: "\n", style: styleOrUndefined(activeStyle()) });
|
|
1327
1490
|
break;
|
|
1328
1491
|
}
|
|
1329
1492
|
case "link": {
|
|
1330
|
-
elements.push(...emitLink(node, ctx,
|
|
1493
|
+
elements.push(...emitLink(node, ctx, activeStyle()));
|
|
1331
1494
|
break;
|
|
1332
1495
|
}
|
|
1333
1496
|
case "linkReference": {
|
|
1334
|
-
elements.push(...emitLinkReference(node, ctx,
|
|
1497
|
+
elements.push(...emitLinkReference(node, ctx, activeStyle()));
|
|
1335
1498
|
break;
|
|
1336
1499
|
}
|
|
1337
1500
|
case "image": {
|
|
@@ -1346,22 +1509,33 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1346
1509
|
type: "link",
|
|
1347
1510
|
url,
|
|
1348
1511
|
text: node.alt && node.alt.length > 0 ? node.alt : url,
|
|
1349
|
-
style: styleOrUndefined(
|
|
1512
|
+
style: styleOrUndefined(activeStyle())
|
|
1350
1513
|
});
|
|
1351
1514
|
} else {
|
|
1515
|
+
const linkable = isValidLinkUrl(url);
|
|
1352
1516
|
ctx.degradations.add({
|
|
1353
1517
|
nodeType: "image",
|
|
1354
1518
|
from: "image",
|
|
1355
|
-
to: "link",
|
|
1519
|
+
to: linkable ? "link" : "text",
|
|
1356
1520
|
reason: "Image URL is not a public http(s) png/jpg/gif \u22643000 chars",
|
|
1357
1521
|
path: ctx.path
|
|
1358
1522
|
});
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1523
|
+
const label = node.alt && node.alt.length > 0 ? node.alt : url.length > 0 ? url : "image";
|
|
1524
|
+
if (linkable) {
|
|
1525
|
+
elements.push({
|
|
1526
|
+
type: "link",
|
|
1527
|
+
url,
|
|
1528
|
+
text: label,
|
|
1529
|
+
style: styleOrUndefined(activeStyle())
|
|
1530
|
+
});
|
|
1531
|
+
} else {
|
|
1532
|
+
const suffix = url.length > 0 && url !== label ? ` (${url})` : "";
|
|
1533
|
+
elements.push({
|
|
1534
|
+
type: "text",
|
|
1535
|
+
text: `${label}${suffix}`,
|
|
1536
|
+
style: styleOrUndefined(activeStyle())
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1365
1539
|
}
|
|
1366
1540
|
break;
|
|
1367
1541
|
}
|
|
@@ -1371,7 +1545,7 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1371
1545
|
elements.push({
|
|
1372
1546
|
type: "text",
|
|
1373
1547
|
text: node.alt ?? node.identifier,
|
|
1374
|
-
style: styleOrUndefined(
|
|
1548
|
+
style: styleOrUndefined(activeStyle())
|
|
1375
1549
|
});
|
|
1376
1550
|
break;
|
|
1377
1551
|
}
|
|
@@ -1385,7 +1559,7 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1385
1559
|
}
|
|
1386
1560
|
],
|
|
1387
1561
|
ctx,
|
|
1388
|
-
|
|
1562
|
+
activeStyle()
|
|
1389
1563
|
);
|
|
1390
1564
|
elements.push(...asImage.elements);
|
|
1391
1565
|
hoistedImages.push(...asImage.hoistedImages);
|
|
@@ -1397,7 +1571,7 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1397
1571
|
elements.push({
|
|
1398
1572
|
type: "text",
|
|
1399
1573
|
text: `[${String(n)}]`,
|
|
1400
|
-
style: styleOrUndefined(
|
|
1574
|
+
style: styleOrUndefined(activeStyle())
|
|
1401
1575
|
});
|
|
1402
1576
|
break;
|
|
1403
1577
|
}
|
|
@@ -1405,7 +1579,7 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1405
1579
|
elements.push({
|
|
1406
1580
|
type: "text",
|
|
1407
1581
|
text: node.value,
|
|
1408
|
-
style: styleOrUndefined({ ...
|
|
1582
|
+
style: styleOrUndefined({ ...activeStyle(), code: true })
|
|
1409
1583
|
});
|
|
1410
1584
|
ctx.degradations.add({
|
|
1411
1585
|
nodeType: "inlineMath",
|
|
@@ -1419,7 +1593,7 @@ function emitPhrasing(nodes, ctx, baseStyle = {}) {
|
|
|
1419
1593
|
default: {
|
|
1420
1594
|
const text = toString2(node);
|
|
1421
1595
|
if (text.length > 0) {
|
|
1422
|
-
elements.push({ type: "text", text, style: styleOrUndefined(
|
|
1596
|
+
elements.push({ type: "text", text, style: styleOrUndefined(activeStyle()) });
|
|
1423
1597
|
}
|
|
1424
1598
|
break;
|
|
1425
1599
|
}
|
|
@@ -1488,7 +1662,7 @@ function truncateLabel(label, max) {
|
|
|
1488
1662
|
if (label.length <= max) {
|
|
1489
1663
|
return { text: label, truncated: false };
|
|
1490
1664
|
}
|
|
1491
|
-
return { text: `${label
|
|
1665
|
+
return { text: `${sliceSurrogateSafe(label, Math.max(0, max - 1))}${ELLIPSIS}`, truncated: true };
|
|
1492
1666
|
}
|
|
1493
1667
|
function hoistedImageBlock(h, ctx) {
|
|
1494
1668
|
return {
|
|
@@ -1509,7 +1683,7 @@ function clampSectionText(text, ctx, nodeType) {
|
|
|
1509
1683
|
reason: "Section text truncated to 3000 chars",
|
|
1510
1684
|
path: ctx.path
|
|
1511
1685
|
});
|
|
1512
|
-
return text
|
|
1686
|
+
return sliceSurrogateSafe(text, SECTION_TEXT_MAX_CHARS);
|
|
1513
1687
|
}
|
|
1514
1688
|
function preformattedRichText(text, language) {
|
|
1515
1689
|
return {
|
|
@@ -1535,7 +1709,7 @@ function clampImageText(value, ctx, field) {
|
|
|
1535
1709
|
reason: `Image ${field} truncated to ${String(IMAGE_ALT_MAX_CHARS)} chars`,
|
|
1536
1710
|
path: ctx.path
|
|
1537
1711
|
});
|
|
1538
|
-
return value
|
|
1712
|
+
return sliceSurrogateSafe(value, IMAGE_ALT_MAX_CHARS);
|
|
1539
1713
|
}
|
|
1540
1714
|
function styleOrUndefined(style) {
|
|
1541
1715
|
if (style.bold === true || style.italic === true || style.strike === true || style.code === true || style.underline === true) {
|
|
@@ -1630,7 +1804,7 @@ function slackEntitySplit(value, style, emit) {
|
|
|
1630
1804
|
function slackEntityRichTextInlines(value, style) {
|
|
1631
1805
|
return slackEntitySplit(value, style, (slice) => emitTextWithEmoji(slice, style));
|
|
1632
1806
|
}
|
|
1633
|
-
var MENTION_RE = /(?<![A-Za-z0-9._-])@([a-zA-Z0-9._-]{
|
|
1807
|
+
var MENTION_RE = /(?<![A-Za-z0-9._-])@([a-zA-Z0-9_-](?:[a-zA-Z0-9._-]{0,62}[a-zA-Z0-9_-])?)|(?<![A-Za-z0-9_-])#([a-zA-Z0-9_-]{1,80})/g;
|
|
1634
1808
|
function phrasingNeedsMentionResolution(nodes, ctx) {
|
|
1635
1809
|
const resolvers = ctx.config.mentionResolvers;
|
|
1636
1810
|
if (resolvers?.resolveUser === void 0 && resolvers?.resolveChannel === void 0) {
|
|
@@ -1707,13 +1881,8 @@ function emitTextWithEmoji(value, style) {
|
|
|
1707
1881
|
if (start > last) {
|
|
1708
1882
|
out.push({ type: "text", text: value.slice(last, start), style: styleOrUndefined(style) });
|
|
1709
1883
|
}
|
|
1710
|
-
const
|
|
1711
|
-
|
|
1712
|
-
const emoji = { type: "emoji", name };
|
|
1713
|
-
out.push(emoji);
|
|
1714
|
-
} else {
|
|
1715
|
-
out.push({ type: "text", text: match[0], style: styleOrUndefined(style) });
|
|
1716
|
-
}
|
|
1884
|
+
const emoji = { type: "emoji", name: match[1] ?? "" };
|
|
1885
|
+
out.push(emoji);
|
|
1717
1886
|
last = start + match[0].length;
|
|
1718
1887
|
match = EMOJI_SHORTCODE_RE.exec(value);
|
|
1719
1888
|
}
|
|
@@ -1780,7 +1949,7 @@ function emitLink(node, ctx, style) {
|
|
|
1780
1949
|
reason: "Invalid or oversized URL",
|
|
1781
1950
|
path: ctx.path
|
|
1782
1951
|
});
|
|
1783
|
-
const suffix = url.length > 0 ? ` (${url})` : "";
|
|
1952
|
+
const suffix = url.length > 0 && url !== text ? ` (${url})` : "";
|
|
1784
1953
|
return [{ type: "text", text: `${text}${suffix}`, style: styleOrUndefined(style) }];
|
|
1785
1954
|
}
|
|
1786
1955
|
const link = {
|
|
@@ -1817,9 +1986,45 @@ function isValidLinkUrl(url) {
|
|
|
1817
1986
|
if (url.length === 0 || url.length > IMAGE_URL_MAX_CHARS) {
|
|
1818
1987
|
return false;
|
|
1819
1988
|
}
|
|
1820
|
-
return HTTP_URL_RE.test(url)
|
|
1989
|
+
return HTTP_URL_RE.test(url);
|
|
1821
1990
|
}
|
|
1822
|
-
|
|
1991
|
+
function anchorInline(anchor, ctx) {
|
|
1992
|
+
const label = anchor.textParts.join("");
|
|
1993
|
+
if (anchor.valid) {
|
|
1994
|
+
return {
|
|
1995
|
+
type: "link",
|
|
1996
|
+
url: anchor.href,
|
|
1997
|
+
text: label.length > 0 ? label : anchor.href,
|
|
1998
|
+
style: styleOrUndefined(anchor.style)
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
ctx.degradations.add({
|
|
2002
|
+
nodeType: "link",
|
|
2003
|
+
from: "link",
|
|
2004
|
+
to: "text",
|
|
2005
|
+
reason: "Invalid or oversized URL",
|
|
2006
|
+
path: ctx.path
|
|
2007
|
+
});
|
|
2008
|
+
const base = label.length > 0 ? label : anchor.href;
|
|
2009
|
+
const suffix = label.length > 0 && anchor.href.length > 0 && anchor.href !== label ? ` (${anchor.href})` : "";
|
|
2010
|
+
return { type: "text", text: `${base}${suffix}`, style: styleOrUndefined(anchor.style) };
|
|
2011
|
+
}
|
|
2012
|
+
var HTML_STYLE_OPEN_RE = /^<(b|strong|i|em|s|del|code)(\s+[^>]{0,200})?>$/i;
|
|
2013
|
+
var HTML_STYLE_CLOSE_RE = /^<\/(b|strong|i|em|s|del|code)\s*>$/i;
|
|
2014
|
+
function htmlTagStyle(base, tag) {
|
|
2015
|
+
const t = tag.toLowerCase();
|
|
2016
|
+
if (t === "b" || t === "strong") {
|
|
2017
|
+
return { ...base, bold: true };
|
|
2018
|
+
}
|
|
2019
|
+
if (t === "i" || t === "em") {
|
|
2020
|
+
return { ...base, italic: true };
|
|
2021
|
+
}
|
|
2022
|
+
if (t === "s" || t === "del") {
|
|
2023
|
+
return { ...base, strike: true };
|
|
2024
|
+
}
|
|
2025
|
+
return { ...base, code: true };
|
|
2026
|
+
}
|
|
2027
|
+
var INLINE_TAG_RE = /<\/?(b|strong|i|em|s|del|code|br|a)(\s+[^>]{0,200})?\s*\/?>|<[^>]{0,200}>|[^<]+|</gi;
|
|
1823
2028
|
function emitInlineHtml(html, style, ctx) {
|
|
1824
2029
|
const out = [];
|
|
1825
2030
|
const stack = [];
|
|
@@ -1827,11 +2032,15 @@ function emitInlineHtml(html, style, ctx) {
|
|
|
1827
2032
|
let openAnchor;
|
|
1828
2033
|
INLINE_TAG_RE.lastIndex = 0;
|
|
1829
2034
|
let m = INLINE_TAG_RE.exec(html);
|
|
1830
|
-
let
|
|
2035
|
+
let strippedUnknown = false;
|
|
1831
2036
|
while (m !== null) {
|
|
1832
|
-
matched = true;
|
|
1833
2037
|
const token = m[0];
|
|
1834
|
-
if (token.startsWith("<")) {
|
|
2038
|
+
if (token.startsWith("<") && token.length > 1 && m[1] === void 0) {
|
|
2039
|
+
strippedUnknown = true;
|
|
2040
|
+
m = INLINE_TAG_RE.exec(html);
|
|
2041
|
+
continue;
|
|
2042
|
+
}
|
|
2043
|
+
if (token.startsWith("<") && m[1] !== void 0) {
|
|
1835
2044
|
const tag = (m[1] ?? "").toLowerCase();
|
|
1836
2045
|
const closing = token.startsWith("</");
|
|
1837
2046
|
if (tag === "br") {
|
|
@@ -1842,13 +2051,7 @@ function emitInlineHtml(html, style, ctx) {
|
|
|
1842
2051
|
}
|
|
1843
2052
|
} else if (closing) {
|
|
1844
2053
|
if (tag === "a" && openAnchor !== void 0) {
|
|
1845
|
-
|
|
1846
|
-
out.push({
|
|
1847
|
-
type: "link",
|
|
1848
|
-
url: openAnchor.href,
|
|
1849
|
-
text: label.length > 0 ? label : openAnchor.href,
|
|
1850
|
-
style: styleOrUndefined(openAnchor.style)
|
|
1851
|
-
});
|
|
2054
|
+
out.push(anchorInline(openAnchor, ctx));
|
|
1852
2055
|
openAnchor = void 0;
|
|
1853
2056
|
}
|
|
1854
2057
|
stack.pop();
|
|
@@ -1857,8 +2060,11 @@ function emitInlineHtml(html, style, ctx) {
|
|
|
1857
2060
|
const hrefMatch = /href\s*=\s*["']([^"']{0,3000})["']/i.exec(token);
|
|
1858
2061
|
const href = hrefMatch?.[1];
|
|
1859
2062
|
stack.push({ tag, style: current });
|
|
1860
|
-
if (href !== void 0
|
|
1861
|
-
openAnchor
|
|
2063
|
+
if (href !== void 0) {
|
|
2064
|
+
if (openAnchor !== void 0) {
|
|
2065
|
+
out.push(anchorInline(openAnchor, ctx));
|
|
2066
|
+
}
|
|
2067
|
+
openAnchor = { href, style: current, textParts: [], valid: isValidLinkUrl(href) };
|
|
1862
2068
|
}
|
|
1863
2069
|
} else {
|
|
1864
2070
|
const next = { ...current };
|
|
@@ -1879,15 +2085,9 @@ function emitInlineHtml(html, style, ctx) {
|
|
|
1879
2085
|
m = INLINE_TAG_RE.exec(html);
|
|
1880
2086
|
}
|
|
1881
2087
|
if (openAnchor !== void 0) {
|
|
1882
|
-
|
|
1883
|
-
out.push({
|
|
1884
|
-
type: "link",
|
|
1885
|
-
url: openAnchor.href,
|
|
1886
|
-
text: label.length > 0 ? label : openAnchor.href,
|
|
1887
|
-
style: styleOrUndefined(openAnchor.style)
|
|
1888
|
-
});
|
|
2088
|
+
out.push(anchorInline(openAnchor, ctx));
|
|
1889
2089
|
}
|
|
1890
|
-
if (
|
|
2090
|
+
if (strippedUnknown) {
|
|
1891
2091
|
ctx.degradations.add({
|
|
1892
2092
|
nodeType: "html",
|
|
1893
2093
|
from: "html",
|
|
@@ -1895,10 +2095,6 @@ function emitInlineHtml(html, style, ctx) {
|
|
|
1895
2095
|
reason: "Unrecognized inline HTML stripped to text",
|
|
1896
2096
|
path: ctx.path
|
|
1897
2097
|
});
|
|
1898
|
-
const stripped = html.replace(/<[^>]{0,200}>/g, "");
|
|
1899
|
-
if (stripped.length > 0) {
|
|
1900
|
-
out.push({ type: "text", text: stripped, style: styleOrUndefined(style) });
|
|
1901
|
-
}
|
|
1902
2098
|
}
|
|
1903
2099
|
return out;
|
|
1904
2100
|
}
|
|
@@ -2130,10 +2326,13 @@ function emitPlainHeader(heading, withLevel) {
|
|
|
2130
2326
|
const block = {
|
|
2131
2327
|
type: "header",
|
|
2132
2328
|
text: { type: "plain_text", text: plain.length > 0 ? plain : " " },
|
|
2133
|
-
level: withLevel ? heading.depth : void 0
|
|
2329
|
+
level: withLevel ? headerLevelOf(heading.depth) : void 0
|
|
2134
2330
|
};
|
|
2135
2331
|
return [block];
|
|
2136
2332
|
}
|
|
2333
|
+
function headerLevelOf(depth) {
|
|
2334
|
+
return depth === 1 || depth === 2 || depth === 3 || depth === 4 ? depth : void 0;
|
|
2335
|
+
}
|
|
2137
2336
|
function emitRichHeading(heading, ctx, hoistImages) {
|
|
2138
2337
|
const plain = phrasingToPlain(heading.children);
|
|
2139
2338
|
const depth = heading.depth;
|
|
@@ -2296,7 +2495,7 @@ function clampContainerTitle(text, ctx) {
|
|
|
2296
2495
|
reason: `Container title truncated to ${String(CONTAINER_TITLE_MAX_CHARS)} chars`,
|
|
2297
2496
|
path: ctx.path
|
|
2298
2497
|
});
|
|
2299
|
-
return text
|
|
2498
|
+
return sliceSurrogateSafe(text, CONTAINER_TITLE_MAX_CHARS);
|
|
2300
2499
|
}
|
|
2301
2500
|
|
|
2302
2501
|
// src/adapters/list-adapter.ts
|
|
@@ -2376,27 +2575,51 @@ function emitListTree(list, indent, ctx) {
|
|
|
2376
2575
|
});
|
|
2377
2576
|
effectiveIndent = RICH_TEXT_LIST_INDENT_MAX;
|
|
2378
2577
|
}
|
|
2379
|
-
const
|
|
2380
|
-
const
|
|
2578
|
+
const ordered = list.ordered === true;
|
|
2579
|
+
const startOffset = ordered && list.start !== null && list.start !== void 0 && list.start > 1 ? list.start - 1 : 0;
|
|
2580
|
+
const out = [];
|
|
2381
2581
|
const hoistedImages = [];
|
|
2382
|
-
|
|
2582
|
+
let pendingSections = [];
|
|
2583
|
+
const flush = (lastIndex) => {
|
|
2584
|
+
if (pendingSections.length === 0) {
|
|
2585
|
+
return;
|
|
2586
|
+
}
|
|
2587
|
+
const chunkStartIndex = lastIndex - pendingSections.length + 1;
|
|
2588
|
+
const offset = startOffset + chunkStartIndex;
|
|
2589
|
+
out.push({
|
|
2590
|
+
type: "rich_text_list",
|
|
2591
|
+
style: ordered ? "ordered" : "bullet",
|
|
2592
|
+
elements: pendingSections,
|
|
2593
|
+
indent: effectiveIndent,
|
|
2594
|
+
offset: ordered && offset > 0 ? offset : void 0
|
|
2595
|
+
});
|
|
2596
|
+
pendingSections = [];
|
|
2597
|
+
};
|
|
2598
|
+
for (const [index, item] of list.children.entries()) {
|
|
2383
2599
|
const { section, childLists, hoistedImages: itemImages } = emitListItem(item, ctx);
|
|
2384
|
-
|
|
2600
|
+
pendingSections.push(section);
|
|
2385
2601
|
hoistedImages.push(...itemImages);
|
|
2602
|
+
if (childLists.length === 0) {
|
|
2603
|
+
continue;
|
|
2604
|
+
}
|
|
2605
|
+
flush(index);
|
|
2386
2606
|
for (const child of childLists) {
|
|
2387
2607
|
const nestedResult = emitListTree(child, effectiveIndent + 1, ctx);
|
|
2388
|
-
|
|
2608
|
+
out.push(...nestedResult.elements);
|
|
2389
2609
|
hoistedImages.push(...nestedResult.hoistedImages);
|
|
2390
2610
|
}
|
|
2391
2611
|
}
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2612
|
+
flush(list.children.length - 1);
|
|
2613
|
+
if (out.length === 0) {
|
|
2614
|
+
out.push({
|
|
2615
|
+
type: "rich_text_list",
|
|
2616
|
+
style: ordered ? "ordered" : "bullet",
|
|
2617
|
+
elements: [{ type: "rich_text_section", elements: [{ type: "text", text: " " }] }],
|
|
2618
|
+
indent: effectiveIndent,
|
|
2619
|
+
offset: void 0
|
|
2620
|
+
});
|
|
2621
|
+
}
|
|
2622
|
+
return { elements: out, hoistedImages };
|
|
2400
2623
|
}
|
|
2401
2624
|
function collectListItemPhrasing(item) {
|
|
2402
2625
|
const phrasing = [];
|
|
@@ -2713,7 +2936,19 @@ async function tryRenderers(source, ctx) {
|
|
|
2713
2936
|
if (!renderer.canRender(req)) {
|
|
2714
2937
|
continue;
|
|
2715
2938
|
}
|
|
2716
|
-
|
|
2939
|
+
let result;
|
|
2940
|
+
try {
|
|
2941
|
+
result = await renderer.render(req);
|
|
2942
|
+
} catch (err) {
|
|
2943
|
+
ctx.degradations.add({
|
|
2944
|
+
nodeType: "code.mermaid",
|
|
2945
|
+
from: "image.render",
|
|
2946
|
+
to: "skip",
|
|
2947
|
+
reason: `Renderer failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2948
|
+
path: ctx.path
|
|
2949
|
+
});
|
|
2950
|
+
continue;
|
|
2951
|
+
}
|
|
2717
2952
|
if (result === null) {
|
|
2718
2953
|
continue;
|
|
2719
2954
|
}
|
|
@@ -2745,7 +2980,19 @@ async function tryRenderers(source, ctx) {
|
|
|
2745
2980
|
});
|
|
2746
2981
|
continue;
|
|
2747
2982
|
}
|
|
2748
|
-
|
|
2983
|
+
let uploaded;
|
|
2984
|
+
try {
|
|
2985
|
+
uploaded = await uploader.upload(result);
|
|
2986
|
+
} catch (err) {
|
|
2987
|
+
ctx.degradations.add({
|
|
2988
|
+
nodeType: "code.mermaid",
|
|
2989
|
+
from: "image.bytes",
|
|
2990
|
+
to: "skip",
|
|
2991
|
+
reason: `Slack upload failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
2992
|
+
path: ctx.path
|
|
2993
|
+
});
|
|
2994
|
+
continue;
|
|
2995
|
+
}
|
|
2749
2996
|
return {
|
|
2750
2997
|
type: "image",
|
|
2751
2998
|
alt_text: clampImageText(result.altText, ctx, "alt_text"),
|
|
@@ -2808,11 +3055,11 @@ function emitParagraph(paragraph, emitCtx, loneImage, hoistImages) {
|
|
|
2808
3055
|
const img = loneImage;
|
|
2809
3056
|
if (isPublicImageUrl(img.url)) {
|
|
2810
3057
|
const altRaw = img.alt ?? "image";
|
|
2811
|
-
const
|
|
3058
|
+
const alt2 = clampImageText(altRaw.length > 0 ? altRaw : "image", emitCtx, "alt_text");
|
|
2812
3059
|
const block = {
|
|
2813
3060
|
type: "image",
|
|
2814
3061
|
image_url: img.url,
|
|
2815
|
-
alt_text:
|
|
3062
|
+
alt_text: alt2,
|
|
2816
3063
|
title: img.title !== null && img.title !== void 0 && img.title.length > 0 ? {
|
|
2817
3064
|
type: "plain_text",
|
|
2818
3065
|
text: clampImageText(img.title, emitCtx, "title")
|
|
@@ -2820,20 +3067,23 @@ function emitParagraph(paragraph, emitCtx, loneImage, hoistImages) {
|
|
|
2820
3067
|
};
|
|
2821
3068
|
return [block];
|
|
2822
3069
|
}
|
|
3070
|
+
const linkable = isValidLinkUrl(img.url);
|
|
2823
3071
|
emitCtx.degradations.add({
|
|
2824
3072
|
nodeType: "image",
|
|
2825
3073
|
from: "image",
|
|
2826
|
-
to: "section.link",
|
|
3074
|
+
to: linkable ? "section.link" : "section.text",
|
|
2827
3075
|
reason: "Non-public or invalid image URL",
|
|
2828
3076
|
path: emitCtx.path
|
|
2829
3077
|
});
|
|
2830
|
-
const
|
|
3078
|
+
const alt = img.alt ?? "";
|
|
3079
|
+
const label = alt.length > 0 ? alt : img.url.length > 0 ? img.url : "image";
|
|
3080
|
+
const fallbackText = linkable ? `<${img.url}|${label}>` : img.url.length > 0 && img.url !== label ? `${label} (${img.url})` : label;
|
|
2831
3081
|
return [
|
|
2832
3082
|
{
|
|
2833
3083
|
type: "section",
|
|
2834
3084
|
text: {
|
|
2835
3085
|
type: "mrkdwn",
|
|
2836
|
-
text: clampSectionText(
|
|
3086
|
+
text: clampSectionText(fallbackText, emitCtx, "section")
|
|
2837
3087
|
}
|
|
2838
3088
|
}
|
|
2839
3089
|
];
|
|
@@ -2893,14 +3143,15 @@ var TableAdapter = class {
|
|
|
2893
3143
|
return node.type === "table";
|
|
2894
3144
|
}
|
|
2895
3145
|
plan(node, ctx) {
|
|
2896
|
-
const table = node;
|
|
3146
|
+
const table = normalizeTableRows(node, ctx);
|
|
2897
3147
|
const rowCount = table.children.length;
|
|
2898
3148
|
const colCount = table.children[0]?.children.length ?? 0;
|
|
2899
|
-
const cellChars = countEmittedCellChars(table, ctx);
|
|
2900
3149
|
if (colCount > TABLE_MAX_COLS) {
|
|
3150
|
+
const cellChars = countEmittedCellChars(table, ctx, "table");
|
|
2901
3151
|
return markdownThenAscii(table, cellChars, "Table exceeds 20 columns");
|
|
2902
3152
|
}
|
|
2903
3153
|
if (rowCount <= TABLE_PREFERRED_MAX_ROWS) {
|
|
3154
|
+
const cellChars = countEmittedCellChars(table, ctx, "table");
|
|
2904
3155
|
return [
|
|
2905
3156
|
{
|
|
2906
3157
|
requires: ["tableBlock"],
|
|
@@ -2915,11 +3166,12 @@ var TableAdapter = class {
|
|
|
2915
3166
|
const dataRows = Math.max(0, rowCount - 1);
|
|
2916
3167
|
if (dataRows <= DATA_TABLE_MAX_DATA_ROWS) {
|
|
2917
3168
|
const preferredTable = truncateRows(table, TABLE_PREFERRED_MAX_ROWS);
|
|
2918
|
-
const preferredChars = countEmittedCellChars(preferredTable, ctx);
|
|
3169
|
+
const preferredChars = countEmittedCellChars(preferredTable, ctx, "table");
|
|
3170
|
+
const dataTableChars = countEmittedCellChars(table, ctx, "data_table");
|
|
2919
3171
|
return [
|
|
2920
3172
|
{
|
|
2921
3173
|
requires: ["dataTable"],
|
|
2922
|
-
budget: { blocks: 1, dataTableChars
|
|
3174
|
+
budget: { blocks: 1, dataTableChars },
|
|
2923
3175
|
emit: (emitCtx) => {
|
|
2924
3176
|
emitCtx.degradations.add({
|
|
2925
3177
|
nodeType: "table",
|
|
@@ -2945,11 +3197,11 @@ var TableAdapter = class {
|
|
|
2945
3197
|
return [buildTableBlock(preferredTable, emitCtx)];
|
|
2946
3198
|
}
|
|
2947
3199
|
},
|
|
2948
|
-
...markdownThenAscii(table,
|
|
3200
|
+
...markdownThenAscii(table, dataTableChars, "native table unavailable")
|
|
2949
3201
|
];
|
|
2950
3202
|
}
|
|
2951
3203
|
const dataChunk = truncateRows(table, DATA_TABLE_MAX_DATA_ROWS + 1);
|
|
2952
|
-
const dataChunkChars = countEmittedCellChars(dataChunk, ctx);
|
|
3204
|
+
const dataChunkChars = countEmittedCellChars(dataChunk, ctx, "data_table");
|
|
2953
3205
|
return [
|
|
2954
3206
|
{
|
|
2955
3207
|
requires: ["dataTable"],
|
|
@@ -2965,10 +3217,37 @@ var TableAdapter = class {
|
|
|
2965
3217
|
return [buildDataTable(dataChunk, emitCtx)];
|
|
2966
3218
|
}
|
|
2967
3219
|
},
|
|
2968
|
-
...markdownThenAscii(table,
|
|
3220
|
+
...markdownThenAscii(table, dataChunkChars, "oversized table")
|
|
2969
3221
|
];
|
|
2970
3222
|
}
|
|
2971
3223
|
};
|
|
3224
|
+
function normalizeTableRows(table, ctx) {
|
|
3225
|
+
const colCount = table.children[0]?.children.length ?? 0;
|
|
3226
|
+
if (colCount === 0 || table.children.every((row) => row.children.length === colCount)) {
|
|
3227
|
+
return table;
|
|
3228
|
+
}
|
|
3229
|
+
const children = table.children.map((row, rowIndex) => {
|
|
3230
|
+
if (row.children.length === colCount) {
|
|
3231
|
+
return row;
|
|
3232
|
+
}
|
|
3233
|
+
if (row.children.length > colCount) {
|
|
3234
|
+
ctx.degradations.add({
|
|
3235
|
+
nodeType: "table",
|
|
3236
|
+
from: `row[${String(rowIndex)}]: ${String(row.children.length)} cells`,
|
|
3237
|
+
to: `${String(colCount)} cells`,
|
|
3238
|
+
reason: "Cells beyond the header column count dropped (GFM ignores the excess)",
|
|
3239
|
+
path: ctx.path
|
|
3240
|
+
});
|
|
3241
|
+
return { ...row, children: row.children.slice(0, colCount) };
|
|
3242
|
+
}
|
|
3243
|
+
const padding = Array.from(
|
|
3244
|
+
{ length: colCount - row.children.length },
|
|
3245
|
+
() => ({ type: "tableCell", children: [] })
|
|
3246
|
+
);
|
|
3247
|
+
return { ...row, children: [...row.children, ...padding] };
|
|
3248
|
+
});
|
|
3249
|
+
return { ...table, children };
|
|
3250
|
+
}
|
|
2972
3251
|
function markdownThenAscii(table, cellChars, reason) {
|
|
2973
3252
|
const md = toPipeMarkdown(table);
|
|
2974
3253
|
return [
|
|
@@ -3014,7 +3293,7 @@ function buildTableBlock(table, ctx) {
|
|
|
3014
3293
|
}
|
|
3015
3294
|
function buildDataTable(table, ctx) {
|
|
3016
3295
|
const captionRaw = ctx.precedingHeading !== void 0 && ctx.precedingHeading.length > 0 ? ctx.precedingHeading : "Table";
|
|
3017
|
-
const caption = captionRaw
|
|
3296
|
+
const caption = sliceSurrogateSafe(captionRaw, 150);
|
|
3018
3297
|
if (captionRaw.length > 150) {
|
|
3019
3298
|
ctx.degradations.add({
|
|
3020
3299
|
nodeType: "table",
|
|
@@ -3025,12 +3304,7 @@ function buildDataTable(table, ctx) {
|
|
|
3025
3304
|
});
|
|
3026
3305
|
}
|
|
3027
3306
|
const rows = table.children.map(
|
|
3028
|
-
(row, rowIndex) => row.children.map((cell) =>
|
|
3029
|
-
if (rowIndex === 0) {
|
|
3030
|
-
return { type: "raw_text", text: toString5(cell) };
|
|
3031
|
-
}
|
|
3032
|
-
return cellToSlack(cell, ctx, false);
|
|
3033
|
-
})
|
|
3307
|
+
(row, rowIndex) => row.children.map((cell) => cellForDataTable(cell, ctx, rowIndex))
|
|
3034
3308
|
);
|
|
3035
3309
|
return {
|
|
3036
3310
|
type: "data_table",
|
|
@@ -3040,25 +3314,31 @@ function buildDataTable(table, ctx) {
|
|
|
3040
3314
|
row_header_column_index: 0
|
|
3041
3315
|
};
|
|
3042
3316
|
}
|
|
3317
|
+
function cellForDataTable(cell, ctx, rowIndex) {
|
|
3318
|
+
if (rowIndex === 0) {
|
|
3319
|
+
return { type: "raw_text", text: toString5(cell) };
|
|
3320
|
+
}
|
|
3321
|
+
return cellToSlack(cell, ctx, false);
|
|
3322
|
+
}
|
|
3043
3323
|
function cellToSlack(cell, ctx, header) {
|
|
3044
|
-
const
|
|
3045
|
-
const
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3324
|
+
const inline = emitPhrasing(cell.children, ctx);
|
|
3325
|
+
const single = inline.elements.length === 1 ? inline.elements[0] : void 0;
|
|
3326
|
+
const isEmpty = inline.elements.length === 0;
|
|
3327
|
+
const isSingleUnstyledText = single?.type === "text" && single.style === void 0;
|
|
3328
|
+
const plainText = isEmpty ? toString5(cell) : isSingleUnstyledText ? single.text : void 0;
|
|
3329
|
+
if (plainText !== void 0) {
|
|
3330
|
+
const trimmed = plainText.trim();
|
|
3331
|
+
if (!header && /^-?\d+(\.\d+)?$/.test(trimmed)) {
|
|
3332
|
+
return { type: "raw_number", value: Number(trimmed), text: trimmed };
|
|
3052
3333
|
}
|
|
3053
|
-
return { type: "raw_text", text:
|
|
3334
|
+
return { type: "raw_text", text: plainText };
|
|
3054
3335
|
}
|
|
3055
|
-
const inline = emitPhrasing(cell.children, ctx);
|
|
3056
3336
|
const rich = {
|
|
3057
3337
|
type: "rich_text",
|
|
3058
3338
|
elements: [
|
|
3059
3339
|
{
|
|
3060
3340
|
type: "rich_text_section",
|
|
3061
|
-
elements: inline.elements
|
|
3341
|
+
elements: inline.elements
|
|
3062
3342
|
}
|
|
3063
3343
|
]
|
|
3064
3344
|
};
|
|
@@ -3085,12 +3365,13 @@ function columnSettings(table) {
|
|
|
3085
3365
|
}
|
|
3086
3366
|
return settings;
|
|
3087
3367
|
}
|
|
3088
|
-
function countEmittedCellChars(table, ctx) {
|
|
3368
|
+
function countEmittedCellChars(table, ctx, mode) {
|
|
3089
3369
|
const probe = ctx.withDegradations(new RecordingDegradationCollector());
|
|
3090
3370
|
let n = 0;
|
|
3091
3371
|
for (const [rowIndex, row] of table.children.entries()) {
|
|
3092
3372
|
for (const cell of row.children) {
|
|
3093
|
-
|
|
3373
|
+
const emitted = mode === "data_table" ? cellForDataTable(cell, probe, rowIndex) : cellToSlack(cell, probe, rowIndex === 0);
|
|
3374
|
+
n += slackCellCharCount(emitted);
|
|
3094
3375
|
}
|
|
3095
3376
|
}
|
|
3096
3377
|
return n;
|
|
@@ -3213,27 +3494,50 @@ function emitUnicodeTaskTree(list, indent, ctx) {
|
|
|
3213
3494
|
});
|
|
3214
3495
|
effectiveIndent = RICH_TEXT_LIST_INDENT_MAX;
|
|
3215
3496
|
}
|
|
3216
|
-
const
|
|
3217
|
-
|
|
3497
|
+
const out = [];
|
|
3498
|
+
let pendingSections = [];
|
|
3499
|
+
const flush = () => {
|
|
3500
|
+
if (pendingSections.length === 0) {
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
out.push({
|
|
3504
|
+
type: "rich_text_list",
|
|
3505
|
+
style: "bullet",
|
|
3506
|
+
elements: pendingSections,
|
|
3507
|
+
indent: effectiveIndent
|
|
3508
|
+
});
|
|
3509
|
+
pendingSections = [];
|
|
3510
|
+
};
|
|
3218
3511
|
for (const item of list.children) {
|
|
3219
3512
|
const prefix = item.checked === true ? "\u2611 " : item.checked === false ? "\u2610 " : "";
|
|
3220
|
-
|
|
3513
|
+
pendingSections.push({
|
|
3221
3514
|
type: "rich_text_section",
|
|
3222
3515
|
elements: [{ type: "text", text: `${prefix}${itemText(item)}` }]
|
|
3223
3516
|
});
|
|
3517
|
+
const childLists = [];
|
|
3224
3518
|
for (const child of item.children) {
|
|
3225
3519
|
if (child.type === "list") {
|
|
3226
|
-
|
|
3520
|
+
childLists.push(child);
|
|
3227
3521
|
}
|
|
3228
3522
|
}
|
|
3523
|
+
if (childLists.length === 0) {
|
|
3524
|
+
continue;
|
|
3525
|
+
}
|
|
3526
|
+
flush();
|
|
3527
|
+
for (const child of childLists) {
|
|
3528
|
+
out.push(...emitUnicodeTaskTree(child, effectiveIndent + 1, ctx));
|
|
3529
|
+
}
|
|
3229
3530
|
}
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3531
|
+
flush();
|
|
3532
|
+
if (out.length === 0) {
|
|
3533
|
+
out.push({
|
|
3534
|
+
type: "rich_text_list",
|
|
3535
|
+
style: "bullet",
|
|
3536
|
+
elements: [{ type: "rich_text_section", elements: [{ type: "text", text: " " }] }],
|
|
3537
|
+
indent: effectiveIndent
|
|
3538
|
+
});
|
|
3539
|
+
}
|
|
3540
|
+
return out;
|
|
3237
3541
|
}
|
|
3238
3542
|
|
|
3239
3543
|
// src/adapters/thematic-break-adapter.ts
|