Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

lint, fmt: support tags for approaches and concepts #822

Merged
merged 13 commits into from
Oct 6, 2023
20 changes: 19 additions & 1 deletion src/fmt/approaches.nim
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import std/[json, strformat]
import std/[json, options, strformat]
import ".."/[helpers, sync/sync_common, types_approaches_config]

func approachesConfigKeyOrderForFmt(e: ApproachesConfig): seq[ApproachesConfigKey] =
Expand All @@ -23,6 +23,20 @@ func addApproachesIntroduction(result: var string;
result.addNewlineAndIndent(indentLevel)
result.add "},"

func addApproachTags(result: var string; val: ApproachConfigTags; indentLevel = 2) =
result.addNewlineAndIndent(indentLevel)
escapeJson("tags", result)
result.add ": {"
if val.all.len > 0:
result.addArray("all", val.all, indentLevel + 1)
if val.`any`.len > 0:
result.addArray("any", val.`any`, indentLevel + 1)
if val.`not`.len > 0:
result.addArray("not", val.`not`, indentLevel + 1)
result.removeComma()
result.addNewlineAndIndent(indentLevel)
result.add "},"

func addApproach(result: var string; val: ApproachConfig; indentLevel = 1) =
## Appends the pretty-printed JSON for an `approach` object with value `val` to
## `result`.
Expand All @@ -35,6 +49,10 @@ func addApproach(result: var string; val: ApproachConfig; indentLevel = 1) =
result.addArray("authors", val.authors, indentLevel + 1)
if val.contributors.len > 0:
result.addArray("contributors", val.contributors, indentLevel + 1)
if val.tags.isSome():
let tags = val.tags.get()
if tags.all.len + tags.`any`.len + tags.`not`.len > 0:
result.addApproachTags(tags, indentLevel + 1)
ee7 marked this conversation as resolved.
Show resolved Hide resolved
result.removeComma()
result.addNewlineAndIndent(indentLevel)
result.add "},"
Expand Down
18 changes: 18 additions & 0 deletions src/fmt/track_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,20 @@ func addKeyFeatures(result: var string; val: KeyFeatures; indentLevel = 1) =
result.addNewlineAndIndent(indentLevel)
result.add "],"

func addConceptTags(result: var string; val: ConceptTags; indentLevel = 2) =
result.addNewlineAndIndent(indentLevel)
escapeJson("tags", result)
result.add ": {"
if val.all.len > 0:
result.addArray("all", val.all, indentLevel + 1)
if val.`any`.len > 0:
result.addArray("any", val.`any`, indentLevel + 1)
if val.`not`.len > 0:
result.addArray("not", val.`not`, indentLevel + 1)
result.removeComma()
result.addNewlineAndIndent(indentLevel)
result.add "},"

func addConcept(result: var string; val: Concept; indentLevel = 1) =
## Appends the pretty-printed JSON for a `concept` object with value `val` to
## `result`.
Expand All @@ -129,6 +143,10 @@ func addConcept(result: var string; val: Concept; indentLevel = 1) =
result.addString("uuid", val.uuid, indentLevel + 1)
result.addString("slug", val.slug, indentLevel + 1)
result.addString("name", val.name, indentLevel + 1)
if val.tags.isSome():
let tags = val.tags.get()
if tags.all.len + tags.`any`.len + tags.`not`.len > 0:
result.addConceptTags(tags, indentLevel + 1)
result.removeComma()
result.addNewlineAndIndent(indentLevel)
result.add "},"
Expand Down
12 changes: 10 additions & 2 deletions src/lint/approaches_and_articles.nim
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ proc hasValidIntroduction(data: JsonNode, path: Path): bool =
result.setFalseIfFileMissingOrEmpty(introductionPath, msg)

proc isValidApproachOrArticle(data: JsonNode, context: string,
path: Path): bool =
path: Path, checkTags: bool): bool =
if isObject(data, context, path):
let checks = [
hasString(data, "uuid", path, context, checkIsUuid = true),
Expand All @@ -41,6 +41,7 @@ proc isValidApproachOrArticle(data: JsonNode, context: string,
hasArrayOfStrings(data, "authors", path, context, uniqueValues = true),
hasArrayOfStrings(data, "contributors", path, context,
isRequired = false),
if checkTags: hasValidTags(data, path) else: true,
ee7 marked this conversation as resolved.
Show resolved Hide resolved
]
result = allTrue(checks)
if result:
Expand All @@ -63,6 +64,12 @@ proc isValidApproachOrArticle(data: JsonNode, context: string,
"there is no corresponding snippet file at the below location"
result.setFalseIfFileMissingOrEmpty(snippetPath, msg)

proc isValidApproach(data: JsonNode, context: string, path: Path): bool =
result = isValidApproachOrArticle(data, context, path, checkTags = true)
ee7 marked this conversation as resolved.
Show resolved Hide resolved

proc isValidArticle(data: JsonNode, context: string, path: Path): bool =
result = isValidApproachOrArticle(data, context, path, checkTags = false)
ee7 marked this conversation as resolved.
Show resolved Hide resolved

proc getSlugs(data: JsonNode, k: string): seq[string] =
result = @[]
if data.kind == JObject and data.hasKey(k):
Expand All @@ -77,7 +84,8 @@ proc isValidConfig(data: JsonNode, path: Path, dk: DocumentKind): bool =
let k = dk.`$`[1..^1] # Remove dot.
let checks = [
if dk == dkApproaches: hasValidIntroduction(data, path) else: true,
hasArrayOf(data, k, path, isValidApproachOrArticle, isRequired = false),
hasArrayOf(data, k, path, if dk == dkApproaches: isValidApproach else: isValidArticle,
isRequired = false),
]
result = allTrue(checks)
if result:
Expand Down
3 changes: 2 additions & 1 deletion src/lint/track_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ proc isValidConcept(data: JsonNode; context: string; path: Path): bool =
hasString(data, "uuid", path, context, checkIsUuid = true),
hasString(data, "slug", path, context, maxLen = 255, checkIsKebab = true),
hasString(data, "name", path, context, maxLen = 255),
hasValidTags(data, path),
ee7 marked this conversation as resolved.
Show resolved Hide resolved
]
result = allTrue(checks)

Expand Down Expand Up @@ -625,7 +626,7 @@ proc checkExerciseSlugsAndForegone(exercises: Exercises; b: var bool;
"but there is an implemented exercise with that slug"
b.setFalseAndPrint(msg, path)

proc checkFilePatternsOverlap(filePatterns: FilePatterns; trackSlug: string,
proc checkFilePatternsOverlap(filePatterns: FilePatterns; trackSlug: string;
b: var bool; path: Path) =
const overlappingSolutionTestTrackSlugs = ["d", "plsql"]
const uniqueFilePatternCombinations = [
Expand Down
24 changes: 24 additions & 0 deletions src/lint/validators.nim
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,30 @@ proc hasInteger*(data: JsonNode; key: string; path: Path; context = "";
elif not isRequired:
result = true

proc hasValidTags*(data: JsonNode; path: Path): bool =
const k = "tags"
if data.hasKey(k):
if hasObject(data, k, path):
let checks = [
hasArrayOfStrings(data[k], "all", path, isRequired = false, uniqueValues = true),
hasArrayOfStrings(data[k], "any", path, isRequired = false, uniqueValues = true),
hasArrayOfStrings(data[k], "not", path, isRequired = false, uniqueValues = true),
]
result = allTrue(checks)
if result:
var anyAllLen = 0

if data[k].hasKey("all"):
anyAllLen += data[k]["all"].len

if data[k].hasKey("any"):
anyAllLen += data[k]["any"].len

if anyAllLen == 0:
result.setFalseAndPrint("There must be at least one element in the `all` or `any` fields in the `tags` object", path)
ee7 marked this conversation as resolved.
Show resolved Hide resolved
else:
result = true

proc parseJson(s: Stream; filename: Path; rawIntegers = false;
rawFloats = false): JsonNode {.borrow.}

Expand Down
9 changes: 9 additions & 0 deletions src/types_approaches_config.nim
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import std/options
import pkg/jsony
ee7 marked this conversation as resolved.
Show resolved Hide resolved
import "."/helpers

type
Expand All @@ -12,6 +14,7 @@ type
akBlurb = "blurb"
akAuthors = "authors"
akContributors = "contributors"
akTags = "tags"

ApproachIntroductionKey* = enum
aiAuthors = "authors"
Expand All @@ -21,13 +24,19 @@ type
authors*: seq[string]
contributors*: seq[string]

ApproachConfigTags* = object
all*: seq[string]
`any`*: seq[string]
`not`*: seq[string]

ApproachConfig* = object
uuid*: string
slug*: string
title*: string
blurb*: string
authors*: seq[string]
contributors*: seq[string]
tags*: Option[ApproachConfigTags]

ApproachesConfig* = object
introduction*: ApproachesIntroductionConfig
Expand Down
6 changes: 6 additions & 0 deletions src/types_track_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,16 @@ type
indentSize*: int
highlightjsLanguage*: string

ConceptTags* = object
all*: seq[string]
`any`*: seq[string]
`not`*: seq[string]
ee7 marked this conversation as resolved.
Show resolved Hide resolved

Concept* = object
name*: string
slug*: string
uuid*: string
tags*: Option[ConceptTags]

Concepts* = seq[Concept]

Expand Down