Skip to content

Commit

Permalink
Merge pull request #24 from ep-linden/issue-23
Browse files Browse the repository at this point in the history
Bugfix for `Issue-23`
  • Loading branch information
pa-eps authored May 17, 2022
2 parents 311417c + 58f3cad commit 2fb53fb
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 28 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ For e.g. With the following configuration
and `../javadocs/1.0.x/overview-summary.html` as the link being checked, this rule checks for the existence of the
`overview-summary.html` file at `../../static/javadocs/1.0.x/overview-summary.html`.

##### Note #####
#### route-map Ordering
Ensure each `route-map` pair is specific because the route-map option will validate relative links using the first
matching regex found in the configuration.

Expand All @@ -115,4 +115,4 @@ For e.g. With the following configuration

and `../../javadocs/1.0.x/overview-summary.html` as the link being checked, this rule checks for the existence of the
`overview-summary.html` file at the first destination `../website/static/javadocs/1.0.x/overview-summary.html` instead
of the second destination `../../static/javadocs/1.0.x/overview-summary.html`.
of the second destination `../../static/javadocs/1.0.x/overview-summary.html`.
21 changes: 14 additions & 7 deletions src/no-dead-relative-link.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {parse, Syntax} from '@textlint/markdown-to-ast';
import {traverse, VisitorOption} from '@textlint/ast-traverse';
import GithubSlugger from 'github-slugger';
import util from 'util';
import { wrapReportHandler} from 'textlint-rule-helper';
import {wrapReportHandler} from 'textlint-rule-helper';

const fileRead = util.promisify(fs.readFile);

