-
Notifications
You must be signed in to change notification settings - Fork 163
[Configlet] Define linting rules #2771
Comments
Note: many of the above linting rules could be defined in a JSON schema, but not all (e.g. the cross-track uniqueness of the UUIDs). |
(cc @exercism/track-maintainers) |
If there's only one allowed value, why bother with the field at all?
Should this also be required if it's set to use tabs?
Would it be useful to check if it's a valid username?
What would an invalid Markdown file look like? |
The version key is so that they version used can be detected when there's a later version 4 |
The "version" key is required
As @lpil said, it is to help with possible future updates to the schema. It can also be used to relatively easily detect if one is working with a v2 config.json file.
Question for @iHiD!
This could definitely be useful.
Not being parseable by a Markdown parser? |
By which Markdown parser? I don't think I've ever encountered an invalid Markdown file. Formatting that is "wrong" in context, sure, but I don't know what an actually invalid file would contain. That's why I'm curious about an example. |
The markdown spec says a parser should not reject any document, however it is possible to have incorrect syntax and it'll just render what was typed verbatim. A common one is to get the link syntax wrong. |
Ah okay, I thought that maybe there was some way to check a Markdown document. @SaschaMann do you think we should check the links in Markdown documents? |
Suggest adding:
It would surprise me if modifying
How can you tell in JSON what the contained type of an empty array is?
I do not think it is useful to have any practice exercise with no prerequisites.
This feels like it will take a lot of repetitive busywork to keep up. For every Rust concept exercise, and most Rust practice exercises,
That's not ideal. General-purpose Markdown linters require that a markdown file start with a level-1 heading, and don't skip between levels. Why not just impose that requirement? If this requirement is intended to make it easier to merge templates, it's a better idea to adjust the heading levels of the included markdown file anyway. I think we'll see better quality markdown if standard Markdown linters do the right thing for our source files. |
Good idea!
I'll rephrase :)
It isn't. This is a mistake on my part.
Something for @iHiD to consider.
Hmmm, I didn't consider this. It depends a bit on how easy the transformation is for @iHiD. |
Having warnings instead of errors for syntax that may be wrong, like a reversed link or unmatched asterisks, would be useful. But since there doesn't seem to be anything like an invalid markdown document, perhaps the spec should be rephrased. I don't think this should cause errors, only warnings. |
It's pretty easy: #!/usr/bin/env bash
n="$1"
file="$2"
if [ -z "$n" ] || [ -z "$file" ]; then
echo "USAGE: $0 N FILE"
echo
echo " N: number of markdown layers to insert"
echo " FILE: file on which to work"
exit 1
fi
n_hashes="$(head -c "$n" < /dev/zero | tr '\0' '#')"
sed_expr="$(printf "s/^#+/%s&/" "$n_hashes")"
sed -i -E -e "$sed_expr" "$file" |
I've removed it from the spec.
With this I meant should we use something like the markdown link checker that we use for v3? To verify that external resources can actually be reached? |
Ah okay. It's something that would have to be run periodically, otherwise you'll get failures for unrelated changes in PRs. Might make more sense to keep it separate for that reason. But I'm not sure. |
Yeay. Maybe this should be a GitHub workflow that tracks can integrate and run periodically? |
I suggest adding the rule of "each JSON object must contain only the specified keys". I think the main benefit is for the case of somebody making a typo while trying to add a non-required key. For example:
For typoing a required key (e.g.
But the error message is better if we print e.g.
Somewhat related: we could consider writing something like "note that every key is lowercase". That is: JSON is case-sensitive, our linting will be case-sensitive, and we don't do any normalization of keys in a later step. Lastly, are there any values that we want to be case-insensitive? There are at least some values that we want to normalize while linting, but that should probably have consistent capitalization. For example:
In this case, we want to print a warning that the
We can't say that "all values must be lowercase" because e.g.:
and some tracks might have uppercase characters in e.g. |
This sounds good in principle, but some tracks do use custom properties: https://github.com/exercism/ruby/blob/master/config.json#L5 I don't know how common that is, or if we want to support that, but it is worth considering. What do others think of this?
One thing we could consider is to implement something like what the Git CLI does, where it tries to detect what string the user intended to write versus what was actually written. So if a
I think the |
This issue defines the linting rules that we want the
configlet
tool to have for v3 tracks:Lint check: required files being present
The linter should check if all the required files are present. The non-exercise specific files that must be present are:
config.json
config/maintainers.json
The Concept Exercise specific files that must be present are:
exercises/concept/<slug>/.docs/hints.md
exercises/concept/<slug>/.docs/instructions.md
exercises/concept/<slug>/.docs/introduction.md
exercises/concept/<slug>/.meta/config.json
There will be a similar list for Practice Exercises, but we've not yet defined the spec for that.
Each concept listed in the
config.json
should have the following files:concepts/<slug>/about.md
concepts/<slug>/introduction.md
(pending agreement on Update concept introductions spec #2767)concepts/<slug>/links.json
Lint check: config.json
The
config.json
file should have the following checks:"language"
key is required"language"
value must be a non-empty string"slug"
key is required"slug"
value must be a non-empty, lowercased string using kebab-case"active"
key is required"active"
value must be a boolean"blurb"
key is required"blurb"
value must be a non-empty string"version"
key is required"version"
value must be the integer3
"online_editor.indent_style"
key is required"online_editor.indent_style"
value must be the stringspace
ortab
"online_editor.indent_size"
key is required"online_editor.indent_size"
value must be a positive integer (>= 0)"exercises"
key is required"exercises.concept"
key is required"exercises.concept"
value must be an array"exercises.concept.slug"
key is required"exercises.concept.slug"
value must be a non-empty, lowercased string using kebab-case"exercises.concept.slug"
value must be unique in"exercises.concept[].slug"
and may not exist in"exercises.practice[].slug"
"exercises.concept.name"
key is required"exercises.concept.name"
value must be a non-empty string"exercises.concept.uuid"
key is required"exercises.concept.uuid"
value must be a unique UUID"exercises.concept.deprecated"
key is optional"exercises.concept.deprecated"
value must be a boolean value"exercises.concept.deprecated"
value must generate a warning if set tofalse
"exercises.concept.concepts"
key is required"exercises.concept.concepts"
value must be a non-empty array of strings"exercises.concept.concepts"
values must be non-empty, lowercased strings using kebab-case"exercises.concept.concepts"
values must not have duplicates"exercises.concept.concepts"
values must not be in any other concept exercise's"concepts"
property"exercises.concept.concepts"
values must match the"concepts.slug"
property of one of the concepts"exercises.concept.prerequisites"
key is required"exercises.concept.prerequisites"
value must be a non-empty array of strings for all but one exercise, which can have an empty array as its value"exercises.concept.prerequisites"
values must be non-empty, lowercased strings using kebab-case"exercises.concept.prerequisites"
values must not have duplicates"exercises.concept.prerequisites"
values must match any other concept exercise's"concepts"
property values"exercises.concept.prerequisites"
values must not match any of the values in the exercise's"exercises.concept.concepts"
property"exercises.concept.prerequisites"
values must match the"concepts.slug"
property of one of the concepts"exercises.concept.concepts"
and"exercises.concept.prerequisites"
"exercises.practice"
key is required"exercises.practice"
value must be an array"exercises.practice.slug"
key is required"exercises.practice.slug"
value must be a non-empty, lowercased string using kebab-case"exercises.practice.slug"
value must be unique in"exercises.practice[].slug"
and may not exist in"exercises.concept[].slug"
"exercises.practice.name"
key is required"exercises.practice.name"
value must be a non-empty string"exercises.practice.uuid"
key is required"exercises.practice.uuid"
value must be a unique UUID"exercises.practice.deprecated"
key is optional"exercises.practice.deprecated"
value must be a boolean value"exercises.practice.deprecated"
value must generate a warning if set tofalse
"exercises.practice.difficulty"
key is required"exercises.practice.difficulty"
value must be an integer >= 0 and <= 10"exercises.practice.prerequisites"
key is required"exercises.practice.prerequisites"
value must be a non-empty array of strings"exercises.practice.prerequisites"
values must be non-empty, lowercased strings using kebab-case"exercises.practice.prerequisites"
values must not have duplicates"exercises.practice.prerequisites"
values must match any concept exercise's"exercises.concept.concepts"
values"exercises.practice.prerequisites"
values must match the"concepts.slug"
property of one of the concepts"exercises.foregone"
key is optional"exercises.foregone"
value must be a non-empty array of strings"exercises.foregone"
values must be non-empty, lowercased strings using kebab-case"exercises.foregone"
values must not match any of the concept or practice exercise slugs"concepts"
key is required"concepts"
value must be an array"concepts"
value must have a entry with a matching"slug"
property for each concept listed in a concept exercise's"concepts"
property"concepts.uuid"
key is required"concepts.uuid"
value must be a unique UUID"concepts.slug"
key is required"concepts.slug"
value must be a non-empty, lowercased string using kebab-case"concepts.name"
key is required"concepts.name"
value must be a non-empty, titleized string"concepts.blurb"
key is required"concepts.blurb"
value must be a non-empty string"concepts"
value must have aconcept/<concepts.slug>/about.md
file. Linting rules for this file are specified below."concepts"
value must have aconcept/<concepts.slug>/introduction.md
file (pending agreement on Update concept introductions spec #2767). Linting rules for this file are specified below."concepts"
value must have aconcept/<concepts.slug>/links.json
file. Linting rules for this file are specified below.Lint check: config/maintainers.json
"maintainers"
key is required"maintainers"
value must be an array"maintainers"
array elements must use the correct format (TODO: specify)Lint check: exercises/concept/<exercise-slug>/.meta/config.json
"authors"
key is required"authors"
value must be an non-empty array"authors[].github_username"
key is required"authors[].github_username"
key must be a non-empty string"authors[].github_username"
value is treated case-insensitively"authors[].exercism_username"
key is required"authors[].exercism_username"
key must be a non-empty string"authors[].github_username"
value is treated case-insensitively"contributors"
key is optional"contributors"
value must be an array"contributors[].github_username"
key is required"contributors[].github_username"
key must be a non-empty string"contributors[].github_username"
value is treated case-insensitively"contributors[].exercism_username"
key is required"contributors[].exercism_username"
key must be a non-empty string"contributors[].exercism_username"
value is treated case-insensitively"authors"
or"contributors"
array (no overlap)"editor.solution_files"
key is required"editor.solution_files"
value must be a non-empty array"editor.test_files"
key is required"editor.test_files"
value must be a non-empty array"editor.solution_files"
must exist"editor.test_files"
must exist"editor.solution_files"
or"editor.test_files"
array (no overlap)"forked_from"
key is optional"forked_from"
value must be a non-empty array"forked_from"
values must be strings formatted as<track-slug>/<exercise-slug>
(e.g.fsharp/bird-watcher
)"forked_from"
values must refer to actually implemented exercises"forked_from"
values must be unique"language_versions"
key is optional"language_versions"
value must be a stringLint check: exercises/concept/<exercise-slug>/.docs/hints.md
## General
or## <task>
where<task>
matches the exact task heading in theinstructions.md
Lint check: exercises/concept/<exercise-slug>/.docs/instructions.md
## 1. Do X
Lint check: exercises/concept/<exercise-slug>/.docs/introduction.md
Lint check: exercises/shared/.docs/cli.md
Lint check: exercises/shared/.docs/debug.md
Lint check: concepts/<concept-slug>/about.md
Lint check: concepts/<concept-slug>/introduction.md (pending agreement on #2767)
Lint check: concept/<concept-slug>/links.json
"[].url"
property is required"[].url"
value must be an URL"[].description"
property is required"[].description"
value must be a non-empty string"[].icon_url"
property is optional"[].icon_url"
value must be an URLAny thoughts or feedback welcome and appreciated!
The text was updated successfully, but these errors were encountered: