@uniweb/semantic-parser 1.12.1 → 1.12.2
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/package.json +1 -1
- package/src/processors/sequence.js +48 -17
package/package.json
CHANGED
|
@@ -79,7 +79,7 @@ function createSequenceElement(node, options = {}) {
|
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// Check for paragraph containing only multiple links (no other text)
|
|
82
|
-
const multipleLinks = isOnlyLinks(node);
|
|
82
|
+
const multipleLinks = isOnlyLinks(node, options);
|
|
83
83
|
if (multipleLinks && multipleLinks.every((l) => isSafeLink(l.attrs?.href))) {
|
|
84
84
|
return multipleLinks; // Returns array of link elements
|
|
85
85
|
}
|
|
@@ -612,8 +612,20 @@ function processInlineElements(content, options = {}) {
|
|
|
612
612
|
if (!content) return [];
|
|
613
613
|
|
|
614
614
|
const items = [];
|
|
615
|
+
// The link the previous run belongs to, while the runs continue it: a label
|
|
616
|
+
// in several styles (`[the *full* guide](/guide)`) is one link, as its anchor
|
|
617
|
+
// is. ⛔ Until 2026-10-19 each run was a link here, so `content.links` held
|
|
618
|
+
// "the ", "full" and " guide".
|
|
619
|
+
let open = null;
|
|
615
620
|
|
|
616
621
|
for (const item of content) {
|
|
622
|
+
const runLink = item.type === "text" ? linkMarkOf(item.marks) : null;
|
|
623
|
+
if (runLink && open && sameLink(open.mark, runLink)) {
|
|
624
|
+
open.link.attrs.label += item.text || "";
|
|
625
|
+
continue;
|
|
626
|
+
}
|
|
627
|
+
open = null;
|
|
628
|
+
|
|
617
629
|
if (isIconNode(item)) {
|
|
618
630
|
items.push({
|
|
619
631
|
type: "icon",
|
|
@@ -651,18 +663,17 @@ function processInlineElements(content, options = {}) {
|
|
|
651
663
|
refId: item.attrs?.refId,
|
|
652
664
|
embedKind: item.attrs?.embedKind || "visual",
|
|
653
665
|
});
|
|
654
|
-
} else if (
|
|
666
|
+
} else if (runLink && isSafeLink(runLink.attrs?.href)) {
|
|
655
667
|
// Extract links from text nodes with link marks
|
|
656
|
-
const
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
}
|
|
668
|
+
const link = {
|
|
669
|
+
type: "link",
|
|
670
|
+
attrs: {
|
|
671
|
+
...runLink.attrs, // Preserve all link attributes (role, target, etc.)
|
|
672
|
+
label: item.text || "",
|
|
673
|
+
},
|
|
674
|
+
};
|
|
675
|
+
items.push(link);
|
|
676
|
+
open = { mark: runLink, link };
|
|
666
677
|
}
|
|
667
678
|
}
|
|
668
679
|
|
|
@@ -1045,9 +1056,10 @@ function isLink(item, options = {}) {
|
|
|
1045
1056
|
* Markdown treats these as a single paragraph, but semantically they're separate links.
|
|
1046
1057
|
*
|
|
1047
1058
|
* @param {Object} item - Sequence item (paragraph)
|
|
1059
|
+
* @param {Object} [options] - Parse options, for the one-link case's `children`
|
|
1048
1060
|
* @returns {Array|false} Array of link objects or false
|
|
1049
1061
|
*/
|
|
1050
|
-
function isOnlyLinks(item) {
|
|
1062
|
+
function isOnlyLinks(item, options = {}) {
|
|
1051
1063
|
if (item.type !== "paragraph") return false;
|
|
1052
1064
|
|
|
1053
1065
|
const content = item?.content || [];
|
|
@@ -1076,22 +1088,41 @@ function isOnlyLinks(item) {
|
|
|
1076
1088
|
// break becomes, an icon — keeps them apart. ⛔ Until 2026-10-19 every run
|
|
1077
1089
|
// was a link of its own, so a button labelled in two styles became two
|
|
1078
1090
|
// buttons, "Go" and " now".
|
|
1079
|
-
// Icons in this paragraph go to body.icons separately (no association)
|
|
1080
1091
|
const groups = [];
|
|
1081
1092
|
let current = null;
|
|
1082
|
-
|
|
1093
|
+
content.forEach((c, i) => {
|
|
1083
1094
|
const mark = c.type === "text" ? linkMarkOf(c.marks) : null;
|
|
1084
1095
|
if (mark && current && sameLink(current.mark, mark)) {
|
|
1085
1096
|
current.label += c.text || "";
|
|
1097
|
+
current.last = i;
|
|
1086
1098
|
} else if (mark) {
|
|
1087
|
-
current = { mark, label: c.text || "" };
|
|
1099
|
+
current = { mark, label: c.text || "", first: i, last: i };
|
|
1088
1100
|
groups.push(current);
|
|
1089
1101
|
} else {
|
|
1090
1102
|
current = null;
|
|
1091
1103
|
}
|
|
1104
|
+
});
|
|
1105
|
+
|
|
1106
|
+
// One link in several runs is a paragraph that is just a link, and takes the
|
|
1107
|
+
// shape `isLink` gives one — its icons, the last before it and the first
|
|
1108
|
+
// after, and its inline elements. ⛔ Until 2026-10-19 its icons were dropped:
|
|
1109
|
+
// ` [**Go** now](/go){button}` lost the star.
|
|
1110
|
+
if (groups.length === 1) {
|
|
1111
|
+
const [{ mark, label, first, last }] = groups;
|
|
1112
|
+
const icons = content.map((c, i) => (isIconNode(c) ? { i, attrs: parseIcon(c.attrs) } : null)).filter(Boolean);
|
|
1113
|
+
return [{
|
|
1114
|
+
type: "link",
|
|
1115
|
+
attrs: {
|
|
1116
|
+
...mark?.attrs,
|
|
1117
|
+
label,
|
|
1118
|
+
iconBefore: icons.filter(({ i }) => i < first).pop()?.attrs || null,
|
|
1119
|
+
iconAfter: icons.find(({ i }) => i > last)?.attrs || null,
|
|
1120
|
+
children: processInlineElements(content, options),
|
|
1121
|
+
},
|
|
1122
|
+
}];
|
|
1092
1123
|
}
|
|
1093
1124
|
|
|
1094
|
-
//
|
|
1125
|
+
// Several links. An icon among them belongs to no one link, and is not carried.
|
|
1095
1126
|
return groups.map(({ mark, label }) => ({
|
|
1096
1127
|
type: "link",
|
|
1097
1128
|
attrs: {
|