Основне призначення configlet - лінтування: перевірка того, чи правильно структуровані файли конфігурації треку, як із погляду синтаксису, так і семантики. Неправильно налаштовані треки можуть синхронізуватися некоректно, мати неправильний вигляд на сайті або давати користувачам не найкращий досвід, тож перевірки configlet відіграють важливу роль у підтриманні цілісності Exercism.
Команду lint можна використати для лінтування треку.
configlet [global-options] lint [command-options]
Global options:
-h, --help Show this help message and exit
--version Show this tool's version information and exit
-t, --track-dir <dir> Specify a track directory to use instead of the current directory
-v, --verbosity <verbosity> The verbosity of output. Allowed values: q[uiet], n[ormal], d[etailed]
Ось правила лінтування, які перевіряються.
Лінтер має перевіряти, чи наявні всі обовʼязкові файли. Файли, які не належать до конкретних вправ і мають бути наявні:
config.jsondocs/ABOUT.mddocs/INSTALLATION.mddocs/LEARNING.mddocs/RESOURCES.mddocs/SNIPPET.txtdocs/TESTS.mdexercises/shared/.docs/help.mdexercises/shared/.docs/tests.mdФайли, специфічні для концептуальних вправ, які мають бути наявні:
exercises/concept/<slug>/.docs/hints.mdexercises/concept/<slug>/.docs/instructions.mdexercises/concept/<slug>/.docs/introduction.mdexercises/concept/<slug>/.meta/config.jsonПодібний перелік буде і для практичних вправ, але специфікацію для них ще не визначено.
Кожна концепція, перелічена в config.json, має мати такі файли:
concepts/<slug>/about.mdconcepts/<slug>/introduction.mdconcepts/<slug>/links.jsonДля файлу config.json виконуються такі перевірки:
"language" є обовʼязковим"language" має бути непорожнім рядком тексту (англ. string)¹ довжиною <= 255"slug" є обовʼязковим"slug" має бути рядком тексту у форматі kebab-case² довжиною <= 255"active" є обовʼязковим"active" має бути булевим значенням (англ. Boolean)"blurb" є обовʼязковим"blurb" має бути непорожнім рядком тексту¹ довжиною <= 400"version" є обовʼязковим"version" має бути цілим числом 3
"status.concept_exercises" є обовʼязковим"status.concept_exercises" має бути булевим значенням"status.test_runner" є обовʼязковим"status.test_runner" має бути булевим значенням"status.representer" є обовʼязковим"status.representer" має бути булевим значенням"status.analyzer" є обовʼязковим"status.analyzer" має бути булевим значенням"online_editor.indent_style" є обовʼязковим"online_editor.indent_style" має бути рядком тексту space або tab
"online_editor.indent_size" є обовʼязковим"online_editor.indent_size" має бути цілим числом >= 0 і <= 8"online_editor.highlightjs_language" необовʼязковий"online_editor.highlightjs_language" має бути непорожнім рядком тексту¹"files" необовʼязковий"files" має бути обʼєктом"files.solution" необовʼязковий"files.solution" має бути масивом"files.solution" мають бути коректними шаблонами⁵"files.solution" не мають містити дублікатів"files.test" необовʼязковий"files.test" має бути масивом"files.test" мають бути коректними шаблонами⁵"files.test" не мають містити дублікатів"files.example" необовʼязковий"files.example" має бути масивом"files.example" мають бути коректними шаблонами⁵"files.example" не мають містити дублікатів"files.exemplar" необовʼязковий"files.exemplar" має бути масивом"files.exemplar" мають бути коректними шаблонами⁵"files.exemplar" не мають містити дублікатів"files.editor" необовʼязковий"files.editor" має бути масивом"files.editor" мають бути коректними шаблонами⁵"files.editor" не мають містити дублікатів"files.invalidator" необовʼязковий"files.invalidator" має бути масивом"files.invalidator" мають бути коректними шаблонами⁵"files.invalidator" не мають містити дублікатів"files.solution", "files.test", "files.example", "files.exemplar", "files.editor" або "files.invalidator" (без перетинів)
d або plsql, файли з "files.solution" і "files.test" можуть перетинатися"files.example і "files.exemplar" можуть перетинатися"test_runner.average_run_time" є обовʼязковим, якщо "status.test_runner" дорівнює true
"test_runner.average_run_time" має бути цілим числом > 0"approaches.snippet_extension" є обовʼязковим, якщо в треку є один або більше підходів"approaches.snippet_extension" має бути непорожнім рядком тексту¹"exercises" є обовʼязковим"exercises.concept" є обовʼязковим"exercises.concept" має бути масивом"exercises.concept[].slug" є обовʼязковим"exercises.concept[].slug" має бути рядком тексту у форматі kebab-case² довжиною <= 255"exercises.concept[].slug" має бути унікальним серед "exercises.concept[].slug" і не може траплятися в "exercises.practice[].slug"
"exercises.concept[].name" є обовʼязковим"exercises.concept[].name" має бути рядком тексту у стилі Title Case³ довжиною <= 255"exercises.concept[].uuid" є обовʼязковим"exercises.concept[].uuid" має бути унікальним рядком тексту UUID версії 4⁶"exercises.concept[].uuid" для кожної вправи ніколи не має змінюватися"exercises.concept[].concepts" є обовʼязковим"exercises.concept[].concepts" має бути непорожнім масивом рядків тексту, якщо "exercises.concept[].status" не дорівнює deprecated
"exercises.concept[].concepts" має бути порожнім масивом, якщо "exercises.concept[].status" дорівнює deprecated
"exercises.concept[].concepts" мають бути рядками тексту у форматі kebab-case²"exercises.concept[].concepts" не мають містити дублікатів"exercises.concept[].concepts" не мають бути у властивості "concepts" жодної іншої концептуальної вправи"exercises.concept[].concepts" мають відповідати властивості "concepts.slug" однієї з концепцій"exercises.concept[].prerequisites" є обовʼязковим"exercises.concept[].prerequisites" має бути непорожнім масивом рядків тексту, якщо "exercises.concept[].status" не дорівнює deprecated, окрім рівно однієї вправи, якій дозволено мати порожній масив як значення"exercises.concept[].prerequisites" має бути порожнім масивом, якщо "exercises.concept[].status" дорівнює deprecated
"exercises.concept[].prerequisites" мають бути рядками тексту у форматі kebab-case²"exercises.concept[].prerequisites" не мають містити дублікатів"exercises.concept[].prerequisites" мають збігатися зі значеннями властивості "concepts" будь-якої іншої концептуальної вправи"exercises.concept[].prerequisites" не мають збігатися з жодним зі значень властивості "exercises.concept[].concepts" цієї вправи"exercises.concept[].prerequisites" мають відповідати властивості "concepts.slug" однієї з концепцій"exercises.concept[].concepts" і "exercises.concept[].prerequisites" не має бути жодних циклів"exercises.concept[].status" необовʼязковий"exercises.concept[].status" має бути рядком тексту wip, beta, active або deprecated
"exercises.practice" є обовʼязковим"exercises.practice" має бути масивом"exercises.practice[].slug" є обовʼязковим"exercises.practice[].slug" має бути рядком тексту у форматі kebab-case² довжиною <= 255"exercises.practice[].slug" має бути унікальним серед "exercises.practice[].slug" і не може траплятися в "exercises.concept[].slug"
"exercises.practice[].slug", яке дорівнює рядку тексту hello-world
"exercises.practice[].name" є обовʼязковим"exercises.practice[].name" має бути рядком тексту у стилі Title Case³ довжиною <= 255"exercises.practice[].uuid" є обовʼязковим"exercises.practice[].uuid" має бути унікальним рядком тексту UUID версії 4⁶"exercises.practice[].uuid" для кожної вправи ніколи не має змінюватися"exercises.practice[].difficulty" є обовʼязковим"exercises.practice[].difficulty" має бути цілим числом >= 1 і <= 10"exercises.practice[].practices" є обовʼязковим"exercises.practice[].practices" має бути непорожнім масивом рядків тексту, якщо "exercises.practice[].status" не дорівнює deprecated
"exercises.practice[].practices" має бути порожнім масивом, якщо "exercises.practice[].status" дорівнює deprecated
"exercises.practice[].practices" мають бути рядками тексту у форматі kebab-case²"exercises.practice[].practices" не мають містити дублікатів"exercises.practice[].practices" мають відповідати властивості "concepts[].slug" однієї з концепцій"exercises.practice[].practices" мають посилатися на слаг окремої концепції не більше ніж 10 разів (у всіх вправах разом)"exercises.practice[].prerequisites" є обовʼязковим"exercises.practice[].prerequisites" має бути непорожнім масивом рядків тексту, якщо "exercises.practice[].status" не дорівнює deprecated
"exercises.practice[].prerequisites" має бути порожнім масивом, якщо "exercises.practice[].status" дорівнює deprecated
"exercises.practice[].prerequisites" має бути порожнім масивом, якщо "exercises.practice[].slug" дорівнює hello-world
"exercises.practice[].prerequisites" мають бути рядками тексту у форматі kebab-case²"exercises.practice[].prerequisites" не мають містити дублікатів"exercises.practice[].prerequisites" мають збігатися зі значеннями "exercises.concept[].concepts" якоїсь концептуальної вправи"exercises.practice[].prerequisites" мають відповідати властивості "concepts[].slug" однієї з концепцій"exercises.practice[].status" необовʼязковий"exercises.practice[].status" має бути рядком тексту wip, beta, active або deprecated
"exercises.practice[].slug" дорівнює hello-world, значення "exercises.practice[].status" має бути або пропущене, або рядком тексту active
"exercises.foregone" необовʼязковий"exercises.foregone" має бути масивом"exercises.foregone" мають бути рядками тексту у форматі kebab-case²"exercises.foregone" не мають містити дублікатів"exercises.foregone" не мають збігатися зі слагами жодної концептуальної чи практичної вправи"concepts" є обовʼязковим"concepts" має бути масивом"concepts[].uuid" є обовʼязковим"concepts[].uuid" має бути унікальним рядком тексту UUID версії 4⁶"concepts[].uuid" для кожної концепції ніколи не має змінюватися"concepts[].slug" є обовʼязковим"concepts[].slug" має бути рядком тексту у форматі kebab-case² довжиною <= 255"concepts[].name" є обовʼязковим"concepts[].name" має бути рядком тексту у стилі Title Case³ довжиною <= 255"concepts[].tags" необовʼязковий"concepts[].tags.all" необовʼязковий, окрім випадку, коли "concepts[].tags.any" порожній"concepts[].tags.all" має бути масивом"concepts[].tags.all" мають бути непорожніми рядками тексту⁷, які є тегами, довжиною <= 255"concepts[].tags.all" не мають містити дублікатів"concepts[].tags.any" необовʼязковий, окрім випадку, коли "concepts[].tags.all" порожній"concepts[].tags.any" має бути масивом"concepts[].tags.any" мають бути непорожніми рядками тексту⁷, які є тегами, довжиною <= 255"concepts[].tags.any" не мають містити дублікатів"concepts[].tags.not" необовʼязковий"concepts[].tags.not" має бути масивом"concepts[].tags.not" мають бути непорожніми рядками тексту⁷, які є тегами, довжиною <= 255"concepts[].tags.not" не мають містити дублікатів"concepts" має мати файл concept/<concepts.slug>/about.md. Правила лінтування для цього файлу описано нижче."concepts" має мати файл concept/<concepts.slug>/introduction.md. Правила лінтування для цього файлу описано нижче."concepts" має мати файл concept/<concepts.slug>/links.json. Правила лінтування для цього файлу описано нижче."key_features" необовʼязковий"key_features" має бути масивом довжиною = 6"key_features[].icon" є обовʼязковим"key_features[].icon" має використовувати одне з наперед визначених значень іконок
"key_features[].title" є обовʼязковим"key_features[].title" має бути рядком тексту у стилі Sentence Case⁴ довжиною <= 25"key_features[].content" є обовʼязковим"key_features[].content" має бути непорожнім рядком тексту¹ довжиною <= 100"tags" є обовʼязковим"tags" має бути масивом рядків тексту"tags" не мають містити дублікатів"tags" мають використовувати одне з наперед визначених значень тегів
"blurb" є обовʼязковим"blurb" має бути непорожнім рядком тексту¹ довжиною <= 350"source" необовʼязковий"source" має бути непорожнім рядком тексту¹"source_url" необовʼязковий"source_url" має бути URL-адресою"authors" є обовʼязковим"authors" має бути непорожнім масивом"authors" мають бути непорожніми рядками тексту¹"authors" не мають містити дублікатів"authors" порівнюються без урахування регістру"contributors" необовʼязковий"contributors" має бути масивом"contributors" мають бути непорожніми рядками тексту¹"contributors" не мають містити дублікатів"contributors" порівнюються без урахування регістру"authors" або "contributors" (без перетинів)"files.solution" є обовʼязковим"files.solution" має бути непорожнім масивом"files.solution" не мають містити дублікатів"files.test" є обовʼязковим"files.test" має бути непорожнім масивом"files.test" не мають містити дублікатів"files.exemplar" є обовʼязковим"files.exemplar" має бути непорожнім масивом"files.exemplar" не мають містити дублікатів"files.editor" необовʼязковий"files.editor" має бути масивом"files.editor" не мають містити дублікатів"files.invalidator" необовʼязковий"files.invalidator" має бути масивом"files.invalidator" не мають містити дублікатів"files.solution", мають існувати"files.test", мають існувати"files.exemplar", мають існувати"files.editor", мають існувати"files.invalidator", мають існувати"files.solution", "files.test", "files.exemplar" або "files.invalidator" (без перетинів)
d або plsql, файли з "files.solution" і "files.test" можуть перетинатися"forked_from" необовʼязковий"forked_from" має бути масивом"forked_from" мають бути рядками тексту у форматі <track-slug>/<exercise-slug> (наприклад, fsharp/bird-watcher)"forked_from" мають указувати на реально реалізовані вправи"forked_from" не мають містити дублікатів"language_versions" необовʼязковий"language_versions" має бути рядком тексту"representer.version" необовʼязковий"representer.version" має бути цілим числом >= 1"icon" необовʼязковий"icon" має бути рядком тексту у форматі kebab-case²## General, або ## X. <task>, де X збігається з номером завдання в заголовку у instructions.md
## 1. Do X
"concepts.slug" однієї з концепцій у config.json треку."blurb" є обовʼязковим"blurb" має бути непорожнім рядком тексту¹ довжиною <= 350"source" необовʼязковий"source" має бути непорожнім рядком тексту¹"source_url" необовʼязковий"source_url" має бути URL-адресою"authors" необовʼязковий"authors" має бути масивом"authors" мають бути непорожніми рядками тексту¹"authors" не мають містити дублікатів"authors" порівнюються без урахування регістру"contributors" необовʼязковий"contributors" має бути масивом"contributors" мають бути непорожніми рядками тексту¹"contributors" не мають містити дублікатів"contributors" порівнюються без урахування регістру"authors" або "contributors" (без перетинів)"files.solution" є обовʼязковим"files.solution" має бути непорожнім масивом"files.solution" не мають містити дублікатів"files.test" є обовʼязковим"files.test" має бути непорожнім масивом"files.test" не мають містити дублікатів"files.example" є обовʼязковим"files.example" має бути непорожнім масивом"files.example" не мають містити дублікатів"files.editor" необовʼязковий"files.editor" має бути масивом"files.editor" не мають містити дублікатів"files.invalidator" необовʼязковий"files.invalidator" має бути масивом"files.invalidator" не мають містити дублікатів"files.solution", мають існувати"files.test", мають існувати"files.example", мають існувати"files.editor", мають існувати"files.invalidator", мають існувати"files.solution", "files.test", "files.example або "files.invalidator" (без перетинів)
d або plsql, файли з "files.solution" і "files.test" можуть перетинатися"language_versions" необовʼязковий"language_versions" має бути рядком тексту"test_runner" необовʼязковий"test_runner" має бути булевим значенням"representer.version" необовʼязковий"representer.version" має бути цілим числом >= 1"icon" необовʼязковий"icon" має бути рядком тексту у форматі kebab-case²introduction.md або сусідній каталог"introduction.authors" необовʼязковий"introduction.authors" має бути масивом"introduction.authors" мають бути непорожніми рядками тексту¹"introduction.authors" не мають містити дублікатів"introduction.authors" порівнюються без урахування регістру"introduction.authors" не порожній, має існувати непорожній файл introduction.md
"introduction.contributors" необовʼязковий"introduction.contributors" має бути масивом"introduction.contributors" мають бути непорожніми рядками тексту¹"introduction.contributors" не мають містити дублікатів"introduction.contributors" порівнюються без урахування регістру"introduction.contributors" не порожній, має існувати непорожній файл introduction.md
"introduction.authors" або "introduction.contributors" (без перетинів)"approaches" необовʼязковий, окрім випадку, коли наявний сусідній каталог (який містить файли підходу)"approaches" має бути масивом обʼєктів"approaches[].uuid" є обовʼязковим"approaches[].uuid" має бути унікальним рядком тексту UUID версії 4⁶"approaches[].uuid" для кожної концепції ніколи не має змінюватися"approaches[].slug" є обовʼязковим"approaches[].slug" має бути рядком тексту у форматі kebab-case² довжиною <= 255"approaches[].slug" має мати відповідний непорожній файл <slug>/content.md
"approaches[].slug" має мати відповідний непорожній файл <slug>/snippet.txt
"approaches[].title" є обовʼязковим"approaches[].title" має бути рядком тексту у стилі Title Case³ довжиною <= 255"approaches[].blurb" є обовʼязковим"approaches[].blurb" має бути непорожнім рядком тексту¹ довжиною <= 350"approaches[].authors" є обовʼязковим"approaches[].authors" має бути непорожнім масивом"approaches[].authors" мають бути непорожніми рядками тексту¹"approaches[].authors" не мають містити дублікатів"approaches[].authors" порівнюються без урахування регістру"approaches[].contributors" необовʼязковий"approaches[].contributors" має бути масивом"approaches[].contributors" мають бути непорожніми рядками тексту¹"approaches[].contributors" не мають містити дублікатів"approaches[].contributors" порівнюються без урахування регістру"approaches[].authors" або "approaches[].contributors" (без перетинів)"approaches[].tags" необовʼязковий"approaches[].tags.all" необовʼязковий, окрім випадку, коли "approaches[].tags.any" порожній"approaches[].tags.all" має бути масивом"approaches[].tags.all" мають бути непорожніми рядками тексту⁷, які є тегами, довжиною <= 255"approaches[].tags.all" не мають містити дублікатів"approaches[].tags.any" необовʼязковий, окрім випадку, коли "approaches[].tags.all" порожній"approaches[].tags.any" має бути масивом"approaches[].tags.any" мають бути непорожніми рядками тексту⁷, які є тегами, довжиною <= 255"approaches[].tags.any" не мають містити дублікатів"approaches[].tags.not" необовʼязковий"approaches[].tags.not" має бути масивом"approaches[].tags.not" мають бути непорожніми рядками тексту⁷, які є тегами, довжиною <= 255"approaches[].tags.not" не мають містити дублікатів.approaches/config.json існує відповідний запис "approaches[].slug"
.approaches/config.json існує відповідний запис "approaches[].slug"
approaches.snippet_extension у файлі config.json треку"articles" необовʼязковий, окрім випадку, коли наявний сусідній каталог (який містить файли статті)"articles" має бути масивом обʼєктів"articles[].uuid" є обовʼязковим"articles[].uuid" має бути унікальним рядком тексту UUID версії 4⁶"articles[].uuid" для кожної концепції ніколи не має змінюватися"articles[].slug" є обовʼязковим"articles[].slug" має бути рядком тексту у форматі kebab-case² довжиною <= 255"articles[].slug" має мати відповідний непорожній файл <slug>/content.md
"articles[].slug" має мати відповідний непорожній файл <slug>/snippet.md
"articles[].title" є обовʼязковим"articles[].title" має бути рядком тексту у стилі Title Case³ довжиною <= 255"articles[].blurb" є обовʼязковим"articles[].blurb" має бути непорожнім рядком тексту¹ довжиною <= 350"articles[].authors" є обовʼязковим"articles[].authors" має бути непорожнім масивом"articles[].authors" мають бути непорожніми рядками тексту¹"articles[].authors" не мають містити дублікатів"articles[].authors" порівнюються без урахування регістру"articles[].contributors" необовʼязковий"articles[].contributors" має бути масивом"articles[].contributors" мають бути непорожніми рядками тексту¹"articles[].contributors" не мають містити дублікатів"articles[].contributors" порівнюються без урахування регістру"articles[].authors" або "articles[].contributors" (без перетинів).articles/config.json існує відповідний запис "articles[].slug"
.articles/config.json існує відповідний запис "articles[].slug"
"[].url" є обовʼязковою"[].url" має бути URL-адресою"[].description" є обовʼязковою"[].description" має бути непорожнім рядком тексту¹"[].icon_url" необовʼязкова"[].icon_url" має бути URL-адресою"blurb" є обовʼязковим"blurb" має бути непорожнім рядком тексту¹ довжиною <= 350"authors" є обовʼязковим"authors" має бути масивом"authors" мають бути непорожніми рядками тексту¹"authors" не мають містити дублікатів"authors" порівнюються без урахування регістру"contributors" необовʼязковий"contributors" має бути масивом"contributors" мають бути непорожніми рядками тексту¹"contributors" не мають містити дублікатів"contributors" порівнюються без урахування регістру"authors" або "contributors" (без перетинів)Непорожній рядок тексту: рядок тексту, який містить принаймні один символ, що не є пробільним.
Рядок тексту у форматі kebab-case: рядок тексту, який містить лише символи з діапазону [a-z0-9], необовʼязково розділені дефісами (наприклад, «two-fer»). Він має відповідати регулярному виразу: ^[a-z0-9]+(-[a-z0-9]+)*$
Рядок тексту у стилі Title Case: непорожній рядок тексту, який відповідає наведеним нижче настановам Chicago Manual of Style:
Рядок тексту у стилі Sentence Case: непорожній рядок тексту, який відповідає наведеним нижче настановам:
Коректний шаблон files: непорожній рядок тексту¹, який задає розташування файлу, використаного у вправі, відносно каталогу вправи. Шаблон може використовувати один із таких заповнювачів:
%{kebab_slug}: слаг вправи у kebab-case (наприклад, bit-manipulation)%{snake_slug}: слаг вправи у snake_case (наприклад, bit_manipulation)%{camel_slug}: слаг вправи у camelCase (наприклад, bitManipulation)%{pascal_slug}: слаг вправи у PascalCase (наприклад, BitManipulation)Унікальний рядок тексту UUID версії 4: рядок тексту, який задовольняє всі ці умови:
config.json рівня треку для конкретного треку Exercismconfig.json рівня треку жодного іншого треку Exercismcanonical-data.json у https://github.com/exercism/problem-specifications^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$
Наприклад, наведений нижче UUID має правильну форму:
d334ffe3-657e-4725-a950-290b284b6d9f
Щоб згенерувати придатний UUID, можна виконати configlet uuid.
Коректний tag аналізатора: непорожній рядок тексту¹ у форматі <category>:<thing>.
Значення <category> має бути одним із:
paradigm (наприклад, paradigm:functional)technique (наприклад, technique:recursion)construct (наприклад, construct:bitwise-and)uses (наприклад, uses:DateTime.add_seconds)Значення <thing> має бути непорожнім рядком тексту¹.