configlet lint


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.

Utilização

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]

Regras

Estas são as regras de linting que são verificadas.

Regra: os ficheiros obrigatórios estão presentes

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.json
  • docs/ABOUT.md
  • docs/INSTALLATION.md
  • docs/LEARNING.md
  • docs/RESOURCES.md
  • docs/SNIPPET.txt
  • docs/TESTS.md
  • exercises/shared/.docs/help.md
  • exercises/shared/.docs/tests.md

Os ficheiros específicos dos exercícios de conceito que têm de estar presentes são:

  • exercises/concept/<slug>/.docs/hints.md
  • exercises/concept/<slug>/.docs/instructions.md
  • exercises/concept/<slug>/.docs/introduction.md
  • exercises/concept/<slug>/.meta/config.json

Haverá 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.md
  • concepts/<slug>/introduction.md
  • concepts/<slug>/links.json

Regra: o ficheiro config.json é válido

O ficheiro config.json deve passar as seguintes verificações:

  • O ficheiro tem de ser um JSON válido
  • A chave "language" é obrigatória
  • O valor de "language" tem de ser uma string não vazia¹ com comprimento <= 255
  • A chave "slug" é obrigatória
  • O valor de "slug" tem de ser uma string em kebab-case² com comprimento <= 255
  • A chave "active" é obrigatória
  • O valor de "active" tem de ser um boolean
  • A chave "blurb" é obrigatória
  • O valor de "blurb" tem de ser uma string não vazia¹ com comprimento <= 400
  • A chave "version" é obrigatória
  • O valor de "version" tem de ser o inteiro 3
  • A chave "status.concept_exercises" é obrigatória
  • O valor de "status.concept_exercises" tem de ser um boolean
  • A chave "status.test_runner" é obrigatória
  • O valor de "status.test_runner" tem de ser um boolean
  • A chave "status.representer" é obrigatória
  • O valor de "status.representer" tem de ser um boolean
  • A chave "status.analyzer" é obrigatória
  • O valor de "status.analyzer" tem de ser um boolean
  • A chave "online_editor.indent_style" é obrigatória
  • O valor de "online_editor.indent_style" tem de ser a string space ou tab
  • A chave "online_editor.indent_size" é obrigatória
  • O valor de "online_editor.indent_size" tem de ser um inteiro >= 0 e <= 8
  • A chave "online_editor.highlightjs_language" é opcional
  • O valor de "online_editor.highlightjs_language" tem de ser uma string não vazia¹
  • A chave "files" é opcional
  • O valor de "files" tem de ser um objeto
  • A chave "files.solution" é opcional
  • O valor de "files.solution" tem de ser um array
  • Os valores de "files.solution" têm de ser padrões válidos⁵
  • Os valores de "files.solution" não podem ter duplicados
  • A chave "files.test" é opcional
  • O valor de "files.test" tem de ser um array
  • Os valores de "files.test" têm de ser padrões válidos⁵
  • Os valores de "files.test" não podem ter duplicados
  • A chave "files.example" é opcional
  • O valor de "files.example" tem de ser um array
  • Os valores de "files.example" têm de ser padrões válidos⁵
  • Os valores de "files.example" não podem ter duplicados
  • A chave "files.exemplar" é opcional
  • O valor de "files.exemplar" tem de ser um array
  • Os valores de "files.exemplar" têm de ser padrões válidos⁵
  • Os valores de "files.exemplar" não podem ter duplicados
  • A chave "files.editor" é opcional
  • O valor de "files.editor" tem de ser um array
  • Os valores de "files.editor" têm de ser padrões válidos⁵
  • Os valores de "files.editor" não podem ter duplicados
  • A chave "files.invalidator" é opcional
  • O valor de "files.invalidator" tem de ser um array
  • Os valores de "files.invalidator" têm de ser padrões válidos⁵
  • Os valores de "files.invalidator" não podem ter duplicados
  • Os padrões só podem constar num dos arrays "files.solution", "files.test", "files.example", "files.exemplar", "files.editor" ou "files.invalidator" (sem sobreposição)
    • Se o percurso for d ou plsql, os ficheiros de "files.solution" e "files.test" podem sobrepor-se
    • Os ficheiros de "files.example e "files.exemplar" podem sobrepor-se
  • A chave "test_runner.average_run_time" é obrigatória se "status.test_runner" for igual a true
  • O valor de "test_runner.average_run_time" tem de ser um inteiro > 0
  • A chave "approaches.snippet_extension" é obrigatória se o percurso tiver uma ou mais abordagens
  • O valor de "approaches.snippet_extension" tem de ser uma string não vazia¹
  • A chave "exercises" é obrigatória
  • A chave "exercises.concept" é obrigatória
  • O valor de "exercises.concept" tem de ser um array
  • A chave "exercises.concept[].slug" é obrigatória
  • O valor de "exercises.concept[].slug" tem de ser uma string em kebab-case² com comprimento <= 255
  • O valor de "exercises.concept[].slug" tem de ser único em "exercises.concept[].slug" e não pode existir em "exercises.practice[].slug"
  • A chave "exercises.concept[].name" é obrigatória
  • O valor de "exercises.concept[].name" tem de ser uma string em Title Case³ com comprimento <= 255
  • A chave "exercises.concept[].uuid" é obrigatória
  • O valor de "exercises.concept[].uuid" tem de ser uma string UUID de versão 4 única⁶
  • O valor de "exercises.concept[].uuid" de cada exercício nunca pode mudar
  • A chave "exercises.concept[].concepts" é obrigatória
  • O valor de "exercises.concept[].concepts" tem de ser um array não vazio de strings se "exercises.concept[].status" não for igual a deprecated
  • O valor de "exercises.concept[].concepts" tem de ser um array vazio se "exercises.concept[].status" for igual a deprecated
  • Os valores de "exercises.concept[].concepts" têm de ser strings em kebab-case²
  • Os valores de "exercises.concept[].concepts" não podem ter duplicados
  • Os valores de "exercises.concept[].concepts" não podem constar na propriedade "concepts" de qualquer outro exercício de conceito
  • Os valores de "exercises.concept[].concepts" têm de corresponder à propriedade "concepts.slug" de um dos conceitos
  • A chave "exercises.concept[].prerequisites" é obrigatória
  • O valor de "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
  • O valor de "exercises.concept[].prerequisites" tem de ser um array vazio se "exercises.concept[].status" for igual a deprecated
  • Os valores de "exercises.concept[].prerequisites" têm de ser strings em kebab-case²
  • Os valores de "exercises.concept[].prerequisites" não podem ter duplicados
  • Os valores de "exercises.concept[].prerequisites" têm de corresponder aos valores da propriedade "concepts" de qualquer outro exercício de conceito
  • Os valores de "exercises.concept[].prerequisites" não podem corresponder a nenhum dos valores da propriedade "exercises.concept[].concepts" do exercício
  • Os valores de "exercises.concept[].prerequisites" têm de corresponder à propriedade "concepts.slug" de um dos conceitos
  • Não pode haver ciclos entre "exercises.concept[].concepts" e "exercises.concept[].prerequisites"
  • A chave "exercises.concept[].status" é opcional
  • O valor de "exercises.concept[].status" tem de ser a string wip, beta, active ou deprecated
  • A chave "exercises.practice" é obrigatória
  • O valor de "exercises.practice" tem de ser um array
  • A chave "exercises.practice[].slug" é obrigatória
  • O valor de "exercises.practice[].slug" tem de ser uma string em kebab-case² com comprimento <= 255
  • O valor de "exercises.practice[].slug" tem de ser único em "exercises.practice[].slug" e não pode existir em "exercises.concept[].slug"
  • Tem de haver exatamente um valor de "exercises.practice[].slug" que seja a string hello-world
  • A chave "exercises.practice[].name" é obrigatória
  • O valor de "exercises.practice[].name" tem de ser uma string em Title Case³ com comprimento <= 255
  • A chave "exercises.practice[].uuid" é obrigatória
  • O valor de "exercises.practice[].uuid" tem de ser uma string UUID de versão 4 única⁶
  • O valor de "exercises.practice[].uuid" de cada exercício nunca pode mudar
  • A chave "exercises.practice[].difficulty" é obrigatória
  • O valor de "exercises.practice[].difficulty" tem de ser um inteiro >= 1 e <= 10
  • A chave "exercises.practice[].practices" é obrigatória
  • O valor de "exercises.practice[].practices" tem de ser um array não vazio de strings se "exercises.practice[].status" não for igual a deprecated
  • O valor de "exercises.practice[].practices" tem de ser um array vazio se "exercises.practice[].status" for igual a deprecated
  • Os valores de "exercises.practice[].practices" têm de ser strings em kebab-case²
  • Os valores de "exercises.practice[].practices" não podem ter duplicados
  • Os valores de "exercises.practice[].practices" têm de corresponder à propriedade "concepts[].slug" de um dos conceitos
  • Os valores de "exercises.practice[].practices" podem referir o slug de um mesmo conceito no máximo 10 vezes (em todos os exercícios)
  • A chave "exercises.practice[].prerequisites" é obrigatória
  • O valor de "exercises.practice[].prerequisites" tem de ser um array não vazio de strings se "exercises.practice[].status" não for igual a deprecated
  • O valor de "exercises.practice[].prerequisites" tem de ser um array vazio se "exercises.practice[].status" for igual a deprecated
  • O valor de "exercises.practice[].prerequisites" tem de ser um array vazio se "exercises.practice[].slug" for igual a hello-world
  • Os valores de "exercises.practice[].prerequisites" têm de ser strings em kebab-case²
  • Os valores de "exercises.practice[].prerequisites" não podem ter duplicados
  • Os valores de "exercises.practice[].prerequisites" têm de corresponder aos valores de "exercises.concept[].concepts" de qualquer exercício de conceito
  • Os valores de "exercises.practice[].prerequisites" têm de corresponder à propriedade "concepts[].slug" de um dos conceitos
  • A chave "exercises.practice[].status" é opcional
  • O valor de "exercises.practice[].status" tem de ser a string wip, beta, active ou deprecated
  • O valor de "exercises.practice[].status" tem de, se "exercises.practice[].slug" for igual a hello-world, ser omitido ou ser a string active
  • A chave "exercises.foregone" é opcional
  • O valor de "exercises.foregone" tem de ser um array
  • Os valores de "exercises.foregone" têm de ser strings em kebab-case²
  • Os valores de "exercises.foregone" não podem ter duplicados
  • Os valores de "exercises.foregone" não podem corresponder a nenhum dos slugs dos exercícios de conceito ou de prática
  • A chave "concepts" é obrigatória
  • O valor de "concepts" tem de ser um array
  • A chave "concepts[].uuid" é obrigatória
  • O valor de "concepts[].uuid" tem de ser uma string UUID de versão 4 única⁶
  • O valor de "concepts[].uuid" de cada conceito nunca pode mudar
  • A chave "concepts[].slug" é obrigatória
  • O valor de "concepts[].slug" tem de ser uma string em kebab-case² com comprimento <= 255
  • A chave "concepts[].name" é obrigatória
  • O valor de "concepts[].name" tem de ser uma string em Title Case³ com comprimento <= 255
  • A chave "concepts[].tags" é opcional
  • A chave "concepts[].tags.all" é opcional, a menos que "concepts[].tags.any" esteja vazio
  • O valor de "concepts[].tags.all" tem de ser um array
  • Os valores de "concepts[].tags.all" têm de ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "concepts[].tags.all" não podem ter duplicados
  • A chave "concepts[].tags.any" é opcional, a menos que "concepts[].tags.all" esteja vazio
  • O valor de "concepts[].tags.any" tem de ser um array
  • Os valores de "concepts[].tags.any" têm de ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "concepts[].tags.any" não podem ter duplicados
  • A chave "concepts[].tags.not" é opcional
  • O valor de "concepts[].tags.not" tem de ser um array
  • Os valores de "concepts[].tags.not" têm de ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "concepts[].tags.not" não podem ter duplicados
  • Cada valor de "concepts" tem de ter um ficheiro concept/<concepts.slug>/about.md. As regras de linting para este ficheiro são especificadas abaixo.
  • Cada valor de "concepts" tem de ter um ficheiro concept/<concepts.slug>/introduction.md. As regras de linting para este ficheiro são especificadas abaixo.
  • Cada valor de "concepts" tem de ter um ficheiro concept/<concepts.slug>/links.json. As regras de linting para este ficheiro são especificadas abaixo.
  • A chave "key_features" é opcional
  • O valor de "key_features" tem de ser um array com comprimento = 6
  • A chave "key_features[].icon" é obrigatória
  • O valor de "key_features[].icon" tem de usar um dos valores de ícone predefinidos
  • A chave "key_features[].title" é obrigatória
  • O valor de "key_features[].title" tem de ser uma string em Sentence Case⁴ com comprimento <= 25
  • A chave "key_features[].content" é obrigatória
  • O valor de "key_features[].content" tem de ser uma string não vazia¹ com comprimento <= 100
  • A chave "tags" é obrigatória
  • O valor de "tags" tem de ser um array de strings
  • Os valores de "tags" não podem ter duplicados
  • Os valores de "tags" têm de usar um dos valores de tag predefinidos

