slackmark 0.6.0 → 0.6.1

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.
@@ -0,0 +1,24 @@
1
+ import type { Nodes } from "mdast";
2
+ /**
3
+ * Plain text for a block that had to be flattened into a single text run.
4
+ *
5
+ * `mdast-util-to-string` concatenates every descendant with no separator, so a
6
+ * table collapses to "ab12" and sibling paragraphs run together as
7
+ * "para onepara two". Flattening is already flagged as a degradation; the text
8
+ * it leaves behind still has to be readable, so re-insert the separators the
9
+ * structure carried.
10
+ */
11
+ export declare function blockToPlainText(node: Nodes): string;
12
+ /** A link or image URL that flattening is about to discard. */
13
+ export interface FlattenedUrl {
14
+ readonly nodeType: "link" | "image";
15
+ readonly url: string;
16
+ }
17
+ /**
18
+ * Link and image URLs carried by a block that is about to be flattened.
19
+ * {@link blockToPlainText} keeps only labels and alt text, so callers must
20
+ * flag these before they disappear — silent omission is a bug even when the
21
+ * surrounding flattening is itself already flagged.
22
+ */
23
+ export declare function collectFlattenedUrls(node: unknown, into: FlattenedUrl[]): void;
24
+ //# sourceMappingURL=block-to-plain-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"block-to-plain-text.d.ts","sourceRoot":"","sources":["../../src/adapters/block-to-plain-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAGnC;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,CAmBpD;AAED,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,CAiB9E"}
@@ -1 +1 @@
1
- {"version":3,"file":"blockquote-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/blockquote-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,OAAO,CAAC;AAIrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAGzE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAYhE;;GAEG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IACnD,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAEzD;IAED,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAAC,SAAS,CAAC,CAezE;CACF"}
1
+ {"version":3,"file":"blockquote-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/blockquote-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,OAAO,CAAC;AAGrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAQzE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAYhE;;GAEG;AACH,qBAAa,iBAAkB,YAAW,WAAW;IACnD,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAEzD;IAED,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAAC,SAAS,CAAC,CAezE;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../../src/adapters/inline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiC,eAAe,EAAgB,MAAM,OAAO,CAAC;AAG1F,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EAEb,cAAc,EAEd,aAAa,EAEd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAYzE,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IACjD,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,EACrC,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,aAAkB,GAC5B,gBAAgB,CAiQlB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,MAAM,CAE7E;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAerD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,EACrC,GAAG,EAAE,iBAAiB,GACrB,MAAM,CAuCR;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAK9F;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,iBAAiB,GAAG,UAAU,CAUrF;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY/F;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAY9F;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,UAAU,GAAG,OAAO,GAC1B,MAAM,CAYR;AA0LD;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,aAAa,GACnB,aAAa,CAAC,cAAc,CAAC,GAAG,SAAS,CAI3C;AAED,gGAAgG;AAChG,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,EACrC,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAQT;AA4HD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAKnD"}
1
+ {"version":3,"file":"inline.d.ts","sourceRoot":"","sources":["../../src/adapters/inline.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiC,eAAe,EAAgB,MAAM,OAAO,CAAC;AAG1F,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EAEb,cAAc,EAEd,aAAa,EAEd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAYzE,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,cAAc,CAAC,CAAC;IACjD,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,EACrC,GAAG,EAAE,iBAAiB,EACtB,SAAS,GAAE,aAAkB,GAC5B,gBAAgB,CAiQlB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,GAAG,MAAM,CAE7E;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAerD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,EACrC,GAAG,EAAE,iBAAiB,GACrB,MAAM,CAuCR;AAsDD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAK9F;AAED,2EAA2E;AAC3E,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,iBAAiB,GAAG,UAAU,CAUrF;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAY/F;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,CAY9F;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,iBAAiB,EACtB,KAAK,EAAE,UAAU,GAAG,OAAO,GAC1B,MAAM,CAYR;AA0LD;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,aAAa,GACnB,aAAa,CAAC,cAAc,CAAC,GAAG,SAAS,CAI3C;AAED,gGAAgG;AAChG,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,aAAa,CAAC,eAAe,CAAC,EACrC,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAQT;AA8HD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAKnD"}
@@ -1 +1 @@
1
- {"version":3,"file":"list-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/list-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAA6B,WAAW,EAAE,MAAM,OAAO,CAAC;AAI1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AASzE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;GAEG;AACH,qBAAa,WAAY,YAAW,WAAW;IAC7C,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAKzD;IAED,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,iBAAiB,GAAG,aAAa,CAAC,SAAS,CAAC,CA2BxE;CACF;AAmBD,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAE9C"}
1
+ {"version":3,"file":"list-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/list-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAA6B,WAAW,EAAE,MAAM,OAAO,CAAC;AAG1E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAczE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;GAEG;AACH,qBAAa,WAAY,YAAW,WAAW;IAC7C,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAKzD;IAED,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,iBAAiB,GAAG,aAAa,CAAC,SAAS,CAAC,CA2BxE;CACF;AAmBD,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAE9C"}
@@ -1 +1 @@
1
- {"version":3,"file":"table-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/table-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,WAAW,EAAsC,MAAM,OAAO,CAAC;AAYxF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAWzE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;GAEG;AACH,qBAAa,YAAa,YAAW,WAAW;IAC9C,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAEzD;IAED,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,iBAAiB,GAAG,aAAa,CAAC,SAAS,CAAC,CAqFxE;CACF"}
1
+ {"version":3,"file":"table-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/table-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,WAAW,EAAsC,MAAM,OAAO,CAAC;AAYxF,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAazE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;GAEG;AACH,qBAAa,YAAa,YAAW,WAAW;IAC9C,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAEzD;IAED,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,iBAAiB,GAAG,aAAa,CAAC,SAAS,CAAC,CAqFxE;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"task-list-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/task-list-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,OAAO,CAAC;AAUzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAIzE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;GAEG;AACH,qBAAa,eAAgB,YAAW,WAAW;IACjD,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAEzD;IAED,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAAC,SAAS,CAAC,CA0BzE;CACF"}
1
+ {"version":3,"file":"task-list-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/task-list-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,OAAO,CAAC;AAUzD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AAKzE,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhE;;GAEG;AACH,qBAAa,eAAgB,YAAW,WAAW;IACjD,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAEzD;IAED,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,aAAa,CAAC,SAAS,CAAC,CA4BzE;CACF"}
@@ -30,12 +30,20 @@ export declare const TABLE_MAX_ROWS = 100;
30
30
  export declare const TABLE_MAX_COLS = 20;
31
31
  /** https://docs.slack.dev/reference/block-kit/blocks/table-block */
32
32
  export declare const TABLE_CELL_CHARS_MAX = 10000;
33
+ /**
34
+ * `raw_text.text` / `raw_number.text` declare `minLength: 1`; a blank markdown
35
+ * cell must be padded or Slack rejects the payload with `invalid_blocks`.
36
+ * https://docs.slack.dev/reference/block-kit/blocks/data-table-block
37
+ */
38
+ export declare const TABLE_CELL_MIN_CHARS = 1;
33
39
  /** Spec decision: prefer `table` up to this many rows (incl. header). */
34
40
  export declare const TABLE_PREFERRED_MAX_ROWS = 50;
35
41
  /** https://docs.slack.dev/reference/block-kit/blocks/data-table-block */
36
42
  export declare const DATA_TABLE_MAX_DATA_ROWS = 200;
37
43
  /** https://docs.slack.dev/reference/block-kit/blocks/data-table-block */
38
44
  export declare const DATA_TABLE_CELL_CHARS_MAX = 20000;
45
+ /** Spec decision: caption is required but unbounded in Slack's docs; match header. */
46
+ export declare const DATA_TABLE_CAPTION_MAX_CHARS = 150;
39
47
  /** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */
40
48
  export declare const CHART_TITLE_MAX_CHARS = 50;
41
49
  /** https://docs.slack.dev/reference/block-kit/blocks/data-visualization-block */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uCAAuC;AACvC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,qEAAqE;AACrE,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,yEAAyE;AACzE,eAAO,MAAM,wBAAwB,EAAE,MAAyB,CAAC;AAEjE,4EAA4E;AAC5E,eAAO,MAAM,iCAAiC,MAAM,CAAC;AAErD,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,uEAAuE;AACvE,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAEpD,oEAAoE;AACpE,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,oEAAoE;AACpE,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC,oEAAoE;AACpE,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAE3C,yEAAyE;AACzE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,yEAAyE;AACzE,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,yEAAyE;AACzE,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAEpD,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAEpD,+DAA+D;AAC/D,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,wEAAwE;AACxE,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,gEAAgE;AAChE,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,eAAO,MAAM,QAAQ,WAAM,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uCAAuC;AACvC,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAE3C,qEAAqE;AACrE,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC,qEAAqE;AACrE,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,oEAAoE;AACpE,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAExC,yEAAyE;AACzE,eAAO,MAAM,wBAAwB,EAAE,MAAyB,CAAC;AAEjE,4EAA4E;AAC5E,eAAO,MAAM,iCAAiC,MAAM,CAAC;AAErD,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAE3C,sEAAsE;AACtE,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,uEAAuE;AACvE,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAEpD,oEAAoE;AACpE,eAAO,MAAM,cAAc,MAAM,CAAC;AAElC,oEAAoE;AACpE,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC,oEAAoE;AACpE,eAAO,MAAM,oBAAoB,QAAS,CAAC;AAE3C;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,IAAI,CAAC;AAEtC,yEAAyE;AACzE,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,yEAAyE;AACzE,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,yEAAyE;AACzE,eAAO,MAAM,yBAAyB,QAAS,CAAC;AAEhD,sFAAsF;AACtF,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAEhD,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,iFAAiF;AACjF,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAExC,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,KAAK,CAAC;AAErC,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,iFAAiF;AACjF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC;;;GAGG;AACH,eAAO,MAAM,kCAAkC,IAAI,CAAC;AAEpD,2EAA2E;AAC3E,eAAO,MAAM,6BAA6B,QAAS,CAAC;AAEpD,+DAA+D;AAC/D,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAEzC,wEAAwE;AACxE,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,gEAAgE;AAChE,eAAO,MAAM,yBAAyB,KAAK,CAAC;AAE5C,eAAO,MAAM,QAAQ,WAAM,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"slackmark-converter.d.ts","sourceRoot":"","sources":["../../src/converter/slackmark-converter.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAiBvE,OAAO,KAAK,EACV,wBAAwB,EACxB,gBAAgB,EAChB,cAAc,EAEd,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAKrB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;CACzC;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAEhD,YAAY,IAAI,EAAE,sBAAsB,EAMvC;IAED;;;;OAIG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwBnF;IAED;;;OAGG;IACG,kBAAkB,CACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GAAG,SAAS,EACnC,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,GAAE,gBAAkD,GAC3D,OAAO,CAAC,gBAAgB,CAAC,CAc3B;IAED;;OAEG;IACG,iBAAiB,CACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,wBAAwB,CAAC,CAYnC;IAED;;OAEG;IACG,4BAA4B,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GAAG,SAAS,EACnC,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,GAAE,gBAAkD,GAC3D,OAAO,CAAC,wBAAwB,CAAC,CAQnC;YAEa,qBAAqB;IAwInC,OAAO,CAAC,oBAAoB;CA8D7B"}
1
+ {"version":3,"file":"slackmark-converter.d.ts","sourceRoot":"","sources":["../../src/converter/slackmark-converter.ts"],"names":[],"mappings":"AAUA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAiBvE,OAAO,KAAK,EACV,wBAAwB,EACxB,gBAAgB,EAChB,cAAc,EAEd,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EACjB,MAAM,aAAa,CAAC;AAKrB,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;CACzC;AAED;;GAEG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAoB;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAiB;IAEhD,YAAY,IAAI,EAAE,sBAAsB,EAMvC;IAED;;;;OAIG;IACG,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAwBnF;IAED;;;OAGG;IACG,kBAAkB,CACtB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GAAG,SAAS,EACnC,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,GAAE,gBAAkD,GAC3D,OAAO,CAAC,gBAAgB,CAAC,CAiB3B;IAED;;OAEG;IACG,iBAAiB,CACrB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,wBAAwB,CAAC,CAYnC;IAED;;OAEG;IACG,4BAA4B,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,GAAG,SAAS,EACnC,SAAS,EAAE,gBAAgB,EAC3B,QAAQ,GAAE,gBAAkD,GAC3D,OAAO,CAAC,wBAAwB,CAAC,CAQnC;YAEa,qBAAqB;IAqJnC,OAAO,CAAC,oBAAoB;CA8D7B"}
package/dist/index.js CHANGED
@@ -1370,6 +1370,38 @@ function parseNumberList(inner) {
1370
1370
  return inner.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((s) => Number(s));
1371
1371
  }
1372
1372
  //#endregion
1373
+ //#region src/adapters/block-to-plain-text.ts
1374
+ /**
1375
+ * Plain text for a block that had to be flattened into a single text run.
1376
+ *
1377
+ * `mdast-util-to-string` concatenates every descendant with no separator, so a
1378
+ * table collapses to "ab12" and sibling paragraphs run together as
1379
+ * "para onepara two". Flattening is already flagged as a degradation; the text
1380
+ * it leaves behind still has to be readable, so re-insert the separators the
1381
+ * structure carried.
1382
+ */
1383
+ function blockToPlainText(node) {
1384
+ if (node.type === "table") return node.children.map((row) => row.children.map((cell) => toString(cell)).join(" | ")).join("\n");
1385
+ if (node.type === "list") return node.children.map((item) => `• ${blockToPlainText(item)}`).join("\n");
1386
+ if (node.type === "blockquote" || node.type === "listItem" || node.type === "footnoteDefinition") return node.children.map((child) => blockToPlainText(child)).join("\n");
1387
+ return toString(node);
1388
+ }
1389
+ /**
1390
+ * Link and image URLs carried by a block that is about to be flattened.
1391
+ * {@link blockToPlainText} keeps only labels and alt text, so callers must
1392
+ * flag these before they disappear — silent omission is a bug even when the
1393
+ * surrounding flattening is itself already flagged.
1394
+ */
1395
+ function collectFlattenedUrls(node, into) {
1396
+ if (node === null || typeof node !== "object") return;
1397
+ const record = node;
1398
+ if ((record.type === "link" || record.type === "image") && typeof record.url === "string") into.push({
1399
+ nodeType: record.type,
1400
+ url: record.url
1401
+ });
1402
+ if (record.children !== void 0) for (const child of record.children) collectFlattenedUrls(child, into);
1403
+ }
1404
+ //#endregion
1373
1405
  //#region src/budget/operation-scope.ts
1374
1406
  function createOperationScope(options, stage) {
1375
1407
  validateOperationOptions(options);
@@ -1734,6 +1766,7 @@ var SlackMarkConverter = class {
1734
1766
  * operation context. The returned promise tracks underlying conversion work.
1735
1767
  */
1736
1768
  async convertWithContext(markdown, options, operation, receipts = new RecordingReceiptCollector()) {
1769
+ resolveConfig(this.defaultOptions, options, operation);
1737
1770
  const multi = await this.convertToMessagesWithContext(markdown, {
1738
1771
  ...options,
1739
1772
  overflow: OverflowMode.Degrade
@@ -1820,6 +1853,17 @@ var SlackMarkConverter = class {
1820
1853
  footnoteOrder.forEach((id, i) => footnoteNumbers.set(id, i + 1));
1821
1854
  const footnoteBlocks = buildFootnoteBlocks(footnoteOrder.map((id, i) => {
1822
1855
  const def = footnotes.get(id);
1856
+ if (def !== void 0) {
1857
+ const dropped = [];
1858
+ collectFlattenedUrls(def, dropped);
1859
+ for (const { nodeType, url } of dropped) degradations.add({
1860
+ nodeType,
1861
+ from: url,
1862
+ to: "label_only",
1863
+ reason: "Footnote body renders as plain context text; URL dropped",
1864
+ path: `footnote[${String(i + 1)}]`
1865
+ });
1866
+ }
1823
1867
  return {
1824
1868
  n: i + 1,
1825
1869
  text: def !== void 0 ? footnoteBodyText(def, footnoteNumbers).trim() : id
@@ -2026,6 +2070,19 @@ function collectRefs(tree, degradations) {
2026
2070
  };
2027
2071
  }
2028
2072
  /**
2073
+ * Separator inserted between the children of a flattened footnote body node.
2074
+ * Without these, sibling paragraphs and table cells run together as
2075
+ * "para onepara two" / "ab12".
2076
+ */
2077
+ const FOOTNOTE_CHILD_SEPARATORS = /* @__PURE__ */ new Map([
2078
+ ["footnoteDefinition", "\n"],
2079
+ ["blockquote", "\n"],
2080
+ ["list", "\n"],
2081
+ ["listItem", "\n"],
2082
+ ["table", "\n"],
2083
+ ["tableRow", " | "]
2084
+ ]);
2085
+ /**
2029
2086
  * Footnote definition body as plain text with nested footnote references
2030
2087
  * rendered as their `[n]` markers (mdast-util-to-string drops them entirely).
2031
2088
  */
@@ -2041,7 +2098,8 @@ function footnoteBodyText(node, numbers) {
2041
2098
  if (record.children !== void 0) {
2042
2099
  const parts = [];
2043
2100
  for (const child of record.children) parts.push(footnoteBodyText(child, numbers));
2044
- return parts.join("");
2101
+ const separator = record.type !== void 0 ? FOOTNOTE_CHILD_SEPARATORS.get(record.type) ?? "" : "";
2102
+ return parts.join(separator);
2045
2103
  }
2046
2104
  return "";
2047
2105
  }
@@ -2353,6 +2411,43 @@ function countHoistableImages(nodes, ctx) {
2353
2411
  }
2354
2412
  return count;
2355
2413
  }
2414
+ /**
2415
+ * Record images a link label swallows. Slack link elements carry plain text, and hoisting
2416
+ * would detach the image from its link, so only the alt text survives.
2417
+ */
2418
+ function flagImagesLostInLabel(nodes, ctx) {
2419
+ for (const node of nodes) switch (node.type) {
2420
+ case "image":
2421
+ addImageLostInLabel(node.url, ctx);
2422
+ break;
2423
+ case "imageReference":
2424
+ addImageLostInLabel(ctx.definitions.get(node.identifier.toLowerCase())?.url ?? node.identifier, ctx);
2425
+ break;
2426
+ case "strong":
2427
+ case "emphasis":
2428
+ case "delete":
2429
+ flagImagesLostInLabel(node.children, ctx);
2430
+ break;
2431
+ case "text":
2432
+ case "inlineCode":
2433
+ case "break":
2434
+ case "link":
2435
+ case "linkReference":
2436
+ case "footnoteReference":
2437
+ case "html":
2438
+ case "inlineMath": break;
2439
+ default: break;
2440
+ }
2441
+ }
2442
+ function addImageLostInLabel(url, ctx) {
2443
+ ctx.degradations.add({
2444
+ nodeType: "image",
2445
+ from: "image",
2446
+ to: "text",
2447
+ reason: `Image nested in a link is dropped; only its alt text survives (${url})`,
2448
+ path: ctx.path
2449
+ });
2450
+ }
2356
2451
  function truncateLabel(label, max) {
2357
2452
  if (label.length <= max) return {
2358
2453
  text: label,
@@ -2639,6 +2734,7 @@ function reassembleSlackLabeledLink(work, i, style) {
2639
2734
  function emitLink(node, ctx, style) {
2640
2735
  const url = node.url;
2641
2736
  const text = phrasingToPlain(node.children);
2737
+ flagImagesLostInLabel(node.children, ctx);
2642
2738
  const pipeIndex = url.indexOf("|");
2643
2739
  if (pipeIndex > 0 && HTTP_URL_RE.test(url) && text === url) {
2644
2740
  const realUrl = url.slice(0, pipeIndex);
@@ -2673,11 +2769,14 @@ function emitLink(node, ctx, style) {
2673
2769
  }
2674
2770
  function emitLinkReference(node, ctx, style) {
2675
2771
  const def = ctx.definitions.get(node.identifier.toLowerCase());
2676
- if (def === void 0) return [{
2677
- type: "text",
2678
- text: phrasingToPlain(node.children) || node.identifier,
2679
- style: styleOrUndefined(style)
2680
- }];
2772
+ if (def === void 0) {
2773
+ flagImagesLostInLabel(node.children, ctx);
2774
+ return [{
2775
+ type: "text",
2776
+ text: phrasingToPlain(node.children) || node.identifier,
2777
+ style: styleOrUndefined(style)
2778
+ }];
2779
+ }
2681
2780
  return emitLink({
2682
2781
  type: "link",
2683
2782
  url: def.url,
@@ -2914,13 +3013,14 @@ function flattenQuote(quote, ctx) {
2914
3013
  reason: "Nested list inside blockquote flattened",
2915
3014
  path: ctx.path
2916
3015
  });
3016
+ flagFlattenedUrls$1(child, ctx);
2917
3017
  if (parts.length > 0) parts.push({
2918
3018
  type: "text",
2919
3019
  text: "\n"
2920
3020
  });
2921
3021
  for (const item of child.children) parts.push({
2922
3022
  type: "text",
2923
- text: `• ${toString(item)}\n`
3023
+ text: `• ${blockToPlainText(item)}\n`
2924
3024
  });
2925
3025
  } else if (child.type === "code") {
2926
3026
  ctx.degradations.add({
@@ -2947,13 +3047,14 @@ function flattenQuote(quote, ctx) {
2947
3047
  reason: "Nested block inside blockquote flattened",
2948
3048
  path: ctx.path
2949
3049
  });
3050
+ flagFlattenedUrls$1(child, ctx);
2950
3051
  if (parts.length > 0) parts.push({
2951
3052
  type: "text",
2952
3053
  text: "\n"
2953
3054
  });
2954
3055
  parts.push({
2955
3056
  type: "text",
2956
- text: toString(child)
3057
+ text: blockToPlainText(child)
2957
3058
  });
2958
3059
  }
2959
3060
  return parts.length > 0 ? parts : [{
@@ -2961,6 +3062,18 @@ function flattenQuote(quote, ctx) {
2961
3062
  text: " "
2962
3063
  }];
2963
3064
  }
3065
+ /** Flattening keeps labels and alt text only; every dropped URL gets a record. */
3066
+ function flagFlattenedUrls$1(node, ctx) {
3067
+ const dropped = [];
3068
+ collectFlattenedUrls(node, dropped);
3069
+ for (const { nodeType, url } of dropped) ctx.degradations.add({
3070
+ nodeType,
3071
+ from: url,
3072
+ to: "label_only",
3073
+ reason: "Block flattened into quote text; URL dropped",
3074
+ path: ctx.path
3075
+ });
3076
+ }
2964
3077
  //#endregion
2965
3078
  //#region src/slack/slack-upload-error.ts
2966
3079
  /** See the brand rationale in `errors.ts`: this class is bundled into more than one entry. */
@@ -3863,11 +3976,26 @@ function emitListItem(item, ctx) {
3863
3976
  reason: "Block child of list item flattened into text",
3864
3977
  path: ctx.path
3865
3978
  });
3866
- const text = toString(child);
3867
- if (text.length > 0) phrasing.push({
3868
- type: "text",
3869
- value: text
3979
+ const dropped = [];
3980
+ collectFlattenedUrls(child, dropped);
3981
+ for (const { nodeType, url } of dropped) ctx.degradations.add({
3982
+ nodeType,
3983
+ from: url,
3984
+ to: "label_only",
3985
+ reason: "Block flattened into list item text; URL dropped",
3986
+ path: ctx.path
3870
3987
  });
3988
+ const text = blockToPlainText(child);
3989
+ if (text.length > 0) {
3990
+ if (sawBlock) phrasing.push({
3991
+ type: "text",
3992
+ value: "\n"
3993
+ });
3994
+ phrasing.push({
3995
+ type: "text",
3996
+ value: text
3997
+ });
3998
+ }
3871
3999
  sawBlock = true;
3872
4000
  }
3873
4001
  const inline = emitPhrasing(phrasing, ctx);
@@ -4438,10 +4566,30 @@ function markdownThenAscii(table, cellChars, reason) {
4438
4566
  function buildTableBlock(table, ctx) {
4439
4567
  return {
4440
4568
  type: "table",
4441
- rows: table.children.map((row, rowIndex) => row.children.map((cell) => cellToSlack(cell, ctx, rowIndex === 0))),
4569
+ rows: buildRows(table, ctx, "table"),
4442
4570
  column_settings: columnSettings(table)
4443
4571
  };
4444
4572
  }
4573
+ /**
4574
+ * Emit every cell and flag the blanks that had to be padded to satisfy Slack's
4575
+ * `minLength: 1` on `raw_text`/`raw_number` text.
4576
+ */
4577
+ function buildRows(table, ctx, mode) {
4578
+ let padded = 0;
4579
+ const rows = table.children.map((row, rowIndex) => row.children.map((cell) => {
4580
+ const emitted = mode === "data_table" ? cellForDataTable(cell, ctx, rowIndex) : cellToSlack(cell, ctx, rowIndex === 0);
4581
+ if (emitted.type === "raw_text" && emitted.text === EMPTY_CELL_TEXT) padded += 1;
4582
+ return emitted;
4583
+ }));
4584
+ if (padded > 0) ctx.degradations.add({
4585
+ nodeType: "table",
4586
+ from: `${String(padded)} empty cells`,
4587
+ to: "single-space cells",
4588
+ reason: "Slack rejects empty table cell text; padded to one space",
4589
+ path: ctx.path
4590
+ });
4591
+ return rows;
4592
+ }
4445
4593
  function buildDataTable(table, ctx) {
4446
4594
  const captionRaw = ctx.precedingHeading !== void 0 && ctx.precedingHeading.length > 0 ? ctx.precedingHeading : "Table";
4447
4595
  const caption = sliceSurrogateSafe(captionRaw, 150);
@@ -4455,16 +4603,25 @@ function buildDataTable(table, ctx) {
4455
4603
  return {
4456
4604
  type: "data_table",
4457
4605
  caption,
4458
- rows: table.children.map((row, rowIndex) => row.children.map((cell) => cellForDataTable(cell, ctx, rowIndex))),
4606
+ rows: buildRows(table, ctx, "data_table"),
4459
4607
  page_size: 5,
4460
4608
  row_header_column_index: 0
4461
4609
  };
4462
4610
  }
4611
+ /**
4612
+ * Slack requires at least one character in every `raw_text`/`raw_number` cell
4613
+ * (`minLength: 1`), so a blank markdown cell renders as a single space.
4614
+ * https://docs.slack.dev/reference/block-kit/blocks/data-table-block
4615
+ */
4616
+ const EMPTY_CELL_TEXT = " ";
4617
+ function cellText(text) {
4618
+ return text.length >= 1 ? text : EMPTY_CELL_TEXT;
4619
+ }
4463
4620
  /** Slack forbids rich_text in data_table headers; keep emission and budget counting aligned. */
4464
4621
  function cellForDataTable(cell, ctx, rowIndex) {
4465
4622
  if (rowIndex === 0) return {
4466
4623
  type: "raw_text",
4467
- text: toString(cell)
4624
+ text: cellText(toString(cell))
4468
4625
  };
4469
4626
  return cellToSlack(cell, ctx, false);
4470
4627
  }
@@ -4483,7 +4640,7 @@ function cellToSlack(cell, ctx, header) {
4483
4640
  };
4484
4641
  return {
4485
4642
  type: "raw_text",
4486
- text: plainText
4643
+ text: cellText(plainText)
4487
4644
  };
4488
4645
  }
4489
4646
  return {
@@ -4571,7 +4728,8 @@ var TaskListAdapter = class {
4571
4728
  blocks: 1,
4572
4729
  markdownChars: md.length
4573
4730
  },
4574
- emit: () => {
4731
+ emit: (ctx) => {
4732
+ flagFlattenedUrls(list, ctx);
4575
4733
  return [{
4576
4734
  type: "markdown",
4577
4735
  text: md
@@ -4580,6 +4738,7 @@ var TaskListAdapter = class {
4580
4738
  }, {
4581
4739
  budget: { blocks: 1 },
4582
4740
  emit: (ctx) => {
4741
+ flagFlattenedUrls(list, ctx);
4583
4742
  ctx.degradations.add({
4584
4743
  nodeType: "list",
4585
4744
  from: "markdown.task_list",
@@ -4603,6 +4762,21 @@ function serializeTaskList(list, indent = 0) {
4603
4762
  }
4604
4763
  return lines.join("\n");
4605
4764
  }
4765
+ /**
4766
+ * Both task-list rungs render item content as plain text ({@link itemText}),
4767
+ * so a `[label](url)` or `![alt](url)` inside an item keeps only its label.
4768
+ */
4769
+ function flagFlattenedUrls(list, ctx) {
4770
+ const dropped = [];
4771
+ collectFlattenedUrls(list, dropped);
4772
+ for (const { nodeType, url } of dropped) ctx.degradations.add({
4773
+ nodeType,
4774
+ from: url,
4775
+ to: "label_only",
4776
+ reason: "Task list item rendered as plain text; URL dropped",
4777
+ path: ctx.path
4778
+ });
4779
+ }
4606
4780
  function itemText(item) {
4607
4781
  const parts = [];
4608
4782
  for (const child of item.children) if (child.type === "paragraph") parts.push(toString(child));
@@ -5080,7 +5254,12 @@ function validateTableCells(rows, path, colsMessage, issues) {
5080
5254
  });
5081
5255
  for (const [c, cell] of row.entries()) {
5082
5256
  chars += cellCharCount(cell);
5083
- if (cell.type === "rich_text") validateRichTextBlock(cell, `${path}.rows[${String(r)}][${String(c)}]`, issues);
5257
+ const cellPath = `${path}.rows[${String(r)}][${String(c)}]`;
5258
+ if (cell.type === "rich_text") validateRichTextBlock(cell, cellPath, issues);
5259
+ else if (cell.text.length < 1) issues.push({
5260
+ path: cellPath,
5261
+ message: "table cell text is empty"
5262
+ });
5084
5263
  }
5085
5264
  }
5086
5265
  return chars;