O uso principal do configlet é a verificação: checar se os arquivos de configuração de uma track estão estruturados corretamente, tanto sintática quanto semanticamente. Tracks mal configuradas podem não sincronizar corretamente, podem parecer erradas no site ou podem oferecer uma experiência ruim para quem usa. Por isso, as proteções do configlet têm um papel importante em manter a integridade do Exercism.
O comando lint pode ser usado para verificar uma track.
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]
Estas são as regras de verificação que são checadas.
O verificador deve checar se todos os arquivos obrigatórios estão presentes. Os arquivos que não são específicos de exercícios e que devem estar presentes são:
config.jsondocs/ABOUT.mddocs/INSTALLATION.mddocs/LEARNING.mddocs/RESOURCES.mddocs/SNIPPET.txtdocs/TESTS.mdexercises/shared/.docs/help.mdexercises/shared/.docs/tests.mdOs arquivos específicos de exercícios de conceito que devem estar presentes são:
exercises/concept/<slug>/.docs/hints.mdexercises/concept/<slug>/.docs/instructions.mdexercises/concept/<slug>/.docs/introduction.mdexercises/concept/<slug>/.meta/config.jsonHaverá uma lista semelhante para os exercícios de prática, mas ainda não definimos a especificação para isso.
Cada conceito listado no config.json deve ter os seguintes arquivos:
concepts/<slug>/about.mdconcepts/<slug>/introduction.mdconcepts/<slug>/links.jsonO arquivo config.json deve passar pelas seguintes verificações:
"language" é obrigatória"language" deve ser uma string não vazia¹ com comprimento <= 255"slug" é obrigatória"slug" deve ser uma string em kebab-case² com comprimento <= 255"active" é obrigatória"active" deve ser um Boolean"blurb" é obrigatória"blurb" deve ser uma string não vazia¹ com comprimento <= 400"version" é obrigatória"version" deve ser o inteiro 3
"status.concept_exercises" é obrigatória"status.concept_exercises" deve ser um Boolean"status.test_runner" é obrigatória"status.test_runner" deve ser um Boolean"status.representer" é obrigatória"status.representer" deve ser um Boolean"status.analyzer" é obrigatória"status.analyzer" deve ser um Boolean"online_editor.indent_style" é obrigatória"online_editor.indent_style" deve ser a string space ou tab
"online_editor.indent_size" é obrigatória"online_editor.indent_size" deve ser um inteiro >= 0 e <= 8"online_editor.highlightjs_language" é opcional"online_editor.highlightjs_language" deve ser uma string não vazia¹"files" é opcional"files" deve ser um objeto"files.solution" é opcional"files.solution" deve ser um array"files.solution" devem ser padrões válidos⁵"files.solution" não podem ter duplicatas"files.test" é opcional"files.test" deve ser um array"files.test" devem ser padrões válidos⁵"files.test" não podem ter duplicatas"files.example" é opcional"files.example" deve ser um array"files.example" devem ser padrões válidos⁵"files.example" não podem ter duplicatas"files.exemplar" é opcional"files.exemplar" deve ser um array"files.exemplar" devem ser padrões válidos⁵"files.exemplar" não podem ter duplicatas"files.editor" é opcional"files.editor" deve ser um array"files.editor" devem ser padrões válidos⁵"files.editor" não podem ter duplicatas"files.invalidator" é opcional"files.invalidator" deve ser um array"files.invalidator" devem ser padrões válidos⁵"files.invalidator" não podem ter duplicatas"files.solution", "files.test", "files.example", "files.exemplar", "files.editor" ou "files.invalidator" (sem sobreposição)
d ou plsql, os arquivos "files.solution" e "files.test" podem se sobrepor"files.example e "files.exemplar" podem se sobrepor"test_runner.average_run_time" é obrigatória se "status.test_runner" for igual a true
"test_runner.average_run_time" deve ser um inteiro > 0"approaches.snippet_extension" é obrigatória se a track tiver uma ou mais abordagens"approaches.snippet_extension" deve ser uma string não vazia¹"exercises" é obrigatória"exercises.concept" é obrigatória"exercises.concept" deve ser um array"exercises.concept[].slug" é obrigatória"exercises.concept[].slug" deve ser uma string em kebab-case² com comprimento <= 255"exercises.concept[].slug" deve ser único em "exercises.concept[].slug" e não pode existir em "exercises.practice[].slug"
"exercises.concept[].name" é obrigatória"exercises.concept[].name" deve ser uma string em Title Case³ com comprimento <= 255"exercises.concept[].uuid" é obrigatória"exercises.concept[].uuid" deve ser uma string UUID versão 4 única⁶"exercises.concept[].uuid" de cada exercício nunca pode mudar"exercises.concept[].concepts" é obrigatória"exercises.concept[].concepts" deve ser um array não vazio de strings se "exercises.concept[].status" não for igual a deprecated
"exercises.concept[].concepts" deve ser um array vazio se "exercises.concept[].status" for igual a deprecated
"exercises.concept[].concepts" devem ser strings em kebab-case²"exercises.concept[].concepts" não podem ter duplicatas"exercises.concept[].concepts" não podem estar na propriedade "concepts" de nenhum outro exercício de conceito"exercises.concept[].concepts" devem corresponder à propriedade "concepts.slug" de um dos conceitos"exercises.concept[].prerequisites" é obrigatória"exercises.concept[].prerequisites" deve ser um array não vazio de strings se "exercises.concept[].status" não for igual a deprecated, exceto por exatamente um exercício que pode ter um array vazio como valor"exercises.concept[].prerequisites" deve ser um array vazio se "exercises.concept[].status" for igual a deprecated
"exercises.concept[].prerequisites" devem ser strings em kebab-case²"exercises.concept[].prerequisites" não podem ter duplicatas"exercises.concept[].prerequisites" devem corresponder aos valores da propriedade "concepts" de qualquer outro exercício de conceito"exercises.concept[].prerequisites" não podem corresponder a nenhum dos valores da propriedade "exercises.concept[].concepts" do exercício"exercises.concept[].prerequisites" devem corresponder à propriedade "concepts.slug" de um dos conceitos"exercises.concept[].concepts" e "exercises.concept[].prerequisites"
"exercises.concept[].status" é opcional"exercises.concept[].status" deve ser a string wip, beta, active ou deprecated
"exercises.practice" é obrigatória"exercises.practice" deve ser um array"exercises.practice[].slug" é obrigatória"exercises.practice[].slug" deve ser uma string em kebab-case² com comprimento <= 255"exercises.practice[].slug" deve ser único em "exercises.practice[].slug" e não pode existir em "exercises.concept[].slug"
"exercises.practice[].slug" que seja a string hello-world
"exercises.practice[].name" é obrigatória"exercises.practice[].name" deve ser uma string em Title Case³ com comprimento <= 255"exercises.practice[].uuid" é obrigatória"exercises.practice[].uuid" deve ser uma string UUID versão 4 única⁶"exercises.practice[].uuid" de cada exercício nunca pode mudar"exercises.practice[].difficulty" é obrigatória"exercises.practice[].difficulty" deve ser um inteiro >= 1 e <= 10"exercises.practice[].practices" é obrigatória"exercises.practice[].practices" deve ser um array não vazio de strings se "exercises.practice[].status" não for igual a deprecated
"exercises.practice[].practices" deve ser um array vazio se "exercises.practice[].status" for igual a deprecated
"exercises.practice[].practices" devem ser strings em kebab-case²"exercises.practice[].practices" não podem ter duplicatas"exercises.practice[].practices" devem corresponder à propriedade "concepts[].slug" de um dos conceitos"exercises.practice[].practices" devem se referir ao slug de um conceito individual no máximo 10 vezes (considerando todos os exercícios)"exercises.practice[].prerequisites" é obrigatória"exercises.practice[].prerequisites" deve ser um array não vazio de strings se "exercises.practice[].status" não for igual a deprecated
"exercises.practice[].prerequisites" deve ser um array vazio se "exercises.practice[].status" for igual a deprecated
"exercises.practice[].prerequisites" deve ser um array vazio se "exercises.practice[].slug" for igual a hello-world
"exercises.practice[].prerequisites" devem ser strings em kebab-case²"exercises.practice[].prerequisites" não podem ter duplicatas"exercises.practice[].prerequisites" devem corresponder aos valores de "exercises.concept[].concepts" de algum exercício de conceito"exercises.practice[].prerequisites" devem corresponder à propriedade "concepts[].slug" de um dos conceitos"exercises.practice[].status" é opcional"exercises.practice[].status" deve ser a string wip, beta, active ou deprecated
"exercises.practice[].status", se "exercises.practice[].slug" for igual a hello-world, deve ser omitido ou ser a string active
"exercises.foregone" é opcional"exercises.foregone" deve ser um array"exercises.foregone" devem ser strings em kebab-case²"exercises.foregone" não podem ter duplicatas"exercises.foregone" não podem corresponder a nenhum dos slugs de exercícios de conceito ou de prática"concepts" é obrigatória"concepts" deve ser um array"concepts[].uuid" é obrigatória"concepts[].uuid" deve ser uma string UUID versão 4 única⁶"concepts[].uuid" de cada conceito nunca pode mudar"concepts[].slug" é obrigatória"concepts[].slug" deve ser uma string em kebab-case² com comprimento <= 255"concepts[].name" é obrigatória"concepts[].name" deve ser uma string em Title Case³ com comprimento <= 255"concepts[].tags" é opcional"concepts[].tags.all" é opcional, a menos que "concepts[].tags.any" esteja vazia"concepts[].tags.all" deve ser um array"concepts[].tags.all" devem ser strings de tag⁷ não vazias com comprimento <= 255"concepts[].tags.all" não podem ter duplicatas"concepts[].tags.any" é opcional, a menos que "concepts[].tags.all" esteja vazia"concepts[].tags.any" deve ser um array"concepts[].tags.any" devem ser strings de tag⁷ não vazias com comprimento <= 255"concepts[].tags.any" não podem ter duplicatas"concepts[].tags.not" é opcional"concepts[].tags.not" deve ser um array"concepts[].tags.not" devem ser strings de tag⁷ não vazias com comprimento <= 255"concepts[].tags.not" não podem ter duplicatas"concepts" deve ter um arquivo concept/<concepts.slug>/about.md. As regras de verificação para esse arquivo estão especificadas abaixo."concepts" deve ter um arquivo concept/<concepts.slug>/introduction.md. As regras de verificação para esse arquivo estão especificadas abaixo."concepts" deve ter um arquivo concept/<concepts.slug>/links.json. As regras de verificação para esse arquivo estão especificadas abaixo."key_features" é opcional"key_features" deve ser um array com comprimento = 6"key_features[].icon" é obrigatória"key_features[].icon" deve usar um dos valores de ícone predefinidos
"key_features[].title" é obrigatória"key_features[].title" deve ser uma string em Sentence Case⁴ com comprimento <= 25"key_features[].content" é obrigatória"key_features[].content" deve ser uma string não vazia¹ com comprimento <= 100"tags" é obrigatória"tags" deve ser um array de strings"tags" não podem ter duplicatas"tags" devem usar um dos valores de tag predefinidos
"blurb" é obrigatória"blurb" deve ser uma string não vazia¹ com comprimento <= 350"source" é opcional"source" deve ser uma string não vazia¹"source_url" é opcional"source_url" deve ser uma URL"authors" é obrigatória"authors" deve ser um array não vazio"authors" devem ser strings não vazias¹"authors" não podem ter duplicatas"authors" são tratados sem diferenciar maiúsculas de minúsculas"contributors" é opcional"contributors" deve ser um array"contributors" devem ser strings não vazias¹"contributors" não podem ter duplicatas"contributors" são tratados sem diferenciar maiúsculas de minúsculas"authors" ou "contributors" (sem sobreposição)"files.solution" é obrigatória"files.solution" deve ser um array não vazio"files.solution" não podem ter duplicatas"files.test" é obrigatória"files.test" deve ser um array não vazio"files.test" não podem ter duplicatas"files.exemplar" é obrigatória"files.exemplar" deve ser um array não vazio"files.exemplar" não podem ter duplicatas"files.editor" é opcional"files.editor" deve ser um array"files.editor" não podem ter duplicatas"files.invalidator" é opcional"files.invalidator" deve ser um array"files.invalidator" não podem ter duplicatas"files.solution" devem existir"files.test" devem existir"files.exemplar" devem existir"files.editor" devem existir"files.invalidator" devem existir"files.solution", "files.test", "files.exemplar" ou "files.invalidator" (sem sobreposição)
d ou plsql, os arquivos "files.solution" e "files.test" podem se sobrepor"forked_from" é opcional"forked_from" deve ser um array"forked_from" devem ser strings formatadas como <track-slug>/<exercise-slug> (por exemplo, fsharp/bird-watcher)"forked_from" devem se referir a exercícios realmente implementados"forked_from" não podem ter duplicatas"language_versions" é opcional"language_versions" deve ser uma string"representer.version" é opcional"representer.version" deve ser um inteiro >= 1"icon" é opcional"icon" deve ser uma string em kebab-case²## General ou ## X. <task>, em que X corresponde ao título do número da tarefa em instructions.md
## 1. Do X
"concepts.slug" de um dos conceitos no config.json da track."blurb" é obrigatória"blurb" deve ser uma string não vazia¹ com comprimento <= 350"source" é opcional"source" deve ser uma string não vazia¹"source_url" é opcional"source_url" deve ser uma URL"authors" é opcional"authors" deve ser um array"authors" devem ser strings não vazias¹"authors" não podem ter duplicatas"authors" são tratados sem diferenciar maiúsculas de minúsculas"contributors" é opcional"contributors" deve ser um array"contributors" devem ser strings não vazias¹"contributors" não podem ter duplicatas"contributors" são tratados sem diferenciar maiúsculas de minúsculas"authors" ou "contributors" (sem sobreposição)"files.solution" é obrigatória"files.solution" deve ser um array não vazio"files.solution" não podem ter duplicatas"files.test" é obrigatória"files.test" deve ser um array não vazio"files.test" não podem ter duplicatas"files.example" é obrigatória"files.example" deve ser um array não vazio"files.example" não podem ter duplicatas"files.editor" é opcional"files.editor" deve ser um array"files.editor" não podem ter duplicatas"files.invalidator" é opcional"files.invalidator" deve ser um array"files.invalidator" não podem ter duplicatas"files.solution" devem existir"files.test" devem existir"files.example" devem existir"files.editor" devem existir"files.invalidator" devem existir"files.solution", "files.test", "files.example ou "files.invalidator" (sem sobreposição)
d ou plsql, os arquivos "files.solution" e "files.test" podem se sobrepor"language_versions" é opcional"language_versions" deve ser uma string"test_runner" é opcional"test_runner" deve ser um Boolean"representer.version" é opcional"representer.version" deve ser um inteiro >= 1"icon" é opcional"icon" deve ser uma string em kebab-case²introduction.md ou um diretório irmão"introduction.authors" é opcional"introduction.authors" deve ser um array"introduction.authors" devem ser strings não vazias¹"introduction.authors" não podem ter duplicatas"introduction.authors" são tratados sem diferenciar maiúsculas de minúsculas"introduction.authors" não estiver vazio, deve haver um arquivo introduction.md não vazio"introduction.contributors" é opcional"introduction.contributors" deve ser um array"introduction.contributors" devem ser strings não vazias¹"introduction.contributors" não podem ter duplicatas"introduction.contributors" são tratados sem diferenciar maiúsculas de minúsculas"introduction.contributors" não estiver vazio, deve haver um arquivo introduction.md não vazio"introduction.authors" ou "introduction.contributors" (sem sobreposição)"approaches" é opcional, a menos que exista um diretório irmão presente (que contém os arquivos da abordagem)"approaches" deve ser um array de objetos"approaches[].uuid" é obrigatória"approaches[].uuid" deve ser uma string UUID versão 4 única⁶"approaches[].uuid" de cada conceito nunca pode mudar"approaches[].slug" é obrigatória"approaches[].slug" deve ser uma string em kebab-case² com comprimento <= 255"approaches[].slug" deve ter um arquivo <slug>/content.md não vazio correspondente"approaches[].slug" deve ter um arquivo <slug>/snippet.txt não vazio correspondente"approaches[].title" é obrigatória"approaches[].title" deve ser uma string em Title Case³ com comprimento <= 255"approaches[].blurb" é obrigatória"approaches[].blurb" deve ser uma string não vazia¹ com comprimento <= 350"approaches[].authors" é obrigatória"approaches[].authors" deve ser um array não vazio"approaches[].authors" devem ser strings não vazias¹"approaches[].authors" não podem ter duplicatas"approaches[].authors" são tratados sem diferenciar maiúsculas de minúsculas"approaches[].contributors" é opcional"approaches[].contributors" deve ser um array"approaches[].contributors" devem ser strings não vazias¹"approaches[].contributors" não podem ter duplicatas"approaches[].contributors" são tratados sem diferenciar maiúsculas de minúsculas"approaches[].authors" ou "approaches[].contributors" (sem sobreposição)"approaches[].tags" é opcional"approaches[].tags.all" é opcional, a menos que "approaches[].tags.any" esteja vazia"approaches[].tags.all" deve ser um array"approaches[].tags.all" devem ser strings de tag⁷ não vazias com comprimento <= 255"approaches[].tags.all" não podem ter duplicatas"approaches[].tags.any" é opcional, a menos que "approaches[].tags.all" esteja vazia"approaches[].tags.any" deve ser um array"approaches[].tags.any" devem ser strings de tag⁷ não vazias com comprimento <= 255"approaches[].tags.any" não podem ter duplicatas"approaches[].tags.not" é opcional"approaches[].tags.not" deve ser um array"approaches[].tags.not" devem ser strings de tag⁷ não vazias com comprimento <= 255"approaches[].tags.not" não podem ter duplicatas"approaches[].slug" correspondente no arquivo .approaches/config.json
"approaches[].slug" correspondente no arquivo .approaches/config.json
approaches.snippet_extension no arquivo config.json da track"articles" é opcional, a menos que exista um diretório irmão presente (que contém os arquivos do artigo)"articles" deve ser um array de objetos"articles[].uuid" é obrigatória"articles[].uuid" deve ser uma string UUID versão 4 única⁶"articles[].uuid" de cada conceito nunca pode mudar"articles[].slug" é obrigatória"articles[].slug" deve ser uma string em kebab-case² com comprimento <= 255"articles[].slug" deve ter um arquivo <slug>/content.md não vazio correspondente"articles[].slug" deve ter um arquivo <slug>/snippet.md não vazio correspondente"articles[].title" é obrigatória"articles[].title" deve ser uma string em Title Case³ com comprimento <= 255"articles[].blurb" é obrigatória"articles[].blurb" deve ser uma string não vazia¹ com comprimento <= 350"articles[].authors" é obrigatória"articles[].authors" deve ser um array não vazio"articles[].authors" devem ser strings não vazias¹"articles[].authors" não podem ter duplicatas"articles[].authors" são tratados sem diferenciar maiúsculas de minúsculas"articles[].contributors" é opcional"articles[].contributors" deve ser um array"articles[].contributors" devem ser strings não vazias¹"articles[].contributors" não podem ter duplicatas"articles[].contributors" são tratados sem diferenciar maiúsculas de minúsculas"articles[].authors" ou "articles[].contributors" (sem sobreposição)"articles[].slug" correspondente no arquivo .articles/config.json
"articles[].slug" correspondente no arquivo .articles/config.json
"[].url" é obrigatória"[].url" deve ser uma URL"[].description" é obrigatória"[].description" deve ser uma string não vazia¹"[].icon_url" é opcional"[].icon_url" deve ser uma URL"blurb" é obrigatória"blurb" deve ser uma string não vazia¹ com comprimento <= 350"authors" é obrigatória"authors" deve ser um array"authors" devem ser strings não vazias¹"authors" não podem ter duplicatas"authors" são tratados sem diferenciar maiúsculas de minúsculas"contributors" é opcional"contributors" deve ser um array"contributors" devem ser strings não vazias¹"contributors" não podem ter duplicatas"contributors" são tratados sem diferenciar maiúsculas de minúsculas"authors" ou "contributors" (sem sobreposição)String não vazia: uma string que contém pelo menos um caractere que não seja espaço em branco.
String em kebab-case: uma string que contém apenas caracteres no intervalo [a-z0-9], opcionalmente separados por hífens (por exemplo, "two-fer"). Ela deve corresponder à expressão regular: ^[a-z0-9]+(-[a-z0-9]+)*$
String em Title Case: uma string não vazia que segue as diretrizes do Chicago Manual of Style abaixo:
String em Sentence Case: uma string não vazia que segue as diretrizes abaixo:
Padrão files válido: uma string não vazia¹ que especifica a localização de um arquivo usado em um exercício, relativa ao diretório do exercício. Um padrão pode usar um dos seguintes placeholders:
%{kebab_slug}: o slug do exercício em kebab-case (por exemplo, bit-manipulation)%{snake_slug}: o slug do exercício em snake_case (por exemplo, bit_manipulation)%{camel_slug}: o slug do exercício em camelCase (por exemplo, bitManipulation)%{pascal_slug}: o slug do exercício em PascalCase (por exemplo, BitManipulation)String UUID versão 4 única: uma string que satisfaz todas estas condições:
config.json de nível de track de uma determinada track do Exercismconfig.json de nível de track de nenhuma outra track do Exercismcanonical-data.json em 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}$
Por exemplo, o UUID abaixo tem a forma correta:
d334ffe3-657e-4725-a950-290b284b6d9f
Você pode rodar configlet uuid para gerar um UUID adequado.
tag de analisador válida: uma string não vazia¹ formatada como <category>:<thing>.
O valor de <category> deve ser um dos seguintes:
paradigm (por exemplo, paradigm:functional)technique (por exemplo, technique:recursion)construct (por exemplo, construct:bitwise-and)uses (por exemplo, uses:DateTime.add_seconds)O valor de <thing> deve ser uma string não vazia¹.