Regra: exercises/concept/<slug>/.meta/config.json é válido

  • O ficheiro tem de ser um JSON válido
  • A raiz do JSON tem de ser um objeto
  • A chave "blurb" é obrigatória
  • O valor de "blurb" tem de ser uma string não vazia¹ com comprimento <= 350
  • A chave "source" é opcional
  • O valor de "source" tem de ser uma string não vazia¹
  • A chave "source_url" é opcional
  • O valor de "source_url" tem de ser um URL
  • A chave "authors" é obrigatória
  • O valor de "authors" tem de ser um array não vazio
  • Os valores de "authors" têm de ser strings não vazias¹
  • Os valores de "authors" não podem ter duplicados
  • Os valores de "authors" não distinguem maiúsculas de minúsculas
  • A chave "contributors" é opcional
  • O valor de "contributors" tem de ser um array
  • Os valores de "contributors" têm de ser strings não vazias¹
  • Os valores de "contributors" não podem ter duplicados
  • Os valores de "contributors" não distinguem maiúsculas de minúsculas
  • Os utilizadores só podem constar num dos arrays, "authors" ou "contributors" (sem sobreposição)
  • A chave "files.solution" é obrigatória
  • O valor de "files.solution" tem de ser um array não vazio
  • Os valores de "files.solution" não podem ter duplicados
  • A chave "files.test" é obrigatória
  • O valor de "files.test" tem de ser um array não vazio
  • Os valores de "files.test" não podem ter duplicados
  • A chave "files.exemplar" é obrigatória
  • O valor de "files.exemplar" tem de ser um array não vazio
  • Os valores de "files.exemplar" não podem ter duplicados
  • A chave "files.editor" é opcional
  • O valor de "files.editor" tem de ser um array
  • Os valores de "files.editor" não podem ter duplicados
  • A chave "files.invalidator" é opcional
  • O valor de "files.invalidator" tem de ser um array
  • Os valores de "files.invalidator" não podem ter duplicados
  • Os ficheiros listados em "files.solution" têm de existir
  • Os ficheiros listados em "files.test" têm de existir
  • Os ficheiros listados em "files.exemplar" têm de existir
  • Os ficheiros listados em "files.editor" têm de existir
  • Os ficheiros listados em "files.invalidator" têm de existir
  • Os ficheiros só podem constar num dos arrays "files.solution", "files.test", "files.exemplar" ou "files.invalidator" (sem sobreposição)
    • Se o percurso for d ou plsql, os ficheiros de "files.solution" e "files.test" podem sobrepor-se
  • A chave "forked_from" é opcional
  • O valor de "forked_from" tem de ser um array
  • Os valores de "forked_from" têm de ser strings com o formato <track-slug>/<exercise-slug> (por exemplo, fsharp/bird-watcher)
  • Os valores de "forked_from" têm de se referir a exercícios realmente implementados
  • Os valores de "forked_from" não podem ter duplicados
  • A chave "language_versions" é opcional
  • O valor de "language_versions" tem de ser uma string
  • A chave "representer.version" é opcional
  • O valor de "representer.version" tem de ser um inteiro >= 1
  • A chave "icon" é opcional
  • O valor de "icon" tem de ser uma string em kebab-case²

