-
Notifications
You must be signed in to change notification settings - Fork 0
/
no_global_links_to_local_files.nim
104 lines (90 loc) · 3.73 KB
/
no_global_links_to_local_files.nim
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# This file is part of osh-tool.
# <https://github.com/hoijui/osh-tool>
#
# SPDX-FileCopyrightText: 2022-2023 Robin Vobruba <[email protected]>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
import options
import os
import std/uri
import strformat
import strutils
import tables
import ../check
import ../check_config
import ../state
import ../util/fs
import ../util/run
#const IDS = @[srcFileNameBase(), "mdngltlf", "mdnogloblinks", "md_no_global_links", "md_no_global_links_to_local_files"]
const ID = srcFileNameBase()
type MdNoGlobalLinksToLocalFilesCheck = ref object of Check
type MdNoGlobalLinksToLocalFilesCheckGenerator = ref object of CheckGenerator
method name*(this: MdNoGlobalLinksToLocalFilesCheck): string =
return "No global links to local files"
method description*(this: MdNoGlobalLinksToLocalFilesCheck): string =
return """Checks no links to project local files use a 'global' prefix,
be it a web-hosting URL or an absolute local path."""
method why*(this: MdNoGlobalLinksToLocalFilesCheck): string =
return """This is a step towards a documentation that is:
- locally browsable an editable without internet connection
- showing and linking to the actual, local, correct content"""
method sourcePath*(this: MdNoGlobalLinksToLocalFilesCheck): string =
return fs.srcFileName()
method requirements*(this: MdNoGlobalLinksToLocalFilesCheck): CheckReqs =
return {
CheckReq.FilesListRec,
CheckReq.ExternalTool,
}
method getSignificanceFactors*(this: MdNoGlobalLinksToLocalFilesCheck): CheckSignificance =
return CheckSignificance(
weight: 0.4,
# because it indicates how well the repo works offline,
# or say: in a distributed environment
openness: 0.8,
hardware: 0.0,
quality: 0.8,
machineReadability: 0.8,
)
method run*(this: MdNoGlobalLinksToLocalFilesCheck, state: var State): CheckResult =
let config = state.config.checks[ID]
let mdFiles = filterByExtensions(state.listfiles(), @["md", "markdown"]) # TODO Make case-insensitive
let links = try:
extractMarkdownLinks(state.config.projRoot, mdFiles)
except IOError as err:
let msg = fmt("Failed to extract Markdown links from docu: {err.msg}")
return newCheckResult(config, CheckResultKind.Bad, CheckIssueSeverity.High, some(msg))
var issues = newSeq[CheckIssue]()
let nl = "<br> "
for link in links:
for projGlobPref in state.config.projPrefixes:
if link.target.startsWith(projGlobPref) and len(link.target) > len(projGlobPref) and not (len(link.target) - 1 == len(projGlobPref) and link.target[^1] == '/'):
var newTarget = link.target
let uri = parseUri(newTarget)
if uri.scheme == "file":
# "file://..." URL
newTarget.removePrefix(projGlobPref)
newTarget = relativePath(newTarget, projGlobPref)
elif len(uri.scheme) > 0:
# URL, but not a "file://..." one
newTarget.removePrefix(projGlobPref)
else:
# file path
newTarget = relativePath(link.target, projGlobPref)
issues.add(CheckIssue(
severity: CheckIssueSeverity.Middle,
msg: some(fmt"'{link.srcFile}':{link.srcLine}:{link.srcColumn}{nl} '{link.target}'{nl} ->{nl} '{newTarget}'")))
continue
if len(issues) == 0:
newCheckResult(config, CheckResultKind.Perfect)
else:
CheckResult(
config: config,
kind: CheckResultKind.Bad,
issues: issues)
method id*(this: MdNoGlobalLinksToLocalFilesCheckGenerator): string =
return ID
method generate*(this: MdNoGlobalLinksToLocalFilesCheckGenerator, config: CheckConfig = this.defaultConfig()): Check =
this.ensureNonConfig(config)
MdNoGlobalLinksToLocalFilesCheck()
proc createGenerator*(): CheckGenerator =
MdNoGlobalLinksToLocalFilesCheckGenerator()