@wix/web5-core 1.63.31 → 1.63.32

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.
@@ -25,7 +25,21 @@ function isBlankCell(raw) {
25
25
  class ComparisonSectionDefinition {
26
26
  constructor() {
27
27
  (0, _defineProperty2.default)(this, "sectionType", 'comparison');
28
- (0, _defineProperty2.default)(this, "patterns", ['html_comment[section^="comparison"] > (h2 | h3 | h4 | t) > html_comment? > t* > table > (t | link)?']);
28
+ // The pre-table slot is the description paragraph, so it has to admit
29
+ // `link`: `convertToBlockElements` unwraps a paragraph into its inline
30
+ // nodes, so `Questions? Email support@shop.example for help.` arrives as
31
+ // `t link t` — GFM autolinks a bare email, no author required — and an
32
+ // authored `[men's shoes](web5://ask/…)` does the same. With `t*` the run
33
+ // ended at that `link`, the whole pattern failed, and the section never
34
+ // reached `parse()`: the heading and prose were claimed by `textBlock` and
35
+ // the TABLE fell to `FallbackSectionDefinition`, whose `partsToMarkdown`
36
+ // has no `table` branch — so it rendered as an empty section and the
37
+ // comparison silently vanished.
38
+ //
39
+ // The trailing slot stays `(t | link)?`: it is the CTA, and `parse()` reads
40
+ // it positionally (see `ctaText` below). Widening it would let the section
41
+ // swallow a paragraph belonging to whatever follows.
42
+ (0, _defineProperty2.default)(this, "patterns", ['html_comment[section^="comparison"] > (h2 | h3 | h4 | t) > html_comment? > (t | link)* > table > (t | link)?']);
29
43
  (0, _defineProperty2.default)(this, "defaults", {
30
44
  title: 'Comparison',
31
45
  columnLabels: ['Option A', 'Option B'],
@@ -133,8 +147,11 @@ See how our platform stacks up against the competition.
133
147
  }));
134
148
  }
135
149
 
136
- // Extract CTA from link parts
137
- const link = (0, _parseUtils.firstLink)(parts);
150
+ // The CTA is the link AFTER the table, not merely the first link in the
151
+ // section the description may now carry its own inline links, and
152
+ // `firstLink(parts)` would promote one of those to the CTA button.
153
+ const lastTableIndex = parts.map(p => p.type).lastIndexOf('table');
154
+ const link = (0, _parseUtils.firstLink)(lastTableIndex >= 0 ? parts.slice(lastTableIndex + 1) : parts);
138
155
  const ctaText = (link == null ? void 0 : link.text) || undefined;
139
156
  const ctaHref = (link == null ? void 0 : link.href) || undefined;
140
157
 
@@ -1 +1 @@
1
- {"version":3,"names":["_parseUtils","require","_parts","_sectionDefinition","_diagnosticTypes","isBlankCell","raw","v","trim","toLowerCase","test","ComparisonSectionDefinition","constructor","_defineProperty2","default","title","columnLabels","rows","feature","values","markdown","expected","featureColumnLabel","description","ctaText","ctaHref","parse","parts","context","_tableParts$","headingText","proseBodyMarkdown","undefined","tableParts","getPartsByType","tableMeta","meta","columns","rawValueRows","map","row","iconHint","parseTableValue","allHeaders","headers","rawRows","slice","label","link","firstLink","text","href","keptRow","some","filteredRows","filter","_","i","filteredRawRows","droppedCount","length","reportDiagnostic","DIAGNOSTIC_TYPES","ITEMS_DROPPED","blankColumns","col","every","SECTION_REJECTED","c","join","DROP_SECTION","exports"],"sources":["../../../../src/component/componentDefinitions/ComparisonSectionDefinition.ts"],"sourcesContent":["import {\n headingText,\n proseBodyMarkdown,\n firstLink,\n parseTableValue,\n} from './parse-utils';\nimport { getPartsByType, type Part } from '../../parts/parts';\nimport type {\n ComparisonColumn,\n ComparisonCompProps,\n ComparisonRow,\n ComparisonSectionComponent,\n SectionFixture,\n} from '../types';\nimport type {\n SectionDefinition,\n ParseContext,\n DropSection,\n} from '../section-definition';\nimport { DROP_SECTION } from '../section-definition';\nimport { DIAGNOSTIC_TYPES } from '../diagnosticTypes';\n\n/**\n * A cell the writer left blank: empty, or a dash / \"n/a\" placeholder standing in\n * for \"we have no fact here\".\n *\n * This has to be judged on the RAW cell text, before `parseTableValue`, because\n * that maps an empty cell to `false` — the very same value a deliberate \"No\"\n * produces. After parsing, \"no data\" and \"no, it does not have that\" are\n * indistinguishable.\n */\nfunction isBlankCell(raw: string | undefined): boolean {\n const v = (raw ?? '').trim().toLowerCase();\n // U+2010–U+2015 are the hyphen/dash family; U+2212 is minus.\n return v === '' || v === 'n/a' || /^[-‐-―−]+$/.test(v);\n}\n\nexport class ComparisonSectionDefinition\n implements SectionDefinition<ComparisonSectionComponent>\n{\n sectionType = 'comparison' as const;\n patterns = [\n 'html_comment[section^=\"comparison\"] > (h2 | h3 | h4 | t) > html_comment? > t* > table > (t | link)?',\n ];\n\n defaults: ComparisonCompProps = {\n title: 'Comparison',\n columnLabels: ['Option A', 'Option B'],\n rows: [\n { feature: 'Price', values: ['$10', '$20'] },\n { feature: 'Storage', values: ['100GB', '1TB'] },\n ],\n };\n\n fixtures: SectionFixture<ComparisonCompProps>[] = [\n {\n markdown: `<!-- section: comparison -->\n## Compare Plans\n\n| Feature | Basic | Pro |\n|---------|-------|-----|\n| Users | 5 | Unlimited |\n| Storage | 100GB | 1TB |`,\n expected: {\n title: 'Compare Plans',\n featureColumnLabel: 'Feature',\n columnLabels: ['Basic', 'Pro'],\n rows: [\n { feature: 'Users', values: ['5', 'Unlimited'] },\n { feature: 'Storage', values: ['100GB', '1TB'] },\n ],\n },\n },\n {\n markdown: `<!-- section: comparison -->\n## Platform Comparison\n\nSee how our platform stacks up against the competition.\n\n| Feature | Our Platform | Competitor |\n|---------|--------------|------------|\n| Storage | 1TB | 100GB |\n| Users | Unlimited | 5 |\n| Support | 24/7 Priority | Email Only |\n\n[Get started](#signup)`,\n expected: {\n title: 'Platform Comparison',\n description: 'See how our platform stacks up against the competition.',\n featureColumnLabel: 'Feature',\n columnLabels: ['Our Platform', 'Competitor'],\n rows: [\n { feature: 'Storage', values: ['1TB', '100GB'] },\n { feature: 'Users', values: ['Unlimited', '5'] },\n { feature: 'Support', values: ['24/7 Priority', 'Email Only'] },\n ],\n ctaText: 'Get started',\n ctaHref: '#signup',\n },\n },\n ];\n\n parse(\n parts: Part[],\n context?: ParseContext,\n ): ComparisonCompProps | DropSection {\n const title =\n headingText(parts, 2) ||\n headingText(parts, 3) ||\n headingText(parts, 4) ||\n 'Comparison';\n const description = proseBodyMarkdown(parts) || undefined;\n\n // Table meta from nodesToParts: { columnLabels, featureColumnLabel, rows: { feature, values }[] }\n const tableParts = getPartsByType<Part>(parts, 'table');\n const tableMeta = tableParts[0]?.meta as\n | {\n columnLabels?: string[];\n columns?: ComparisonColumn[];\n featureColumnLabel?: string;\n rows?: { feature: string; iconHint?: string; values: string[] }[];\n // Legacy format from partsConverter\n headers?: string[];\n }\n | undefined;\n\n let columnLabels: string[];\n let columns: ComparisonColumn[] | undefined;\n let featureColumnLabel: string | undefined;\n let rows: ComparisonRow[];\n /** The cells exactly as written, index-aligned with `rows`. */\n let rawValueRows: string[][];\n\n if (tableMeta?.columnLabels !== undefined) {\n // SDK nodesToParts format\n columnLabels = tableMeta.columnLabels;\n columns = tableMeta.columns;\n featureColumnLabel = tableMeta.featureColumnLabel || undefined;\n rawValueRows = (tableMeta.rows ?? []).map((row) => row.values);\n rows = (tableMeta.rows ?? []).map((row) => ({\n feature: row.feature,\n ...(row.iconHint ? { iconHint: row.iconHint } : {}),\n values: row.values.map(parseTableValue),\n }));\n } else {\n // Legacy partsConverter format: { headers: string[], rows: string[][] }\n const allHeaders = tableMeta?.headers ?? [];\n const rawRows = (tableMeta as any)?.rows ?? [];\n featureColumnLabel = allHeaders[0] || undefined;\n columnLabels = allHeaders.slice(1);\n columns = columnLabels.map((label) => ({ label }));\n rawValueRows = rawRows.map((row: string[]) => row.slice(1));\n rows = rawRows.map((row: string[]) => ({\n feature: row[0] ?? '',\n values: row.slice(1).map(parseTableValue),\n }));\n }\n\n // Extract CTA from link parts\n const link = firstLink(parts);\n const ctaText = link?.text || undefined;\n const ctaHref = link?.href || undefined;\n\n // Filter out rows where all values are empty (e.g. trailing non-table text parsed as a row)\n const keptRow = rawValueRows.map((raw) => raw.some((v) => !isBlankCell(v)));\n const filteredRows = rows.filter((_, i) => keptRow[i]);\n const filteredRawRows = rawValueRows.filter((_, i) => keptRow[i]);\n const droppedCount = rows.length - filteredRows.length;\n if (droppedCount > 0) {\n context?.reportDiagnostic?.(\n DIAGNOSTIC_TYPES.ITEMS_DROPPED,\n `comparison: ${droppedCount} row(s) dropped (all values empty)`,\n );\n }\n\n // A column blank in every row is a side of the comparison the writer had no\n // facts for — it renders as a full column of dashes next to a populated one,\n // which reads as a real answer and is not one. Half a comparison is worse\n // than none, so drop the whole section. (No rows left at all lands here too:\n // every column is vacuously blank.)\n const blankColumns = columnLabels\n .map((_, col) => col)\n .filter((col) =>\n filteredRawRows.every((raw) => isBlankCell(raw[col])),\n );\n if (columnLabels.length > 0 && blankColumns.length > 0) {\n context?.reportDiagnostic?.(\n DIAGNOSTIC_TYPES.SECTION_REJECTED,\n `comparison: column(s) ${blankColumns\n .map((c) => columnLabels[c] || `#${c + 1}`)\n .join(', ')} blank across all ${filteredRawRows.length} row(s) — section dropped`,\n );\n return DROP_SECTION;\n }\n\n return {\n title,\n description,\n columnLabels,\n columns,\n rows: filteredRows,\n featureColumnLabel,\n ctaText,\n ctaHref,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_parseUtils","require","_parts","_sectionDefinition","_diagnosticTypes","isBlankCell","raw","v","trim","toLowerCase","test","ComparisonSectionDefinition","constructor","_defineProperty2","default","title","columnLabels","rows","feature","values","markdown","expected","featureColumnLabel","description","ctaText","ctaHref","parse","parts","context","_tableParts$","headingText","proseBodyMarkdown","undefined","tableParts","getPartsByType","tableMeta","meta","columns","rawValueRows","map","row","iconHint","parseTableValue","allHeaders","headers","rawRows","slice","label","lastTableIndex","p","type","lastIndexOf","link","firstLink","text","href","keptRow","some","filteredRows","filter","_","i","filteredRawRows","droppedCount","length","reportDiagnostic","DIAGNOSTIC_TYPES","ITEMS_DROPPED","blankColumns","col","every","SECTION_REJECTED","c","join","DROP_SECTION","exports"],"sources":["../../../../src/component/componentDefinitions/ComparisonSectionDefinition.ts"],"sourcesContent":["import {\n headingText,\n proseBodyMarkdown,\n firstLink,\n parseTableValue,\n} from './parse-utils';\nimport { getPartsByType, type Part } from '../../parts/parts';\nimport type {\n ComparisonColumn,\n ComparisonCompProps,\n ComparisonRow,\n ComparisonSectionComponent,\n SectionFixture,\n} from '../types';\nimport type {\n SectionDefinition,\n ParseContext,\n DropSection,\n} from '../section-definition';\nimport { DROP_SECTION } from '../section-definition';\nimport { DIAGNOSTIC_TYPES } from '../diagnosticTypes';\n\n/**\n * A cell the writer left blank: empty, or a dash / \"n/a\" placeholder standing in\n * for \"we have no fact here\".\n *\n * This has to be judged on the RAW cell text, before `parseTableValue`, because\n * that maps an empty cell to `false` — the very same value a deliberate \"No\"\n * produces. After parsing, \"no data\" and \"no, it does not have that\" are\n * indistinguishable.\n */\nfunction isBlankCell(raw: string | undefined): boolean {\n const v = (raw ?? '').trim().toLowerCase();\n // U+2010–U+2015 are the hyphen/dash family; U+2212 is minus.\n return v === '' || v === 'n/a' || /^[-‐-―−]+$/.test(v);\n}\n\nexport class ComparisonSectionDefinition\n implements SectionDefinition<ComparisonSectionComponent>\n{\n sectionType = 'comparison' as const;\n // The pre-table slot is the description paragraph, so it has to admit\n // `link`: `convertToBlockElements` unwraps a paragraph into its inline\n // nodes, so `Questions? Email support@shop.example for help.` arrives as\n // `t link t` — GFM autolinks a bare email, no author required — and an\n // authored `[men's shoes](web5://ask/…)` does the same. With `t*` the run\n // ended at that `link`, the whole pattern failed, and the section never\n // reached `parse()`: the heading and prose were claimed by `textBlock` and\n // the TABLE fell to `FallbackSectionDefinition`, whose `partsToMarkdown`\n // has no `table` branch — so it rendered as an empty section and the\n // comparison silently vanished.\n //\n // The trailing slot stays `(t | link)?`: it is the CTA, and `parse()` reads\n // it positionally (see `ctaText` below). Widening it would let the section\n // swallow a paragraph belonging to whatever follows.\n patterns = [\n 'html_comment[section^=\"comparison\"] > (h2 | h3 | h4 | t) > html_comment? > (t | link)* > table > (t | link)?',\n ];\n\n defaults: ComparisonCompProps = {\n title: 'Comparison',\n columnLabels: ['Option A', 'Option B'],\n rows: [\n { feature: 'Price', values: ['$10', '$20'] },\n { feature: 'Storage', values: ['100GB', '1TB'] },\n ],\n };\n\n fixtures: SectionFixture<ComparisonCompProps>[] = [\n {\n markdown: `<!-- section: comparison -->\n## Compare Plans\n\n| Feature | Basic | Pro |\n|---------|-------|-----|\n| Users | 5 | Unlimited |\n| Storage | 100GB | 1TB |`,\n expected: {\n title: 'Compare Plans',\n featureColumnLabel: 'Feature',\n columnLabels: ['Basic', 'Pro'],\n rows: [\n { feature: 'Users', values: ['5', 'Unlimited'] },\n { feature: 'Storage', values: ['100GB', '1TB'] },\n ],\n },\n },\n {\n markdown: `<!-- section: comparison -->\n## Platform Comparison\n\nSee how our platform stacks up against the competition.\n\n| Feature | Our Platform | Competitor |\n|---------|--------------|------------|\n| Storage | 1TB | 100GB |\n| Users | Unlimited | 5 |\n| Support | 24/7 Priority | Email Only |\n\n[Get started](#signup)`,\n expected: {\n title: 'Platform Comparison',\n description: 'See how our platform stacks up against the competition.',\n featureColumnLabel: 'Feature',\n columnLabels: ['Our Platform', 'Competitor'],\n rows: [\n { feature: 'Storage', values: ['1TB', '100GB'] },\n { feature: 'Users', values: ['Unlimited', '5'] },\n { feature: 'Support', values: ['24/7 Priority', 'Email Only'] },\n ],\n ctaText: 'Get started',\n ctaHref: '#signup',\n },\n },\n ];\n\n parse(\n parts: Part[],\n context?: ParseContext,\n ): ComparisonCompProps | DropSection {\n const title =\n headingText(parts, 2) ||\n headingText(parts, 3) ||\n headingText(parts, 4) ||\n 'Comparison';\n const description = proseBodyMarkdown(parts) || undefined;\n\n // Table meta from nodesToParts: { columnLabels, featureColumnLabel, rows: { feature, values }[] }\n const tableParts = getPartsByType<Part>(parts, 'table');\n const tableMeta = tableParts[0]?.meta as\n | {\n columnLabels?: string[];\n columns?: ComparisonColumn[];\n featureColumnLabel?: string;\n rows?: { feature: string; iconHint?: string; values: string[] }[];\n // Legacy format from partsConverter\n headers?: string[];\n }\n | undefined;\n\n let columnLabels: string[];\n let columns: ComparisonColumn[] | undefined;\n let featureColumnLabel: string | undefined;\n let rows: ComparisonRow[];\n /** The cells exactly as written, index-aligned with `rows`. */\n let rawValueRows: string[][];\n\n if (tableMeta?.columnLabels !== undefined) {\n // SDK nodesToParts format\n columnLabels = tableMeta.columnLabels;\n columns = tableMeta.columns;\n featureColumnLabel = tableMeta.featureColumnLabel || undefined;\n rawValueRows = (tableMeta.rows ?? []).map((row) => row.values);\n rows = (tableMeta.rows ?? []).map((row) => ({\n feature: row.feature,\n ...(row.iconHint ? { iconHint: row.iconHint } : {}),\n values: row.values.map(parseTableValue),\n }));\n } else {\n // Legacy partsConverter format: { headers: string[], rows: string[][] }\n const allHeaders = tableMeta?.headers ?? [];\n const rawRows = (tableMeta as any)?.rows ?? [];\n featureColumnLabel = allHeaders[0] || undefined;\n columnLabels = allHeaders.slice(1);\n columns = columnLabels.map((label) => ({ label }));\n rawValueRows = rawRows.map((row: string[]) => row.slice(1));\n rows = rawRows.map((row: string[]) => ({\n feature: row[0] ?? '',\n values: row.slice(1).map(parseTableValue),\n }));\n }\n\n // The CTA is the link AFTER the table, not merely the first link in the\n // section — the description may now carry its own inline links, and\n // `firstLink(parts)` would promote one of those to the CTA button.\n const lastTableIndex = parts.map((p) => p.type).lastIndexOf('table');\n const link = firstLink(\n lastTableIndex >= 0 ? parts.slice(lastTableIndex + 1) : parts,\n );\n const ctaText = link?.text || undefined;\n const ctaHref = link?.href || undefined;\n\n // Filter out rows where all values are empty (e.g. trailing non-table text parsed as a row)\n const keptRow = rawValueRows.map((raw) => raw.some((v) => !isBlankCell(v)));\n const filteredRows = rows.filter((_, i) => keptRow[i]);\n const filteredRawRows = rawValueRows.filter((_, i) => keptRow[i]);\n const droppedCount = rows.length - filteredRows.length;\n if (droppedCount > 0) {\n context?.reportDiagnostic?.(\n DIAGNOSTIC_TYPES.ITEMS_DROPPED,\n `comparison: ${droppedCount} row(s) dropped (all values empty)`,\n );\n }\n\n // A column blank in every row is a side of the comparison the writer had no\n // facts for — it renders as a full column of dashes next to a populated one,\n // which reads as a real answer and is not one. Half a comparison is worse\n // than none, so drop the whole section. (No rows left at all lands here too:\n // every column is vacuously blank.)\n const blankColumns = columnLabels\n .map((_, col) => col)\n .filter((col) =>\n filteredRawRows.every((raw) => isBlankCell(raw[col])),\n );\n if (columnLabels.length > 0 && blankColumns.length > 0) {\n context?.reportDiagnostic?.(\n DIAGNOSTIC_TYPES.SECTION_REJECTED,\n `comparison: column(s) ${blankColumns\n .map((c) => columnLabels[c] || `#${c + 1}`)\n .join(', ')} blank across all ${filteredRawRows.length} row(s) — section dropped`,\n );\n return DROP_SECTION;\n }\n\n return {\n title,\n description,\n columnLabels,\n columns,\n rows: filteredRows,\n featureColumnLabel,\n ctaText,\n ctaHref,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -41,8 +41,23 @@ class NextStepsSectionDefinition {
41
41
  constructor() {
42
42
  (0, _defineProperty2.default)(this, "sectionType", 'nextSteps');
43
43
  (0, _defineProperty2.default)(this, "patterns", [
44
- // Framing sentence (`t?`) then one chip per bullet — the authored shape.
45
- '(html_comment[section^="next"] | html_comment[semantic^="next"]) > h2 > image? > t? > list{item[1-]:(icon | t)* > (t? > link)+}',
44
+ // Framing sentence then one chip per bullet — the authored shape. The
45
+ // framing slot is `(t | link)*`, not `t?`, because a paragraph is unwrapped
46
+ // into its inline nodes: `Questions? Email support@shop.example for help.`
47
+ // arrives as `t link t` (GFM autolinks a bare email) and so does an
48
+ // authored `[men's shoes](web5://ask/…)`. With `t?` the run ended at that
49
+ // `link`, this pattern failed, and the legacy pattern below claimed the
50
+ // section instead — turning the prose link into a chip and stranding the
51
+ // real chip list in the fallback as raw bullets.
52
+ //
53
+ // This does NOT steal the legacy pattern's inputs: the `list` here is
54
+ // mandatory, so a section with chips in the prose and no list still falls
55
+ // through. It does change one rare shape — prose that is nothing but links
56
+ // ALONGSIDE a chip list now matches here, and `proseBodyMarkdown` drops
57
+ // link-only paragraphs, so those links are dropped rather than rendered
58
+ // inline. That shape previously stranded the list entirely, so neither
59
+ // outcome was whole; this one at least renders the authored chips.
60
+ '(html_comment[section^="next"] | html_comment[semantic^="next"]) > h2 > image? > (t | link)* > list{item[1-]:(icon | t)* > (t? > link)+}',
46
61
  // Legacy inline shape: chips embedded in the prose. Still arrives from
47
62
  // sites whose next-steps prompt has not moved to the list shape.
48
63
  '(html_comment[section^="next"] | html_comment[semantic^="next"]) > h2 > image? > (t | link)+']);
@@ -1 +1 @@
1
- {"version":3,"names":["_parseUtils","require","_parts","linkToMarkdown","link","_link$content","_link$meta","content","trim","meta","href","appendInlineToken","current","token","trimmed","test","inlineBodyMarkdown","parts","body","reduce","part","type","_part$meta","markdown","undefined","NextStepsSectionDefinition","constructor","_defineProperty2","default","title","backgroundImage","steps","expected","parse","headingText","firstImageSrc","chipsInlineInBody","lists","getPartsByType","length","proseBodyMarkdown","list","item","_list$meta","items","_item$meta","_iconPart$meta","itemParts","iconPart","find","p","iconHint","contentFragments","push","_p$content","filter","Boolean","join","extractListItemText","links","getLinks","_link$content2","_link$meta2","text","exports"],"sources":["../../../../src/component/componentDefinitions/NextStepsSectionDefinition.ts"],"sourcesContent":["import {\n headingText,\n proseBodyMarkdown,\n extractListItemText,\n firstImageSrc,\n} from './parse-utils';\nimport {\n getPartsByType,\n getLinks,\n type Part,\n type ListPart,\n type LinkPart,\n type IconPart,\n} from '../../parts/parts';\nimport type {\n NextStepsCompProps,\n NextStepsSectionComponent,\n SectionFixture,\n} from '../types';\nimport type { SectionDefinition } from '../section-definition';\n\nfunction linkToMarkdown(link: LinkPart): string {\n return `[${link.content?.trim() || ''}](${link.meta?.href || ''})`;\n}\n\nfunction appendInlineToken(current: string, token: string): string {\n const trimmed = token.trim();\n if (!trimmed) {\n return current;\n }\n if (!current) {\n return trimmed;\n }\n if (/^[,.;:!?)]/.test(trimmed)) {\n return `${current}${trimmed}`;\n }\n return `${current} ${trimmed}`;\n}\n\nfunction inlineBodyMarkdown(parts: Part[]): string | undefined {\n const body = parts.reduce((current, part) => {\n if (part.type === 'link') {\n return appendInlineToken(current, linkToMarkdown(part as LinkPart));\n }\n if (part.type === 'text' || part.type === 'richText') {\n const markdown = (part.meta?.markdown as string | undefined)?.trim();\n return appendInlineToken(current, markdown || part.content || '');\n }\n return current;\n }, '');\n\n return body || undefined;\n}\n\nexport class NextStepsSectionDefinition\n implements SectionDefinition<NextStepsSectionComponent>\n{\n sectionType = 'nextSteps' as const;\n patterns = [\n // Framing sentence (`t?`) then one chip per bullet — the authored shape.\n '(html_comment[section^=\"next\"] | html_comment[semantic^=\"next\"]) > h2 > image? > t? > list{item[1-]:(icon | t)* > (t? > link)+}',\n // Legacy inline shape: chips embedded in the prose. Still arrives from\n // sites whose next-steps prompt has not moved to the list shape.\n '(html_comment[section^=\"next\"] | html_comment[semantic^=\"next\"]) > h2 > image? > (t | link)+',\n ];\n\n defaults: NextStepsCompProps = {\n title: 'Next Steps',\n body: 'Where would you like to go next?',\n backgroundImage: undefined,\n steps: [{ content: '[Get started](/start)' }],\n };\n\n fixtures: SectionFixture<NextStepsCompProps>[] = [\n {\n markdown: `<!-- section:next-steps, semantic:next_steps -->\n\n## Find the right care for mature, sensitive skin\n\nWant to focus on rich hydrators and barrier builders?\n\n- [hydrating creams →](web5://ask/hydrating+creams+for+mature+skin)\n- [gentle resurfacing serums →](web5://ask/gentle+resurfacing+serums)`,\n expected: {\n title: 'Find the right care for mature, sensitive skin',\n body: 'Want to focus on rich hydrators and barrier builders?',\n steps: [\n {\n content:\n '[hydrating creams →](web5://ask/hydrating+creams+for+mature+skin)',\n },\n {\n content:\n '[gentle resurfacing serums →](web5://ask/gentle+resurfacing+serums)',\n },\n ],\n },\n },\n {\n markdown: `<!-- section: next_steps -->\n\n## Next Steps\n\n- Check out [Documentation](/docs)\n- Try [Examples](/examples)`,\n expected: {\n title: 'Next Steps',\n steps: [\n { content: 'Check out [Documentation](/docs)' },\n { content: 'Try [Examples](/examples)' },\n ],\n },\n },\n ];\n\n parse(parts: Part[]): NextStepsCompProps {\n const title = headingText(parts, 2) || 'Next Steps';\n const backgroundImage = firstImageSrc(parts);\n const steps: { content: string; iconHint?: string }[] = [];\n let body: string | undefined;\n let chipsInlineInBody = false;\n\n // Try list-based pattern first\n const lists = getPartsByType<ListPart>(parts, 'list');\n if (lists.length > 0) {\n // The framing sentence is the only top-level prose — list items live\n // under each list's meta.items, so this never picks up a chip.\n body = proseBodyMarkdown(parts) || undefined;\n\n for (const list of lists) {\n for (const item of list.meta?.items ?? []) {\n const itemParts = (item.meta?.parts ?? []) as Part[];\n\n const iconPart = itemParts.find((p) => p.type === 'icon') as\n | IconPart\n | undefined;\n const iconHint = (iconPart?.meta as { iconHint?: string })?.iconHint;\n\n const contentFragments: string[] = [];\n for (const p of itemParts) {\n if (p.type === 'link') {\n const link = p as LinkPart;\n contentFragments.push(linkToMarkdown(link));\n } else if (p.type === 'text' || p.type === 'richText') {\n contentFragments.push(p.content?.trim() || '');\n }\n }\n const content =\n contentFragments.filter(Boolean).join(' ') ||\n extractListItemText(item);\n if (content.trim()) {\n steps.push({\n content: content.trim(),\n ...(iconHint ? { iconHint } : {}),\n });\n }\n }\n }\n } else {\n body = inlineBodyMarkdown(parts);\n // body carries the chips as inline links — flag it so renderers show the\n // prose alone instead of repeating every chip as a row beneath it.\n chipsInlineInBody = Boolean(body);\n }\n\n // Fallback: inline links pattern\n if (steps.length === 0) {\n const links = getLinks(parts);\n for (const link of links) {\n const text = link.content?.trim();\n const href = link.meta?.href;\n if (text && href) {\n steps.push({ content: linkToMarkdown(link) });\n }\n }\n }\n\n return {\n title,\n ...(body ? { body } : {}),\n ...(chipsInlineInBody ? { chipsInlineInBody } : {}),\n ...(backgroundImage ? { backgroundImage } : {}),\n steps,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["_parseUtils","require","_parts","linkToMarkdown","link","_link$content","_link$meta","content","trim","meta","href","appendInlineToken","current","token","trimmed","test","inlineBodyMarkdown","parts","body","reduce","part","type","_part$meta","markdown","undefined","NextStepsSectionDefinition","constructor","_defineProperty2","default","title","backgroundImage","steps","expected","parse","headingText","firstImageSrc","chipsInlineInBody","lists","getPartsByType","length","proseBodyMarkdown","list","item","_list$meta","items","_item$meta","_iconPart$meta","itemParts","iconPart","find","p","iconHint","contentFragments","push","_p$content","filter","Boolean","join","extractListItemText","links","getLinks","_link$content2","_link$meta2","text","exports"],"sources":["../../../../src/component/componentDefinitions/NextStepsSectionDefinition.ts"],"sourcesContent":["import {\n headingText,\n proseBodyMarkdown,\n extractListItemText,\n firstImageSrc,\n} from './parse-utils';\nimport {\n getPartsByType,\n getLinks,\n type Part,\n type ListPart,\n type LinkPart,\n type IconPart,\n} from '../../parts/parts';\nimport type {\n NextStepsCompProps,\n NextStepsSectionComponent,\n SectionFixture,\n} from '../types';\nimport type { SectionDefinition } from '../section-definition';\n\nfunction linkToMarkdown(link: LinkPart): string {\n return `[${link.content?.trim() || ''}](${link.meta?.href || ''})`;\n}\n\nfunction appendInlineToken(current: string, token: string): string {\n const trimmed = token.trim();\n if (!trimmed) {\n return current;\n }\n if (!current) {\n return trimmed;\n }\n if (/^[,.;:!?)]/.test(trimmed)) {\n return `${current}${trimmed}`;\n }\n return `${current} ${trimmed}`;\n}\n\nfunction inlineBodyMarkdown(parts: Part[]): string | undefined {\n const body = parts.reduce((current, part) => {\n if (part.type === 'link') {\n return appendInlineToken(current, linkToMarkdown(part as LinkPart));\n }\n if (part.type === 'text' || part.type === 'richText') {\n const markdown = (part.meta?.markdown as string | undefined)?.trim();\n return appendInlineToken(current, markdown || part.content || '');\n }\n return current;\n }, '');\n\n return body || undefined;\n}\n\nexport class NextStepsSectionDefinition\n implements SectionDefinition<NextStepsSectionComponent>\n{\n sectionType = 'nextSteps' as const;\n patterns = [\n // Framing sentence then one chip per bullet — the authored shape. The\n // framing slot is `(t | link)*`, not `t?`, because a paragraph is unwrapped\n // into its inline nodes: `Questions? Email support@shop.example for help.`\n // arrives as `t link t` (GFM autolinks a bare email) and so does an\n // authored `[men's shoes](web5://ask/…)`. With `t?` the run ended at that\n // `link`, this pattern failed, and the legacy pattern below claimed the\n // section instead — turning the prose link into a chip and stranding the\n // real chip list in the fallback as raw bullets.\n //\n // This does NOT steal the legacy pattern's inputs: the `list` here is\n // mandatory, so a section with chips in the prose and no list still falls\n // through. It does change one rare shape — prose that is nothing but links\n // ALONGSIDE a chip list now matches here, and `proseBodyMarkdown` drops\n // link-only paragraphs, so those links are dropped rather than rendered\n // inline. That shape previously stranded the list entirely, so neither\n // outcome was whole; this one at least renders the authored chips.\n '(html_comment[section^=\"next\"] | html_comment[semantic^=\"next\"]) > h2 > image? > (t | link)* > list{item[1-]:(icon | t)* > (t? > link)+}',\n // Legacy inline shape: chips embedded in the prose. Still arrives from\n // sites whose next-steps prompt has not moved to the list shape.\n '(html_comment[section^=\"next\"] | html_comment[semantic^=\"next\"]) > h2 > image? > (t | link)+',\n ];\n\n defaults: NextStepsCompProps = {\n title: 'Next Steps',\n body: 'Where would you like to go next?',\n backgroundImage: undefined,\n steps: [{ content: '[Get started](/start)' }],\n };\n\n fixtures: SectionFixture<NextStepsCompProps>[] = [\n {\n markdown: `<!-- section:next-steps, semantic:next_steps -->\n\n## Find the right care for mature, sensitive skin\n\nWant to focus on rich hydrators and barrier builders?\n\n- [hydrating creams →](web5://ask/hydrating+creams+for+mature+skin)\n- [gentle resurfacing serums →](web5://ask/gentle+resurfacing+serums)`,\n expected: {\n title: 'Find the right care for mature, sensitive skin',\n body: 'Want to focus on rich hydrators and barrier builders?',\n steps: [\n {\n content:\n '[hydrating creams →](web5://ask/hydrating+creams+for+mature+skin)',\n },\n {\n content:\n '[gentle resurfacing serums →](web5://ask/gentle+resurfacing+serums)',\n },\n ],\n },\n },\n {\n markdown: `<!-- section: next_steps -->\n\n## Next Steps\n\n- Check out [Documentation](/docs)\n- Try [Examples](/examples)`,\n expected: {\n title: 'Next Steps',\n steps: [\n { content: 'Check out [Documentation](/docs)' },\n { content: 'Try [Examples](/examples)' },\n ],\n },\n },\n ];\n\n parse(parts: Part[]): NextStepsCompProps {\n const title = headingText(parts, 2) || 'Next Steps';\n const backgroundImage = firstImageSrc(parts);\n const steps: { content: string; iconHint?: string }[] = [];\n let body: string | undefined;\n let chipsInlineInBody = false;\n\n // Try list-based pattern first\n const lists = getPartsByType<ListPart>(parts, 'list');\n if (lists.length > 0) {\n // The framing sentence is the only top-level prose — list items live\n // under each list's meta.items, so this never picks up a chip.\n body = proseBodyMarkdown(parts) || undefined;\n\n for (const list of lists) {\n for (const item of list.meta?.items ?? []) {\n const itemParts = (item.meta?.parts ?? []) as Part[];\n\n const iconPart = itemParts.find((p) => p.type === 'icon') as\n | IconPart\n | undefined;\n const iconHint = (iconPart?.meta as { iconHint?: string })?.iconHint;\n\n const contentFragments: string[] = [];\n for (const p of itemParts) {\n if (p.type === 'link') {\n const link = p as LinkPart;\n contentFragments.push(linkToMarkdown(link));\n } else if (p.type === 'text' || p.type === 'richText') {\n contentFragments.push(p.content?.trim() || '');\n }\n }\n const content =\n contentFragments.filter(Boolean).join(' ') ||\n extractListItemText(item);\n if (content.trim()) {\n steps.push({\n content: content.trim(),\n ...(iconHint ? { iconHint } : {}),\n });\n }\n }\n }\n } else {\n body = inlineBodyMarkdown(parts);\n // body carries the chips as inline links — flag it so renderers show the\n // prose alone instead of repeating every chip as a row beneath it.\n chipsInlineInBody = Boolean(body);\n }\n\n // Fallback: inline links pattern\n if (steps.length === 0) {\n const links = getLinks(parts);\n for (const link of links) {\n const text = link.content?.trim();\n const href = link.meta?.href;\n if (text && href) {\n steps.push({ content: linkToMarkdown(link) });\n }\n }\n }\n\n return {\n title,\n ...(body ? { body } : {}),\n ...(chipsInlineInBody ? { chipsInlineInBody } : {}),\n ...(backgroundImage ? { backgroundImage } : {}),\n steps,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -21,7 +21,21 @@ function isBlankCell(raw) {
21
21
  export class ComparisonSectionDefinition {
22
22
  constructor() {
23
23
  _defineProperty(this, "sectionType", 'comparison');
24
- _defineProperty(this, "patterns", ['html_comment[section^="comparison"] > (h2 | h3 | h4 | t) > html_comment? > t* > table > (t | link)?']);
24
+ // The pre-table slot is the description paragraph, so it has to admit
25
+ // `link`: `convertToBlockElements` unwraps a paragraph into its inline
26
+ // nodes, so `Questions? Email support@shop.example for help.` arrives as
27
+ // `t link t` — GFM autolinks a bare email, no author required — and an
28
+ // authored `[men's shoes](web5://ask/…)` does the same. With `t*` the run
29
+ // ended at that `link`, the whole pattern failed, and the section never
30
+ // reached `parse()`: the heading and prose were claimed by `textBlock` and
31
+ // the TABLE fell to `FallbackSectionDefinition`, whose `partsToMarkdown`
32
+ // has no `table` branch — so it rendered as an empty section and the
33
+ // comparison silently vanished.
34
+ //
35
+ // The trailing slot stays `(t | link)?`: it is the CTA, and `parse()` reads
36
+ // it positionally (see `ctaText` below). Widening it would let the section
37
+ // swallow a paragraph belonging to whatever follows.
38
+ _defineProperty(this, "patterns", ['html_comment[section^="comparison"] > (h2 | h3 | h4 | t) > html_comment? > (t | link)* > table > (t | link)?']);
25
39
  _defineProperty(this, "defaults", {
26
40
  title: 'Comparison',
27
41
  columnLabels: ['Option A', 'Option B'],
@@ -129,8 +143,11 @@ See how our platform stacks up against the competition.
129
143
  }));
130
144
  }
131
145
 
132
- // Extract CTA from link parts
133
- const link = firstLink(parts);
146
+ // The CTA is the link AFTER the table, not merely the first link in the
147
+ // section the description may now carry its own inline links, and
148
+ // `firstLink(parts)` would promote one of those to the CTA button.
149
+ const lastTableIndex = parts.map(p => p.type).lastIndexOf('table');
150
+ const link = firstLink(lastTableIndex >= 0 ? parts.slice(lastTableIndex + 1) : parts);
134
151
  const ctaText = (link == null ? void 0 : link.text) || undefined;
135
152
  const ctaHref = (link == null ? void 0 : link.href) || undefined;
136
153
 
@@ -1 +1 @@
1
- {"version":3,"names":["headingText","proseBodyMarkdown","firstLink","parseTableValue","getPartsByType","DROP_SECTION","DIAGNOSTIC_TYPES","isBlankCell","raw","v","trim","toLowerCase","test","ComparisonSectionDefinition","constructor","_defineProperty","title","columnLabels","rows","feature","values","markdown","expected","featureColumnLabel","description","ctaText","ctaHref","parse","parts","context","_tableParts$","undefined","tableParts","tableMeta","meta","columns","rawValueRows","map","row","iconHint","allHeaders","headers","rawRows","slice","label","link","text","href","keptRow","some","filteredRows","filter","_","i","filteredRawRows","droppedCount","length","reportDiagnostic","ITEMS_DROPPED","blankColumns","col","every","SECTION_REJECTED","c","join"],"sources":["../../../../src/component/componentDefinitions/ComparisonSectionDefinition.ts"],"sourcesContent":["import {\n headingText,\n proseBodyMarkdown,\n firstLink,\n parseTableValue,\n} from './parse-utils';\nimport { getPartsByType, type Part } from '../../parts/parts';\nimport type {\n ComparisonColumn,\n ComparisonCompProps,\n ComparisonRow,\n ComparisonSectionComponent,\n SectionFixture,\n} from '../types';\nimport type {\n SectionDefinition,\n ParseContext,\n DropSection,\n} from '../section-definition';\nimport { DROP_SECTION } from '../section-definition';\nimport { DIAGNOSTIC_TYPES } from '../diagnosticTypes';\n\n/**\n * A cell the writer left blank: empty, or a dash / \"n/a\" placeholder standing in\n * for \"we have no fact here\".\n *\n * This has to be judged on the RAW cell text, before `parseTableValue`, because\n * that maps an empty cell to `false` — the very same value a deliberate \"No\"\n * produces. After parsing, \"no data\" and \"no, it does not have that\" are\n * indistinguishable.\n */\nfunction isBlankCell(raw: string | undefined): boolean {\n const v = (raw ?? '').trim().toLowerCase();\n // U+2010–U+2015 are the hyphen/dash family; U+2212 is minus.\n return v === '' || v === 'n/a' || /^[-‐-―−]+$/.test(v);\n}\n\nexport class ComparisonSectionDefinition\n implements SectionDefinition<ComparisonSectionComponent>\n{\n sectionType = 'comparison' as const;\n patterns = [\n 'html_comment[section^=\"comparison\"] > (h2 | h3 | h4 | t) > html_comment? > t* > table > (t | link)?',\n ];\n\n defaults: ComparisonCompProps = {\n title: 'Comparison',\n columnLabels: ['Option A', 'Option B'],\n rows: [\n { feature: 'Price', values: ['$10', '$20'] },\n { feature: 'Storage', values: ['100GB', '1TB'] },\n ],\n };\n\n fixtures: SectionFixture<ComparisonCompProps>[] = [\n {\n markdown: `<!-- section: comparison -->\n## Compare Plans\n\n| Feature | Basic | Pro |\n|---------|-------|-----|\n| Users | 5 | Unlimited |\n| Storage | 100GB | 1TB |`,\n expected: {\n title: 'Compare Plans',\n featureColumnLabel: 'Feature',\n columnLabels: ['Basic', 'Pro'],\n rows: [\n { feature: 'Users', values: ['5', 'Unlimited'] },\n { feature: 'Storage', values: ['100GB', '1TB'] },\n ],\n },\n },\n {\n markdown: `<!-- section: comparison -->\n## Platform Comparison\n\nSee how our platform stacks up against the competition.\n\n| Feature | Our Platform | Competitor |\n|---------|--------------|------------|\n| Storage | 1TB | 100GB |\n| Users | Unlimited | 5 |\n| Support | 24/7 Priority | Email Only |\n\n[Get started](#signup)`,\n expected: {\n title: 'Platform Comparison',\n description: 'See how our platform stacks up against the competition.',\n featureColumnLabel: 'Feature',\n columnLabels: ['Our Platform', 'Competitor'],\n rows: [\n { feature: 'Storage', values: ['1TB', '100GB'] },\n { feature: 'Users', values: ['Unlimited', '5'] },\n { feature: 'Support', values: ['24/7 Priority', 'Email Only'] },\n ],\n ctaText: 'Get started',\n ctaHref: '#signup',\n },\n },\n ];\n\n parse(\n parts: Part[],\n context?: ParseContext,\n ): ComparisonCompProps | DropSection {\n const title =\n headingText(parts, 2) ||\n headingText(parts, 3) ||\n headingText(parts, 4) ||\n 'Comparison';\n const description = proseBodyMarkdown(parts) || undefined;\n\n // Table meta from nodesToParts: { columnLabels, featureColumnLabel, rows: { feature, values }[] }\n const tableParts = getPartsByType<Part>(parts, 'table');\n const tableMeta = tableParts[0]?.meta as\n | {\n columnLabels?: string[];\n columns?: ComparisonColumn[];\n featureColumnLabel?: string;\n rows?: { feature: string; iconHint?: string; values: string[] }[];\n // Legacy format from partsConverter\n headers?: string[];\n }\n | undefined;\n\n let columnLabels: string[];\n let columns: ComparisonColumn[] | undefined;\n let featureColumnLabel: string | undefined;\n let rows: ComparisonRow[];\n /** The cells exactly as written, index-aligned with `rows`. */\n let rawValueRows: string[][];\n\n if (tableMeta?.columnLabels !== undefined) {\n // SDK nodesToParts format\n columnLabels = tableMeta.columnLabels;\n columns = tableMeta.columns;\n featureColumnLabel = tableMeta.featureColumnLabel || undefined;\n rawValueRows = (tableMeta.rows ?? []).map((row) => row.values);\n rows = (tableMeta.rows ?? []).map((row) => ({\n feature: row.feature,\n ...(row.iconHint ? { iconHint: row.iconHint } : {}),\n values: row.values.map(parseTableValue),\n }));\n } else {\n // Legacy partsConverter format: { headers: string[], rows: string[][] }\n const allHeaders = tableMeta?.headers ?? [];\n const rawRows = (tableMeta as any)?.rows ?? [];\n featureColumnLabel = allHeaders[0] || undefined;\n columnLabels = allHeaders.slice(1);\n columns = columnLabels.map((label) => ({ label }));\n rawValueRows = rawRows.map((row: string[]) => row.slice(1));\n rows = rawRows.map((row: string[]) => ({\n feature: row[0] ?? '',\n values: row.slice(1).map(parseTableValue),\n }));\n }\n\n // Extract CTA from link parts\n const link = firstLink(parts);\n const ctaText = link?.text || undefined;\n const ctaHref = link?.href || undefined;\n\n // Filter out rows where all values are empty (e.g. trailing non-table text parsed as a row)\n const keptRow = rawValueRows.map((raw) => raw.some((v) => !isBlankCell(v)));\n const filteredRows = rows.filter((_, i) => keptRow[i]);\n const filteredRawRows = rawValueRows.filter((_, i) => keptRow[i]);\n const droppedCount = rows.length - filteredRows.length;\n if (droppedCount > 0) {\n context?.reportDiagnostic?.(\n DIAGNOSTIC_TYPES.ITEMS_DROPPED,\n `comparison: ${droppedCount} row(s) dropped (all values empty)`,\n );\n }\n\n // A column blank in every row is a side of the comparison the writer had no\n // facts for — it renders as a full column of dashes next to a populated one,\n // which reads as a real answer and is not one. Half a comparison is worse\n // than none, so drop the whole section. (No rows left at all lands here too:\n // every column is vacuously blank.)\n const blankColumns = columnLabels\n .map((_, col) => col)\n .filter((col) =>\n filteredRawRows.every((raw) => isBlankCell(raw[col])),\n );\n if (columnLabels.length > 0 && blankColumns.length > 0) {\n context?.reportDiagnostic?.(\n DIAGNOSTIC_TYPES.SECTION_REJECTED,\n `comparison: column(s) ${blankColumns\n .map((c) => columnLabels[c] || `#${c + 1}`)\n .join(', ')} blank across all ${filteredRawRows.length} row(s) — section dropped`,\n );\n return DROP_SECTION;\n }\n\n return {\n title,\n description,\n columnLabels,\n columns,\n rows: filteredRows,\n featureColumnLabel,\n ctaText,\n ctaHref,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["headingText","proseBodyMarkdown","firstLink","parseTableValue","getPartsByType","DROP_SECTION","DIAGNOSTIC_TYPES","isBlankCell","raw","v","trim","toLowerCase","test","ComparisonSectionDefinition","constructor","_defineProperty","title","columnLabels","rows","feature","values","markdown","expected","featureColumnLabel","description","ctaText","ctaHref","parse","parts","context","_tableParts$","undefined","tableParts","tableMeta","meta","columns","rawValueRows","map","row","iconHint","allHeaders","headers","rawRows","slice","label","lastTableIndex","p","type","lastIndexOf","link","text","href","keptRow","some","filteredRows","filter","_","i","filteredRawRows","droppedCount","length","reportDiagnostic","ITEMS_DROPPED","blankColumns","col","every","SECTION_REJECTED","c","join"],"sources":["../../../../src/component/componentDefinitions/ComparisonSectionDefinition.ts"],"sourcesContent":["import {\n headingText,\n proseBodyMarkdown,\n firstLink,\n parseTableValue,\n} from './parse-utils';\nimport { getPartsByType, type Part } from '../../parts/parts';\nimport type {\n ComparisonColumn,\n ComparisonCompProps,\n ComparisonRow,\n ComparisonSectionComponent,\n SectionFixture,\n} from '../types';\nimport type {\n SectionDefinition,\n ParseContext,\n DropSection,\n} from '../section-definition';\nimport { DROP_SECTION } from '../section-definition';\nimport { DIAGNOSTIC_TYPES } from '../diagnosticTypes';\n\n/**\n * A cell the writer left blank: empty, or a dash / \"n/a\" placeholder standing in\n * for \"we have no fact here\".\n *\n * This has to be judged on the RAW cell text, before `parseTableValue`, because\n * that maps an empty cell to `false` — the very same value a deliberate \"No\"\n * produces. After parsing, \"no data\" and \"no, it does not have that\" are\n * indistinguishable.\n */\nfunction isBlankCell(raw: string | undefined): boolean {\n const v = (raw ?? '').trim().toLowerCase();\n // U+2010–U+2015 are the hyphen/dash family; U+2212 is minus.\n return v === '' || v === 'n/a' || /^[-‐-―−]+$/.test(v);\n}\n\nexport class ComparisonSectionDefinition\n implements SectionDefinition<ComparisonSectionComponent>\n{\n sectionType = 'comparison' as const;\n // The pre-table slot is the description paragraph, so it has to admit\n // `link`: `convertToBlockElements` unwraps a paragraph into its inline\n // nodes, so `Questions? Email support@shop.example for help.` arrives as\n // `t link t` — GFM autolinks a bare email, no author required — and an\n // authored `[men's shoes](web5://ask/…)` does the same. With `t*` the run\n // ended at that `link`, the whole pattern failed, and the section never\n // reached `parse()`: the heading and prose were claimed by `textBlock` and\n // the TABLE fell to `FallbackSectionDefinition`, whose `partsToMarkdown`\n // has no `table` branch — so it rendered as an empty section and the\n // comparison silently vanished.\n //\n // The trailing slot stays `(t | link)?`: it is the CTA, and `parse()` reads\n // it positionally (see `ctaText` below). Widening it would let the section\n // swallow a paragraph belonging to whatever follows.\n patterns = [\n 'html_comment[section^=\"comparison\"] > (h2 | h3 | h4 | t) > html_comment? > (t | link)* > table > (t | link)?',\n ];\n\n defaults: ComparisonCompProps = {\n title: 'Comparison',\n columnLabels: ['Option A', 'Option B'],\n rows: [\n { feature: 'Price', values: ['$10', '$20'] },\n { feature: 'Storage', values: ['100GB', '1TB'] },\n ],\n };\n\n fixtures: SectionFixture<ComparisonCompProps>[] = [\n {\n markdown: `<!-- section: comparison -->\n## Compare Plans\n\n| Feature | Basic | Pro |\n|---------|-------|-----|\n| Users | 5 | Unlimited |\n| Storage | 100GB | 1TB |`,\n expected: {\n title: 'Compare Plans',\n featureColumnLabel: 'Feature',\n columnLabels: ['Basic', 'Pro'],\n rows: [\n { feature: 'Users', values: ['5', 'Unlimited'] },\n { feature: 'Storage', values: ['100GB', '1TB'] },\n ],\n },\n },\n {\n markdown: `<!-- section: comparison -->\n## Platform Comparison\n\nSee how our platform stacks up against the competition.\n\n| Feature | Our Platform | Competitor |\n|---------|--------------|------------|\n| Storage | 1TB | 100GB |\n| Users | Unlimited | 5 |\n| Support | 24/7 Priority | Email Only |\n\n[Get started](#signup)`,\n expected: {\n title: 'Platform Comparison',\n description: 'See how our platform stacks up against the competition.',\n featureColumnLabel: 'Feature',\n columnLabels: ['Our Platform', 'Competitor'],\n rows: [\n { feature: 'Storage', values: ['1TB', '100GB'] },\n { feature: 'Users', values: ['Unlimited', '5'] },\n { feature: 'Support', values: ['24/7 Priority', 'Email Only'] },\n ],\n ctaText: 'Get started',\n ctaHref: '#signup',\n },\n },\n ];\n\n parse(\n parts: Part[],\n context?: ParseContext,\n ): ComparisonCompProps | DropSection {\n const title =\n headingText(parts, 2) ||\n headingText(parts, 3) ||\n headingText(parts, 4) ||\n 'Comparison';\n const description = proseBodyMarkdown(parts) || undefined;\n\n // Table meta from nodesToParts: { columnLabels, featureColumnLabel, rows: { feature, values }[] }\n const tableParts = getPartsByType<Part>(parts, 'table');\n const tableMeta = tableParts[0]?.meta as\n | {\n columnLabels?: string[];\n columns?: ComparisonColumn[];\n featureColumnLabel?: string;\n rows?: { feature: string; iconHint?: string; values: string[] }[];\n // Legacy format from partsConverter\n headers?: string[];\n }\n | undefined;\n\n let columnLabels: string[];\n let columns: ComparisonColumn[] | undefined;\n let featureColumnLabel: string | undefined;\n let rows: ComparisonRow[];\n /** The cells exactly as written, index-aligned with `rows`. */\n let rawValueRows: string[][];\n\n if (tableMeta?.columnLabels !== undefined) {\n // SDK nodesToParts format\n columnLabels = tableMeta.columnLabels;\n columns = tableMeta.columns;\n featureColumnLabel = tableMeta.featureColumnLabel || undefined;\n rawValueRows = (tableMeta.rows ?? []).map((row) => row.values);\n rows = (tableMeta.rows ?? []).map((row) => ({\n feature: row.feature,\n ...(row.iconHint ? { iconHint: row.iconHint } : {}),\n values: row.values.map(parseTableValue),\n }));\n } else {\n // Legacy partsConverter format: { headers: string[], rows: string[][] }\n const allHeaders = tableMeta?.headers ?? [];\n const rawRows = (tableMeta as any)?.rows ?? [];\n featureColumnLabel = allHeaders[0] || undefined;\n columnLabels = allHeaders.slice(1);\n columns = columnLabels.map((label) => ({ label }));\n rawValueRows = rawRows.map((row: string[]) => row.slice(1));\n rows = rawRows.map((row: string[]) => ({\n feature: row[0] ?? '',\n values: row.slice(1).map(parseTableValue),\n }));\n }\n\n // The CTA is the link AFTER the table, not merely the first link in the\n // section — the description may now carry its own inline links, and\n // `firstLink(parts)` would promote one of those to the CTA button.\n const lastTableIndex = parts.map((p) => p.type).lastIndexOf('table');\n const link = firstLink(\n lastTableIndex >= 0 ? parts.slice(lastTableIndex + 1) : parts,\n );\n const ctaText = link?.text || undefined;\n const ctaHref = link?.href || undefined;\n\n // Filter out rows where all values are empty (e.g. trailing non-table text parsed as a row)\n const keptRow = rawValueRows.map((raw) => raw.some((v) => !isBlankCell(v)));\n const filteredRows = rows.filter((_, i) => keptRow[i]);\n const filteredRawRows = rawValueRows.filter((_, i) => keptRow[i]);\n const droppedCount = rows.length - filteredRows.length;\n if (droppedCount > 0) {\n context?.reportDiagnostic?.(\n DIAGNOSTIC_TYPES.ITEMS_DROPPED,\n `comparison: ${droppedCount} row(s) dropped (all values empty)`,\n );\n }\n\n // A column blank in every row is a side of the comparison the writer had no\n // facts for — it renders as a full column of dashes next to a populated one,\n // which reads as a real answer and is not one. Half a comparison is worse\n // than none, so drop the whole section. (No rows left at all lands here too:\n // every column is vacuously blank.)\n const blankColumns = columnLabels\n .map((_, col) => col)\n .filter((col) =>\n filteredRawRows.every((raw) => isBlankCell(raw[col])),\n );\n if (columnLabels.length > 0 && blankColumns.length > 0) {\n context?.reportDiagnostic?.(\n DIAGNOSTIC_TYPES.SECTION_REJECTED,\n `comparison: column(s) ${blankColumns\n .map((c) => columnLabels[c] || `#${c + 1}`)\n .join(', ')} blank across all ${filteredRawRows.length} row(s) — section dropped`,\n );\n return DROP_SECTION;\n }\n\n return {\n title,\n description,\n columnLabels,\n columns,\n rows: filteredRows,\n featureColumnLabel,\n ctaText,\n ctaHref,\n };\n }\n}\n"],"mappings":";AAAA,SACEA,WAAW,EACXC,iBAAiB,EACjBC,SAAS,EACTC,eAAe,QACV,eAAe;AACtB,SAASC,cAAc,QAAmB,mBAAmB;AAa7D,SAASC,YAAY,QAAQ,uBAAuB;AACpD,SAASC,gBAAgB,QAAQ,oBAAoB;;AAErD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASC,WAAWA,CAACC,GAAuB,EAAW;EACrD,MAAMC,CAAC,GAAG,CAACD,GAAG,IAAI,EAAE,EAAEE,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;EAC1C;EACA,OAAOF,CAAC,KAAK,EAAE,IAAIA,CAAC,KAAK,KAAK,IAAI,YAAY,CAACG,IAAI,CAACH,CAAC,CAAC;AACxD;AAEA,OAAO,MAAMI,2BAA2B,CAExC;EAAAC,YAAA;IAAAC,eAAA,sBACgB,YAAY;IAC1B;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IAAAA,eAAA,mBACW,CACT,8GAA8G,CAC/G;IAAAA,eAAA,mBAE+B;MAC9BC,KAAK,EAAE,YAAY;MACnBC,YAAY,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;MACtCC,IAAI,EAAE,CACJ;QAAEC,OAAO,EAAE,OAAO;QAAEC,MAAM,EAAE,CAAC,KAAK,EAAE,KAAK;MAAE,CAAC,EAC5C;QAAED,OAAO,EAAE,SAAS;QAAEC,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK;MAAE,CAAC;IAEpD,CAAC;IAAAL,eAAA,mBAEiD,CAChD;MACEM,QAAQ,EAAE;AAChB;AACA;AACA;AACA;AACA;AACA,0BAA0B;MACpBC,QAAQ,EAAE;QACRN,KAAK,EAAE,eAAe;QACtBO,kBAAkB,EAAE,SAAS;QAC7BN,YAAY,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC;QAC9BC,IAAI,EAAE,CACJ;UAAEC,OAAO,EAAE,OAAO;UAAEC,MAAM,EAAE,CAAC,GAAG,EAAE,WAAW;QAAE,CAAC,EAChD;UAAED,OAAO,EAAE,SAAS;UAAEC,MAAM,EAAE,CAAC,OAAO,EAAE,KAAK;QAAE,CAAC;MAEpD;IACF,CAAC,EACD;MACEC,QAAQ,EAAE;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;MACjBC,QAAQ,EAAE;QACRN,KAAK,EAAE,qBAAqB;QAC5BQ,WAAW,EAAE,yDAAyD;QACtED,kBAAkB,EAAE,SAAS;QAC7BN,YAAY,EAAE,CAAC,cAAc,EAAE,YAAY,CAAC;QAC5CC,IAAI,EAAE,CACJ;UAAEC,OAAO,EAAE,SAAS;UAAEC,MAAM,EAAE,CAAC,KAAK,EAAE,OAAO;QAAE,CAAC,EAChD;UAAED,OAAO,EAAE,OAAO;UAAEC,MAAM,EAAE,CAAC,WAAW,EAAE,GAAG;QAAE,CAAC,EAChD;UAAED,OAAO,EAAE,SAAS;UAAEC,MAAM,EAAE,CAAC,eAAe,EAAE,YAAY;QAAE,CAAC,CAChE;QACDK,OAAO,EAAE,aAAa;QACtBC,OAAO,EAAE;MACX;IACF,CAAC,CACF;EAAA;EAEDC,KAAKA,CACHC,KAAa,EACbC,OAAsB,EACa;IAAA,IAAAC,YAAA;IACnC,MAAMd,KAAK,GACThB,WAAW,CAAC4B,KAAK,EAAE,CAAC,CAAC,IACrB5B,WAAW,CAAC4B,KAAK,EAAE,CAAC,CAAC,IACrB5B,WAAW,CAAC4B,KAAK,EAAE,CAAC,CAAC,IACrB,YAAY;IACd,MAAMJ,WAAW,GAAGvB,iBAAiB,CAAC2B,KAAK,CAAC,IAAIG,SAAS;;IAEzD;IACA,MAAMC,UAAU,GAAG5B,cAAc,CAAOwB,KAAK,EAAE,OAAO,CAAC;IACvD,MAAMK,SAAS,IAAAH,YAAA,GAAGE,UAAU,CAAC,CAAC,CAAC,qBAAbF,YAAA,CAAeI,IASpB;IAEb,IAAIjB,YAAsB;IAC1B,IAAIkB,OAAuC;IAC3C,IAAIZ,kBAAsC;IAC1C,IAAIL,IAAqB;IACzB;IACA,IAAIkB,YAAwB;IAE5B,IAAI,CAAAH,SAAS,oBAATA,SAAS,CAAEhB,YAAY,MAAKc,SAAS,EAAE;MACzC;MACAd,YAAY,GAAGgB,SAAS,CAAChB,YAAY;MACrCkB,OAAO,GAAGF,SAAS,CAACE,OAAO;MAC3BZ,kBAAkB,GAAGU,SAAS,CAACV,kBAAkB,IAAIQ,SAAS;MAC9DK,YAAY,GAAG,CAACH,SAAS,CAACf,IAAI,IAAI,EAAE,EAAEmB,GAAG,CAAEC,GAAG,IAAKA,GAAG,CAAClB,MAAM,CAAC;MAC9DF,IAAI,GAAG,CAACe,SAAS,CAACf,IAAI,IAAI,EAAE,EAAEmB,GAAG,CAAEC,GAAG,KAAM;QAC1CnB,OAAO,EAAEmB,GAAG,CAACnB,OAAO;QACpB,IAAImB,GAAG,CAACC,QAAQ,GAAG;UAAEA,QAAQ,EAAED,GAAG,CAACC;QAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QACnDnB,MAAM,EAAEkB,GAAG,CAAClB,MAAM,CAACiB,GAAG,CAAClC,eAAe;MACxC,CAAC,CAAC,CAAC;IACL,CAAC,MAAM;MACL;MACA,MAAMqC,UAAU,GAAG,CAAAP,SAAS,oBAATA,SAAS,CAAEQ,OAAO,KAAI,EAAE;MAC3C,MAAMC,OAAO,GAAG,CAACT,SAAS,oBAATA,SAAS,CAAUf,IAAI,KAAI,EAAE;MAC9CK,kBAAkB,GAAGiB,UAAU,CAAC,CAAC,CAAC,IAAIT,SAAS;MAC/Cd,YAAY,GAAGuB,UAAU,CAACG,KAAK,CAAC,CAAC,CAAC;MAClCR,OAAO,GAAGlB,YAAY,CAACoB,GAAG,CAAEO,KAAK,KAAM;QAAEA;MAAM,CAAC,CAAC,CAAC;MAClDR,YAAY,GAAGM,OAAO,CAACL,GAAG,CAAEC,GAAa,IAAKA,GAAG,CAACK,KAAK,CAAC,CAAC,CAAC,CAAC;MAC3DzB,IAAI,GAAGwB,OAAO,CAACL,GAAG,CAAEC,GAAa,KAAM;QACrCnB,OAAO,EAAEmB,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE;QACrBlB,MAAM,EAAEkB,GAAG,CAACK,KAAK,CAAC,CAAC,CAAC,CAACN,GAAG,CAAClC,eAAe;MAC1C,CAAC,CAAC,CAAC;IACL;;IAEA;IACA;IACA;IACA,MAAM0C,cAAc,GAAGjB,KAAK,CAACS,GAAG,CAAES,CAAC,IAAKA,CAAC,CAACC,IAAI,CAAC,CAACC,WAAW,CAAC,OAAO,CAAC;IACpE,MAAMC,IAAI,GAAG/C,SAAS,CACpB2C,cAAc,IAAI,CAAC,GAAGjB,KAAK,CAACe,KAAK,CAACE,cAAc,GAAG,CAAC,CAAC,GAAGjB,KAC1D,CAAC;IACD,MAAMH,OAAO,GAAG,CAAAwB,IAAI,oBAAJA,IAAI,CAAEC,IAAI,KAAInB,SAAS;IACvC,MAAML,OAAO,GAAG,CAAAuB,IAAI,oBAAJA,IAAI,CAAEE,IAAI,KAAIpB,SAAS;;IAEvC;IACA,MAAMqB,OAAO,GAAGhB,YAAY,CAACC,GAAG,CAAE7B,GAAG,IAAKA,GAAG,CAAC6C,IAAI,CAAE5C,CAAC,IAAK,CAACF,WAAW,CAACE,CAAC,CAAC,CAAC,CAAC;IAC3E,MAAM6C,YAAY,GAAGpC,IAAI,CAACqC,MAAM,CAAC,CAACC,CAAC,EAAEC,CAAC,KAAKL,OAAO,CAACK,CAAC,CAAC,CAAC;IACtD,MAAMC,eAAe,GAAGtB,YAAY,CAACmB,MAAM,CAAC,CAACC,CAAC,EAAEC,CAAC,KAAKL,OAAO,CAACK,CAAC,CAAC,CAAC;IACjE,MAAME,YAAY,GAAGzC,IAAI,CAAC0C,MAAM,GAAGN,YAAY,CAACM,MAAM;IACtD,IAAID,YAAY,GAAG,CAAC,EAAE;MACpB9B,OAAO,YAAPA,OAAO,CAAEgC,gBAAgB,YAAzBhC,OAAO,CAAEgC,gBAAgB,CACvBvD,gBAAgB,CAACwD,aAAa,EAC9B,eAAeH,YAAY,oCAC7B,CAAC;IACH;;IAEA;IACA;IACA;IACA;IACA;IACA,MAAMI,YAAY,GAAG9C,YAAY,CAC9BoB,GAAG,CAAC,CAACmB,CAAC,EAAEQ,GAAG,KAAKA,GAAG,CAAC,CACpBT,MAAM,CAAES,GAAG,IACVN,eAAe,CAACO,KAAK,CAAEzD,GAAG,IAAKD,WAAW,CAACC,GAAG,CAACwD,GAAG,CAAC,CAAC,CACtD,CAAC;IACH,IAAI/C,YAAY,CAAC2C,MAAM,GAAG,CAAC,IAAIG,YAAY,CAACH,MAAM,GAAG,CAAC,EAAE;MACtD/B,OAAO,YAAPA,OAAO,CAAEgC,gBAAgB,YAAzBhC,OAAO,CAAEgC,gBAAgB,CACvBvD,gBAAgB,CAAC4D,gBAAgB,EACjC,yBAAyBH,YAAY,CAClC1B,GAAG,CAAE8B,CAAC,IAAKlD,YAAY,CAACkD,CAAC,CAAC,IAAI,IAAIA,CAAC,GAAG,CAAC,EAAE,CAAC,CAC1CC,IAAI,CAAC,IAAI,CAAC,qBAAqBV,eAAe,CAACE,MAAM,2BAC1D,CAAC;MACD,OAAOvD,YAAY;IACrB;IAEA,OAAO;MACLW,KAAK;MACLQ,WAAW;MACXP,YAAY;MACZkB,OAAO;MACPjB,IAAI,EAAEoC,YAAY;MAClB/B,kBAAkB;MAClBE,OAAO;MACPC;IACF,CAAC;EACH;AACF","ignoreList":[]}
@@ -36,8 +36,23 @@ export class NextStepsSectionDefinition {
36
36
  constructor() {
37
37
  _defineProperty(this, "sectionType", 'nextSteps');
38
38
  _defineProperty(this, "patterns", [
39
- // Framing sentence (`t?`) then one chip per bullet — the authored shape.
40
- '(html_comment[section^="next"] | html_comment[semantic^="next"]) > h2 > image? > t? > list{item[1-]:(icon | t)* > (t? > link)+}',
39
+ // Framing sentence then one chip per bullet — the authored shape. The
40
+ // framing slot is `(t | link)*`, not `t?`, because a paragraph is unwrapped
41
+ // into its inline nodes: `Questions? Email support@shop.example for help.`
42
+ // arrives as `t link t` (GFM autolinks a bare email) and so does an
43
+ // authored `[men's shoes](web5://ask/…)`. With `t?` the run ended at that
44
+ // `link`, this pattern failed, and the legacy pattern below claimed the
45
+ // section instead — turning the prose link into a chip and stranding the
46
+ // real chip list in the fallback as raw bullets.
47
+ //
48
+ // This does NOT steal the legacy pattern's inputs: the `list` here is
49
+ // mandatory, so a section with chips in the prose and no list still falls
50
+ // through. It does change one rare shape — prose that is nothing but links
51
+ // ALONGSIDE a chip list now matches here, and `proseBodyMarkdown` drops
52
+ // link-only paragraphs, so those links are dropped rather than rendered
53
+ // inline. That shape previously stranded the list entirely, so neither
54
+ // outcome was whole; this one at least renders the authored chips.
55
+ '(html_comment[section^="next"] | html_comment[semantic^="next"]) > h2 > image? > (t | link)* > list{item[1-]:(icon | t)* > (t? > link)+}',
41
56
  // Legacy inline shape: chips embedded in the prose. Still arrives from
42
57
  // sites whose next-steps prompt has not moved to the list shape.
43
58
  '(html_comment[section^="next"] | html_comment[semantic^="next"]) > h2 > image? > (t | link)+']);
@@ -1 +1 @@
1
- {"version":3,"names":["headingText","proseBodyMarkdown","extractListItemText","firstImageSrc","getPartsByType","getLinks","linkToMarkdown","link","_link$content","_link$meta","content","trim","meta","href","appendInlineToken","current","token","trimmed","test","inlineBodyMarkdown","parts","body","reduce","part","type","_part$meta","markdown","undefined","NextStepsSectionDefinition","constructor","_defineProperty","title","backgroundImage","steps","expected","parse","chipsInlineInBody","lists","length","list","item","_list$meta","items","_item$meta","_iconPart$meta","itemParts","iconPart","find","p","iconHint","contentFragments","push","_p$content","filter","Boolean","join","links","_link$content2","_link$meta2","text"],"sources":["../../../../src/component/componentDefinitions/NextStepsSectionDefinition.ts"],"sourcesContent":["import {\n headingText,\n proseBodyMarkdown,\n extractListItemText,\n firstImageSrc,\n} from './parse-utils';\nimport {\n getPartsByType,\n getLinks,\n type Part,\n type ListPart,\n type LinkPart,\n type IconPart,\n} from '../../parts/parts';\nimport type {\n NextStepsCompProps,\n NextStepsSectionComponent,\n SectionFixture,\n} from '../types';\nimport type { SectionDefinition } from '../section-definition';\n\nfunction linkToMarkdown(link: LinkPart): string {\n return `[${link.content?.trim() || ''}](${link.meta?.href || ''})`;\n}\n\nfunction appendInlineToken(current: string, token: string): string {\n const trimmed = token.trim();\n if (!trimmed) {\n return current;\n }\n if (!current) {\n return trimmed;\n }\n if (/^[,.;:!?)]/.test(trimmed)) {\n return `${current}${trimmed}`;\n }\n return `${current} ${trimmed}`;\n}\n\nfunction inlineBodyMarkdown(parts: Part[]): string | undefined {\n const body = parts.reduce((current, part) => {\n if (part.type === 'link') {\n return appendInlineToken(current, linkToMarkdown(part as LinkPart));\n }\n if (part.type === 'text' || part.type === 'richText') {\n const markdown = (part.meta?.markdown as string | undefined)?.trim();\n return appendInlineToken(current, markdown || part.content || '');\n }\n return current;\n }, '');\n\n return body || undefined;\n}\n\nexport class NextStepsSectionDefinition\n implements SectionDefinition<NextStepsSectionComponent>\n{\n sectionType = 'nextSteps' as const;\n patterns = [\n // Framing sentence (`t?`) then one chip per bullet — the authored shape.\n '(html_comment[section^=\"next\"] | html_comment[semantic^=\"next\"]) > h2 > image? > t? > list{item[1-]:(icon | t)* > (t? > link)+}',\n // Legacy inline shape: chips embedded in the prose. Still arrives from\n // sites whose next-steps prompt has not moved to the list shape.\n '(html_comment[section^=\"next\"] | html_comment[semantic^=\"next\"]) > h2 > image? > (t | link)+',\n ];\n\n defaults: NextStepsCompProps = {\n title: 'Next Steps',\n body: 'Where would you like to go next?',\n backgroundImage: undefined,\n steps: [{ content: '[Get started](/start)' }],\n };\n\n fixtures: SectionFixture<NextStepsCompProps>[] = [\n {\n markdown: `<!-- section:next-steps, semantic:next_steps -->\n\n## Find the right care for mature, sensitive skin\n\nWant to focus on rich hydrators and barrier builders?\n\n- [hydrating creams →](web5://ask/hydrating+creams+for+mature+skin)\n- [gentle resurfacing serums →](web5://ask/gentle+resurfacing+serums)`,\n expected: {\n title: 'Find the right care for mature, sensitive skin',\n body: 'Want to focus on rich hydrators and barrier builders?',\n steps: [\n {\n content:\n '[hydrating creams →](web5://ask/hydrating+creams+for+mature+skin)',\n },\n {\n content:\n '[gentle resurfacing serums →](web5://ask/gentle+resurfacing+serums)',\n },\n ],\n },\n },\n {\n markdown: `<!-- section: next_steps -->\n\n## Next Steps\n\n- Check out [Documentation](/docs)\n- Try [Examples](/examples)`,\n expected: {\n title: 'Next Steps',\n steps: [\n { content: 'Check out [Documentation](/docs)' },\n { content: 'Try [Examples](/examples)' },\n ],\n },\n },\n ];\n\n parse(parts: Part[]): NextStepsCompProps {\n const title = headingText(parts, 2) || 'Next Steps';\n const backgroundImage = firstImageSrc(parts);\n const steps: { content: string; iconHint?: string }[] = [];\n let body: string | undefined;\n let chipsInlineInBody = false;\n\n // Try list-based pattern first\n const lists = getPartsByType<ListPart>(parts, 'list');\n if (lists.length > 0) {\n // The framing sentence is the only top-level prose — list items live\n // under each list's meta.items, so this never picks up a chip.\n body = proseBodyMarkdown(parts) || undefined;\n\n for (const list of lists) {\n for (const item of list.meta?.items ?? []) {\n const itemParts = (item.meta?.parts ?? []) as Part[];\n\n const iconPart = itemParts.find((p) => p.type === 'icon') as\n | IconPart\n | undefined;\n const iconHint = (iconPart?.meta as { iconHint?: string })?.iconHint;\n\n const contentFragments: string[] = [];\n for (const p of itemParts) {\n if (p.type === 'link') {\n const link = p as LinkPart;\n contentFragments.push(linkToMarkdown(link));\n } else if (p.type === 'text' || p.type === 'richText') {\n contentFragments.push(p.content?.trim() || '');\n }\n }\n const content =\n contentFragments.filter(Boolean).join(' ') ||\n extractListItemText(item);\n if (content.trim()) {\n steps.push({\n content: content.trim(),\n ...(iconHint ? { iconHint } : {}),\n });\n }\n }\n }\n } else {\n body = inlineBodyMarkdown(parts);\n // body carries the chips as inline links — flag it so renderers show the\n // prose alone instead of repeating every chip as a row beneath it.\n chipsInlineInBody = Boolean(body);\n }\n\n // Fallback: inline links pattern\n if (steps.length === 0) {\n const links = getLinks(parts);\n for (const link of links) {\n const text = link.content?.trim();\n const href = link.meta?.href;\n if (text && href) {\n steps.push({ content: linkToMarkdown(link) });\n }\n }\n }\n\n return {\n title,\n ...(body ? { body } : {}),\n ...(chipsInlineInBody ? { chipsInlineInBody } : {}),\n ...(backgroundImage ? { backgroundImage } : {}),\n steps,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"names":["headingText","proseBodyMarkdown","extractListItemText","firstImageSrc","getPartsByType","getLinks","linkToMarkdown","link","_link$content","_link$meta","content","trim","meta","href","appendInlineToken","current","token","trimmed","test","inlineBodyMarkdown","parts","body","reduce","part","type","_part$meta","markdown","undefined","NextStepsSectionDefinition","constructor","_defineProperty","title","backgroundImage","steps","expected","parse","chipsInlineInBody","lists","length","list","item","_list$meta","items","_item$meta","_iconPart$meta","itemParts","iconPart","find","p","iconHint","contentFragments","push","_p$content","filter","Boolean","join","links","_link$content2","_link$meta2","text"],"sources":["../../../../src/component/componentDefinitions/NextStepsSectionDefinition.ts"],"sourcesContent":["import {\n headingText,\n proseBodyMarkdown,\n extractListItemText,\n firstImageSrc,\n} from './parse-utils';\nimport {\n getPartsByType,\n getLinks,\n type Part,\n type ListPart,\n type LinkPart,\n type IconPart,\n} from '../../parts/parts';\nimport type {\n NextStepsCompProps,\n NextStepsSectionComponent,\n SectionFixture,\n} from '../types';\nimport type { SectionDefinition } from '../section-definition';\n\nfunction linkToMarkdown(link: LinkPart): string {\n return `[${link.content?.trim() || ''}](${link.meta?.href || ''})`;\n}\n\nfunction appendInlineToken(current: string, token: string): string {\n const trimmed = token.trim();\n if (!trimmed) {\n return current;\n }\n if (!current) {\n return trimmed;\n }\n if (/^[,.;:!?)]/.test(trimmed)) {\n return `${current}${trimmed}`;\n }\n return `${current} ${trimmed}`;\n}\n\nfunction inlineBodyMarkdown(parts: Part[]): string | undefined {\n const body = parts.reduce((current, part) => {\n if (part.type === 'link') {\n return appendInlineToken(current, linkToMarkdown(part as LinkPart));\n }\n if (part.type === 'text' || part.type === 'richText') {\n const markdown = (part.meta?.markdown as string | undefined)?.trim();\n return appendInlineToken(current, markdown || part.content || '');\n }\n return current;\n }, '');\n\n return body || undefined;\n}\n\nexport class NextStepsSectionDefinition\n implements SectionDefinition<NextStepsSectionComponent>\n{\n sectionType = 'nextSteps' as const;\n patterns = [\n // Framing sentence then one chip per bullet — the authored shape. The\n // framing slot is `(t | link)*`, not `t?`, because a paragraph is unwrapped\n // into its inline nodes: `Questions? Email support@shop.example for help.`\n // arrives as `t link t` (GFM autolinks a bare email) and so does an\n // authored `[men's shoes](web5://ask/…)`. With `t?` the run ended at that\n // `link`, this pattern failed, and the legacy pattern below claimed the\n // section instead — turning the prose link into a chip and stranding the\n // real chip list in the fallback as raw bullets.\n //\n // This does NOT steal the legacy pattern's inputs: the `list` here is\n // mandatory, so a section with chips in the prose and no list still falls\n // through. It does change one rare shape — prose that is nothing but links\n // ALONGSIDE a chip list now matches here, and `proseBodyMarkdown` drops\n // link-only paragraphs, so those links are dropped rather than rendered\n // inline. That shape previously stranded the list entirely, so neither\n // outcome was whole; this one at least renders the authored chips.\n '(html_comment[section^=\"next\"] | html_comment[semantic^=\"next\"]) > h2 > image? > (t | link)* > list{item[1-]:(icon | t)* > (t? > link)+}',\n // Legacy inline shape: chips embedded in the prose. Still arrives from\n // sites whose next-steps prompt has not moved to the list shape.\n '(html_comment[section^=\"next\"] | html_comment[semantic^=\"next\"]) > h2 > image? > (t | link)+',\n ];\n\n defaults: NextStepsCompProps = {\n title: 'Next Steps',\n body: 'Where would you like to go next?',\n backgroundImage: undefined,\n steps: [{ content: '[Get started](/start)' }],\n };\n\n fixtures: SectionFixture<NextStepsCompProps>[] = [\n {\n markdown: `<!-- section:next-steps, semantic:next_steps -->\n\n## Find the right care for mature, sensitive skin\n\nWant to focus on rich hydrators and barrier builders?\n\n- [hydrating creams →](web5://ask/hydrating+creams+for+mature+skin)\n- [gentle resurfacing serums →](web5://ask/gentle+resurfacing+serums)`,\n expected: {\n title: 'Find the right care for mature, sensitive skin',\n body: 'Want to focus on rich hydrators and barrier builders?',\n steps: [\n {\n content:\n '[hydrating creams →](web5://ask/hydrating+creams+for+mature+skin)',\n },\n {\n content:\n '[gentle resurfacing serums →](web5://ask/gentle+resurfacing+serums)',\n },\n ],\n },\n },\n {\n markdown: `<!-- section: next_steps -->\n\n## Next Steps\n\n- Check out [Documentation](/docs)\n- Try [Examples](/examples)`,\n expected: {\n title: 'Next Steps',\n steps: [\n { content: 'Check out [Documentation](/docs)' },\n { content: 'Try [Examples](/examples)' },\n ],\n },\n },\n ];\n\n parse(parts: Part[]): NextStepsCompProps {\n const title = headingText(parts, 2) || 'Next Steps';\n const backgroundImage = firstImageSrc(parts);\n const steps: { content: string; iconHint?: string }[] = [];\n let body: string | undefined;\n let chipsInlineInBody = false;\n\n // Try list-based pattern first\n const lists = getPartsByType<ListPart>(parts, 'list');\n if (lists.length > 0) {\n // The framing sentence is the only top-level prose — list items live\n // under each list's meta.items, so this never picks up a chip.\n body = proseBodyMarkdown(parts) || undefined;\n\n for (const list of lists) {\n for (const item of list.meta?.items ?? []) {\n const itemParts = (item.meta?.parts ?? []) as Part[];\n\n const iconPart = itemParts.find((p) => p.type === 'icon') as\n | IconPart\n | undefined;\n const iconHint = (iconPart?.meta as { iconHint?: string })?.iconHint;\n\n const contentFragments: string[] = [];\n for (const p of itemParts) {\n if (p.type === 'link') {\n const link = p as LinkPart;\n contentFragments.push(linkToMarkdown(link));\n } else if (p.type === 'text' || p.type === 'richText') {\n contentFragments.push(p.content?.trim() || '');\n }\n }\n const content =\n contentFragments.filter(Boolean).join(' ') ||\n extractListItemText(item);\n if (content.trim()) {\n steps.push({\n content: content.trim(),\n ...(iconHint ? { iconHint } : {}),\n });\n }\n }\n }\n } else {\n body = inlineBodyMarkdown(parts);\n // body carries the chips as inline links — flag it so renderers show the\n // prose alone instead of repeating every chip as a row beneath it.\n chipsInlineInBody = Boolean(body);\n }\n\n // Fallback: inline links pattern\n if (steps.length === 0) {\n const links = getLinks(parts);\n for (const link of links) {\n const text = link.content?.trim();\n const href = link.meta?.href;\n if (text && href) {\n steps.push({ content: linkToMarkdown(link) });\n }\n }\n }\n\n return {\n title,\n ...(body ? { body } : {}),\n ...(chipsInlineInBody ? { chipsInlineInBody } : {}),\n ...(backgroundImage ? { backgroundImage } : {}),\n steps,\n };\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"ComparisonSectionDefinition.d.ts","sourceRoot":"","sources":["../../../../src/component/componentDefinitions/ComparisonSectionDefinition.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAEV,mBAAmB,EAEnB,0BAA0B,EAC1B,cAAc,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACZ,MAAM,uBAAuB,CAAC;AAmB/B,qBAAa,2BACX,YAAW,iBAAiB,CAAC,0BAA0B,CAAC;IAExD,WAAW,eAAyB;IACpC,QAAQ,WAEN;IAEF,QAAQ,EAAE,mBAAmB,CAO3B;IAEF,QAAQ,EAAE,cAAc,CAAC,mBAAmB,CAAC,EAAE,CA8C7C;IAEF,KAAK,CACH,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,CAAC,EAAE,YAAY,GACrB,mBAAmB,GAAG,WAAW;CAqGrC"}
1
+ {"version":3,"file":"ComparisonSectionDefinition.d.ts","sourceRoot":"","sources":["../../../../src/component/componentDefinitions/ComparisonSectionDefinition.ts"],"names":[],"mappings":"AAMA,OAAO,EAAkB,KAAK,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAEV,mBAAmB,EAEnB,0BAA0B,EAC1B,cAAc,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACZ,MAAM,uBAAuB,CAAC;AAmB/B,qBAAa,2BACX,YAAW,iBAAiB,CAAC,0BAA0B,CAAC;IAExD,WAAW,eAAyB;IAepC,QAAQ,WAEN;IAEF,QAAQ,EAAE,mBAAmB,CAO3B;IAEF,QAAQ,EAAE,cAAc,CAAC,mBAAmB,CAAC,EAAE,CA8C7C;IAEF,KAAK,CACH,KAAK,EAAE,IAAI,EAAE,EACb,OAAO,CAAC,EAAE,YAAY,GACrB,mBAAmB,GAAG,WAAW;CA0GrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"NextStepsSectionDefinition.d.ts","sourceRoot":"","sources":["../../../../src/component/componentDefinitions/NextStepsSectionDefinition.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,IAAI,EAIV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,kBAAkB,EAClB,yBAAyB,EACzB,cAAc,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAmC/D,qBAAa,0BACX,YAAW,iBAAiB,CAAC,yBAAyB,CAAC;IAEvD,WAAW,cAAwB;IACnC,QAAQ,WAMN;IAEF,QAAQ,EAAE,kBAAkB,CAK1B;IAEF,QAAQ,EAAE,cAAc,CAAC,kBAAkB,CAAC,EAAE,CAwC5C;IAEF,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,kBAAkB;CAsEzC"}
1
+ {"version":3,"file":"NextStepsSectionDefinition.d.ts","sourceRoot":"","sources":["../../../../src/component/componentDefinitions/NextStepsSectionDefinition.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,IAAI,EAIV,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,kBAAkB,EAClB,yBAAyB,EACzB,cAAc,EACf,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAmC/D,qBAAa,0BACX,YAAW,iBAAiB,CAAC,yBAAyB,CAAC;IAEvD,WAAW,cAAwB;IACnC,QAAQ,WAqBN;IAEF,QAAQ,EAAE,kBAAkB,CAK1B;IAEF,QAAQ,EAAE,cAAc,CAAC,kBAAkB,CAAC,EAAE,CAwC5C;IAEF,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,kBAAkB;CAsEzC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wix/web5-core",
3
3
  "license": "MIT",
4
- "version": "1.63.31",
4
+ "version": "1.63.32",
5
5
  "author": {
6
6
  "name": "tsachis",
7
7
  "email": "tsachis@wix.com"
@@ -100,5 +100,5 @@
100
100
  "wallaby": {
101
101
  "autoDetect": true
102
102
  },
103
- "falconPackageHash": "523f94109d3641d2438b8fd67c07456611f125cd752e25b892491a6f"
103
+ "falconPackageHash": "6772047e941dfd79375c77ef18fe92b3d7cc9881d44877f06e0c6fc9"
104
104
  }