diff --git a/doc/Rules.md b/doc/Rules.md index 20e17494..8d067e7f 100644 --- a/doc/Rules.md +++ b/doc/Rules.md @@ -2696,8 +2696,6 @@ Parameters: - `style`: Table column style (`string`, default `any`, values `aligned` / `any` / `compact` / `tight`) -- `wide_character`: RegExp for matching wide character(s) (`string`, default - `TBD`) This rule is triggered when the column separators of a [GitHub Flavored Markdown table][gfm-table-060] are used inconsistently. diff --git a/doc/md060.md b/doc/md060.md index 671a9143..209ad088 100644 --- a/doc/md060.md +++ b/doc/md060.md @@ -8,8 +8,6 @@ Parameters: - `style`: Table column style (`string`, default `any`, values `aligned` / `any` / `compact` / `tight`) -- `wide_character`: RegExp for matching wide character(s) (`string`, default - `TBD`) This rule is triggered when the column separators of a [GitHub Flavored Markdown table][gfm-table-060] are used inconsistently. diff --git a/lib/configuration-strict.d.ts b/lib/configuration-strict.d.ts index bb1fce10..563e22ed 100644 --- a/lib/configuration-strict.d.ts +++ b/lib/configuration-strict.d.ts @@ -2281,10 +2281,6 @@ export interface ConfigurationStrict { * Table column style */ style?: "any" | "aligned" | "compact" | "tight"; - /** - * RegExp for matching wide character(s) - */ - wide_character?: string; }; /** * MD060/table-column-style : Table column style : https://github.com/DavidAnson/markdownlint/blob/v0.39.0/doc/md060.md @@ -2305,10 +2301,6 @@ export interface ConfigurationStrict { * Table column style */ style?: "any" | "aligned" | "compact" | "tight"; - /** - * RegExp for matching wide character(s) - */ - wide_character?: string; }; /** * headings : MD001, MD003, MD018, MD019, MD020, MD021, MD022, MD023, MD024, MD025, MD026, MD036, MD041, MD043 diff --git a/lib/md060.mjs b/lib/md060.mjs index 0026ac42..76f0e882 100644 --- a/lib/md060.mjs +++ b/lib/md060.mjs @@ -2,58 +2,34 @@ import { filterByTypes } from "../helpers/micromark-helpers.cjs"; import { filterByTypesCached } from "./cache.mjs"; +import stringWidth from "string-width"; /** @typedef {import("micromark-extension-gfm-table")} */ /** @typedef {import("markdownlint").MicromarkToken} MicromarkToken */ /** @typedef {import("markdownlint").RuleOnErrorInfo} RuleOnErrorInfo */ -const regExpFlags = "gv"; -const anyCharacterRe = new RegExp("[\\s\\S]", regExpFlags); -// See: -// https://www.unicode.org/reports/tr11/ -// https://unicode.org/reports/tr24/ -// https://unicode.org/reports/tr51/ -// https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%3AEast_Asian_Width%3DFullwidth%3A%5D&abb=on&esc=on&g=&i= -// Notes: -// The East_Asian_Width property is not supported (seemingly at all) by JavaScript, so East_Asian_Width=Fullwidth ranges are matched directly: -// https://github.com/tc39/proposal-regexp-unicode-property-escapes/issues/28 -// As an alternative to matching by Script names, consider matching East_Asian_Width=Wide (Wide is a superset of Fullwidth) directly as well: -// https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B%3AEast_Asian_Width%3DWide%3A%5D&abb=on&esc=on&g=&i= -const defaultWideCharacterReString = "[\\p{RGI_Emoji}\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}\\u3000\\uFF01-\\uFF60\\uFFE0-\\uFFE6]"; - /** * @typedef Column * @property {number} actual Actual column (1-based) * @property {number} effective Effective column (1-based) */ -/** - * Gets the effective (adjusted for wide characters) column for an actual column. - * - * @param {string} line Line of text. - * @param {number} column Actual column (1-based). - * @param {RegExp} wideCharacterRe Wide character RegExp. - * @returns {number} Effective column (1-based). - */ -function effectiveColumn(line, column, wideCharacterRe) { - const span = line.slice(0, column - 1); - const totalCharacterCount = (span.match(anyCharacterRe) || []).length; - const wideCharacterCount = (span.match(wideCharacterRe) || []).length; - return totalCharacterCount + wideCharacterCount; -} - /** * Gets a list of table cell divider columns. * * @param {readonly string[]} lines File/string lines. * @param {MicromarkToken} row Micromark row token. - * @param {RegExp} wideCharacterRe Wide character RegExp. * @returns {Column[]} Divider columns. */ -function getTableDividerColumns(lines, row, wideCharacterRe) { +function getTableDividerColumns(lines, row) { return filterByTypes( row.children, - [ "tableCellDivider" ]).map((divider) => ({ "actual": divider.startColumn, "effective": effectiveColumn(lines[row.startLine - 1], divider.startColumn, wideCharacterRe) }) + [ "tableCellDivider" ] + ).map( + (divider) => ({ + "actual": divider.startColumn, + "effective": stringWidth(lines[row.startLine - 1].slice(0, divider.startColumn - 1)) + }) ); } @@ -84,7 +60,6 @@ export default { const styleAlignedAllowed = (style === "any") || (style === "aligned"); const styleCompactAllowed = (style === "any") || (style === "compact"); const styleTightAllowed = (style === "any") || (style === "tight"); - const wideCharacterRe = new RegExp(params.config.wide_character || defaultWideCharacterReString, regExpFlags); // Scan all tables/rows const tables = filterByTypesCached([ "table" ]); @@ -96,10 +71,10 @@ export default { /** @type {RuleOnErrorInfo[]} */ const errorsIfAligned = []; if (styleAlignedAllowed) { - const headingDividerColumns = getTableDividerColumns(params.lines, headingRow, wideCharacterRe); + const headingDividerColumns = getTableDividerColumns(params.lines, headingRow); for (const row of rows.slice(1)) { const remainingHeadingDividerColumns = new Set(headingDividerColumns.map((column) => column.effective)); - const rowDividerColumns = getTableDividerColumns(params.lines, row, wideCharacterRe); + const rowDividerColumns = getTableDividerColumns(params.lines, row); for (const dividerColumn of rowDividerColumns) { if ((remainingHeadingDividerColumns.size > 0) && !remainingHeadingDividerColumns.delete(dividerColumn.effective)) { addError(errorsIfAligned, row.startLine, dividerColumn.actual, "Table pipe does not align with heading for style \"aligned\""); diff --git a/package.json b/package.json index ea17945b..945fead6 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "build-config": "npm run build-config-schema && npm run build-config-example", "build-config-example": "node schema/build-config-example.mjs", "build-config-schema": "node schema/build-config-schema.mjs", - "build-declaration": "tsc --allowJs --checkJs --declaration --emitDeclarationOnly --module nodenext --outDir dts --rootDir . --target es2024 lib/exports.mjs lib/exports-async.mjs lib/exports-promise.mjs lib/exports-sync.mjs lib/markdownlint.mjs lib/resolve-module.cjs && node scripts/index.mjs copy dts/lib/exports.d.mts lib/exports.d.mts && node scripts/index.mjs copy dts/lib/exports-async.d.mts lib/exports-async.d.mts && node scripts/index.mjs copy dts/lib/exports-promise.d.mts lib/exports-promise.d.mts && node scripts/index.mjs copy dts/lib/exports-sync.d.mts lib/exports-sync.d.mts && node scripts/index.mjs copy dts/lib/markdownlint.d.mts lib/markdownlint.d.mts && node scripts/index.mjs copy dts/lib/resolve-module.d.cts lib/resolve-module.d.cts && node scripts/index.mjs remove dts", + "build-declaration": "tsc --allowJs --checkJs --declaration --emitDeclarationOnly --module nodenext --outDir dts --rootDir . --target es2015 lib/exports.mjs lib/exports-async.mjs lib/exports-promise.mjs lib/exports-sync.mjs lib/markdownlint.mjs lib/resolve-module.cjs && node scripts/index.mjs copy dts/lib/exports.d.mts lib/exports.d.mts && node scripts/index.mjs copy dts/lib/exports-async.d.mts lib/exports-async.d.mts && node scripts/index.mjs copy dts/lib/exports-promise.d.mts lib/exports-promise.d.mts && node scripts/index.mjs copy dts/lib/exports-sync.d.mts lib/exports-sync.d.mts && node scripts/index.mjs copy dts/lib/markdownlint.d.mts lib/markdownlint.d.mts && node scripts/index.mjs copy dts/lib/resolve-module.d.cts lib/resolve-module.d.cts && node scripts/index.mjs remove dts", "build-demo": "node scripts/index.mjs copy node_modules/markdown-it/dist/markdown-it.min.js demo/markdown-it.min.js && cd demo && webpack --no-stats", "build-docs": "node doc-build/build-rules.mjs", "ci": "npm-run-all --continue-on-error --parallel build-demo lint serial-config-docs serial-declaration test-cover && git diff --exit-code", @@ -80,7 +80,8 @@ "micromark-extension-gfm-footnote": "2.1.0", "micromark-extension-gfm-table": "2.1.1", "micromark-extension-math": "3.1.0", - "micromark-util-types": "2.0.2" + "micromark-util-types": "2.0.2", + "string-width": "8.1.0" }, "devDependencies": { "@eslint/js": "9.39.1", diff --git a/schema/.markdownlint.jsonc b/schema/.markdownlint.jsonc index 141cd691..831440ad 100644 --- a/schema/.markdownlint.jsonc +++ b/schema/.markdownlint.jsonc @@ -340,8 +340,6 @@ // MD060/table-column-style : Table column style : https://github.com/DavidAnson/markdownlint/blob/v0.39.0/doc/md060.md "MD060": { // Table column style - "style": "any", - // RegExp for matching wide character(s) - "wide_character": "TBD" + "style": "any" } } \ No newline at end of file diff --git a/schema/.markdownlint.yaml b/schema/.markdownlint.yaml index b7407272..e769041e 100644 --- a/schema/.markdownlint.yaml +++ b/schema/.markdownlint.yaml @@ -304,5 +304,3 @@ MD059: MD060: # Table column style style: "any" - # RegExp for matching wide character(s) - wide_character: "TBD" diff --git a/schema/build-config-schema.mjs b/schema/build-config-schema.mjs index aa6414b9..3b5a7c2b 100644 --- a/schema/build-config-schema.mjs +++ b/schema/build-config-schema.mjs @@ -645,12 +645,6 @@ for (const rule of rules) { ], "default": "any" }; - // @ts-ignore - subscheme.properties.wide_character = { - "description": "RegExp for matching wide character(s)", - "type": "string", - "default": "TBD" - }; break; default: break; diff --git a/schema/markdownlint-config-schema-strict.json b/schema/markdownlint-config-schema-strict.json index 24ff7635..f9c0a250 100644 --- a/schema/markdownlint-config-schema-strict.json +++ b/schema/markdownlint-config-schema-strict.json @@ -4701,11 +4701,6 @@ "tight" ], "default": "any" - }, - "wide_character": { - "description": "RegExp for matching wide character(s)", - "type": "string", - "default": "TBD" } } } @@ -4752,11 +4747,6 @@ "tight" ], "default": "any" - }, - "wide_character": { - "description": "RegExp for matching wide character(s)", - "type": "string", - "default": "TBD" } } } diff --git a/schema/markdownlint-config-schema.json b/schema/markdownlint-config-schema.json index a8df6fa3..91b2bc2f 100644 --- a/schema/markdownlint-config-schema.json +++ b/schema/markdownlint-config-schema.json @@ -4701,11 +4701,6 @@ "tight" ], "default": "any" - }, - "wide_character": { - "description": "RegExp for matching wide character(s)", - "type": "string", - "default": "TBD" } } } @@ -4752,11 +4747,6 @@ "tight" ], "default": "any" - }, - "wide_character": { - "description": "RegExp for matching wide character(s)", - "type": "string", - "default": "TBD" } } } diff --git a/test/markdownlint-test.mjs b/test/markdownlint-test.mjs index 2798da7d..bc2825dc 100644 --- a/test/markdownlint-test.mjs +++ b/test/markdownlint-test.mjs @@ -1101,7 +1101,7 @@ test("readme", async(t) => { }); test("validateJsonUsingConfigSchemaStrict", async(t) => { - t.plan(222); + t.plan(220); // @ts-ignore const ajv = new Ajv(ajvOptions); const validateSchemaStrict = ajv.compile(configSchemaStrict); diff --git a/test/snapshots/markdownlint-test-scenarios.mjs.md b/test/snapshots/markdownlint-test-scenarios.mjs.md index ea51bd22..038d5df4 100644 --- a/test/snapshots/markdownlint-test-scenarios.mjs.md +++ b/test/snapshots/markdownlint-test-scenarios.mjs.md @@ -72533,242 +72533,6 @@ Generated by [AVA](https://avajs.dev). `, } -## table-column-style-wide-characters-custom.md - -> Snapshot 1 - - { - errors: [ - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 6, - 1, - ], - fixInfo: null, - lineNumber: 12, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 11, - 1, - ], - fixInfo: null, - lineNumber: 12, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 11, - 1, - ], - fixInfo: null, - lineNumber: 13, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 6, - 1, - ], - fixInfo: null, - lineNumber: 14, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 11, - 1, - ], - fixInfo: null, - lineNumber: 14, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - ], - fixed: `# Table Column Style - Wide Characters (Custom)␊ - ␊ - | NN | W |␊ - | -- | -- |␊ - | NN | NN |␊ - | W | NN |␊ - | NN | W |␊ - | W | W |␊ - | ✅N | NN |␊ - | NN | ✅N |␊ - | ✅N | ✅N |␊ - | WW | NN |␊ - | NN | WW |␊ - | WW | WW |␊ - ␊ - {MD060:-4} {MD060:-3} {MD060:-2}␊ - ␊ - ␊ - `, - } - -## table-column-style-wide-characters-disable.md - -> Snapshot 1 - - { - errors: [ - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 5, - 1, - ], - fixInfo: null, - lineNumber: 6, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 10, - 1, - ], - fixInfo: null, - lineNumber: 6, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 10, - 1, - ], - fixInfo: null, - lineNumber: 7, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 5, - 1, - ], - fixInfo: null, - lineNumber: 8, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - { - errorContext: null, - errorDetail: 'Table pipe does not align with heading for style "aligned"', - errorRange: [ - 9, - 1, - ], - fixInfo: null, - lineNumber: 8, - ruleDescription: 'Table column style', - ruleInformation: 'https://github.com/DavidAnson/markdownlint/blob/v0.0.0/doc/md060.md', - ruleNames: [ - 'MD060', - 'table-column-style', - ], - severity: 'error', - }, - ], - fixed: `# Table Column Style - Wide Characters (Disable)␊ - ␊ - | NN | WW |␊ - | -- | -- |␊ - | NN | NN |␊ - | W | NN |␊ - | NN | W |␊ - | W | W |␊ - | ✅N | NN |␊ - | NN | ✅N |␊ - | ✅N | ✅N |␊ - | WW | NN |␊ - | NN | WW |␊ - | WW | WW |␊ - ␊ - {MD060:-10} {MD060:-9} {MD060:-8}␊ - ␊ - ␊ - `, - } - ## table-column-style-wide-characters.md > Snapshot 1 diff --git a/test/snapshots/markdownlint-test-scenarios.mjs.snap b/test/snapshots/markdownlint-test-scenarios.mjs.snap index b0c00853..53858b88 100644 Binary files a/test/snapshots/markdownlint-test-scenarios.mjs.snap and b/test/snapshots/markdownlint-test-scenarios.mjs.snap differ diff --git a/test/table-column-style-wide-characters-custom.md b/test/table-column-style-wide-characters-custom.md deleted file mode 100644 index d0823836..00000000 --- a/test/table-column-style-wide-characters-custom.md +++ /dev/null @@ -1,23 +0,0 @@ -# Table Column Style - Wide Characters (Custom) - -| NN | W | -| -- | -- | -| NN | NN | -| W | NN | -| NN | W | -| W | W | -| ✅N | NN | -| NN | ✅N | -| ✅N | ✅N | -| WW | NN | -| NN | WW | -| WW | WW | - -{MD060:-4} {MD060:-3} {MD060:-2} - - diff --git a/test/table-column-style-wide-characters-disable.md b/test/table-column-style-wide-characters-disable.md deleted file mode 100644 index c18eb77a..00000000 --- a/test/table-column-style-wide-characters-disable.md +++ /dev/null @@ -1,23 +0,0 @@ -# Table Column Style - Wide Characters (Disable) - -| NN | WW | -| -- | -- | -| NN | NN | -| W | NN | -| NN | W | -| W | W | -| ✅N | NN | -| NN | ✅N | -| ✅N | ✅N | -| WW | NN | -| NN | WW | -| WW | WW | - -{MD060:-10} {MD060:-9} {MD060:-8} - -