testomatio-editor-blocks 0.4.76 → 0.4.77

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.
@@ -379,7 +379,20 @@ function serializeBlock(block, ctx, orderedIndex, stepIndex) {
379
379
  return lines;
380
380
  }
381
381
  lines.push(`<!-- ${kind}`);
382
- fields.forEach((field) => lines.push(`${field.key}: ${field.value}`));
382
+ fields.forEach((field) => {
383
+ // List-valued keys (e.g. `issues`) are written back as a YAML list to
384
+ // preserve the backend's format. The single panel field holds the items
385
+ // comma-separated, so split them back out into ` - item` lines.
386
+ if (LIST_META_KEYS.has(field.key.trim().toLowerCase())) {
387
+ const items = field.value.split(",").map((s) => s.trim()).filter(Boolean);
388
+ if (items.length) {
389
+ lines.push(`${field.key}:`);
390
+ items.forEach((item) => lines.push(` - ${item}`));
391
+ return;
392
+ }
393
+ }
394
+ lines.push(`${field.key}: ${field.value}`);
395
+ });
383
396
  lines.push("-->");
384
397
  return lines;
385
398
  }
@@ -1210,12 +1223,26 @@ function parseParagraph(lines, index) {
1210
1223
  };
1211
1224
  }
1212
1225
  const META_COMMENT_OPEN_REGEX = /^<!--\s*(test|suite)(?=\s|-->|$)/i;