Regra: exercises/concept/<slug>/.docs/hints.md é válido

  • O Markdown tem de estar de acordo com as normas de Markdown
  • Todos os cabeçalhos têm de ser ## General ou ## X. <task>, em que X corresponde ao número da tarefa no cabeçalho do instructions.md
  • Todas as dicas têm de ser especificadas como itens de lista de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: exercises/concept/<slug>/.docs/instructions.md é válido

  • O Markdown tem de estar de acordo com as normas de Markdown
  • Todas as tarefas têm de começar com um cabeçalho de nível dois que começa com um número seguido de um ponto: ## 1. Do X
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: exercises/concept/<slug>/.docs/instructions.md.tpl é válido (se existir)

  • O conceito de cada placeholder de conceito tem de corresponder à propriedade "concepts.slug" de um dos conceitos no config.json do percurso.

Regra: exercises/concept/<slug>/.docs/introduction.md é válido

  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: exercises/practice/<slug>/.meta/config.json é válido

  • O ficheiro tem de ser um JSON válido
  • A raiz do JSON tem de ser um objeto
  • A chave "blurb" é obrigatória
  • O valor de "blurb" tem de ser uma string não vazia¹ com comprimento <= 350
  • A chave "source" é opcional
  • O valor de "source" tem de ser uma string não vazia¹
  • A chave "source_url" é opcional
  • O valor de "source_url" tem de ser um URL
  • A chave "authors" é opcional
  • O valor de "authors" tem de ser um array
  • Os valores de "authors" têm de ser strings não vazias¹
  • Os valores de "authors" não podem ter duplicados
  • Os valores de "authors" não distinguem maiúsculas de minúsculas
  • A chave "contributors" é opcional
  • O valor de "contributors" tem de ser um array
  • Os valores de "contributors" têm de ser strings não vazias¹
  • Os valores de "contributors" não podem ter duplicados
  • Os valores de "contributors" não distinguem maiúsculas de minúsculas
  • Os utilizadores só podem constar num dos arrays, "authors" ou "contributors" (sem sobreposição)
  • A chave "files.solution" é obrigatória
  • O valor de "files.solution" tem de ser um array não vazio
  • Os valores de "files.solution" não podem ter duplicados
  • A chave "files.test" é obrigatória
  • O valor de "files.test" tem de ser um array não vazio
  • Os valores de "files.test" não podem ter duplicados
  • A chave "files.example" é obrigatória
  • O valor de "files.example" tem de ser um array não vazio
  • Os valores de "files.example" não podem ter duplicados
  • A chave "files.editor" é opcional
  • O valor de "files.editor" tem de ser um array
  • Os valores de "files.editor" não podem ter duplicados
  • A chave "files.invalidator" é opcional
  • O valor de "files.invalidator" tem de ser um array
  • Os valores de "files.invalidator" não podem ter duplicados
  • Os ficheiros listados em "files.solution" têm de existir
  • Os ficheiros listados em "files.test" têm de existir
  • Os ficheiros listados em "files.example" têm de existir
  • Os ficheiros listados em "files.editor" têm de existir
  • Os ficheiros listados em "files.invalidator" têm de existir
  • Os ficheiros só podem constar num dos arrays "files.solution", "files.test", "files.example ou "files.invalidator" (sem sobreposição)
    • Se o percurso for d ou plsql, os ficheiros de "files.solution" e "files.test" podem sobrepor-se
  • A chave "language_versions" é opcional
  • O valor de "language_versions" tem de ser uma string
  • A chave "test_runner" é opcional
  • O valor de "test_runner" tem de ser um boolean
  • A chave "representer.version" é opcional
  • O valor de "representer.version" tem de ser um inteiro >= 1
  • A chave "icon" é opcional
  • O valor de "icon" tem de ser uma string em kebab-case²

