Skip to content

Commit c685139

Browse files
authored
feat: added new rule table-column-count (#392)
1 parent fbf8235 commit c685139

File tree

4 files changed

+398
-0
lines changed

4 files changed

+398
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export default defineConfig([
8686
| [`no-missing-label-refs`](./docs/rules/no-missing-label-refs.md) | Disallow missing label references | yes |
8787
| [`no-multiple-h1`](./docs/rules/no-multiple-h1.md) | Disallow multiple H1 headings in the same document | yes |
8888
| [`require-alt-text`](./docs/rules/require-alt-text.md) | Require alternative text for images | yes |
89+
| [`table-column-count`](./docs/rules/table-column-count.md) | Disallow data rows in a GitHub Flavored Markdown table from having more cells than the header row | yes |
8990
<!-- Rule Table End -->
9091

9192
**Note:** This plugin does not provide formatting rules. We recommend using a source code formatter such as [Prettier](https://prettier.io) for that purpose.

docs/rules/table-column-count.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# table-column-count
2+
3+
Disallow data rows in a GitHub Flavored Markdown table from having more cells than the header row.
4+
5+
## Background
6+
7+
In GitHub Flavored Markdown [tables](https://github.github.com/gfm/#tables-extension-), rows should maintain a consistent number of cells. While variations are sometimes tolerated, data rows having *more* cells than the header can lead to lost data or rendering issues. This rule prevents data rows from exceeding the header's column count.
8+
9+
## Rule Details
10+
11+
> [!IMPORTANT] <!-- eslint-disable-line -- This should be fixed in https://github.com/eslint/markdown/issues/294 -->
12+
>
13+
> This rule relies on the `table` AST node, typically available when using a GFM-compatible parser (e.g., `language: "markdown/gfm"`).
14+
15+
This rule is triggered if a data row in a GFM table contains more cells than the header row. It does not flag rows with fewer cells than the header.
16+
17+
Examples of **incorrect** code for this rule:
18+
19+
```markdown
20+
<!-- eslint markdown/table-column-count: "error" -->
21+
22+
| Head1 | Head2 |
23+
| ----- | ----- |
24+
| R1C1 | R1C2 | R2C3 | <!-- This data row has 3 cells, header has 2 -->
25+
26+
| A |
27+
| - |
28+
| 1 | 2 | <!-- This data row has 2 cells, header has 1 -->
29+
```
30+
31+
Examples of **correct** code for this rule:
32+
33+
```markdown
34+
<!-- eslint markdown/table-column-count: "error" -->
35+
36+
<!-- Standard correct table -->
37+
| Header | Header |
38+
| ------ | ------ |
39+
| Cell | Cell |
40+
| Cell | Cell |
41+
42+
<!-- Data row with fewer cells than header (VALID for this rule) -->
43+
<!-- Rows with fewer cells are valid because they render correctly and no data is lost -->
44+
| Header | Header | Header |
45+
| ------ | ------ | ------ |
46+
| Cell | Cell | |
47+
48+
<!-- Table with some empty cells (VALID for this rule) -->
49+
<!-- Missing cells are treated as empty and don't cause rendering issues -->
50+
| Col A | Col B | Col C |
51+
| ----- | ----- | ----- |
52+
| 1 | | 3 |
53+
| 4 | 5 |
54+
55+
<!-- Single column table -->
56+
| Single Header |
57+
| ------------- |
58+
| Single Cell |
59+
```
60+
61+
## When Not To Use It
62+
63+
If you intentionally create Markdown tables where data rows are expected to contain more cells than the header, and you have a specific (perhaps non-standard) processing or rendering pipeline that handles this scenario correctly, you might choose to disable this rule. However, adhering to this rule is recommended for typical GFM rendering and data consistency.
64+
65+
## Prior Art
66+
67+
* [MD056 - table-column-count](https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md056---table-column-count)

src/rules/table-column-count.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* @fileoverview Rule to disallow data rows in a GitHub Flavored Markdown table from having more cells than the header row
3+
* @author Sweta Tanwar (@SwetaTanwar)
4+
*/
5+
6+
//-----------------------------------------------------------------------------
7+
// Type Definitions
8+
//-----------------------------------------------------------------------------
9+
10+
/**
11+
* @typedef {import("../types.ts").MarkdownRuleDefinition<{ RuleOptions: []; }>} TableColumnCountRuleDefinition
12+
*/
13+
14+
//-----------------------------------------------------------------------------
15+
// Rule Definition
16+
//-----------------------------------------------------------------------------
17+
18+
/** @type {TableColumnCountRuleDefinition} */
19+
export default {
20+
meta: {
21+
type: "problem",
22+
23+
docs: {
24+
recommended: true,
25+
description:
26+
"Disallow data rows in a GitHub Flavored Markdown table from having more cells than the header row",
27+
url: "https://github.com/eslint/markdown/blob/main/docs/rules/table-column-count.md",
28+
},
29+
30+
messages: {
31+
inconsistentColumnCount:
32+
"Table column count mismatch (Expected: {{expectedCells}}, Actual: {{actualCells}}), extra data starting here will be ignored.",
33+
},
34+
},
35+
36+
create(context) {
37+
return {
38+
table(node) {
39+
if (node.children.length < 1) {
40+
return;
41+
}
42+
43+
const headerRow = node.children[0];
44+
const expectedCellsLength = headerRow.children.length;
45+
46+
for (let i = 1; i < node.children.length; i++) {
47+
const currentRow = node.children[i];
48+
const actualCellsLength = currentRow.children.length;
49+
50+
if (actualCellsLength > expectedCellsLength) {
51+
const firstExtraCellNode =
52+
currentRow.children[expectedCellsLength];
53+
54+
const lastActualCellNode =
55+
currentRow.children[actualCellsLength - 1];
56+
57+
context.report({
58+
loc: {
59+
start: firstExtraCellNode.position.start,
60+
end: lastActualCellNode.position.end,
61+
},
62+
messageId: "inconsistentColumnCount",
63+
data: {
64+
actualCells: String(actualCellsLength),
65+
expectedCells: String(expectedCellsLength),
66+
},
67+
});
68+
}
69+
}
70+
},
71+
};
72+
},
73+
};

0 commit comments

Comments
 (0)