3 Commits

Author SHA1 Message Date
bf9403ad84 style: fix prettier 2024-04-06 20:14:59 +02:00
9675c7a275 fix: update markdown-it to v14.1.0
This allows to use the same version as markdownlint v0.34.0.
2024-04-06 20:10:13 +02:00
5af131b840 fix: link fragment with accents should be valid if the heading exists
Fixes a regression introduced in v2.3.0, which needed to lower case/manage case insensitive heading.
2024-01-31 21:56:55 +01:00
12 changed files with 1676 additions and 1982 deletions

View File

@ -13,7 +13,7 @@ jobs:
- uses: "actions/checkout@v4.1.1" - uses: "actions/checkout@v4.1.1"
- name: "Setup Node.js" - name: "Setup Node.js"
uses: "actions/setup-node@v4.0.1" uses: "actions/setup-node@v4.0.2"
with: with:
node-version: "lts/*" node-version: "lts/*"
cache: "npm" cache: "npm"

View File

@ -19,7 +19,7 @@ jobs:
persist-credentials: false persist-credentials: false
- name: "Setup Node.js" - name: "Setup Node.js"
uses: "actions/setup-node@v4.0.1" uses: "actions/setup-node@v4.0.2"
with: with:
node-version: "lts/*" node-version: "lts/*"
cache: "npm" cache: "npm"

View File

@ -13,7 +13,7 @@ jobs:
- uses: "actions/checkout@v4.1.1" - uses: "actions/checkout@v4.1.1"
- name: "Setup Node.js" - name: "Setup Node.js"
uses: "actions/setup-node@v4.0.1" uses: "actions/setup-node@v4.0.2"
with: with:
node-version: "lts/*" node-version: "lts/*"
cache: "npm" cache: "npm"

View File

@ -20,6 +20,6 @@
"noUncheckedIndexedAccess": true, "noUncheckedIndexedAccess": true,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true
}, }
} }

3562
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -44,28 +44,28 @@
"postpublish": "pinst --enable" "postpublish": "pinst --enable"
}, },
"dependencies": { "dependencies": {
"markdown-it": "14.0.0" "markdown-it": "14.1.0"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "18.6.0", "@commitlint/cli": "19.1.0",
"@commitlint/config-conventional": "18.6.0", "@commitlint/config-conventional": "19.1.0",
"@types/markdown-it": "13.0.7", "@types/markdown-it": "14.0.0",
"@types/node": "20.11.10", "@types/node": "20.12.5",
"editorconfig-checker": "5.1.2", "editorconfig-checker": "5.1.5",
"eslint": "8.56.0", "eslint": "8.56.0",
"eslint-config-conventions": "13.1.0", "eslint-config-conventions": "14.1.0",
"eslint-config-prettier": "9.1.0", "eslint-config-prettier": "9.1.0",
"eslint-plugin-import": "2.29.1", "eslint-plugin-import": "2.29.1",
"eslint-plugin-prettier": "5.1.3", "eslint-plugin-prettier": "5.1.3",
"eslint-plugin-promise": "6.1.1", "eslint-plugin-promise": "6.1.1",
"eslint-plugin-unicorn": "50.0.1", "eslint-plugin-unicorn": "51.0.1",
"husky": "9.0.7", "husky": "9.0.11",
"lint-staged": "15.2.0", "lint-staged": "15.2.2",
"markdownlint": "0.33.0", "markdownlint": "0.34.0",
"markdownlint-cli2": "0.12.1", "markdownlint-cli2": "0.13.0",
"pinst": "3.0.0", "pinst": "3.0.0",
"prettier": "3.2.4", "prettier": "3.2.5",
"semantic-release": "23.0.0", "semantic-release": "23.0.7",
"typescript": "5.3.3" "typescript": "5.4.4"
} }
} }

View File

