testomatio-editor-blocks 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.
@@ -141,6 +141,24 @@ function inlineToMarkdown(content) {
141
141
  })
142
142
  .join("");
143
143
  }
144
+ function inlineContentToPlainText(content) {
145
+ if (!Array.isArray(content)) {
146
+ return "";
147
+ }
148
+ return content
149
+ .map((node) => {
150
+ if (node && typeof node === "object") {
151
+ if (typeof node.text === "string") {
152
+ return node.text;
153
+ }
154
+ if (Array.isArray(node.content)) {
155
+ return inlineContentToPlainText(node.content);
156
+ }
157
+ }
158
+ return "";
159
+ })
160
+ .join("");
161
+ }
144
162
  function serializeChildren(block, ctx) {
145
163
  var _a;
146
164
  if (!((_a = block.children) === null || _a === void 0 ? void 0 : _a.length)) {
@@ -534,7 +552,7 @@ function countIndent(line) {
534
552
  const match = line.match(/^ */);
535
553
  return match ? match[0].length : 0;
536
554
  }
537
- function parseList(lines, startIndex, listType, indentLevel) {
555
+ function parseList(lines, startIndex, listType, indentLevel, allowEmptySteps = false) {
538
556
  var _a, _b, _c, _d;
539
557
  const items = [];
540
558
  let index = startIndex;
@@ -546,14 +564,13 @@ function parseList(lines, startIndex, listType, indentLevel) {
546
564
  continue;
547
565
  }
548
566
  let indent = countIndent(rawLine);
549
- const baseIndent = indentLevel * 2;
550
- if (indent > baseIndent && indent <= baseIndent + 1) {
551
- indent = baseIndent;
552
- }
553
567
  if (indent < indentLevel * 2) {
554
568
  break;
555
569
  }
556
- if (indent > indentLevel * 2) {
570
+ // Check if this line should be parsed as nested content
571
+ // Only go deeper if indent is at least 2 more than the next level's expected indent
572
+ const nextLevelExpectedIndent = (indentLevel + 1) * 2;
573
+ if (indent >= nextLevelExpectedIndent) {
557
574
  const lastItem = items.at(-1);
558
575
  if (!lastItem) {
559
576
  break;
@@ -562,7 +579,12 @@ function parseList(lines, startIndex, listType, indentLevel) {
562
579
  if (!nestedType) {
563
580
  break;
564
581
  }
565
- const nested = parseList(lines, index, nestedType, indentLevel + 1);
582
+ const nested = parseList(lines, index, nestedType, indentLevel + 1, allowEmptySteps);
583
+ // If nested parsing made no progress, skip this line to avoid infinite loop
584
+ if (nested.nextIndex === index) {
585
+ index += 1;
586
+ continue;
587
+ }
566
588
  lastItem.children = [...((_a = lastItem.children) !== null && _a !== void 0 ? _a : []), ...nested.items];
567
589
  index = nested.nextIndex;
568
590
  continue;
@@ -571,6 +593,16 @@ function parseList(lines, startIndex, listType, indentLevel) {
571
593
  if (detectedType !== listType) {
572
594
  break;
573
595
  }
596
+ // Only try to parse as testStep for top-level bullet items (indentLevel === 0)
597
+ // Nested bullets within numbered lists should remain as regular bulletListItem
598
+ if (listType === "bullet" && indentLevel === 0) {
599
+ const nextStep = parseTestStep(lines, index, allowEmptySteps);
600
+ if (nextStep) {
601
+ items.push(nextStep.block);
602
+ index = nextStep.nextIndex;
603
+ continue;
604
+ }
605
+ }
574
606
  if (listType === "check") {
575
607
  const checkMatch = trimmed.match(/^[-*+]\s+\[([xX\s])\]\s+(.*)$/);
576
608
  const checked = ((_b = checkMatch === null || checkMatch === void 0 ? void 0 : checkMatch[1]) !== null && _b !== void 0 ? _b : "").toLowerCase() === "x";
@@ -607,7 +639,7 @@ function parseList(lines, startIndex, listType, indentLevel) {
607
639
  }
608
640
  return { items, nextIndex: index };
609
641
  }
610
- function parseTestStep(lines, index, snippetId) {
642
+ function parseTestStep(lines, index, allowEmpty = false, snippetId) {
611
643
  const current = lines[index];
612
644
  const trimmed = current.trim();
613
645
  if (!trimmed.startsWith("* ") && !trimmed.startsWith("- ")) {
@@ -635,13 +667,19 @@ function parseTestStep(lines, index, snippetId) {
635
667
  let expectedResult = "";
636
668
  let next = index + 1;
637
669
  let inExpectedResult = false;
670
+ let foundFirstExpected = false;
638
671
  while (next < lines.length) {
639
672
  const line = lines[next];
640
673
  const hasIndent = /^\s{2,}/.test(line);
641
674
  const rawTrimmed = line.trim();
642
675
  if (!rawTrimmed) {
643
- if (stepDataLines.length > 0) {
644
- stepDataLines.push("");
676
+ if (stepDataLines.length > 0 || inExpectedResult) {
677
+ if (inExpectedResult) {
678
+ expectedResult += "\n";
679
+ }
680
+ else {
681
+ stepDataLines.push("");
682
+ }
645
683
  }
646
684
  next += 1;
647
685
  continue;
@@ -658,20 +696,68 @@ function parseTestStep(lines, index, snippetId) {
658
696
  rawTrimmed.startsWith("|")) {
659
697
  break;
660
698
  }
661
- if (rawTrimmed.match(EXPECTED_LABEL_REGEX)) {
699
+ // Check for expected result labels with different formatting
700
+ const expectedMatch = rawTrimmed.match(EXPECTED_LABEL_REGEX);
701
+ const expectedStarMatch = rawTrimmed.match(/^\*expected\s*\*:\s*(.*)$/i) ||
702
+ rawTrimmed.match(/^\*expected\*:\s*(.*)$/i);
703
+ if (expectedMatch || expectedStarMatch) {
704
+ foundFirstExpected = true;
705
+ inExpectedResult = true;
706
+ const label = expectedMatch ? expectedMatch[0] : (expectedStarMatch ? expectedStarMatch[0] : '');
707
+ let content = rawTrimmed.slice(label.length).trim();
708
+ // Add the content (if any) from this line
709
+ if (content) {
710
+ const expectedContent = unescapeMarkdown(content);
711
+ if (expectedResult.length > 0) {
712
+ expectedResult += "\n" + expectedContent;
713
+ }
714
+ else {
715
+ expectedResult = expectedContent;
716
+ }
717
+ }
718
+ next += 1;
719
+ continue;
720
+ }
721
+ // Check for lines that start with * and contain Expected (but don't match the above patterns)
722
+ if (rawTrimmed.match(/^\*[^*]*expected/i)) {
723
+ foundFirstExpected = true;
662
724
  inExpectedResult = true;
663
- const withoutLabel = stripExpectedPrefix(rawTrimmed);
664
- expectedResult = unescapeMarkdown(withoutLabel);
725
+ // Remove the leading * and trim
726
+ let content = rawTrimmed.slice(1).trim();
727
+ // Remove any "Expected:" prefix
728
+ content = content.replace(/^expected\s*:?\s*/i, '').trim();
729
+ const expectedContent = unescapeMarkdown(content);
730
+ if (expectedResult.length > 0) {
731
+ expectedResult += "\n" + expectedContent;
732
+ }
733
+ else {
734
+ expectedResult = expectedContent;
735
+ }
665
736
  next += 1;
666
737
  continue;
667
738
  }
668
739
  if (rawTrimmed.startsWith("```")) {
669
- stepDataLines.push(unescapeMarkdown(rawTrimmed));
740
+ if (inExpectedResult) {
741
+ if (expectedResult.length > 0) {
742
+ expectedResult += "\n" + unescapeMarkdown(rawTrimmed);
743
+ }
744
+ else {
745
+ expectedResult = unescapeMarkdown(rawTrimmed);
746
+ }
747
+ }
748
+ else {
749
+ stepDataLines.push(unescapeMarkdown(rawTrimmed));
750
+ }
670
751
  next += 1;
671
752
  while (next < lines.length) {
672
753
  const fenceLine = lines[next];
673
754
  const fenceTrimmed = fenceLine.trim();
674
- stepDataLines.push(unescapeMarkdown(fenceTrimmed));
755
+ if (inExpectedResult) {
756
+ expectedResult += "\n" + unescapeMarkdown(fenceTrimmed);
757
+ }
758
+ else {
759
+ stepDataLines.push(unescapeMarkdown(fenceTrimmed));
760
+ }
675
761
  next += 1;
676
762
  if (fenceTrimmed.startsWith("```")) {
677
763
  break;
@@ -680,8 +766,27 @@ function parseTestStep(lines, index, snippetId) {
680
766
  continue;
681
767
  }
682
768
  if (inExpectedResult) {
683
- const withoutLabel = stripExpectedPrefix(rawTrimmed);
684
- expectedResult += "\n" + unescapeMarkdown(withoutLabel);
769
+ // After finding the first expected result, indented lines are part of it
770
+ if (hasIndent) {
771
+ const expectedContent = unescapeMarkdown(rawTrimmed);
772
+ if (expectedResult.length > 0) {
773
+ expectedResult += "\n" + expectedContent;
774
+ }
775
+ else {
776
+ expectedResult = expectedContent;
777
+ }
778
+ }
779
+ else if (foundFirstExpected && rawTrimmed.startsWith("*") && !rawTrimmed.startsWith("* ")) {
780
+ // Non-indented lines starting with single * (not list item) are likely more expected results
781
+ // Remove the leading * and treat the rest as content
782
+ const expectedContent = unescapeMarkdown(rawTrimmed.slice(1).trim());
783
+ if (expectedResult.length > 0) {
784
+ expectedResult += "\n" + expectedContent;
785
+ }
786
+ else {
787
+ expectedResult = expectedContent;
788
+ }
789
+ }
685
790
  next += 1;
686
791
  continue;
687
792
  }
@@ -691,13 +796,23 @@ function parseTestStep(lines, index, snippetId) {
691
796
  next += 1;
692
797
  continue;
693
798
  }
799
+ // If we have indent and the line doesn't match other patterns, treat it as step data
800
+ if (hasIndent) {
801
+ const content = unescapeMarkdown(rawTrimmed);
802
+ stepDataLines.push(content);
803
+ next += 1;
804
+ continue;
805
+ }
694
806
  break;
695
807
  }
696
808
  const stepData = stepDataLines
697
809
  .map((line) => line.trimEnd())
698
810
  .join("\n")
699
811
  .trim();
700
- if (!isLikelyStep && !expectedResult && stepDataLines.length === 0) {
812
+ if (!isLikelyStep &&
813
+ !expectedResult &&
814
+ stepDataLines.length === 0 &&
815
+ !(allowEmpty && titleWithPlaceholders.length > 0)) {
701
816
  return null;
702
817
  }
703
818
  const stepDataWithImages = [stepData, titleImages.join("\n")]
@@ -900,10 +1015,12 @@ function parseSnippetWrapper(lines, index) {
900
1015
  };
901
1016
  }
902
1017
  export function markdownToBlocks(markdown) {
1018
+ var _a, _b;
903
1019
  const normalized = markdown.replace(/\r\n/g, "\n");
904
1020
  const lines = normalized.split("\n");
905
1021
  const blocks = [];
906
1022
  let index = 0;
1023
+ let stepsHeadingLevel = null;
907
1024
  while (index < lines.length) {
908
1025
  const line = lines[index];
909
1026
  if (!line.trim()) {
@@ -916,7 +1033,7 @@ export function markdownToBlocks(markdown) {
916
1033
  index = snippetWrapper.nextIndex;
917
1034
  continue;
918
1035
  }
919
- const stepLikeBlock = parseTestStep(lines, index);
1036
+ const stepLikeBlock = parseTestStep(lines, index, stepsHeadingLevel !== null);
920
1037
  if (stepLikeBlock) {
921
1038
  blocks.push(stepLikeBlock.block);
922
1039
  index = stepLikeBlock.nextIndex;
@@ -930,7 +1047,19 @@ export function markdownToBlocks(markdown) {
930
1047
  }
931
1048
  const heading = parseHeading(lines, index);
932
1049
  if (heading) {
933
- blocks.push(heading.block);
1050
+ const headingBlock = heading.block;
1051
+ const headingLevel = (_b = (_a = headingBlock.props) === null || _a === void 0 ? void 0 : _a.level) !== null && _b !== void 0 ? _b : 3;
1052
+ const headingText = inlineContentToPlainText(headingBlock.content);
1053
+ const normalizedHeading = headingText.trim().toLowerCase();
1054
+ if (normalizedHeading === "steps") {
1055
+ stepsHeadingLevel = headingLevel;
1056
+ }
1057
+ else if (stepsHeadingLevel !== null &&
1058
+ headingLevel <= stepsHeadingLevel &&
1059
+ normalizedHeading.length > 0) {
1060
+ stepsHeadingLevel = null;
1061
+ }
1062
+ blocks.push(headingBlock);
934
1063
  index = heading.nextIndex;
935
1064
  continue;
936
1065
  }
@@ -948,7 +1077,7 @@ export function markdownToBlocks(markdown) {
948
1077
  }
949
1078
  const listType = detectListType(line.trim());
950
1079
  if (listType) {
951
- const { items, nextIndex } = parseList(lines, index, listType, 0);
1080
+ const { items, nextIndex } = parseList(lines, index, listType, 0, stepsHeadingLevel !== null);
952
1081
  blocks.push(...items);
953
1082
  index = nextIndex;
954
1083
  continue;