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

fmt, lint: support icon key for practice exercise config.json #716

Merged
merged 6 commits into from
Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,10 @@ The canonical key order for an exercise `.meta/config.json` file is:
- [invalidator]
- [language_versions]
- [forked_from] (Concept Exercises only)
- [icon] (Concept Exercises only)
- [test_runner] (Practice Exercises only)
- [representer]
- version
- [icon]
- blurb
- [source]
- [source_url]
Expand Down
2 changes: 1 addition & 1 deletion src/lint/concept_exercises.nim
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ proc isValidConceptExerciseConfig(data: JsonNode;
hasArrayOfStrings(data, "contributors", path, isRequired = false,
uniqueValues = true),
hasValidFiles(data, path, exerciseDir),
hasString(data, "language_versions", path, isRequired = false),
hasArrayOfStrings(data, "forked_from", path, isRequired = false,
uniqueValues = true),
hasString(data, "language_versions", path, isRequired = false),
hasValidRepresenter(data, path),
hasString(data, "icon", path, isRequired = false, checkIsKebab = true),
]
Expand Down
1 change: 1 addition & 0 deletions src/lint/practice_exercises.nim
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ proc isValidPracticeExerciseConfig(data: JsonNode;
hasString(data, "language_versions", path, isRequired = false),
hasBoolean(data, "test_runner", path, isRequired = false),
hasValidRepresenter(data, path),
hasString(data, "icon", path, isRequired = false, checkIsKebab = true),
]
result = allTrue(checks)