@ -22,6 +22,7 @@ const customRule = {
names: ["relative-links"], names: ["relative-links"],
description: "Relative links should be valid", description: "Relative links should be valid",
tags: ["links"], tags: ["links"],
parser: "markdownit",
function: (params, onError) => { function: (params, onError) => {
filterTokens(params, "inline", (token) => { filterTokens(params, "inline", (token) => {
const children = token.children ?? [] const children = token.children ?? []

View File

@ -15,7 +15,7 @@
* @returns {void} * @returns {void}
*/ */
const filterTokens = (params, type, handler) => { const filterTokens = (params, type, handler) => {
for (const token of params.tokens) { for (const token of params.parsers.markdownit.tokens) {
if (token.type === type) { if (token.type === type) {
handler(token) handler(token)
} }

View File

@ -26,7 +26,7 @@ const convertHeadingToHTMLFragment = (inlineText) => {
"", "",
) )
.replace(/ /gu, "-"), .replace(/ /gu, "-"),
) ).toLowerCase()
) )
} }

View File

@ -0,0 +1,3 @@
# Awesome
## Développement

View File

@ -0,0 +1,3 @@
# Valid
[Link fragment](./awesome.md#développement)

View File

@ -26,80 +26,80 @@ test("ensure the rule validates correctly", async (t) => {
await t.test("should be invalid", async (t) => { await t.test("should be invalid", async (t) => {
const testCases = [ const testCases = [
{ {
name: "with an empty id fragment", name: "should be invalid with an empty id fragment",
fixturePath: fixturePath:
"test/fixtures/invalid/empty-id-fragment/empty-id-fragment.md", "test/fixtures/invalid/empty-id-fragment/empty-id-fragment.md",
error: '"./awesome.md#" should have a valid fragment identifier', error: '"./awesome.md#" should have a valid fragment identifier',
}, },
{ {
name: "with a name fragment other than for an anchor", name: "should be invalid with a name fragment other than for an anchor",
fixturePath: fixturePath:
"test/fixtures/invalid/ignore-name-fragment-if-not-an-anchor/ignore-name-fragment-if-not-an-anchor.md", "test/fixtures/invalid/ignore-name-fragment-if-not-an-anchor/ignore-name-fragment-if-not-an-anchor.md",
error: error:
'"./awesome.md#name-should-be-ignored" should have a valid fragment identifier', '"./awesome.md#name-should-be-ignored" should have a valid fragment identifier',
}, },
{ {
name: "with a non-existing id fragment (data-id !== id)", name: "should be invalid with a non-existing id fragment (data-id !== id)",
fixturePath: fixturePath:
"test/fixtures/invalid/ignore-not-an-id-fragment/ignore-not-an-id-fragment.md", "test/fixtures/invalid/ignore-not-an-id-fragment/ignore-not-an-id-fragment.md",
error: error:
'"./awesome.md#not-an-id-should-be-ignored" should have a valid fragment identifier', '"./awesome.md#not-an-id-should-be-ignored" should have a valid fragment identifier',
}, },
{ {
name: "with invalid heading with #L fragment", name: "should be invalid with invalid heading with #L fragment",
fixturePath: fixturePath:
"test/fixtures/invalid/invalid-heading-with-L-fragment/invalid-heading-with-L-fragment.md", "test/fixtures/invalid/invalid-heading-with-L-fragment/invalid-heading-with-L-fragment.md",
error: '"./awesome.md#L7abc" should have a valid fragment identifier', error: '"./awesome.md#L7abc" should have a valid fragment identifier',
}, },
{ {
name: "with a invalid line number fragment", name: "should be invalid with a invalid line number fragment",
fixturePath: fixturePath:
"test/fixtures/invalid/invalid-line-number-fragment/invalid-line-number-fragment.md", "test/fixtures/invalid/invalid-line-number-fragment/invalid-line-number-fragment.md",
error: error:
'"./awesome.md#L7" should have a valid fragment identifier, "./awesome.md#L7" should have at least 7 lines to be valid', '"./awesome.md#L7" should have a valid fragment identifier, "./awesome.md#L7" should have at least 7 lines to be valid',
}, },
{ {
name: "with a non-existing anchor name fragment", name: "should be invalid with a non-existing anchor name fragment",
fixturePath: fixturePath:
"test/fixtures/invalid/non-existing-anchor-name-fragment/non-existing-anchor-name-fragment.md", "test/fixtures/invalid/non-existing-anchor-name-fragment/non-existing-anchor-name-fragment.md",
error: error:
'"./awesome.md#non-existing-anchor-name-fragment" should have a valid fragment identifier', '"./awesome.md#non-existing-anchor-name-fragment" should have a valid fragment identifier',
}, },
{ {
name: "with a non-existing element id fragment", name: "should be invalid with a non-existing element id fragment",
fixturePath: fixturePath:
"test/fixtures/invalid/non-existing-element-id-fragment/non-existing-element-id-fragment.md", "test/fixtures/invalid/non-existing-element-id-fragment/non-existing-element-id-fragment.md",
error: error:
'"./awesome.md#non-existing-element-id-fragment" should have a valid fragment identifier', '"./awesome.md#non-existing-element-id-fragment" should have a valid fragment identifier',
}, },
{ {
name: "with a non-existing heading fragment", name: "should be invalid with a non-existing heading fragment",
fixturePath: fixturePath:
"test/fixtures/invalid/non-existing-heading-fragment/non-existing-heading-fragment.md", "test/fixtures/invalid/non-existing-heading-fragment/non-existing-heading-fragment.md",
error: error:
'"./awesome.md#non-existing-heading" should have a valid fragment identifier', '"./awesome.md#non-existing-heading" should have a valid fragment identifier',
}, },
{ {
name: "with a link to an image with a empty fragment", name: "should be invalid with a link to an image with a empty fragment",
fixturePath: fixturePath:
"test/fixtures/invalid/ignore-empty-fragment-checking-for-image.md", "test/fixtures/invalid/ignore-empty-fragment-checking-for-image.md",
error: error:
'"../image.png#" should not have a fragment identifier as it is an image', '"../image.png#" should not have a fragment identifier as it is an image',
}, },
{ {
name: "with a link to an image with a fragment", name: "should be invalid with a link to an image with a fragment",
fixturePath: fixturePath:
"test/fixtures/invalid/ignore-fragment-checking-for-image.md", "test/fixtures/invalid/ignore-fragment-checking-for-image.md",
error: error:
'"../image.png#non-existing-fragment" should not have a fragment identifier as it is an image', '"../image.png#non-existing-fragment" should not have a fragment identifier as it is an image',
}, },
{ {
name: "with a non-existing file", name: "should be invalid with a non-existing file",
fixturePath: "test/fixtures/invalid/non-existing-file.md", fixturePath: "test/fixtures/invalid/non-existing-file.md",
error: '"./index.test.js" should exist in the file system', error: '"./index.test.js" should exist in the file system',
}, },
{ {
name: "with a non-existing image", name: "should be invalid with a non-existing image",
fixturePath: "test/fixtures/invalid/non-existing-image.md", fixturePath: "test/fixtures/invalid/non-existing-image.md",
error: '"./image.png" should exist in the file system', error: '"./image.png" should exist in the file system',
}, },
@ -122,46 +122,51 @@ test("ensure the rule validates correctly", async (t) => {
await t.test("should be valid", async (t) => { await t.test("should be valid", async (t) => {
const testCases = [ const testCases = [
{ {
name: "with an existing anchor name fragment", name: "should be valid with an existing anchor name fragment",
fixturePath: fixturePath:
"test/fixtures/valid/existing-anchor-name-fragment/existing-anchor-name-fragment.md", "test/fixtures/valid/existing-anchor-name-fragment/existing-anchor-name-fragment.md",
}, },
{ {
name: "with an existing element id fragment", name: "should be valid with an existing element id fragment",
fixturePath: fixturePath:
"test/fixtures/valid/existing-element-id-fragment/existing-element-id-fragment.md", "test/fixtures/valid/existing-element-id-fragment/existing-element-id-fragment.md",
}, },
{ {
name: "with an existing heading fragment (case insensitive)", name: "should be valid with an existing heading fragment (case insensitive)",
fixturePath: fixturePath:
"test/fixtures/valid/existing-heading-case-insensitive/existing-heading-case-insensitive.md", "test/fixtures/valid/existing-heading-case-insensitive/existing-heading-case-insensitive.md",
}, },
{ {
name: "with an existing heading fragment", name: "should be valid with an existing heading fragment",
fixturePath: fixturePath:
"test/fixtures/valid/existing-heading-fragment/existing-heading-fragment.md", "test/fixtures/valid/existing-heading-fragment/existing-heading-fragment.md",
}, },
{
name: 'should be valid with an existing heading fragment with accents (e.g: "é")',
fixturePath:
"test/fixtures/valid/existing-heading-with-accents/existing-heading-with-accents.md",
},
{ {
name: "should only parse markdown files for fragments checking", name: "should only parse markdown files for fragments checking",
fixturePath: fixturePath:
"test/fixtures/valid/only-parse-markdown-files-for-fragments/only-parse-markdown-files-for-fragments.md", "test/fixtures/valid/only-parse-markdown-files-for-fragments/only-parse-markdown-files-for-fragments.md",
}, },
{ {
name: 'with valid heading "like" line number fragment', name: 'should be valid with valid heading "like" line number fragment',
fixturePath: fixturePath:
"test/fixtures/valid/valid-heading-like-number-fragment/valid-heading-like-number-fragment.md", "test/fixtures/valid/valid-heading-like-number-fragment/valid-heading-like-number-fragment.md",
}, },
{ {
name: "with valid line number fragment", name: "should be valid with valid line number fragment",
fixturePath: fixturePath:
"test/fixtures/valid/valid-line-number-fragment/valid-line-number-fragment.md", "test/fixtures/valid/valid-line-number-fragment/valid-line-number-fragment.md",
}, },
{ {
name: "with an existing file", name: "should be valid with an existing file",
fixturePath: "test/fixtures/valid/existing-file.md", fixturePath: "test/fixtures/valid/existing-file.md",
}, },
{ {
name: "with an existing image", name: "should be valid with an existing image",
fixturePath: "test/fixtures/valid/existing-image.md", fixturePath: "test/fixtures/valid/existing-image.md",
}, },
{ {