Regra: exercises/{concept|practice}/<slug>/.approaches/config.json é válido

  • A presença do ficheiro é opcional, a menos que exista um introduction.md ou um diretório irmão
  • O ficheiro tem de ser um JSON válido
  • A raiz do JSON tem de ser um objeto
  • A chave "introduction.authors" é opcional
  • O valor de "introduction.authors" tem de ser um array
  • Os valores de "introduction.authors" têm de ser strings não vazias¹
  • Os valores de "introduction.authors" não podem ter duplicados
  • Os valores de "introduction.authors" não distinguem maiúsculas de minúsculas
  • Se o array "introduction.authors" não estiver vazio, tem de existir um ficheiro introduction.md não vazio
  • A chave "introduction.contributors" é opcional
  • O valor de "introduction.contributors" tem de ser um array
  • Os valores de "introduction.contributors" têm de ser strings não vazias¹
  • Os valores de "introduction.contributors" não podem ter duplicados
  • Os valores de "introduction.contributors" não distinguem maiúsculas de minúsculas
  • Se o array "introduction.contributors" não estiver vazio, tem de existir um ficheiro introduction.md não vazio
  • Os utilizadores só podem constar num dos arrays, "introduction.authors" ou "introduction.contributors" (sem sobreposição)
  • A chave "approaches" é opcional, a menos que exista um diretório irmão (que contém os ficheiros da abordagem)
  • O valor de "approaches" tem de ser um array de objetos
  • A chave "approaches[].uuid" é obrigatória
  • O valor de "approaches[].uuid" tem de ser uma string UUID de versão 4 única⁶
  • O valor de "approaches[].uuid" de cada conceito nunca pode mudar
  • A chave "approaches[].slug" é obrigatória
  • O valor de "approaches[].slug" tem de ser uma string em kebab-case² com comprimento <= 255
  • O valor de "approaches[].slug" tem de ter um ficheiro <slug>/content.md não vazio correspondente
  • O valor de "approaches[].slug" tem de ter um ficheiro <slug>/snippet.txt não vazio correspondente
  • A chave "approaches[].title" é obrigatória
  • O valor de "approaches[].title" tem de ser uma string em Title Case³ com comprimento <= 255
  • A chave "approaches[].blurb" é obrigatória
  • O valor de "approaches[].blurb" tem de ser uma string não vazia¹ com comprimento <= 350
  • A chave "approaches[].authors" é obrigatória
  • O valor de "approaches[].authors" tem de ser um array não vazio
  • Os valores de "approaches[].authors" têm de ser strings não vazias¹
  • Os valores de "approaches[].authors" não podem ter duplicados
  • Os valores de "approaches[].authors" não distinguem maiúsculas de minúsculas
  • A chave "approaches[].contributors" é opcional
  • O valor de "approaches[].contributors" tem de ser um array
  • Os valores de "approaches[].contributors" têm de ser strings não vazias¹
  • Os valores de "approaches[].contributors" não podem ter duplicados
  • Os valores de "approaches[].contributors" não distinguem maiúsculas de minúsculas
  • Os utilizadores só podem constar num dos arrays, "approaches[].authors" ou "approaches[].contributors" (sem sobreposição)
  • A chave "approaches[].tags" é opcional
  • A chave "approaches[].tags.all" é opcional, a menos que "approaches[].tags.any" esteja vazio
  • O valor de "approaches[].tags.all" tem de ser um array
  • Os valores de "approaches[].tags.all" têm de ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "approaches[].tags.all" não podem ter duplicados
  • A chave "approaches[].tags.any" é opcional, a menos que "approaches[].tags.all" esteja vazio
  • O valor de "approaches[].tags.any" tem de ser um array
  • Os valores de "approaches[].tags.any" têm de ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "approaches[].tags.any" não podem ter duplicados
  • A chave "approaches[].tags.not" é opcional
  • O valor de "approaches[].tags.not" tem de ser um array
  • Os valores de "approaches[].tags.not" têm de ser strings de tag⁷ não vazias com comprimento <= 255
  • Os valores de "approaches[].tags.not" não podem ter duplicados