Expand Down Expand Up @@ -39,11 +39,16 @@ async function validateLinkNode(linkNode, context, options) {

async function validateRelativeLink(linkNode, context, options) {
let linkURL = getLinkURL(linkNode.url, context, options);
let routedLinkURL;
if (!await fileExists(url.fileURLToPath(linkURL))) {
if (options["route-map"]) {
linkURL = await getRoutedLink(linkNode, context, options);
if (linkURL && !await fileExists(url.fileURLToPath(linkURL))) {
reportError(linkNode, context, `${path.basename(linkURL.pathname)} does not exist`);
routedLinkURL = await getRoutedLink(linkNode, context, options);
if (!routedLinkURL) {
reportError(linkNode, context, `${path.basename(linkURL.pathname)} has no mapped routing`);
return;
}
else if (!await fileExists(url.fileURLToPath(routedLinkURL))) {
reportError(linkNode, context, `The routed destination for ${path.basename(routedLinkURL.pathname)} does not exist`);
return;
}
} else {
Expand All @@ -52,6 +57,10 @@ async function validateRelativeLink(linkNode, context, options) {
}
}

// use the routedLinkURL to check for the anchor
if (routedLinkURL) {
linkURL = routedLinkURL;
}
if (linkURL && linkURL.hash && path.extname(linkURL.pathname) === ".md") {
return validateAnchorLink(url.fileURLToPath(linkURL), linkURL.hash.slice(1), linkNode, context);
}
Expand All @@ -60,14 +69,12 @@ async function validateRelativeLink(linkNode, context, options) {
async function getRoutedLink(linkNode, context, options) {
let linkRouteMaps = options["route-map"];
let nodeUrl = linkNode.url;

for (const mapping of linkRouteMaps) {
let sourceRegex = new RegExp(mapping["source"], "g");
let mappedDestination = mapping["destination"]
if (sourceRegex.test(nodeUrl)) {
let routedUrl = nodeUrl.replace(sourceRegex, mappedDestination);
let linkURL = getLinkURL(routedUrl, context, options);
return linkURL;
return getLinkURL(routedUrl, context, options);
}
}
}
Expand Down
14 changes: 9 additions & 5 deletions test/fixtures/testFiles/invalidLinkRoutingTest.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
This invalid link to a file with an anchor has no valid routing [invalidAnchorLink](../../invalidLink.md#does-not-exist)
This invalid link to a file has no valid routing [invalidLink](../../invalidLink.md)
This invalid link to a html file with an anchor that needs to be resolved as markdown has no valid routing [invalidAnchorLink](../dir/invalidLink.html#does-not-exist)
This invalid link to html file that needs to be resolved as markdown has no valid routing [invalidLink](../dir/invalidLink.html)
This invalid link to a file with an anchor is routed to a valid link with an invalid anchor [invalidAnchorLink](../../subdir/linkTestFile.md#header-7)
This invalid link to a file with an anchor is routed to a destination where the file doesn't exist [invalidAnchorLink](../dir/invalidLink.md#does-not-exist)
This invalid link to a file is routed to a destination where the file doesn't exist [invalidLink](../dir/invalidLink.md)
This invalid link to a html file with an anchor that needs to be resolved as markdown is routed to a destination where the file doesn't exist [invalidAnchorLink](../dir/invalidLink.html#does-not-exist)
This invalid link to html file that needs to be resolved as markdown is routed to a destination where the file doesn't exist [invalidLink](../dir/invalidLink.html)
This invalid link to a file with an anchor is routed to a valid destination, but the anchor is non-existent [invalidAnchorLink](../../subdir/linkTestFile.md#header-7)
This invalid link to a file has no matched routing [invalidAnchorLink](../../dir/subdir/linkTestFile.md)
This invalid link to a file with an anchor has no matched routing [invalidAnchorLink](../../dir/subdir/linkTestFile.md#header-7)
This invalid link to a file is routed to an invalid destination [invalidAnchorLink](../dir/subdir/linkTestFile.md)
This invalid link to a file with an anchor is routed to an invalid destination [invalidAnchorLink](../dir/subdir/linkTestFile.md#header-7)
149 changes: 135 additions & 14 deletions test/no-dead-relative-link-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,24 @@ tester.run(
"resolve-as-markdown": ".html",
"route-map": [
{
"source": "../../invalidLink.md",
"destination": "../invalidLink.md"
"source": "^../dir/subdir",
"destination": "/dir/subdir"
},
{
"source": "../dir/",
"source": "^../dir/",
"destination": "../"
},
{
"source": "../../(subdir)/",
"source": "^../../(subdir)/",
"destination": "$1/"
},
{
"source": "^../../linkTestFile.md",
"destination": "../linkTestFile.md"
},
{
"source": "^../../linkTestFile.html",
"destination": "../linkTestFile.md"
}
]
}
Expand All @@ -108,31 +116,144 @@ tester.run(
inputPath: path.resolve("./test/fixtures/testFiles/invalidLinkRoutingTest.md"),
errors: [
{
message: "invalidLink.md does not exist",
message: "The routed destination for invalidLink.md does not exist",
line: 1,
column: 85
column: 120
},
{
message: "invalidLink.md does not exist",
message: "The routed destination for invalidLink.md does not exist",
line: 2,
column: 64
column: 99
},
{
message: "invalidLink.md does not exist",
message: "The routed destination for invalidLink.md does not exist",
line: 3,
column: 128
column: 163
},
{
message: "invalidLink.md does not exist",
message: "The routed destination for invalidLink.md does not exist",
line: 4,
column: 105
column: 140
},
{
message: "Anchor #header-7 does not exist in linkTestFile.md",
line: 5,
column: 113
column: 129
},
{
message: "linkTestFile.md has no mapped routing",
line: 6,
column: 72
},
{
message: "linkTestFile.md has no mapped routing",
line: 7,
column: 87
},
{
message: "The routed destination for linkTestFile.md does not exist",
line: 8,
column: 85
},
{
message: "The routed destination for linkTestFile.md does not exist",
line: 9,
column: 100
}
]
}
]
});
});
tester.run(
"no-dead-relative-links: with route-map only",
{
rules: [
{
ruleId: "no-dead-relative-link",
rule: validateRelativeLinks,
options: {
"route-map": [
{
"source": "^../dir/subdir",
"destination": "/dir/subdir"
},
{
"source": "^../dir/",
"destination": "../"
},
{
"source": "^../../(subdir)/",
"destination": "$1/"
},
{
"source": "^../../linkTestFile.md",
"destination": "../linkTestFile.md"
},
{
"source": "^../../linkTestFile.html",
"destination": "../linkTestFile.md"
}
]
}
}
]
},
{
valid: [
{
inputPath: path.resolve("./test/fixtures/testFiles/validLinkRoutingTest.md"),
}
],
invalid: [
{
inputPath: path.resolve("./test/fixtures/testFiles/invalidLinkRoutingTest.md"),
errors: [
{
message: "The routed destination for invalidLink.md does not exist",
line: 1,
column: 120
},
{
message: "The routed destination for invalidLink.md does not exist",
line: 2,
column: 99
},
{
message: "The routed destination for invalidLink.html does not exist",
line: 3,
column: 163
},
{
message: "The routed destination for invalidLink.html does not exist",
line: 4,
column: 140
},
{
message: "Anchor #header-7 does not exist in linkTestFile.md",
line: 5,
column: 129
},
{
message: "linkTestFile.md has no mapped routing",
line: 6,
column: 72
},
{
message: "linkTestFile.md has no mapped routing",
line: 7,
column: 87
},
{
message: "The routed destination for linkTestFile.md does not exist",
line: 8,
column: 85
},
{
message: "The routed destination for linkTestFile.md does not exist",
line: 9,
column: 100
}
]
}
]
});

0 comments on commit 2fb53fb

Please sign in to comment.