@uniweb/semantic-parser 1.6.0 → 1.7.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/README.md +5 -4
- package/package.json +1 -1
- package/src/builders/doc.js +8 -4
- package/src/processors/sequence.js +26 -33
package/README.md
CHANGED
|
@@ -74,8 +74,8 @@ result = {
|
|
|
74
74
|
// Body fields
|
|
75
75
|
paragraphs: ["Get started today."],
|
|
76
76
|
links: [], // All links (including buttons)
|
|
77
|
-
images: [],
|
|
78
|
-
videos: [],
|
|
77
|
+
images: [], // { url, alt, caption, role, placement?, author?, … }
|
|
78
|
+
videos: [], // { src, poster?, caption, placement?, … }
|
|
79
79
|
documents: [], // Files marked {role=pdf} — { url, name, mime, size?, alt,
|
|
80
80
|
// caption, preview?, … }
|
|
81
81
|
icons: [],
|
|
@@ -87,7 +87,8 @@ result = {
|
|
|
87
87
|
snippets: [], // Fenced code blocks — { language, code }
|
|
88
88
|
data: {}, // Structured data (tagged data blocks, forms, cards)
|
|
89
89
|
headings: [], // Only from nested content (quote/list bodies)
|
|
90
|
-
// tables: [], // Only when the content has one — { rows, attrs }
|
|
90
|
+
// tables: [], // Only when the content has one — { rows, attrs } — attrs:
|
|
91
|
+
// caption, id, placement, from its caption line
|
|
91
92
|
// math: [], // Only when the content has one — { id, latex, mathml }
|
|
92
93
|
|
|
93
94
|
// Additional content groups (from headings after content)
|
|
@@ -116,7 +117,7 @@ const content = parseContent(doc);
|
|
|
116
117
|
|
|
117
118
|
const title = content.title;
|
|
118
119
|
const description = content.paragraphs.join(" ");
|
|
119
|
-
const image = content.images[0]?.
|
|
120
|
+
const image = content.images[0]?.url;
|
|
120
121
|
```
|
|
121
122
|
|
|
122
123
|
### Processing Content Sections
|
package/package.json
CHANGED
package/src/builders/doc.js
CHANGED
|
@@ -103,12 +103,16 @@ function linkParagraph({ text, label, href, target }) {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
function imageBlock({ src, url, alt = '', caption = '',
|
|
106
|
+
function imageBlock({ src, url, alt = '', caption = '', placement, role, width, height }) {
|
|
107
107
|
// The node attr is `url` and so is the parsed field; `src` is this builder's
|
|
108
108
|
// original spelling. Either one in, `url` out.
|
|
109
109
|
const attrs = { url: src || url, alt }
|
|
110
110
|
if (caption) attrs.caption = caption
|
|
111
|
-
|
|
111
|
+
// The parsed field's own word, so parseContent(buildDoc(x)) keeps it. The
|
|
112
|
+
// editor's node calls it `direction` and drops an attr it does not declare,
|
|
113
|
+
// so the editor reads none until it saves the vocabulary; no starter content
|
|
114
|
+
// sets one. ⛔ Until 2026-10-15 this took and wrote `direction`.
|
|
115
|
+
if (placement) attrs.placement = placement
|
|
112
116
|
if (role) attrs.role = role
|
|
113
117
|
if (width && height) {
|
|
114
118
|
attrs.aspect_ratio = { width, height, ratio: (height / width) * 100 }
|
|
@@ -153,10 +157,10 @@ function iconNode({ src, url, svg, library, name, size, color }) {
|
|
|
153
157
|
return { type: 'UniwebIcon', attrs }
|
|
154
158
|
}
|
|
155
159
|
|
|
156
|
-
function videoNode({ src, url, caption,
|
|
160
|
+
function videoNode({ src, url, caption, placement, coverImg }) {
|
|
157
161
|
const attrs = { src: src || url }
|
|
158
162
|
if (caption) attrs.caption = caption
|
|
159
|
-
if (
|
|
163
|
+
if (placement) attrs.placement = placement // as an image's, above
|
|
160
164
|
// ⛔ The editor's `Video` node holds `coverImg` as an OBJECT — the reader is
|
|
161
165
|
// `makeAssetUrl`, which looks for `.src` / `.url` / `.identifier`. A bare
|
|
162
166
|
// string passed straight through parses back as "": `info?.src` on a string
|
|
@@ -861,8 +861,8 @@ function parseCardBlock(itemAttrs) {
|
|
|
861
861
|
//
|
|
862
862
|
// Read through `parseImgBlock`, which resolves the address and the preview's the
|
|
863
863
|
// way every image's are, and then narrowed to what a document IS: where the file
|
|
864
|
-
// is, what it is called, and the resource's own metadata.
|
|
865
|
-
//
|
|
864
|
+
// is, what it is called, and the resource's own metadata. Where a picture sits
|
|
865
|
+
// in a flow (`placement`) is not a file's, and is left out.
|
|
866
866
|
function parseMarkdownDocument(itemAttrs, options) {
|
|
867
867
|
const { url, alt, caption, role, href, target, id, preview, author, description } =
|
|
868
868
|
parseImgBlock(itemAttrs || {}, options);
|
|
@@ -1016,47 +1016,47 @@ function parseImgBlock(itemAttrs, options) {
|
|
|
1016
1016
|
info: imgInfo,
|
|
1017
1017
|
targetId,
|
|
1018
1018
|
caption = "",
|
|
1019
|
-
direction,
|
|
1020
|
-
filter,
|
|
1021
1019
|
alt = "",
|
|
1022
1020
|
src,
|
|
1023
1021
|
url,
|
|
1024
1022
|
href = "",
|
|
1025
1023
|
target = "",
|
|
1026
|
-
theme,
|
|
1027
1024
|
role,
|
|
1028
|
-
credit
|
|
1025
|
+
credit, // the editor's word for `author` — delivered as `author`
|
|
1029
1026
|
id, // {#fig-id} cross-reference label — preserved so Press
|
|
1030
1027
|
// adapters can emit \label{id} (LaTeX) / <id> (Typst).
|
|
1031
1028
|
// ── Markdown-authored attributes ────────────────────────────────
|
|
1032
1029
|
// This function was written for the EDITOR's `ImageBlock` node and
|
|
1033
1030
|
// later reused for the markdown `image` node (see `case "image"`), so
|
|
1034
|
-
// its vocabulary
|
|
1035
|
-
//
|
|
1036
|
-
//
|
|
1037
|
-
//
|
|
1038
|
-
//
|
|
1039
|
-
//
|
|
1040
|
-
//
|
|
1031
|
+
// its vocabulary was the editor's. Everything markdown declares and
|
|
1032
|
+
// the editor does not was therefore tokenized, declared, and then
|
|
1033
|
+
// dropped one layer before delivery — the published "Image
|
|
1034
|
+
// Attributes" table (docs/reference/content-structure.md) reached no
|
|
1035
|
+
// component, and neither did the `role=pdf` set added 2026-07-29 for
|
|
1036
|
+
// the editor's `document` fold-in. Carried 2026-07-30.
|
|
1037
|
+
//
|
|
1038
|
+
// ⭐ An element now holds the vocabulary's words, whichever node it
|
|
1039
|
+
// came from. ⛔ Until 2026-10-15 it also held the editor's `direction`
|
|
1040
|
+
// and two things derived from it — `imgPos` (left/right) and a
|
|
1041
|
+
// layout `size` (basic/lg/full, `basic` for every image without one) —
|
|
1042
|
+
// plus `filter` and `theme`, none of which a stored document holds. A
|
|
1043
|
+
// component handing the element to kit's <Image> passed that `size` as
|
|
1044
|
+
// Image's avatar preset, so a "wide" image drew as a 96px square.
|
|
1041
1045
|
width,
|
|
1042
1046
|
height,
|
|
1043
1047
|
loading,
|
|
1044
1048
|
fit,
|
|
1045
1049
|
position,
|
|
1050
|
+
placement, // where it sits in a flow: left, right, wide, full
|
|
1046
1051
|
preview, // role=pdf — the preview image
|
|
1047
|
-
author, // role=pdf
|
|
1052
|
+
author, // the image's attribution; for role=pdf, the resource's
|
|
1048
1053
|
description, // role=pdf — describes the RESOURCE, not the image (≠ alt)
|
|
1049
1054
|
} = itemAttrs;
|
|
1050
1055
|
|
|
1051
1056
|
let { contentType, viewType, contentId, identifier } = imgInfo || {};
|
|
1052
1057
|
|
|
1053
|
-
const sizes = {
|
|
1054
|
-
center: "basic",
|
|
1055
|
-
wide: "lg",
|
|
1056
|
-
fill: "full",
|
|
1057
|
-
};
|
|
1058
|
-
|
|
1059
1058
|
caption = stripTags(caption);
|
|
1059
|
+
const attribution = author || credit;
|
|
1060
1060
|
|
|
1061
1061
|
// Reference precedence. Standard ProseMirror `image` nodes use `src`; the
|
|
1062
1062
|
// custom `ImageBlock` node uses `url`. Honor either so callers don't have to
|
|
@@ -1088,19 +1088,9 @@ function parseImgBlock(itemAttrs, options) {
|
|
|
1088
1088
|
value: identifier || "",
|
|
1089
1089
|
alt: alt || caption,
|
|
1090
1090
|
caption,
|
|
1091
|
-
direction,
|
|
1092
|
-
filter,
|
|
1093
|
-
imgPos: direction === "left" || direction === "right" ? direction : "",
|
|
1094
|
-
// NOTE: `size` here is the direction-derived LAYOUT size
|
|
1095
|
-
// (basic/lg/full), not the author's `{size=…}` — that attribute is
|
|
1096
|
-
// icon-only and is read by parseUniwebIcon. Do not wire `{size=…}`
|
|
1097
|
-
// through here; the two meanings collide on one key.
|
|
1098
|
-
size: sizes[direction] || "basic",
|
|
1099
1091
|
href,
|
|
1100
1092
|
target,
|
|
1101
|
-
theme,
|
|
1102
1093
|
role,
|
|
1103
|
-
credit,
|
|
1104
1094
|
id: id || undefined,
|
|
1105
1095
|
// Omitted when absent, so an existing consumer sees no new empty keys.
|
|
1106
1096
|
...(width !== undefined && width !== null && { width }),
|
|
@@ -1108,12 +1098,13 @@ function parseImgBlock(itemAttrs, options) {
|
|
|
1108
1098
|
...(loading && { loading }),
|
|
1109
1099
|
...(fit && { fit }),
|
|
1110
1100
|
...(position && { position }),
|
|
1101
|
+
...(placement && { placement }),
|
|
1111
1102
|
...((() => {
|
|
1112
1103
|
// Same rule for a document's preview image.
|
|
1113
1104
|
const p = secondaryAssetUrl(itemAttrs, options, "preview");
|
|
1114
1105
|
return p ? { preview: p } : {};
|
|
1115
1106
|
})()),
|
|
1116
|
-
...(
|
|
1107
|
+
...(attribution && { author: attribution }),
|
|
1117
1108
|
...(description && { description }),
|
|
1118
1109
|
};
|
|
1119
1110
|
}
|
|
@@ -1142,6 +1133,7 @@ function parseMarkdownVideo(itemAttrs, options) {
|
|
|
1142
1133
|
target = "",
|
|
1143
1134
|
role,
|
|
1144
1135
|
id, // {#fig-id} cross-reference label, same as parseImgBlock
|
|
1136
|
+
placement, // where it sits in a flow, same as parseImgBlock
|
|
1145
1137
|
} = itemAttrs || {};
|
|
1146
1138
|
|
|
1147
1139
|
// Reference precedence, now genuinely identical to parseImgBlock: a
|
|
@@ -1175,6 +1167,7 @@ function parseMarkdownVideo(itemAttrs, options) {
|
|
|
1175
1167
|
if (loop !== undefined) video.loop = loop;
|
|
1176
1168
|
if (controls !== undefined) video.controls = controls;
|
|
1177
1169
|
if (id) video.id = id;
|
|
1170
|
+
if (placement) video.placement = placement;
|
|
1178
1171
|
|
|
1179
1172
|
return video;
|
|
1180
1173
|
}
|
|
@@ -1183,12 +1176,12 @@ function parseVideoBlock(itemAttrs, options) {
|
|
|
1183
1176
|
let {
|
|
1184
1177
|
src,
|
|
1185
1178
|
caption = "",
|
|
1186
|
-
direction,
|
|
1187
1179
|
info = {},
|
|
1188
1180
|
coverImg = {},
|
|
1189
1181
|
alt,
|
|
1190
1182
|
href = "",
|
|
1191
1183
|
target = "",
|
|
1184
|
+
placement, // where it sits in a flow; the editor's `direction` is not read
|
|
1192
1185
|
} = itemAttrs;
|
|
1193
1186
|
|
|
1194
1187
|
// Same precedence as parseImgBlock / parseMarkdownVideo: a resolvable
|
|
@@ -1198,11 +1191,11 @@ function parseVideoBlock(itemAttrs, options) {
|
|
|
1198
1191
|
return {
|
|
1199
1192
|
src: video,
|
|
1200
1193
|
caption,
|
|
1201
|
-
direction,
|
|
1202
1194
|
coverImg: makeAssetUrl(coverImg),
|
|
1203
1195
|
alt,
|
|
1204
1196
|
href,
|
|
1205
1197
|
target,
|
|
1198
|
+
...(placement && { placement }),
|
|
1206
1199
|
};
|
|
1207
1200
|
}
|
|
1208
1201
|
|