Regra: exercises/{concept|practice}/<slug>/.approaches/<approach-slug>/content.md é válido

  • A presença do ficheiro é obrigatória se existir uma entrada "approaches[].slug" correspondente no ficheiro .approaches/config.json
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: exercises/{concept|practice}/<slug>/.approaches/<approach-slug>/snippet.<snippet-extension> é válido

  • A presença do ficheiro é obrigatória se existir uma entrada "approaches[].slug" correspondente no ficheiro .approaches/config.json
  • O snippet pode ter no máximo 8 linhas
  • A extensão do snippet é obtida a partir do valor approaches.snippet_extension no ficheiro config.json do percurso

Regra: exercises/{concept|practice}/<slug>/.articles/config.json é válido

  • A presença do ficheiro é opcional, a menos que exista um diretório irmão
  • O ficheiro tem de ser um JSON válido
  • A raiz do JSON tem de ser um objeto
  • A chave "articles" é opcional, a menos que exista um diretório irmão (que contém os ficheiros do artigo)
  • O valor de "articles" tem de ser um array de objetos
  • A chave "articles[].uuid" é obrigatória
  • O valor de "articles[].uuid" tem de ser uma string UUID de versão 4 única⁶
  • O valor de "articles[].uuid" de cada conceito nunca pode mudar
  • A chave "articles[].slug" é obrigatória
  • O valor de "articles[].slug" tem de ser uma string em kebab-case² com comprimento <= 255
  • O valor de "articles[].slug" tem de ter um ficheiro <slug>/content.md não vazio correspondente
  • O valor de "articles[].slug" tem de ter um ficheiro <slug>/snippet.md não vazio correspondente
  • A chave "articles[].title" é obrigatória
  • O valor de "articles[].title" tem de ser uma string em Title Case³ com comprimento <= 255
  • A chave "articles[].blurb" é obrigatória
  • O valor de "articles[].blurb" tem de ser uma string não vazia¹ com comprimento <= 350
  • A chave "articles[].authors" é obrigatória
  • O valor de "articles[].authors" tem de ser um array não vazio
  • Os valores de "articles[].authors" têm de ser strings não vazias¹
  • Os valores de "articles[].authors" não podem ter duplicados
  • Os valores de "articles[].authors" não distinguem maiúsculas de minúsculas
  • A chave "articles[].contributors" é opcional
  • O valor de "articles[].contributors" tem de ser um array
  • Os valores de "articles[].contributors" têm de ser strings não vazias¹
  • Os valores de "articles[].contributors" não podem ter duplicados
  • Os valores de "articles[].contributors" não distinguem maiúsculas de minúsculas
  • Os utilizadores só podem constar num dos arrays, "articles[].authors" ou "articles[].contributors" (sem sobreposição)

