A principal utilização do configlet é o linting: verificar se os ficheiros de configuração de um percurso estão bem estruturados, tanto a nível sintático como semântico. Os percursos mal configurados podem não sincronizar corretamente, podem parecer errados no site ou podem proporcionar uma experiência de utilizador abaixo do ideal, por isso as verificações do configlet desempenham um papel importante na manutenção da integridade do Exercism.
O comando lint pode ser usado para fazer o linting de um percurso.
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 linting que são verificadas.
O linter deve verificar se todos os ficheiros obrigatórios estão presentes. Os ficheiros que não são específicos de um exercício e que têm de 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 ficheiros específicos dos exercícios de conceito que têm de 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 ficheiros:
concepts/<slug>/about.mdconcepts/<slug>/introduction.mdconcepts/<slug>/links.jsonO ficheiro config.json deve passar as seguintes verificações:
"language" é obrigatória"language" tem de ser uma string não vazia¹ com comprimento <= 255"slug" é obrigatória"slug" tem de ser uma string em kebab-case² com comprimento <= 255"active" é obrigatória"active" tem de ser um boolean"blurb" é obrigatória"blurb" tem de ser uma string não vazia¹ com comprimento <= 400"version" é obrigatória"version" tem de ser o inteiro 3
"status.concept_exercises" é obrigatória"status.concept_exercises" tem de ser um boolean"status.test_runner" é obrigatória"status.test_runner" tem de ser um boolean"status.representer" é obrigatória"status.representer" tem de ser um boolean"status.analyzer" é obrigatória"status.analyzer" tem de ser um boolean"online_editor.indent_style" é obrigatória"online_editor.indent_style" tem de ser a string space ou tab
"online_editor.indent_size" é obrigatória"online_editor.indent_size" tem de ser um inteiro >= 0 e <= 8"online_editor.highlightjs_language" é opcional"online_editor.highlightjs_language" tem de ser uma string não vazia¹"files" é opcional"files" tem de ser um objeto"files.solution" é opcional"files.solution" tem de ser um array"files.solution" têm de ser padrões válidos⁵"files.solution" não podem ter duplicados"files.test" é opcional"files.test" tem de ser um array"files.test" têm de ser padrões válidos⁵"files.test" não podem ter duplicados"files.example" é opcional"files.example" tem de ser um array"files.example" têm de ser padrões válidos⁵"files.example" não podem ter duplicados"files.exemplar" é opcional"files.exemplar" tem de ser um array"files.exemplar" têm de ser padrões válidos⁵"files.exemplar" não podem ter duplicados"files.editor" é opcional"files.editor" tem de ser um array"files.editor" têm de ser padrões válidos⁵"files.editor" não podem ter duplicados"files.invalidator" é opcional"files.invalidator" tem de ser um array"files.invalidator" têm de ser padrões válidos⁵"files.invalidator" não podem ter duplicados"files.solution", "files.test", "files.example", "files.exemplar", "files.editor" ou "files.invalidator" (sem sobreposição)
d ou plsql, os ficheiros de "files.solution" e "files.test" podem sobrepor-se"files.example e "files.exemplar" podem sobrepor-se"test_runner.average_run_time" é obrigatória se "status.test_runner" for igual a true
"test_runner.average_run_time" tem de ser um inteiro > 0"approaches.snippet_extension" é obrigatória se o percurso tiver uma ou mais abordagens"approaches.snippet_extension" tem de ser uma string não vazia¹"exercises" é obrigatória"exercises.concept" é obrigatória"exercises.concept" tem de ser um array"exercises.concept[].slug" é obrigatória"exercises.concept[].slug" tem de ser uma string em kebab-case² com comprimento <= 255"exercises.concept[].slug" tem de ser único em "exercises.concept[].slug" e não pode existir em "exercises.practice[].slug"
"exercises.concept[].name" é obrigatória"exercises.concept[].name" tem de ser uma string em Title Case³ com comprimento <= 255"exercises.concept[].uuid" é obrigatória"exercises.concept[].uuid" tem de ser uma string UUID de versão 4 única⁶"exercises.concept[].uuid" de cada exercício nunca pode mudar"exercises.concept[].concepts" é obrigatória"exercises.concept[].concepts" tem de ser um array não vazio de strings se "exercises.concept[].status" não for igual a deprecated
"exercises.concept[].concepts" tem de ser um array vazio se "exercises.concept[].status" for igual a deprecated
"exercises.concept[].concepts" têm de ser strings em kebab-case²"exercises.concept[].concepts" não podem ter duplicados"exercises.concept[].concepts" não podem constar na propriedade "concepts" de qualquer outro exercício de conceito"exercises.concept[].concepts" têm de corresponder à propriedade "concepts.slug" de um dos conceitos"exercises.concept[].prerequisites" é obrigatória"exercises.concept[].prerequisites" tem de ser um array não vazio de strings se "exercises.concept[].status" não for igual a deprecated, exceto exatamente um exercício, que pode ter um array vazio como valor"exercises.concept[].prerequisites" tem de ser um array vazio se "exercises.concept[].status" for igual a deprecated
"exercises.concept[].prerequisites" têm de ser strings em kebab-case²"exercises.concept[].prerequisites" não podem ter duplicados"exercises.concept[].prerequisites" têm de 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" têm de corresponder à propriedade "concepts.slug" de um dos conceitos"exercises.concept[].concepts" e "exercises.concept[].prerequisites"
"exercises.concept[].status" é opcional"exercises.concept[].status" tem de ser a string wip, beta, active ou deprecated
"exercises.practice" é obrigatória"exercises.practice" tem de ser um array"exercises.practice[].slug" é obrigatória"exercises.practice[].slug" tem de ser uma string em kebab-case² com comprimento <= 255"exercises.practice[].slug" tem de 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" tem de ser uma string em Title Case³ com comprimento <= 255"exercises.practice[].uuid" é obrigatória"exercises.practice[].uuid" tem de ser uma string UUID de versão 4 única⁶"exercises.practice[].uuid" de cada exercício nunca pode mudar"exercises.practice[].difficulty" é obrigatória"exercises.practice[].difficulty" tem de ser um inteiro >= 1 e <= 10"exercises.practice[].practices" é obrigatória"exercises.practice[].practices" tem de ser um array não vazio de strings se "exercises.practice[].status" não for igual a deprecated
"exercises.practice[].practices" tem de ser um array vazio se "exercises.practice[].status" for igual a deprecated
"exercises.practice[].practices" têm de ser strings em kebab-case²"exercises.practice[].practices" não podem ter duplicados"exercises.practice[].practices" têm de corresponder à propriedade "concepts[].slug" de um dos conceitos"exercises.practice[].practices" podem referir o slug de um mesmo conceito no máximo 10 vezes (em todos os exercícios)"exercises.practice[].prerequisites" é obrigatória"exercises.practice[].prerequisites" tem de ser um array não vazio de strings se "exercises.practice[].status" não for igual a deprecated
"exercises.practice[].prerequisites" tem de ser um array vazio se "exercises.practice[].status" for igual a deprecated
"exercises.practice[].prerequisites" tem de ser um array vazio se "exercises.practice[].slug" for igual a hello-world
"exercises.practice[].prerequisites" têm de ser strings em kebab-case²"exercises.practice[].prerequisites" não podem ter duplicados"exercises.practice[].prerequisites" têm de corresponder aos valores de "exercises.concept[].concepts" de qualquer exercício de conceito"exercises.practice[].prerequisites" têm de corresponder à propriedade "concepts[].slug" de um dos conceitos"exercises.practice[].status" é opcional"exercises.practice[].status" tem de ser a string wip, beta, active ou deprecated
"exercises.practice[].status" tem de, se "exercises.practice[].slug" for igual a hello-world, ser omitido ou ser a string active
"exercises.foregone" é opcional"exercises.foregone" tem de ser um array"exercises.foregone" têm de ser strings em kebab-case²"exercises.foregone" não podem ter duplicados"exercises.foregone" não podem corresponder a nenhum dos slugs dos exercícios de conceito ou de prática"concepts" é obrigatória"concepts" tem de ser um array"concepts[].uuid" é obrigatória"concepts[].uuid" tem de ser uma string UUID de versão 4 única⁶"concepts[].uuid" de cada conceito nunca pode mudar"concepts[].slug" é obrigatória"concepts[].slug" tem de ser uma string em kebab-case² com comprimento <= 255"concepts[].name" é obrigatória"concepts[].name" tem de ser uma string em Title Case³ com comprimento <= 255"concepts[].tags" é opcional"concepts[].tags.all" é opcional, a menos que "concepts[].tags.any" esteja vazio"concepts[].tags.all" tem de ser um array"concepts[].tags.all" têm de ser strings de tag⁷ não vazias com comprimento <= 255"concepts[].tags.all" não podem ter duplicados"concepts[].tags.any" é opcional, a menos que "concepts[].tags.all" esteja vazio"concepts[].tags.any" tem de ser um array"concepts[].tags.any" têm de ser strings de tag⁷ não vazias com comprimento <= 255"concepts[].tags.any" não podem ter duplicados"concepts[].tags.not" é opcional"concepts[].tags.not" tem de ser um array"concepts[].tags.not" têm de ser strings de tag⁷ não vazias com comprimento <= 255"concepts[].tags.not" não podem ter duplicados"concepts" tem de ter um ficheiro concept/<concepts.slug>/about.md. As regras de linting para este ficheiro são especificadas abaixo."concepts" tem de ter um ficheiro concept/<concepts.slug>/introduction.md. As regras de linting para este ficheiro são especificadas abaixo."concepts" tem de ter um ficheiro concept/<concepts.slug>/links.json. As regras de linting para este ficheiro são especificadas abaixo."key_features" é opcional"key_features" tem de ser um array com comprimento = 6"key_features[].icon" é obrigatória"key_features[].icon" tem de usar um dos valores de ícone predefinidos
"key_features[].title" é obrigatória"key_features[].title" tem de ser uma string em Sentence Case⁴ com comprimento <= 25"key_features[].content" é obrigatória"key_features[].content" tem de ser uma string não vazia¹ com comprimento <= 100"tags" é obrigatória"tags" tem de ser um array de strings"tags" não podem ter duplicados"tags" têm de usar um dos valores de tag predefinidos
"blurb" é obrigatória"blurb" tem de ser uma string não vazia¹ com comprimento <= 350"source" é opcional"source" tem de ser uma string não vazia¹"source_url" é opcional"source_url" tem de ser um URL"authors" é obrigatória"authors" tem de ser um array não vazio"authors" têm de ser strings não vazias¹"authors" não podem ter duplicados"authors" não distinguem maiúsculas de minúsculas"contributors" é opcional"contributors" tem de ser um array"contributors" têm de ser strings não vazias¹"contributors" não podem ter duplicados"contributors" não distinguem maiúsculas de minúsculas"authors" ou "contributors" (sem sobreposição)"files.solution" é obrigatória"files.solution" tem de ser um array não vazio"files.solution" não podem ter duplicados"files.test" é obrigatória"files.test" tem de ser um array não vazio"files.test" não podem ter duplicados"files.exemplar" é obrigatória"files.exemplar" tem de ser um array não vazio"files.exemplar" não podem ter duplicados"files.editor" é opcional"files.editor" tem de ser um array"files.editor" não podem ter duplicados"files.invalidator" é opcional"files.invalidator" tem de ser um array"files.invalidator" não podem ter duplicados"files.solution" têm de existir"files.test" têm de existir"files.exemplar" têm de existir"files.editor" têm de existir"files.invalidator" têm de existir"files.solution", "files.test", "files.exemplar" ou "files.invalidator" (sem sobreposição)
d ou plsql, os ficheiros de "files.solution" e "files.test" podem sobrepor-se"forked_from" é opcional"forked_from" tem de ser um array"forked_from" têm de ser strings com o formato <track-slug>/<exercise-slug> (por exemplo, fsharp/bird-watcher)"forked_from" têm de se referir a exercícios realmente implementados"forked_from" não podem ter duplicados"language_versions" é opcional"language_versions" tem de ser uma string"representer.version" é opcional"representer.version" tem de ser um inteiro >= 1"icon" é opcional"icon" tem de ser uma string em kebab-case²## General ou ## X. <task>, em que X corresponde ao número da tarefa no cabeçalho do instructions.md
## 1. Do X
"concepts.slug" de um dos conceitos no config.json do percurso."blurb" é obrigatória"blurb" tem de ser uma string não vazia¹ com comprimento <= 350"source" é opcional"source" tem de ser uma string não vazia¹"source_url" é opcional"source_url" tem de ser um URL"authors" é opcional"authors" tem de ser um array"authors" têm de ser strings não vazias¹"authors" não podem ter duplicados"authors" não distinguem maiúsculas de minúsculas"contributors" é opcional"contributors" tem de ser um array"contributors" têm de ser strings não vazias¹"contributors" não podem ter duplicados"contributors" não distinguem maiúsculas de minúsculas"authors" ou "contributors" (sem sobreposição)"files.solution" é obrigatória"files.solution" tem de ser um array não vazio"files.solution" não podem ter duplicados"files.test" é obrigatória"files.test" tem de ser um array não vazio"files.test" não podem ter duplicados"files.example" é obrigatória"files.example" tem de ser um array não vazio"files.example" não podem ter duplicados"files.editor" é opcional"files.editor" tem de ser um array"files.editor" não podem ter duplicados"files.invalidator" é opcional"files.invalidator" tem de ser um array"files.invalidator" não podem ter duplicados"files.solution" têm de existir"files.test" têm de existir"files.example" têm de existir"files.editor" têm de existir"files.invalidator" têm de existir"files.solution", "files.test", "files.example ou "files.invalidator" (sem sobreposição)
d ou plsql, os ficheiros de "files.solution" e "files.test" podem sobrepor-se"language_versions" é opcional"language_versions" tem de ser uma string"test_runner" é opcional"test_runner" tem de ser um boolean"representer.version" é opcional"representer.version" tem de ser um inteiro >= 1"icon" é opcional"icon" tem de ser uma string em kebab-case²introduction.md ou um diretório irmão"introduction.authors" é opcional"introduction.authors" tem de ser um array"introduction.authors" têm de ser strings não vazias¹"introduction.authors" não podem ter duplicados"introduction.authors" não distinguem maiúsculas de minúsculas"introduction.authors" não estiver vazio, tem de existir um ficheiro introduction.md não vazio"introduction.contributors" é opcional"introduction.contributors" tem de ser um array"introduction.contributors" têm de ser strings não vazias¹"introduction.contributors" não podem ter duplicados"introduction.contributors" não distinguem maiúsculas de minúsculas"introduction.contributors" não estiver vazio, tem de existir um ficheiro introduction.md não vazio"introduction.authors" ou "introduction.contributors" (sem sobreposição)"approaches" é opcional, a menos que exista um diretório irmão (que contém os ficheiros da abordagem)"approaches" tem de ser um array de objetos"approaches[].uuid" é obrigatória"approaches[].uuid" tem de ser uma string UUID de versão 4 única⁶"approaches[].uuid" de cada conceito nunca pode mudar"approaches[].slug" é obrigatória"approaches[].slug" tem de ser uma string em kebab-case² com comprimento <= 255"approaches[].slug" tem de ter um ficheiro <slug>/content.md não vazio correspondente"approaches[].slug" tem de ter um ficheiro <slug>/snippet.txt não vazio correspondente"approaches[].title" é obrigatória"approaches[].title" tem de ser uma string em Title Case³ com comprimento <= 255"approaches[].blurb" é obrigatória"approaches[].blurb" tem de ser uma string não vazia¹ com comprimento <= 350"approaches[].authors" é obrigatória"approaches[].authors" tem de ser um array não vazio"approaches[].authors" têm de ser strings não vazias¹"approaches[].authors" não podem ter duplicados"approaches[].authors" não distinguem maiúsculas de minúsculas"approaches[].contributors" é opcional"approaches[].contributors" tem de ser um array"approaches[].contributors" têm de ser strings não vazias¹"approaches[].contributors" não podem ter duplicados"approaches[].contributors" não distinguem 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 vazio"approaches[].tags.all" tem de ser um array"approaches[].tags.all" têm de ser strings de tag⁷ não vazias com comprimento <= 255"approaches[].tags.all" não podem ter duplicados"approaches[].tags.any" é opcional, a menos que "approaches[].tags.all" esteja vazio"approaches[].tags.any" tem de ser um array"approaches[].tags.any" têm de ser strings de tag⁷ não vazias com comprimento <= 255"approaches[].tags.any" não podem ter duplicados"approaches[].tags.not" é opcional"approaches[].tags.not" tem de ser um array"approaches[].tags.not" têm de ser strings de tag⁷ não vazias com comprimento <= 255"approaches[].tags.not" não podem ter duplicados"approaches[].slug" correspondente no ficheiro .approaches/config.json
"approaches[].slug" correspondente no ficheiro .approaches/config.json
approaches.snippet_extension no ficheiro config.json do percurso"articles" é opcional, a menos que exista um diretório irmão (que contém os ficheiros do artigo)"articles" tem de ser um array de objetos"articles[].uuid" é obrigatória"articles[].uuid" tem de ser uma string UUID de versão 4 única⁶"articles[].uuid" de cada conceito nunca pode mudar"articles[].slug" é obrigatória"articles[].slug" tem de ser uma string em kebab-case² com comprimento <= 255"articles[].slug" tem de ter um ficheiro <slug>/content.md não vazio correspondente"articles[].slug" tem de ter um ficheiro <slug>/snippet.md não vazio correspondente"articles[].title" é obrigatória"articles[].title" tem de ser uma string em Title Case³ com comprimento <= 255"articles[].blurb" é obrigatória"articles[].blurb" tem de ser uma string não vazia¹ com comprimento <= 350"articles[].authors" é obrigatória"articles[].authors" tem de ser um array não vazio"articles[].authors" têm de ser strings não vazias¹"articles[].authors" não podem ter duplicados"articles[].authors" não distinguem maiúsculas de minúsculas"articles[].contributors" é opcional"articles[].contributors" tem de ser um array"articles[].contributors" têm de ser strings não vazias¹"articles[].contributors" não podem ter duplicados"articles[].contributors" não distinguem maiúsculas de minúsculas"articles[].authors" ou "articles[].contributors" (sem sobreposição)"articles[].slug" correspondente no ficheiro .articles/config.json
"articles[].slug" correspondente no ficheiro .articles/config.json
"[].url" é obrigatória"[].url" tem de ser um URL"[].description" é obrigatória"[].description" tem de ser uma string não vazia¹"[].icon_url" é opcional"[].icon_url" tem de ser um URL"blurb" é obrigatória"blurb" tem de ser uma string não vazia¹ com comprimento <= 350"authors" é obrigatória"authors" tem de ser um array"authors" têm de ser strings não vazias¹"authors" não podem ter duplicados"authors" não distinguem maiúsculas de minúsculas"contributors" é opcional"contributors" tem de ser um array"contributors" têm de ser strings não vazias¹"contributors" não podem ter duplicados"contributors" não distinguem maiúsculas de minúsculas"authors" ou "contributors" (sem sobreposição)String não vazia: uma string que contém pelo menos um caráter que não seja um espaço em branco.
String em kebab-case: uma string que contém apenas carateres no intervalo [a-z0-9], opcionalmente separados por hífenes (por exemplo, "two-fer"). Tem de corresponder à expressão regular: ^[a-z0-9]+(-[a-z0-9]+)*$
String em Title Case: uma string não vazia que segue as orientações do Chicago Manual of Style abaixo:
String em Sentence Case: uma string não vazia que segue as orientações abaixo:
Padrão de files válido: uma string não vazia¹ que especifica a localização de um ficheiro usado num 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 de versão 4 única: uma string que satisfaz todas estas condições:
config.json ao nível do percurso de um determinado percurso do Exercismconfig.json ao nível do percurso de qualquer outro percurso 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
Podes executar configlet uuid para gerar um UUID adequado.
tag de analisador válida: uma string não vazia¹ com o formato <category>:<thing>.
O valor de <category> tem de 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> tem de ser uma string não vazia¹.