1226
+ // Keys whose value is a YAML-style list (`key:` followed by indented `- item`
1227
+ // lines) in the testomat.io comment format — e.g. `issues` holding URLs. These
1228
+ // round-trip back to a list on serialize; everything else stays a flat line.
1229
+ const LIST_META_KEYS = new Set(["issues"]);
1213
1230
  function metaFieldsFromBody(bodyLines) {
1214
1231
  const fields = [];
1215
1232
  for (const raw of bodyLines) {
1216
1233
  const line = raw.trim();
1217
1234
  if (!line)
1218
1235
  continue;
1236
+ // YAML list item: belongs to the most recent `key:` field. The whole item
1237
+ // (e.g. `https://github.com/...`) is kept verbatim — because we catch the
1238
+ // list line before the colon check, URLs with `://` are never split.
1239
+ if (line === "-" || line.startsWith("- ")) {
1240
+ const item = line.slice(1).trim();
1241
+ const current = fields[fields.length - 1];
1242
+ if (current && item)
1243
+ current.items.push(item);
1244
+ continue;
1245
+ }
1219
1246
  const colon = line.indexOf(":");
1220
1247
  // "Each line is `key: value`; lines without `:` are ignored."
1221
1248
  if (colon === -1)
@@ -1224,9 +1251,13 @@ function metaFieldsFromBody(bodyLines) {
1224
1251
  const value = line.slice(colon + 1).trim();
1225
1252
  if (!key)
1226
1253
  continue;
1227
- fields.push({ key, value });
1254
+ fields.push({ key, value, items: [] });
1228
1255
  }
1229
- return fields;
1256
+ // A field with collected list items → value is the items joined by ", ".
1257
+ return fields.map(({ key, value, items }) => ({
1258
+ key,
1259
+ value: items.length ? items.join(", ") : value,
1260
+ }));
1230
1261
  }
1231
1262
  function parseMetaComment(lines, index) {
1232
1263
  const first = lines[index];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testomatio-editor-blocks",
3
- "version": "0.4.76",
3
+ "version": "0.4.77",
4
4
  "description": "Custom BlockNote schema, markdown conversion helpers, and UI for Testomatio-style test cases and steps.",
5
5
  "type": "module",
6
6
  "main": "./package/index.js",
@@ -3223,6 +3223,77 @@ describe("test/suite metadata comments", () => {
3223
3223
  expect(blocksToMarkdown(blocks as CustomEditorBlock[])).toBe(markdown);
3224
3224
  });
3225
3225
 
3226
+ it("parses a YAML-list issues field without splitting URLs on ://", () => {
3227
+ const markdown = [
3228
+ "<!-- test",
3229
+ "id: @T4ffddec3",
3230
+ "type: manual",
3231
+ "issues:",
3232
+ " - https://github.com/testomatio/testomatio/issues/8963",
3233
+ "-->",
3234
+ ].join("\n");
3235
+ const blocks = markdownToBlocks(markdown);
3236
+ expect((blocks[0].props as any).metaFields).toBe(
3237
+ JSON.stringify([
3238
+ { key: "id", value: "@T4ffddec3" },
3239
+ { key: "type", value: "manual" },
3240
+ {
3241
+ key: "issues",
3242
+ value: "https://github.com/testomatio/testomatio/issues/8963",
3243
+ },
3244
+ ]),
3245
+ );
3246
+ });
3247
+
3248
+ it("joins multiple YAML-list issues items with a comma", () => {
3249
+ const markdown = [
3250
+ "<!-- test",
3251
+ "id: @T4ffddec3",
3252
+ "issues:",
3253
+ " - https://github.com/testomatio/testomatio/issues/8963",
3254
+ " - https://github.com/testomatio/testomatio/issues/9001",
3255
+ "-->",
3256
+ ].join("\n");
3257
+ const blocks = markdownToBlocks(markdown);
3258
+ expect((blocks[0].props as any).metaFields).toBe(
3259
+ JSON.stringify([
3260
+ { key: "id", value: "@T4ffddec3" },
3261
+ {
3262
+ key: "issues",
3263
+ value:
3264
+ "https://github.com/testomatio/testomatio/issues/8963, https://github.com/testomatio/testomatio/issues/9001",
3265
+ },
3266
+ ]),
3267
+ );
3268
+ });
3269
+
3270
+ it("round-trips a YAML-list issues field (single item)", () => {
3271
+ const markdown = [
3272
+ "<!-- test",
3273
+ "id: @T4ffddec3",
3274
+ "type: manual",
3275
+ "priority: normal",
3276
+ "issues:",
3277
+ " - https://github.com/testomatio/testomatio/issues/8963",
3278
+ "-->",
3279
+ ].join("\n");
3280
+ const blocks = markdownToBlocks(markdown);
3281
+ expect(blocksToMarkdown(blocks as CustomEditorBlock[])).toBe(markdown);
3282
+ });
3283
+
3284
+ it("round-trips a YAML-list issues field (multiple items)", () => {
3285
+ const markdown = [
3286
+ "<!-- test",
3287
+ "id: @T4ffddec3",
3288
+ "issues:",
3289
+ " - https://github.com/testomatio/testomatio/issues/8963",
3290
+ " - https://github.com/testomatio/testomatio/issues/9001",
3291
+ "-->",
3292
+ ].join("\n");
3293
+ const blocks = markdownToBlocks(markdown);
3294
+ expect(blocksToMarkdown(blocks as CustomEditorBlock[])).toBe(markdown);
3295
+ });
3296
+
3226
3297
  it("ignores lines without a colon inside a metadata block", () => {
3227
3298
  const markdown = [
3228
3299
  "<!-- test",
@@ -451,7 +451,20 @@ function serializeBlock(
451
451
  }
452
452
 
453
453
  lines.push(`<!-- ${kind}`);
454
- fields.forEach((field) => lines.push(`${field.key}: ${field.value}`));
454
+ fields.forEach((field) => {
455
+ // List-valued keys (e.g. `issues`) are written back as a YAML list to
456
+ // preserve the backend's format. The single panel field holds the items
457
+ // comma-separated, so split them back out into ` - item` lines.
458
+ if (LIST_META_KEYS.has(field.key.trim().toLowerCase())) {
459
+ const items = field.value.split(",").map((s) => s.trim()).filter(Boolean);
460
+ if (items.length) {
461
+ lines.push(`${field.key}:`);
462
+ items.forEach((item) => lines.push(` - ${item}`));
463
+ return;
464
+ }
465
+ }
466
+ lines.push(`${field.key}: ${field.value}`);
467
+ });
455
468
  lines.push("-->");
456
469
  return lines;
457
470
  }
@@ -1422,20 +1435,41 @@ function parseParagraph(lines: string[], index: number): { block: CustomPartialB
1422
1435
 
1423
1436
  const META_COMMENT_OPEN_REGEX = /^<!--\s*(test|suite)(?=\s|-->|$)/i;
1424
1437
 
1438
+ // Keys whose value is a YAML-style list (`key:` followed by indented `- item`
1439
+ // lines) in the testomat.io comment format — e.g. `issues` holding URLs. These
1440
+ // round-trip back to a list on serialize; everything else stays a flat line.
1441
+ const LIST_META_KEYS = new Set(["issues"]);
1442
+
1425
1443
  function metaFieldsFromBody(bodyLines: string[]): { key: string; value: string }[] {
1426
- const fields: { key: string; value: string }[] = [];
1444
+ const fields: { key: string; value: string; items: string[] }[] = [];
1427
1445
  for (const raw of bodyLines) {
1428
1446
  const line = raw.trim();
1429
1447
  if (!line) continue;
1448
+
1449
+ // YAML list item: belongs to the most recent `key:` field. The whole item
1450
+ // (e.g. `https://github.com/...`) is kept verbatim — because we catch the
1451
+ // list line before the colon check, URLs with `://` are never split.
1452
+ if (line === "-" || line.startsWith("- ")) {
1453
+ const item = line.slice(1).trim();
1454
+ const current = fields[fields.length - 1];
1455
+ if (current && item) current.items.push(item);
1456
+ continue;
1457
+ }
1458
+
1430
1459
  const colon = line.indexOf(":");
1431
1460
  // "Each line is `key: value`; lines without `:` are ignored."
1432
1461
  if (colon === -1) continue;
1433
1462
  const key = line.slice(0, colon).trim();
1434
1463
  const value = line.slice(colon + 1).trim();
1435
1464
  if (!key) continue;
1436
- fields.push({ key, value });
1465
+ fields.push({ key, value, items: [] });
1437
1466
  }
1438
- return fields;
1467
+
1468
+ // A field with collected list items → value is the items joined by ", ".
1469
+ return fields.map(({ key, value, items }) => ({
1470
+ key,
1471
+ value: items.length ? items.join(", ") : value,
1472
+ }));
1439
1473
  }
1440
1474
 
1441
1475
  function parseMetaComment(