Regra: exercises/{concept|practice}/<slug>/.articles/<article-slug>/content.md é válido

  • A presença do ficheiro é obrigatória se existir uma entrada "articles[].slug" correspondente no ficheiro .articles/config.json
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: exercises/{concept|practice}/<slug>/.articles/<article-slug>/snippet.md é válido

  • A presença do ficheiro é obrigatória se existir uma entrada "articles[].slug" correspondente no ficheiro .articles/config.json
  • O Markdown tem de estar de acordo com as normas de Markdown
  • O snippet pode ter no máximo 8 linhas (os delimitadores de bloco de código no início e no fim são ignorados)

Regra: exercises/shared/.docs/debug.md é válido

  • A presença do ficheiro é opcional
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: exercises/shared/.docs/help.md é válido

  • A presença do ficheiro é obrigatória
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: exercises/shared/.docs/tests.md é válido

  • A presença do ficheiro é obrigatória
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: concepts/<slug>/about.md é válido

  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: concepts/<slug>/introduction.md é válido

  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)
  • O ficheiro tem de ser um JSON válido
  • A raiz do JSON tem de ser um array
  • A propriedade "[].url" é obrigatória
  • O valor de "[].url" tem de ser um URL
  • A propriedade "[].description" é obrigatória
  • O valor de "[].description" tem de ser uma string não vazia¹
  • A propriedade "[].icon_url" é opcional
  • O valor de "[].icon_url" tem de ser um URL

