Skip to content

Commit

Permalink
lint: add linting of concepts links.json
Browse files Browse the repository at this point in the history
  • Loading branch information
ee7 committed Mar 18, 2021
1 parent fbec735 commit 67d2eea
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 4 deletions.
57 changes: 56 additions & 1 deletion src/lint/concepts.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,61 @@
import std/os
import std/[json, os, strutils]
import ".."/helpers
import "."/validators

proc isUrlLike(s: string): bool =
## Returns true if `s` if `s` starts with `http://`, `https://` or `www`.
# For now, this is deliberately simplistic. We don't want to use regex here
# because it would add significant bloat to the binary, and introduce a
# dependency on PCRE or some Nimble package.
if s.startsWith("http"):
if s.continuesWith("://", 4) or s.continuesWith("s://", 4):
result = true
elif s.startsWith("www"):
result = true

proc isValidLinkObject(data: JsonNode, context: string, path: string): bool =
if isObject(data, context, path):
result = true
if not checkString(data, "url", path):
result = false
if not checkString(data, "description", path):
result = false
if not checkString(data, "icon_url", path, isRequired = false):
result = false

if result:
var s = data["url"].getStr()
if not isUrlLike(s):
result.setFalseAndPrint("not a valid URL: " & s, path)
if data.hasKey("icon_url"):
s = data["icon_url"].getStr()
if not isUrlLike(s):
result.setFalseAndPrint("not a valid URL: " & s, path)
else:
result.setFalseAndPrint("At least one element of the root array is not an object:" &
$data[context], path)

proc isValidLinksFile(data: JsonNode, path: string): bool =
result = isArrayOf(data, "", path, isValidLinkObject)

proc isEveryConceptLinksFileValid*(trackDir: string): bool =
let conceptsDir = trackDir / "concepts"
result = true
if dirExists(conceptsDir):
for subdir in getSortedSubdirs(conceptsDir):
let linksPath = subdir / "links.json"
if fileExists(linksPath):
let j =
try:
parseFile(linksPath)
except CatchableError:
result.setFalseAndPrint("JSON parsing error", getCurrentExceptionMsg())
continue
if not isValidLinksFile(j, linksPath):
result = false
else:
result.setFalseAndPrint("Missing file", linksPath)

proc conceptFilesExist*(trackDir: string): bool =
## Returns true if every subdirectory in `trackDir/concepts` has the required
## files.
Expand Down
8 changes: 5 additions & 3 deletions src/lint/lint.nim
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,17 @@ proc lint*(conf: Conf) =
let b2 = conceptExerciseFilesExist(trackDir)
let b3 = practiceExerciseFilesExist(trackDir)
let b4 = conceptFilesExist(trackDir)
let b5 = isEveryConceptExerciseConfigValid(trackDir)
let b6 = isEveryPracticeExerciseConfigValid(trackDir)
let b5 = isEveryConceptLinksFileValid(trackDir)
let b6 = isEveryConceptExerciseConfigValid(trackDir)
let b7 = isEveryPracticeExerciseConfigValid(trackDir)

if b1 and b2 and b3 and b4 and b5 and b6:
if b1 and b2 and b3 and b4 and b5 and b6 and b7:
echo """
Basic linting finished successfully:
- config.json exists and is valid JSON
- config.json has these valid fields: language, slug, active, blurb, version, tags
- Every concept has the required .md files and links.json file
- Every concept links.json file is valid
- Every concept exercise has the required .md files and a .meta/config.json file
- Every concept exercise .meta/config.json file is valid
- Every practice exercise has the required .md files and a .meta/config.json file
Expand Down

0 comments on commit 67d2eea

Please sign in to comment.