Expand Down
9 changes: 4 additions & 5 deletions src/sync/sync_common.nim
Original file line number Diff line number Diff line change
Expand Up @@ -336,14 +336,14 @@ func keyOrderForFmt(e: ConceptExerciseConfig |
when e is ConceptExerciseConfig:
if e.forked_from.isSome() and e.forked_from.get().len > 0:
result.add eckForkedFrom
if e.icon.len > 0:
result.add eckIcon
when e is PracticeExerciseConfig:
# Strips `"test_runner": true`.
if e.test_runner.isSome() and not e.test_runner.get():
result.add eckTestRunner
if e.representer.isSome():
result.add eckRepresenter
if e.icon.len > 0:
result.add eckIcon
result.add eckBlurb
if e.source.isSome():
result.add eckSource
Expand Down Expand Up @@ -396,15 +396,14 @@ proc pretty*(e: ConceptExerciseConfig | PracticeExerciseConfig,
of eckForkedFrom:
when e is ConceptExerciseConfig:
addValOrNull(forked_from, addArray)
of eckIcon:
when e is ConceptExerciseConfig:
result.addString("icon", e.icon)
of eckTestRunner:
when e is PracticeExerciseConfig:
addValOrNull(test_runner, addBool)
of eckRepresenter:
if e.representer.isSome():
result.addRepresenter(e.representer.get());
of eckIcon:
result.addString("icon", e.icon)
of eckBlurb:
result.addString("blurb", e.blurb)
of eckSource:
Expand Down
9 changes: 5 additions & 4 deletions src/types_exercise_config.nim
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ type
# case kind*: ExerciseKind
# of ekConcept:
# forked_from: Option[seq[string]]
# icon: string
# of ekPractice:
# test_runner: Option[bool]
# icon: string
# blurb*: string
# source*: string
# source_url*: string
Expand Down Expand Up @@ -59,9 +59,9 @@ type
eckFiles = "files"
eckLanguageVersions = "language_versions"
eckForkedFrom = "forked_from"
eckIcon = "icon"
eckTestRunner = "test_runner"
eckRepresenter = "representer"
eckIcon = "icon"
eckBlurb = "blurb"
eckSource = "source"
eckSourceUrl = "source_url"
Expand Down Expand Up @@ -100,9 +100,9 @@ type
contributors*: Option[seq[string]]
files*: ConceptExerciseFiles
language_versions*: string
representer*: Option[Representer]
forked_from*: Option[seq[string]] ## Allowed only for a Concept Exercise.
icon*: string ## Allowed only for a Concept Exercise.
representer*: Option[Representer]
icon*: string
blurb*: string
source*: Option[string]
source_url*: Option[string]
Expand All @@ -116,6 +116,7 @@ type
language_versions*: string
test_runner*: Option[bool] ## Allowed only for a Practice Exercise.
representer*: Option[Representer]
icon*: string
# The below fields are synced for a Practice Exercise that exists in the
# `exercism/problem-specifications` repo.
blurb*: string
Expand Down
17 changes: 10 additions & 7 deletions tests/test_fmt.nim
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ proc testFmt =
test "omits optional keys that have an empty value - Concept Exercise":
let p = ConceptExerciseConfig(
originalKeyOrder: @[eckContributors, eckFiles, eckLanguageVersions,
eckForkedFrom, eckIcon, eckRepresenter, eckSource,
eckForkedFrom, eckRepresenter, eckIcon, eckSource,
eckSourceUrl, eckCustom],
contributors: some(newSeq[string]()),
files: ConceptExerciseFiles(
Expand All @@ -96,7 +96,8 @@ proc testFmt =
test "omits optional keys that have an empty value - Practice Exercise":
let p = PracticeExerciseConfig(
originalKeyOrder: @[eckContributors, eckFiles, eckLanguageVersions,
eckRepresenter, eckSource, eckSourceUrl, eckCustom],
eckRepresenter, eckIcon, eckSource, eckSourceUrl,
eckCustom],
contributors: some(newSeq[string]()),
files: PracticeExerciseFiles(
originalKeyOrder: @[fkEditor],
Expand Down Expand Up @@ -148,8 +149,8 @@ proc testFmt =
),
language_versions: ">=1.2.3",
forked_from: some(@["bar/lovely-lasagna"]),
icon: "myicon",
representer: some(Representer(version: 42)),
icon: "myicon",
blurb: "Learn about the basics of Foo by following a lasagna recipe.",
source: some("mysource"),
source_url: some("https://example.com"),
Expand Down Expand Up @@ -180,10 +181,10 @@ proc testFmt =
"forked_from": [
"bar/lovely-lasagna"
],
"icon": "myicon",
"representer": {
"version": 42
},
"icon": "myicon",
"blurb": "Learn about the basics of Foo by following a lasagna recipe.",
"source": "mysource",
"source_url": "https://example.com",
Expand Down Expand Up @@ -217,7 +218,7 @@ proc testFmt =
test "populated config with random key order - Practice Exercise":
var exerciseConfig = PracticeExerciseConfig(
originalKeyOrder: @[eckAuthors, eckContributors, eckFiles,
eckLanguageVersions, eckTestRunner,
eckLanguageVersions, eckTestRunner, eckIcon,
eckRepresenter, eckBlurb, eckSource, eckSourceUrl,
eckCustom],
authors: @["author1"],
Expand All @@ -231,6 +232,7 @@ proc testFmt =
),
language_versions: ">=1.2.3",
test_runner: some(false),
icon: "myicon",
representer: some(Representer(version: 42)),
blurb: "Write a function that returns the earned points in a single toss of a Darts game.",
source: some("Inspired by an exercise created by a professor Della Paolera in Argentina"),
Expand Down Expand Up @@ -263,6 +265,7 @@ proc testFmt =
"representer": {
"version": 42
},
"icon": "myicon",
"blurb": "Write a function that returns the earned points in a single toss of a Darts game.",
"source": "Inspired by an exercise created by a professor Della Paolera in Argentina",
"source_url": "https://example.com",
Expand Down Expand Up @@ -337,15 +340,15 @@ proc testFmt =
let val = j["forked_from"]
if val.kind == JNull or (val.kind == JArray and val.len == 0):
delete(j, "forked_from")
if j["icon"].getStr().len == 0:
delete(j, "icon")
when e is PracticeExerciseConfig:
let val = j["test_runner"]
# Strip `"test_runner": true`
if val.kind == JNull or (val.kind == JBool and val.getBool()):
delete(j, "test_runner")
if j["representer"].kind != JObject or j["representer"].len == 0:
delete(j, "representer")
if j["icon"].getStr().len == 0:
delete(j, "icon")
for k in ["language_versions", "source", "source_url"]:
if j[k].getStr().len == 0:
delete(j, k)
Expand Down
7 changes: 5 additions & 2 deletions tests/test_sync.nim
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,9 @@ proc testSyncCommon =
test "populated Practice Exercise":
let exerciseConfig = PracticeExerciseConfig(
originalKeyOrder: @[eckAuthors, eckContributors, eckFiles,
eckLanguageVersions, eckTestRunner, eckRepresenter,
eckBlurb, eckSource, eckSourceUrl, eckCustom],
eckLanguageVersions, eckTestRunner, eckIcon,
eckRepresenter, eckBlurb, eckSource, eckSourceUrl,
eckCustom],
authors: @["author1"],
contributors: some(@["contributor1"]),
files: PracticeExerciseFiles(
Expand All @@ -235,6 +236,7 @@ proc testSyncCommon =
),
language_versions: ">=1.2.3",
test_runner: some(false),
icon: "myicon",
representer: some(Representer(version: 42)),
blurb: "Write a function that returns the earned points in a single toss of a Darts game.",
source: some("Inspired by an exercise created by a professor Della Paolera in Argentina"),
Expand Down Expand Up @@ -264,6 +266,7 @@ proc testSyncCommon =
},
"language_versions": ">=1.2.3",
"test_runner": false,
"icon": "myicon",
"representer": {
"version": 42
},
Expand Down