Regra: concept/<slug>/.meta/config.json é válido

  • O ficheiro tem de ser um JSON válido
  • A raiz do JSON tem de ser um objeto
  • A chave "blurb" é obrigatória
  • O valor de "blurb" tem de ser uma string não vazia¹ com comprimento <= 350
  • A chave "authors" é obrigatória
  • O valor de "authors" tem de ser um array
  • Os valores de "authors" têm de ser strings não vazias¹
  • Os valores de "authors" não podem ter duplicados
  • Os valores de "authors" não distinguem maiúsculas de minúsculas
  • A chave "contributors" é opcional
  • O valor de "contributors" tem de ser um array
  • Os valores de "contributors" têm de ser strings não vazias¹
  • Os valores de "contributors" não podem ter duplicados
  • Os valores de "contributors" não distinguem maiúsculas de minúsculas
  • Os utilizadores só podem constar num dos arrays, "authors" ou "contributors" (sem sobreposição)

Regra: docs/ABOUT.md é válido

  • A presença do ficheiro é obrigatória
  • O conteúdo do ficheiro não pode estar vazio
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: docs/INSTALLATION.md é válido

  • A presença do ficheiro é obrigatória
  • O conteúdo do ficheiro não pode estar vazio
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: docs/LEARNING.md é válido

  • A presença do ficheiro é obrigatória
  • O conteúdo do ficheiro não pode estar vazio
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: docs/RESOURCES.md é válido

  • A presença do ficheiro é obrigatória
  • O conteúdo do ficheiro não pode estar vazio
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Regra: docs/SNIPPET.txt é válido

  • A presença do ficheiro é obrigatória
  • O conteúdo do ficheiro não pode estar vazio

