Skip to content

Commit

Permalink
lint: add more linting rules for track config.json (#183)
Browse files Browse the repository at this point in the history
* refactor: create module for track config.json validation

* lint: add validator to check boolean property

* lint: add validator to check integer property

* lint: validate basic property of track config.json file

The properties validated are:

- language: non-empty string (required)
- slug: non-empty string (required)
- blurb: non-empty string (required)
- active: boolean (required)
- version: integer (required)

* lint: valid tags property of track config.json file

* lint: update output of applied rules

Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com>
  • Loading branch information
ErikSchierboom and ee7 committed Feb 19, 2021
1 parent c5ea62d commit cc0128c
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 14 deletions.
18 changes: 4 additions & 14 deletions src/lint/lint.nim
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
import std/[json, os, terminal]
import std/[os, terminal]
import ".."/[cli, helpers]
import "."/concept_exercises

proc isValidTrackConfig(trackDir: string): bool =
result = true
let configJsonPath = trackDir / "config.json"
if fileExists(configJsonPath):
try:
let j = parseFile(configJsonPath)
except:
writeError("JSON parsing error", getCurrentExceptionMsg())
else:
writeError("Missing file", configJsonPath)
import "."/[concept_exercises, track_config]

proc subdirsContain(dir: string, files: openArray[string]): bool =
## Returns `true` if every file in `files` exists in every subdirectory of
Expand Down Expand Up @@ -60,7 +49,7 @@ proc lint*(conf: Conf) =
"the latest linting rules.\n"

let trackDir = conf.trackDir
let b1 = isValidTrackConfig(trackDir)
let b1 = isTrackConfigValid(trackDir)
let b2 = conceptExerciseFilesExist(trackDir)
let b3 = conceptFilesExist(trackDir)
let b4 = isEveryConceptExerciseConfigValid(trackDir)
Expand All @@ -69,6 +58,7 @@ proc lint*(conf: Conf) =
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 exercise has the required .md files and a .meta/config.json file
- Every concept exercise .meta/config.json file is valid"""
Expand Down
77 changes: 77 additions & 0 deletions src/lint/track_config.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import std/[json, os, sets, terminal]
import ".."/helpers
import "."/validators

const tags = [
"paradigm/declarative",
"paradigm/functional",
"paradigm/imperative",
"paradigm/logic",
"paradigm/object_oriented",
"paradigm/procedural",
"typing/static",
"typing/dynamic",
"typing/strong",
"typing/weak",
"execution_mode/compiled",
"execution_mode/interpreted",
"platform/windows",
"platform/mac",
"platform/linux",
"platform/ios",
"platform/android",
"platform/web",
"runtime/standalone_executable",
"runtime/language_specific",
"runtime/clr",
"runtime/jvm",
"runtime/beam",
"used_for/artificial_intelligence",
"used_for/backends",
"used_for/cross_platform_development",
"used_for/embedded_systems",
"used_for/financial_systems",
"used_for/frontends",
"used_for/games",
"used_for/guis",
"used_for/mobile",
"used_for/robotics",
"used_for/scientific_calculations",
"used_for/scripts",
"used_for/web_development",
].toHashSet()

proc isValidTag(data: JsonNode, context: string, path: string): bool =
if data.kind == JString:
let s = data.getStr()
if tags.contains(s):
return true
else:
writeError("Not a valid tag: " & $data, path)
else:
writeError("Tag is not a string: " & $data, path)

proc isValidTrackConfig(data: JsonNode, path: string): bool =
if isObject(data, "root", path):
result = true
checkString("language")
checkString("slug")
checkBoolean("active")
checkString("blurb")
checkInteger("version")
checkArrayOf("tags", isValidTag)

proc isTrackConfigValid*(trackDir: string): bool =
result = true
let configJsonPath = trackDir / "config.json"
if fileExists(configJsonPath):
let j =
try:
parseFile(configJsonPath)
except:
writeError("JSON parsing error", getCurrentExceptionMsg())
return
if not isValidTrackConfig(j, configJsonPath):
result = false
else:
writeError("Missing file", configJsonPath)
14 changes: 14 additions & 0 deletions src/lint/validators.nim
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,17 @@ template checkArrayOf*(key: string,
writeError("Not an array: " & q(key), path)
elif isRequired:
writeError("Missing key: " & q(key), path)

template checkBoolean*(key: string, isRequired = true) =
if data.hasKey(key):
if data[key].kind != JBool:
writeError("Not a bool: " & q(key) & ": " & $data[key], path)
elif isRequired:
writeError("Missing key: " & q(key), path)

template checkInteger*(key: string, isRequired = true) =
if data.hasKey(key):
if data[key].kind != JInt:
writeError("Not an integer: " & q(key) & ": " & $data[key], path)
elif isRequired:
writeError("Missing key: " & q(key), path)

0 comments on commit cc0128c

Please sign in to comment.