Regra: docs/TESTS.md é válido

  • A presença do ficheiro é obrigatória
  • O conteúdo do ficheiro não pode estar vazio
  • O Markdown tem de estar de acordo com as normas de Markdown
  • As ligações têm de ser absolutas (não são permitidas ligações relativas)

Glossário

  1. String não vazia: uma string que contém pelo menos um caráter que não seja um espaço em branco.

  2. 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]+)*$

  3. String em Title Case: uma string não vazia que segue as orientações do Chicago Manual of Style abaixo:

    • Escreve com maiúscula a primeira e a última palavra de títulos e subtítulos.
    • Escreve com maiúscula as palavras "principais" (nomes, pronomes, verbos, adjetivos, advérbios e algumas conjunções).
    • Escreve com minúscula as conjunções and, but, for, or e nor.
    • Escreve com minúscula os artigos the, a e an.
    • Escreve com minúscula as preposições, independentemente do comprimento, exceto quando são tónicas, são usadas como advérbios ou adjetivos, ou são usadas como conjunções.
    • Escreve com minúscula as palavras to e as.
    • Escreve com minúscula a segunda parte dos nomes de espécies latinas.
  4. String em Sentence Case: uma string não vazia que segue as orientações abaixo:

    • Escreve com maiúscula a primeira palavra da frase, bem como os nomes próprios e outras palavras conforme exigido por uma regra mais específica.
  5. 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)
  6. String UUID de versão 4 única: uma string que satisfaz todas estas condições:

    • Existe apenas uma vez no ficheiro config.json ao nível do percurso de um determinado percurso do Exercism
    • Não existe no ficheiro config.json ao nível do percurso de qualquer outro percurso do Exercism
    • Não existe em nenhum ficheiro canonical-data.json em https://github.com/exercism/problem-specifications
    • Não existe em mais nenhum sítio do Exercism
    • Corresponde à expressão regular:
    ^[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.

  7. 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¹.